![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
chan_features.c
Go to the documentation of this file.
00001 /* 00002 * Asterisk -- An open source telephony toolkit. 00003 * 00004 * Copyright (C) 1999 - 2005, Digium, Inc. 00005 * 00006 * Mark Spencer <markster@digium.com> 00007 * 00008 * See http://www.asterisk.org for more information about 00009 * the Asterisk project. Please do not directly contact 00010 * any of the maintainers of this project for assistance; 00011 * the project provides a web site, mailing lists and IRC 00012 * channels for your use. 00013 * 00014 * This program is free software, distributed under the terms of 00015 * the GNU General Public License Version 2. See the LICENSE file 00016 * at the top of the source tree. 00017 */ 00018 00019 /*! \file 00020 * 00021 * \brief feature Proxy Channel 00022 * 00023 * \author Mark Spencer <markster@digium.com> 00024 * 00025 * \note *** Experimental code **** 00026 * 00027 * \ingroup channel_drivers 00028 */ 00029 00030 #include "asterisk.h" 00031 00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 51806 $") 00033 00034 #include <stdio.h> 00035 #include <string.h> 00036 #include <unistd.h> 00037 #include <sys/socket.h> 00038 #include <errno.h> 00039 #include <stdlib.h> 00040 #include <fcntl.h> 00041 #include <netdb.h> 00042 #include <netinet/in.h> 00043 #include <arpa/inet.h> 00044 #include <sys/signal.h> 00045 00046 #include "asterisk/lock.h" 00047 #include "asterisk/channel.h" 00048 #include "asterisk/config.h" 00049 #include "asterisk/logger.h" 00050 #include "asterisk/module.h" 00051 #include "asterisk/pbx.h" 00052 #include "asterisk/options.h" 00053 #include "asterisk/lock.h" 00054 #include "asterisk/sched.h" 00055 #include "asterisk/io.h" 00056 #include "asterisk/rtp.h" 00057 #include "asterisk/acl.h" 00058 #include "asterisk/callerid.h" 00059 #include "asterisk/file.h" 00060 #include "asterisk/cli.h" 00061 #include "asterisk/app.h" 00062 #include "asterisk/musiconhold.h" 00063 #include "asterisk/manager.h" 00064 #include "asterisk/stringfields.h" 00065 00066 static const char tdesc[] = "Feature Proxy Channel Driver"; 00067 00068 #define IS_OUTBOUND(a,b) (a == b->chan ? 1 : 0) 00069 00070 struct feature_sub { 00071 struct ast_channel *owner; 00072 int inthreeway; 00073 int pfd; 00074 int timingfdbackup; 00075 int alertpipebackup[2]; 00076 }; 00077 00078 struct feature_pvt { 00079 ast_mutex_t lock; /* Channel private lock */ 00080 char tech[AST_MAX_EXTENSION]; /* Technology to abstract */ 00081 char dest[AST_MAX_EXTENSION]; /* Destination to abstract */ 00082 struct ast_channel *subchan; 00083 struct feature_sub subs[3]; /* Subs */ 00084 struct ast_channel *owner; /* Current Master Channel */ 00085 AST_LIST_ENTRY(feature_pvt) list; /* Next entity */ 00086 }; 00087 00088 static AST_LIST_HEAD_STATIC(features, feature_pvt); 00089 00090 #define SUB_REAL 0 /* Active call */ 00091 #define SUB_CALLWAIT 1 /* Call-Waiting call on hold */ 00092 #define SUB_THREEWAY 2 /* Three-way call */ 00093 00094 static struct ast_channel *features_request(const char *type, int format, void *data, int *cause); 00095 static int features_digit_begin(struct ast_channel *ast, char digit); 00096 static int features_digit_end(struct ast_channel *ast, char digit, unsigned int duration); 00097 static int features_call(struct ast_channel *ast, char *dest, int timeout); 00098 static int features_hangup(struct ast_channel *ast); 00099 static int features_answer(struct ast_channel *ast); 00100 static struct ast_frame *features_read(struct ast_channel *ast); 00101 static int features_write(struct ast_channel *ast, struct ast_frame *f); 00102 static int features_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen); 00103 static int features_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); 00104 00105 static const struct ast_channel_tech features_tech = { 00106 .type = "Feature", 00107 .description = tdesc, 00108 .capabilities = -1, 00109 .requester = features_request, 00110 .send_digit_begin = features_digit_begin, 00111 .send_digit_end = features_digit_end, 00112 .call = features_call, 00113 .hangup = features_hangup, 00114 .answer = features_answer, 00115 .read = features_read, 00116 .write = features_write, 00117 .exception = features_read, 00118 .indicate = features_indicate, 00119 .fixup = features_fixup, 00120 }; 00121 00122 static inline void init_sub(struct feature_sub *sub) 00123 { 00124 sub->inthreeway = 0; 00125 sub->pfd = -1; 00126 sub->timingfdbackup = -1; 00127 sub->alertpipebackup[0] = sub->alertpipebackup[1] = -1; 00128 } 00129 00130 static inline int indexof(struct feature_pvt *p, struct ast_channel *owner, int nullok) 00131 { 00132 int x; 00133 if (!owner) { 00134 ast_log(LOG_WARNING, "indexof called on NULL owner??\n"); 00135 return -1; 00136 } 00137 for (x=0; x<3; x++) { 00138 if (owner == p->subs[x].owner) 00139 return x; 00140 } 00141 return -1; 00142 } 00143 00144 #if 0 00145 static void wakeup_sub(struct feature_pvt *p, int a) 00146 { 00147 struct ast_frame null = { AST_FRAME_NULL, }; 00148 for (;;) { 00149 if (p->subs[a].owner) { 00150 if (ast_mutex_trylock(&p->subs[a].owner->lock)) { 00151 ast_mutex_unlock(&p->lock); 00152 usleep(1); 00153 ast_mutex_lock(&p->lock); 00154 } else { 00155 ast_queue_frame(p->subs[a].owner, &null); 00156 ast_mutex_unlock(&p->subs[a].owner->lock); 00157 break; 00158 } 00159 } else 00160 break; 00161 } 00162 } 00163 #endif 00164 00165 static void restore_channel(struct feature_pvt *p, int index) 00166 { 00167 /* Restore timing/alertpipe */ 00168 p->subs[index].owner->timingfd = p->subs[index].timingfdbackup; 00169 p->subs[index].owner->alertpipe[0] = p->subs[index].alertpipebackup[0]; 00170 p->subs[index].owner->alertpipe[1] = p->subs[index].alertpipebackup[1]; 00171 p->subs[index].owner->fds[AST_ALERT_FD] = p->subs[index].alertpipebackup[0]; 00172 p->subs[index].owner->fds[AST_TIMING_FD] = p->subs[index].timingfdbackup; 00173 } 00174 00175 static void update_features(struct feature_pvt *p, int index) 00176 { 00177 int x; 00178 if (p->subs[index].owner) { 00179 for (x=0; x<AST_MAX_FDS; x++) { 00180 if (index) 00181 p->subs[index].owner->fds[x] = -1; 00182 else 00183 p->subs[index].owner->fds[x] = p->subchan->fds[x]; 00184 } 00185 if (!index) { 00186 /* Copy timings from master channel */ 00187 p->subs[index].owner->timingfd = p->subchan->timingfd; 00188 p->subs[index].owner->alertpipe[0] = p->subchan->alertpipe[0]; 00189 p->subs[index].owner->alertpipe[1] = p->subchan->alertpipe[1]; 00190 if (p->subs[index].owner->nativeformats != p->subchan->readformat) { 00191 p->subs[index].owner->nativeformats = p->subchan->readformat; 00192 if (p->subs[index].owner->readformat) 00193 ast_set_read_format(p->subs[index].owner, p->subs[index].owner->readformat); 00194 if (p->subs[index].owner->writeformat) 00195 ast_set_write_format(p->subs[index].owner, p->subs[index].owner->writeformat); 00196 } 00197 } else{ 00198 restore_channel(p, index); 00199 } 00200 } 00201 } 00202 00203 #if 0 00204 static void swap_subs(struct feature_pvt *p, int a, int b) 00205 { 00206 int tinthreeway; 00207 struct ast_channel *towner; 00208 00209 if (option_debug) 00210 ast_log(LOG_DEBUG, "Swapping %d and %d\n", a, b); 00211 00212 towner = p->subs[a].owner; 00213 tinthreeway = p->subs[a].inthreeway; 00214 00215 p->subs[a].owner = p->subs[b].owner; 00216 p->subs[a].inthreeway = p->subs[b].inthreeway; 00217 00218 p->subs[b].owner = towner; 00219 p->subs[b].inthreeway = tinthreeway; 00220 update_features(p,a); 00221 update_features(p,b); 00222 wakeup_sub(p, a); 00223 wakeup_sub(p, b); 00224 } 00225 #endif 00226 00227 static int features_answer(struct ast_channel *ast) 00228 { 00229 struct feature_pvt *p = ast->tech_pvt; 00230 int res = -1; 00231 int x; 00232 00233 ast_mutex_lock(&p->lock); 00234 x = indexof(p, ast, 0); 00235 if (!x && p->subchan) 00236 res = ast_answer(p->subchan); 00237 ast_mutex_unlock(&p->lock); 00238 return res; 00239 } 00240 00241 static struct ast_frame *features_read(struct ast_channel *ast) 00242 { 00243 struct feature_pvt *p = ast->tech_pvt; 00244 struct ast_frame *f; 00245 int x; 00246 00247 f = &ast_null_frame; 00248 ast_mutex_lock(&p->lock); 00249 x = indexof(p, ast, 0); 00250 if (!x && p->subchan) { 00251 update_features(p, x); 00252 f = ast_read(p->subchan); 00253 } 00254 ast_mutex_unlock(&p->lock); 00255 return f; 00256 } 00257 00258 static int features_write(struct ast_channel *ast, struct ast_frame *f) 00259 { 00260 struct feature_pvt *p = ast->tech_pvt; 00261 int res = -1; 00262 int x; 00263 00264 ast_mutex_lock(&p->lock); 00265 x = indexof(p, ast, 0); 00266 if (!x && p->subchan) 00267 res = ast_write(p->subchan, f); 00268 ast_mutex_unlock(&p->lock); 00269 return res; 00270 } 00271 00272 static int features_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) 00273 { 00274 struct feature_pvt *p = newchan->tech_pvt; 00275 int x; 00276 00277 ast_mutex_lock(&p->lock); 00278 if (p->owner == oldchan) 00279 p->owner = newchan; 00280 for (x = 0; x < 3; x++) { 00281 if (p->subs[x].owner == oldchan) 00282 p->subs[x].owner = newchan; 00283 } 00284 ast_mutex_unlock(&p->lock); 00285 return 0; 00286 } 00287 00288 static int features_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen) 00289 { 00290 struct feature_pvt *p = ast->tech_pvt; 00291 int res = -1; 00292 int x; 00293 00294 /* Queue up a frame representing the indication as a control frame */ 00295 ast_mutex_lock(&p->lock); 00296 x = indexof(p, ast, 0); 00297 if (!x && p->subchan) 00298 res = ast_indicate(p->subchan, condition); 00299 ast_mutex_unlock(&p->lock); 00300 return res; 00301 } 00302 00303 static int features_digit_begin(struct ast_channel *ast, char digit) 00304 { 00305 struct feature_pvt *p = ast->tech_pvt; 00306 int res = -1; 00307 int x; 00308 00309 /* Queue up a frame representing the indication as a control frame */ 00310 ast_mutex_lock(&p->lock); 00311 x = indexof(p, ast, 0); 00312 if (!x && p->subchan) 00313 res = ast_senddigit_begin(p->subchan, digit); 00314 ast_mutex_unlock(&p->lock); 00315 00316 return res; 00317 } 00318 00319 static int features_digit_end(struct ast_channel *ast, char digit, unsigned int duration) 00320 { 00321 struct feature_pvt *p = ast->tech_pvt; 00322 int res = -1; 00323 int x; 00324 00325 /* Queue up a frame representing the indication as a control frame */ 00326 ast_mutex_lock(&p->lock); 00327 x = indexof(p, ast, 0); 00328 if (!x && p->subchan) 00329 res = ast_senddigit_end(p->subchan, digit, duration); 00330 ast_mutex_unlock(&p->lock); 00331 return res; 00332 } 00333 00334 static int features_call(struct ast_channel *ast, char *dest, int timeout) 00335 { 00336 struct feature_pvt *p = ast->tech_pvt; 00337 int res = -1; 00338 int x; 00339 char *dest2; 00340 00341 dest2 = strchr(dest, '/'); 00342 if (dest2) { 00343 ast_mutex_lock(&p->lock); 00344 x = indexof(p, ast, 0); 00345 if (!x && p->subchan) { 00346 p->subchan->cid.cid_num = ast_strdup(p->owner->cid.cid_num); 00347 p->subchan->cid.cid_name = ast_strdup(p->owner->cid.cid_name); 00348 p->subchan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis); 00349 p->subchan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani); 00350 00351 p->subchan->cid.cid_pres = p->owner->cid.cid_pres; 00352 ast_string_field_set(p->subchan, language, p->owner->language); 00353 ast_string_field_set(p->subchan, accountcode, p->owner->accountcode); 00354 p->subchan->cdrflags = p->owner->cdrflags; 00355 res = ast_call(p->subchan, dest2, timeout); 00356 update_features(p, x); 00357 } else 00358 ast_log(LOG_NOTICE, "Uhm yah, not quite there with the call waiting...\n"); 00359 ast_mutex_unlock(&p->lock); 00360 } 00361 return res; 00362 } 00363 00364 static int features_hangup(struct ast_channel *ast) 00365 { 00366 struct feature_pvt *p = ast->tech_pvt; 00367 int x; 00368 00369 ast_mutex_lock(&p->lock); 00370 x = indexof(p, ast, 0); 00371 if (x > -1) { 00372 restore_channel(p, x); 00373 p->subs[x].owner = NULL; 00374 /* XXX Re-arrange, unconference, etc XXX */ 00375 } 00376 ast->tech_pvt = NULL; 00377 00378 if (!p->subs[SUB_REAL].owner && !p->subs[SUB_CALLWAIT].owner && !p->subs[SUB_THREEWAY].owner) { 00379 ast_mutex_unlock(&p->lock); 00380 /* Remove from list */ 00381 AST_LIST_LOCK(&features); 00382 AST_LIST_REMOVE(&features, p, list); 00383 AST_LIST_UNLOCK(&features); 00384 ast_mutex_lock(&p->lock); 00385 /* And destroy */ 00386 if (p->subchan) 00387 ast_hangup(p->subchan); 00388 ast_mutex_unlock(&p->lock); 00389 ast_mutex_destroy(&p->lock); 00390 free(p); 00391 return 0; 00392 } 00393 ast_mutex_unlock(&p->lock); 00394 return 0; 00395 } 00396 00397 static struct feature_pvt *features_alloc(char *data, int format) 00398 { 00399 struct feature_pvt *tmp; 00400 char *dest=NULL; 00401 char *tech; 00402 int x; 00403 int status; 00404 struct ast_channel *chan; 00405 00406 tech = ast_strdupa(data); 00407 if (tech) { 00408 dest = strchr(tech, '/'); 00409 if (dest) { 00410 *dest = '\0'; 00411 dest++; 00412 } 00413 } 00414 if (!tech || !dest) { 00415 ast_log(LOG_NOTICE, "Format for feature channel is Feature/Tech/Dest ('%s' not valid)!\n", 00416 data); 00417 return NULL; 00418 } 00419 AST_LIST_LOCK(&features); 00420 AST_LIST_TRAVERSE(&features, tmp, list) { 00421 if (!strcasecmp(tmp->tech, tech) && !strcmp(tmp->dest, dest)) 00422 break; 00423 } 00424 AST_LIST_UNLOCK(&features); 00425 if (!tmp) { 00426 chan = ast_request(tech, format, dest, &status); 00427 if (!chan) { 00428 ast_log(LOG_NOTICE, "Unable to allocate subchannel '%s/%s'\n", tech, dest); 00429 return NULL; 00430 } 00431 tmp = malloc(sizeof(struct feature_pvt)); 00432 if (tmp) { 00433 memset(tmp, 0, sizeof(struct feature_pvt)); 00434 for (x=0;x<3;x++) 00435 init_sub(tmp->subs + x); 00436 ast_mutex_init(&tmp->lock); 00437 ast_copy_string(tmp->tech, tech, sizeof(tmp->tech)); 00438 ast_copy_string(tmp->dest, dest, sizeof(tmp->dest)); 00439 tmp->subchan = chan; 00440 AST_LIST_LOCK(&features); 00441 AST_LIST_INSERT_HEAD(&features, tmp, list); 00442 AST_LIST_UNLOCK(&features); 00443 } 00444 } 00445 return tmp; 00446 } 00447 00448 static struct ast_channel *features_new(struct feature_pvt *p, int state, int index) 00449 { 00450 struct ast_channel *tmp; 00451 int x,y; 00452 char *b2 = 0; 00453 if (!p->subchan) { 00454 ast_log(LOG_WARNING, "Called upon channel with no subchan:(\n"); 00455 return NULL; 00456 } 00457 if (p->subs[index].owner) { 00458 ast_log(LOG_WARNING, "Called to put index %d already there!\n", index); 00459 return NULL; 00460 } 00461 /* figure out what you want the name to be */ 00462 for (x=1;x<4;x++) { 00463 if (b2) 00464 free(b2); 00465 asprintf(&b2, "Feature/%s/%s-%d", p->tech, p->dest, x); 00466 for (y=0;y<3;y++) { 00467 if (y == index) 00468 continue; 00469 if (p->subs[y].owner && !strcasecmp(p->subs[y].owner->name, b2)) 00470 break; 00471 } 00472 if (y >= 3) 00473 break; 00474 } 00475 tmp = ast_channel_alloc(0, state, 0,0, b2); 00476 /* free up the name, it was copied into the channel name */ 00477 if (b2) 00478 free(b2); 00479 if (!tmp) { 00480 ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); 00481 return NULL; 00482 } 00483 tmp->tech = &features_tech; 00484 tmp->writeformat = p->subchan->writeformat; 00485 tmp->rawwriteformat = p->subchan->rawwriteformat; 00486 tmp->readformat = p->subchan->readformat; 00487 tmp->rawreadformat = p->subchan->rawreadformat; 00488 tmp->nativeformats = p->subchan->readformat; 00489 tmp->tech_pvt = p; 00490 p->subs[index].owner = tmp; 00491 if (!p->owner) 00492 p->owner = tmp; 00493 ast_module_ref(ast_module_info->self); 00494 return tmp; 00495 } 00496 00497 00498 static struct ast_channel *features_request(const char *type, int format, void *data, int *cause) 00499 { 00500 struct feature_pvt *p; 00501 struct ast_channel *chan = NULL; 00502 00503 p = features_alloc(data, format); 00504 if (p && !p->subs[SUB_REAL].owner) 00505 chan = features_new(p, AST_STATE_DOWN, SUB_REAL); 00506 if (chan) 00507 update_features(p,SUB_REAL); 00508 return chan; 00509 } 00510 00511 static int features_show(int fd, int argc, char **argv) 00512 { 00513 struct feature_pvt *p; 00514 00515 if (argc != 3) 00516 return RESULT_SHOWUSAGE; 00517 00518 if (AST_LIST_EMPTY(&features)) { 00519 ast_cli(fd, "No feature channels in use\n"); 00520 return RESULT_SUCCESS; 00521 } 00522 00523 AST_LIST_LOCK(&features); 00524 AST_LIST_TRAVERSE(&features, p, list) { 00525 ast_mutex_lock(&p->lock); 00526 ast_cli(fd, "%s -- %s/%s\n", p->owner ? p->owner->name : "<unowned>", p->tech, p->dest); 00527 ast_mutex_unlock(&p->lock); 00528 } 00529 AST_LIST_UNLOCK(&features); 00530 return RESULT_SUCCESS; 00531 } 00532 00533 static const char show_features_usage[] = 00534 "Usage: feature show channels\n" 00535 " Provides summary information on feature channels.\n"; 00536 00537 static struct ast_cli_entry cli_features[] = { 00538 { { "feature", "show", "channels", NULL }, 00539 features_show, "List status of feature channels", 00540 show_features_usage }, 00541 }; 00542 00543 static int load_module(void) 00544 { 00545 /* Make sure we can register our sip channel type */ 00546 if (ast_channel_register(&features_tech)) { 00547 ast_log(LOG_ERROR, "Unable to register channel class 'Feature'\n"); 00548 return -1; 00549 } 00550 ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 00551 return 0; 00552 } 00553 00554 static int unload_module(void) 00555 { 00556 struct feature_pvt *p; 00557 00558 /* First, take us out of the channel loop */ 00559 ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry)); 00560 ast_channel_unregister(&features_tech); 00561 00562 if (!AST_LIST_LOCK(&features)) 00563 return -1; 00564 /* Hangup all interfaces if they have an owner */ 00565 AST_LIST_TRAVERSE_SAFE_BEGIN(&features, p, list) { 00566 if (p->owner) 00567 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 00568 AST_LIST_REMOVE_CURRENT(&features, list); 00569 free(p); 00570 } 00571 AST_LIST_TRAVERSE_SAFE_END 00572 AST_LIST_UNLOCK(&features); 00573 00574 return 0; 00575 } 00576 00577 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Feature Proxy Channel"); 00578