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.
21 * \author Mark Spencer <markster@digium.com>
23 * \brief Local Proxy Channel
25 * \ingroup channel_drivers
31 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <sys/signal.h>
42 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
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"
64 static const char tdesc
[] = "Local Proxy Channel Driver";
66 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
68 static struct ast_channel
*local_request(const char *type
, int format
, void *data
, int *cause
);
69 static int local_digit(struct ast_channel
*ast
, char digit
);
70 static int local_call(struct ast_channel
*ast
, char *dest
, int timeout
);
71 static int local_hangup(struct ast_channel
*ast
);
72 static int local_answer(struct ast_channel
*ast
);
73 static struct ast_frame
*local_read(struct ast_channel
*ast
);
74 static int local_write(struct ast_channel
*ast
, struct ast_frame
*f
);
75 static int local_indicate(struct ast_channel
*ast
, int condition
);
76 static int local_fixup(struct ast_channel
*oldchan
, struct ast_channel
*newchan
);
77 static int local_sendhtml(struct ast_channel
*ast
, int subclass
, const char *data
, int datalen
);
79 /* PBX interface structure for channel registration */
80 static const struct ast_channel_tech local_tech
= {
84 .requester
= local_request
,
85 .send_digit
= local_digit
,
87 .hangup
= local_hangup
,
88 .answer
= local_answer
,
91 .exception
= local_read
,
92 .indicate
= local_indicate
,
94 .send_html
= local_sendhtml
,
98 ast_mutex_t lock
; /* Channel private lock */
99 char context
[AST_MAX_CONTEXT
]; /* Context to call */
100 char exten
[AST_MAX_EXTENSION
]; /* Extension to call */
101 int reqformat
; /* Requested format */
102 int glaredetect
; /* Detect glare on hangup */
103 int cancelqueue
; /* Cancel queue */
104 int alreadymasqed
; /* Already masqueraded */
105 int launchedpbx
; /* Did we launch the PBX */
106 int nooptimization
; /* Don't leave masq state */
107 struct ast_channel
*owner
; /* Master Channel */
108 struct ast_channel
*chan
; /* Outbound channel */
109 AST_LIST_ENTRY(local_pvt
) list
; /* Next entity */
112 static AST_LIST_HEAD_STATIC(locals
, local_pvt
);
114 static int local_queue_frame(struct local_pvt
*p
, int isoutbound
, struct ast_frame
*f
, struct ast_channel
*us
)
116 struct ast_channel
*other
;
118 /* Recalculate outbound channel */
124 /* Set glare detection */
126 if (p
->cancelqueue
) {
127 /* We had a glare on the hangup. Forget all this business,
128 return and destroy p. */
129 ast_mutex_unlock(&p
->lock
);
130 ast_mutex_destroy(&p
->lock
);
138 if (ast_mutex_trylock(&other
->lock
)) {
139 /* Failed to lock. Release main lock and try again */
140 ast_mutex_unlock(&p
->lock
);
142 if (ast_mutex_unlock(&us
->lock
)) {
143 ast_log(LOG_WARNING
, "%s wasn't locked while sending %d/%d\n",
144 us
->name
, f
->frametype
, f
->subclass
);
148 /* Wait just a bit */
150 /* Only we can destroy ourselves, so we can't disappear here */
152 ast_mutex_lock(&us
->lock
);
153 ast_mutex_lock(&p
->lock
);
156 ast_queue_frame(other
, f
);
157 ast_mutex_unlock(&other
->lock
);
162 static int local_answer(struct ast_channel
*ast
)
164 struct local_pvt
*p
= ast
->tech_pvt
;
168 ast_mutex_lock(&p
->lock
);
169 isoutbound
= IS_OUTBOUND(ast
, p
);
171 /* Pass along answer since somebody answered us */
172 struct ast_frame answer
= { AST_FRAME_CONTROL
, AST_CONTROL_ANSWER
};
173 res
= local_queue_frame(p
, isoutbound
, &answer
, ast
);
175 ast_log(LOG_WARNING
, "Huh? Local is being asked to answer?\n");
176 ast_mutex_unlock(&p
->lock
);
180 static void check_bridge(struct local_pvt
*p
, int isoutbound
)
182 if (p
->alreadymasqed
|| p
->nooptimization
)
184 if (!p
->chan
|| !p
->owner
)
186 if (isoutbound
&& p
->chan
->_bridge
/* Not ast_bridged_channel! Only go one step! */ && !p
->owner
->readq
) {
187 /* Masquerade bridged channel into owner */
188 /* Lock everything we need, one by one, and give up if
189 we can't get everything. Remember, we'll get another
190 chance in just a little bit */
191 if (!ast_mutex_trylock(&(p
->chan
->_bridge
)->lock
)) {
192 if (!p
->chan
->_bridge
->_softhangup
) {
193 if (!ast_mutex_trylock(&p
->owner
->lock
)) {
194 if (!p
->owner
->_softhangup
) {
195 ast_channel_masquerade(p
->owner
, p
->chan
->_bridge
);
196 p
->alreadymasqed
= 1;
198 ast_mutex_unlock(&p
->owner
->lock
);
200 ast_mutex_unlock(&(p
->chan
->_bridge
)->lock
);
203 } else if (!isoutbound
&& p
->owner
&& p
->owner
->_bridge
&& p
->chan
&& !p
->chan
->readq
) {
204 /* Masquerade bridged channel into chan */
205 if (!ast_mutex_trylock(&(p
->owner
->_bridge
)->lock
)) {
206 if (!p
->owner
->_bridge
->_softhangup
) {
207 if (!ast_mutex_trylock(&p
->chan
->lock
)) {
208 if (!p
->chan
->_softhangup
) {
209 ast_channel_masquerade(p
->chan
, p
->owner
->_bridge
);
210 p
->alreadymasqed
= 1;
212 ast_mutex_unlock(&p
->chan
->lock
);
215 ast_mutex_unlock(&(p
->owner
->_bridge
)->lock
);
220 static struct ast_frame
*local_read(struct ast_channel
*ast
)
222 return &ast_null_frame
;
225 static int local_write(struct ast_channel
*ast
, struct ast_frame
*f
)
227 struct local_pvt
*p
= ast
->tech_pvt
;
231 /* Just queue for delivery to the other side */
232 ast_mutex_lock(&p
->lock
);
233 isoutbound
= IS_OUTBOUND(ast
, p
);
234 if (f
&& (f
->frametype
== AST_FRAME_VOICE
))
235 check_bridge(p
, isoutbound
);
236 if (!p
->alreadymasqed
)
237 res
= local_queue_frame(p
, isoutbound
, f
, ast
);
239 ast_log(LOG_DEBUG
, "Not posting to queue since already masked on '%s'\n", ast
->name
);
242 ast_mutex_unlock(&p
->lock
);
246 static int local_fixup(struct ast_channel
*oldchan
, struct ast_channel
*newchan
)
248 struct local_pvt
*p
= newchan
->tech_pvt
;
249 ast_mutex_lock(&p
->lock
);
251 if ((p
->owner
!= oldchan
) && (p
->chan
!= oldchan
)) {
252 ast_log(LOG_WARNING
, "Old channel wasn't %p but was %p/%p\n", oldchan
, p
->owner
, p
->chan
);
253 ast_mutex_unlock(&p
->lock
);
256 if (p
->owner
== oldchan
)
260 ast_mutex_unlock(&p
->lock
);
264 static int local_indicate(struct ast_channel
*ast
, int condition
)
266 struct local_pvt
*p
= ast
->tech_pvt
;
268 struct ast_frame f
= { AST_FRAME_CONTROL
, };
271 /* Queue up a frame representing the indication as a control frame */
272 ast_mutex_lock(&p
->lock
);
273 isoutbound
= IS_OUTBOUND(ast
, p
);
274 f
.subclass
= condition
;
275 res
= local_queue_frame(p
, isoutbound
, &f
, ast
);
276 ast_mutex_unlock(&p
->lock
);
280 static int local_digit(struct ast_channel
*ast
, char digit
)
282 struct local_pvt
*p
= ast
->tech_pvt
;
284 struct ast_frame f
= { AST_FRAME_DTMF
, };
287 ast_mutex_lock(&p
->lock
);
288 isoutbound
= IS_OUTBOUND(ast
, p
);
290 res
= local_queue_frame(p
, isoutbound
, &f
, ast
);
291 ast_mutex_unlock(&p
->lock
);
295 static int local_sendhtml(struct ast_channel
*ast
, int subclass
, const char *data
, int datalen
)
297 struct local_pvt
*p
= ast
->tech_pvt
;
299 struct ast_frame f
= { AST_FRAME_HTML
, };
302 ast_mutex_lock(&p
->lock
);
303 isoutbound
= IS_OUTBOUND(ast
, p
);
304 f
.subclass
= subclass
;
305 f
.data
= (char *)data
;
307 res
= local_queue_frame(p
, isoutbound
, &f
, ast
);
308 ast_mutex_unlock(&p
->lock
);
312 /*! \brief Initiate new call, part of PBX interface
313 * dest is the dial string */
314 static int local_call(struct ast_channel
*ast
, char *dest
, int timeout
)
316 struct local_pvt
*p
= ast
->tech_pvt
;
318 struct ast_var_t
*varptr
= NULL
, *new;
321 ast_mutex_lock(&p
->lock
);
323 p
->chan
->cid
.cid_num
= ast_strdup(p
->owner
->cid
.cid_num
);
324 p
->chan
->cid
.cid_name
= ast_strdup(p
->owner
->cid
.cid_name
);
325 p
->chan
->cid
.cid_rdnis
= ast_strdup(p
->owner
->cid
.cid_rdnis
);
326 p
->chan
->cid
.cid_ani
= ast_strdup(p
->owner
->cid
.cid_ani
);
328 ast_string_field_set(p
->chan
, language
, p
->owner
->language
);
329 ast_string_field_set(p
->chan
, accountcode
, p
->owner
->accountcode
);
330 p
->chan
->cdrflags
= p
->owner
->cdrflags
;
332 /* copy the channel variables from the incoming channel to the outgoing channel */
333 /* Note that due to certain assumptions, they MUST be in the same order */
334 AST_LIST_TRAVERSE(&p
->owner
->varshead
, varptr
, entries
) {
335 namelen
= strlen(varptr
->name
);
336 len
= sizeof(struct ast_var_t
) + namelen
+ strlen(varptr
->value
) + 2;
337 if ((new = ast_calloc(1, len
))) {
338 memcpy(new, varptr
, len
);
339 new->value
= &(new->name
[0]) + namelen
+ 1;
340 AST_LIST_INSERT_TAIL(&p
->chan
->varshead
, new, entries
);
346 /* Start switch on sub channel */
347 res
= ast_pbx_start(p
->chan
);
348 ast_mutex_unlock(&p
->lock
);
353 static void local_destroy(struct local_pvt
*p
)
355 struct local_pvt
*cur
;
357 AST_LIST_LOCK(&locals
);
358 AST_LIST_TRAVERSE_SAFE_BEGIN(&locals
, cur
, list
) {
360 AST_LIST_REMOVE_CURRENT(&locals
, list
);
361 ast_mutex_destroy(&cur
->lock
);
366 AST_LIST_TRAVERSE_SAFE_END
367 AST_LIST_UNLOCK(&locals
);
369 ast_log(LOG_WARNING
, "Unable ot find local '%s@%s' in local list\n", p
->exten
, p
->context
);
373 /*! \brief Hangup a call through the local proxy channel */
374 static int local_hangup(struct ast_channel
*ast
)
376 struct local_pvt
*p
= ast
->tech_pvt
;
378 struct ast_frame f
= { AST_FRAME_CONTROL
, AST_CONTROL_HANGUP
};
379 struct ast_channel
*ochan
= NULL
;
382 ast_mutex_lock(&p
->lock
);
383 isoutbound
= IS_OUTBOUND(ast
, p
);
385 const char *status
= pbx_builtin_getvar_helper(p
->chan
, "DIALSTATUS");
386 if ((status
) && (p
->owner
))
387 pbx_builtin_setvar_helper(p
->owner
, "CHANLOCALSTATUS", status
);
392 ast
->tech_pvt
= NULL
;
394 ast_atomic_fetchadd_int(&__mod_desc
->usecnt
, -1);
396 if (!p
->owner
&& !p
->chan
) {
397 /* Okay, done with the private part now, too. */
398 glaredetect
= p
->glaredetect
;
399 /* If we have a queue holding, don't actually destroy p yet, but
400 let local_queue do it. */
403 ast_mutex_unlock(&p
->lock
);
404 /* Remove from list */
405 AST_LIST_LOCK(&locals
);
406 AST_LIST_REMOVE(&locals
, p
, list
);
407 AST_LIST_UNLOCK(&locals
);
408 /* Grab / release lock just in case */
409 ast_mutex_lock(&p
->lock
);
410 ast_mutex_unlock(&p
->lock
);
413 ast_mutex_destroy(&p
->lock
);
418 if (p
->chan
&& !p
->launchedpbx
)
419 /* Need to actually hangup since there is no PBX */
422 local_queue_frame(p
, isoutbound
, &f
, NULL
);
423 ast_mutex_unlock(&p
->lock
);
429 /*! \brief Create a call structure */
430 static struct local_pvt
*local_alloc(const char *data
, int format
)
432 struct local_pvt
*tmp
;
436 if (!(tmp
= ast_calloc(1, sizeof(*tmp
))))
439 ast_mutex_init(&tmp
->lock
);
440 ast_copy_string(tmp
->exten
, data
, sizeof(tmp
->exten
));
441 opts
= strchr(tmp
->exten
, '/');
444 if (strchr(opts
, 'n'))
445 tmp
->nooptimization
= 1;
447 c
= strchr(tmp
->exten
, '@');
450 ast_copy_string(tmp
->context
, c
? c
: "default", sizeof(tmp
->context
));
451 tmp
->reqformat
= format
;
452 if (!ast_exists_extension(NULL
, tmp
->context
, tmp
->exten
, 1, NULL
)) {
453 ast_log(LOG_NOTICE
, "No such extension/context %s@%s creating local channel\n", tmp
->exten
, tmp
->context
);
454 ast_mutex_destroy(&tmp
->lock
);
459 AST_LIST_LOCK(&locals
);
460 AST_LIST_INSERT_HEAD(&locals
, tmp
, list
);
461 AST_LIST_UNLOCK(&locals
);
467 /*! \brief Start new local channel */
468 static struct ast_channel
*local_new(struct local_pvt
*p
, int state
)
470 struct ast_channel
*tmp
, *tmp2
;
471 int randnum
= ast_random() & 0xffff;
473 tmp
= ast_channel_alloc(1);
474 tmp2
= ast_channel_alloc(1);
477 ast_channel_free(tmp
);
479 ast_channel_free(tmp2
);
480 ast_log(LOG_WARNING
, "Unable to allocate channel structure(s)\n");
484 tmp2
->tech
= tmp
->tech
= &local_tech
;
485 tmp
->nativeformats
= p
->reqformat
;
486 tmp2
->nativeformats
= p
->reqformat
;
487 ast_string_field_build(tmp
, name
, "Local/%s@%s-%04x,1", p
->exten
, p
->context
, randnum
);
488 ast_string_field_build(tmp2
, name
, "Local/%s@%s-%04x,2", p
->exten
, p
->context
, randnum
);
489 ast_setstate(tmp
, state
);
490 ast_setstate(tmp2
, AST_STATE_RING
);
491 tmp
->writeformat
= p
->reqformat
;
492 tmp2
->writeformat
= p
->reqformat
;
493 tmp
->rawwriteformat
= p
->reqformat
;
494 tmp2
->rawwriteformat
= p
->reqformat
;
495 tmp
->readformat
= p
->reqformat
;
496 tmp2
->readformat
= p
->reqformat
;
497 tmp
->rawreadformat
= p
->reqformat
;
498 tmp2
->rawreadformat
= p
->reqformat
;
503 ast_atomic_fetchadd_int(&__mod_desc
->usecnt
, +2); /* we allocate 2 new channels */
504 ast_update_use_count();
505 ast_copy_string(tmp
->context
, p
->context
, sizeof(tmp
->context
));
506 ast_copy_string(tmp2
->context
, p
->context
, sizeof(tmp2
->context
));
507 ast_copy_string(tmp2
->exten
, p
->exten
, sizeof(tmp
->exten
));
515 /*! \brief Part of PBX interface */
516 static struct ast_channel
*local_request(const char *type
, int format
, void *data
, int *cause
)
519 struct ast_channel
*chan
= NULL
;
521 p
= local_alloc(data
, format
);
523 chan
= local_new(p
, AST_STATE_DOWN
);
527 /*! \brief CLI command "local show channels" */
528 static int locals_show(int fd
, int argc
, char **argv
)
533 return RESULT_SHOWUSAGE
;
534 if (AST_LIST_EMPTY(&locals
))
535 ast_cli(fd
, "No local channels in use\n");
536 AST_LIST_LOCK(&locals
);
537 AST_LIST_TRAVERSE(&locals
, p
, list
) {
538 ast_mutex_lock(&p
->lock
);
539 ast_cli(fd
, "%s -- %s@%s\n", p
->owner
? p
->owner
->name
: "<unowned>", p
->exten
, p
->context
);
540 ast_mutex_unlock(&p
->lock
);
542 AST_LIST_UNLOCK(&locals
);
543 return RESULT_SUCCESS
;
546 static char show_locals_usage
[] =
547 "Usage: local show channels\n"
548 " Provides summary information on active local proxy channels.\n";
550 static struct ast_cli_entry cli_show_locals
= {
551 { "local", "show", "channels", NULL
}, locals_show
,
552 "Show status of local channels", show_locals_usage
, NULL
};
554 /*! \brief Load module into PBX, register channel */
555 static int load_module(void *mod
)
559 /* Make sure we can register our channel type */
560 if (ast_channel_register(&local_tech
)) {
561 ast_log(LOG_ERROR
, "Unable to register channel class 'Local'\n");
564 ast_cli_register(&cli_show_locals
);
568 /*! \brief Unload the local proxy channel from Asterisk */
569 static int unload_module(void *mod
)
573 /* First, take us out of the channel loop */
574 ast_cli_unregister(&cli_show_locals
);
575 ast_channel_unregister(&local_tech
);
576 if (!AST_LIST_LOCK(&locals
)) {
577 /* Hangup all interfaces if they have an owner */
578 AST_LIST_TRAVERSE(&locals
, p
, list
) {
580 ast_softhangup(p
->owner
, AST_SOFTHANGUP_APPUNLOAD
);
582 AST_LIST_UNLOCK(&locals
);
583 AST_LIST_HEAD_DESTROY(&locals
);
585 ast_log(LOG_WARNING
, "Unable to lock the monitor\n");
591 static const char *key(void)
593 return ASTERISK_GPL_KEY
;
596 static const char *description(void)
598 return "Local Proxy Channel";
601 STD_MOD(MOD_1
, NULL
, NULL
, NULL
);