From 9164eac21a1cce9c9f205e7a5a939346de55bf5f Mon Sep 17 00:00:00 2001 From: Mark Spencer <markster@digium.com> Date: Sat, 25 Mar 2006 23:50:09 +0000 Subject: [PATCH] Add micro-http server and abstract manager interface, make snmp not die on reload. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@14953 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- Makefile | 2 +- apps/app_queue.c | 80 +++++-- asterisk.c | 5 +- channels/chan_agent.c | 4 +- channels/chan_iax2.c | 84 +++++-- channels/chan_sip.c | 106 ++++----- channels/chan_zap.c | 4 +- configs/http.conf.sample | 23 ++ db.c | 2 +- http.c | 463 +++++++++++++++++++++++++++++++++++++ include/asterisk/http.h | 64 +++++ include/asterisk/manager.h | 39 +--- loader.c | 2 + manager.c | 106 ++++++--- res/res_features.c | 4 +- res/res_snmp.c | 7 +- 16 files changed, 823 insertions(+), 172 deletions(-) create mode 100644 configs/http.conf.sample create mode 100644 http.c create mode 100644 include/asterisk/http.h diff --git a/Makefile b/Makefile index bec360ae49..4414a76708 100644 --- 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 diff --git a/apps/app_queue.c b/apps/app_queue.c index 072024ba77..b935951ec8 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -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); diff --git a/asterisk.c b/asterisk.c index e26e6a517a..72c28358e4 100644 --- a/asterisk.c +++ b/asterisk.c @@ -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()); diff --git a/channels/chan_agent.c b/channels/chan_agent.c index b2fc203f91..e548f71827 100644 --- a/channels/chan_agent.c +++ b/channels/chan_agent.c @@ -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; diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index d8995c696d..69fccbb044 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -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(®exbuf); @@ -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; } diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 746d1f0b2b..f7085f1000 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -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); } } diff --git a/channels/chan_zap.c b/channels/chan_zap.c index 6858435ce1..9ce7c5d55f 100644 --- a/channels/chan_zap.c +++ b/channels/chan_zap.c @@ -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 index 0000000000..0b1f38be24 --- /dev/null +++ b/configs/http.conf.sample @@ -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 522e3de1c3..93d23d0322 100644 --- 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 index 0000000000..c2c6ef09f3 --- /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> Asterisk™ 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(¶ms, "&"))) { + 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 index 0000000000..ea580c3ca8 --- /dev/null +++ b/include/asterisk/http.h @@ -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 */ diff --git a/include/asterisk/manager.h b/include/asterisk/manager.h index 523ccfaae6..53f82f4678 100644 --- a/include/asterisk/manager.h +++ b/include/asterisk/manager.h @@ -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 */ diff --git a/loader.c b/loader.c index 2639b98c57..d93f6fb31f 100644 --- 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 } }; diff --git a/manager.c b/manager.c index 81c67ff865..47badecace 100644 --- 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 (;;) { diff --git a/res/res_features.c b/res/res_features.c index 0787ec8625..68675bd6d5 100644 --- a/res/res_features.c +++ b/res/res_features.c @@ -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); diff --git a/res/res_snmp.c b/res/res_snmp.c index e62e6fb05d..871a74da6c 100644 --- a/res/res_snmp.c +++ b/res/res_snmp.c @@ -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; -- GitLab