c5f57384f070f7811f0a24320c7752e11cf60f29
[asterisk/asterisk.git] / manager.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Channel Management and more
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <pthread.h>
17 #include <string.h>
18 #include <sys/time.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <signal.h>
23 #include <errno.h>
24 #include <unistd.h>
25 #include <asterisk/channel.h>
26 #include <asterisk/file.h>
27 #include <asterisk/manager.h>
28 #include <asterisk/config.h>
29 #include <asterisk/lock.h>
30 #include <asterisk/logger.h>
31 #include <asterisk/options.h>
32 #include <asterisk/cli.h>
33 #include <asterisk/pbx.h>
34
35 static int enabled = 0;
36 static int portno = DEFAULT_MANAGER_PORT;
37 static int asock = -1;
38 static pthread_t t;
39 static pthread_mutex_t sessionlock = AST_MUTEX_INITIALIZER;
40
41 static struct permalias {
42         int num;
43         char *label;
44 } perms[] = {
45         { EVENT_FLAG_SYSTEM, "system" },
46         { EVENT_FLAG_CALL, "call" },
47         { EVENT_FLAG_LOG, "log" },
48         { EVENT_FLAG_VERBOSE, "verbose" },
49         { EVENT_FLAG_COMMAND, "command" },
50         { EVENT_FLAG_AGENT, "agent" },
51         { -1, "all" },
52 };
53
54 static struct mansession *sessions = NULL;
55 static struct manager_action *first_action = NULL;
56 static pthread_mutex_t actionlock = AST_MUTEX_INITIALIZER;
57
58 static int handle_showmancmds(int fd, int argc, char *argv[])
59 {
60         struct manager_action *cur = first_action;
61
62         ast_pthread_mutex_lock(&actionlock);
63         while(cur) { /* Walk the list of actions */
64                 ast_cli(fd, "\t%s  %s\r\n",cur->action, cur->synopsis);
65                 cur = cur->next;
66         }
67
68         ast_pthread_mutex_unlock(&actionlock);
69         return RESULT_SUCCESS;
70 }
71
72 static char showmancmds_help[] = 
73 "Usage: show manager commands\n"
74 "       Prints a listing of all the available manager commands.\n";
75
76 static struct ast_cli_entry show_mancmds_cli =
77         { { "show", "manager", "commands", NULL },
78         handle_showmancmds, "Show manager commands", showmancmds_help };
79
80 static void destroy_session(struct mansession *s)
81 {
82         struct mansession *cur, *prev = NULL;
83         ast_pthread_mutex_lock(&sessionlock);
84         cur = sessions;
85         while(cur) {
86                 if (cur == s)
87                         break;
88                 prev = cur;
89                 cur = cur->next;
90         }
91         if (cur) {
92                 if (prev)
93                         prev->next = cur->next;
94                 else
95                         sessions = cur->next;
96                 if (s->fd > -1)
97                         close(s->fd);
98                 free(s);
99         } else
100                 ast_log(LOG_WARNING, "Trying to delete non-existant session %p?\n", s);
101         ast_pthread_mutex_unlock(&sessionlock);
102         
103 }
104
105 static char *get_header(struct message *m, char *var)
106 {
107         char cmp[80];
108         int x;
109         snprintf(cmp, sizeof(cmp), "%s: ", var);
110         for (x=0;x<m->hdrcount;x++)
111                 if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
112                         return m->headers[x] + strlen(cmp);
113         return "";
114 }
115
116 static void send_error(struct mansession *s, char *error)
117 {
118         ast_pthread_mutex_lock(&s->lock);
119         ast_cli(s->fd, "Response: Error\r\n");
120         ast_cli(s->fd, "Message: %s\r\n\r\n", error);
121         ast_pthread_mutex_unlock(&s->lock);
122 }
123
124 static void send_response(struct mansession *s, char *resp, char *msg)
125 {
126         ast_pthread_mutex_lock(&s->lock);
127         ast_cli(s->fd, "Response: %s\r\n", resp);
128         if (msg)
129                 ast_cli(s->fd, "Message: %s\r\n\r\n", msg);
130         else
131                 ast_cli(s->fd, "\r\n");
132         ast_pthread_mutex_unlock(&s->lock);
133 }
134
135 static void send_ack(struct mansession *s, char *msg)
136 {
137         send_response(s, "Success", msg);
138 }
139
140 static int get_perm(char *instr)
141 {
142         char tmp[256];
143         char *c;
144         int x;
145         int ret = 0;
146         char *stringp=NULL;
147         if (!instr)
148                 return 0;
149         strncpy(tmp, instr, sizeof(tmp) - 1);
150         stringp=tmp;
151         c = strsep(&stringp, ",");
152         while(c) {
153                 for (x=0;x<sizeof(perms) / sizeof(perms[0]);x++) {
154                         if (!strcasecmp(perms[x].label, c)) 
155                                 ret |= perms[x].num;
156                 }
157                 c = strsep(&stringp, ",");
158         }
159         return ret;
160 }
161
162 static int authenticate(struct mansession *s, struct message *m)
163 {
164         struct ast_config *cfg;
165         char *cat;
166         char *user = get_header(m, "Username");
167         char *pass = get_header(m, "Secret");
168         cfg = ast_load("manager.conf");
169         if (!cfg)
170                 return -1;
171         cat = ast_category_browse(cfg, NULL);
172         while(cat) {
173                 if (strcasecmp(cat, "general")) {
174                         /* This is a user */
175                         if (!strcasecmp(cat, user)) {
176                                 char *password = ast_variable_retrieve(cfg, cat, "secret");
177                                 if (password && !strcasecmp(password, pass)) {
178                                         break;
179                                 } else {
180                                         ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", inet_ntoa(s->sin.sin_addr), user);
181                                         ast_destroy(cfg);
182                                         return -1;
183                                 }       
184                         }
185                 }
186                 cat = ast_category_browse(cfg, cat);
187         }
188         if (cat) {
189                 strncpy(s->username, cat, sizeof(s->username) - 1);
190                 s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
191                 s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
192                 ast_destroy(cfg);
193                 return 0;
194         }
195         ast_log(LOG_NOTICE, "%s tried to authenticate with non-existant user '%s'\n", inet_ntoa(s->sin.sin_addr), user);
196         ast_destroy(cfg);
197         return -1;
198 }
199
200 static int action_ping(struct mansession *s, struct message *m)
201 {
202         send_response(s, "Pong", NULL);
203         return 0;
204 }
205
206 static int action_logoff(struct mansession *s, struct message *m)
207 {
208         send_response(s, "Goodbye", "Thanks for all the fish.");
209         return -1;
210 }
211
212 static int action_hangup(struct mansession *s, struct message *m)
213 {
214         struct ast_channel *c = NULL;
215         char *name = get_header(m, "Channel");
216         if (!strlen(name)) {
217                 send_error(s, "No channel specified");
218                 return 0;
219         }
220         c = ast_channel_walk(NULL);
221         while(c) {
222                 if (!strcasecmp(c->name, name)) {
223                         break;
224                 }
225                 c = ast_channel_walk(c);
226         }
227         if (!c) {
228                 send_error(s, "No such channel");
229                 return 0;
230         }
231         ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
232         send_ack(s, "Channel Hungup");
233         return 0;
234 }
235
236 static int action_status(struct mansession *s, struct message *m)
237 {
238         struct ast_channel *c;
239         char bridge[256];
240         send_ack(s, "Channel status will follow");
241         c = ast_channel_walk(NULL);
242         while(c) {
243                 if (c->bridge)
244                         snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->bridge->name);
245                 else
246                         strcpy(bridge, "");
247                 if (c->pbx) {
248                         ast_cli(s->fd,
249                         "Event: Status\r\n"
250                         "Channel: %s\r\n"
251                         "CallerID: %s\r\n"
252                         "State: %s\r\n"
253                         "Context: %s\r\n"
254                         "Extension: %s\r\n"
255                         "Priority: %d\r\n"
256                         "%s"
257                         "\r\n",
258                         c->name, c->callerid ? c->callerid : "<unknown>", 
259                         ast_state2str(c->_state), c->context,
260                         c->exten, c->priority, bridge);
261                 } else {
262                         ast_cli(s->fd,
263                         "Event: Status\r\n"
264                         "Channel: %s\r\n"
265                         "CallerID: %s\r\n"
266                         "State: %s\r\n"
267                         "%s"
268                         "\r\n",
269                         c->name, c->callerid ? c->callerid : "<unknown>", 
270                         ast_state2str(c->_state), bridge);
271                 }
272                 c = ast_channel_walk(c);
273         }
274         return 0;
275 }
276
277 static int action_redirect(struct mansession *s, struct message *m)
278 {
279         char *name = get_header(m, "Channel");
280         char *name2 = get_header(m, "ExtraChannel");
281         char *exten = get_header(m, "Exten");
282         char *context = get_header(m, "Context");
283         char *priority = get_header(m, "Priority");
284         int pi = 0;
285         int res;
286         if (!name || !strlen(name)) {
287                 send_error(s, "Channel not specified");
288                 return 0;
289         }
290         if (strlen(priority) && (sscanf(priority, "%d", &pi) != 1)) {
291                 send_error(s, "Invalid priority\n");
292                 return 0;
293         }
294         res = ast_async_goto_by_name(name, context, exten, pi);
295         if (!res) {
296                 if (strlen(name2)) {
297                         res = ast_async_goto_by_name(name2, context, exten, pi);
298                         if (!res)
299                                 send_ack(s, "Dual Redirect successful");
300                         else
301                                 send_error(s, "Secondary redirect failed");
302                 } else
303                         send_ack(s, "Redirect successful");
304         } else
305                 send_error(s, "Redirect failed");
306         return 0;
307 }
308
309 static int action_command(struct mansession *s, struct message *m)
310 {
311         char *cmd = get_header(m, "Command");
312         ast_pthread_mutex_lock(&s->lock);
313         s->blocking = 1;
314         ast_pthread_mutex_unlock(&s->lock);
315         ast_cli(s->fd, "Response: Follows\r\n");
316         ast_cli_command(s->fd, cmd);
317         ast_cli(s->fd, "--END COMMAND--\r\n\r\n");
318         ast_pthread_mutex_lock(&s->lock);
319         s->blocking = 0;
320         ast_pthread_mutex_unlock(&s->lock);
321         return 0;
322 }
323
324 static int action_originate(struct mansession *s, struct message *m)
325 {
326         char *name = get_header(m, "Channel");
327         char *exten = get_header(m, "Exten");
328         char *context = get_header(m, "Context");
329         char *priority = get_header(m, "Priority");
330         char *timeout = get_header(m, "Timeout");
331         char *callerid = get_header(m, "CallerID");
332         char *tech, *data;
333         int pi = 0;
334         int res;
335         int to = 30000;
336         int reason = 0;
337         char tmp[256];
338         if (!name) {
339                 send_error(s, "Channel not specified");
340                 return 0;
341         }
342         if (strlen(priority) && (sscanf(priority, "%d", &pi) != 1)) {
343                 send_error(s, "Invalid priority\n");
344                 return 0;
345         }
346         if (strlen(timeout) && (sscanf(timeout, "%d", &to) != 1)) {
347                 send_error(s, "Invalid timeout\n");
348                 return 0;
349         }
350         strncpy(tmp, name, sizeof(tmp) - 1);
351         tech = tmp;
352         data = strchr(tmp, '/');
353         if (!data) {
354                 send_error(s, "Invalid channel\n");
355                 return 0;
356         }
357         *data = '\0';
358         data++;
359         res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 0, strlen(callerid) ? callerid : NULL, NULL );
360         if (!res)
361                 send_ack(s, "Originate successfully queued");
362         else
363                 send_error(s, "Originate failed");
364         return 0;
365 }
366
367 static int process_message(struct mansession *s, struct message *m)
368 {
369         char action[80];
370         struct manager_action *tmp = first_action;
371
372         strncpy(action, get_header(m, "Action"), sizeof(action));
373
374         if (!strlen(action)) {
375                 send_error(s, "Missing action in request");
376                 return 0;
377         }
378         if (!s->authenticated) {
379                 if (!strcasecmp(action, "Login")) {
380                         if (authenticate(s, m)) {
381                                 sleep(1);
382                                 send_error(s, "Authentication failed");
383                                 return -1;
384                         } else {
385                                 s->authenticated = 1;
386                                 if (option_verbose > 1) 
387                                         ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
388                                 ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
389                                 send_ack(s, "Authentication accepted");
390                         }
391                 } else 
392                         send_error(s, "Authentication Required");
393         } else {
394                 while( tmp ) {          
395                         if (!strcasecmp(action, tmp->action)) {
396                                 if ((s->writeperm & tmp->authority) == tmp->authority) {
397                                         if (tmp->func(s, m))
398                                                 return -1;
399                                 } else {
400                                         send_error(s, "Permission denied");
401                                 }
402                                 return 0;
403                         }
404                         tmp = tmp->next;
405                 }
406                 send_error(s, "Invalid/unknown command");
407         }
408         return 0;
409 }
410
411 static int get_input(struct mansession *s, char *output)
412 {
413         /* output must have at least sizeof(s->inbuf) space */
414         int res;
415         int x;
416         fd_set fds;
417         for (x=1;x<s->inlen;x++) {
418                 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
419                         /* Copy output data up to and including \r\n */
420                         memcpy(output, s->inbuf, x + 1);
421                         /* Add trailing \0 */
422                         output[x+1] = '\0';
423                         /* Move remaining data back to the front */
424                         memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
425                         s->inlen -= (x + 1);
426                         return 1;
427                 }
428         } 
429         if (s->inlen >= sizeof(s->inbuf) - 1) {
430                 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", inet_ntoa(s->sin.sin_addr), s->inbuf);
431                 s->inlen = 0;
432         }
433         FD_ZERO(&fds);
434         FD_SET(s->fd, &fds);
435         res = select(s->fd + 1, &fds, NULL, NULL, NULL);
436         if (res < 0) {
437                 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
438         } else if (res > 0) {
439                 ast_pthread_mutex_lock(&s->lock);
440                 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
441                 ast_pthread_mutex_unlock(&s->lock);
442                 if (res < 1)
443                         return -1;
444         }
445         s->inlen += res;
446         s->inbuf[s->inlen] = '\0';
447         return 0;
448 }
449
450 static void *session_do(void *data)
451 {
452         struct mansession *s = data;
453         struct message m;
454         int res;
455         
456         ast_pthread_mutex_lock(&s->lock);
457         ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n");
458         ast_pthread_mutex_unlock(&s->lock);
459         memset(&m, 0, sizeof(&m));
460         for (;;) {
461                 res = get_input(s, m.headers[m.hdrcount]);
462                 if (res > 0) {
463                         /* Strip trailing \r\n */
464                         if (strlen(m.headers[m.hdrcount]) < 2)
465                                 continue;
466                         m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
467                         if (!strlen(m.headers[m.hdrcount])) {
468                                 if (process_message(s, &m))
469                                         break;
470                                 memset(&m, 0, sizeof(&m));
471                         } else if (m.hdrcount < MAX_HEADERS - 1)
472                                 m.hdrcount++;
473                 } else if (res < 0)
474                         break;
475         }
476         if (s->authenticated) {
477                 if (option_verbose > 1) 
478                         ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
479                 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, inet_ntoa(s->sin.sin_addr));
480         } else {
481                 if (option_verbose > 1)
482                         ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", inet_ntoa(s->sin.sin_addr));
483                 ast_log(LOG_EVENT, "Failed attempt from %s\n", inet_ntoa(s->sin.sin_addr));
484         }
485         destroy_session(s);
486         return NULL;
487 }
488
489 static void *accept_thread(void *ignore)
490 {
491         int as;
492         struct sockaddr_in sin;
493         int sinlen;
494         struct mansession *s;
495         for (;;) {
496                 sinlen = sizeof(sin);
497                 as = accept(asock, &sin, &sinlen);
498                 if (as < 0) {
499                         ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
500                         continue;
501                 }
502                 s = malloc(sizeof(struct mansession));
503                 if (!s) {
504                         ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
505                         continue;
506                 } 
507                 memset(s, 0, sizeof(struct mansession));
508                 memcpy(&s->sin, &sin, sizeof(sin));
509                 ast_pthread_mutex_init(&s->lock);
510                 s->fd = as;
511                 ast_pthread_mutex_lock(&sessionlock);
512                 s->next = sessions;
513                 sessions = s;
514                 ast_pthread_mutex_unlock(&sessionlock);
515                 if (pthread_create(&t, NULL, session_do, s))
516                         destroy_session(s);
517         }
518         return NULL;
519 }
520
521 int manager_event(int category, char *event, char *fmt, ...)
522 {
523         struct mansession *s;
524         char tmp[4096];
525         va_list ap;
526
527         ast_pthread_mutex_lock(&sessionlock);
528         s = sessions;
529         while(s) {
530                 if ((s->readperm & category) == category) {
531                         ast_pthread_mutex_lock(&s->lock);
532                         if (!s->blocking) {
533                                 ast_cli(s->fd, "Event: %s\r\n", event);
534                                 va_start(ap, fmt);
535                                 vsnprintf(tmp, sizeof(tmp), fmt, ap);
536                                 va_end(ap);
537                                 write(s->fd, tmp, strlen(tmp));
538                                 ast_cli(s->fd, "\r\n");
539                         }
540                         ast_pthread_mutex_unlock(&s->lock);
541                 }
542                 s = s->next;
543         }
544         ast_pthread_mutex_unlock(&sessionlock);
545         return 0;
546 }
547
548 int ast_manager_unregister( char *action ) {
549         struct manager_action *cur = first_action, *prev = first_action;
550
551         ast_pthread_mutex_lock(&actionlock);
552         while( cur ) {          
553                 if (!strcasecmp(action, cur->action)) {
554                         prev->next = cur->next;
555                         free(cur);
556                         if (option_verbose > 1) 
557                                 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
558                         ast_pthread_mutex_unlock(&actionlock);
559                         return 0;
560                 }
561                 prev = cur;
562                 cur = cur->next;
563         }
564         ast_pthread_mutex_unlock(&actionlock);
565         return 0;
566 }
567
568 int ast_manager_register( char *action, int auth, 
569         int (*func)(struct mansession *s, struct message *m), char *synopsis)
570 {
571         struct manager_action *cur = first_action, *prev = NULL;
572
573         ast_pthread_mutex_lock(&actionlock);
574         while(cur) { /* Walk the list of actions */
575                 prev = cur; 
576                 cur = cur->next;
577         }
578         cur = malloc( sizeof(struct manager_action) );
579         if( !cur ) {
580                 ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
581                 ast_pthread_mutex_unlock(&actionlock);
582                 return -1;
583         }
584         strncpy( cur->action, action, 255 );
585         cur->authority = auth;
586         cur->func = func;
587         cur->synopsis = synopsis;
588         cur->next = NULL;
589
590         if( prev ) prev->next = cur;
591         else first_action = cur;
592
593         if (option_verbose > 1) 
594                 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", action);
595         ast_pthread_mutex_unlock(&actionlock);
596         return 0;
597 }
598
599 static int registered = 0;
600
601 int init_manager(void)
602 {
603         struct ast_config *cfg;
604         char *val;
605         int oldportno = portno;
606         static struct sockaddr_in ba;
607         int x = 1;
608         if (!registered) {
609                 /* Register default actions */
610                 ast_manager_register( "Ping", 0, action_ping, "Ping" );
611                 ast_manager_register( "Logoff", 0, action_logoff, "Logoff Manager" );
612                 ast_manager_register( "Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel" );
613                 ast_manager_register( "Status", EVENT_FLAG_CALL, action_status, "Status" );
614                 ast_manager_register( "Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect" );
615                 ast_manager_register( "Originate", EVENT_FLAG_CALL, action_originate, "Originate Call" );
616                 ast_manager_register( "Command", EVENT_FLAG_COMMAND, action_command, "Execute Command" );
617
618                 ast_cli_register(&show_mancmds_cli);
619                 registered = 1;
620         }
621         portno = DEFAULT_MANAGER_PORT;
622         cfg = ast_load("manager.conf");
623         if (!cfg) {
624                 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf.  Call management disabled.\n");
625                 return 0;
626         }
627         memset(&ba, 0, sizeof(ba));
628         val = ast_variable_retrieve(cfg, "general", "enabled");
629         if (val)
630                 enabled = ast_true(val);
631
632         if ((val = ast_variable_retrieve(cfg, "general", "portno"))) {
633                 if (sscanf(val, "%d", &portno) != 1) {
634                         ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
635                         portno = DEFAULT_MANAGER_PORT;
636                 }
637         }
638         
639         ba.sin_family = AF_INET;
640         ba.sin_port = htons(portno);
641         memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
642         
643         if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
644                 if (!inet_aton(val, &ba.sin_addr)) { 
645                         ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
646                         memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
647                 }
648         }
649
650         if ((asock > -1) && ((portno != oldportno) || !enabled)) {
651 #if 0
652                 /* Can't be done yet */
653                 close(asock);
654                 asock = -1;
655 #else
656                 ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
657 #endif
658         }
659         /* If not enabled, do nothing */
660         if (!enabled)
661                 return 0;
662         if (asock < 0) {
663                 asock = socket(AF_INET, SOCK_STREAM, 0);
664                 if (asock < 0) {
665                         ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
666                         return -1;
667                 }
668                 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
669                 if (bind(asock, &ba, sizeof(ba))) {
670                         ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
671                         close(asock);
672                         asock = -1;
673                         return -1;
674                 }
675                 if (listen(asock, 2)) {
676                         ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
677                         close(asock);
678                         asock = -1;
679                         return -1;
680                 }
681                 if (option_verbose)
682                         ast_verbose("Asterisk Management interface listening on port %d\n", portno);
683                 pthread_create(&t, NULL, accept_thread, NULL);
684         }
685         ast_destroy(cfg);
686         return 0;
687 }
688
689 int reload_manager(void)
690 {
691         return init_manager();
692 }