Add micro-http server and abstract manager interface, make snmp not die
authorMark Spencer <markster@digium.com>
Sat, 25 Mar 2006 23:50:09 +0000 (23:50 +0000)
committerMark Spencer <markster@digium.com>
Sat, 25 Mar 2006 23:50:09 +0000 (23:50 +0000)
on reload.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@14953 65c4cc65-6c06-0410-ace0-fbb531ad65f3

16 files changed:
Makefile
apps/app_queue.c
asterisk.c
channels/chan_agent.c
channels/chan_iax2.c
channels/chan_sip.c
channels/chan_zap.c
configs/http.conf.sample [new file with mode: 0644]
db.c
http.c [new file with mode: 0644]
include/asterisk/http.h [new file with mode: 0644]
include/asterisk/manager.h
loader.c
manager.c
res/res_features.c
res/res_snmp.c

index bec360a..4414a76 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -364,7 +364,7 @@ OBJS=io.o sched.o logger.o frame.o loader.o config.o channel.o \
        astmm.o enum.o srv.o dns.o aescrypt.o aestab.o aeskey.o \
        utils.o plc.o jitterbuf.o dnsmgr.o devicestate.o \
        netsock.o slinfactory.o ast_expr2.o ast_expr2f.o \
-       cryptostub.o sha1.o
+       cryptostub.o sha1.o http.o
 
 # we need to link in the objects statically, not as a library, because
 # otherwise modules will not have them available if none of the static
index 072024b..b935951 100644 (file)
@@ -3357,7 +3357,7 @@ static void reload_queues(void)
        AST_LIST_UNLOCK(&queues);
 }
 
-static int __queues_show(int manager, int fd, int argc, char **argv, int queue_show)
+static int __queues_show(struct mansession *s, int manager, int fd, int argc, char **argv, int queue_show)
 {
        struct ast_call_queue *q;
        struct queue_ent *qe;
@@ -3381,10 +3381,17 @@ static int __queues_show(int manager, int fd, int argc, char **argv, int queue_s
        AST_LIST_LOCK(&queues);
        if (AST_LIST_EMPTY(&queues)) {
                AST_LIST_UNLOCK(&queues);
-               if (queue_show)
-                       ast_cli(fd, "No such queue: %s.%s",argv[2], term);
-               else
-                       ast_cli(fd, "No queues.%s", term);
+               if (queue_show) {
+                       if (s)
+                               astman_append(s, "No such queue: %s.%s",argv[2], term);
+                       else
+                               ast_cli(fd, "No such queue: %s.%s",argv[2], term);
+               } else {
+                       if (s)
+                               astman_append(s, "No queues.%s", term);
+                       else
+                               ast_cli(fd, "No queues.%s", term);
+               }
                return RESULT_SUCCESS;
        }
        AST_LIST_TRAVERSE(&queues, q, list) {
@@ -3409,10 +3416,17 @@ static int __queues_show(int manager, int fd, int argc, char **argv, int queue_s
                sl = 0;
                if(q->callscompleted > 0)
                        sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
-               ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
-                       q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
+               if (s)
+                       astman_append(s, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
+                               q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
+               else
+                       ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
+                               q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel, term);
                if (q->members) {
-                       ast_cli(fd, "   Members: %s", term);
+                       if (s)
+                               astman_append(s, "   Members: %s", term);
+                       else
+                               ast_cli(fd, "   Members: %s", term);
                        for (mem = q->members; mem; mem = mem->next) {
                                max_buf[0] = '\0';
                                max = max_buf;
@@ -3429,19 +3443,37 @@ static int __queues_show(int manager, int fd, int argc, char **argv, int queue_s
                                                         mem->calls, (long)(time(NULL) - mem->lastcall));
                                } else
                                        ast_build_string(&max, &max_left, " has taken no calls yet");
-                               ast_cli(fd, "      %s%s%s", mem->interface, max_buf, term);
+                               if (s)
+                                       astman_append(s, "      %s%s%s", mem->interface, max_buf, term);
+                               else
+                                       ast_cli(fd, "      %s%s%s", mem->interface, max_buf, term);
                        }
-               } else
+               } else if (s)
+                       astman_append(s, "   No Members%s", term);
+               else    
                        ast_cli(fd, "   No Members%s", term);
                if (q->head) {
                        pos = 1;
-                       ast_cli(fd, "   Callers: %s", term);
-                       for (qe = q->head; qe; qe = qe->next) 
-                               ast_cli(fd, "      %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++, qe->chan->name,
-                                       (long)(now - qe->start) / 60, (long)(now - qe->start) % 60, qe->prio, term);
-               } else
+                       if (s)
+                               astman_append(s, "   Callers: %s", term);
+                       else
+                               ast_cli(fd, "   Callers: %s", term);
+                       for (qe = q->head; qe; qe = qe->next) {
+                               if (s)
+                                       astman_append(s, "      %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++, qe->chan->name,
+                                               (long)(now - qe->start) / 60, (long)(now - qe->start) % 60, qe->prio, term);
+                               else
+                                       ast_cli(fd, "      %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++, qe->chan->name,
+                                               (long)(now - qe->start) / 60, (long)(now - qe->start) % 60, qe->prio, term);
+                       }
+               } else if (s)
+                       astman_append(s, "   No Callers%s", term);
+               else
                        ast_cli(fd, "   No Callers%s", term);
-               ast_cli(fd, "%s", term);
+               if (s)
+                       astman_append(s, "%s", term);
+               else
+                       ast_cli(fd, "%s", term);
                ast_mutex_unlock(&q->lock);
                if (queue_show)
                        break;
@@ -3452,12 +3484,12 @@ static int __queues_show(int manager, int fd, int argc, char **argv, int queue_s
 
 static int queues_show(int fd, int argc, char **argv)
 {
-       return __queues_show(0, fd, argc, argv, 0);
+       return __queues_show(NULL, 0, fd, argc, argv, 0);
 }
 
 static int queue_show(int fd, int argc, char **argv)
 {
-       return __queues_show(0, fd, argc, argv, 1);
+       return __queues_show(NULL, 0, fd, argc, argv, 1);
 }
 
 static char *complete_queue(const char *line, const char *word, int pos, int state)
@@ -3485,8 +3517,8 @@ static char *complete_queue(const char *line, const char *word, int pos, int sta
 static int manager_queues_show( struct mansession *s, struct message *m )
 {
        char *a[] = { "show", "queues" };
-       __queues_show(1, s->fd, 2, a, 0);
-       ast_cli(s->fd, "\r\n\r\n");     /* Properly terminate Manager output */
+       __queues_show(s, 1, -1, 2, a, 0);
+       astman_append(s, "\r\n\r\n");   /* Properly terminate Manager output */
 
        return RESULT_SUCCESS;
 } 
@@ -3518,7 +3550,7 @@ static int manager_queues_status( struct mansession *s, struct message *m )
                if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
                        if(q->callscompleted > 0)
                                sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
-                       ast_cli(s->fd, "Event: QueueParams\r\n"
+                       astman_append(s, "Event: QueueParams\r\n"
                                                "Queue: %s\r\n"
                                                "Max: %d\r\n"
                                                "Calls: %d\r\n"
@@ -3535,7 +3567,7 @@ static int manager_queues_status( struct mansession *s, struct message *m )
                        /* List Queue Members */
                        for (mem = q->members; mem; mem = mem->next) {
                                if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) {
-                                       ast_cli(s->fd, "Event: QueueMember\r\n"
+                                       astman_append(s, "Event: QueueMember\r\n"
                                                "Queue: %s\r\n"
                                                "Location: %s\r\n"
                                                "Membership: %s\r\n"
@@ -3553,7 +3585,7 @@ static int manager_queues_status( struct mansession *s, struct message *m )
                        /* List Queue Entries */
                        pos = 1;
                        for (qe = q->head; qe; qe = qe->next) {
-                               ast_cli(s->fd, "Event: QueueEntry\r\n"
+                               astman_append(s, "Event: QueueEntry\r\n"
                                        "Queue: %s\r\n"
                                        "Position: %d\r\n"
                                        "Channel: %s\r\n"
@@ -3572,7 +3604,7 @@ static int manager_queues_status( struct mansession *s, struct message *m )
        }
        AST_LIST_UNLOCK(&queues);
 
-       ast_cli(s->fd,
+       astman_append(s,
                "Event: QueueStatusComplete\r\n"
                "%s"
                "\r\n",idText);
index e26e6a5..72c2835 100644 (file)
@@ -107,6 +107,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/pbx.h"
 #include "asterisk/enum.h"
 #include "asterisk/rtp.h"
+#include "asterisk/http.h"
 #if defined(T38_SUPPORT)
 #include "asterisk/udptl.h"
 #endif
@@ -1847,7 +1848,8 @@ static int show_cli_help(void) {
        return 0;
 }
 
-static void ast_readconfig(void) {
+static void ast_readconfig(void) 
+{
        struct ast_config *cfg;
        struct ast_variable *v;
        char *config = AST_CONFIG_FILE;
@@ -2321,6 +2323,7 @@ int main(int argc, char *argv[])
                printf(term_quit());
                exit(1);
        }
+       ast_http_init();
        ast_channels_init();
        if (init_manager()) {
                printf(term_quit());
index b2fc203..e548f71 100644 (file)
@@ -1411,7 +1411,7 @@ static int action_agents(struct mansession *s, struct message *m)
                        status = "AGENT_LOGGEDOFF";
                }
 
-               ast_cli(s->fd, "Event: Agents\r\n"
+               astman_append(s, "Event: Agents\r\n"
                        "Agent: %s\r\n"
                        "Name: %s\r\n"
                        "Status: %s\r\n"
@@ -1424,7 +1424,7 @@ static int action_agents(struct mansession *s, struct message *m)
                ast_mutex_unlock(&p->lock);
        }
        AST_LIST_UNLOCK(&agents);
-       ast_cli(s->fd, "Event: AgentsComplete\r\n"
+       astman_append(s, "Event: AgentsComplete\r\n"
                "%s"
                "\r\n",idText);
        return 0;
index d8995c6..69fccbb 100644 (file)
@@ -673,7 +673,7 @@ static void reg_source_db(struct iax2_peer *p);
 static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in *sin);
 
 static void destroy_peer(struct iax2_peer *peer);
-static int ast_cli_netstats(int fd, int limit_fmt);
+static int ast_cli_netstats(struct mansession *s, int fd, int limit_fmt);
 
 #define IAX_IOSTATE_IDLE               0
 #define IAX_IOSTATE_READY              1
@@ -4324,7 +4324,7 @@ static int iax2_show_users(int fd, int argc, char *argv[])
 #undef FORMAT2
 }
 
-static int __iax2_show_peers(int manager, int fd, int argc, char *argv[])
+static int __iax2_show_peers(int manager, int fd, struct mansession *s, int argc, char *argv[])
 {
        regex_t regexbuf;
        int havepattern = 0;
@@ -4376,7 +4376,10 @@ static int __iax2_show_peers(int manager, int fd, int argc, char *argv[])
        }
 
        ast_mutex_lock(&peerl.lock);
-       ast_cli(fd, FORMAT2, "Name/Username", "Host", "   ", "Mask", "Port", "   ", "Status", term);
+       if (s)
+               astman_append(s, FORMAT2, "Name/Username", "Host", "   ", "Mask", "Port", "   ", "Status", term);
+       else
+               ast_cli(fd, FORMAT2, "Name/Username", "Host", "   ", "Mask", "Port", "   ", "Status", term);
        for (peer = peerl.peers;peer;peer = peer->next) {
                char nm[20];
                char status[20];
@@ -4410,7 +4413,15 @@ static int __iax2_show_peers(int manager, int fd, int argc, char *argv[])
                                        ntohs(peer->addr.sin_port), ast_test_flag(peer, IAX_TRUNK) ? "(T)" : "   ",
                                        peer->encmethods ? "(E)" : "   ", status, term);
 
-               ast_cli(fd, FORMAT, name, 
+               if (s)
+                       astman_append(s, FORMAT, name, 
+                                       peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)",
+                                       ast_test_flag(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
+                                       nm,
+                                       ntohs(peer->addr.sin_port), ast_test_flag(peer, IAX_TRUNK) ? "(T)" : "   ",
+                                       peer->encmethods ? "(E)" : "   ", status, term);
+               else
+                       ast_cli(fd, FORMAT, name, 
                                        peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)",
                                        ast_test_flag(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
                                        nm,
@@ -4420,7 +4431,10 @@ static int __iax2_show_peers(int manager, int fd, int argc, char *argv[])
        }
        ast_mutex_unlock(&peerl.lock);
 
-       ast_cli(fd,"%d iax2 peers [%d online, %d offline, %d unmonitored]%s", total_peers, online_peers, offline_peers, unmonitored_peers, term);
+       if (s)
+               astman_append(s,"%d iax2 peers [%d online, %d offline, %d unmonitored]%s", total_peers, online_peers, offline_peers, unmonitored_peers, term);
+       else
+               ast_cli(fd,"%d iax2 peers [%d online, %d offline, %d unmonitored]%s", total_peers, online_peers, offline_peers, unmonitored_peers, term);
 
        if (havepattern)
                regfree(&regexbuf);
@@ -4473,12 +4487,12 @@ static int iax2_show_threads(int fd, int argc, char *argv[])
 
 static int iax2_show_peers(int fd, int argc, char *argv[])
 {
-       return __iax2_show_peers(0, fd, argc, argv);
+       return __iax2_show_peers(0, fd, NULL, argc, argv);
 }
 static int manager_iax2_show_netstats( struct mansession *s, struct message *m )
 {
-       ast_cli_netstats(s->fd, 0);
-       ast_cli(s->fd, "\r\n");
+       ast_cli_netstats(s, -1, 0);
+       astman_append(s, "\r\n");
        return RESULT_SUCCESS;
 }
 
@@ -4515,9 +4529,9 @@ static int manager_iax2_show_peers( struct mansession *s, struct message *m )
        char *id;
        id = astman_get_header(m,"ActionID");
        if (!ast_strlen_zero(id))
-               ast_cli(s->fd, "ActionID: %s\r\n",id);
-       ret = __iax2_show_peers(1, s->fd, 3, a );
-       ast_cli(s->fd, "\r\n\r\n" );
+               astman_append(s, "ActionID: %s\r\n",id);
+       ret = __iax2_show_peers(1, -1, s, 3, a );
+       astman_append(s, "\r\n\r\n" );
        return ret;
 } /* /JDG */
 
@@ -4651,7 +4665,7 @@ static int iax2_show_channels(int fd, int argc, char *argv[])
 #undef FORMATB
 }
 
-static int ast_cli_netstats(int fd, int limit_fmt)
+static int ast_cli_netstats(struct mansession *s, int fd, int limit_fmt)
 {
        int x;
        int numchans = 0;
@@ -4660,13 +4674,21 @@ static int ast_cli_netstats(int fd, int limit_fmt)
                if (iaxs[x]) {
 #ifdef BRIDGE_OPTIMIZATION
                        if (iaxs[x]->bridgecallno) {
-                               if (limit_fmt)  
-                                       ast_cli(fd, "%-25.25s <NATIVE BRIDGED>",
-                                               iaxs[x]->owner ? iaxs[x]->owner->name : "(None)");
-                               else
-                                       ast_cli(fd, "%s <NATIVE BRIDGED>",
-                                               iaxs[x]->owner ? iaxs[x]->owner->name : "(None)");
-                        } else
+                               if (limit_fmt)   {
+                                       if (s)
+                                               astman_append(s, "%-25.25s <NATIVE BRIDGED>",
+                                                       iaxs[x]->owner ? iaxs[x]->owner->name : "(None)");
+                                       else
+                                               ast_cli(fd, "%-25.25s <NATIVE BRIDGED>",
+                                                       iaxs[x]->owner ? iaxs[x]->owner->name : "(None)");
+                               } else {
+                                       if (s)
+                                               astman_append(s, "%s <NATIVE BRIDGED>",
+                                                       iaxs[x]->owner ? iaxs[x]->owner->name : "(None)");
+                                       else
+                                               ast_cli(fd, "%s <NATIVE BRIDGED>",
+                                                       iaxs[x]->owner ? iaxs[x]->owner->name : "(None)");
+                               } else
 #endif
                        {
                                int localjitter, localdelay, locallost, locallosspct, localdropped, localooo;
@@ -4705,7 +4727,27 @@ static int ast_cli_netstats(int fd, int limit_fmt)
                                        fmt = "%-25.25s %4d %4d %4d %5d %3d %5d %4d %6d %4d %4d %5d %3d %5d %4d %6d\n";
                                else
                                        fmt = "%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n";
-                               ast_cli(fd, fmt,
+                               if (s)
+                               
+                                       astman_append(s, fmt,
+                                               iaxs[x]->owner ? iaxs[x]->owner->name : "(None)",
+                                               iaxs[x]->pingtime,
+                                               localjitter, 
+                                               localdelay,
+                                               locallost,
+                                               locallosspct,
+                                               localdropped,
+                                               localooo,
+                                               iaxs[x]->frames_received/1000,
+                                               iaxs[x]->remote_rr.jitter,
+                                               iaxs[x]->remote_rr.delay,
+                                               iaxs[x]->remote_rr.losscnt,
+                                               iaxs[x]->remote_rr.losspct,
+                                               iaxs[x]->remote_rr.dropped,
+                                               iaxs[x]->remote_rr.ooo,
+                                               iaxs[x]->remote_rr.packets/1000);
+                               else
+                                       ast_cli(fd, fmt,
                                                iaxs[x]->owner ? iaxs[x]->owner->name : "(None)",
                                                iaxs[x]->pingtime,
                                                localjitter, 
@@ -4738,7 +4780,7 @@ static int iax2_show_netstats(int fd, int argc, char *argv[])
                return RESULT_SHOWUSAGE;
        ast_cli(fd, "                                -------- LOCAL ---------------------  -------- REMOTE --------------------\n");
        ast_cli(fd, "Channel                    RTT  Jit  Del  Lost   %%  Drop  OOO  Kpkts  Jit  Del  Lost   %%  Drop  OOO  Kpkts\n");
-       numchans = ast_cli_netstats(fd, 1);
+       numchans = ast_cli_netstats(NULL, fd, 1);
        ast_cli(fd, "%d active IAX channel%s\n", numchans, (numchans != 1) ? "s" : "");
        return RESULT_SUCCESS;
 }
index 746d1f0..f7085f1 100644 (file)
@@ -7600,9 +7600,9 @@ static int manager_sip_show_peers( struct mansession *s, struct message *m )
 
        astman_send_ack(s, m, "Peer status list will follow");
        /* List the peers in separate manager events */
-       _sip_show_peers(s->fd, &total, s, m, 3, a);
+       _sip_show_peers(-1, &total, s, m, 3, a);
        /* Send final confirmation */
-       ast_cli(s->fd,
+       astman_append(s,
        "Event: PeerlistComplete\r\n"
        "ListItems: %d\r\n"
        "%s"
@@ -7712,7 +7712,7 @@ static int _sip_show_peers(int fd, int *total, struct mansession *s, struct mess
                        realtimepeers ? (ast_test_flag(iterator, SIP_REALTIME) ? "Cached RT":"") : "");
                } else {        /* Manager format */
                        /* The names here need to be the same as other channels */
-                       ast_cli(fd, 
+                       astman_append(s, 
                        "Event: PeerEntry\r\n%s"
                        "Channeltype: SIP\r\n"
                        "ObjectName: %s\r\n"
@@ -8031,9 +8031,9 @@ static int manager_sip_show_peer( struct mansession *s, struct message *m )
        a[3] = peer;
 
        if (!ast_strlen_zero(id))
-               ast_cli(s->fd, "ActionID: %s\r\n",id);
-       ret = _sip_show_peer(1, s->fd, s, m, 4, a );
-       ast_cli( s->fd, "\r\n\r\n" );
+               astman_append(s, "ActionID: %s\r\n",id);
+       ret = _sip_show_peer(1, -1, s, m, 4, a );
+       astman_append(s, "\r\n\r\n" );
        return ret;
 }
 
@@ -8067,7 +8067,7 @@ static int _sip_show_peer(int type, int fd, struct mansession *s, struct message
        peer = find_peer(argv[3], NULL, load_realtime);
        if (s) {        /* Manager */
                if (peer)
-                       ast_cli(s->fd, "Response: Success\r\n");
+                       astman_append(s, "Response: Success\r\n");
                else {
                        snprintf (cbuf, sizeof(cbuf), "Peer %s not found.\n", argv[3]);
                        astman_send_error(s, m, cbuf);
@@ -8161,73 +8161,73 @@ static int _sip_show_peer(int type, int fd, struct mansession *s, struct message
        } else  if (peer && type == 1) { /* manager listing */
                char *actionid = astman_get_header(m,"ActionID");
 
-               ast_cli(fd, "Channeltype: SIP\r\n");
+               astman_append(s, "Channeltype: SIP\r\n");
                if (actionid)
-                       ast_cli(fd, "ActionID: %s\r\n", actionid);
-               ast_cli(fd, "ObjectName: %s\r\n", peer->name);
-               ast_cli(fd, "ChanObjectType: peer\r\n");
-               ast_cli(fd, "SecretExist: %s\r\n", ast_strlen_zero(peer->secret)?"N":"Y");
-               ast_cli(fd, "MD5SecretExist: %s\r\n", ast_strlen_zero(peer->md5secret)?"N":"Y");
-               ast_cli(fd, "Context: %s\r\n", peer->context);
-               ast_cli(fd, "Language: %s\r\n", peer->language);
+                       astman_append(s, "ActionID: %s\r\n", actionid);
+               astman_append(s, "ObjectName: %s\r\n", peer->name);
+               astman_append(s, "ChanObjectType: peer\r\n");
+               astman_append(s, "SecretExist: %s\r\n", ast_strlen_zero(peer->secret)?"N":"Y");
+               astman_append(s, "MD5SecretExist: %s\r\n", ast_strlen_zero(peer->md5secret)?"N":"Y");
+               astman_append(s, "Context: %s\r\n", peer->context);
+               astman_append(s, "Language: %s\r\n", peer->language);
                if (!ast_strlen_zero(peer->accountcode))
-                       ast_cli(fd, "Accountcode: %s\r\n", peer->accountcode);
-               ast_cli(fd, "AMAflags: %s\r\n", ast_cdr_flags2str(peer->amaflags));
-               ast_cli(fd, "CID-CallingPres: %s\r\n", ast_describe_caller_presentation(peer->callingpres));
+                       astman_append(s, "Accountcode: %s\r\n", peer->accountcode);
+               astman_append(s, "AMAflags: %s\r\n", ast_cdr_flags2str(peer->amaflags));
+               astman_append(s, "CID-CallingPres: %s\r\n", ast_describe_caller_presentation(peer->callingpres));
                if (!ast_strlen_zero(peer->fromuser))
-                       ast_cli(fd, "SIP-FromUser: %s\r\n", peer->fromuser);
+                       astman_append(s, "SIP-FromUser: %s\r\n", peer->fromuser);
                if (!ast_strlen_zero(peer->fromdomain))
-                       ast_cli(fd, "SIP-FromDomain: %s\r\n", peer->fromdomain);
-               ast_cli(fd, "Callgroup: ");
+                       astman_append(s, "SIP-FromDomain: %s\r\n", peer->fromdomain);
+               astman_append(s, "Callgroup: ");
                print_group(fd, peer->callgroup, 1);
-               ast_cli(fd, "Pickupgroup: ");
+               astman_append(s, "Pickupgroup: ");
                print_group(fd, peer->pickupgroup, 1);
-               ast_cli(fd, "VoiceMailbox: %s\r\n", peer->mailbox);
-               ast_cli(fd, "LastMsgsSent: %d\r\n", peer->lastmsgssent);
-               ast_cli(fd, "Call limit: %d\r\n", peer->call_limit);
-               ast_cli(fd, "Dynamic: %s\r\n", (ast_test_flag((&peer->flags_page2), SIP_PAGE2_DYNAMIC)?"Y":"N"));
-               ast_cli(fd, "Callerid: %s\r\n", ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, ""));
-               ast_cli(fd, "RegExpire: %ld seconds\r\n", ast_sched_when(sched,peer->expire));
-               ast_cli(fd, "SIP-AuthInsecure: %s\r\n", insecure2str(ast_test_flag(peer, SIP_INSECURE_PORT), ast_test_flag(peer, SIP_INSECURE_INVITE)));
-               ast_cli(fd, "SIP-NatSupport: %s\r\n", nat2str(ast_test_flag(peer, SIP_NAT)));
-               ast_cli(fd, "ACL: %s\r\n", (peer->ha?"Y":"N"));
-               ast_cli(fd, "SIP-CanReinvite: %s\r\n", (ast_test_flag(peer, SIP_CAN_REINVITE)?"Y":"N"));
-               ast_cli(fd, "SIP-PromiscRedir: %s\r\n", (ast_test_flag(peer, SIP_PROMISCREDIR)?"Y":"N"));
-               ast_cli(fd, "SIP-UserPhone: %s\r\n", (ast_test_flag(peer, SIP_USEREQPHONE)?"Y":"N"));
+               astman_append(s, "VoiceMailbox: %s\r\n", peer->mailbox);
+               astman_append(s, "LastMsgsSent: %d\r\n", peer->lastmsgssent);
+               astman_append(s, "Call limit: %d\r\n", peer->call_limit);
+               astman_append(s, "Dynamic: %s\r\n", (ast_test_flag((&peer->flags_page2), SIP_PAGE2_DYNAMIC)?"Y":"N"));
+               astman_append(s, "Callerid: %s\r\n", ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, ""));
+               astman_append(s, "RegExpire: %ld seconds\r\n", ast_sched_when(sched,peer->expire));
+               astman_append(s, "SIP-AuthInsecure: %s\r\n", insecure2str(ast_test_flag(peer, SIP_INSECURE_PORT), ast_test_flag(peer, SIP_INSECURE_INVITE)));
+               astman_append(s, "SIP-NatSupport: %s\r\n", nat2str(ast_test_flag(peer, SIP_NAT)));
+               astman_append(s, "ACL: %s\r\n", (peer->ha?"Y":"N"));
+               astman_append(s, "SIP-CanReinvite: %s\r\n", (ast_test_flag(peer, SIP_CAN_REINVITE)?"Y":"N"));
+               astman_append(s, "SIP-PromiscRedir: %s\r\n", (ast_test_flag(peer, SIP_PROMISCREDIR)?"Y":"N"));
+               astman_append(s, "SIP-UserPhone: %s\r\n", (ast_test_flag(peer, SIP_USEREQPHONE)?"Y":"N"));
 
                /* - is enumerated */
-               ast_cli(fd, "SIP-DTMFmode %s\r\n", dtmfmode2str(ast_test_flag(peer, SIP_DTMF)));
-               ast_cli(fd, "SIPLastMsg: %d\r\n", peer->lastmsg);
-               ast_cli(fd, "ToHost: %s\r\n", peer->tohost);
-               ast_cli(fd, "Address-IP: %s\r\nAddress-Port: %d\r\n",  peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "", ntohs(peer->addr.sin_port));
-               ast_cli(fd, "Default-addr-IP: %s\r\nDefault-addr-port: %d\r\n", ast_inet_ntoa(iabuf, sizeof(iabuf), peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port));
-               ast_cli(fd, "Default-Username: %s\r\n", peer->username);
+               astman_append(s, "SIP-DTMFmode %s\r\n", dtmfmode2str(ast_test_flag(peer, SIP_DTMF)));
+               astman_append(s, "SIPLastMsg: %d\r\n", peer->lastmsg);
+               astman_append(s, "ToHost: %s\r\n", peer->tohost);
+               astman_append(s, "Address-IP: %s\r\nAddress-Port: %d\r\n",  peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "", ntohs(peer->addr.sin_port));
+               astman_append(s, "Default-addr-IP: %s\r\nDefault-addr-port: %d\r\n", ast_inet_ntoa(iabuf, sizeof(iabuf), peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port));
+               astman_append(s, "Default-Username: %s\r\n", peer->username);
                if (!ast_strlen_zero(global_regcontext))
-                       ast_cli(fd, "RegExtension: %s\r\n", peer->regexten);
-               ast_cli(fd, "Codecs: ");
+                       astman_append(s, "RegExtension: %s\r\n", peer->regexten);
+               astman_append(s, "Codecs: ");
                ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability);
-               ast_cli(fd, "%s\r\n", codec_buf);
-               ast_cli(fd, "CodecOrder: ");
+               astman_append(s, "%s\r\n", codec_buf);
+               astman_append(s, "CodecOrder: ");
                pref = &peer->prefs;
                for(x = 0; x < 32 ; x++) {
                        codec = ast_codec_pref_index(pref,x);
                        if (!codec)
                                break;
-                       ast_cli(fd, "%s", ast_getformatname(codec));
+                       astman_append(s, "%s", ast_getformatname(codec));
                        if (x < 31 && ast_codec_pref_index(pref,x+1))
-                               ast_cli(fd, ",");
+                               astman_append(s, ",");
                }
 
-               ast_cli(fd, "\r\n");
-               ast_cli(fd, "Status: ");
+               astman_append(s, "\r\n");
+               astman_append(s, "Status: ");
                peer_status(peer, status, sizeof(status));
-               ast_cli(fd, "%s\r\n", status);
-               ast_cli(fd, "SIP-Useragent: %s\r\n", peer->useragent);
-               ast_cli(fd, "Reg-Contact : %s\r\n", peer->fullcontact);
+               astman_append(s, "%s\r\n", status);
+               astman_append(s, "SIP-Useragent: %s\r\n", peer->useragent);
+               astman_append(s, "Reg-Contact : %s\r\n", peer->fullcontact);
                if (peer->chanvars) {
                        for (v = peer->chanvars ; v ; v = v->next) {
-                               ast_cli(fd, "ChanVariable:\n");
-                               ast_cli(fd, " %s,%s\r\n", v->name, v->value);
+                               astman_append(s, "ChanVariable:\n");
+                               astman_append(s, " %s,%s\r\n", v->name, v->value);
                        }
                }
 
index 6858435..9ce7c5d 100644 (file)
@@ -10251,7 +10251,7 @@ static int action_zapshowchannels(struct mansession *s, struct message *m)
        while (tmp) {
                if (tmp->channel > 0) {
                        int alarm = get_alarms(tmp);
-                       ast_cli(s->fd,
+                       astman_append(s,
                                "Event: ZapShowChannels\r\n"
                                "Channel: %d\r\n"
                                "Signalling: %s\r\n"
@@ -10270,7 +10270,7 @@ static int action_zapshowchannels(struct mansession *s, struct message *m)
 
        ast_mutex_unlock(&iflock);
        
-       ast_cli(s->fd, 
+       astman_append(s, 
                "Event: ZapShowChannelsComplete\r\n"
                "%s"
                "\r\n", 
diff --git a/configs/http.conf.sample b/configs/http.conf.sample
new file mode 100644 (file)
index 0000000..0b1f38b
--- /dev/null
@@ -0,0 +1,23 @@
+;
+; Asterisk Builtin mini-HTTP server
+;
+;
+[general]
+;
+; Whether HTTP interface is enabled or not.
+;
+enabled=yes
+;
+; Address to bind to
+;
+bindaddr=127.0.0.1
+;
+; Port to bind to
+;
+bindport=8088
+;
+; Prefix allows you to specify a prefix for all requests
+; to the server.  The default is "asterisk" so that all
+; requests must begin with /asterisk
+;
+;prefix=asterisk
diff --git a/db.c b/db.c
index 522e3de..93d23d0 100644 (file)
--- a/db.c
+++ b/db.c
@@ -568,7 +568,7 @@ static int manager_dbget(struct mansession *s, struct message *m)
                astman_send_error(s, m, "Database entry not found");
        } else {
                astman_send_ack(s, m, "Result will follow");
-               ast_cli(s->fd, "Event: DBGetResponse\r\n"
+               astman_append(s, "Event: DBGetResponse\r\n"
                                "Family: %s\r\n"
                                "Key: %s\r\n"
                                "Val: %s\r\n"
diff --git a/http.c b/http.c
new file mode 100644 (file)
index 0000000..c2c6ef0
--- /dev/null
+++ b/http.c
@@ -0,0 +1,463 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2006, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/signal.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <asterisk/cli.h>
+#include <asterisk/http.h>
+#include <asterisk/utils.h>
+#include <asterisk/strings.h>
+
+#define MAX_PREFIX 80
+#define DEFAULT_PREFIX "asterisk"
+
+/* This program implements a tiny http server supporting the "get" method
+   only and was inspired by micro-httpd by Jef Poskanzer */
+
+struct ast_http_server_instance {
+       FILE *f;
+       int fd;
+       struct sockaddr_in requestor;
+       ast_http_callback callback;
+};
+
+static struct ast_http_uri *uris;
+
+static int httpfd = -1;
+static pthread_t master = AST_PTHREADT_NULL;
+static char prefix[MAX_PREFIX];
+static int prefix_len = 0;
+static struct sockaddr_in oldsin;
+
+
+static char *httpstatus_callback(struct sockaddr_in *req, const char *uri, struct ast_variable *vars, int *status, char **title, int *contentlength)
+{
+       char result[4096];
+       int reslen = sizeof(result);
+       char *c=result;
+       struct ast_variable *v;
+       char iabuf[INET_ADDRSTRLEN];
+
+       ast_build_string(&c, &reslen,
+               "\r\n"
+               "<title>Asterisk HTTP Status</title>\r\n"
+               "<body bgcolor=\"#ffffff\">\r\n"
+               "<table bgcolor=\"#f1f1f1\" align=\"center\"><tr><td bgcolor=\"#e0e0ff\" colspan=\"2\" width=\"500\">\r\n"
+               "<h2>&nbsp;&nbsp;Asterisk&trade; HTTP Status</h2></td></tr>\r\n");
+
+       ast_build_string(&c, &reslen, "<tr><td><i>Prefix</i></td><td><b>%s</b></td></tr>\r\n", prefix);
+       ast_build_string(&c, &reslen, "<tr><td><i>Bind Address</i></td><td><b>%s</b></td></tr>\r\n",
+                       ast_inet_ntoa(iabuf, sizeof(iabuf), oldsin.sin_addr));
+       ast_build_string(&c, &reslen, "<tr><td><i>Bind Port</i></td><td><b>%d</b></td></tr>\r\n",
+                       ntohs(oldsin.sin_port));
+       ast_build_string(&c, &reslen, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
+       v = vars;
+       while(v) {
+               ast_build_string(&c, &reslen, "<tr><td><i>Submitted Variable '%s'</i></td><td>%s</td></tr>\r\n", v->name, v->value);
+               v = v->next;
+       }
+       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");
+       return strdup(result);
+}
+
+static struct ast_http_uri statusuri = {
+       .callback = httpstatus_callback,
+       .description = "Asterisk HTTP General Status",
+       .uri = "httpstatus",
+       .has_subtree = 0,
+};
+       
+char *ast_http_error(int status, const char *title, const char *extra_header, const char *text)
+{
+       char *c = NULL;
+       asprintf(&c,
+               "Content-type: text/html\r\n"
+               "%s"
+               "\r\n"
+               "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
+               "<html><head>\r\n"
+               "<title>%d %s</title>\r\n"
+               "</head><body>\r\n"
+               "<h1>%s</h1>\r\n"
+               "<p>%s</p>\r\n"
+               "<hr />\r\n"
+               "<address>Asterisk Server</address>\r\n"
+               "</body></html>\r\n",
+                       (extra_header ? extra_header : ""), status, title, title, text);
+       return c;
+}
+
+int ast_http_uri_link(struct ast_http_uri *urih)
+{
+       struct ast_http_uri *prev=uris;
+       if (!uris || strlen(uris->uri) <= strlen(urih->uri)) {
+               urih->next = uris;
+               uris = urih;
+       } else {
+               while (prev->next && (strlen(prev->next->uri) > strlen(urih->uri)))
+                       prev = prev->next;
+               /* Insert it here */
+               urih->next = prev->next;
+               prev->next = urih;
+       }
+       return 0;
+}      
+
+void ast_http_uri_unlink(struct ast_http_uri *urih)
+{
+       struct ast_http_uri *prev = uris;
+       if (!uris)
+               return;
+       if (uris == urih) {
+               uris = uris->next;
+       }
+       while(prev->next) {
+               if (prev->next == urih) {
+                       prev->next = urih->next;
+                       break;
+               }
+               prev = prev->next;
+       }
+}
+
+static char *handle_uri(struct sockaddr_in *sin, char *uri, int *status, char **title, int *contentlength)
+{
+       char *c;
+       char *turi;
+       char *params;
+       char *var;
+       char *val;
+       struct ast_http_uri *urih=NULL;
+       int len;
+       struct ast_variable *vars=NULL, *v, *prev = NULL;
+       
+       
+       if (*uri == '/')
+               uri++;
+       params = strchr(uri, '?');
+       if (params) {
+               *params = '\0';
+               params++;
+               while ((var = strsep(&params, "&"))) {
+                       val = strchr(var, '=');
+                       if (val) {
+                               *val = '\0';
+                               val++;
+                       } else 
+                               val = "";
+                       ast_uri_decode(val);
+                       ast_uri_decode(var);
+                       if ((v = ast_variable_new(var, val))) {
+                               if (vars)
+                                       prev->next = v;
+                               else
+                                       vars = v;
+                               prev = v;
+                       }
+               }
+       }
+       ast_uri_decode(uri);
+       if (!strncasecmp(uri, prefix, prefix_len)) {
+               uri += prefix_len;
+               if (!*uri || (*uri == '/')) {
+                       if (*uri == '/')
+                               uri++;
+                       urih = uris;
+                       while(urih) {
+                               len = strlen(urih->uri);
+                               if (!strncasecmp(urih->uri, uri, len)) {
+                                       if (!uri[len] || uri[len] == '/') {
+                                               turi = uri + len;
+                                               if (*turi == '/')
+                                                       turi++;
+                                               if (!*turi || urih->has_subtree) {
+                                                       uri = turi;
+                                                       break;
+                                               }
+                                       }
+                               }
+                               urih = urih->next;
+                       }
+               }
+       }
+       if (urih) {
+               c = urih->callback(sin, uri, vars, status, title, contentlength);
+               ast_variables_destroy(vars);
+       } else {
+               c = ast_http_error(404, "Not Found", NULL, "The requested URL was not found on this serer.");
+               *status = 404;
+               *title = strdup("Not Found");
+       }
+       return c;
+}
+
+static void *ast_httpd_helper_thread(void *data)
+{
+       char buf[4096];
+       char timebuf[256];
+       struct ast_http_server_instance *ser = data;
+       char *uri, *c, *title=NULL;
+       int status = 200, contentlength = 0;
+       time_t t;
+
+       if (fgets(buf, sizeof(buf), ser->f)) {
+               /* Skip method */
+               uri = buf;
+               while(*uri && (*uri > 32)) uri++;
+               if (*uri) {
+                       *uri = '\0';
+                       uri++;
+               }
+
+               /* Skip white space */
+               while (*uri && (*uri < 33)) uri++;
+
+               if (*uri) {
+                       c = uri;
+                       while (*c && (*c > 32)) c++;
+                       if (*c) {
+                               *c = '\0';
+                       }
+               }
+               if (*uri) {
+                       if (!strcasecmp(buf, "get")) 
+                               c = handle_uri(&ser->requestor, uri, &status, &title, &contentlength);
+                       else 
+                               c = ast_http_error(501, "Not Implemented", NULL, "Attempt to use unimplemented / unsupported method");\
+               } else 
+                       c = ast_http_error(400, "Bad Request", NULL, "Invalid Request");
+               if (!c)
+                       c = ast_http_error(500, "Internal Error", NULL, "Internal Server Error");
+               if (c) {
+                       time(&t);
+                       strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
+                       ast_cli(ser->fd, "HTTP/1.1 GET %d %s\r\n", status, title ? title : "OK");
+                       ast_cli(ser->fd, "Server: Asterisk\r\n");
+                       ast_cli(ser->fd, "Date: %s\r\n", timebuf);
+                       if (contentlength)
+                               ast_cli(ser->fd, "Content-length: %d\r\n", contentlength);
+                       ast_cli(ser->fd, "Connection: close\r\n");
+                       ast_cli(ser->fd, "%s", c);
+                       free(c);
+               }
+               if (title)
+                       free(title);
+       }
+       fclose(ser->f);
+       free(ser);
+       return NULL;
+}
+
+static void *http_root(void *data)
+{
+       int fd;
+       struct sockaddr_in sin;
+       int sinlen;
+       struct ast_http_server_instance *ser;
+       pthread_t launched;
+       for (;;) {
+               ast_wait_for_input(httpfd, -1);
+               sinlen = sizeof(sin);
+               fd = accept(httpfd, (struct sockaddr *)&sin, &sinlen);
+               if (fd < 0) {
+                       if ((errno != EAGAIN) && (errno != EINTR))
+                               ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno));
+                       continue;
+               }
+               ser = calloc(1, sizeof(*ser));
+               if (ser) {
+                       ser->fd = fd;
+                       if ((ser->f = fdopen(ser->fd, "w+"))) {
+                               if (ast_pthread_create(&launched, NULL, ast_httpd_helper_thread, ser)) {
+                                       ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
+                                       fclose(ser->f);
+                                       free(ser);
+                               }
+                       } else {
+                               ast_log(LOG_WARNING, "fdopen failed!\n");
+                               close(ser->fd);
+                               free(ser);
+                       }
+               } else {
+                       ast_log(LOG_WARNING, "Out of memory!\n");
+                       close(fd);
+               }
+       }
+       return NULL;
+}
+
+static void http_server_start(struct sockaddr_in *sin)
+{
+       char iabuf[INET_ADDRSTRLEN];
+       int flags;
+       int x = 1;
+       
+       /* Do nothing if nothing has changed */
+       if (!memcmp(&oldsin, sin, sizeof(oldsin))) {
+               ast_log(LOG_DEBUG, "Nothing changed in http\n");
+               return;
+       }
+       
+       memcpy(&oldsin, sin, sizeof(oldsin));
+       
+       /* Shutdown a running server if there is one */
+       if (master != AST_PTHREADT_NULL) {
+               pthread_cancel(master);
+               pthread_kill(master, SIGURG);
+               pthread_join(master, NULL);
+       }
+       
+       if (httpfd != -1)
+               close(httpfd);
+
+       /* If there's no new server, stop here */
+       if (!sin->sin_family)
+               return;
+       
+       
+       httpfd = socket(AF_INET, SOCK_STREAM, 0);
+       if (httpfd < 0) {
+               ast_log(LOG_WARNING, "Unable to allocate socket: %s\n", strerror(errno));
+               return;
+       }
+       
+       setsockopt(httpfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
+       if (bind(httpfd, (struct sockaddr *)sin, sizeof(*sin))) {
+               ast_log(LOG_NOTICE, "Unable to bind http server to %s:%d: %s\n",
+                       ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port),
+                       strerror(errno));
+               close(httpfd);
+               httpfd = -1;
+               return;
+       }
+       if (listen(httpfd, 10)) {
+               ast_log(LOG_NOTICE, "Unable to listen!\n");
+               close(httpfd);
+               httpfd = -1;
+               return;
+       }
+       flags = fcntl(httpfd, F_GETFL);
+       fcntl(httpfd, F_SETFL, flags | O_NONBLOCK);
+       if (ast_pthread_create(&master, NULL, http_root, NULL)) {
+               ast_log(LOG_NOTICE, "Unable to launch http server on %s:%d: %s\n",
+                               ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port),
+                               strerror(errno));
+               close(httpfd);
+               httpfd = -1;
+       }
+}
+
+static int __ast_http_load(int reload)
+{
+       struct ast_config *cfg;
+       struct ast_variable *v;
+       int enabled=0;
+       struct sockaddr_in sin;
+       struct hostent *hp;
+       struct ast_hostent ahp;
+       char newprefix[MAX_PREFIX];
+       memset(&sin, 0, sizeof(sin));
+       sin.sin_port = 8088;
+       strcpy(newprefix, DEFAULT_PREFIX);
+       cfg = ast_config_load("http.conf");
+       if (cfg) {
+               v = ast_variable_browse(cfg, "general");
+               while(v) {
+                       if (!strcasecmp(v->name, "enabled"))
+                               enabled = ast_true(v->value);
+                       else if (!strcasecmp(v->name, "bindport"))
+                               sin.sin_port = ntohs(atoi(v->value));
+                       else if (!strcasecmp(v->name, "bindaddr")) {
+                               if ((hp = ast_gethostbyname(v->value, &ahp))) {
+                                       memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
+                               } else {
+                                       ast_log(LOG_WARNING, "Invalid bind address '%s'\n", v->value);
+                               }
+                       } else if (!strcasecmp(v->name, "prefix"))
+                               ast_copy_string(newprefix, v->value, sizeof(newprefix));
+                       v = v->next;
+               }
+               ast_config_destroy(cfg);
+       }
+       if (enabled)
+               sin.sin_family = AF_INET;
+       if (strcmp(prefix, newprefix)) {
+               ast_copy_string(prefix, newprefix, sizeof(prefix));
+               prefix_len = strlen(prefix);
+       }
+       http_server_start(&sin);
+       return 0;
+}
+
+static int handle_show_http(int fd, int argc, char *argv[])
+{
+       char iabuf[INET_ADDRSTRLEN];
+       struct ast_http_uri *urih;
+       if (argc != 2)
+               return RESULT_SHOWUSAGE;
+       ast_cli(fd, "HTTP Server Status:\n");
+       ast_cli(fd, "Prefix: %s\n", prefix);
+       if (oldsin.sin_family)
+               ast_cli(fd, "Server Enabled and Bound to %s:%d\n\n",
+                       ast_inet_ntoa(iabuf, sizeof(iabuf), oldsin.sin_addr),
+                       ntohs(oldsin.sin_port));
+       else
+               ast_cli(fd, "Server Disabled\n\n");
+       ast_cli(fd, "Enabled URI's:\n");
+       urih = uris;
+       while(urih){
+               ast_cli(fd, "/%s/%s%s => %s\n", prefix, urih->uri, (urih->has_subtree ? "/..." : "" ), urih->description);
+               urih = urih->next;
+       }
+       if (!uris)
+               ast_cli(fd, "None.\n");
+       return RESULT_SUCCESS;
+}
+
+int ast_http_reload(void)
+{
+       return __ast_http_load(1);
+}
+
+static char show_http_help[] =
+"Usage: show http\n"
+"       Shows status of internal HTTP engine\n";
+
+static struct ast_cli_entry http_cli[] = {
+       { { "show", "http", NULL }, handle_show_http,
+         "Display HTTP status", show_http_help },
+};
+
+int ast_http_init(void)
+{
+       ast_http_uri_link(&statusuri);
+       ast_cli_register_multiple(http_cli, sizeof(http_cli) / sizeof(http_cli[0]));
+       return __ast_http_load(0);
+}
diff --git a/include/asterisk/http.h b/include/asterisk/http.h
new file mode 100644 (file)
index 0000000..ea580c3
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2006, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*
+ * DNS SRV record support
+ */
+
+#ifndef _ASTERISK_HTTP_H
+#define _ASTERISK_HTTP_H
+
+#include "asterisk/config.h"
+
+/*!
+  \file http.h
+  \brief Support for Private Asterisk HTTP Servers.
+  \note Note: The Asterisk HTTP servers are extremely simple and minimal and
+        only support the "GET" method.
+*/
+
+/* HTTP Callbacks take the socket, the method and the path as arguments and should
+   return the content, allocated with malloc().  Status should be changed to reflect
+   the status of the request if it isn't 200 and title may be set to a malloc()'d string
+   to an appropriate title for non-200 responses.  Content length may also be specified. 
+   The return value may include additional headers at the front and MUST include a blank 
+   line with \r\n to provide separation between user headers and content (even if no
+   content is specified) */
+typedef char *(*ast_http_callback)(struct sockaddr_in *requestor, const char *uri, struct ast_variable *params, int *status, char **title, int *contentlength);
+
+struct ast_http_uri {
+       struct ast_http_uri *next;
+       const char *description;
+       const char *uri;
+       int has_subtree;
+       ast_http_callback callback;
+};
+
+/* Link into the Asterisk HTTP server */
+int ast_http_uri_link(struct ast_http_uri *urihandler);
+
+/* Return a malloc()'d string containing an HTTP error message */
+char *ast_http_error(int status, const char *title, const char *extra_header, const char *text);
+
+/* Destroy an HTTP server */
+void ast_http_uri_unlink(struct ast_http_uri *urihandler);
+
+int ast_http_init(void);
+int ast_http_reload(void);
+
+#endif /* _ASTERISK_SRV_H */
index 523ccfa..53f82f4 100644 (file)
@@ -64,40 +64,7 @@ struct eventqent {
        char eventdata[1];
 };
 
-struct mansession {
-       /*! Execution thread */
-       pthread_t t;
-       /*! Thread lock -- don't use in action callbacks, it's already taken care of  */
-       ast_mutex_t __lock;
-       /*! socket address */
-       struct sockaddr_in sin;
-       /*! TCP socket */
-       int fd;
-       /*! Whether or not we're busy doing an action */
-       int busy;
-       /*! Whether or not we're "dead" */
-       int dead;
-       /*! Logged in username */
-       char username[80];
-       /*! Authentication challenge */
-       char challenge[10];
-       /*! Authentication status */
-       int authenticated;
-       /*! Authorization for reading */
-       int readperm;
-       /*! Authorization for writing */
-       int writeperm;
-       /*! Buffer */
-       char inbuf[AST_MAX_MANHEADER_LEN];
-       int inlen;
-       int send_events;
-       /* Queued events that we've not had the ability to send yet */
-       struct eventqent *eventq;
-       /* Timeout for ast_carefulwrite() */
-       int writetimeout;
-       struct mansession *next;
-};
-
+struct mansession;
 
 struct message {
        int hdrcount;
@@ -164,6 +131,10 @@ extern void astman_send_error(struct mansession *s, struct message *m, char *err
 extern void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg);
 extern void astman_send_ack(struct mansession *s, struct message *m, char *msg);
 
+extern void astman_append(struct mansession *s, const char *fmt, ...)
+        __attribute__ ((format (printf, 2, 3)));
+
+
 /*! Called by Asterisk initialization */
 extern int init_manager(void);
 /*! Called by Asterisk initialization */
index 2639b98..d93f6fb 100644 (file)
--- a/loader.c
+++ b/loader.c
@@ -43,6 +43,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/cdr.h"
 #include "asterisk/enum.h"
 #include "asterisk/rtp.h"
+#include "asterisk/http.h"
 #include "asterisk/lock.h"
 #ifdef DLFCNCOMPAT
 #include "asterisk/dlfcn-compat.h"
@@ -115,6 +116,7 @@ static struct reload_classes_t {
        { "enum",       ast_enum_reload },
        { "manager",    reload_manager },
        { "rtp",        ast_rtp_reload },
+       { "http",       ast_http_reload },
        { NULL, NULL }
 };
 
index 81c67ff..47badec 100644 (file)
--- a/manager.c
+++ b/manager.c
@@ -106,7 +106,40 @@ static struct permalias {
        { 0, "none" },
 };
 
-static struct mansession *sessions = NULL;
+static struct mansession {
+       /*! Execution thread */
+       pthread_t t;
+       /*! Thread lock -- don't use in action callbacks, it's already taken care of  */
+       ast_mutex_t __lock;
+       /*! socket address */
+       struct sockaddr_in sin;
+       /*! TCP socket */
+       int fd;
+       /*! Whether or not we're busy doing an action */
+       int busy;
+       /*! Whether or not we're "dead" */
+       int dead;
+       /*! Logged in username */
+       char username[80];
+       /*! Authentication challenge */
+       char challenge[10];
+       /*! Authentication status */
+       int authenticated;
+       /*! Authorization for reading */
+       int readperm;
+       /*! Authorization for writing */
+       int writeperm;
+       /*! Buffer */
+       char inbuf[AST_MAX_MANHEADER_LEN];
+       int inlen;
+       int send_events;
+       /* Queued events that we've not had the ability to send yet */
+       struct eventqent *eventq;
+       /* Timeout for ast_carefulwrite() */
+       int writetimeout;
+       struct mansession *next;
+} *sessions = NULL;
+
 static struct manager_action *first_action = NULL;
 AST_MUTEX_DEFINE_STATIC(actionlock);
 
@@ -182,6 +215,23 @@ static char *complete_show_mancmd(const char *line, const char *word, int pos, i
        return NULL;
 }
 
+void astman_append(struct mansession *s, const char *fmt, ...)
+{
+       char *stuff;
+       int res;
+       va_list ap;
+
+       va_start(ap, fmt);
+       res = vasprintf(&stuff, fmt, ap);
+       va_end(ap);
+       if (res == -1) {
+               ast_log(LOG_ERROR, "Memory allocation failure\n");
+       } else {
+               ast_carefulwrite(s->fd, stuff, strlen(stuff), 100);
+               free(stuff);
+       }
+}
+
 static int handle_showmancmd(int fd, int argc, char *argv[])
 {
        struct manager_action *cur = first_action;
@@ -370,23 +420,23 @@ void astman_send_error(struct mansession *s, struct message *m, char *error)
 {
        char *id = astman_get_header(m,"ActionID");
 
-       ast_cli(s->fd, "Response: Error\r\n");
+       astman_append(s, "Response: Error\r\n");
        if (!ast_strlen_zero(id))
-               ast_cli(s->fd, "ActionID: %s\r\n",id);
-       ast_cli(s->fd, "Message: %s\r\n\r\n", error);
+               astman_append(s, "ActionID: %s\r\n",id);
+       astman_append(s, "Message: %s\r\n\r\n", error);
 }
 
 void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg)
 {
        char *id = astman_get_header(m,"ActionID");
 
-       ast_cli(s->fd, "Response: %s\r\n", resp);
+       astman_append(s, "Response: %s\r\n", resp);
        if (!ast_strlen_zero(id))
-               ast_cli(s->fd, "ActionID: %s\r\n",id);
+               astman_append(s, "ActionID: %s\r\n",id);
        if (msg)
-               ast_cli(s->fd, "Message: %s\r\n\r\n", msg);
+               astman_append(s, "Message: %s\r\n\r\n", msg);
        else
-               ast_cli(s->fd, "\r\n");
+               astman_append(s, "\r\n");
 }
 
 void astman_send_ack(struct mansession *s, struct message *m, char *msg)
@@ -610,15 +660,15 @@ static int action_listcommands(struct mansession *s, struct message *m)
 
        if (!ast_strlen_zero(id))
                snprintf(idText,256,"ActionID: %s\r\n",id);
-       ast_cli(s->fd, "Response: Success\r\n%s", idText);
+       astman_append(s, "Response: Success\r\n%s", idText);
        ast_mutex_lock(&actionlock);
        while (cur) { /* Walk the list of actions */
                if ((s->writeperm & cur->authority) == cur->authority)
-                       ast_cli(s->fd, "%s: %s (Priv: %s)\r\n", cur->action, cur->synopsis, authority_to_str(cur->authority, temp, sizeof(temp)) );
+                       astman_append(s, "%s: %s (Priv: %s)\r\n", cur->action, cur->synopsis, authority_to_str(cur->authority, temp, sizeof(temp)) );
                cur = cur->next;
        }
        ast_mutex_unlock(&actionlock);
-       ast_cli(s->fd, "\r\n");
+       astman_append(s, "\r\n");
 
        return 0;
 }
@@ -758,11 +808,11 @@ static int action_getvar(struct mansession *s, struct message *m)
 
        if (c)
                ast_mutex_unlock(&c->lock);
-       ast_cli(s->fd, "Response: Success\r\n"
+       astman_append(s, "Response: Success\r\n"
                "Variable: %s\r\nValue: %s\r\n", varname, varval);
        if (!ast_strlen_zero(id))
-               ast_cli(s->fd, "ActionID: %s\r\n",id);
-       ast_cli(s->fd, "\r\n");
+               astman_append(s, "ActionID: %s\r\n",id);
+       astman_append(s, "\r\n");
 
        return 0;
 }
@@ -803,7 +853,7 @@ static int action_status(struct mansession *s, struct message *m)
                        if (c->cdr) {
                                elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
                        }
-                       ast_cli(s->fd,
+                       astman_append(s,
                        "Event: Status\r\n"
                        "Privilege: Call\r\n"
                        "Channel: %s\r\n"
@@ -826,7 +876,7 @@ static int action_status(struct mansession *s, struct message *m)
                        ast_state2str(c->_state), c->context,
                        c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, idText);
                } else {
-                       ast_cli(s->fd,
+                       astman_append(s,
                        "Event: Status\r\n"
                        "Privilege: Call\r\n"
                        "Channel: %s\r\n"
@@ -849,7 +899,7 @@ static int action_status(struct mansession *s, struct message *m)
                        break;
                c = ast_channel_walk_locked(c);
        }
-       ast_cli(s->fd,
+       astman_append(s,
        "Event: StatusComplete\r\n"
        "%s"
        "\r\n",idText);
@@ -930,12 +980,12 @@ static int action_command(struct mansession *s, struct message *m)
 {
        char *cmd = astman_get_header(m, "Command");
        char *id = astman_get_header(m, "ActionID");
-       ast_cli(s->fd, "Response: Follows\r\nPrivilege: Command\r\n");
+       astman_append(s, "Response: Follows\r\nPrivilege: Command\r\n");
        if (!ast_strlen_zero(id))
-               ast_cli(s->fd, "ActionID: %s\r\n", id);
+               astman_append(s, "ActionID: %s\r\n", id);
        /* FIXME: Wedge a ActionID response in here, waiting for later changes */
        ast_cli_command(s->fd, cmd);
-       ast_cli(s->fd, "--END COMMAND--\r\n\r\n");
+       astman_append(s, "--END COMMAND--\r\n\r\n");
        return 0;
 }
 
@@ -1130,7 +1180,7 @@ static int action_mailboxstatus(struct mansession *s, struct message *m)
         if (!ast_strlen_zero(id))
                 snprintf(idText,256,"ActionID: %s\r\n",id);
        ret = ast_app_has_voicemail(mailbox, NULL);
-       ast_cli(s->fd, "Response: Success\r\n"
+       astman_append(s, "Response: Success\r\n"
                                   "%s"
                                   "Message: Mailbox Status\r\n"
                                   "Mailbox: %s\r\n"
@@ -1163,7 +1213,7 @@ static int action_mailboxcount(struct mansession *s, struct message *m)
        if (!ast_strlen_zero(id)) {
                snprintf(idText,256,"ActionID: %s\r\n",id);
        }
-       ast_cli(s->fd, "Response: Success\r\n"
+       astman_append(s, "Response: Success\r\n"
                                   "%s"
                                   "Message: Mailbox Message Count\r\n"
                                   "Mailbox: %s\r\n"
@@ -1204,7 +1254,7 @@ static int action_extensionstate(struct mansession *s, struct message *m)
         if (!ast_strlen_zero(id)) {
                 snprintf(idText,256,"ActionID: %s\r\n",id);
         }
-       ast_cli(s->fd, "Response: Success\r\n"
+       astman_append(s, "Response: Success\r\n"
                                   "%s"
                                   "Message: Extension Status\r\n"
                                   "Exten: %s\r\n"
@@ -1261,9 +1311,9 @@ static int process_message(struct mansession *s, struct message *m)
                astman_send_error(s, m, "Missing action in request");
                return 0;
        }
-        if (!ast_strlen_zero(id)) {
-                snprintf(idText,256,"ActionID: %s\r\n",id);
-        }
+       if (!ast_strlen_zero(id)) {
+               snprintf(idText,256,"ActionID: %s\r\n",id);
+       }
        if (!s->authenticated) {
                if (!strcasecmp(action, "Challenge")) {
                        char *authtype;
@@ -1272,7 +1322,7 @@ static int process_message(struct mansession *s, struct message *m)
                                if (ast_strlen_zero(s->challenge))
                                        snprintf(s->challenge, sizeof(s->challenge), "%d", rand());
                                ast_mutex_lock(&s->__lock);
-                               ast_cli(s->fd, "Response: Success\r\n"
+                               astman_append(s, "Response: Success\r\n"
                                                "%s"
                                                "Challenge: %s\r\n\r\n",
                                                idText,s->challenge);
@@ -1396,7 +1446,7 @@ static void *session_do(void *data)
        int res;
        
        ast_mutex_lock(&s->__lock);
-       ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n");
+       astman_append(s, "Asterisk Call Manager/1.0\r\n");
        ast_mutex_unlock(&s->__lock);
        memset(&m, 0, sizeof(m));
        for (;;) {
index 0787ec8..68675bd 100644 (file)
@@ -1897,7 +1897,7 @@ static int manager_parking_status( struct mansession *s, struct message *m )
 
         cur=parkinglot;
         while(cur) {
-                       ast_cli(s->fd, "Event: ParkedCall\r\n"
+                       astman_append(s, "Event: ParkedCall\r\n"
                        "Exten: %d\r\n"
                        "Channel: %s\r\n"
                        "From: %s\r\n"
@@ -1915,7 +1915,7 @@ static int manager_parking_status( struct mansession *s, struct message *m )
             cur = cur->next;
         }
 
-       ast_cli(s->fd,
+       astman_append(s,
        "Event: ParkedCallsComplete\r\n"
        "%s"
        "\r\n",idText);
index e62e6fb..871a74d 100644 (file)
@@ -31,7 +31,7 @@ int res_snmp_agentx_subagent;
 int res_snmp_dont_stop;
 int res_snmp_enabled;
 
-static pthread_t thread;
+static pthread_t thread = AST_PTHREADT_NULL;
 
 static int load_config(void)
 {
@@ -111,8 +111,9 @@ int reload(void)
     ast_verbose(VERBOSE_PREFIX_1 "Reloading [Sub]Agent Module\n");
 
     res_snmp_dont_stop = 0;
-    pthread_join(thread, NULL);
-
+       if (thread != AST_PTHREADT_NULL)
+           pthread_join(thread, NULL);
+       thread = AST_PTHREADT_NULL;
     load_config();
 
     res_snmp_dont_stop = 1;