manager.c 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2005, Digium, Inc.
  5. *
  6. * Mark Spencer <markster@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. *
  20. * \brief The Asterisk Management Interface - AMI
  21. *
  22. * Channel Management and more
  23. *
  24. * \ref amiconf
  25. */
  26. /*! \addtogroup Group_AMI AMI functions
  27. */
  28. /*! @{
  29. Doxygen group */
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <sys/time.h>
  34. #include <sys/types.h>
  35. #include <netdb.h>
  36. #include <sys/socket.h>
  37. #include <netinet/in.h>
  38. #include <netinet/tcp.h>
  39. #include <arpa/inet.h>
  40. #include <signal.h>
  41. #include <errno.h>
  42. #include <unistd.h>
  43. #include "asterisk.h"
  44. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  45. #include "asterisk/channel.h"
  46. #include "asterisk/file.h"
  47. #include "asterisk/manager.h"
  48. #include "asterisk/config.h"
  49. #include "asterisk/callerid.h"
  50. #include "asterisk/lock.h"
  51. #include "asterisk/logger.h"
  52. #include "asterisk/options.h"
  53. #include "asterisk/cli.h"
  54. #include "asterisk/app.h"
  55. #include "asterisk/pbx.h"
  56. #include "asterisk/md5.h"
  57. #include "asterisk/acl.h"
  58. #include "asterisk/utils.h"
  59. struct fast_originate_helper {
  60. char tech[AST_MAX_MANHEADER_LEN];
  61. char data[AST_MAX_MANHEADER_LEN];
  62. int timeout;
  63. char app[AST_MAX_APP];
  64. char appdata[AST_MAX_MANHEADER_LEN];
  65. char cid_name[AST_MAX_MANHEADER_LEN];
  66. char cid_num[AST_MAX_MANHEADER_LEN];
  67. char context[AST_MAX_CONTEXT];
  68. char exten[AST_MAX_EXTENSION];
  69. char idtext[AST_MAX_MANHEADER_LEN];
  70. char account[AST_MAX_ACCOUNT_CODE];
  71. int priority;
  72. struct ast_variable *vars;
  73. };
  74. static int enabled = 0;
  75. static int portno = DEFAULT_MANAGER_PORT;
  76. static int asock = -1;
  77. static int displayconnects = 1;
  78. static pthread_t t;
  79. AST_MUTEX_DEFINE_STATIC(sessionlock);
  80. static int block_sockets = 0;
  81. static struct permalias {
  82. int num;
  83. char *label;
  84. } perms[] = {
  85. { EVENT_FLAG_SYSTEM, "system" },
  86. { EVENT_FLAG_CALL, "call" },
  87. { EVENT_FLAG_LOG, "log" },
  88. { EVENT_FLAG_VERBOSE, "verbose" },
  89. { EVENT_FLAG_COMMAND, "command" },
  90. { EVENT_FLAG_AGENT, "agent" },
  91. { EVENT_FLAG_USER, "user" },
  92. { -1, "all" },
  93. { 0, "none" },
  94. };
  95. static struct mansession *sessions = NULL;
  96. static struct manager_action *first_action = NULL;
  97. AST_MUTEX_DEFINE_STATIC(actionlock);
  98. /*! If you are calling ast_carefulwrite, it is assumed that you are calling
  99. it on a file descriptor that _DOES_ have NONBLOCK set. This way,
  100. there is only one system call made to do a write, unless we actually
  101. have a need to wait. This way, we get better performance. */
  102. int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
  103. {
  104. /* Try to write string, but wait no more than ms milliseconds
  105. before timing out */
  106. int res=0;
  107. struct pollfd fds[1];
  108. while(len) {
  109. res = write(fd, s, len);
  110. if ((res < 0) && (errno != EAGAIN)) {
  111. return -1;
  112. }
  113. if (res < 0) res = 0;
  114. len -= res;
  115. s += res;
  116. res = 0;
  117. if (len) {
  118. fds[0].fd = fd;
  119. fds[0].events = POLLOUT;
  120. /* Wait until writable again */
  121. res = poll(fds, 1, timeoutms);
  122. if (res < 1)
  123. return -1;
  124. }
  125. }
  126. return res;
  127. }
  128. /*! authority_to_str: Convert authority code to string with serveral options */
  129. static char *authority_to_str(int authority, char *res, int reslen)
  130. {
  131. int running_total = 0, i;
  132. memset(res, 0, reslen);
  133. for (i=0; i<sizeof(perms) / sizeof(perms[0]) - 1; i++) {
  134. if (authority & perms[i].num) {
  135. if (*res) {
  136. strncat(res, ",", (reslen > running_total) ? reslen - running_total : 0);
  137. running_total++;
  138. }
  139. strncat(res, perms[i].label, (reslen > running_total) ? reslen - running_total : 0);
  140. running_total += strlen(perms[i].label);
  141. }
  142. }
  143. if (ast_strlen_zero(res)) {
  144. ast_copy_string(res, "<none>", reslen);
  145. }
  146. return res;
  147. }
  148. static char *complete_show_mancmd(char *line, char *word, int pos, int state)
  149. {
  150. struct manager_action *cur = first_action;
  151. int which = 0;
  152. ast_mutex_lock(&actionlock);
  153. while (cur) { /* Walk the list of actions */
  154. if (!strncasecmp(word, cur->action, strlen(word))) {
  155. if (++which > state) {
  156. char *ret = strdup(cur->action);
  157. ast_mutex_unlock(&actionlock);
  158. return ret;
  159. }
  160. }
  161. cur = cur->next;
  162. }
  163. ast_mutex_unlock(&actionlock);
  164. return NULL;
  165. }
  166. static int handle_showmancmd(int fd, int argc, char *argv[])
  167. {
  168. struct manager_action *cur = first_action;
  169. char authority[80];
  170. int num;
  171. if (argc != 4)
  172. return RESULT_SHOWUSAGE;
  173. ast_mutex_lock(&actionlock);
  174. while (cur) { /* Walk the list of actions */
  175. for (num = 3; num < argc; num++) {
  176. if (!strcasecmp(cur->action, argv[num])) {
  177. ast_cli(fd, "Action: %s\nSynopsis: %s\nPrivilege: %s\n%s\n", cur->action, cur->synopsis, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->description ? cur->description : "");
  178. }
  179. }
  180. cur = cur->next;
  181. }
  182. ast_mutex_unlock(&actionlock);
  183. return RESULT_SUCCESS;
  184. }
  185. /*! \brief handle_showmancmds: CLI command */
  186. /* Should change to "manager show commands" */
  187. static int handle_showmancmds(int fd, int argc, char *argv[])
  188. {
  189. struct manager_action *cur = first_action;
  190. char authority[80];
  191. char *format = " %-15.15s %-15.15s %-55.55s\n";
  192. ast_mutex_lock(&actionlock);
  193. ast_cli(fd, format, "Action", "Privilege", "Synopsis");
  194. ast_cli(fd, format, "------", "---------", "--------");
  195. while (cur) { /* Walk the list of actions */
  196. ast_cli(fd, format, cur->action, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->synopsis);
  197. cur = cur->next;
  198. }
  199. ast_mutex_unlock(&actionlock);
  200. return RESULT_SUCCESS;
  201. }
  202. /*! \brief handle_showmanconn: CLI command show manager connected */
  203. /* Should change to "manager show connected" */
  204. static int handle_showmanconn(int fd, int argc, char *argv[])
  205. {
  206. struct mansession *s;
  207. char iabuf[INET_ADDRSTRLEN];
  208. char *format = " %-15.15s %-15.15s\n";
  209. ast_mutex_lock(&sessionlock);
  210. s = sessions;
  211. ast_cli(fd, format, "Username", "IP Address");
  212. while (s) {
  213. ast_cli(fd, format,s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
  214. s = s->next;
  215. }
  216. ast_mutex_unlock(&sessionlock);
  217. return RESULT_SUCCESS;
  218. }
  219. static char showmancmd_help[] =
  220. "Usage: show manager command <actionname>\n"
  221. " Shows the detailed description for a specific Asterisk manager interface command.\n";
  222. static char showmancmds_help[] =
  223. "Usage: show manager commands\n"
  224. " Prints a listing of all the available Asterisk manager interface commands.\n";
  225. static char showmanconn_help[] =
  226. "Usage: show manager connected\n"
  227. " Prints a listing of the users that are currently connected to the\n"
  228. "Asterisk manager interface.\n";
  229. static struct ast_cli_entry show_mancmd_cli =
  230. { { "show", "manager", "command", NULL },
  231. handle_showmancmd, "Show a manager interface command", showmancmd_help, complete_show_mancmd };
  232. static struct ast_cli_entry show_mancmds_cli =
  233. { { "show", "manager", "commands", NULL },
  234. handle_showmancmds, "List manager interface commands", showmancmds_help };
  235. static struct ast_cli_entry show_manconn_cli =
  236. { { "show", "manager", "connected", NULL },
  237. handle_showmanconn, "Show connected manager interface users", showmanconn_help };
  238. static void free_session(struct mansession *s)
  239. {
  240. struct eventqent *eqe;
  241. if (s->fd > -1)
  242. close(s->fd);
  243. ast_mutex_destroy(&s->__lock);
  244. while(s->eventq) {
  245. eqe = s->eventq;
  246. s->eventq = s->eventq->next;
  247. free(eqe);
  248. }
  249. free(s);
  250. }
  251. static void destroy_session(struct mansession *s)
  252. {
  253. struct mansession *cur, *prev = NULL;
  254. ast_mutex_lock(&sessionlock);
  255. cur = sessions;
  256. while(cur) {
  257. if (cur == s)
  258. break;
  259. prev = cur;
  260. cur = cur->next;
  261. }
  262. if (cur) {
  263. if (prev)
  264. prev->next = cur->next;
  265. else
  266. sessions = cur->next;
  267. free_session(s);
  268. } else
  269. ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
  270. ast_mutex_unlock(&sessionlock);
  271. }
  272. char *astman_get_header(struct message *m, char *var)
  273. {
  274. char cmp[80];
  275. int x;
  276. snprintf(cmp, sizeof(cmp), "%s: ", var);
  277. for (x=0;x<m->hdrcount;x++)
  278. if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
  279. return m->headers[x] + strlen(cmp);
  280. return "";
  281. }
  282. struct ast_variable *astman_get_variables(struct message *m)
  283. {
  284. int varlen, x, y;
  285. struct ast_variable *head = NULL, *cur;
  286. char *var, *val;
  287. unsigned int var_count;
  288. char *vars[32];
  289. varlen = strlen("Variable: ");
  290. for (x = 0; x < m->hdrcount; x++) {
  291. if (strncasecmp("Variable: ", m->headers[x], varlen))
  292. continue;
  293. if (!(var = ast_strdupa(m->headers[x] + varlen)))
  294. return head;
  295. if ((var_count = ast_app_separate_args(var, '|', vars, sizeof(vars) / sizeof(vars[0])))) {
  296. for (y = 0; y < var_count; y++) {
  297. if (!vars[y])
  298. continue;
  299. var = val = ast_strdupa(vars[y]);
  300. strsep(&val, "=");
  301. if (!val || ast_strlen_zero(var))
  302. continue;
  303. cur = ast_variable_new(var, val);
  304. if (head) {
  305. cur->next = head;
  306. head = cur;
  307. } else
  308. head = cur;
  309. }
  310. }
  311. }
  312. return head;
  313. }
  314. /*! NOTE:
  315. Callers of astman_send_error(), astman_send_response() or astman_send_ack() must EITHER
  316. hold the session lock _or_ be running in an action callback (in which case s->busy will
  317. be non-zero). In either of these cases, there is no need to lock-protect the session's
  318. fd, since no other output will be sent (events will be queued), and no input will
  319. be read until either the current action finishes or get_input() obtains the session
  320. lock.
  321. */
  322. void astman_send_error(struct mansession *s, struct message *m, char *error)
  323. {
  324. char *id = astman_get_header(m,"ActionID");
  325. ast_cli(s->fd, "Response: Error\r\n");
  326. if (!ast_strlen_zero(id))
  327. ast_cli(s->fd, "ActionID: %s\r\n",id);
  328. ast_cli(s->fd, "Message: %s\r\n\r\n", error);
  329. }
  330. void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg)
  331. {
  332. char *id = astman_get_header(m,"ActionID");
  333. ast_cli(s->fd, "Response: %s\r\n", resp);
  334. if (!ast_strlen_zero(id))
  335. ast_cli(s->fd, "ActionID: %s\r\n",id);
  336. if (msg)
  337. ast_cli(s->fd, "Message: %s\r\n\r\n", msg);
  338. else
  339. ast_cli(s->fd, "\r\n");
  340. }
  341. void astman_send_ack(struct mansession *s, struct message *m, char *msg)
  342. {
  343. astman_send_response(s, m, "Success", msg);
  344. }
  345. /*! Tells you if smallstr exists inside bigstr
  346. which is delim by delim and uses no buf or stringsep
  347. ast_instring("this|that|more","this",',') == 1;
  348. feel free to move this to app.c -anthm */
  349. static int ast_instring(char *bigstr, char *smallstr, char delim)
  350. {
  351. char *val = bigstr, *next;
  352. do {
  353. if ((next = strchr(val, delim))) {
  354. if (!strncmp(val, smallstr, (next - val)))
  355. return 1;
  356. else
  357. continue;
  358. } else
  359. return !strcmp(smallstr, val);
  360. } while (*(val = (next + 1)));
  361. return 0;
  362. }
  363. static int get_perm(char *instr)
  364. {
  365. int x = 0, ret = 0;
  366. if (!instr)
  367. return 0;
  368. for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
  369. if (ast_instring(instr, perms[x].label, ','))
  370. ret |= perms[x].num;
  371. return ret;
  372. }
  373. static int ast_is_number(char *string)
  374. {
  375. int ret = 1, x = 0;
  376. if (!string)
  377. return 0;
  378. for (x=0; x < strlen(string); x++) {
  379. if (!(string[x] >= 48 && string[x] <= 57)) {
  380. ret = 0;
  381. break;
  382. }
  383. }
  384. return ret ? atoi(string) : 0;
  385. }
  386. static int ast_strings_to_mask(char *string)
  387. {
  388. int x, ret = -1;
  389. x = ast_is_number(string);
  390. if (x) {
  391. ret = x;
  392. } else if (ast_strlen_zero(string)) {
  393. ret = -1;
  394. } else if (ast_false(string)) {
  395. ret = 0;
  396. } else if (ast_true(string)) {
  397. ret = 0;
  398. for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++)
  399. ret |= perms[x].num;
  400. } else {
  401. ret = 0;
  402. for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++) {
  403. if (ast_instring(string, perms[x].label, ','))
  404. ret |= perms[x].num;
  405. }
  406. }
  407. return ret;
  408. }
  409. /*!
  410. Rather than braindead on,off this now can also accept a specific int mask value
  411. or a ',' delim list of mask strings (the same as manager.conf) -anthm
  412. */
  413. static int set_eventmask(struct mansession *s, char *eventmask)
  414. {
  415. int maskint = ast_strings_to_mask(eventmask);
  416. ast_mutex_lock(&s->__lock);
  417. if (maskint >= 0)
  418. s->send_events = maskint;
  419. ast_mutex_unlock(&s->__lock);
  420. return maskint;
  421. }
  422. static int authenticate(struct mansession *s, struct message *m)
  423. {
  424. struct ast_config *cfg;
  425. char iabuf[INET_ADDRSTRLEN];
  426. char *cat;
  427. char *user = astman_get_header(m, "Username");
  428. char *pass = astman_get_header(m, "Secret");
  429. char *authtype = astman_get_header(m, "AuthType");
  430. char *key = astman_get_header(m, "Key");
  431. char *events = astman_get_header(m, "Events");
  432. cfg = ast_config_load("manager.conf");
  433. if (!cfg)
  434. return -1;
  435. cat = ast_category_browse(cfg, NULL);
  436. while(cat) {
  437. if (strcasecmp(cat, "general")) {
  438. /* This is a user */
  439. if (!strcasecmp(cat, user)) {
  440. struct ast_variable *v;
  441. struct ast_ha *ha = NULL;
  442. char *password = NULL;
  443. v = ast_variable_browse(cfg, cat);
  444. while (v) {
  445. if (!strcasecmp(v->name, "secret")) {
  446. password = v->value;
  447. } else if (!strcasecmp(v->name, "permit") ||
  448. !strcasecmp(v->name, "deny")) {
  449. ha = ast_append_ha(v->name, v->value, ha);
  450. } else if (!strcasecmp(v->name, "writetimeout")) {
  451. int val = atoi(v->value);
  452. if (val < 100)
  453. ast_log(LOG_WARNING, "Invalid writetimeout value '%s' at line %d\n", v->value, v->lineno);
  454. else
  455. s->writetimeout = val;
  456. }
  457. v = v->next;
  458. }
  459. if (ha && !ast_apply_ha(ha, &(s->sin))) {
  460. ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
  461. ast_free_ha(ha);
  462. ast_config_destroy(cfg);
  463. return -1;
  464. } else if (ha)
  465. ast_free_ha(ha);
  466. if (!strcasecmp(authtype, "MD5")) {
  467. if (!ast_strlen_zero(key) &&
  468. !ast_strlen_zero(s->challenge) && !ast_strlen_zero(password)) {
  469. int x;
  470. int len=0;
  471. char md5key[256] = "";
  472. struct MD5Context md5;
  473. unsigned char digest[16];
  474. MD5Init(&md5);
  475. MD5Update(&md5, (unsigned char *) s->challenge, strlen(s->challenge));
  476. MD5Update(&md5, (unsigned char *) password, strlen(password));
  477. MD5Final(digest, &md5);
  478. for (x=0;x<16;x++)
  479. len += sprintf(md5key + len, "%2.2x", digest[x]);
  480. if (!strcmp(md5key, key))
  481. break;
  482. else {
  483. ast_config_destroy(cfg);
  484. return -1;
  485. }
  486. }
  487. } else if (password && !strcasecmp(password, pass)) {
  488. break;
  489. } else {
  490. ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
  491. ast_config_destroy(cfg);
  492. return -1;
  493. }
  494. }
  495. }
  496. cat = ast_category_browse(cfg, cat);
  497. }
  498. if (cat) {
  499. ast_copy_string(s->username, cat, sizeof(s->username));
  500. s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read"));
  501. s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write"));
  502. ast_config_destroy(cfg);
  503. if (events)
  504. set_eventmask(s, events);
  505. return 0;
  506. }
  507. ast_log(LOG_NOTICE, "%s tried to authenticate with nonexistent user '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user);
  508. ast_config_destroy(cfg);
  509. return -1;
  510. }
  511. /*! \brief PING: Manager PING */
  512. static char mandescr_ping[] =
  513. "Description: A 'Ping' action will ellicit a 'Pong' response. Used to keep the "
  514. " manager connection open.\n"
  515. "Variables: NONE\n";
  516. static int action_ping(struct mansession *s, struct message *m)
  517. {
  518. astman_send_response(s, m, "Pong", NULL);
  519. return 0;
  520. }
  521. static char mandescr_listcommands[] =
  522. "Description: Returns the action name and synopsis for every\n"
  523. " action that is available to the user\n"
  524. "Variables: NONE\n";
  525. static int action_listcommands(struct mansession *s, struct message *m)
  526. {
  527. struct manager_action *cur = first_action;
  528. char idText[256] = "";
  529. char temp[BUFSIZ];
  530. char *id = astman_get_header(m,"ActionID");
  531. if (!ast_strlen_zero(id))
  532. snprintf(idText,256,"ActionID: %s\r\n",id);
  533. ast_cli(s->fd, "Response: Success\r\n%s", idText);
  534. ast_mutex_lock(&actionlock);
  535. while (cur) { /* Walk the list of actions */
  536. if ((s->writeperm & cur->authority) == cur->authority)
  537. ast_cli(s->fd, "%s: %s (Priv: %s)\r\n", cur->action, cur->synopsis, authority_to_str(cur->authority, temp, sizeof(temp)) );
  538. cur = cur->next;
  539. }
  540. ast_mutex_unlock(&actionlock);
  541. ast_cli(s->fd, "\r\n");
  542. return 0;
  543. }
  544. static char mandescr_events[] =
  545. "Description: Enable/Disable sending of events to this manager\n"
  546. " client.\n"
  547. "Variables:\n"
  548. " EventMask: 'on' if all events should be sent,\n"
  549. " 'off' if no events should be sent,\n"
  550. " 'system,call,log' to select which flags events should have to be sent.\n";
  551. static int action_events(struct mansession *s, struct message *m)
  552. {
  553. char *mask = astman_get_header(m, "EventMask");
  554. int res;
  555. res = set_eventmask(s, mask);
  556. if (res > 0)
  557. astman_send_response(s, m, "Events On", NULL);
  558. else if (res == 0)
  559. astman_send_response(s, m, "Events Off", NULL);
  560. return 0;
  561. }
  562. static char mandescr_logoff[] =
  563. "Description: Logoff this manager session\n"
  564. "Variables: NONE\n";
  565. static int action_logoff(struct mansession *s, struct message *m)
  566. {
  567. astman_send_response(s, m, "Goodbye", "Thanks for all the fish.");
  568. return -1;
  569. }
  570. static char mandescr_hangup[] =
  571. "Description: Hangup a channel\n"
  572. "Variables: \n"
  573. " Channel: The channel name to be hungup\n";
  574. static int action_hangup(struct mansession *s, struct message *m)
  575. {
  576. struct ast_channel *c = NULL;
  577. char *name = astman_get_header(m, "Channel");
  578. if (ast_strlen_zero(name)) {
  579. astman_send_error(s, m, "No channel specified");
  580. return 0;
  581. }
  582. c = ast_get_channel_by_name_locked(name);
  583. if (!c) {
  584. astman_send_error(s, m, "No such channel");
  585. return 0;
  586. }
  587. ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
  588. ast_mutex_unlock(&c->lock);
  589. astman_send_ack(s, m, "Channel Hungup");
  590. return 0;
  591. }
  592. static char mandescr_setvar[] =
  593. "Description: Set a global or local channel variable.\n"
  594. "Variables: (Names marked with * are required)\n"
  595. " Channel: Channel to set variable for\n"
  596. " *Variable: Variable name\n"
  597. " *Value: Value\n";
  598. static int action_setvar(struct mansession *s, struct message *m)
  599. {
  600. struct ast_channel *c = NULL;
  601. char *name = astman_get_header(m, "Channel");
  602. char *varname = astman_get_header(m, "Variable");
  603. char *varval = astman_get_header(m, "Value");
  604. if (ast_strlen_zero(varname)) {
  605. astman_send_error(s, m, "No variable specified");
  606. return 0;
  607. }
  608. if (!ast_strlen_zero(name)) {
  609. c = ast_get_channel_by_name_locked(name);
  610. if (!c) {
  611. astman_send_error(s, m, "No such channel");
  612. return 0;
  613. }
  614. }
  615. pbx_builtin_setvar_helper(c, varname, varval ? varval : "");
  616. if (c)
  617. ast_mutex_unlock(&c->lock);
  618. astman_send_ack(s, m, "Variable Set");
  619. return 0;
  620. }
  621. static char mandescr_getvar[] =
  622. "Description: Get the value of a global or local channel variable.\n"
  623. "Variables: (Names marked with * are required)\n"
  624. " Channel: Channel to read variable from\n"
  625. " *Variable: Variable name\n"
  626. " ActionID: Optional Action id for message matching.\n";
  627. static int action_getvar(struct mansession *s, struct message *m)
  628. {
  629. struct ast_channel *c = NULL;
  630. char *name = astman_get_header(m, "Channel");
  631. char *varname = astman_get_header(m, "Variable");
  632. char *id = astman_get_header(m,"ActionID");
  633. char *varval;
  634. char *varval2=NULL;
  635. if (!strlen(varname)) {
  636. astman_send_error(s, m, "No variable specified");
  637. return 0;
  638. }
  639. if (strlen(name)) {
  640. c = ast_get_channel_by_name_locked(name);
  641. if (!c) {
  642. astman_send_error(s, m, "No such channel");
  643. return 0;
  644. }
  645. }
  646. varval=pbx_builtin_getvar_helper(c,varname);
  647. if (varval)
  648. varval2 = ast_strdupa(varval);
  649. if (!varval2)
  650. varval2 = "";
  651. if (c)
  652. ast_mutex_unlock(&c->lock);
  653. ast_cli(s->fd, "Response: Success\r\n"
  654. "Variable: %s\r\nValue: %s\r\n" ,varname,varval2);
  655. if (!ast_strlen_zero(id))
  656. ast_cli(s->fd, "ActionID: %s\r\n",id);
  657. ast_cli(s->fd, "\r\n");
  658. return 0;
  659. }
  660. /*! \brief action_status: Manager "status" command to show channels */
  661. /* Needs documentation... */
  662. static int action_status(struct mansession *s, struct message *m)
  663. {
  664. char *id = astman_get_header(m,"ActionID");
  665. char *name = astman_get_header(m,"Channel");
  666. char idText[256] = "";
  667. struct ast_channel *c;
  668. char bridge[256];
  669. struct timeval now = ast_tvnow();
  670. long elapsed_seconds=0;
  671. int all = ast_strlen_zero(name); /* set if we want all channels */
  672. if (!ast_strlen_zero(id))
  673. snprintf(idText,256,"ActionID: %s\r\n",id);
  674. if (all)
  675. c = ast_channel_walk_locked(NULL);
  676. else {
  677. c = ast_get_channel_by_name_locked(name);
  678. if (!c) {
  679. astman_send_error(s, m, "No such channel");
  680. return 0;
  681. }
  682. }
  683. astman_send_ack(s, m, "Channel status will follow");
  684. /* if we look by name, we break after the first iteration */
  685. while(c) {
  686. if (c->_bridge)
  687. snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->_bridge->name);
  688. else
  689. bridge[0] = '\0';
  690. if (c->pbx) {
  691. if (c->cdr) {
  692. elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
  693. }
  694. ast_cli(s->fd,
  695. "Event: Status\r\n"
  696. "Privilege: Call\r\n"
  697. "Channel: %s\r\n"
  698. "CallerID: %s\r\n"
  699. "CallerIDName: %s\r\n"
  700. "Account: %s\r\n"
  701. "State: %s\r\n"
  702. "Context: %s\r\n"
  703. "Extension: %s\r\n"
  704. "Priority: %d\r\n"
  705. "Seconds: %ld\r\n"
  706. "%s"
  707. "Uniqueid: %s\r\n"
  708. "%s"
  709. "\r\n",
  710. c->name,
  711. c->cid.cid_num ? c->cid.cid_num : "<unknown>",
  712. c->cid.cid_name ? c->cid.cid_name : "<unknown>",
  713. c->accountcode,
  714. ast_state2str(c->_state), c->context,
  715. c->exten, c->priority, (long)elapsed_seconds, bridge, c->uniqueid, idText);
  716. } else {
  717. ast_cli(s->fd,
  718. "Event: Status\r\n"
  719. "Privilege: Call\r\n"
  720. "Channel: %s\r\n"
  721. "CallerID: %s\r\n"
  722. "CallerIDName: %s\r\n"
  723. "Account: %s\r\n"
  724. "State: %s\r\n"
  725. "%s"
  726. "Uniqueid: %s\r\n"
  727. "%s"
  728. "\r\n",
  729. c->name,
  730. c->cid.cid_num ? c->cid.cid_num : "<unknown>",
  731. c->cid.cid_name ? c->cid.cid_name : "<unknown>",
  732. c->accountcode,
  733. ast_state2str(c->_state), bridge, c->uniqueid, idText);
  734. }
  735. ast_mutex_unlock(&c->lock);
  736. if (!all)
  737. break;
  738. c = ast_channel_walk_locked(c);
  739. }
  740. ast_cli(s->fd,
  741. "Event: StatusComplete\r\n"
  742. "%s"
  743. "\r\n",idText);
  744. return 0;
  745. }
  746. static char mandescr_redirect[] =
  747. "Description: Redirect (transfer) a call.\n"
  748. "Variables: (Names marked with * are required)\n"
  749. " *Channel: Channel to redirect\n"
  750. " ExtraChannel: Second call leg to transfer (optional)\n"
  751. " *Exten: Extension to transfer to\n"
  752. " *Context: Context to transfer to\n"
  753. " *Priority: Priority to transfer to\n"
  754. " ActionID: Optional Action id for message matching.\n";
  755. /*! \brief action_redirect: The redirect manager command */
  756. static int action_redirect(struct mansession *s, struct message *m)
  757. {
  758. char *name = astman_get_header(m, "Channel");
  759. char *name2 = astman_get_header(m, "ExtraChannel");
  760. char *exten = astman_get_header(m, "Exten");
  761. char *context = astman_get_header(m, "Context");
  762. char *priority = astman_get_header(m, "Priority");
  763. struct ast_channel *chan, *chan2 = NULL;
  764. int pi = 0;
  765. int res;
  766. if (ast_strlen_zero(name)) {
  767. astman_send_error(s, m, "Channel not specified");
  768. return 0;
  769. }
  770. if (!ast_strlen_zero(priority) && (sscanf(priority, "%30d", &pi) != 1)) {
  771. astman_send_error(s, m, "Invalid priority\n");
  772. return 0;
  773. }
  774. chan = ast_get_channel_by_name_locked(name);
  775. if (!chan) {
  776. char buf[BUFSIZ];
  777. snprintf(buf, sizeof(buf), "Channel does not exist: %s", name);
  778. astman_send_error(s, m, buf);
  779. return 0;
  780. }
  781. if (ast_check_hangup(chan)) {
  782. astman_send_error(s, m, "Redirect failed, channel hung up.\n");
  783. ast_mutex_unlock(&chan->lock);
  784. return 0;
  785. }
  786. if (!ast_strlen_zero(name2))
  787. chan2 = ast_get_channel_by_name_locked(name2);
  788. if (chan2 && ast_check_hangup(chan2)) {
  789. astman_send_error(s, m, "Redirect failed, extra channel hung up.\n");
  790. ast_mutex_unlock(&chan->lock);
  791. ast_mutex_unlock(&chan2->lock);
  792. return 0;
  793. }
  794. res = ast_async_goto(chan, context, exten, pi);
  795. if (!res) {
  796. if (!ast_strlen_zero(name2)) {
  797. if (chan2)
  798. res = ast_async_goto(chan2, context, exten, pi);
  799. else
  800. res = -1;
  801. if (!res)
  802. astman_send_ack(s, m, "Dual Redirect successful");
  803. else
  804. astman_send_error(s, m, "Secondary redirect failed");
  805. } else
  806. astman_send_ack(s, m, "Redirect successful");
  807. } else
  808. astman_send_error(s, m, "Redirect failed");
  809. if (chan)
  810. ast_mutex_unlock(&chan->lock);
  811. if (chan2)
  812. ast_mutex_unlock(&chan2->lock);
  813. return 0;
  814. }
  815. static char mandescr_command[] =
  816. "Description: Run a CLI command.\n"
  817. "Variables: (Names marked with * are required)\n"
  818. " *Command: Asterisk CLI command to run\n"
  819. " ActionID: Optional Action id for message matching.\n";
  820. /*! \brief action_command: Manager command "command" - execute CLI command */
  821. static int action_command(struct mansession *s, struct message *m)
  822. {
  823. char *cmd = astman_get_header(m, "Command");
  824. char *id = astman_get_header(m, "ActionID");
  825. ast_cli(s->fd, "Response: Follows\r\nPrivilege: Command\r\n");
  826. if (!ast_strlen_zero(id))
  827. ast_cli(s->fd, "ActionID: %s\r\n", id);
  828. /* FIXME: Wedge a ActionID response in here, waiting for later changes */
  829. ast_cli_command(s->fd, cmd);
  830. ast_cli(s->fd, "--END COMMAND--\r\n\r\n");
  831. return 0;
  832. }
  833. static void *fast_originate(void *data)
  834. {
  835. struct fast_originate_helper *in = data;
  836. int res;
  837. int reason = 0;
  838. struct ast_channel *chan = NULL;
  839. if (!ast_strlen_zero(in->app)) {
  840. res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1,
  841. !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL,
  842. !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
  843. in->vars, in->account, &chan);
  844. } else {
  845. res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1,
  846. !ast_strlen_zero(in->cid_num) ? in->cid_num : NULL,
  847. !ast_strlen_zero(in->cid_name) ? in->cid_name : NULL,
  848. in->vars, in->account, &chan);
  849. }
  850. if (!res)
  851. manager_event(EVENT_FLAG_CALL,
  852. "OriginateSuccess",
  853. "%s"
  854. "Channel: %s/%s\r\n"
  855. "Context: %s\r\n"
  856. "Exten: %s\r\n"
  857. "Reason: %d\r\n"
  858. "Uniqueid: %s\r\n",
  859. in->idtext, in->tech, in->data, in->context, in->exten, reason, chan ? chan->uniqueid : "<null>");
  860. else
  861. manager_event(EVENT_FLAG_CALL,
  862. "OriginateFailure",
  863. "%s"
  864. "Channel: %s/%s\r\n"
  865. "Context: %s\r\n"
  866. "Exten: %s\r\n"
  867. "Reason: %d\r\n"
  868. "Uniqueid: %s\r\n",
  869. in->idtext, in->tech, in->data, in->context, in->exten, reason, chan ? chan->uniqueid : "<null>");
  870. /* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
  871. if (chan)
  872. ast_mutex_unlock(&chan->lock);
  873. free(in);
  874. return NULL;
  875. }
  876. static char mandescr_originate[] =
  877. "Description: Generates an outgoing call to a Extension/Context/Priority or\n"
  878. " Application/Data\n"
  879. "Variables: (Names marked with * are required)\n"
  880. " *Channel: Channel name to call\n"
  881. " Exten: Extension to use (requires 'Context' and 'Priority')\n"
  882. " Context: Context to use (requires 'Exten' and 'Priority')\n"
  883. " Priority: Priority to use (requires 'Exten' and 'Context')\n"
  884. " Application: Application to use\n"
  885. " Data: Data to use (requires 'Application')\n"
  886. " Timeout: How long to wait for call to be answered (in ms)\n"
  887. " CallerID: Caller ID to be set on the outgoing channel\n"
  888. " Variable: Channel variable to set, multiple Variable: headers are allowed\n"
  889. " Account: Account code\n"
  890. " Async: Set to 'true' for fast origination\n";
  891. static int action_originate(struct mansession *s, struct message *m)
  892. {
  893. char *name = astman_get_header(m, "Channel");
  894. char *exten = astman_get_header(m, "Exten");
  895. char *context = astman_get_header(m, "Context");
  896. char *priority = astman_get_header(m, "Priority");
  897. char *timeout = astman_get_header(m, "Timeout");
  898. char *callerid = astman_get_header(m, "CallerID");
  899. char *account = astman_get_header(m, "Account");
  900. char *app = astman_get_header(m, "Application");
  901. char *appdata = astman_get_header(m, "Data");
  902. char *async = astman_get_header(m, "Async");
  903. char *id = astman_get_header(m, "ActionID");
  904. struct ast_variable *vars = astman_get_variables(m);
  905. char *tech, *data;
  906. char *l=NULL, *n=NULL;
  907. int pi = 0;
  908. int res;
  909. int to = 30000;
  910. int reason = 0;
  911. char tmp[256];
  912. char tmp2[256];
  913. pthread_t th;
  914. pthread_attr_t attr;
  915. if (!name) {
  916. astman_send_error(s, m, "Channel not specified");
  917. return 0;
  918. }
  919. if (!ast_strlen_zero(priority) && (sscanf(priority, "%30d", &pi) != 1)) {
  920. astman_send_error(s, m, "Invalid priority\n");
  921. return 0;
  922. }
  923. if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%30d", &to) != 1)) {
  924. astman_send_error(s, m, "Invalid timeout\n");
  925. return 0;
  926. }
  927. ast_copy_string(tmp, name, sizeof(tmp));
  928. tech = tmp;
  929. data = strchr(tmp, '/');
  930. if (!data) {
  931. astman_send_error(s, m, "Invalid channel\n");
  932. return 0;
  933. }
  934. *data = '\0';
  935. data++;
  936. ast_copy_string(tmp2, callerid, sizeof(tmp2));
  937. ast_callerid_parse(tmp2, &n, &l);
  938. if (n) {
  939. if (ast_strlen_zero(n))
  940. n = NULL;
  941. }
  942. if (l) {
  943. ast_shrink_phone_number(l);
  944. if (ast_strlen_zero(l))
  945. l = NULL;
  946. }
  947. if (ast_true(async)) {
  948. struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper));
  949. if (!fast) {
  950. res = -1;
  951. } else {
  952. memset(fast, 0, sizeof(struct fast_originate_helper));
  953. if (!ast_strlen_zero(id))
  954. snprintf(fast->idtext, sizeof(fast->idtext), "ActionID: %s\r\n", id);
  955. ast_copy_string(fast->tech, tech, sizeof(fast->tech));
  956. ast_copy_string(fast->data, data, sizeof(fast->data));
  957. ast_copy_string(fast->app, app, sizeof(fast->app));
  958. ast_copy_string(fast->appdata, appdata, sizeof(fast->appdata));
  959. if (l)
  960. ast_copy_string(fast->cid_num, l, sizeof(fast->cid_num));
  961. if (n)
  962. ast_copy_string(fast->cid_name, n, sizeof(fast->cid_name));
  963. fast->vars = vars;
  964. ast_copy_string(fast->context, context, sizeof(fast->context));
  965. ast_copy_string(fast->exten, exten, sizeof(fast->exten));
  966. ast_copy_string(fast->account, account, sizeof(fast->account));
  967. fast->timeout = to;
  968. fast->priority = pi;
  969. pthread_attr_init(&attr);
  970. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  971. if (ast_pthread_create(&th, &attr, fast_originate, fast)) {
  972. res = -1;
  973. } else {
  974. res = 0;
  975. }
  976. pthread_attr_destroy(&attr);
  977. }
  978. } else if (!ast_strlen_zero(app)) {
  979. res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
  980. } else {
  981. if (exten && context && pi)
  982. res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
  983. else {
  984. astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
  985. return 0;
  986. }
  987. }
  988. if (!res)
  989. astman_send_ack(s, m, "Originate successfully queued");
  990. else
  991. astman_send_error(s, m, "Originate failed");
  992. return 0;
  993. }
  994. /*! \brief Help text for manager command mailboxstatus
  995. */
  996. static char mandescr_mailboxstatus[] =
  997. "Description: Checks a voicemail account for status.\n"
  998. "Variables: (Names marked with * are required)\n"
  999. " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
  1000. " ActionID: Optional ActionID for message matching.\n"
  1001. "Returns number of messages.\n"
  1002. " Message: Mailbox Status\n"
  1003. " Mailbox: <mailboxid>\n"
  1004. " Waiting: <count>\n"
  1005. "\n";
  1006. static int action_mailboxstatus(struct mansession *s, struct message *m)
  1007. {
  1008. char *mailbox = astman_get_header(m, "Mailbox");
  1009. char *id = astman_get_header(m,"ActionID");
  1010. char idText[256] = "";
  1011. int ret;
  1012. if (ast_strlen_zero(mailbox)) {
  1013. astman_send_error(s, m, "Mailbox not specified");
  1014. return 0;
  1015. }
  1016. if (!ast_strlen_zero(id))
  1017. snprintf(idText,256,"ActionID: %s\r\n",id);
  1018. ret = ast_app_has_voicemail(mailbox, NULL);
  1019. ast_cli(s->fd, "Response: Success\r\n"
  1020. "%s"
  1021. "Message: Mailbox Status\r\n"
  1022. "Mailbox: %s\r\n"
  1023. "Waiting: %d\r\n\r\n", idText, mailbox, ret);
  1024. return 0;
  1025. }
  1026. static char mandescr_mailboxcount[] =
  1027. "Description: Checks a voicemail account for new messages.\n"
  1028. "Variables: (Names marked with * are required)\n"
  1029. " *Mailbox: Full mailbox ID <mailbox>@<vm-context>\n"
  1030. " ActionID: Optional ActionID for message matching.\n"
  1031. "Returns number of new and old messages.\n"
  1032. " Message: Mailbox Message Count\n"
  1033. " Mailbox: <mailboxid>\n"
  1034. " NewMessages: <count>\n"
  1035. " OldMessages: <count>\n"
  1036. "\n";
  1037. static int action_mailboxcount(struct mansession *s, struct message *m)
  1038. {
  1039. char *mailbox = astman_get_header(m, "Mailbox");
  1040. char *id = astman_get_header(m,"ActionID");
  1041. char idText[256] = "";
  1042. int newmsgs = 0, oldmsgs = 0;
  1043. if (ast_strlen_zero(mailbox)) {
  1044. astman_send_error(s, m, "Mailbox not specified");
  1045. return 0;
  1046. }
  1047. ast_app_messagecount(mailbox, &newmsgs, &oldmsgs);
  1048. if (!ast_strlen_zero(id)) {
  1049. snprintf(idText,256,"ActionID: %s\r\n",id);
  1050. }
  1051. ast_cli(s->fd, "Response: Success\r\n"
  1052. "%s"
  1053. "Message: Mailbox Message Count\r\n"
  1054. "Mailbox: %s\r\n"
  1055. "NewMessages: %d\r\n"
  1056. "OldMessages: %d\r\n"
  1057. "\r\n",
  1058. idText,mailbox, newmsgs, oldmsgs);
  1059. return 0;
  1060. }
  1061. static char mandescr_extensionstate[] =
  1062. "Description: Report the extension state for given extension.\n"
  1063. " If the extension has a hint, will use devicestate to check\n"
  1064. " the status of the device connected to the extension.\n"
  1065. "Variables: (Names marked with * are required)\n"
  1066. " *Exten: Extension to check state on\n"
  1067. " *Context: Context for extension\n"
  1068. " ActionId: Optional ID for this transaction\n"
  1069. "Will return an \"Extension Status\" message.\n"
  1070. "The response will include the hint for the extension and the status.\n";
  1071. static int action_extensionstate(struct mansession *s, struct message *m)
  1072. {
  1073. char *exten = astman_get_header(m, "Exten");
  1074. char *context = astman_get_header(m, "Context");
  1075. char *id = astman_get_header(m,"ActionID");
  1076. char idText[256] = "";
  1077. char hint[256] = "";
  1078. int status;
  1079. if (ast_strlen_zero(exten)) {
  1080. astman_send_error(s, m, "Extension not specified");
  1081. return 0;
  1082. }
  1083. if (ast_strlen_zero(context))
  1084. context = "default";
  1085. status = ast_extension_state(NULL, context, exten);
  1086. ast_get_hint(hint, sizeof(hint) - 1, NULL, 0, NULL, context, exten);
  1087. if (!ast_strlen_zero(id)) {
  1088. snprintf(idText,256,"ActionID: %s\r\n",id);
  1089. }
  1090. ast_cli(s->fd, "Response: Success\r\n"
  1091. "%s"
  1092. "Message: Extension Status\r\n"
  1093. "Exten: %s\r\n"
  1094. "Context: %s\r\n"
  1095. "Hint: %s\r\n"
  1096. "Status: %d\r\n\r\n",
  1097. idText,exten, context, hint, status);
  1098. return 0;
  1099. }
  1100. static char mandescr_timeout[] =
  1101. "Description: Hangup a channel after a certain time.\n"
  1102. "Variables: (Names marked with * are required)\n"
  1103. " *Channel: Channel name to hangup\n"
  1104. " *Timeout: Maximum duration of the call (sec)\n"
  1105. "Acknowledges set time with 'Timeout Set' message\n";
  1106. static int action_timeout(struct mansession *s, struct message *m)
  1107. {
  1108. struct ast_channel *c = NULL;
  1109. char *name = astman_get_header(m, "Channel");
  1110. int timeout = atoi(astman_get_header(m, "Timeout"));
  1111. if (ast_strlen_zero(name)) {
  1112. astman_send_error(s, m, "No channel specified");
  1113. return 0;
  1114. }
  1115. if (!timeout) {
  1116. astman_send_error(s, m, "No timeout specified");
  1117. return 0;
  1118. }
  1119. c = ast_get_channel_by_name_locked(name);
  1120. if (!c) {
  1121. astman_send_error(s, m, "No such channel");
  1122. return 0;
  1123. }
  1124. ast_channel_setwhentohangup(c, timeout);
  1125. ast_mutex_unlock(&c->lock);
  1126. astman_send_ack(s, m, "Timeout Set");
  1127. return 0;
  1128. }
  1129. static int process_message(struct mansession *s, struct message *m)
  1130. {
  1131. char action[80] = "";
  1132. struct manager_action *tmp = first_action;
  1133. char *id = astman_get_header(m,"ActionID");
  1134. char idText[256] = "";
  1135. char iabuf[INET_ADDRSTRLEN];
  1136. ast_copy_string(action, astman_get_header(m, "Action"), sizeof(action));
  1137. ast_log( LOG_DEBUG, "Manager received command '%s'\n", action );
  1138. if (ast_strlen_zero(action)) {
  1139. astman_send_error(s, m, "Missing action in request");
  1140. return 0;
  1141. }
  1142. if (!ast_strlen_zero(id)) {
  1143. snprintf(idText,256,"ActionID: %s\r\n",id);
  1144. }
  1145. if (!s->authenticated) {
  1146. if (!strcasecmp(action, "Challenge")) {
  1147. char *authtype;
  1148. authtype = astman_get_header(m, "AuthType");
  1149. if (!strcasecmp(authtype, "MD5")) {
  1150. if (ast_strlen_zero(s->challenge))
  1151. snprintf(s->challenge, sizeof(s->challenge), "%d", rand());
  1152. ast_mutex_lock(&s->__lock);
  1153. ast_cli(s->fd, "Response: Success\r\n"
  1154. "%s"
  1155. "Challenge: %s\r\n\r\n",
  1156. idText,s->challenge);
  1157. ast_mutex_unlock(&s->__lock);
  1158. return 0;
  1159. } else {
  1160. astman_send_error(s, m, "Must specify AuthType");
  1161. return 0;
  1162. }
  1163. } else if (!strcasecmp(action, "Login")) {
  1164. if (authenticate(s, m)) {
  1165. sleep(1);
  1166. astman_send_error(s, m, "Authentication failed");
  1167. return -1;
  1168. } else {
  1169. s->authenticated = 1;
  1170. if (option_verbose > 1) {
  1171. if ( displayconnects ) {
  1172. ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
  1173. }
  1174. }
  1175. ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
  1176. astman_send_ack(s, m, "Authentication accepted");
  1177. }
  1178. } else if (!strcasecmp(action, "Logoff")) {
  1179. astman_send_ack(s, m, "See ya");
  1180. return -1;
  1181. } else
  1182. astman_send_error(s, m, "Authentication Required");
  1183. } else {
  1184. int ret=0;
  1185. struct eventqent *eqe;
  1186. ast_mutex_lock(&s->__lock);
  1187. s->busy = 1;
  1188. ast_mutex_unlock(&s->__lock);
  1189. while( tmp ) {
  1190. if (!strcasecmp(action, tmp->action)) {
  1191. if ((s->writeperm & tmp->authority) == tmp->authority) {
  1192. if (tmp->func(s, m))
  1193. ret = -1;
  1194. } else {
  1195. astman_send_error(s, m, "Permission denied");
  1196. }
  1197. break;
  1198. }
  1199. tmp = tmp->next;
  1200. }
  1201. if (!tmp)
  1202. astman_send_error(s, m, "Invalid/unknown command");
  1203. ast_mutex_lock(&s->__lock);
  1204. s->busy = 0;
  1205. while(s->eventq) {
  1206. if (ast_carefulwrite(s->fd, s->eventq->eventdata, strlen(s->eventq->eventdata), s->writetimeout) < 0) {
  1207. ret = -1;
  1208. break;
  1209. }
  1210. eqe = s->eventq;
  1211. s->eventq = s->eventq->next;
  1212. free(eqe);
  1213. }
  1214. ast_mutex_unlock(&s->__lock);
  1215. return ret;
  1216. }
  1217. return 0;
  1218. }
  1219. static int get_input(struct mansession *s, char *output)
  1220. {
  1221. /* output must have at least sizeof(s->inbuf) space */
  1222. int res;
  1223. int x;
  1224. struct pollfd fds[1];
  1225. char iabuf[INET_ADDRSTRLEN];
  1226. for (x=1;x<s->inlen;x++) {
  1227. if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
  1228. /* Copy output data up to and including \r\n */
  1229. memcpy(output, s->inbuf, x + 1);
  1230. /* Add trailing \0 */
  1231. output[x+1] = '\0';
  1232. /* Move remaining data back to the front */
  1233. memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
  1234. s->inlen -= (x + 1);
  1235. return 1;
  1236. }
  1237. }
  1238. if (s->inlen >= sizeof(s->inbuf) - 1) {
  1239. ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->inbuf);
  1240. s->inlen = 0;
  1241. }
  1242. fds[0].fd = s->fd;
  1243. fds[0].events = POLLIN;
  1244. do {
  1245. res = poll(fds, 1, -1);
  1246. if (res < 0) {
  1247. if (errno == EINTR) {
  1248. if (s->dead)
  1249. return -1;
  1250. continue;
  1251. }
  1252. ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
  1253. return -1;
  1254. } else if (res > 0) {
  1255. ast_mutex_lock(&s->__lock);
  1256. res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
  1257. ast_mutex_unlock(&s->__lock);
  1258. if (res < 1)
  1259. return -1;
  1260. break;
  1261. }
  1262. } while(1);
  1263. s->inlen += res;
  1264. s->inbuf[s->inlen] = '\0';
  1265. return 0;
  1266. }
  1267. static void *session_do(void *data)
  1268. {
  1269. struct mansession *s = data;
  1270. struct message m;
  1271. char iabuf[INET_ADDRSTRLEN];
  1272. int res;
  1273. ast_mutex_lock(&s->__lock);
  1274. ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n");
  1275. ast_mutex_unlock(&s->__lock);
  1276. memset(&m, 0, sizeof(m));
  1277. for (;;) {
  1278. res = get_input(s, m.headers[m.hdrcount]);
  1279. if (res > 0) {
  1280. /* Strip trailing \r\n */
  1281. if (strlen(m.headers[m.hdrcount]) < 2)
  1282. continue;
  1283. m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
  1284. if (ast_strlen_zero(m.headers[m.hdrcount])) {
  1285. if (process_message(s, &m))
  1286. break;
  1287. memset(&m, 0, sizeof(m));
  1288. } else if (m.hdrcount < AST_MAX_MANHEADERS - 1)
  1289. m.hdrcount++;
  1290. } else if (res < 0)
  1291. break;
  1292. }
  1293. if (s->authenticated) {
  1294. if (option_verbose > 1) {
  1295. if (displayconnects)
  1296. ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
  1297. }
  1298. ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
  1299. } else {
  1300. if (option_verbose > 1) {
  1301. if ( displayconnects )
  1302. ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
  1303. }
  1304. ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr));
  1305. }
  1306. destroy_session(s);
  1307. return NULL;
  1308. }
  1309. static void *accept_thread(void *ignore)
  1310. {
  1311. int as;
  1312. struct sockaddr_in sin;
  1313. socklen_t sinlen;
  1314. struct mansession *s;
  1315. struct protoent *p;
  1316. int arg = 1;
  1317. int flags;
  1318. pthread_attr_t attr;
  1319. pthread_attr_init(&attr);
  1320. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  1321. for (;;) {
  1322. sinlen = sizeof(sin);
  1323. as = accept(asock, (struct sockaddr *)&sin, &sinlen);
  1324. if (as < 0) {
  1325. ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
  1326. continue;
  1327. }
  1328. p = getprotobyname("tcp");
  1329. if (p) {
  1330. if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
  1331. ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
  1332. }
  1333. }
  1334. s = malloc(sizeof(struct mansession));
  1335. if (!s) {
  1336. ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
  1337. continue;
  1338. }
  1339. memset(s, 0, sizeof(struct mansession));
  1340. memcpy(&s->sin, &sin, sizeof(sin));
  1341. s->writetimeout = 100;
  1342. if(! block_sockets) {
  1343. /* For safety, make sure socket is non-blocking */
  1344. flags = fcntl(as, F_GETFL);
  1345. fcntl(as, F_SETFL, flags | O_NONBLOCK);
  1346. }
  1347. ast_mutex_init(&s->__lock);
  1348. s->fd = as;
  1349. s->send_events = -1;
  1350. ast_mutex_lock(&sessionlock);
  1351. s->next = sessions;
  1352. sessions = s;
  1353. ast_mutex_unlock(&sessionlock);
  1354. if (ast_pthread_create(&s->t, &attr, session_do, s))
  1355. destroy_session(s);
  1356. }
  1357. pthread_attr_destroy(&attr);
  1358. return NULL;
  1359. }
  1360. static int append_event(struct mansession *s, const char *str)
  1361. {
  1362. struct eventqent *tmp, *prev=NULL;
  1363. tmp = malloc(sizeof(struct eventqent) + strlen(str));
  1364. if (tmp) {
  1365. tmp->next = NULL;
  1366. strcpy(tmp->eventdata, str);
  1367. if (s->eventq) {
  1368. prev = s->eventq;
  1369. while(prev->next)
  1370. prev = prev->next;
  1371. prev->next = tmp;
  1372. } else {
  1373. s->eventq = tmp;
  1374. }
  1375. return 0;
  1376. }
  1377. return -1;
  1378. }
  1379. /*! \brief manager_event: Send AMI event to client */
  1380. int manager_event(int category, char *event, char *fmt, ...)
  1381. {
  1382. struct mansession *s;
  1383. char auth[80];
  1384. char tmp[4096] = "";
  1385. char *tmp_next = tmp;
  1386. size_t tmp_left = sizeof(tmp) - 2;
  1387. va_list ap;
  1388. ast_mutex_lock(&sessionlock);
  1389. for (s = sessions; s; s = s->next) {
  1390. if ((s->readperm & category) != category)
  1391. continue;
  1392. if ((s->send_events & category) != category)
  1393. continue;
  1394. if (ast_strlen_zero(tmp)) {
  1395. ast_build_string(&tmp_next, &tmp_left, "Event: %s\r\nPrivilege: %s\r\n",
  1396. event, authority_to_str(category, auth, sizeof(auth)));
  1397. va_start(ap, fmt);
  1398. ast_build_string_va(&tmp_next, &tmp_left, fmt, ap);
  1399. va_end(ap);
  1400. *tmp_next++ = '\r';
  1401. *tmp_next++ = '\n';
  1402. *tmp_next = '\0';
  1403. }
  1404. ast_mutex_lock(&s->__lock);
  1405. if (s->busy) {
  1406. append_event(s, tmp);
  1407. } else if (!s->dead) {
  1408. if (ast_carefulwrite(s->fd, tmp, tmp_next - tmp, s->writetimeout) < 0) {
  1409. ast_log(LOG_WARNING, "Disconnecting slow (or gone) manager session!\n");
  1410. s->dead = 1;
  1411. pthread_kill(s->t, SIGURG);
  1412. }
  1413. }
  1414. ast_mutex_unlock(&s->__lock);
  1415. }
  1416. ast_mutex_unlock(&sessionlock);
  1417. return 0;
  1418. }
  1419. int ast_manager_unregister( char *action )
  1420. {
  1421. struct manager_action *cur = first_action, *prev = first_action;
  1422. ast_mutex_lock(&actionlock);
  1423. while( cur ) {
  1424. if (!strcasecmp(action, cur->action)) {
  1425. prev->next = cur->next;
  1426. free(cur);
  1427. if (option_verbose > 1)
  1428. ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action);
  1429. ast_mutex_unlock(&actionlock);
  1430. return 0;
  1431. }
  1432. prev = cur;
  1433. cur = cur->next;
  1434. }
  1435. ast_mutex_unlock(&actionlock);
  1436. return 0;
  1437. }
  1438. static int manager_state_cb(char *context, char *exten, int state, void *data)
  1439. {
  1440. /* Notify managers of change */
  1441. manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state);
  1442. return 0;
  1443. }
  1444. static int ast_manager_register_struct(struct manager_action *act)
  1445. {
  1446. struct manager_action *cur = first_action, *prev = NULL;
  1447. int ret;
  1448. ast_mutex_lock(&actionlock);
  1449. while(cur) { /* Walk the list of actions */
  1450. ret = strcasecmp(cur->action, act->action);
  1451. if (ret == 0) {
  1452. ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action);
  1453. ast_mutex_unlock(&actionlock);
  1454. return -1;
  1455. } else if (ret > 0) {
  1456. /* Insert these alphabetically */
  1457. if (prev) {
  1458. act->next = prev->next;
  1459. prev->next = act;
  1460. } else {
  1461. act->next = first_action;
  1462. first_action = act;
  1463. }
  1464. break;
  1465. }
  1466. prev = cur;
  1467. cur = cur->next;
  1468. }
  1469. if (!cur) {
  1470. if (prev)
  1471. prev->next = act;
  1472. else
  1473. first_action = act;
  1474. act->next = NULL;
  1475. }
  1476. if (option_verbose > 1)
  1477. ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action);
  1478. ast_mutex_unlock(&actionlock);
  1479. return 0;
  1480. }
  1481. /*! \brief register a new command with manager, including online help. This is
  1482. the preferred way to register a manager command */
  1483. int ast_manager_register2(const char *action, int auth, int (*func)(struct mansession *s, struct message *m), const char *synopsis, const char *description)
  1484. {
  1485. struct manager_action *cur;
  1486. cur = malloc(sizeof(struct manager_action));
  1487. if (!cur) {
  1488. ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n");
  1489. return -1;
  1490. }
  1491. cur->action = action;
  1492. cur->authority = auth;
  1493. cur->func = func;
  1494. cur->synopsis = synopsis;
  1495. cur->description = description;
  1496. cur->next = NULL;
  1497. ast_manager_register_struct(cur);
  1498. return 0;
  1499. }
  1500. /*! @}
  1501. END Doxygen group */
  1502. static int registered = 0;
  1503. int init_manager(void)
  1504. {
  1505. struct ast_config *cfg;
  1506. char *val;
  1507. int oldportno = portno;
  1508. static struct sockaddr_in ba;
  1509. int x = 1;
  1510. if (!registered) {
  1511. /* Register default actions */
  1512. ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping);
  1513. ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events);
  1514. ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff);
  1515. ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup);
  1516. ast_manager_register("Status", EVENT_FLAG_CALL, action_status, "Lists channel status" );
  1517. ast_manager_register2("Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar );
  1518. ast_manager_register2("Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar );
  1519. ast_manager_register2("Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call", mandescr_redirect );
  1520. ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate);
  1521. ast_manager_register2("Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command );
  1522. ast_manager_register2("ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate );
  1523. ast_manager_register2("AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout );
  1524. ast_manager_register2("MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus );
  1525. ast_manager_register2("MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count", mandescr_mailboxcount );
  1526. ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands);
  1527. ast_cli_register(&show_mancmd_cli);
  1528. ast_cli_register(&show_mancmds_cli);
  1529. ast_cli_register(&show_manconn_cli);
  1530. ast_extension_state_add(NULL, NULL, manager_state_cb, NULL);
  1531. registered = 1;
  1532. }
  1533. portno = DEFAULT_MANAGER_PORT;
  1534. displayconnects = 1;
  1535. cfg = ast_config_load("manager.conf");
  1536. if (!cfg) {
  1537. ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n");
  1538. return 0;
  1539. }
  1540. memset(&ba, 0, sizeof(ba));
  1541. val = ast_variable_retrieve(cfg, "general", "enabled");
  1542. if (val)
  1543. enabled = ast_true(val);
  1544. val = ast_variable_retrieve(cfg, "general", "block-sockets");
  1545. if(val)
  1546. block_sockets = ast_true(val);
  1547. if ((val = ast_variable_retrieve(cfg, "general", "port"))) {
  1548. if (sscanf(val, "%5d", &portno) != 1) {
  1549. ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
  1550. portno = DEFAULT_MANAGER_PORT;
  1551. }
  1552. } else if ((val = ast_variable_retrieve(cfg, "general", "portno"))) {
  1553. if (sscanf(val, "%5d", &portno) != 1) {
  1554. ast_log(LOG_WARNING, "Invalid port number '%s'\n", val);
  1555. portno = DEFAULT_MANAGER_PORT;
  1556. }
  1557. ast_log(LOG_NOTICE, "Use of portno in manager.conf deprecated. Please use 'port=%s' instead.\n", val);
  1558. }
  1559. /* Parsing the displayconnects */
  1560. if ((val = ast_variable_retrieve(cfg, "general", "displayconnects"))) {
  1561. displayconnects = ast_true(val);;
  1562. }
  1563. ba.sin_family = AF_INET;
  1564. ba.sin_port = htons(portno);
  1565. memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
  1566. if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) {
  1567. if (!inet_aton(val, &ba.sin_addr)) {
  1568. ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val);
  1569. memset(&ba.sin_addr, 0, sizeof(ba.sin_addr));
  1570. }
  1571. }
  1572. if ((asock > -1) && ((portno != oldportno) || !enabled)) {
  1573. #if 0
  1574. /* Can't be done yet */
  1575. close(asock);
  1576. asock = -1;
  1577. #else
  1578. ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
  1579. #endif
  1580. }
  1581. ast_config_destroy(cfg);
  1582. /* If not enabled, do nothing */
  1583. if (!enabled) {
  1584. return 0;
  1585. }
  1586. if (asock < 0) {
  1587. asock = socket(AF_INET, SOCK_STREAM, 0);
  1588. if (asock < 0) {
  1589. ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
  1590. return -1;
  1591. }
  1592. setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
  1593. if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) {
  1594. ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno));
  1595. close(asock);
  1596. asock = -1;
  1597. return -1;
  1598. }
  1599. if (listen(asock, 2)) {
  1600. ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno));
  1601. close(asock);
  1602. asock = -1;
  1603. return -1;
  1604. }
  1605. if (option_verbose)
  1606. ast_verbose("Asterisk Management interface listening on port %d\n", portno);
  1607. ast_pthread_create(&t, NULL, accept_thread, NULL);
  1608. }
  1609. return 0;
  1610. }
  1611. int reload_manager(void)
  1612. {
  1613. manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
  1614. return init_manager();
  1615. }