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 DEADLOCK_AVOIDANCE(&p
->lock
);
144 ast_queue_frame(p
->subs
[a
].owner
, &null
);
145 ast_mutex_unlock(&p
->subs
[a
].owner
->lock
);
154 static void restore_channel(struct feature_pvt
*p
, int index
)
156 /* Restore timing/alertpipe */
157 p
->subs
[index
].owner
->timingfd
= p
->subs
[index
].timingfdbackup
;
158 p
->subs
[index
].owner
->alertpipe
[0] = p
->subs
[index
].alertpipebackup
[0];
159 p
->subs
[index
].owner
->alertpipe
[1] = p
->subs
[index
].alertpipebackup
[1];
160 ast_channel_set_fd(p
->subs
[index
].owner
, AST_ALERT_FD
, p
->subs
[index
].alertpipebackup
[0]);
161 ast_channel_set_fd(p
->subs
[index
].owner
, AST_TIMING_FD
, p
->subs
[index
].timingfdbackup
);
164 static void update_features(struct feature_pvt
*p
, int index
)
167 if (p
->subs
[index
].owner
) {
168 for (x
=0; x
<AST_MAX_FDS
; x
++) {
170 ast_channel_set_fd(p
->subs
[index
].owner
, x
, -1);
172 ast_channel_set_fd(p
->subs
[index
].owner
, x
, p
->subchan
->fds
[x
]);
175 /* Copy timings from master channel */
176 p
->subs
[index
].owner
->timingfd
= p
->subchan
->timingfd
;
177 p
->subs
[index
].owner
->alertpipe
[0] = p
->subchan
->alertpipe
[0];
178 p
->subs
[index
].owner
->alertpipe
[1] = p
->subchan
->alertpipe
[1];
179 if (p
->subs
[index
].owner
->nativeformats
!= p
->subchan
->readformat
) {
180 p
->subs
[index
].owner
->nativeformats
= p
->subchan
->readformat
;
181 if (p
->subs
[index
].owner
->readformat
)
182 ast_set_read_format(p
->subs
[index
].owner
, p
->subs
[index
].owner
->readformat
);
183 if (p
->subs
[index
].owner
->writeformat
)
184 ast_set_write_format(p
->subs
[index
].owner
, p
->subs
[index
].owner
->writeformat
);
187 restore_channel(p
, index
);
193 static void swap_subs(struct feature_pvt
*p
, int a
, int b
)
196 struct ast_channel
*towner
;
198 ast_debug(1, "Swapping %d and %d\n", a
, b
);
200 towner
= p
->subs
[a
].owner
;
201 tinthreeway
= p
->subs
[a
].inthreeway
;
203 p
->subs
[a
].owner
= p
->subs
[b
].owner
;
204 p
->subs
[a
].inthreeway
= p
->subs
[b
].inthreeway
;
206 p
->subs
[b
].owner
= towner
;
207 p
->subs
[b
].inthreeway
= tinthreeway
;
208 update_features(p
,a
);
209 update_features(p
,b
);
215 static int features_answer(struct ast_channel
*ast
)
217 struct feature_pvt
*p
= ast
->tech_pvt
;
221 ast_mutex_lock(&p
->lock
);
222 x
= indexof(p
, ast
, 0);
223 if (!x
&& p
->subchan
)
224 res
= ast_answer(p
->subchan
);
225 ast_mutex_unlock(&p
->lock
);
229 static struct ast_frame
*features_read(struct ast_channel
*ast
)
231 struct feature_pvt
*p
= ast
->tech_pvt
;
236 ast_mutex_lock(&p
->lock
);
237 x
= indexof(p
, ast
, 0);
238 if (!x
&& p
->subchan
) {
239 update_features(p
, x
);
240 f
= ast_read(p
->subchan
);
242 ast_mutex_unlock(&p
->lock
);
246 static int features_write(struct ast_channel
*ast
, struct ast_frame
*f
)
248 struct feature_pvt
*p
= ast
->tech_pvt
;
252 ast_mutex_lock(&p
->lock
);
253 x
= indexof(p
, ast
, 0);
254 if (!x
&& p
->subchan
)
255 res
= ast_write(p
->subchan
, f
);
256 ast_mutex_unlock(&p
->lock
);
260 static int features_fixup(struct ast_channel
*oldchan
, struct ast_channel
*newchan
)
262 struct feature_pvt
*p
= newchan
->tech_pvt
;
265 ast_mutex_lock(&p
->lock
);
266 if (p
->owner
== oldchan
)
268 for (x
= 0; x
< 3; x
++) {
269 if (p
->subs
[x
].owner
== oldchan
)
270 p
->subs
[x
].owner
= newchan
;
272 ast_mutex_unlock(&p
->lock
);
276 static int features_indicate(struct ast_channel
*ast
, int condition
, const void *data
, size_t datalen
)
278 struct feature_pvt
*p
= ast
->tech_pvt
;
282 /* Queue up a frame representing the indication as a control frame */
283 ast_mutex_lock(&p
->lock
);
284 x
= indexof(p
, ast
, 0);
285 if (!x
&& p
->subchan
)
286 res
= ast_indicate(p
->subchan
, condition
);
287 ast_mutex_unlock(&p
->lock
);
291 static int features_digit_begin(struct ast_channel
*ast
, char digit
)
293 struct feature_pvt
*p
= ast
->tech_pvt
;
297 /* Queue up a frame representing the indication as a control frame */
298 ast_mutex_lock(&p
->lock
);
299 x
= indexof(p
, ast
, 0);
300 if (!x
&& p
->subchan
)
301 res
= ast_senddigit_begin(p
->subchan
, digit
);
302 ast_mutex_unlock(&p
->lock
);
307 static int features_digit_end(struct ast_channel
*ast
, char digit
, unsigned int duration
)
309 struct feature_pvt
*p
= ast
->tech_pvt
;
313 /* Queue up a frame representing the indication as a control frame */
314 ast_mutex_lock(&p
->lock
);
315 x
= indexof(p
, ast
, 0);
316 if (!x
&& p
->subchan
)
317 res
= ast_senddigit_end(p
->subchan
, digit
, duration
);
318 ast_mutex_unlock(&p
->lock
);
322 static int features_call(struct ast_channel
*ast
, char *dest
, int timeout
)
324 struct feature_pvt
*p
= ast
->tech_pvt
;
329 dest2
= strchr(dest
, '/');
331 ast_mutex_lock(&p
->lock
);
332 x
= indexof(p
, ast
, 0);
333 if (!x
&& p
->subchan
) {
334 p
->subchan
->cid
.cid_num
= ast_strdup(p
->owner
->cid
.cid_num
);
335 p
->subchan
->cid
.cid_name
= ast_strdup(p
->owner
->cid
.cid_name
);
336 p
->subchan
->cid
.cid_rdnis
= ast_strdup(p
->owner
->cid
.cid_rdnis
);
337 p
->subchan
->cid
.cid_ani
= ast_strdup(p
->owner
->cid
.cid_ani
);
339 p
->subchan
->cid
.cid_pres
= p
->owner
->cid
.cid_pres
;
340 ast_string_field_set(p
->subchan
, language
, p
->owner
->language
);
341 ast_string_field_set(p
->subchan
, accountcode
, p
->owner
->accountcode
);
342 p
->subchan
->cdrflags
= p
->owner
->cdrflags
;
343 res
= ast_call(p
->subchan
, dest2
, timeout
);
344 update_features(p
, x
);
346 ast_log(LOG_NOTICE
, "Uhm yah, not quite there with the call waiting...\n");
347 ast_mutex_unlock(&p
->lock
);
352 static int features_hangup(struct ast_channel
*ast
)
354 struct feature_pvt
*p
= ast
->tech_pvt
;
357 ast_mutex_lock(&p
->lock
);
358 x
= indexof(p
, ast
, 0);
360 restore_channel(p
, x
);
361 p
->subs
[x
].owner
= NULL
;
362 /* XXX Re-arrange, unconference, etc XXX */
364 ast
->tech_pvt
= NULL
;
366 if (!p
->subs
[SUB_REAL
].owner
&& !p
->subs
[SUB_CALLWAIT
].owner
&& !p
->subs
[SUB_THREEWAY
].owner
) {
367 ast_mutex_unlock(&p
->lock
);
368 /* Remove from list */
369 AST_LIST_LOCK(&features
);
370 AST_LIST_REMOVE(&features
, p
, list
);
371 AST_LIST_UNLOCK(&features
);
372 ast_mutex_lock(&p
->lock
);
375 ast_hangup(p
->subchan
);
376 ast_mutex_unlock(&p
->lock
);
377 ast_mutex_destroy(&p
->lock
);
381 ast_mutex_unlock(&p
->lock
);
385 static struct feature_pvt
*features_alloc(char *data
, int format
)
387 struct feature_pvt
*tmp
;
392 struct ast_channel
*chan
;
394 tech
= ast_strdupa(data
);
396 dest
= strchr(tech
, '/');
402 if (!tech
|| !dest
) {
403 ast_log(LOG_NOTICE
, "Format for feature channel is Feature/Tech/Dest ('%s' not valid)!\n",
407 AST_LIST_LOCK(&features
);
408 AST_LIST_TRAVERSE(&features
, tmp
, list
) {
409 if (!strcasecmp(tmp
->tech
, tech
) && !strcmp(tmp
->dest
, dest
))
412 AST_LIST_UNLOCK(&features
);
414 chan
= ast_request(tech
, format
, dest
, &status
);
416 ast_log(LOG_NOTICE
, "Unable to allocate subchannel '%s/%s'\n", tech
, dest
);
419 tmp
= ast_calloc(1, sizeof(*tmp
));
422 init_sub(tmp
->subs
+ x
);
423 ast_mutex_init(&tmp
->lock
);
424 ast_copy_string(tmp
->tech
, tech
, sizeof(tmp
->tech
));
425 ast_copy_string(tmp
->dest
, dest
, sizeof(tmp
->dest
));
427 AST_LIST_LOCK(&features
);
428 AST_LIST_INSERT_HEAD(&features
, tmp
, list
);
429 AST_LIST_UNLOCK(&features
);
435 static struct ast_channel
*features_new(struct feature_pvt
*p
, int state
, int index
)
437 struct ast_channel
*tmp
;
441 ast_log(LOG_WARNING
, "Called upon channel with no subchan:(\n");
444 if (p
->subs
[index
].owner
) {
445 ast_log(LOG_WARNING
, "Called to put index %d already there!\n", index
);
448 /* figure out what you want the name to be */
452 asprintf(&b2
, "%s/%s-%d", p
->tech
, p
->dest
, x
);
456 if (p
->subs
[y
].owner
&& !strcasecmp(p
->subs
[y
].owner
->name
, b2
))
462 tmp
= ast_channel_alloc(0, state
, 0,0, "", "", "", 0, "Feature/%s", b2
);
463 /* free up the name, it was copied into the channel name */
467 ast_log(LOG_WARNING
, "Unable to allocate channel structure\n");
470 tmp
->tech
= &features_tech
;
471 tmp
->writeformat
= p
->subchan
->writeformat
;
472 tmp
->rawwriteformat
= p
->subchan
->rawwriteformat
;
473 tmp
->readformat
= p
->subchan
->readformat
;
474 tmp
->rawreadformat
= p
->subchan
->rawreadformat
;
475 tmp
->nativeformats
= p
->subchan
->readformat
;
477 p
->subs
[index
].owner
= tmp
;
480 ast_module_ref(ast_module_info
->self
);
485 static struct ast_channel
*features_request(const char *type
, int format
, void *data
, int *cause
)
487 struct feature_pvt
*p
;
488 struct ast_channel
*chan
= NULL
;
490 p
= features_alloc(data
, format
);
491 if (p
&& !p
->subs
[SUB_REAL
].owner
)
492 chan
= features_new(p
, AST_STATE_DOWN
, SUB_REAL
);
494 update_features(p
,SUB_REAL
);
498 static char *features_show(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
500 struct feature_pvt
*p
;
504 e
->command
= "feature show channels";
506 "Usage: feature show channels\n"
507 " Provides summary information on feature channels.\n";
514 return CLI_SHOWUSAGE
;
516 if (AST_LIST_EMPTY(&features
)) {
517 ast_cli(a
->fd
, "No feature channels in use\n");
521 AST_LIST_LOCK(&features
);
522 AST_LIST_TRAVERSE(&features
, p
, list
) {
523 ast_mutex_lock(&p
->lock
);
524 ast_cli(a
->fd
, "%s -- %s/%s\n", p
->owner
? p
->owner
->name
: "<unowned>", p
->tech
, p
->dest
);
525 ast_mutex_unlock(&p
->lock
);
527 AST_LIST_UNLOCK(&features
);
531 static struct ast_cli_entry cli_features
[] = {
532 AST_CLI_DEFINE(features_show
, "List status of feature channels"),
535 static int load_module(void)
537 /* Make sure we can register our sip channel type */
538 if (ast_channel_register(&features_tech
)) {
539 ast_log(LOG_ERROR
, "Unable to register channel class 'Feature'\n");
540 return AST_MODULE_LOAD_FAILURE
;
542 ast_cli_register_multiple(cli_features
, sizeof(cli_features
) / sizeof(struct ast_cli_entry
));
543 return AST_MODULE_LOAD_SUCCESS
;
546 static int unload_module(void)
548 struct feature_pvt
*p
;
550 /* First, take us out of the channel loop */
551 ast_cli_unregister_multiple(cli_features
, sizeof(cli_features
) / sizeof(struct ast_cli_entry
));
552 ast_channel_unregister(&features_tech
);
554 if (!AST_LIST_LOCK(&features
))
556 /* Hangup all interfaces if they have an owner */
557 while ((p
= AST_LIST_REMOVE_HEAD(&features
, list
))) {
559 ast_softhangup(p
->owner
, AST_SOFTHANGUP_APPUNLOAD
);
562 AST_LIST_UNLOCK(&features
);
567 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY
, "Feature Proxy Channel");