Merged revisions 121078 via svnmerge from
[asterisk-bristuff.git] / channels / chan_local.c
blobd53184462e5406a1f42f1b3ed5a8967a0f1faddf
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 <fcntl.h>
33 #include <sys/signal.h>
35 #include "asterisk/lock.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/config.h"
38 #include "asterisk/module.h"
39 #include "asterisk/pbx.h"
40 #include "asterisk/sched.h"
41 #include "asterisk/io.h"
42 #include "asterisk/rtp.h"
43 #include "asterisk/acl.h"
44 #include "asterisk/callerid.h"
45 #include "asterisk/file.h"
46 #include "asterisk/cli.h"
47 #include "asterisk/app.h"
48 #include "asterisk/musiconhold.h"
49 #include "asterisk/manager.h"
50 #include "asterisk/stringfields.h"
51 #include "asterisk/devicestate.h"
53 static const char tdesc[] = "Local Proxy Channel Driver";
55 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
57 static struct ast_jb_conf g_jb_conf = {
58 .flags = 0,
59 .max_size = -1,
60 .resync_threshold = -1,
61 .impl = "",
64 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause);
65 static int local_digit_begin(struct ast_channel *ast, char digit);
66 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
67 static int local_call(struct ast_channel *ast, char *dest, int timeout);
68 static int local_hangup(struct ast_channel *ast);
69 static int local_answer(struct ast_channel *ast);
70 static struct ast_frame *local_read(struct ast_channel *ast);
71 static int local_write(struct ast_channel *ast, struct ast_frame *f);
72 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
73 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
74 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
75 static int local_sendtext(struct ast_channel *ast, const char *text);
76 static int local_devicestate(void *data);
77 static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
79 /* PBX interface structure for channel registration */
80 static const struct ast_channel_tech local_tech = {
81 .type = "Local",
82 .description = tdesc,
83 .capabilities = -1,
84 .requester = local_request,
85 .send_digit_begin = local_digit_begin,
86 .send_digit_end = local_digit_end,
87 .call = local_call,
88 .hangup = local_hangup,
89 .answer = local_answer,
90 .read = local_read,
91 .write = local_write,
92 .write_video = local_write,
93 .exception = local_read,
94 .indicate = local_indicate,
95 .fixup = local_fixup,
96 .send_html = local_sendhtml,
97 .send_text = local_sendtext,
98 .devicestate = local_devicestate,
99 .bridged_channel = local_bridgedchannel,
102 struct local_pvt {
103 ast_mutex_t lock; /* Channel private lock */
104 unsigned int flags; /* Private flags */
105 char context[AST_MAX_CONTEXT]; /* Context to call */
106 char exten[AST_MAX_EXTENSION]; /* Extension to call */
107 int reqformat; /* Requested format */
108 struct ast_jb_conf jb_conf; /*!< jitterbuffer configuration for this local channel */
109 struct ast_channel *owner; /* Master Channel */
110 struct ast_channel *chan; /* Outbound channel */
111 struct ast_module_user *u_owner; /*! reference to keep the module loaded while in use */
112 struct ast_module_user *u_chan; /*! reference to keep the module loaded while in use */
113 AST_LIST_ENTRY(local_pvt) list; /* Next entity */
116 #define LOCAL_GLARE_DETECT (1 << 0) /*!< Detect glare on hangup */
117 #define LOCAL_CANCEL_QUEUE (1 << 1) /*!< Cancel queue */
118 #define LOCAL_ALREADY_MASQED (1 << 2) /*!< Already masqueraded */
119 #define LOCAL_LAUNCHED_PBX (1 << 3) /*!< PBX was launched */
120 #define LOCAL_NO_OPTIMIZATION (1 << 4) /*!< Do not optimize using masquerading */
121 #define LOCAL_BRIDGE (1 << 5) /*!< Report back the "true" channel as being bridged to */
123 static AST_LIST_HEAD_STATIC(locals, local_pvt);
125 /*! \brief Adds devicestate to local channels */
126 static int local_devicestate(void *data)
128 char *exten = ast_strdupa(data);
129 char *context = NULL, *opts = NULL;
130 int res;
131 struct local_pvt *lp;
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 ast_debug(3, "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;
150 res = AST_DEVICE_NOT_INUSE;
151 AST_LIST_LOCK(&locals);
152 AST_LIST_TRAVERSE(&locals, lp, list) {
153 if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) {
154 res = AST_DEVICE_INUSE;
155 break;
158 AST_LIST_UNLOCK(&locals);
160 return res;
164 * \note Assumes the pvt is no longer in the pvts list
166 static struct local_pvt *local_pvt_destroy(struct local_pvt *pvt)
168 ast_mutex_destroy(&pvt->lock);
169 ast_free(pvt);
170 return NULL;
173 /*! \brief Return the bridged channel of a Local channel */
174 static struct ast_channel *local_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
176 struct local_pvt *p = bridge->tech_pvt;
177 struct ast_channel *bridged = bridge;
179 ast_mutex_lock(&p->lock);
181 if (ast_test_flag(p, LOCAL_BRIDGE)) {
182 /* Find the opposite channel */
183 bridged = (bridge == p->owner ? p->chan : p->owner);
185 /* Now see if the opposite channel is bridged to anything */
186 if (!bridged) {
187 bridged = bridge;
188 } else if (bridged->_bridge) {
189 bridged = bridged->_bridge;
193 ast_mutex_unlock(&p->lock);
195 return bridged;
198 static int local_queue_frame(struct local_pvt *p, int isoutbound, struct ast_frame *f,
199 struct ast_channel *us, int us_locked)
201 struct ast_channel *other = NULL;
203 /* Recalculate outbound channel */
204 other = isoutbound ? p->owner : p->chan;
206 /* Set glare detection */
207 ast_set_flag(p, LOCAL_GLARE_DETECT);
208 if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) {
209 /* We had a glare on the hangup. Forget all this business,
210 return and destroy p. */
211 ast_mutex_unlock(&p->lock);
212 p = local_pvt_destroy(p);
213 return -1;
215 if (!other) {
216 ast_clear_flag(p, LOCAL_GLARE_DETECT);
217 return 0;
220 /* Ensure that we have both channels locked */
221 while (other && ast_channel_trylock(other)) {
222 ast_mutex_unlock(&p->lock);
223 if (us && us_locked) {
224 ast_channel_unlock(us);
226 usleep(1);
227 if (us && us_locked) {
228 ast_channel_lock(us);
230 ast_mutex_lock(&p->lock);
231 other = isoutbound ? p->owner : p->chan;
234 if (other) {
235 ast_queue_frame(other, f);
236 ast_channel_unlock(other);
239 ast_clear_flag(p, LOCAL_GLARE_DETECT);
241 return 0;
244 static int local_answer(struct ast_channel *ast)
246 struct local_pvt *p = ast->tech_pvt;
247 int isoutbound;
248 int res = -1;
250 if (!p)
251 return -1;
253 ast_mutex_lock(&p->lock);
254 isoutbound = IS_OUTBOUND(ast, p);
255 if (isoutbound) {
256 /* Pass along answer since somebody answered us */
257 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
258 res = local_queue_frame(p, isoutbound, &answer, ast, 1);
259 } else
260 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n");
261 if (!res)
262 ast_mutex_unlock(&p->lock);
263 return res;
266 static void check_bridge(struct local_pvt *p, int isoutbound)
268 struct ast_channel_monitor *tmp;
269 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)))
270 return;
272 /* only do the masquerade if we are being called on the outbound channel,
273 if it has been bridged to another channel and if there are no pending
274 frames on the owner channel (because they would be transferred to the
275 outbound channel during the masquerade)
277 if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) {
278 /* Masquerade bridged channel into owner */
279 /* Lock everything we need, one by one, and give up if
280 we can't get everything. Remember, we'll get another
281 chance in just a little bit */
282 if (!ast_channel_trylock(p->chan->_bridge)) {
283 if (!ast_check_hangup(p->chan->_bridge)) {
284 if (!ast_channel_trylock(p->owner)) {
285 if (!ast_check_hangup(p->owner)) {
286 if(p->owner->monitor && !p->chan->_bridge->monitor) {
287 /* If a local channel is being monitored, we don't want a masquerade
288 * to cause the monitor to go away. Since the masquerade swaps the monitors,
289 * pre-swapping the monitors before the masquerade will ensure that the monitor
290 * ends up where it is expected.
292 tmp = p->owner->monitor;
293 p->owner->monitor = p->chan->_bridge->monitor;
294 p->chan->_bridge->monitor = tmp;
296 ast_channel_masquerade(p->owner, p->chan->_bridge);
297 ast_set_flag(p, LOCAL_ALREADY_MASQED);
299 ast_channel_unlock(p->owner);
301 ast_channel_unlock(p->chan->_bridge);
304 /* We only allow masquerading in one 'direction'... it's important to preserve the state
305 (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan)
306 when the local channels go away.
308 #if 0
309 } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) {
310 /* Masquerade bridged channel into chan */
311 if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) {
312 if (!ast_check_hangup(p->owner->_bridge)) {
313 if (!ast_mutex_trylock(&p->chan->lock)) {
314 if (!ast_check_hangup(p->chan)) {
315 ast_channel_masquerade(p->chan, p->owner->_bridge);
316 ast_set_flag(p, LOCAL_ALREADY_MASQED);
318 ast_mutex_unlock(&p->chan->lock);
321 ast_mutex_unlock(&(p->owner->_bridge)->lock);
323 #endif
327 static struct ast_frame *local_read(struct ast_channel *ast)
329 return &ast_null_frame;
332 static int local_write(struct ast_channel *ast, struct ast_frame *f)
334 struct local_pvt *p = ast->tech_pvt;
335 int res = -1;
336 int isoutbound;
338 if (!p)
339 return -1;
341 /* Just queue for delivery to the other side */
342 ast_mutex_lock(&p->lock);
343 isoutbound = IS_OUTBOUND(ast, p);
344 if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
345 check_bridge(p, isoutbound);
346 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
347 res = local_queue_frame(p, isoutbound, f, ast, 1);
348 else {
349 ast_debug(1, "Not posting to queue since already masked on '%s'\n", ast->name);
350 res = 0;
352 if (!res)
353 ast_mutex_unlock(&p->lock);
354 return res;
357 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
359 struct local_pvt *p = newchan->tech_pvt;
361 if (!p)
362 return -1;
364 ast_mutex_lock(&p->lock);
366 if ((p->owner != oldchan) && (p->chan != oldchan)) {
367 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
368 ast_mutex_unlock(&p->lock);
369 return -1;
371 if (p->owner == oldchan)
372 p->owner = newchan;
373 else
374 p->chan = newchan;
375 ast_mutex_unlock(&p->lock);
376 return 0;
379 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
381 struct local_pvt *p = ast->tech_pvt;
382 int res = 0;
383 struct ast_frame f = { AST_FRAME_CONTROL, };
384 int isoutbound;
386 if (!p)
387 return -1;
389 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
390 if (condition == AST_CONTROL_HOLD) {
391 ast_moh_start(ast, data, NULL);
392 } else if (condition == AST_CONTROL_UNHOLD) {
393 ast_moh_stop(ast);
394 } else {
395 /* Queue up a frame representing the indication as a control frame */
396 ast_mutex_lock(&p->lock);
397 isoutbound = IS_OUTBOUND(ast, p);
398 f.subclass = condition;
399 f.data.ptr = (void*)data;
400 f.datalen = datalen;
401 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1)))
402 ast_mutex_unlock(&p->lock);
405 return res;
408 static int local_digit_begin(struct ast_channel *ast, char digit)
410 struct local_pvt *p = ast->tech_pvt;
411 int res = -1;
412 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
413 int isoutbound;
415 if (!p)
416 return -1;
418 ast_mutex_lock(&p->lock);
419 isoutbound = IS_OUTBOUND(ast, p);
420 f.subclass = digit;
421 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
422 ast_mutex_unlock(&p->lock);
424 return res;
427 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
429 struct local_pvt *p = ast->tech_pvt;
430 int res = -1;
431 struct ast_frame f = { AST_FRAME_DTMF_END, };
432 int isoutbound;
434 if (!p)
435 return -1;
437 ast_mutex_lock(&p->lock);
438 isoutbound = IS_OUTBOUND(ast, p);
439 f.subclass = digit;
440 f.len = duration;
441 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
442 ast_mutex_unlock(&p->lock);
444 return res;
447 static int local_sendtext(struct ast_channel *ast, const char *text)
449 struct local_pvt *p = ast->tech_pvt;
450 int res = -1;
451 struct ast_frame f = { AST_FRAME_TEXT, };
452 int isoutbound;
454 if (!p)
455 return -1;
457 ast_mutex_lock(&p->lock);
458 isoutbound = IS_OUTBOUND(ast, p);
459 f.data.ptr = (char *) text;
460 f.datalen = strlen(text) + 1;
461 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
462 ast_mutex_unlock(&p->lock);
463 return res;
466 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
468 struct local_pvt *p = ast->tech_pvt;
469 int res = -1;
470 struct ast_frame f = { AST_FRAME_HTML, };
471 int isoutbound;
473 if (!p)
474 return -1;
476 ast_mutex_lock(&p->lock);
477 isoutbound = IS_OUTBOUND(ast, p);
478 f.subclass = subclass;
479 f.data.ptr = (char *)data;
480 f.datalen = datalen;
481 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
482 ast_mutex_unlock(&p->lock);
483 return res;
486 /*! \brief Initiate new call, part of PBX interface
487 * dest is the dial string */
488 static int local_call(struct ast_channel *ast, char *dest, int timeout)
490 struct local_pvt *p = ast->tech_pvt;
491 int res;
492 struct ast_var_t *varptr = NULL, *new;
493 size_t len, namelen;
495 if (!p)
496 return -1;
498 ast_mutex_lock(&p->lock);
501 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
502 * call, so it's done here instead.
504 p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
505 p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
506 p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
507 p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
508 p->chan->cid.cid_pres = p->owner->cid.cid_pres;
509 ast_string_field_set(p->chan, language, p->owner->language);
510 ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
511 ast_cdr_update(p->chan);
512 p->chan->cdrflags = p->owner->cdrflags;
514 /* copy the channel variables from the incoming channel to the outgoing channel */
515 /* Note that due to certain assumptions, they MUST be in the same order */
516 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
517 namelen = strlen(varptr->name);
518 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
519 if ((new = ast_calloc(1, len))) {
520 memcpy(new, varptr, len);
521 new->value = &(new->name[0]) + namelen + 1;
522 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
525 ast_channel_datastore_inherit(p->owner, p->chan);
527 /* Start switch on sub channel */
528 if (!(res = ast_pbx_start(p->chan)))
529 ast_set_flag(p, LOCAL_LAUNCHED_PBX);
531 ast_mutex_unlock(&p->lock);
532 return res;
535 /*! \brief Hangup a call through the local proxy channel */
536 static int local_hangup(struct ast_channel *ast)
538 struct local_pvt *p = ast->tech_pvt;
539 int isoutbound;
540 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP, .data.uint32 = ast->hangupcause };
541 struct ast_channel *ochan = NULL;
542 int glaredetect = 0, res = 0;
544 if (!p)
545 return -1;
547 ast_mutex_lock(&p->lock);
548 if (p->chan && ast_test_flag(ast, AST_FLAG_ANSWERED_ELSEWHERE))
549 ast_set_flag(p->chan, AST_FLAG_ANSWERED_ELSEWHERE);
550 isoutbound = IS_OUTBOUND(ast, p);
551 if (isoutbound) {
552 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
553 if ((status) && (p->owner)) {
554 /* Deadlock avoidance */
555 while (p->owner && ast_channel_trylock(p->owner)) {
556 ast_mutex_unlock(&p->lock);
557 if (ast) {
558 ast_channel_unlock(ast);
560 usleep(1);
561 if (ast) {
562 ast_channel_lock(ast);
564 ast_mutex_lock(&p->lock);
566 if (p->owner) {
567 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
568 ast_channel_unlock(p->owner);
571 p->chan = NULL;
572 ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
573 ast_module_user_remove(p->u_chan);
574 } else {
575 p->owner = NULL;
576 ast_module_user_remove(p->u_owner);
579 ast->tech_pvt = NULL;
581 if (!p->owner && !p->chan) {
582 /* Okay, done with the private part now, too. */
583 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
584 /* If we have a queue holding, don't actually destroy p yet, but
585 let local_queue do it. */
586 if (glaredetect)
587 ast_set_flag(p, LOCAL_CANCEL_QUEUE);
588 ast_mutex_unlock(&p->lock);
589 /* Remove from list */
590 AST_LIST_LOCK(&locals);
591 AST_LIST_REMOVE(&locals, p, list);
592 AST_LIST_UNLOCK(&locals);
593 /* Grab / release lock just in case */
594 ast_mutex_lock(&p->lock);
595 ast_mutex_unlock(&p->lock);
596 /* And destroy */
597 if (!glaredetect) {
598 p = local_pvt_destroy(p);
600 return 0;
602 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
603 /* Need to actually hangup since there is no PBX */
604 ochan = p->chan;
605 else
606 res = local_queue_frame(p, isoutbound, &f, NULL, 1);
607 if (!res)
608 ast_mutex_unlock(&p->lock);
609 if (ochan)
610 ast_hangup(ochan);
611 return 0;
614 /*! \brief Create a call structure */
615 static struct local_pvt *local_alloc(const char *data, int format)
617 struct local_pvt *tmp = NULL;
618 char *c = NULL, *opts = NULL;
620 if (!(tmp = ast_calloc(1, sizeof(*tmp))))
621 return NULL;
623 /* Initialize private structure information */
624 ast_mutex_init(&tmp->lock);
625 ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
627 memcpy(&tmp->jb_conf, &g_jb_conf, sizeof(tmp->jb_conf));
629 /* Look for options */
630 if ((opts = strchr(tmp->exten, '/'))) {
631 *opts++ = '\0';
632 if (strchr(opts, 'n'))
633 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
634 if (strchr(opts, 'j')) {
635 if (ast_test_flag(tmp, LOCAL_NO_OPTIMIZATION))
636 ast_set_flag(&tmp->jb_conf, AST_JB_ENABLED);
637 else {
638 ast_log(LOG_ERROR, "You must use the 'n' option for chan_local "
639 "to use the 'j' option to enable the jitterbuffer\n");
642 if (strchr(opts, 'b')) {
643 ast_set_flag(tmp, LOCAL_BRIDGE);
647 /* Look for a context */
648 if ((c = strchr(tmp->exten, '@')))
649 *c++ = '\0';
651 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
653 tmp->reqformat = format;
655 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
656 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
657 tmp = local_pvt_destroy(tmp);
658 } else {
659 /* Add to list */
660 AST_LIST_LOCK(&locals);
661 AST_LIST_INSERT_HEAD(&locals, tmp, list);
662 AST_LIST_UNLOCK(&locals);
665 return tmp;
668 /*! \brief Start new local channel */
669 static struct ast_channel *local_new(struct local_pvt *p, int state)
671 struct ast_channel *tmp = NULL, *tmp2 = NULL;
672 int randnum = ast_random() & 0xffff, fmt = 0;
673 const char *t;
674 int ama;
676 /* Allocate two new Asterisk channels */
677 /* safe accountcode */
678 if (p->owner && p->owner->accountcode)
679 t = p->owner->accountcode;
680 else
681 t = "";
683 if (p->owner)
684 ama = p->owner->amaflags;
685 else
686 ama = 0;
687 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))
688 || !(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))) {
689 if (tmp)
690 ast_channel_free(tmp);
691 if (tmp2)
692 ast_channel_free(tmp2);
693 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
694 return NULL;
697 tmp2->tech = tmp->tech = &local_tech;
699 tmp->nativeformats = p->reqformat;
700 tmp2->nativeformats = p->reqformat;
702 /* Determine our read/write format and set it on each channel */
703 fmt = ast_best_codec(p->reqformat);
704 tmp->writeformat = fmt;
705 tmp2->writeformat = fmt;
706 tmp->rawwriteformat = fmt;
707 tmp2->rawwriteformat = fmt;
708 tmp->readformat = fmt;
709 tmp2->readformat = fmt;
710 tmp->rawreadformat = fmt;
711 tmp2->rawreadformat = fmt;
713 tmp->tech_pvt = p;
714 tmp2->tech_pvt = p;
716 p->owner = tmp;
717 p->chan = tmp2;
718 p->u_owner = ast_module_user_add(p->owner);
719 p->u_chan = ast_module_user_add(p->chan);
721 ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
722 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
723 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
724 tmp->priority = 1;
725 tmp2->priority = 1;
727 ast_jb_configure(tmp, &p->jb_conf);
729 return tmp;
732 /*! \brief Part of PBX interface */
733 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
735 struct local_pvt *p = NULL;
736 struct ast_channel *chan = NULL;
738 /* Allocate a new private structure and then Asterisk channel */
739 if ((p = local_alloc(data, format))) {
740 if (!(chan = local_new(p, AST_STATE_DOWN))) {
741 AST_LIST_LOCK(&locals);
742 AST_LIST_REMOVE(&locals, p, list);
743 AST_LIST_UNLOCK(&locals);
744 p = local_pvt_destroy(p);
748 return chan;
751 /*! \brief CLI command "local show channels" */
752 static char *locals_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
754 struct local_pvt *p = NULL;
756 switch (cmd) {
757 case CLI_INIT:
758 e->command = "local show channels";
759 e->usage =
760 "Usage: local show channels\n"
761 " Provides summary information on active local proxy channels.\n";
762 return NULL;
763 case CLI_GENERATE:
764 return NULL;
767 if (a->argc != 3)
768 return CLI_SHOWUSAGE;
770 AST_LIST_LOCK(&locals);
771 if (!AST_LIST_EMPTY(&locals)) {
772 AST_LIST_TRAVERSE(&locals, p, list) {
773 ast_mutex_lock(&p->lock);
774 ast_cli(a->fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
775 ast_mutex_unlock(&p->lock);
777 } else
778 ast_cli(a->fd, "No local channels in use\n");
779 AST_LIST_UNLOCK(&locals);
781 return CLI_SUCCESS;
784 static struct ast_cli_entry cli_local[] = {
785 AST_CLI_DEFINE(locals_show, "List status of local channels"),
788 /*! \brief Load module into PBX, register channel */
789 static int load_module(void)
791 /* Make sure we can register our channel type */
792 if (ast_channel_register(&local_tech)) {
793 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
794 return AST_MODULE_LOAD_FAILURE;
796 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
797 return AST_MODULE_LOAD_SUCCESS;
800 /*! \brief Unload the local proxy channel from Asterisk */
801 static int unload_module(void)
803 struct local_pvt *p = NULL;
805 /* First, take us out of the channel loop */
806 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
807 ast_channel_unregister(&local_tech);
808 if (!AST_LIST_LOCK(&locals)) {
809 /* Hangup all interfaces if they have an owner */
810 AST_LIST_TRAVERSE(&locals, p, list) {
811 if (p->owner)
812 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
814 AST_LIST_UNLOCK(&locals);
815 } else {
816 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
817 return -1;
819 return 0;
822 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Local Proxy Channel (Note: used internally by other modules)");