Disable automatic build of chan_h323
[asterisk-bristuff.git] / channels / chan_local.c
blobfa396bce4b4b8288d183e2e31d48a0c6a8d829eb
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 /* do not queue frame if generator is on both local channels */
172 if (us && us->generator && other->generator)
173 return 0;
175 /* Set glare detection */
176 ast_set_flag(p, LOCAL_GLARE_DETECT);
177 if (ast_test_flag(p, LOCAL_CANCEL_QUEUE)) {
178 /* We had a glare on the hangup. Forget all this business,
179 return and destroy p. */
180 ast_mutex_unlock(&p->lock);
181 p = local_pvt_destroy(p);
182 return -1;
184 if (!other) {
185 ast_clear_flag(p, LOCAL_GLARE_DETECT);
186 return 0;
189 /* Ensure that we have both channels locked */
190 while (other && ast_channel_trylock(other)) {
191 ast_mutex_unlock(&p->lock);
192 if (us && us_locked) {
193 do {
194 ast_channel_unlock(us);
195 usleep(1);
196 ast_channel_lock(us);
197 } while (ast_mutex_trylock(&p->lock));
198 } else {
199 usleep(1);
200 ast_mutex_lock(&p->lock);
202 other = isoutbound ? p->owner : p->chan;
205 if (other) {
206 ast_queue_frame(other, f);
207 ast_channel_unlock(other);
210 ast_clear_flag(p, LOCAL_GLARE_DETECT);
212 return 0;
215 static int local_answer(struct ast_channel *ast)
217 struct local_pvt *p = ast->tech_pvt;
218 int isoutbound;
219 int res = -1;
221 if (!p)
222 return -1;
224 ast_mutex_lock(&p->lock);
225 isoutbound = IS_OUTBOUND(ast, p);
226 if (isoutbound) {
227 /* Pass along answer since somebody answered us */
228 struct ast_frame answer = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
229 res = local_queue_frame(p, isoutbound, &answer, ast, 1);
230 } else
231 ast_log(LOG_WARNING, "Huh? Local is being asked to answer?\n");
232 if (!res)
233 ast_mutex_unlock(&p->lock);
234 return res;
237 static void check_bridge(struct local_pvt *p, int isoutbound)
239 struct ast_channel_monitor *tmp;
240 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)))
241 return;
243 /* only do the masquerade if we are being called on the outbound channel,
244 if it has been bridged to another channel and if there are no pending
245 frames on the owner channel (because they would be transferred to the
246 outbound channel during the masquerade)
248 if (isoutbound && p->chan->_bridge /* Not ast_bridged_channel! Only go one step! */ && AST_LIST_EMPTY(&p->owner->readq)) {
249 /* Masquerade bridged channel into owner */
250 /* Lock everything we need, one by one, and give up if
251 we can't get everything. Remember, we'll get another
252 chance in just a little bit */
253 if (!ast_mutex_trylock(&(p->chan->_bridge)->lock)) {
254 if (!p->chan->_bridge->_softhangup) {
255 if (!ast_mutex_trylock(&p->owner->lock)) {
256 if (!p->owner->_softhangup) {
257 if(p->owner->monitor && !p->chan->_bridge->monitor) {
258 /* If a local channel is being monitored, we don't want a masquerade
259 * to cause the monitor to go away. Since the masquerade swaps the monitors,
260 * pre-swapping the monitors before the masquerade will ensure that the monitor
261 * ends up where it is expected.
263 tmp = p->owner->monitor;
264 p->owner->monitor = p->chan->_bridge->monitor;
265 p->chan->_bridge->monitor = tmp;
267 ast_channel_masquerade(p->owner, p->chan->_bridge);
268 ast_set_flag(p, LOCAL_ALREADY_MASQED);
270 ast_mutex_unlock(&p->owner->lock);
272 ast_mutex_unlock(&(p->chan->_bridge)->lock);
275 /* We only allow masquerading in one 'direction'... it's important to preserve the state
276 (group variables, etc.) that live on p->chan->_bridge (and were put there by the dialplan)
277 when the local channels go away.
279 #if 0
280 } else if (!isoutbound && p->owner && p->owner->_bridge && p->chan && AST_LIST_EMPTY(&p->chan->readq)) {
281 /* Masquerade bridged channel into chan */
282 if (!ast_mutex_trylock(&(p->owner->_bridge)->lock)) {
283 if (!p->owner->_bridge->_softhangup) {
284 if (!ast_mutex_trylock(&p->chan->lock)) {
285 if (!p->chan->_softhangup) {
286 ast_channel_masquerade(p->chan, p->owner->_bridge);
287 ast_set_flag(p, LOCAL_ALREADY_MASQED);
289 ast_mutex_unlock(&p->chan->lock);
292 ast_mutex_unlock(&(p->owner->_bridge)->lock);
294 #endif
298 static struct ast_frame *local_read(struct ast_channel *ast)
300 return &ast_null_frame;
303 static int local_write(struct ast_channel *ast, struct ast_frame *f)
305 struct local_pvt *p = ast->tech_pvt;
306 int res = -1;
307 int isoutbound;
309 if (!p)
310 return -1;
312 /* Just queue for delivery to the other side */
313 ast_mutex_lock(&p->lock);
314 isoutbound = IS_OUTBOUND(ast, p);
315 if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO))
316 check_bridge(p, isoutbound);
317 if (!ast_test_flag(p, LOCAL_ALREADY_MASQED))
318 res = local_queue_frame(p, isoutbound, f, ast, 1);
319 else {
320 if (option_debug)
321 ast_log(LOG_DEBUG, "Not posting to queue since already masked on '%s'\n", ast->name);
322 res = 0;
324 if (!res)
325 ast_mutex_unlock(&p->lock);
326 return res;
329 static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
331 struct local_pvt *p = newchan->tech_pvt;
333 if (!p)
334 return -1;
336 ast_mutex_lock(&p->lock);
338 if ((p->owner != oldchan) && (p->chan != oldchan)) {
339 ast_log(LOG_WARNING, "Old channel wasn't %p but was %p/%p\n", oldchan, p->owner, p->chan);
340 ast_mutex_unlock(&p->lock);
341 return -1;
343 if (p->owner == oldchan)
344 p->owner = newchan;
345 else
346 p->chan = newchan;
347 ast_mutex_unlock(&p->lock);
348 return 0;
351 static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
353 struct local_pvt *p = ast->tech_pvt;
354 int res = 0;
355 struct ast_frame f = { AST_FRAME_CONTROL, };
356 int isoutbound;
358 if (!p)
359 return -1;
361 /* If this is an MOH hold or unhold, do it on the Local channel versus real channel */
362 if (condition == AST_CONTROL_HOLD) {
363 ast_moh_start(ast, data, NULL);
364 } else if (condition == AST_CONTROL_UNHOLD) {
365 ast_moh_stop(ast);
366 } else {
367 /* Queue up a frame representing the indication as a control frame */
368 ast_mutex_lock(&p->lock);
369 isoutbound = IS_OUTBOUND(ast, p);
370 f.subclass = condition;
371 f.data = (void*)data;
372 f.datalen = datalen;
373 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 1)))
374 ast_mutex_unlock(&p->lock);
377 return res;
380 static int local_digit_begin(struct ast_channel *ast, char digit)
382 struct local_pvt *p = ast->tech_pvt;
383 int res = -1;
384 struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
385 int isoutbound;
387 if (!p)
388 return -1;
390 ast_mutex_lock(&p->lock);
391 isoutbound = IS_OUTBOUND(ast, p);
392 f.subclass = digit;
393 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
394 ast_mutex_unlock(&p->lock);
396 return res;
399 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
401 struct local_pvt *p = ast->tech_pvt;
402 int res = -1;
403 struct ast_frame f = { AST_FRAME_DTMF_END, };
404 int isoutbound;
406 if (!p)
407 return -1;
409 ast_mutex_lock(&p->lock);
410 isoutbound = IS_OUTBOUND(ast, p);
411 f.subclass = digit;
412 f.len = duration;
413 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
414 ast_mutex_unlock(&p->lock);
416 return res;
419 static int local_sendtext(struct ast_channel *ast, const char *text)
421 struct local_pvt *p = ast->tech_pvt;
422 int res = -1;
423 struct ast_frame f = { AST_FRAME_TEXT, };
424 int isoutbound;
426 if (!p)
427 return -1;
429 ast_mutex_lock(&p->lock);
430 isoutbound = IS_OUTBOUND(ast, p);
431 f.data = (char *) text;
432 f.datalen = strlen(text) + 1;
433 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
434 ast_mutex_unlock(&p->lock);
435 return res;
438 static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
440 struct local_pvt *p = ast->tech_pvt;
441 int res = -1;
442 struct ast_frame f = { AST_FRAME_HTML, };
443 int isoutbound;
445 if (!p)
446 return -1;
448 ast_mutex_lock(&p->lock);
449 isoutbound = IS_OUTBOUND(ast, p);
450 f.subclass = subclass;
451 f.data = (char *)data;
452 f.datalen = datalen;
453 if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0)))
454 ast_mutex_unlock(&p->lock);
455 return res;
458 /*! \brief Initiate new call, part of PBX interface
459 * dest is the dial string */
460 static int local_call(struct ast_channel *ast, char *dest, int timeout)
462 struct local_pvt *p = ast->tech_pvt;
463 int res;
464 struct ast_var_t *varptr = NULL, *new;
465 size_t len, namelen;
467 if (!p)
468 return -1;
470 ast_mutex_lock(&p->lock);
473 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
474 * call, so it's done here instead.
476 p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num);
477 p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name);
478 p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis);
479 p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani);
480 p->chan->cid.cid_pres = p->owner->cid.cid_pres;
481 ast_string_field_set(p->chan, language, p->owner->language);
482 ast_string_field_set(p->chan, accountcode, p->owner->accountcode);
483 ast_cdr_update(p->chan);
484 p->chan->cdrflags = p->owner->cdrflags;
486 if (!ast_exists_extension(NULL, p->chan->context, p->chan->exten, 1, p->owner->cid.cid_num)) {
487 ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->chan->exten, p->chan->context);
488 return -1;
491 /* copy the channel variables from the incoming channel to the outgoing channel */
492 /* Note that due to certain assumptions, they MUST be in the same order */
493 AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) {
494 namelen = strlen(varptr->name);
495 len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2;
496 if ((new = ast_calloc(1, len))) {
497 memcpy(new, varptr, len);
498 new->value = &(new->name[0]) + namelen + 1;
499 AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries);
502 ast_channel_datastore_inherit(p->owner, p->chan);
504 /* Start switch on sub channel */
505 if (!(res = ast_pbx_start(p->chan)))
506 ast_set_flag(p, LOCAL_LAUNCHED_PBX);
508 ast_mutex_unlock(&p->lock);
509 return res;
512 /*! \brief Hangup a call through the local proxy channel */
513 static int local_hangup(struct ast_channel *ast)
515 struct local_pvt *p = ast->tech_pvt;
516 int isoutbound;
517 struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP };
518 struct ast_channel *ochan = NULL;
519 int glaredetect = 0, res = 0;
521 if (!p)
522 return -1;
524 while (ast_mutex_trylock(&p->lock)) {
525 ast_channel_unlock(ast);
526 usleep(1);
527 ast_channel_lock(ast);
530 isoutbound = IS_OUTBOUND(ast, p);
531 if (isoutbound) {
532 const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS");
533 if ((status) && (p->owner)) {
534 /* Deadlock avoidance */
535 while (p->owner && ast_channel_trylock(p->owner)) {
536 ast_mutex_unlock(&p->lock);
537 if (ast) {
538 ast_channel_unlock(ast);
540 usleep(1);
541 if (ast) {
542 ast_channel_lock(ast);
544 ast_mutex_lock(&p->lock);
546 if (p->owner) {
547 pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status);
548 ast_channel_unlock(p->owner);
551 p->chan = NULL;
552 ast_clear_flag(p, LOCAL_LAUNCHED_PBX);
553 ast_module_user_remove(p->u_chan);
554 } else {
555 p->owner = NULL;
556 ast_module_user_remove(p->u_owner);
557 if (p->chan) {
558 ast_queue_hangup(p->chan);
562 ast->tech_pvt = NULL;
564 if (!p->owner && !p->chan) {
565 /* Okay, done with the private part now, too. */
566 glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT);
567 /* If we have a queue holding, don't actually destroy p yet, but
568 let local_queue do it. */
569 if (glaredetect)
570 ast_set_flag(p, LOCAL_CANCEL_QUEUE);
571 ast_mutex_unlock(&p->lock);
572 /* Remove from list */
573 AST_LIST_LOCK(&locals);
574 AST_LIST_REMOVE(&locals, p, list);
575 AST_LIST_UNLOCK(&locals);
576 /* Grab / release lock just in case */
577 ast_mutex_lock(&p->lock);
578 ast_mutex_unlock(&p->lock);
579 /* And destroy */
580 if (!glaredetect) {
581 p = local_pvt_destroy(p);
583 return 0;
585 if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX))
586 /* Need to actually hangup since there is no PBX */
587 ochan = p->chan;
588 else
589 res = local_queue_frame(p, isoutbound, &f, NULL, 1);
590 if (!res)
591 ast_mutex_unlock(&p->lock);
592 if (ochan)
593 ast_hangup(ochan);
594 return 0;
597 /*! \brief Create a call structure */
598 static struct local_pvt *local_alloc(const char *data, int format)
600 struct local_pvt *tmp = NULL;
601 char *c = NULL, *opts = NULL;
603 if (!(tmp = ast_calloc(1, sizeof(*tmp))))
604 return NULL;
606 /* Initialize private structure information */
607 ast_mutex_init(&tmp->lock);
608 ast_copy_string(tmp->exten, data, sizeof(tmp->exten));
610 /* Look for options */
611 if ((opts = strchr(tmp->exten, '/'))) {
612 *opts++ = '\0';
613 if (strchr(opts, 'n'))
614 ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION);
617 /* Look for a context */
618 if ((c = strchr(tmp->exten, '@')))
619 *c++ = '\0';
621 ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context));
623 tmp->reqformat = format;
625 #if 0
626 /* We can't do this check here, because we don't know the CallerID yet, and
627 * the CallerID could potentially affect what step is actually taken (or
628 * even if that step exists). */
629 if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) {
630 ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context);
631 tmp = local_pvt_destroy(tmp);
632 } else {
633 #endif
634 /* Add to list */
635 AST_LIST_LOCK(&locals);
636 AST_LIST_INSERT_HEAD(&locals, tmp, list);
637 AST_LIST_UNLOCK(&locals);
638 #if 0
640 #endif
642 return tmp;
645 /*! \brief Start new local channel */
646 static struct ast_channel *local_new(struct local_pvt *p, int state)
648 struct ast_channel *tmp = NULL, *tmp2 = NULL;
649 int randnum = ast_random() & 0xffff, fmt = 0;
650 const char *t;
651 int ama;
653 /* Allocate two new Asterisk channels */
654 /* safe accountcode */
655 if (p->owner && p->owner->accountcode)
656 t = p->owner->accountcode;
657 else
658 t = "";
660 if (p->owner)
661 ama = p->owner->amaflags;
662 else
663 ama = 0;
664 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))
665 || !(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))) {
666 if (tmp)
667 ast_channel_free(tmp);
668 if (tmp2)
669 ast_channel_free(tmp2);
670 ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
671 return NULL;
674 tmp2->tech = tmp->tech = &local_tech;
676 tmp->nativeformats = p->reqformat;
677 tmp2->nativeformats = p->reqformat;
679 /* Determine our read/write format and set it on each channel */
680 fmt = ast_best_codec(p->reqformat);
681 tmp->writeformat = fmt;
682 tmp2->writeformat = fmt;
683 tmp->rawwriteformat = fmt;
684 tmp2->rawwriteformat = fmt;
685 tmp->readformat = fmt;
686 tmp2->readformat = fmt;
687 tmp->rawreadformat = fmt;
688 tmp2->rawreadformat = fmt;
690 tmp->tech_pvt = p;
691 tmp2->tech_pvt = p;
693 p->owner = tmp;
694 p->chan = tmp2;
695 p->u_owner = ast_module_user_add(p->owner);
696 p->u_chan = ast_module_user_add(p->chan);
698 ast_copy_string(tmp->context, p->context, sizeof(tmp->context));
699 ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context));
700 ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten));
701 tmp->priority = 1;
702 tmp2->priority = 1;
704 return tmp;
707 /*! \brief Part of PBX interface */
708 static struct ast_channel *local_request(const char *type, int format, void *data, int *cause)
710 struct local_pvt *p = NULL;
711 struct ast_channel *chan = NULL;
713 /* Allocate a new private structure and then Asterisk channel */
714 if ((p = local_alloc(data, format))) {
715 if (!(chan = local_new(p, AST_STATE_DOWN))) {
716 AST_LIST_LOCK(&locals);
717 AST_LIST_REMOVE(&locals, p, list);
718 AST_LIST_UNLOCK(&locals);
719 p = local_pvt_destroy(p);
723 return chan;
726 /*! \brief CLI command "local show channels" */
727 static int locals_show(int fd, int argc, char **argv)
729 struct local_pvt *p = NULL;
731 if (argc != 3)
732 return RESULT_SHOWUSAGE;
734 AST_LIST_LOCK(&locals);
735 if (!AST_LIST_EMPTY(&locals)) {
736 AST_LIST_TRAVERSE(&locals, p, list) {
737 ast_mutex_lock(&p->lock);
738 ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context);
739 ast_mutex_unlock(&p->lock);
741 } else
742 ast_cli(fd, "No local channels in use\n");
743 AST_LIST_UNLOCK(&locals);
745 return RESULT_SUCCESS;
748 static char show_locals_usage[] =
749 "Usage: local show channels\n"
750 " Provides summary information on active local proxy channels.\n";
752 static struct ast_cli_entry cli_local[] = {
753 { { "local", "show", "channels", NULL },
754 locals_show, "List status of local channels",
755 show_locals_usage },
758 /*! \brief Load module into PBX, register channel */
759 static int load_module(void)
761 /* Make sure we can register our channel type */
762 if (ast_channel_register(&local_tech)) {
763 ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n");
764 return -1;
766 ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
767 return 0;
770 /*! \brief Unload the local proxy channel from Asterisk */
771 static int unload_module(void)
773 struct local_pvt *p = NULL;
775 /* First, take us out of the channel loop */
776 ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry));
777 ast_channel_unregister(&local_tech);
778 if (!AST_LIST_LOCK(&locals)) {
779 /* Hangup all interfaces if they have an owner */
780 AST_LIST_TRAVERSE(&locals, p, list) {
781 if (p->owner)
782 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
784 AST_LIST_UNLOCK(&locals);
785 } else {
786 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
787 return -1;
789 return 0;
792 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Local Proxy Channel (Note: used internally by other modules)");