00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "asterisk.h"
00032
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 153823 $")
00034
00035 #include <sys/types.h>
00036 #include <stdio.h>
00037 #include <unistd.h>
00038 #include <stdlib.h>
00039 #include <time.h>
00040 #include <string.h>
00041 #include <netinet/in.h>
00042 #include <sys/time.h>
00043 #include <sys/socket.h>
00044 #include <sys/stat.h>
00045 #include <sys/signal.h>
00046 #include <arpa/inet.h>
00047 #include <errno.h>
00048 #include <fcntl.h>
00049 #include <pthread.h>
00050
00051 #include "asterisk/cli.h"
00052 #include "asterisk/http.h"
00053 #include "asterisk/utils.h"
00054 #include "asterisk/strings.h"
00055 #include "asterisk/options.h"
00056 #include "asterisk/config.h"
00057 #include "asterisk/version.h"
00058 #include "asterisk/manager.h"
00059
00060 #define MAX_PREFIX 80
00061 #define DEFAULT_PREFIX "/asterisk"
00062
00063 struct ast_http_server_instance {
00064 FILE *f;
00065 int fd;
00066 struct sockaddr_in requestor;
00067 ast_http_callback callback;
00068 };
00069
00070 AST_RWLOCK_DEFINE_STATIC(uris_lock);
00071 static struct ast_http_uri *uris;
00072
00073 static int httpfd = -1;
00074 static pthread_t master = AST_PTHREADT_NULL;
00075 static char prefix[MAX_PREFIX];
00076 static int prefix_len;
00077 static struct sockaddr_in oldsin;
00078 static int enablestatic;
00079
00080
00081 static struct {
00082 const char *ext;
00083 const char *mtype;
00084 } mimetypes[] = {
00085 { "png", "image/png" },
00086 { "jpg", "image/jpeg" },
00087 { "js", "application/x-javascript" },
00088 { "wav", "audio/x-wav" },
00089 { "mp3", "audio/mpeg" },
00090 { "svg", "image/svg+xml" },
00091 { "svgz", "image/svg+xml" },
00092 { "gif", "image/gif" },
00093 };
00094
00095 static const char *ftype2mtype(const char *ftype, char *wkspace, int wkspacelen)
00096 {
00097 int x;
00098 if (ftype) {
00099 for (x=0;x<sizeof(mimetypes) / sizeof(mimetypes[0]); x++) {
00100 if (!strcasecmp(ftype, mimetypes[x].ext))
00101 return mimetypes[x].mtype;
00102 }
00103 }
00104 snprintf(wkspace, wkspacelen, "text/%s", ftype ? ftype : "plain");
00105 return wkspace;
00106 }
00107
00108 static char *static_callback(struct sockaddr_in *req, const char *uri, struct ast_variable *vars, int *status, char **title, int *contentlength)
00109 {
00110 char result[4096];
00111 char *c=result;
00112 char *path;
00113 char *ftype;
00114 const char *mtype;
00115 char wkspace[80];
00116 struct stat st;
00117 int len;
00118 int fd;
00119 void *blob;
00120
00121
00122
00123 if (!enablestatic || ast_strlen_zero(uri))
00124 goto out403;
00125
00126 if ((uri[0] < 33) || strchr("./|~@#$%^&*() \t", uri[0]))
00127 goto out403;
00128 if (strstr(uri, "/.."))
00129 goto out403;
00130
00131 if ((ftype = strrchr(uri, '.')))
00132 ftype++;
00133 mtype = ftype2mtype(ftype, wkspace, sizeof(wkspace));
00134
00135
00136 len = strlen(uri) + strlen(ast_config_AST_DATA_DIR) + strlen("/static-http/") + 5;
00137 if (len > 1024)
00138 goto out403;
00139
00140 path = alloca(len);
00141 sprintf(path, "%s/static-http/%s", ast_config_AST_DATA_DIR, uri);
00142 if (stat(path, &st))
00143 goto out404;
00144 if (S_ISDIR(st.st_mode))
00145 goto out404;
00146 fd = open(path, O_RDONLY);
00147 if (fd < 0)
00148 goto out403;
00149
00150 len = st.st_size + strlen(mtype) + 40;
00151
00152 blob = malloc(len);
00153 if (blob) {
00154 c = blob;
00155 sprintf(c, "Content-type: %s\r\n\r\n", mtype);
00156 c += strlen(c);
00157 *contentlength = read(fd, c, st.st_size);
00158 if (*contentlength < 0) {
00159 close(fd);
00160 free(blob);
00161 goto out403;
00162 }
00163 }
00164 close(fd);
00165 return blob;
00166
00167 out404:
00168 *status = 404;
00169 *title = strdup("Not Found");
00170 return ast_http_error(404, "Not Found", NULL, "The requested URL was not found on this server.");
00171
00172 out403:
00173 *status = 403;
00174 *title = strdup("Access Denied");
00175 return ast_http_error(403, "Access Denied", NULL, "You do not have permission to access the requested URL.");
00176 }
00177
00178
00179 static char *httpstatus_callback(struct sockaddr_in *req, const char *uri, struct ast_variable *vars, int *status, char **title, int *contentlength)
00180 {
00181 char result[4096];
00182 size_t reslen = sizeof(result);
00183 char *c=result;
00184 struct ast_variable *v;
00185
00186 ast_build_string(&c, &reslen,
00187 "\r\n"
00188 "<title>Asterisk HTTP Status</title>\r\n"
00189 "<body bgcolor=\"#ffffff\">\r\n"
00190 "<table bgcolor=\"#f1f1f1\" align=\"center\"><tr><td bgcolor=\"#e0e0ff\" colspan=\"2\" width=\"500\">\r\n"
00191 "<h2> Asterisk™ HTTP Status</h2></td></tr>\r\n");
00192
00193 ast_build_string(&c, &reslen, "<tr><td><i>Prefix</i></td><td><b>%s</b></td></tr>\r\n", prefix);
00194 ast_build_string(&c, &reslen, "<tr><td><i>Bind Address</i></td><td><b>%s</b></td></tr>\r\n",
00195 ast_inet_ntoa(oldsin.sin_addr));
00196 ast_build_string(&c, &reslen, "<tr><td><i>Bind Port</i></td><td><b>%d</b></td></tr>\r\n",
00197 ntohs(oldsin.sin_port));
00198 ast_build_string(&c, &reslen, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
00199 v = vars;
00200 while(v) {
00201 if (strncasecmp(v->name, "cookie_", 7))
00202 ast_build_string(&c, &reslen, "<tr><td><i>Submitted Variable '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
00203 v = v->next;
00204 }
00205 ast_build_string(&c, &reslen, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
00206 v = vars;
00207 while(v) {
00208 if (!strncasecmp(v->name, "cookie_", 7))
00209 ast_build_string(&c, &reslen, "<tr><td><i>Cookie '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
00210 v = v->next;
00211 }
00212 ast_build_string(&c, &reslen, "</table><center><font size=\"-1\"><i>Asterisk and Digium are registered trademarks of Digium, Inc.</i></font></center></body>\r\n");
00213 return strdup(result);
00214 }
00215
00216 static struct ast_http_uri statusuri = {
00217 .callback = httpstatus_callback,
00218 .description = "Asterisk HTTP General Status",
00219 .uri = "httpstatus",
00220 .has_subtree = 0,
00221 };
00222
00223 static struct ast_http_uri staticuri = {
00224 .callback = static_callback,
00225 .description = "Asterisk HTTP Static Delivery",
00226 .uri = "static",
00227 .has_subtree = 1,
00228 .static_content = 1,
00229 };
00230
00231 char *ast_http_error(int status, const char *title, const char *extra_header, const char *text)
00232 {
00233 char *c = NULL;
00234 if (asprintf(&c,
00235 "Content-type: text/html\r\n"
00236 "%s"
00237 "\r\n"
00238 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
00239 "<html><head>\r\n"
00240 "<title>%d %s</title>\r\n"
00241 "</head><body>\r\n"
00242 "<h1>%s</h1>\r\n"
00243 "<p>%s</p>\r\n"
00244 "<hr />\r\n"
00245 "<address>Asterisk Server</address>\r\n"
00246 "</body></html>\r\n",
00247 (extra_header ? extra_header : ""), status, title, title, text) < 0) {
00248 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00249 c = NULL;
00250 }
00251 return c;
00252 }
00253
00254 int ast_http_uri_link(struct ast_http_uri *urih)
00255 {
00256 struct ast_http_uri *prev;
00257
00258 ast_rwlock_wrlock(&uris_lock);
00259 prev = uris;
00260 if (!uris || strlen(uris->uri) <= strlen(urih->uri)) {
00261 urih->next = uris;
00262 uris = urih;
00263 } else {
00264 while (prev->next && (strlen(prev->next->uri) > strlen(urih->uri)))
00265 prev = prev->next;
00266
00267 urih->next = prev->next;
00268 prev->next = urih;
00269 }
00270 ast_rwlock_unlock(&uris_lock);
00271
00272 return 0;
00273 }
00274
00275 void ast_http_uri_unlink(struct ast_http_uri *urih)
00276 {
00277 struct ast_http_uri *prev;
00278
00279 ast_rwlock_wrlock(&uris_lock);
00280 if (!uris) {
00281 ast_rwlock_unlock(&uris_lock);
00282 return;
00283 }
00284 prev = uris;
00285 if (uris == urih) {
00286 uris = uris->next;
00287 }
00288 while(prev->next) {
00289 if (prev->next == urih) {
00290 prev->next = urih->next;
00291 break;
00292 }
00293 prev = prev->next;
00294 }
00295 ast_rwlock_unlock(&uris_lock);
00296 }
00297
00298 static char *handle_uri(struct sockaddr_in *sin, char *uri, int *status,
00299 char **title, int *contentlength, struct ast_variable **cookies,
00300 unsigned int *static_content)
00301 {
00302 char *c;
00303 char *turi;
00304 char *params;
00305 char *var;
00306 char *val;
00307 struct ast_http_uri *urih=NULL;
00308 int len;
00309 struct ast_variable *vars=NULL, *v, *prev = NULL;
00310
00311
00312 params = strchr(uri, '?');
00313 if (params) {
00314 *params = '\0';
00315 params++;
00316 while ((var = strsep(¶ms, "&"))) {
00317 val = strchr(var, '=');
00318 if (val) {
00319 *val = '\0';
00320 val++;
00321 ast_uri_decode(val);
00322 } else
00323 val = "";
00324 ast_uri_decode(var);
00325 if ((v = ast_variable_new(var, val))) {
00326 if (vars)
00327 prev->next = v;
00328 else
00329 vars = v;
00330 prev = v;
00331 }
00332 }
00333 }
00334 if (prev)
00335 prev->next = *cookies;
00336 else
00337 vars = *cookies;
00338 *cookies = NULL;
00339 ast_uri_decode(uri);
00340 if (!strncasecmp(uri, prefix, prefix_len)) {
00341 uri += prefix_len;
00342 if (!*uri || (*uri == '/')) {
00343 if (*uri == '/')
00344 uri++;
00345 ast_rwlock_rdlock(&uris_lock);
00346 urih = uris;
00347 while(urih) {
00348 len = strlen(urih->uri);
00349 if (!strncasecmp(urih->uri, uri, len)) {
00350 if (!uri[len] || uri[len] == '/') {
00351 turi = uri + len;
00352 if (*turi == '/')
00353 turi++;
00354 if (!*turi || urih->has_subtree) {
00355 uri = turi;
00356 break;
00357 }
00358 }
00359 }
00360 urih = urih->next;
00361 }
00362 if (!urih)
00363 ast_rwlock_unlock(&uris_lock);
00364 }
00365 }
00366 if (urih) {
00367 if (urih->static_content)
00368 *static_content = 1;
00369 c = urih->callback(sin, uri, vars, status, title, contentlength);
00370 ast_rwlock_unlock(&uris_lock);
00371 } else if (ast_strlen_zero(uri) && ast_strlen_zero(prefix)) {
00372
00373 c = ast_http_error(302, "Moved Temporarily", "Location: /static/index.html\r\n", "Redirecting to /static/index.html.");
00374 *status = 302;
00375 *title = strdup("Moved Temporarily");
00376 } else {
00377 c = ast_http_error(404, "Not Found", NULL, "The requested URL was not found on this server.");
00378 *status = 404;
00379 *title = strdup("Not Found");
00380 }
00381 ast_variables_destroy(vars);
00382 return c;
00383 }
00384
00385 static struct ast_variable *parse_cookies(char *cookies)
00386 {
00387 char *cur;
00388 struct ast_variable *vars = NULL, *var;
00389
00390
00391 cookies += 8;
00392
00393 while ((cur = strsep(&cookies, ";"))) {
00394 char *name, *val;
00395
00396 name = val = cur;
00397 strsep(&val, "=");
00398
00399 if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
00400 continue;
00401 }
00402
00403 name = ast_strip(name);
00404 val = ast_strip_quoted(val, "\"", "\"");
00405
00406 if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
00407 continue;
00408 }
00409
00410 if (option_debug) {
00411 ast_log(LOG_DEBUG, "mmm ... cookie! Name: '%s' Value: '%s'\n", name, val);
00412 }
00413
00414 var = ast_variable_new(name, val);
00415 var->next = vars;
00416 vars = var;
00417 }
00418
00419 return vars;
00420 }
00421
00422 static void *ast_httpd_helper_thread(void *data)
00423 {
00424 char buf[4096];
00425 char cookie[4096];
00426 char timebuf[256];
00427 struct ast_http_server_instance *ser = data;
00428 struct ast_variable *vars = NULL;
00429 char *uri, *c, *title=NULL;
00430 int status = 200, contentlength = 0;
00431 time_t t;
00432 unsigned int static_content = 0;
00433
00434 if (fgets(buf, sizeof(buf), ser->f)) {
00435
00436 uri = buf;
00437 while(*uri && (*uri > 32))
00438 uri++;
00439 if (*uri) {
00440 *uri = '\0';
00441 uri++;
00442 }
00443
00444
00445 while (*uri && (*uri < 33))
00446 uri++;
00447
00448 if (*uri) {
00449 c = uri;
00450 while (*c && (*c > 32))
00451 c++;
00452 if (*c) {
00453 *c = '\0';
00454 }
00455 }
00456
00457 while (fgets(cookie, sizeof(cookie), ser->f)) {
00458
00459 while(!ast_strlen_zero(cookie) && (cookie[strlen(cookie) - 1] < 33)) {
00460 cookie[strlen(cookie) - 1] = '\0';
00461 }
00462 if (ast_strlen_zero(cookie))
00463 break;
00464 if (!strncasecmp(cookie, "Cookie: ", 8)) {
00465 vars = parse_cookies(cookie);
00466 }
00467 }
00468
00469 if (*uri) {
00470 if (!strcasecmp(buf, "get"))
00471 c = handle_uri(&ser->requestor, uri, &status, &title, &contentlength, &vars, &static_content);
00472 else
00473 c = ast_http_error(501, "Not Implemented", NULL, "Attempt to use unimplemented / unsupported method");\
00474 } else
00475 c = ast_http_error(400, "Bad Request", NULL, "Invalid Request");
00476
00477
00478 if (vars)
00479 ast_variables_destroy(vars);
00480
00481 if (!c)
00482 c = ast_http_error(500, "Internal Error", NULL, "Internal Server Error");
00483 if (c) {
00484 time(&t);
00485 strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
00486 ast_cli(ser->fd, "HTTP/1.1 %d %s\r\n", status, title ? title : "OK");
00487 ast_cli(ser->fd, "Server: Asterisk/%s\r\n", ASTERISK_VERSION);
00488 ast_cli(ser->fd, "Date: %s\r\n", timebuf);
00489 ast_cli(ser->fd, "Connection: close\r\n");
00490 if (!static_content)
00491 ast_cli(ser->fd, "Cache-Control: no-cache, no-store\r\n");
00492
00493
00494
00495
00496
00497 if (contentlength) {
00498 char *tmp;
00499 tmp = strstr(c, "\r\n\r\n");
00500 if (tmp) {
00501 ast_cli(ser->fd, "Content-length: %d\r\n", contentlength);
00502 if (write(ser->fd, c, (tmp + 4 - c)) < 0) {
00503 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00504 }
00505 if (write(ser->fd, tmp + 4, contentlength) < 0) {
00506 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00507 }
00508 }
00509 } else
00510 ast_cli(ser->fd, "%s", c);
00511 free(c);
00512 }
00513 if (title)
00514 free(title);
00515 }
00516 fclose(ser->f);
00517 free(ser);
00518 return NULL;
00519 }
00520
00521 static void *http_root(void *data)
00522 {
00523 int fd;
00524 struct sockaddr_in sin;
00525 socklen_t sinlen;
00526 struct ast_http_server_instance *ser;
00527 pthread_t launched;
00528 pthread_attr_t attr;
00529
00530 for (;;) {
00531 int flags;
00532
00533 ast_wait_for_input(httpfd, -1);
00534 sinlen = sizeof(sin);
00535 fd = accept(httpfd, (struct sockaddr *)&sin, &sinlen);
00536 if (fd < 0) {
00537 if ((errno != EAGAIN) && (errno != EINTR))
00538 ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno));
00539 continue;
00540 }
00541 ser = ast_calloc(1, sizeof(*ser));
00542 if (!ser) {
00543 ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno));
00544 close(fd);
00545 continue;
00546 }
00547 flags = fcntl(fd, F_GETFL);
00548 fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
00549 ser->fd = fd;
00550 memcpy(&ser->requestor, &sin, sizeof(ser->requestor));
00551 if ((ser->f = fdopen(ser->fd, "w+"))) {
00552 pthread_attr_init(&attr);
00553 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00554
00555 if (ast_pthread_create_background(&launched, &attr, ast_httpd_helper_thread, ser)) {
00556 ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
00557 fclose(ser->f);
00558 free(ser);
00559 }
00560 pthread_attr_destroy(&attr);
00561 } else {
00562 ast_log(LOG_WARNING, "fdopen failed!\n");
00563 close(ser->fd);
00564 free(ser);
00565 }
00566 }
00567 return NULL;
00568 }
00569
00570 char *ast_http_setcookie(const char *var, const char *val, int expires, char *buf, size_t buflen)
00571 {
00572 char *c;
00573 c = buf;
00574 ast_build_string(&c, &buflen, "Set-Cookie: %s=\"%s\"; Version=\"1\"", var, val);
00575 if (expires)
00576 ast_build_string(&c, &buflen, "; Max-Age=%d", expires);
00577 ast_build_string(&c, &buflen, "\r\n");
00578 return buf;
00579 }
00580
00581
00582 static void http_server_start(struct sockaddr_in *sin)
00583 {
00584 int flags;
00585 int x = 1;
00586
00587
00588 if (!memcmp(&oldsin, sin, sizeof(oldsin))) {
00589 ast_log(LOG_DEBUG, "Nothing changed in http\n");
00590 return;
00591 }
00592
00593 memcpy(&oldsin, sin, sizeof(oldsin));
00594
00595
00596 if (master != AST_PTHREADT_NULL) {
00597 pthread_cancel(master);
00598 pthread_kill(master, SIGURG);
00599 pthread_join(master, NULL);
00600 }
00601
00602 if (httpfd != -1)
00603 close(httpfd);
00604
00605
00606 if (!sin->sin_family)
00607 return;
00608
00609
00610 httpfd = socket(AF_INET, SOCK_STREAM, 0);
00611 if (httpfd < 0) {
00612 ast_log(LOG_WARNING, "Unable to allocate socket: %s\n", strerror(errno));
00613 return;
00614 }
00615
00616 setsockopt(httpfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
00617 if (bind(httpfd, (struct sockaddr *)sin, sizeof(*sin))) {
00618 ast_log(LOG_NOTICE, "Unable to bind http server to %s:%d: %s\n",
00619 ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port),
00620 strerror(errno));
00621 close(httpfd);
00622 httpfd = -1;
00623 return;
00624 }
00625 if (listen(httpfd, 10)) {
00626 ast_log(LOG_NOTICE, "Unable to listen!\n");
00627 close(httpfd);
00628 httpfd = -1;
00629 return;
00630 }
00631 flags = fcntl(httpfd, F_GETFL);
00632 fcntl(httpfd, F_SETFL, flags | O_NONBLOCK);
00633 if (ast_pthread_create_background(&master, NULL, http_root, NULL)) {
00634 ast_log(LOG_NOTICE, "Unable to launch http server on %s:%d: %s\n",
00635 ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port),
00636 strerror(errno));
00637 close(httpfd);
00638 httpfd = -1;
00639 }
00640 }
00641
00642 static int __ast_http_load(int reload)
00643 {
00644 struct ast_config *cfg;
00645 struct ast_variable *v;
00646 int enabled=0;
00647 int newenablestatic=0;
00648 struct sockaddr_in sin;
00649 struct hostent *hp;
00650 struct ast_hostent ahp;
00651 char newprefix[MAX_PREFIX];
00652
00653 memset(&sin, 0, sizeof(sin));
00654 sin.sin_port = htons(8088);
00655
00656 strcpy(newprefix, DEFAULT_PREFIX);
00657
00658 cfg = ast_config_load("http.conf");
00659 if (cfg) {
00660 v = ast_variable_browse(cfg, "general");
00661 while(v) {
00662 if (!strcasecmp(v->name, "enabled"))
00663 enabled = ast_true(v->value);
00664 else if (!strcasecmp(v->name, "enablestatic"))
00665 newenablestatic = ast_true(v->value);
00666 else if (!strcasecmp(v->name, "bindport"))
00667 sin.sin_port = ntohs(atoi(v->value));
00668 else if (!strcasecmp(v->name, "bindaddr")) {
00669 if ((hp = ast_gethostbyname(v->value, &ahp))) {
00670 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
00671 } else {
00672 ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value);
00673 }
00674 } else if (!strcasecmp(v->name, "prefix")) {
00675 if (!ast_strlen_zero(v->value)) {
00676 newprefix[0] = '/';
00677 ast_copy_string(newprefix + 1, v->value, sizeof(newprefix) - 1);
00678 } else {
00679 newprefix[0] = '\0';
00680 }
00681
00682 }
00683 v = v->next;
00684 }
00685 ast_config_destroy(cfg);
00686 }
00687 if (enabled)
00688 sin.sin_family = AF_INET;
00689 if (strcmp(prefix, newprefix)) {
00690 ast_copy_string(prefix, newprefix, sizeof(prefix));
00691 prefix_len = strlen(prefix);
00692 }
00693 enablestatic = newenablestatic;
00694
00695 http_server_start(&sin);
00696
00697
00698 return 0;
00699 }
00700
00701 static int handle_show_http(int fd, int argc, char *argv[])
00702 {
00703 struct ast_http_uri *urih;
00704
00705 if (argc != 3)
00706 return RESULT_SHOWUSAGE;
00707
00708 ast_cli(fd, "HTTP Server Status:\n");
00709 ast_cli(fd, "Prefix: %s\n", prefix);
00710 if (oldsin.sin_family)
00711 ast_cli(fd, "Server Enabled and Bound to %s:%d\n\n",
00712 ast_inet_ntoa(oldsin.sin_addr),
00713 ntohs(oldsin.sin_port));
00714 else
00715 ast_cli(fd, "Server Disabled\n\n");
00716 ast_cli(fd, "Enabled URI's:\n");
00717 ast_rwlock_rdlock(&uris_lock);
00718 urih = uris;
00719 while(urih){
00720 ast_cli(fd, "%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description);
00721 urih = urih->next;
00722 }
00723 if (!uris)
00724 ast_cli(fd, "None.\n");
00725 ast_rwlock_unlock(&uris_lock);
00726
00727 return RESULT_SUCCESS;
00728 }
00729
00730 int ast_http_reload(void)
00731 {
00732 return __ast_http_load(1);
00733 }
00734
00735 static char show_http_help[] =
00736 "Usage: http show status\n"
00737 " Lists status of internal HTTP engine\n";
00738
00739 static struct ast_cli_entry cli_http[] = {
00740 { { "http", "show", "status", NULL },
00741 handle_show_http, "Display HTTP server status",
00742 show_http_help },
00743 };
00744
00745 int ast_http_init(void)
00746 {
00747 ast_http_uri_link(&statusuri);
00748 ast_http_uri_link(&staticuri);
00749 ast_cli_register_multiple(cli_http, sizeof(cli_http) / sizeof(struct ast_cli_entry));
00750
00751 return __ast_http_load(0);
00752 }