Fix a deadlock involving channel autoservice and chan_local that was debugged
[asterisk-bristuff.git] / channels / chan_local.c
blobe0c74313719f9633d30a689cf73e45a59da9eb0b
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
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.
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.
19 /*! \file
21 * \author Mark Spencer <markster@digium.com>
23 * \brief Local Proxy Channel
25 * \ingroup channel_drivers
28 #include "asterisk.h"
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32 #include <stdio.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <sys/socket.h>
36 #include <errno.h>
37 #include <stdlib.h>
38 #include <fcntl.h>
39 #include <netdb.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42 #include <sys/signal.h>
44 #include "asterisk/lock.h"
45 #include "asterisk/channel.h"
46 #include "asterisk/config.h"
47 #include "asterisk/logger.h"
48 #include "asterisk/module.h"
49 #include "asterisk/pbx.h"
50 #include "asterisk/options.h"
51 #include "asterisk/lock.h"
52 #include "asterisk/sched.h"
53 #include "asterisk/io.h"
54 #include "asterisk/rtp.h"
55 #include "asterisk/acl.h"
56 #include "asterisk/callerid.h"
57 #include "asterisk/file.h"
58 #include "asterisk/cli.h"
59 #include "asterisk/app.h"
60 #include "asterisk/musiconhold.h"
61 #include "asterisk/manager.h"
62 #include "asterisk/stringfields.h"
63 #include "asterisk/devicestate.h"
65 static const char tdesc[] = "Local Proxy Channel Driver";
67 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
69 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause);
70 static int local_digit_begin(struct ast_channel *ast, char digit);
71 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
72 static int local_call(struct ast_channel *ast, char *dest, int timeout);
73 static int local_hangup(struct ast_channel *ast);
74 static int local_answer(struct ast_channel *ast);
75 static struct ast_frame *local_read(struct ast_channel *ast);
76 static int local_write(struct ast_channel *ast, struct ast_frame *f);
77 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
78 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
79 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
80 static int local_sendtext(struct ast_channel *ast, const char *text);
81 static int local_devicestate(void *data);
83 /* PBX interface structure for channel registration */
84 static const struct ast_channel_tech local_tech = {
85 .type = "Local",
86 .description = tdesc,
87 .capabilities = -1,
88 .requester = local_request,
89 .send_digit_begin = local_digit_begin,
90 .send_digit_end = local_digit_end,
91 .call = local_call,
92 .hangup = local_hangup,
93 .answer = local_answer,
94 .read = local_read,
95 .write = local_write,
96 .write_video = local_write,
97 .exception = local_read,
98 .indicate = local_indicate,
99 .fixup = local_fixup,
100 .send_html = local_sendhtml,
101 .send_text = local_sendtext,
102 .devicestate = local_devicestate,
105 struct local_pvt {
106 ast_mutex_t lock; /* Channel private lock */
107 unsigned int flags; /* Private flags */
108 char context[AST_MAX_CONTEXT]; /* Context to call */
109 char exten[AST_MAX_EXTENSION]; /* Extension to call */
110 int reqformat; /* Requested format */
111 struct ast_channel *owner; /* Master Channel */
112 struct ast_channel *chan; /* Outbound channel */
113 struct ast_module_user *u_owner; /*! reference to keep the module loaded while in use */
114 struct ast_module_user *u_chan; /*! reference to keep the module loaded while in use */
115 AST_LIST_ENTRY(local_pvt) list; /* Next entity */
118 #define LOCAL_GLARE_DETECT (1 << 0) /*!< Detect glare on hangup */
119 #define LOCAL_CANCEL_QUEUE (1 << 1) /*!< Cancel queue */
120 #define LOCAL_ALREADY_MASQED (1 << 2) /*!< Already masqueraded */
121 #define LOCAL_LAUNCHED_PBX (1 << 3) /*!< PBX was launched */
122 #define LOCAL_NO_OPTIMIZATION (1 << 4) /*!< Do not optimize using masquerading */
124 static AST_LIST_HEAD_STATIC(locals, local_pvt);
126 /*! \brief Adds devicestate to local channels */
127 static int local_devicestate(void *data)
129 char *exten = ast_strdupa(data);
130 char *context = NULL, *opts = NULL;
131 int res;
133 if (!(context = strchr(exten, '@'))) {
134 ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
135 return AST_DEVICE_INVALID;
138 *context++ = '\0';
140 /* Strip options if they exist */
141 if ((opts = strchr(context, '/')))
142 *opts = '\0';
144 if (option_debug > 2)
145 ast_log(LOG_DEBUG, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
146 res = ast_exists_extension(NULL, context, exten, 1, NULL);
147 if (!res)
148 return AST_DEVICE_INVALID;
149 else
150 return AST_DEVICE_UNKNOWN;
154 * \note Assumes the pvt is no longer in the pvts list
156 static struct local_pvt *local_pvt_destroy(struct local_pvt *pvt)
158 ast_mutex_destroy(&pvt->lock);
159 free(pvt);
160 return NULL;
163 static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f,
164 struct ast_channel *us, int us_locked)
166 struct ast_channel *other = NULL;
168 /* Recalculate outbound channel */
169 other = isoutbound ? p->owner : p->chan;
171 /* Set glare detection */
172 ast_set_flag(p, LOCAL_GLARE_DETECT);
173 if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) {
174 /* We had a glare on the hangup. Forget all this business,
175 return and destroy p. */
176 ast_mutex_unlock(&p->lock);
177 p = local_pvt_destroy(p);
178 return -1;
180 if (!other) {
181 ast_clear_flag(p, LOCAL_GLARE_DETECT);
182 return 0;
185 /* Ensure that we have both channels locked */
186 while (other && ast_channel_trylock(other)) {
187 ast_mutex_unlock(&p->lock);
188 if (us && us_locked) {
189 ast_channel_unlock(us);
191 usleep(1);
192 if (us && us_locked) {
193 ast_channel_lock(us);
195 ast_mutex_lock(&p->lock);
196 other = isoutbound ? p->owner : p->chan;
199 if (other) {
200 ast_queue_frame(other, f);
201 ast_channel_unlock(other);
204 ast_clear_flag(p, LOCAL_GLARE_DETECT);
206 return 0;
209 static int local_answer(struct ast_channel *ast)
211 struct local_pvt *p = ast->tech_pvt;
212 int isoutbound;
213 int res = -1;
215 if (!p)
216 return -1;
218 ast_mutex_lock(&p->lock);
219 isoutbound = IS_OUTBOUND(ast, p);
220 if (isoutbound) {
221 /* Pass along answer since somebody answered us */
222 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
223 res = local_queue_frame(p, isoutbound, &answer, ast, 1);
224 } else
225 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n");
226 if (!res)
227 ast_mutex_unlock(&p->lock);
228 return res;
231 static void check_bridge(struct local_pvt *p, int isoutbound)
233 struct ast_channel_monitor *tmp;
234 if (ast_test_flag(p, LOCAL_ALREADY_MASQED) || ast_test_flag(p, LOCAL_NO_OPTIMIZATION) || !p->chan || !p->owner || (p->chan->_bridge != ast_bridged_channel(p->chan)))
235 return;
237 /* only do the masquerade if we are being called on the outbound channel,
238 if it has been bridged to another channel and if there are no pending
239 frames on the owner channel (because they would be transferred to the
240 outbound channel during the masquerade)
242 if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) {
243 /* Masquerade bridged channel into owner */
244 /* Lock everything we need, one by one, and give up if
245 we can't get everything. Remember, we'll get another
246 chance in just a little bit */
247 if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) {
248 if (!p->chan->_bridge->_softhangup) {
249 if (!ast_mutex_trylock(&p->owner->lock)) {
250 if (!p->owner->_softhangup) {
251 if(p->owner->monitor && !p->chan->_bridge->monitor) {
252 /* If a local channel is being monitored, we don't want a masquerade
253 * to cause the monitor to go away. Since the masquerade swaps the monitors,
254 * pre-swapping the monitors before the masquerade will ensure that the monitor
255 * ends up where it is expected.
257 tmp = p->owner->monitor;
258 p->owner->monitor = p->chan->_bridge->monitor;
259 p->chan->_bridge->monitor = tmp;
261 ast_channel_masquerade(p->owner, p->chan->_bridge);
262 ast_set_flag(p, LOCAL_ALREADY_MASQED);
264 ast_mutex_unlock(&p->owner->lock);
266 ast_mutex_unlock(&(p->chan->_bridge)->lock);
269 /* We only allow masquerading in one 'direction'... it's important to preserve the state
270 (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan)
271 when the local channels go away.
273 #if 0
274 } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) {
275 /* Masquerade bridged channel into chan */
276 if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) {
277 if (!p->owner->_bridge->_softhangup) {
278 if (!ast_mutex_trylock(&p->chan->lock)) {
279 if (!p->chan->_softhangup) {
280 ast_channel_masquerade(p->chan, p->owner->_bridge);
281 ast_set_flag(p, LOCAL_ALREADY_MASQED);
283 ast_mutex_unlock(&p->chan->lock);
286 ast_mutex_unlock(&(p->owner->_bridge)->lock);
288 #endif
292 static struct ast_frame *local_read(struct ast_channel *ast)
294 return &ast_null_frame;
297 static int local_write(struct ast_channel *ast, struct ast_frame *f)
299 struct local_pvt *p = ast->tech_pvt;
300 int res = -1;
301 int isoutbound;
303 if (!p)
304 return -1;
306 /* Just queue for delivery to the other side */
307 ast_mutex_lock(&p->lock);
308 isoutbound = IS_OUTBOUND(ast, p);
309 if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
310 check_bridge(p, isoutbound);
311 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
312 res = local_queue_frame(p, isoutbound, f, ast, 1);
313 else {
314 if (option_debug)
315 ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name);
316 res = 0;
318 if (!res)
319 ast_mutex_unlock(&p->lock);
320 return res;
323 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
325 struct local_pvt *p = newchan->tech_pvt;
327 if (!p)
328 return -1;
330 ast_mutex_lock(&p->lock);
332 if ((p->owner != oldchan) && (p->chan != oldchan)) {
333 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
334 ast_mutex_unlock(&p->lock);
335 return -1;
337 if (p->owner == oldchan)
338 p->owner = newchan;
339 else
340 p->chan = newchan;
341 ast_mutex_unlock(&p->lock);
342 return 0;
345 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
347 struct local_pvt *p = ast->tech_pvt;
348 int res = 0;
349 struct ast_frame f = { AST_FRAME_CONTROL, };
350 int isoutbound;
352 if (!p)
353 return -1;
355 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
356 if (condition == AST_CONTROL_HOLD) {
357 ast_moh_start(ast, data, NULL);
358 } else if (condition == AST_CONTROL_UNHOLD) {
359 ast_moh_stop(ast);
360 } else {
361 /* Queue up a frame representing the indication as a control frame */
362 ast_mutex_lock(&p->lock);
363 isoutbound = IS_OUTBOUND(ast, p);
364 f.subclass = condition;
365 f.data = (void*)data;
366 f.datalen = datalen;
367 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1)))
368 ast_mutex_unlock(&p->lock);
371 return res;
374 static int local_digit_begin(struct ast_channel *ast, char digit)
376 struct local_pvt *p = ast->tech_pvt;
377 int res = -1;
378 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
379 int isoutbound;
381 if (!p)
382 return -1;
384 ast_mutex_lock(&p->lock);
385 isoutbound = IS_OUTBOUND(ast, p);
386 f.subclass = digit;
387 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
388 ast_mutex_unlock(&p->lock);
390 return res;
393 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
395 struct local_pvt *p = ast->tech_pvt;
396 int res = -1;
397 struct ast_frame f = { AST_FRAME_DTMF_END, };
398 int isoutbound;
400 if (!p)
401 return -1;
403 ast_mutex_lock(&p->lock);
404 isoutbound = IS_OUTBOUND(ast, p);
405 f.subclass = digit;
406 f.len = duration;
407 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
408 ast_mutex_unlock(&p->lock);
410 return res;
413 static int local_sendtext(struct ast_channel *ast, const char *text)
415 struct local_pvt *p = ast->tech_pvt;
416 int res = -1;
417 struct ast_frame f = { AST_FRAME_TEXT, };
418 int isoutbound;
420 if (!p)
421 return -1;
423 ast_mutex_lock(&p->lock);
424 isoutbound = IS_OUTBOUND(ast, p);
425 f.data = (char *) text;
426 f.datalen = strlen(text) + 1;
427 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
428 ast_mutex_unlock(&p->lock);
429 return res;
432 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
434 struct local_pvt *p = ast->tech_pvt;
435 int res = -1;
436 struct ast_frame f = { AST_FRAME_HTML, };
437 int isoutbound;
439 if (!p)
440 return -1;
442 ast_mutex_lock(&p->lock);
443 isoutbound = IS_OUTBOUND(ast, p);
444 f.subclass = subclass;
445 f.data = (char *)data;
446 f.datalen = datalen;
447 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
448 ast_mutex_unlock(&p->lock);
449 return res;
452 /*! \brief Initiate new call, part of PBX interface
453 * dest is the dial string */
454 static int local_call(struct ast_channel *ast, char *dest, int timeout)
456 struct local_pvt *p = ast->tech_pvt;
457 int res;
458 struct ast_var_t *varptr = NULL, *new;
459 size_t len, namelen;
461 if (!p)
462 return -1;
464 ast_mutex_lock(&p->lock);
467 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
468 * call, so it's done here instead.
470 p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
471 p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
472 p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
473 p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
474 p->chan->cid.cid_pres = p->owner->cid.cid_pres;
475 ast_string_field_set(p->chan, language, p->owner->language);
476 ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
477 ast_cdr_update(p->chan);
478 p->chan->cdrflags = p->owner->cdrflags;
480 /* copy the channel variables from the incoming channel to the outgoing channel */
481 /* Note that due to certain assumptions, they MUST be in the same order */
482 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
483 namelen = strlen(varptr->name);
484 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
485 if ((new = ast_calloc(1, len))) {
486 memcpy(new, varptr, len);
487 new->value = &(new->name[0]) + namelen + 1;
488 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
491 ast_channel_datastore_inherit(p->owner, p->chan);
493 /* Start switch on sub channel */
494 if (!(res = ast_pbx_start(p->chan)))
495 ast_set_flag(p, LOCAL_LAUNCHED_PBX);
497 ast_mutex_unlock(&p->lock);
498 return res;
501 /*! \brief Hangup a call through the local proxy channel */
502 static int local_hangup(struct ast_channel *ast)
504 struct local_pvt *p = ast->tech_pvt;
505 int isoutbound;
506 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP };
507 struct ast_channel *ochan = NULL;
508 int glaredetect = 0, res = 0;
510 if (!p)
511 return -1;
513 ast_mutex_lock(&p->lock);
514 isoutbound = IS_OUTBOUND(ast, p);
515 if (isoutbound) {
516 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
517 if ((status) && (p->owner)) {
518 /* Deadlock avoidance */
519 while (p->owner && ast_channel_trylock(p->owner)) {
520 ast_mutex_unlock(&p->lock);
521 if (ast) {
522 ast_channel_unlock(ast);
524 usleep(1);
525 if (ast) {
526 ast_channel_lock(ast);
528 ast_mutex_lock(&p->lock);
530 if (p->owner) {
531 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
532 ast_channel_unlock(p->owner);
535 p->chan = NULL;
536 ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
537 ast_module_user_remove(p->u_chan);
538 } else {
539 p->owner = NULL;
540 ast_module_user_remove(p->u_owner);
543 ast->tech_pvt = NULL;
545 if (!p->owner && !p->chan) {
546 /* Okay, done with the private part now, too. */
547 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
548 /* If we have a queue holding, don't actually destroy p yet, but
549 let local_queue do it. */
550 if (glaredetect)
551 ast_set_flag(p, LOCAL_CANCEL_QUEUE);
552 ast_mutex_unlock(&p->lock);
553 /* Remove from list */
554 AST_LIST_LOCK(&locals);
555 AST_LIST_REMOVE(&locals, p, list);
556 AST_LIST_UNLOCK(&locals);
557 /* Grab / release lock just in case */
558 ast_mutex_lock(&p->lock);
559 ast_mutex_unlock(&p->lock);
560 /* And destroy */
561 if (!glaredetect) {
562 p = local_pvt_destroy(p);
564 return 0;
566 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
567 /* Need to actually hangup since there is no PBX */
568 ochan = p->chan;
569 else
570 res = local_queue_frame(p, isoutbound, &f, NULL, 1);
571 if (!res)
572 ast_mutex_unlock(&p->lock);
573 if (ochan)
574 ast_hangup(ochan);
575 return 0;
578 /*! \brief Create a call structure */
579 static struct local_pvt *local_alloc(const char *data, int format)
581 struct local_pvt *tmp = NULL;
582 char *c = NULL, *opts = NULL;
584 if (!(tmp = ast_calloc(1, sizeof(*tmp))))
585 return NULL;
587 /* Initialize private structure information */
588 ast_mutex_init(&tmp->lock);
589 ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
591 /* Look for options */
592 if ((opts = strchr(tmp->exten, '/'))) {
593 *opts++ = '\0';
594 if (strchr(opts, 'n'))
595 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
598 /* Look for a context */
599 if ((c = strchr(tmp->exten, '@')))
600 *c++ = '\0';
602 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
604 tmp->reqformat = format;
606 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
607 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
608 tmp = local_pvt_destroy(tmp);
609 } else {
610 /* Add to list */
611 AST_LIST_LOCK(&locals);
612 AST_LIST_INSERT_HEAD(&locals, tmp, list);
613 AST_LIST_UNLOCK(&locals);
616 return tmp;
619 /*! \brief Start new local channel */
620 static struct ast_channel *local_new(struct local_pvt *p, int state)
622 struct ast_channel *tmp = NULL, *tmp2 = NULL;
623 int randnum = ast_random() & 0xffff, fmt = 0;
624 const char *t;
625 int ama;
627 /* Allocate two new Asterisk channels */
628 /* safe accountcode */
629 if (p->owner && p->owner->accountcode)
630 t = p->owner->accountcode;
631 else
632 t = "";
634 if (p->owner)
635 ama = p->owner->amaflags;
636 else
637 ama = 0;
638 if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x,1", p->exten, p->context, randnum))
639 || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x,2", p->exten, p->context, randnum))) {
640 if (tmp)
641 ast_channel_free(tmp);
642 if (tmp2)
643 ast_channel_free(tmp2);
644 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
645 return NULL;
648 tmp2->tech = tmp->tech = &local_tech;
650 tmp->nativeformats = p->reqformat;
651 tmp2->nativeformats = p->reqformat;
653 /* Determine our read/write format and set it on each channel */
654 fmt = ast_best_codec(p->reqformat);
655 tmp->writeformat = fmt;
656 tmp2->writeformat = fmt;
657 tmp->rawwriteformat = fmt;
658 tmp2->rawwriteformat = fmt;
659 tmp->readformat = fmt;
660 tmp2->readformat = fmt;
661 tmp->rawreadformat = fmt;
662 tmp2->rawreadformat = fmt;
664 tmp->tech_pvt = p;
665 tmp2->tech_pvt = p;
667 p->owner = tmp;
668 p->chan = tmp2;
669 p->u_owner = ast_module_user_add(p->owner);
670 p->u_chan = ast_module_user_add(p->chan);
672 ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
673 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
674 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
675 tmp->priority = 1;
676 tmp2->priority = 1;
678 return tmp;
681 /*! \brief Part of PBX interface */
682 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
684 struct local_pvt *p = NULL;
685 struct ast_channel *chan = NULL;
687 /* Allocate a new private structure and then Asterisk channel */
688 if ((p = local_alloc(data, format))) {
689 if (!(chan = local_new(p, AST_STATE_DOWN))) {
690 AST_LIST_LOCK(&locals);
691 AST_LIST_REMOVE(&locals, p, list);
692 AST_LIST_UNLOCK(&locals);
693 p = local_pvt_destroy(p);
697 return chan;
700 /*! \brief CLI command "local show channels" */
701 static int locals_show(int fd, int argc, char **argv)
703 struct local_pvt *p = NULL;
705 if (argc != 3)
706 return RESULT_SHOWUSAGE;
708 AST_LIST_LOCK(&locals);
709 if (!AST_LIST_EMPTY(&locals)) {
710 AST_LIST_TRAVERSE(&locals, p, list) {
711 ast_mutex_lock(&p->lock);
712 ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
713 ast_mutex_unlock(&p->lock);
715 } else
716 ast_cli(fd, "No local channels in use\n");
717 AST_LIST_UNLOCK(&locals);
719 return RESULT_SUCCESS;
722 static char show_locals_usage[] =
723 "Usage: local show channels\n"
724 " Provides summary information on active local proxy channels.\n";
726 static struct ast_cli_entry cli_local[] = {
727 { { "local", "show", "channels", NULL },
728 locals_show, "List status of local channels",
729 show_locals_usage },
732 /*! \brief Load module into PBX, register channel */
733 static int load_module(void)
735 /* Make sure we can register our channel type */
736 if (ast_channel_register(&local_tech)) {
737 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
738 return -1;
740 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
741 return 0;
744 /*! \brief Unload the local proxy channel from Asterisk */
745 static int unload_module(void)
747 struct local_pvt *p = NULL;
749 /* First, take us out of the channel loop */
750 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
751 ast_channel_unregister(&local_tech);
752 if (!AST_LIST_LOCK(&locals)) {
753 /* Hangup all interfaces if they have an owner */
754 AST_LIST_TRAVERSE(&locals, p, list) {
755 if (p->owner)
756 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
758 AST_LIST_UNLOCK(&locals);
759 AST_LIST_HEAD_DESTROY(&locals);
760 } else {
761 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
762 return -1;
764 return 0;
767 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Local Proxy Channel (Note: used internally by other modules)");