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 * \brief feature Proxy Channel
23 * \author Mark Spencer <markster@digium.com>
25 * \note *** Experimental code ****
27 * \ingroup channel_drivers
30 <defaultenabled>no</defaultenabled>
35 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
38 #include <sys/signal.h>
40 #include "asterisk/lock.h"
41 #include "asterisk/channel.h"
42 #include "asterisk/config.h"
43 #include "asterisk/module.h"
44 #include "asterisk/pbx.h"
45 #include "asterisk/sched.h"
46 #include "asterisk/io.h"
47 #include "asterisk/rtp.h"
48 #include "asterisk/acl.h"
49 #include "asterisk/callerid.h"
50 #include "asterisk/file.h"
51 #include "asterisk/cli.h"
52 #include "asterisk/app.h"
53 #include "asterisk/musiconhold.h"
54 #include "asterisk/manager.h"
55 #include "asterisk/stringfields.h"
57 static const char tdesc
[] = "Feature Proxy Channel Driver";
59 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0)
62 struct ast_channel
*owner
;
66 int alertpipebackup
[2];
70 ast_mutex_t lock
; /* Channel private lock */
71 char tech
[AST_MAX_EXTENSION
]; /* Technology to abstract */
72 char dest
[AST_MAX_EXTENSION
]; /* Destination to abstract */
73 struct ast_channel
*subchan
;
74 struct feature_sub subs
[3]; /* Subs */
75 struct ast_channel
*owner
; /* Current Master Channel */
76 AST_LIST_ENTRY(feature_pvt
) list
; /* Next entity */
79 static AST_LIST_HEAD_STATIC(features
, feature_pvt
);
81 #define SUB_REAL 0 /* Active call */
82 #define SUB_CALLWAIT 1 /* Call-Waiting call on hold */
83 #define SUB_THREEWAY 2 /* Three-way call */
85 static struct ast_channel
*features_request(const char *type
, int format
, void *data
, int *cause
);
86 static int features_digit_begin(struct ast_channel
*ast
, char digit
);
87 static int features_digit_end(struct ast_channel
*ast
, char digit
, unsigned int duration
);
88 static int features_call(struct ast_channel
*ast
, char *dest
, int timeout
);
89 static int features_hangup(struct ast_channel
*ast
);
90 static int features_answer(struct ast_channel
*ast
);
91 static struct ast_frame
*features_read(struct ast_channel
*ast
);
92 static int features_write(struct ast_channel
*ast
, struct ast_frame
*f
);
93 static int features_indicate(struct ast_channel
*ast
, int condition
, const void *data
, size_t datalen
);
94 static int features_fixup(struct ast_channel
*oldchan
, struct ast_channel
*newchan
);
96 static const struct ast_channel_tech features_tech
= {
100 .requester
= features_request
,
101 .send_digit_begin
= features_digit_begin
,
102 .send_digit_end
= features_digit_end
,
103 .call
= features_call
,
104 .hangup
= features_hangup
,
105 .answer
= features_answer
,
106 .read
= features_read
,
107 .write
= features_write
,
108 .exception
= features_read
,
109 .indicate
= features_indicate
,
110 .fixup
= features_fixup
,
113 static inline void init_sub(struct feature_sub
*sub
)
117 sub
->timingfdbackup
= -1;
118 sub
->alertpipebackup
[0] = sub
->alertpipebackup
[1] = -1;
121 static inline int indexof(struct feature_pvt
*p
, struct ast_channel
*owner
, int nullok
)
125 ast_log(LOG_WARNING
, "indexof called on NULL owner??\n");
128 for (x
=0; x
<3; x
++) {
129 if (owner
== p
->subs
[x
].owner
)
136 static void wakeup_sub(struct feature_pvt
*p
, int a
)
138 struct ast_frame null
= { AST_FRAME_NULL
, };
140 if (p
->subs
[a
].owner
) {
141 if (ast_mutex_trylock(&p
->subs
[a
].owner
->lock
)) {
142 ast_mutex_unlock(&p
->lock
);
144 ast_mutex_lock(&p
->lock
);
146 ast_queue_frame(p
->subs
[a
].owner
, &null
);
147 ast_mutex_unlock(&p
->subs
[a
].owner
->lock
);
156 static void restore_channel(struct feature_pvt
*p
, int index
)
158 /* Restore timing/alertpipe */
159 p
->subs
[index
].owner
->timingfd
= p
->subs
[index
].timingfdbackup
;
160 p
->subs
[index
].owner
->alertpipe
[0] = p
->subs
[index
].alertpipebackup
[0];
161 p
->subs
[index
].owner
->alertpipe
[1] = p
->subs
[index
].alertpipebackup
[1];
162 ast_channel_set_fd(p
->subs
[index
].owner
, AST_ALERT_FD
, p
->subs
[index
].alertpipebackup
[0]);
163 ast_channel_set_fd(p
->subs
[index
].owner
, AST_TIMING_FD
, p
->subs
[index
].timingfdbackup
);
166 static void update_features(struct feature_pvt
*p
, int index
)
169 if (p
->subs
[index
].owner
) {
170 for (x
=0; x
<AST_MAX_FDS
; x
++) {
172 ast_channel_set_fd(p
->subs
[index
].owner
, x
, -1);
174 ast_channel_set_fd(p
->subs
[index
].owner
, x
, p
->subchan
->fds
[x
]);
177 /* Copy timings from master channel */
178 p
->subs
[index
].owner
->timingfd
= p
->subchan
->timingfd
;
179 p
->subs
[index
].owner
->alertpipe
[0] = p
->subchan
->alertpipe
[0];
180 p
->subs
[index
].owner
->alertpipe
[1] = p
->subchan
->alertpipe
[1];
181 if (p
->subs
[index
].owner
->nativeformats
!= p
->subchan
->readformat
) {
182 p
->subs
[index
].owner
->nativeformats
= p
->subchan
->readformat
;
183 if (p
->subs
[index
].owner
->readformat
)
184 ast_set_read_format(p
->subs
[index
].owner
, p
->subs
[index
].owner
->readformat
);
185 if (p
->subs
[index
].owner
->writeformat
)
186 ast_set_write_format(p
->subs
[index
].owner
, p
->subs
[index
].owner
->writeformat
);
189 restore_channel(p
, index
);
195 static void swap_subs(struct feature_pvt
*p
, int a
, int b
)
198 struct ast_channel
*towner
;
200 ast_debug(1, "Swapping %d and %d\n", a
, b
);
202 towner
= p
->subs
[a
].owner
;
203 tinthreeway
= p
->subs
[a
].inthreeway
;
205 p
->subs
[a
].owner
= p
->subs
[b
].owner
;
206 p
->subs
[a
].inthreeway
= p
->subs
[b
].inthreeway
;
208 p
->subs
[b
].owner
= towner
;
209 p
->subs
[b
].inthreeway
= tinthreeway
;
210 update_features(p
,a
);
211 update_features(p
,b
);
217 static int features_answer(struct ast_channel
*ast
)
219 struct feature_pvt
*p
= ast
->tech_pvt
;
223 ast_mutex_lock(&p
->lock
);
224 x
= indexof(p
, ast
, 0);
225 if (!x
&& p
->subchan
)
226 res
= ast_answer(p
->subchan
);
227 ast_mutex_unlock(&p
->lock
);
231 static struct ast_frame
*features_read(struct ast_channel
*ast
)
233 struct feature_pvt
*p
= ast
->tech_pvt
;
238 ast_mutex_lock(&p
->lock
);
239 x
= indexof(p
, ast
, 0);
240 if (!x
&& p
->subchan
) {
241 update_features(p
, x
);
242 f
= ast_read(p
->subchan
);
244 ast_mutex_unlock(&p
->lock
);
248 static int features_write(struct ast_channel
*ast
, struct ast_frame
*f
)
250 struct feature_pvt
*p
= ast
->tech_pvt
;
254 ast_mutex_lock(&p
->lock
);
255 x
= indexof(p
, ast
, 0);
256 if (!x
&& p
->subchan
)
257 res
= ast_write(p
->subchan
, f
);
258 ast_mutex_unlock(&p
->lock
);
262 static int features_fixup(struct ast_channel
*oldchan
, struct ast_channel
*newchan
)
264 struct feature_pvt
*p
= newchan
->tech_pvt
;
267 ast_mutex_lock(&p
->lock
);
268 if (p
->owner
== oldchan
)
270 for (x
= 0; x
< 3; x
++) {
271 if (p
->subs
[x
].owner
== oldchan
)
272 p
->subs
[x
].owner
= newchan
;
274 ast_mutex_unlock(&p
->lock
);
278 static int features_indicate(struct ast_channel
*ast
, int condition
, const void *data
, size_t datalen
)
280 struct feature_pvt
*p
= ast
->tech_pvt
;
284 /* Queue up a frame representing the indication as a control frame */
285 ast_mutex_lock(&p
->lock
);
286 x
= indexof(p
, ast
, 0);
287 if (!x
&& p
->subchan
)
288 res
= ast_indicate(p
->subchan
, condition
);
289 ast_mutex_unlock(&p
->lock
);
293 static int features_digit_begin(struct ast_channel
*ast
, char digit
)
295 struct feature_pvt
*p
= ast
->tech_pvt
;
299 /* Queue up a frame representing the indication as a control frame */
300 ast_mutex_lock(&p
->lock
);
301 x
= indexof(p
, ast
, 0);
302 if (!x
&& p
->subchan
)
303 res
= ast_senddigit_begin(p
->subchan
, digit
);
304 ast_mutex_unlock(&p
->lock
);
309 static int features_digit_end(struct ast_channel
*ast
, char digit
, unsigned int duration
)
311 struct feature_pvt
*p
= ast
->tech_pvt
;
315 /* Queue up a frame representing the indication as a control frame */
316 ast_mutex_lock(&p
->lock
);
317 x
= indexof(p
, ast
, 0);
318 if (!x
&& p
->subchan
)
319 res
= ast_senddigit_end(p
->subchan
, digit
, duration
);
320 ast_mutex_unlock(&p
->lock
);
324 static int features_call(struct ast_channel
*ast
, char *dest
, int timeout
)
326 struct feature_pvt
*p
= ast
->tech_pvt
;
331 dest2
= strchr(dest
, '/');
333 ast_mutex_lock(&p
->lock
);
334 x
= indexof(p
, ast
, 0);
335 if (!x
&& p
->subchan
) {
336 p
->subchan
->cid
.cid_num
= ast_strdup(p
->owner
->cid
.cid_num
);
337 p
->subchan
->cid
.cid_name
= ast_strdup(p
->owner
->cid
.cid_name
);
338 p
->subchan
->cid
.cid_rdnis
= ast_strdup(p
->owner
->cid
.cid_rdnis
);
339 p
->subchan
->cid
.cid_ani
= ast_strdup(p
->owner
->cid
.cid_ani
);
341 p
->subchan
->cid
.cid_pres
= p
->owner
->cid
.cid_pres
;
342 ast_string_field_set(p
->subchan
, language
, p
->owner
->language
);
343 ast_string_field_set(p
->subchan
, accountcode
, p
->owner
->accountcode
);
344 p
->subchan
->cdrflags
= p
->owner
->cdrflags
;
345 res
= ast_call(p
->subchan
, dest2
, timeout
);
346 update_features(p
, x
);
348 ast_log(LOG_NOTICE
, "Uhm yah, not quite there with the call waiting...\n");
349 ast_mutex_unlock(&p
->lock
);
354 static int features_hangup(struct ast_channel
*ast
)
356 struct feature_pvt
*p
= ast
->tech_pvt
;
359 ast_mutex_lock(&p
->lock
);
360 x
= indexof(p
, ast
, 0);
362 restore_channel(p
, x
);
363 p
->subs
[x
].owner
= NULL
;
364 /* XXX Re-arrange, unconference, etc XXX */
366 ast
->tech_pvt
= NULL
;
368 if (!p
->subs
[SUB_REAL
].owner
&& !p
->subs
[SUB_CALLWAIT
].owner
&& !p
->subs
[SUB_THREEWAY
].owner
) {
369 ast_mutex_unlock(&p
->lock
);
370 /* Remove from list */
371 AST_LIST_LOCK(&features
);
372 AST_LIST_REMOVE(&features
, p
, list
);
373 AST_LIST_UNLOCK(&features
);
374 ast_mutex_lock(&p
->lock
);
377 ast_hangup(p
->subchan
);
378 ast_mutex_unlock(&p
->lock
);
379 ast_mutex_destroy(&p
->lock
);
383 ast_mutex_unlock(&p
->lock
);
387 static struct feature_pvt
*features_alloc(char *data
, int format
)
389 struct feature_pvt
*tmp
;
394 struct ast_channel
*chan
;
396 tech
= ast_strdupa(data
);
398 dest
= strchr(tech
, '/');
404 if (!tech
|| !dest
) {
405 ast_log(LOG_NOTICE
, "Format for feature channel is Feature/Tech/Dest ('%s' not valid)!\n",
409 AST_LIST_LOCK(&features
);
410 AST_LIST_TRAVERSE(&features
, tmp
, list
) {
411 if (!strcasecmp(tmp
->tech
, tech
) && !strcmp(tmp
->dest
, dest
))
414 AST_LIST_UNLOCK(&features
);
416 chan
= ast_request(tech
, format
, dest
, &status
);
418 ast_log(LOG_NOTICE
, "Unable to allocate subchannel '%s/%s'\n", tech
, dest
);
421 tmp
= ast_calloc(1, sizeof(*tmp
));
424 init_sub(tmp
->subs
+ x
);
425 ast_mutex_init(&tmp
->lock
);
426 ast_copy_string(tmp
->tech
, tech
, sizeof(tmp
->tech
));
427 ast_copy_string(tmp
->dest
, dest
, sizeof(tmp
->dest
));
429 AST_LIST_LOCK(&features
);
430 AST_LIST_INSERT_HEAD(&features
, tmp
, list
);
431 AST_LIST_UNLOCK(&features
);
437 static struct ast_channel
*features_new(struct feature_pvt
*p
, int state
, int index
)
439 struct ast_channel
*tmp
;
443 ast_log(LOG_WARNING
, "Called upon channel with no subchan:(\n");
446 if (p
->subs
[index
].owner
) {
447 ast_log(LOG_WARNING
, "Called to put index %d already there!\n", index
);
450 /* figure out what you want the name to be */
454 asprintf(&b2
, "%s/%s-%d", p
->tech
, p
->dest
, x
);
458 if (p
->subs
[y
].owner
&& !strcasecmp(p
->subs
[y
].owner
->name
, b2
))
464 tmp
= ast_channel_alloc(0, state
, 0,0, "", "", "", 0, "Feature/%s", b2
);
465 /* free up the name, it was copied into the channel name */
469 ast_log(LOG_WARNING
, "Unable to allocate channel structure\n");
472 tmp
->tech
= &features_tech
;
473 tmp
->writeformat
= p
->subchan
->writeformat
;
474 tmp
->rawwriteformat
= p
->subchan
->rawwriteformat
;
475 tmp
->readformat
= p
->subchan
->readformat
;
476 tmp
->rawreadformat
= p
->subchan
->rawreadformat
;
477 tmp
->nativeformats
= p
->subchan
->readformat
;
479 p
->subs
[index
].owner
= tmp
;
482 ast_module_ref(ast_module_info
->self
);
487 static struct ast_channel
*features_request(const char *type
, int format
, void *data
, int *cause
)
489 struct feature_pvt
*p
;
490 struct ast_channel
*chan
= NULL
;
492 p
= features_alloc(data
, format
);
493 if (p
&& !p
->subs
[SUB_REAL
].owner
)
494 chan
= features_new(p
, AST_STATE_DOWN
, SUB_REAL
);
496 update_features(p
,SUB_REAL
);
500 static char *features_show(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
502 struct feature_pvt
*p
;
506 e
->command
= "feature show channels";
508 "Usage: feature show channels\n"
509 " Provides summary information on feature channels.\n";
516 return CLI_SHOWUSAGE
;
518 if (AST_LIST_EMPTY(&features
)) {
519 ast_cli(a
->fd
, "No feature channels in use\n");
523 AST_LIST_LOCK(&features
);
524 AST_LIST_TRAVERSE(&features
, p
, list
) {
525 ast_mutex_lock(&p
->lock
);
526 ast_cli(a
->fd
, "%s -- %s/%s\n", p
->owner
? p
->owner
->name
: "<unowned>", p
->tech
, p
->dest
);
527 ast_mutex_unlock(&p
->lock
);
529 AST_LIST_UNLOCK(&features
);
533 static struct ast_cli_entry cli_features
[] = {
534 AST_CLI_DEFINE(features_show
, "List status of feature channels"),
537 static int load_module(void)
539 /* Make sure we can register our sip channel type */
540 if (ast_channel_register(&features_tech
)) {
541 ast_log(LOG_ERROR
, "Unable to register channel class 'Feature'\n");
542 return AST_MODULE_LOAD_FAILURE
;
544 ast_cli_register_multiple(cli_features
, sizeof(cli_features
) / sizeof(struct ast_cli_entry
));
545 return AST_MODULE_LOAD_SUCCESS
;
548 static int unload_module(void)
550 struct feature_pvt
*p
;
552 /* First, take us out of the channel loop */
553 ast_cli_unregister_multiple(cli_features
, sizeof(cli_features
) / sizeof(struct ast_cli_entry
));
554 ast_channel_unregister(&features_tech
);
556 if (!AST_LIST_LOCK(&features
))
558 /* Hangup all interfaces if they have an owner */
559 while ((p
= AST_LIST_REMOVE_HEAD(&features
, list
))) {
561 ast_softhangup(p
->owner
, AST_SOFTHANGUP_APPUNLOAD
);
564 AST_LIST_UNLOCK(&features
);
569 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY
, "Feature Proxy Channel");