![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
chan_mgcp.c
Go to the documentation of this file.
00001 /* 00002 * Asterisk -- An open source telephony toolkit. 00003 * 00004 * Copyright (C) 1999 - 2006, 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 Implementation of Media Gateway Control Protocol 00022 * 00023 * \author Mark Spencer <markster@digium.com> 00024 * 00025 * \par See also 00026 * \arg \ref Config_mgcp 00027 * 00028 * \ingroup channel_drivers 00029 */ 00030 00031 #include "asterisk.h" 00032 00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 51385 $") 00034 00035 #include <stdio.h> 00036 #include <string.h> 00037 #include <unistd.h> 00038 #include <sys/socket.h> 00039 #include <sys/ioctl.h> 00040 #include <net/if.h> 00041 #include <errno.h> 00042 #include <stdlib.h> 00043 #include <fcntl.h> 00044 #include <netdb.h> 00045 #include <sys/signal.h> 00046 #include <signal.h> 00047 #include <netinet/in.h> 00048 #include <netinet/in_systm.h> 00049 #include <netinet/ip.h> 00050 #include <arpa/inet.h> 00051 #include <ctype.h> 00052 00053 #include "asterisk/lock.h" 00054 #include "asterisk/channel.h" 00055 #include "asterisk/config.h" 00056 #include "asterisk/logger.h" 00057 #include "asterisk/module.h" 00058 #include "asterisk/pbx.h" 00059 #include "asterisk/options.h" 00060 #include "asterisk/lock.h" 00061 #include "asterisk/sched.h" 00062 #include "asterisk/io.h" 00063 #include "asterisk/rtp.h" 00064 #include "asterisk/acl.h" 00065 #include "asterisk/callerid.h" 00066 #include "asterisk/cli.h" 00067 #include "asterisk/say.h" 00068 #include "asterisk/cdr.h" 00069 #include "asterisk/astdb.h" 00070 #include "asterisk/features.h" 00071 #include "asterisk/app.h" 00072 #include "asterisk/musiconhold.h" 00073 #include "asterisk/utils.h" 00074 #include "asterisk/causes.h" 00075 #include "asterisk/dsp.h" 00076 #include "asterisk/devicestate.h" 00077 #include "asterisk/stringfields.h" 00078 #include "asterisk/abstract_jb.h" 00079 00080 #ifndef IPTOS_MINCOST 00081 #define IPTOS_MINCOST 0x02 00082 #endif 00083 00084 /* 00085 * Define to work around buggy dlink MGCP phone firmware which 00086 * appears not to know that "rt" is part of the "G" package. 00087 */ 00088 /* #define DLINK_BUGGY_FIRMWARE */ 00089 00090 #define MGCPDUMPER 00091 #define DEFAULT_EXPIRY 120 00092 #define MAX_EXPIRY 3600 00093 #define CANREINVITE 1 00094 00095 #ifndef INADDR_NONE 00096 #define INADDR_NONE (in_addr_t)(-1) 00097 #endif 00098 00099 /*! Global jitterbuffer configuration - by default, jb is disabled */ 00100 static struct ast_jb_conf default_jbconf = 00101 { 00102 .flags = 0, 00103 .max_size = -1, 00104 .resync_threshold = -1, 00105 .impl = "" 00106 }; 00107 static struct ast_jb_conf global_jbconf; 00108 00109 static const char tdesc[] = "Media Gateway Control Protocol (MGCP)"; 00110 static const char config[] = "mgcp.conf"; 00111 00112 #define MGCP_DTMF_RFC2833 (1 << 0) 00113 #define MGCP_DTMF_INBAND (1 << 1) 00114 #define MGCP_DTMF_HYBRID (1 << 2) 00115 00116 #define DEFAULT_MGCP_GW_PORT 2427 /*!< From RFC 2705 */ 00117 #define DEFAULT_MGCP_CA_PORT 2727 /*!< From RFC 2705 */ 00118 #define MGCP_MAX_PACKET 1500 /*!< Also from RFC 2543, should sub headers tho */ 00119 #define DEFAULT_RETRANS 1000 /*!< How frequently to retransmit */ 00120 #define MAX_RETRANS 5 /*!< Try only 5 times for retransmissions */ 00121 00122 /*! MGCP rtp stream modes { */ 00123 #define MGCP_CX_SENDONLY 0 00124 #define MGCP_CX_RECVONLY 1 00125 #define MGCP_CX_SENDRECV 2 00126 #define MGCP_CX_CONF 3 00127 #define MGCP_CX_CONFERENCE 3 00128 #define MGCP_CX_MUTE 4 00129 #define MGCP_CX_INACTIVE 4 00130 /*! } */ 00131 00132 static char *mgcp_cxmodes[] = { 00133 "sendonly", 00134 "recvonly", 00135 "sendrecv", 00136 "confrnce", 00137 "inactive" 00138 }; 00139 00140 enum { 00141 MGCP_CMD_EPCF, 00142 MGCP_CMD_CRCX, 00143 MGCP_CMD_MDCX, 00144 MGCP_CMD_DLCX, 00145 MGCP_CMD_RQNT, 00146 MGCP_CMD_NTFY, 00147 MGCP_CMD_AUEP, 00148 MGCP_CMD_AUCX, 00149 MGCP_CMD_RSIP 00150 }; 00151 00152 static char context[AST_MAX_EXTENSION] = "default"; 00153 00154 static char language[MAX_LANGUAGE] = ""; 00155 static char musicclass[MAX_MUSICCLASS] = ""; 00156 static char cid_num[AST_MAX_EXTENSION] = ""; 00157 static char cid_name[AST_MAX_EXTENSION] = ""; 00158 00159 static int dtmfmode = 0; 00160 static int nat = 0; 00161 00162 static ast_group_t cur_callergroup = 0; 00163 static ast_group_t cur_pickupgroup = 0; 00164 00165 static int tos = 0; 00166 00167 static int immediate = 0; 00168 00169 static int callwaiting = 0; 00170 00171 static int callreturn = 0; 00172 00173 static int slowsequence = 0; 00174 00175 static int threewaycalling = 0; 00176 00177 /*! This is for flashhook transfers */ 00178 static int transfer = 0; 00179 00180 static int cancallforward = 0; 00181 00182 static int singlepath = 0; 00183 00184 static int canreinvite = CANREINVITE; 00185 00186 static char accountcode[AST_MAX_ACCOUNT_CODE] = ""; 00187 00188 static char mailbox[AST_MAX_EXTENSION]; 00189 00190 static int amaflags = 0; 00191 00192 static int adsi = 0; 00193 00194 static unsigned int oseq; 00195 00196 /*! Wait up to 16 seconds for first digit (FXO logic) */ 00197 static int firstdigittimeout = 16000; 00198 00199 /*! How long to wait for following digits (FXO logic) */ 00200 static int gendigittimeout = 8000; 00201 00202 /*! How long to wait for an extra digit, if there is an ambiguous match */ 00203 static int matchdigittimeout = 3000; 00204 00205 /*! Protect the monitoring thread, so only one process can kill or start it, and not 00206 when it's doing something critical. */ 00207 AST_MUTEX_DEFINE_STATIC(netlock); 00208 00209 AST_MUTEX_DEFINE_STATIC(monlock); 00210 00211 /*! This is the thread for the monitor which checks for input on the channels 00212 which are not currently in use. */ 00213 static pthread_t monitor_thread = AST_PTHREADT_NULL; 00214 00215 static int restart_monitor(void); 00216 00217 static int capability = AST_FORMAT_ULAW; 00218 static int nonCodecCapability = AST_RTP_DTMF; 00219 00220 static char ourhost[MAXHOSTNAMELEN]; 00221 static struct in_addr __ourip; 00222 static int ourport; 00223 00224 static int mgcpdebug = 0; 00225 00226 static struct sched_context *sched; 00227 static struct io_context *io; 00228 /*! The private structures of the mgcp channels are linked for 00229 ! selecting outgoing channels */ 00230 00231 #define MGCP_MAX_HEADERS 64 00232 #define MGCP_MAX_LINES 64 00233 00234 struct mgcp_request { 00235 int len; 00236 char *verb; 00237 char *identifier; 00238 char *endpoint; 00239 char *version; 00240 int headers; /*!< MGCP Headers */ 00241 char *header[MGCP_MAX_HEADERS]; 00242 int lines; /*!< SDP Content */ 00243 char *line[MGCP_MAX_LINES]; 00244 char data[MGCP_MAX_PACKET]; 00245 int cmd; /*!< int version of verb = command */ 00246 unsigned int trid; /*!< int version of identifier = transaction id */ 00247 struct mgcp_request *next; /*!< next in the queue */ 00248 }; 00249 00250 /*! \brief mgcp_message: MGCP message for queuing up */ 00251 struct mgcp_message { 00252 struct mgcp_endpoint *owner_ep; 00253 struct mgcp_subchannel *owner_sub; 00254 int retrans; 00255 unsigned long expire; 00256 unsigned int seqno; 00257 int len; 00258 struct mgcp_message *next; 00259 char buf[0]; 00260 }; 00261 00262 #define RESPONSE_TIMEOUT 30 /*!< in seconds */ 00263 00264 struct mgcp_response { 00265 time_t whensent; 00266 int len; 00267 int seqno; 00268 struct mgcp_response *next; 00269 char buf[0]; 00270 }; 00271 00272 #define MAX_SUBS 2 00273 00274 #define SUB_REAL 0 00275 #define SUB_ALT 1 00276 00277 struct mgcp_subchannel { 00278 /*! subchannel magic string. 00279 Needed to prove that any subchannel pointer passed by asterisk 00280 really points to a valid subchannel memory area. 00281 Ugly.. But serves the purpose for the time being. 00282 */ 00283 #define MGCP_SUBCHANNEL_MAGIC "!978!" 00284 char magic[6]; 00285 ast_mutex_t lock; 00286 int id; 00287 struct ast_channel *owner; 00288 struct mgcp_endpoint *parent; 00289 struct ast_rtp *rtp; 00290 struct sockaddr_in tmpdest; 00291 char txident[80]; /*! \todo FIXME txident is replaced by rqnt_ident in endpoint. 00292 This should be obsoleted */ 00293 char cxident[80]; 00294 char callid[80]; 00295 int cxmode; 00296 struct mgcp_request *cx_queue; /*!< pending CX commands */ 00297 ast_mutex_t cx_queue_lock; /*!< CX queue lock */ 00298 int nat; 00299 int iseq; /*!< Not used? RTP? */ 00300 int outgoing; 00301 int alreadygone; 00302 struct mgcp_subchannel *next; /*!< for out circular linked list */ 00303 }; 00304 00305 #define MGCP_ONHOOK 1 00306 #define MGCP_OFFHOOK 2 00307 00308 #define TYPE_TRUNK 1 00309 #define TYPE_LINE 2 00310 00311 struct mgcp_endpoint { 00312 ast_mutex_t lock; 00313 char name[80]; 00314 struct mgcp_subchannel *sub; /*!< Pointer to our current connection, channel and stuff */ 00315 char accountcode[AST_MAX_ACCOUNT_CODE]; 00316 char exten[AST_MAX_EXTENSION]; /*!< Extention where to start */ 00317 char context[AST_MAX_EXTENSION]; 00318 char language[MAX_LANGUAGE]; 00319 char cid_num[AST_MAX_EXTENSION]; /*!< Caller*ID number */ 00320 char cid_name[AST_MAX_EXTENSION]; /*!< Caller*ID name */ 00321 char lastcallerid[AST_MAX_EXTENSION]; /*!< Last Caller*ID */ 00322 char call_forward[AST_MAX_EXTENSION]; /*!< Last Caller*ID */ 00323 char mailbox[AST_MAX_EXTENSION]; 00324 char musicclass[MAX_MUSICCLASS]; 00325 char curtone[80]; /*!< Current tone */ 00326 ast_group_t callgroup; 00327 ast_group_t pickupgroup; 00328 int callwaiting; 00329 int hascallwaiting; 00330 int transfer; 00331 int threewaycalling; 00332 int singlepath; 00333 int cancallforward; 00334 int canreinvite; 00335 int callreturn; 00336 int dnd; /* How does this affect callwait? Do we just deny a mgcp_request if we're dnd? */ 00337 int hascallerid; 00338 int hidecallerid; 00339 int dtmfmode; 00340 int amaflags; 00341 int type; 00342 int slowsequence; /*!< MS: Sequence the endpoint as a whole */ 00343 int group; 00344 int iseq; /*!< Not used? */ 00345 int lastout; /*!< tracking this on the subchannels. Is it needed here? */ 00346 int needdestroy; /*!< Not used? */ 00347 int capability; 00348 int nonCodecCapability; 00349 int onhooktime; 00350 int msgstate; /*!< voicemail message state */ 00351 int immediate; 00352 int hookstate; 00353 int adsi; 00354 char rqnt_ident[80]; /*!< request identifier */ 00355 struct mgcp_request *rqnt_queue; /*!< pending RQNT commands */ 00356 ast_mutex_t rqnt_queue_lock; 00357 struct mgcp_request *cmd_queue; /*!< pending commands other than RQNT */ 00358 ast_mutex_t cmd_queue_lock; 00359 int delme; /*!< needed for reload */ 00360 int needaudit; /*!< needed for reload */ 00361 struct ast_dsp *dsp; /*!< XXX Should there be a dsp/subchannel? XXX */ 00362 /* owner is tracked on the subchannels, and the *sub indicates whos in charge */ 00363 /* struct ast_channel *owner; */ 00364 /* struct ast_rtp *rtp; */ 00365 /* struct sockaddr_in tmpdest; */ 00366 /* message go the the endpoint and not the channel so they stay here */ 00367 struct mgcp_endpoint *next; 00368 struct mgcp_gateway *parent; 00369 }; 00370 00371 static struct mgcp_gateway { 00372 /* A gateway containing one or more endpoints */ 00373 char name[80]; 00374 int isnamedottedip; /*!< is the name FQDN or dotted ip */ 00375 struct sockaddr_in addr; 00376 struct sockaddr_in defaddr; 00377 struct in_addr ourip; 00378 int dynamic; 00379 int expire; /*!< XXX Should we ever expire dynamic registrations? XXX */ 00380 struct mgcp_endpoint *endpoints; 00381 struct ast_ha *ha; 00382 /* obsolete 00383 time_t lastouttime; 00384 int lastout; 00385 int messagepending; 00386 */ 00387 /* Wildcard endpoint name */ 00388 char wcardep[30]; 00389 struct mgcp_message *msgs; /*!< gw msg queue */ 00390 ast_mutex_t msgs_lock; /*!< queue lock */ 00391 int retransid; /*!< retrans timer id */ 00392 int delme; /*!< needed for reload */ 00393 struct mgcp_response *responses; 00394 struct mgcp_gateway *next; 00395 } *gateways; 00396 00397 AST_MUTEX_DEFINE_STATIC(mgcp_reload_lock); 00398 static int mgcp_reloading = 0; 00399 00400 /*! \brief gatelock: mutex for gateway/endpoint lists */ 00401 AST_MUTEX_DEFINE_STATIC(gatelock); 00402 00403 static int mgcpsock = -1; 00404 00405 static struct sockaddr_in bindaddr; 00406 00407 static struct ast_frame *mgcp_read(struct ast_channel *ast); 00408 static int transmit_response(struct mgcp_subchannel *sub, char *msg, struct mgcp_request *req, char *msgrest); 00409 static int transmit_notify_request(struct mgcp_subchannel *sub, char *tone); 00410 static int transmit_modify_request(struct mgcp_subchannel *sub); 00411 static int transmit_notify_request_with_callerid(struct mgcp_subchannel *sub, char *tone, char *callernum, char *callername); 00412 static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp, int codecs); 00413 static int transmit_connection_del(struct mgcp_subchannel *sub); 00414 static int transmit_audit_endpoint(struct mgcp_endpoint *p); 00415 static void start_rtp(struct mgcp_subchannel *sub); 00416 static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub, 00417 int result, unsigned int ident, struct mgcp_request *resp); 00418 static void dump_cmd_queues(struct mgcp_endpoint *p, struct mgcp_subchannel *sub); 00419 static int mgcp_do_reload(void); 00420 static int mgcp_reload(int fd, int argc, char *argv[]); 00421 00422 static struct ast_channel *mgcp_request(const char *type, int format, void *data, int *cause); 00423 static int mgcp_call(struct ast_channel *ast, char *dest, int timeout); 00424 static int mgcp_hangup(struct ast_channel *ast); 00425 static int mgcp_answer(struct ast_channel *ast); 00426 static struct ast_frame *mgcp_read(struct ast_channel *ast); 00427 static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame); 00428 static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen); 00429 static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); 00430 static int mgcp_senddigit_begin(struct ast_channel *ast, char digit); 00431 static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration); 00432 static int mgcp_devicestate(void *data); 00433 00434 static const struct ast_channel_tech mgcp_tech = { 00435 .type = "MGCP", 00436 .description = tdesc, 00437 .capabilities = AST_FORMAT_ULAW, 00438 .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER, 00439 .requester = mgcp_request, 00440 .devicestate = mgcp_devicestate, 00441 .call = mgcp_call, 00442 .hangup = mgcp_hangup, 00443 .answer = mgcp_answer, 00444 .read = mgcp_read, 00445 .write = mgcp_write, 00446 .indicate = mgcp_indicate, 00447 .fixup = mgcp_fixup, 00448 .send_digit_begin = mgcp_senddigit_begin, 00449 .send_digit_end = mgcp_senddigit_end, 00450 .bridge = ast_rtp_bridge, 00451 }; 00452 00453 static int has_voicemail(struct mgcp_endpoint *p) 00454 { 00455 return ast_app_has_voicemail(p->mailbox, NULL); 00456 } 00457 00458 static int unalloc_sub(struct mgcp_subchannel *sub) 00459 { 00460 struct mgcp_endpoint *p = sub->parent; 00461 if (p->sub == sub) { 00462 ast_log(LOG_WARNING, "Trying to unalloc the real channel %s@%s?!?\n", p->name, p->parent->name); 00463 return -1; 00464 } 00465 if (option_debug) 00466 ast_log(LOG_DEBUG, "Released sub %d of channel %s@%s\n", sub->id, p->name, p->parent->name); 00467 00468 sub->owner = NULL; 00469 if (!ast_strlen_zero(sub->cxident)) { 00470 transmit_connection_del(sub); 00471 } 00472 sub->cxident[0] = '\0'; 00473 sub->callid[0] = '\0'; 00474 sub->cxmode = MGCP_CX_INACTIVE; 00475 sub->outgoing = 0; 00476 sub->alreadygone = 0; 00477 memset(&sub->tmpdest, 0, sizeof(sub->tmpdest)); 00478 if (sub->rtp) { 00479 ast_rtp_destroy(sub->rtp); 00480 sub->rtp = NULL; 00481 } 00482 dump_cmd_queues(NULL, sub); /* SC */ 00483 return 0; 00484 } 00485 00486 /* modified for new transport mechanism */ 00487 static int __mgcp_xmit(struct mgcp_gateway *gw, char *data, int len) 00488 { 00489 int res; 00490 if (gw->addr.sin_addr.s_addr) 00491 res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->addr, sizeof(struct sockaddr_in)); 00492 else 00493 res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->defaddr, sizeof(struct sockaddr_in)); 00494 if (res != len) { 00495 ast_log(LOG_WARNING, "mgcp_xmit returned %d: %s\n", res, strerror(errno)); 00496 } 00497 return res; 00498 } 00499 00500 static int resend_response(struct mgcp_subchannel *sub, struct mgcp_response *resp) 00501 { 00502 struct mgcp_endpoint *p = sub->parent; 00503 int res; 00504 if (mgcpdebug) { 00505 ast_verbose("Retransmitting:\n%s\n to %s:%d\n", resp->buf, ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port)); 00506 } 00507 res = __mgcp_xmit(p->parent, resp->buf, resp->len); 00508 if (res > 0) 00509 res = 0; 00510 return res; 00511 } 00512 00513 static int send_response(struct mgcp_subchannel *sub, struct mgcp_request *req) 00514 { 00515 struct mgcp_endpoint *p = sub->parent; 00516 int res; 00517 if (mgcpdebug) { 00518 ast_verbose("Transmitting:\n%s\n to %s:%d\n", req->data, ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port)); 00519 } 00520 res = __mgcp_xmit(p->parent, req->data, req->len); 00521 if (res > 0) 00522 res = 0; 00523 return res; 00524 } 00525 00526 /* modified for new transport framework */ 00527 static void dump_queue(struct mgcp_gateway *gw, struct mgcp_endpoint *p) 00528 { 00529 struct mgcp_message *cur, *q = NULL, *w, *prev; 00530 00531 ast_mutex_lock(&gw->msgs_lock); 00532 prev = NULL, cur = gw->msgs; 00533 while (cur) { 00534 if (!p || cur->owner_ep == p) { 00535 if (prev) 00536 prev->next = cur->next; 00537 else 00538 gw->msgs = cur->next; 00539 00540 ast_log(LOG_NOTICE, "Removing message from %s transaction %u\n", 00541 gw->name, cur->seqno); 00542 00543 w = cur; 00544 cur = cur->next; 00545 if (q) { 00546 w->next = q; 00547 } else { 00548 w->next = NULL; 00549 } 00550 q = w; 00551 } else { 00552 prev = cur, cur=cur->next; 00553 } 00554 } 00555 ast_mutex_unlock(&gw->msgs_lock); 00556 00557 while (q) { 00558 cur = q; 00559 q = q->next; 00560 free(cur); 00561 } 00562 } 00563 00564 static void mgcp_queue_frame(struct mgcp_subchannel *sub, struct ast_frame *f) 00565 { 00566 for(;;) { 00567 if (sub->owner) { 00568 if (!ast_mutex_trylock(&sub->owner->lock)) { 00569 ast_queue_frame(sub->owner, f); 00570 ast_mutex_unlock(&sub->owner->lock); 00571 break; 00572 } else { 00573 ast_mutex_unlock(&sub->lock); 00574 usleep(1); 00575 ast_mutex_lock(&sub->lock); 00576 } 00577 } else 00578 break; 00579 } 00580 } 00581 00582 static void mgcp_queue_hangup(struct mgcp_subchannel *sub) 00583 { 00584 for(;;) { 00585 if (sub->owner) { 00586 if (!ast_mutex_trylock(&sub->owner->lock)) { 00587 ast_queue_hangup(sub->owner); 00588 ast_mutex_unlock(&sub->owner->lock); 00589 break; 00590 } else { 00591 ast_mutex_unlock(&sub->lock); 00592 usleep(1); 00593 ast_mutex_lock(&sub->lock); 00594 } 00595 } else 00596 break; 00597 } 00598 } 00599 00600 static void mgcp_queue_control(struct mgcp_subchannel *sub, int control) 00601 { 00602 struct ast_frame f = { AST_FRAME_CONTROL, }; 00603 f.subclass = control; 00604 return mgcp_queue_frame(sub, &f); 00605 } 00606 00607 static int retrans_pkt(void *data) 00608 { 00609 struct mgcp_gateway *gw = (struct mgcp_gateway *)data; 00610 struct mgcp_message *cur, *exq = NULL, *w, *prev; 00611 int res = 0; 00612 00613 /* find out expired msgs */ 00614 ast_mutex_lock(&gw->msgs_lock); 00615 00616 prev = NULL, cur = gw->msgs; 00617 while (cur) { 00618 if (cur->retrans < MAX_RETRANS) { 00619 cur->retrans++; 00620 if (mgcpdebug) { 00621 ast_verbose("Retransmitting #%d transaction %u on [%s]\n", 00622 cur->retrans, cur->seqno, gw->name); 00623 } 00624 __mgcp_xmit(gw, cur->buf, cur->len); 00625 00626 prev = cur; 00627 cur = cur->next; 00628 } else { 00629 if (prev) 00630 prev->next = cur->next; 00631 else 00632 gw->msgs = cur->next; 00633 00634 ast_log(LOG_WARNING, "Maximum retries exceeded for transaction %u on [%s]\n", 00635 cur->seqno, gw->name); 00636 00637 w = cur; 00638 cur = cur->next; 00639 00640 if (exq) { 00641 w->next = exq; 00642 } else { 00643 w->next = NULL; 00644 } 00645 exq = w; 00646 } 00647 } 00648 00649 if (!gw->msgs) { 00650 gw->retransid = -1; 00651 res = 0; 00652 } else { 00653 res = 1; 00654 } 00655 ast_mutex_unlock(&gw->msgs_lock); 00656 00657 while (exq) { 00658 cur = exq; 00659 /* time-out transaction */ 00660 handle_response(cur->owner_ep, cur->owner_sub, 406, cur->seqno, NULL); 00661 exq = exq->next; 00662 free(cur); 00663 } 00664 00665 return res; 00666 } 00667 00668 /* modified for the new transaction mechanism */ 00669 static int mgcp_postrequest(struct mgcp_endpoint *p, struct mgcp_subchannel *sub, 00670 char *data, int len, unsigned int seqno) 00671 { 00672 struct mgcp_message *msg = malloc(sizeof(struct mgcp_message) + len); 00673 struct mgcp_message *cur; 00674 struct mgcp_gateway *gw = ((p && p->parent) ? p->parent : NULL); 00675 struct timeval tv; 00676 00677 if (!msg) { 00678 return -1; 00679 } 00680 if (!gw) { 00681 return -1; 00682 } 00683 /* SC 00684 time(&t); 00685 if (gw->messagepending && (gw->lastouttime + 20 < t)) { 00686 ast_log(LOG_NOTICE, "Timeout waiting for response to message:%d, lastouttime: %ld, now: %ld. Dumping pending queue\n", 00687 gw->msgs ? gw->msgs->seqno : -1, (long) gw->lastouttime, (long) t); 00688 dump_queue(sub->parent); 00689 } 00690 */ 00691 msg->owner_sub = sub; 00692 msg->owner_ep = p; 00693 msg->seqno = seqno; 00694 msg->next = NULL; 00695 msg->len = len; 00696 msg->retrans = 0; 00697 memcpy(msg->buf, data, msg->len); 00698 00699 ast_mutex_lock(&gw->msgs_lock); 00700 cur = gw->msgs; 00701 if (cur) { 00702 while(cur->next) 00703 cur = cur->next; 00704 cur->next = msg; 00705 } else { 00706 gw->msgs = msg; 00707 } 00708 00709 if (gettimeofday(&tv, NULL) < 0) { 00710 /* This shouldn't ever happen, but let's be sure */ 00711 ast_log(LOG_NOTICE, "gettimeofday() failed!\n"); 00712 } else { 00713 msg->expire = tv.tv_sec * 1000 + tv.tv_usec / 1000 + DEFAULT_RETRANS; 00714 00715 if (gw->retransid == -1) 00716 gw->retransid = ast_sched_add(sched, DEFAULT_RETRANS, retrans_pkt, (void *)gw); 00717 } 00718 ast_mutex_unlock(&gw->msgs_lock); 00719 /* SC 00720 if (!gw->messagepending) { 00721 gw->messagepending = 1; 00722 gw->lastout = seqno; 00723 gw->lastouttime = t; 00724 */ 00725 __mgcp_xmit(gw, msg->buf, msg->len); 00726 /* XXX Should schedule retransmission XXX */ 00727 /* SC 00728 } else 00729 if (option_debug) 00730 ast_log(LOG_DEBUG, "Deferring transmission of transaction %d\n", seqno); 00731 */ 00732 return 0; 00733 } 00734 00735 /* modified for new transport */ 00736 static int send_request(struct mgcp_endpoint *p, struct mgcp_subchannel *sub, 00737 struct mgcp_request *req, unsigned int seqno) 00738 { 00739 int res = 0; 00740 struct mgcp_request **queue, *q, *r, *t; 00741 ast_mutex_t *l; 00742 00743 if (option_debug) 00744 ast_log(LOG_DEBUG, "Slow sequence is %d\n", p->slowsequence); 00745 if (p->slowsequence) { 00746 queue = &p->cmd_queue; 00747 l = &p->cmd_queue_lock; 00748 ast_mutex_lock(l); 00749 } else { 00750 switch (req->cmd) { 00751 case MGCP_CMD_DLCX: 00752 queue = &sub->cx_queue; 00753 l = &sub->cx_queue_lock; 00754 ast_mutex_lock(l); 00755 q = sub->cx_queue; 00756 /* delete pending cx cmds */ 00757 while (q) { 00758 r = q->next; 00759 free(q); 00760 q = r; 00761 } 00762 *queue = NULL; 00763 break; 00764 00765 case MGCP_CMD_CRCX: 00766 case MGCP_CMD_MDCX: 00767 queue = &sub->cx_queue; 00768 l = &sub->cx_queue_lock; 00769 ast_mutex_lock(l); 00770 break; 00771 00772 case MGCP_CMD_RQNT: 00773 queue = &p->rqnt_queue; 00774 l = &p->rqnt_queue_lock; 00775 ast_mutex_lock(l); 00776 break; 00777 00778 default: 00779 queue = &p->cmd_queue; 00780 l = &p->cmd_queue_lock; 00781 ast_mutex_lock(l); 00782 break; 00783 } 00784 } 00785 00786 r = (struct mgcp_request *) malloc (sizeof(struct mgcp_request)); 00787 if (!r) { 00788 ast_log(LOG_WARNING, "Cannot post MGCP request: insufficient memory\n"); 00789 ast_mutex_unlock(l); 00790 return -1; 00791 } 00792 memcpy(r, req, sizeof(struct mgcp_request)); 00793 00794 if (!(*queue)) { 00795 if (mgcpdebug) { 00796 ast_verbose("Posting Request:\n%s to %s:%d\n", req->data, 00797 ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port)); 00798 } 00799 00800 res = mgcp_postrequest(p, sub, req->data, req->len, seqno); 00801 } else { 00802 if (mgcpdebug) { 00803 ast_verbose("Queueing Request:\n%s to %s:%d\n", req->data, 00804 ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port)); 00805 } 00806 } 00807 00808 /* XXX find tail. We could also keep tail in the data struct for faster access */ 00809 for (t = *queue; t && t->next; t = t->next); 00810 00811 r->next = NULL; 00812 if (t) 00813 t->next = r; 00814 else 00815 *queue = r; 00816 00817 ast_mutex_unlock(l); 00818 00819 return res; 00820 } 00821 00822 static int mgcp_call(struct ast_channel *ast, char *dest, int timeout) 00823 { 00824 int res; 00825 struct mgcp_endpoint *p; 00826 struct mgcp_subchannel *sub; 00827 char tone[50] = ""; 00828 const char *distinctive_ring = NULL; 00829 struct varshead *headp; 00830 struct ast_var_t *current; 00831 00832 if (mgcpdebug) { 00833 ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_call(%s)\n", ast->name); 00834 } 00835 sub = ast->tech_pvt; 00836 p = sub->parent; 00837 headp = &ast->varshead; 00838 AST_LIST_TRAVERSE(headp,current,entries) { 00839 /* Check whether there is an ALERT_INFO variable */ 00840 if (strcasecmp(ast_var_name(current),"ALERT_INFO") == 0) { 00841 distinctive_ring = ast_var_value(current); 00842 } 00843 } 00844 00845 ast_mutex_lock(&sub->lock); 00846 switch (p->hookstate) { 00847 case MGCP_OFFHOOK: 00848 if (!ast_strlen_zero(distinctive_ring)) { 00849 snprintf(tone, sizeof(tone), "L/wt%s", distinctive_ring); 00850 if (mgcpdebug) { 00851 ast_verbose(VERBOSE_PREFIX_3 "MGCP distinctive callwait %s\n", tone); 00852 } 00853 } else { 00854 snprintf(tone, sizeof(tone), "L/wt"); 00855 if (mgcpdebug) { 00856 ast_verbose(VERBOSE_PREFIX_3 "MGCP normal callwait %s\n", tone); 00857 } 00858 } 00859 break; 00860 case MGCP_ONHOOK: 00861 default: 00862 if (!ast_strlen_zero(distinctive_ring)) { 00863 snprintf(tone, sizeof(tone), "L/r%s", distinctive_ring); 00864 if (mgcpdebug) { 00865 ast_verbose(VERBOSE_PREFIX_3 "MGCP distinctive ring %s\n", tone); 00866 } 00867 } else { 00868 snprintf(tone, sizeof(tone), "L/rg"); 00869 if (mgcpdebug) { 00870 ast_verbose(VERBOSE_PREFIX_3 "MGCP default ring\n"); 00871 } 00872 } 00873 break; 00874 } 00875 00876 if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) { 00877 ast_log(LOG_WARNING, "mgcp_call called on %s, neither down nor reserved\n", ast->name); 00878 ast_mutex_unlock(&sub->lock); 00879 return -1; 00880 } 00881 00882 res = 0; 00883 sub->outgoing = 1; 00884 sub->cxmode = MGCP_CX_RECVONLY; 00885 if (p->type == TYPE_LINE) { 00886 if (!sub->rtp) { 00887 start_rtp(sub); 00888 } else { 00889 transmit_modify_request(sub); 00890 } 00891 00892 if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) { 00893 /* try to prevent a callwait from disturbing the other connection */ 00894 sub->next->cxmode = MGCP_CX_RECVONLY; 00895 transmit_modify_request(sub->next); 00896 } 00897 00898 transmit_notify_request_with_callerid(sub, tone, ast->cid.cid_num, ast->cid.cid_name); 00899 ast_setstate(ast, AST_STATE_RINGING); 00900 00901 if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) { 00902 /* Put the connection back in sendrecv */ 00903 sub->next->cxmode = MGCP_CX_SENDRECV; 00904 transmit_modify_request(sub->next); 00905 } 00906 } else { 00907 ast_log(LOG_NOTICE, "Don't know how to dial on trunks yet\n"); 00908 res = -1; 00909 } 00910 ast_mutex_unlock(&sub->lock); 00911 ast_queue_control(ast, AST_CONTROL_RINGING); 00912 return res; 00913 } 00914 00915 static int mgcp_hangup(struct ast_channel *ast) 00916 { 00917 struct mgcp_subchannel *sub = ast->tech_pvt; 00918 struct mgcp_endpoint *p = sub->parent; 00919 00920 if (option_debug) { 00921 ast_log(LOG_DEBUG, "mgcp_hangup(%s)\n", ast->name); 00922 } 00923 if (!ast->tech_pvt) { 00924 if (option_debug) 00925 ast_log(LOG_DEBUG, "Asked to hangup channel not connected\n"); 00926 return 0; 00927 } 00928 if (strcmp(sub->magic, MGCP_SUBCHANNEL_MAGIC)) { 00929 if (option_debug) 00930 ast_log(LOG_DEBUG, "Invalid magic. MGCP subchannel freed up already.\n"); 00931 return 0; 00932 } 00933 ast_mutex_lock(&sub->lock); 00934 if (mgcpdebug) { 00935 ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s\n", ast->name, p->name, p->parent->name); 00936 } 00937 00938 if ((p->dtmfmode & MGCP_DTMF_INBAND) && p->dsp) { 00939 /* check whether other channel is active. */ 00940 if (!sub->next->owner) { 00941 if (p->dtmfmode & MGCP_DTMF_HYBRID) 00942 p->dtmfmode &= ~MGCP_DTMF_INBAND; 00943 if (mgcpdebug) { 00944 ast_verbose(VERBOSE_PREFIX_2 "MGCP free dsp on %s@%s\n", p->name, p->parent->name); 00945 } 00946 ast_dsp_free(p->dsp); 00947 p->dsp = NULL; 00948 } 00949 } 00950 00951 sub->owner = NULL; 00952 if (!ast_strlen_zero(sub->cxident)) { 00953 transmit_connection_del(sub); 00954 } 00955 sub->cxident[0] = '\0'; 00956 if ((sub == p->sub) && sub->next->owner) { 00957 if (p->hookstate == MGCP_OFFHOOK) { 00958 if (sub->next->owner && ast_bridged_channel(sub->next->owner)) { 00959 transmit_notify_request_with_callerid(p->sub, "L/wt", ast_bridged_channel(sub->next->owner)->cid.cid_num, ast_bridged_channel(sub->next->owner)->cid.cid_name); 00960 } 00961 } else { 00962 /* set our other connection as the primary and swith over to it */ 00963 p->sub = sub->next; 00964 p->sub->cxmode = MGCP_CX_RECVONLY; 00965 transmit_modify_request(p->sub); 00966 if (sub->next->owner && ast_bridged_channel(sub->next->owner)) { 00967 transmit_notify_request_with_callerid(p->sub, "L/rg", ast_bridged_channel(sub->next->owner)->cid.cid_num, ast_bridged_channel(sub->next->owner)->cid.cid_name); 00968 } 00969 } 00970 00971 } else if ((sub == p->sub->next) && p->hookstate == MGCP_OFFHOOK) { 00972 transmit_notify_request(sub, "L/v"); 00973 } else if (p->hookstate == MGCP_OFFHOOK) { 00974 transmit_notify_request(sub, "L/ro"); 00975 } else { 00976 transmit_notify_request(sub, ""); 00977 } 00978 00979 ast->tech_pvt = NULL; 00980 sub->alreadygone = 0; 00981 sub->outgoing = 0; 00982 sub->cxmode = MGCP_CX_INACTIVE; 00983 sub->callid[0] = '\0'; 00984 /* Reset temporary destination */ 00985 memset(&sub->tmpdest, 0, sizeof(sub->tmpdest)); 00986 if (sub->rtp) { 00987 ast_rtp_destroy(sub->rtp); 00988 sub->rtp = NULL; 00989 } 00990 00991 ast_module_unref(ast_module_info->self); 00992 00993 if ((p->hookstate == MGCP_ONHOOK) && (!sub->next->rtp)) { 00994 p->hidecallerid = 0; 00995 if (p->hascallwaiting && !p->callwaiting) { 00996 if (option_verbose > 2) 00997 ast_verbose(VERBOSE_PREFIX_3 "Enabling call waiting on %s\n", ast->name); 00998 p->callwaiting = -1; 00999 } 01000 if (has_voicemail(p)) { 01001 if (mgcpdebug) { 01002 ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s set vmwi(+)\n", 01003 ast->name, p->name, p->parent->name); 01004 } 01005 transmit_notify_request(sub, "L/vmwi(+)"); 01006 } else { 01007 if (mgcpdebug) { 01008 ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s set vmwi(-)\n", 01009 ast->name, p->name, p->parent->name); 01010 } 01011 transmit_notify_request(sub, "L/vmwi(-)"); 01012 } 01013 } 01014 ast_mutex_unlock(&sub->lock); 01015 return 0; 01016 } 01017 01018 static int mgcp_show_endpoints(int fd, int argc, char *argv[]) 01019 { 01020 struct mgcp_gateway *g; 01021 struct mgcp_endpoint *e; 01022 int hasendpoints = 0; 01023 01024 if (argc != 3) 01025 return RESULT_SHOWUSAGE; 01026 ast_mutex_lock(&gatelock); 01027 g = gateways; 01028 while(g) { 01029 e = g->endpoints; 01030 ast_cli(fd, "Gateway '%s' at %s (%s)\n", g->name, g->addr.sin_addr.s_addr ? ast_inet_ntoa(g->addr.sin_addr) : ast_inet_ntoa(g->defaddr.sin_addr), g->dynamic ? "Dynamic" : "Static"); 01031 while(e) { 01032 /* Don't show wilcard endpoint */ 01033 if (strcmp(e->name, g->wcardep) !=0) 01034 ast_cli(fd, " -- '%s@%s in '%s' is %s\n", e->name, g->name, e->context, e->sub->owner ? "active" : "idle"); 01035 hasendpoints = 1; 01036 e = e->next; 01037 } 01038 if (!hasendpoints) { 01039 ast_cli(fd, " << No Endpoints Defined >> "); 01040 } 01041 g = g->next; 01042 } 01043 ast_mutex_unlock(&gatelock); 01044 return RESULT_SUCCESS; 01045 } 01046 01047 static const char show_endpoints_usage[] = 01048 "Usage: mgcp show endpoints\n" 01049 " Lists all endpoints known to the MGCP (Media Gateway Control Protocol) subsystem.\n"; 01050 01051 static const char audit_endpoint_usage[] = 01052 "Usage: mgcp audit endpoint <endpointid>\n" 01053 " Lists the capabilities of an endpoint in the MGCP (Media Gateway Control Protocol) subsystem.\n" 01054 " mgcp debug MUST be on to see the results of this command.\n"; 01055 01056 static const char debug_usage[] = 01057 "Usage: mgcp set debug\n" 01058 " Enables dumping of MGCP packets for debugging purposes\n"; 01059 01060 static const char no_debug_usage[] = 01061 "Usage: mgcp set debug off\n" 01062 " Disables dumping of MGCP packets for debugging purposes\n"; 01063 01064 static const char mgcp_reload_usage[] = 01065 "Usage: mgcp reload\n" 01066 " Reloads MGCP configuration from mgcp.conf\n" 01067 " Deprecated: please use 'reload chan_mgcp.so' instead.\n"; 01068 01069 static int mgcp_audit_endpoint(int fd, int argc, char *argv[]) 01070 { 01071 struct mgcp_gateway *g; 01072 struct mgcp_endpoint *e; 01073 int found = 0; 01074 char *ename,*gname, *c; 01075 01076 if (!mgcpdebug) { 01077 return RESULT_SHOWUSAGE; 01078 } 01079 if (argc != 4) 01080 return RESULT_SHOWUSAGE; 01081 /* split the name into parts by null */ 01082 ename = argv[3]; 01083 gname = ename; 01084 while (*gname) { 01085 if (*gname == '@') { 01086 *gname = 0; 01087 gname++; 01088 break; 01089 } 01090 gname++; 01091 } 01092 if (gname[0] == '[') 01093 gname++; 01094 if ((c = strrchr(gname, ']'))) 01095 *c = '\0'; 01096 ast_mutex_lock(&gatelock); 01097 g = gateways; 01098 while(g) { 01099 if (!strcasecmp(g->name, gname)) { 01100 e = g->endpoints; 01101 while(e) { 01102 if (!strcasecmp(e->name, ename)) { 01103 found = 1; 01104 transmit_audit_endpoint(e); 01105 break; 01106 } 01107 e = e->next; 01108 } 01109 if (found) { 01110 break; 01111 } 01112 } 01113 g = g->next; 01114 } 01115 if (!found) { 01116 ast_cli(fd, " << Could not find endpoint >> "); 01117 } 01118 ast_mutex_unlock(&gatelock); 01119 return RESULT_SUCCESS; 01120 } 01121 01122 static int mgcp_do_debug(int fd, int argc, char *argv[]) 01123 { 01124 if (argc != 3) 01125 return RESULT_SHOWUSAGE; 01126 mgcpdebug = 1; 01127 ast_cli(fd, "MGCP Debugging Enabled\n"); 01128 return RESULT_SUCCESS; 01129 } 01130 01131 static int mgcp_no_debug(int fd, int argc, char *argv[]) 01132 { 01133 if (argc != 4) 01134 return RESULT_SHOWUSAGE; 01135 mgcpdebug = 0; 01136 ast_cli(fd, "MGCP Debugging Disabled\n"); 01137 return RESULT_SUCCESS; 01138 } 01139 01140 static struct ast_cli_entry cli_mgcp[] = { 01141 { { "mgcp", "audit", "endpoint", NULL }, 01142 mgcp_audit_endpoint, "Audit specified MGCP endpoint", 01143 audit_endpoint_usage }, 01144 01145 { { "mgcp", "show", "endpoints", NULL }, 01146 mgcp_show_endpoints, "List defined MGCP endpoints", 01147 show_endpoints_usage }, 01148 01149 { { "mgcp", "set", "debug", NULL }, 01150 mgcp_do_debug, "Enable MGCP debugging", 01151 debug_usage }, 01152 01153 { { "mgcp", "set", "debug", "off", NULL }, 01154 mgcp_no_debug, "Disable MGCP debugging", 01155 no_debug_usage }, 01156 01157 { { "mgcp", "reload", NULL }, 01158 mgcp_reload, "Reload MGCP configuration", 01159 mgcp_reload_usage }, 01160 }; 01161 01162 static int mgcp_answer(struct ast_channel *ast) 01163 { 01164 int res = 0; 01165 struct mgcp_subchannel *sub = ast->tech_pvt; 01166 struct mgcp_endpoint *p = sub->parent; 01167 01168 ast_mutex_lock(&sub->lock); 01169 sub->cxmode = MGCP_CX_SENDRECV; 01170 if (!sub->rtp) { 01171 start_rtp(sub); 01172 } else { 01173 transmit_modify_request(sub); 01174 } 01175 /* verbose level check */ 01176 if (option_verbose > 2) { 01177 ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_answer(%s) on %s@%s-%d\n", 01178 ast->name, p->name, p->parent->name, sub->id); 01179 } 01180 if (ast->_state != AST_STATE_UP) { 01181 ast_setstate(ast, AST_STATE_UP); 01182 if (option_debug) 01183 ast_log(LOG_DEBUG, "mgcp_answer(%s)\n", ast->name); 01184 transmit_notify_request(sub, ""); 01185 transmit_modify_request(sub); 01186 } 01187 ast_mutex_unlock(&sub->lock); 01188 return res; 01189 } 01190 01191 static struct ast_frame *mgcp_rtp_read(struct mgcp_subchannel *sub) 01192 { 01193 /* Retrieve audio/etc from channel. Assumes sub->lock is already held. */ 01194 struct ast_frame *f; 01195 01196 f = ast_rtp_read(sub->rtp); 01197 /* Don't send RFC2833 if we're not supposed to */ 01198 if (f && (f->frametype == AST_FRAME_DTMF) && !(sub->parent->dtmfmode & MGCP_DTMF_RFC2833)) 01199 return &ast_null_frame; 01200 if (sub->owner) { 01201 /* We already hold the channel lock */ 01202 if (f->frametype == AST_FRAME_VOICE) { 01203 if (f->subclass != sub->owner->nativeformats) { 01204 if (option_debug) 01205 ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass); 01206 sub->owner->nativeformats = f->subclass; 01207 ast_set_read_format(sub->owner, sub->owner->readformat); 01208 ast_set_write_format(sub->owner, sub->owner->writeformat); 01209 } 01210 /* Courtesy fearnor aka alex@pilosoft.com */ 01211 if ((sub->parent->dtmfmode & MGCP_DTMF_INBAND) && (sub->parent->dsp)) { 01212 #if 0 01213 ast_log(LOG_NOTICE, "MGCP ast_dsp_process\n"); 01214 #endif 01215 f = ast_dsp_process(sub->owner, sub->parent->dsp, f); 01216 } 01217 } 01218 } 01219 return f; 01220 } 01221 01222 01223 static struct ast_frame *mgcp_read(struct ast_channel *ast) 01224 { 01225 struct ast_frame *f; 01226 struct mgcp_subchannel *sub = ast->tech_pvt; 01227 ast_mutex_lock(&sub->lock); 01228 f = mgcp_rtp_read(sub); 01229 ast_mutex_unlock(&sub->lock); 01230 return f; 01231 } 01232 01233 static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame) 01234 { 01235 struct mgcp_subchannel *sub = ast->tech_pvt; 01236 int res = 0; 01237 if (frame->frametype != AST_FRAME_VOICE) { 01238 if (frame->frametype == AST_FRAME_IMAGE) 01239 return 0; 01240 else { 01241 ast_log(LOG_WARNING, "Can't send %d type frames with MGCP write\n", frame->frametype); 01242 return 0; 01243 } 01244 } else { 01245 if (!(frame->subclass & ast->nativeformats)) { 01246 ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n", 01247 frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat); 01248 return -1; 01249 } 01250 } 01251 if (sub) { 01252 ast_mutex_lock(&sub->lock); 01253 if ((sub->parent->sub == sub) || !sub->parent->singlepath) { 01254 if (sub->rtp) { 01255 res = ast_rtp_write(sub->rtp, frame); 01256 } 01257 } 01258 ast_mutex_unlock(&sub->lock); 01259 } 01260 return res; 01261 } 01262 01263 static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) 01264 { 01265 struct mgcp_subchannel *sub = newchan->tech_pvt; 01266 01267 ast_mutex_lock(&sub->lock); 01268 ast_log(LOG_NOTICE, "mgcp_fixup(%s, %s)\n", oldchan->name, newchan->name); 01269 if (sub->owner != oldchan) { 01270 ast_mutex_unlock(&sub->lock); 01271 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner); 01272 return -1; 01273 } 01274 sub->owner = newchan; 01275 ast_mutex_unlock(&sub->lock); 01276 return 0; 01277 } 01278 01279 static int mgcp_senddigit_begin(struct ast_channel *ast, char digit) 01280 { 01281 /* Let asterisk play inband indications */ 01282 return -1; 01283 } 01284 01285 static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration) 01286 { 01287 struct mgcp_subchannel *sub = ast->tech_pvt; 01288 char tmp[4]; 01289 01290 tmp[0] = 'D'; 01291 tmp[1] = '/'; 01292 tmp[2] = digit; 01293 tmp[3] = '\0'; 01294 ast_mutex_lock(&sub->lock); 01295 transmit_notify_request(sub, tmp); 01296 ast_mutex_unlock(&sub->lock); 01297 return -1; /* Return non-zero so that Asterisk will stop the inband indications */ 01298 } 01299 01300 /*! 01301 * \brief mgcp_devicestate: channel callback for device status monitoring 01302 * \param data tech/resource name of MGCP device to query 01303 * 01304 * Callback for device state management in channel subsystem 01305 * to obtain device status (up/down) of a specific MGCP endpoint 01306 * 01307 * \return device status result (from devicestate.h) AST_DEVICE_INVALID (not available) or AST_DEVICE_UNKNOWN (available but unknown state) 01308 */ 01309 static int mgcp_devicestate(void *data) 01310 { 01311 struct mgcp_gateway *g; 01312 struct mgcp_endpoint *e = NULL; 01313 char *tmp, *endpt, *gw; 01314 int ret = AST_DEVICE_INVALID; 01315 01316 endpt = ast_strdupa(data); 01317 if ((tmp = strchr(endpt, '@'))) { 01318 *tmp++ = '\0'; 01319 gw = tmp; 01320 } else 01321 goto error; 01322 01323 ast_mutex_lock(&gatelock); 01324 g = gateways; 01325 while (g) { 01326 if (strcasecmp(g->name, gw) == 0) { 01327 e = g->endpoints; 01328 break; 01329 } 01330 g = g->next; 01331 } 01332 01333 if (!e) 01334 goto error; 01335 01336 while (e) { 01337 if (strcasecmp(e->name, endpt) == 0) 01338 break; 01339 e = e->next; 01340 } 01341 01342 if (!e) 01343 goto error; 01344 01345 /* 01346 * As long as the gateway/endpoint is valid, we'll 01347 * assume that the device is available and its state 01348 * can be tracked. 01349 */ 01350 ret = AST_DEVICE_UNKNOWN; 01351 01352 error: 01353 ast_mutex_unlock(&gatelock); 01354 return ret; 01355 } 01356 01357 static char *control2str(int ind) { 01358 switch (ind) { 01359 case AST_CONTROL_HANGUP: 01360 return "Other end has hungup"; 01361 case AST_CONTROL_RING: 01362 return "Local ring"; 01363 case AST_CONTROL_RINGING: 01364 return "Remote end is ringing"; 01365 case AST_CONTROL_ANSWER: 01366 return "Remote end has answered"; 01367 case AST_CONTROL_BUSY: 01368 return "Remote end is busy"; 01369 case AST_CONTROL_TAKEOFFHOOK: 01370 return "Make it go off hook"; 01371 case AST_CONTROL_OFFHOOK: 01372 return "Line is off hook"; 01373 case AST_CONTROL_CONGESTION: 01374 return "Congestion (circuits busy)"; 01375 case AST_CONTROL_FLASH: 01376 return "Flash hook"; 01377 case AST_CONTROL_WINK: 01378 return "Wink"; 01379 case AST_CONTROL_OPTION: 01380 return "Set a low-level option"; 01381 case AST_CONTROL_RADIO_KEY: 01382 return "Key Radio"; 01383 case AST_CONTROL_RADIO_UNKEY: 01384 return "Un-Key Radio"; 01385 } 01386 return "UNKNOWN"; 01387 } 01388 01389 static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen) 01390 { 01391 struct mgcp_subchannel *sub = ast->tech_pvt; 01392 int res = 0; 01393 01394 if (mgcpdebug) { 01395 ast_verbose(VERBOSE_PREFIX_3 "MGCP asked to indicate %d '%s' condition on channel %s\n", 01396 ind, control2str(ind), ast->name); 01397 } 01398 ast_mutex_lock(&sub->lock); 01399 switch(ind) { 01400 case AST_CONTROL_RINGING: 01401 #ifdef DLINK_BUGGY_FIRMWARE 01402 transmit_notify_request(sub, "rt"); 01403 #else 01404 transmit_notify_request(sub, "G/rt"); 01405 #endif 01406 break; 01407 case AST_CONTROL_BUSY: 01408 transmit_notify_request(sub, "L/bz"); 01409 break; 01410 case AST_CONTROL_CONGESTION: 01411 transmit_notify_request(sub, "G/cg"); 01412 break; 01413 case AST_CONTROL_HOLD: 01414 ast_moh_start(ast, data, NULL); 01415 break; 01416 case AST_CONTROL_UNHOLD: 01417 ast_moh_stop(ast); 01418 break; 01419 case -1: 01420 transmit_notify_request(sub, ""); 01421 break; 01422 default: 01423 ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind); 01424 res = -1; 01425 } 01426 ast_mutex_unlock(&sub->lock); 01427 return res; 01428 } 01429 01430 static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state) 01431 { 01432 struct ast_channel *tmp; 01433 struct mgcp_endpoint *i = sub->parent; 01434 int fmt; 01435 01436 tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id); 01437 if (tmp) { 01438 tmp->tech = &mgcp_tech; 01439 tmp->nativeformats = i->capability; 01440 if (!tmp->nativeformats) 01441 tmp->nativeformats = capability; 01442 fmt = ast_best_codec(tmp->nativeformats); 01443 ast_string_field_build(tmp, name, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id); 01444 if (sub->rtp) 01445 tmp->fds[0] = ast_rtp_fd(sub->rtp); 01446 if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) { 01447 i->dsp = ast_dsp_new(); 01448 ast_dsp_set_features(i->dsp,DSP_FEATURE_DTMF_DETECT); 01449 /* this is to prevent clipping of dtmf tones during dsp processing */ 01450 ast_dsp_digitmode(i->dsp, DSP_DIGITMODE_NOQUELCH); 01451 } else { 01452 i->dsp = NULL; 01453 } 01454 if (state == AST_STATE_RING) 01455 tmp->rings = 1; 01456 tmp->writeformat = fmt; 01457 tmp->rawwriteformat = fmt; 01458 tmp->readformat = fmt; 01459 tmp->rawreadformat = fmt; 01460 tmp->tech_pvt = sub; 01461 if (!ast_strlen_zero(i->language)) 01462 ast_string_field_set(tmp, language, i->language); 01463 if (!ast_strlen_zero(i->accountcode)) 01464 ast_string_field_set(tmp, accountcode, i->accountcode); 01465 if (i->amaflags) 01466 tmp->amaflags = i->amaflags; 01467 sub->owner = tmp; 01468 ast_module_ref(ast_module_info->self); 01469 tmp->callgroup = i->callgroup; 01470 tmp->pickupgroup = i->pickupgroup; 01471 ast_string_field_set(tmp, call_forward, i->call_forward); 01472 ast_copy_string(tmp->context, i->context, sizeof(tmp->context)); 01473 ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten)); 01474 01475 /* Don't use ast_set_callerid() here because it will 01476 * generate a needless NewCallerID event */ 01477 tmp->cid.cid_num = ast_strdup(i->cid_num); 01478 tmp->cid.cid_ani = ast_strdup(i->cid_num); 01479 tmp->cid.cid_name = ast_strdup(i->cid_name); 01480 01481 if (!i->adsi) 01482 tmp->adsicpe = AST_ADSI_UNAVAILABLE; 01483 tmp->priority = 1; 01484 if (sub->rtp) 01485 ast_jb_configure(tmp, &global_jbconf); 01486 if (state != AST_STATE_DOWN) { 01487 if (ast_pbx_start(tmp)) { 01488 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name); 01489 ast_hangup(tmp); 01490 tmp = NULL; 01491 } 01492 } 01493 /* verbose level check */ 01494 if (option_verbose > 2) { 01495 ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_new(%s) created in state: %s\n", 01496 tmp->name, ast_state2str(state)); 01497 } 01498 } else { 01499 ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); 01500 } 01501 return tmp; 01502 } 01503 01504 static char* get_sdp_by_line(char* line, char *name, int nameLen) 01505 { 01506 if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') { 01507 char* r = line + nameLen + 1; 01508 while (*r && (*r < 33)) ++r; 01509 return r; 01510 } 01511 return ""; 01512 } 01513 01514 static char *get_sdp(struct mgcp_request *req, char *name) 01515 { 01516 int x; 01517 int len = strlen(name); 01518 char *r; 01519 01520 for (x=0; x<req->lines; x++) { 01521 r = get_sdp_by_line(req->line[x], name, len); 01522 if (r[0] != '\0') return r; 01523 } 01524 return ""; 01525 } 01526 01527 static void sdpLineNum_iterator_init(int* iterator) 01528 { 01529 *iterator = 0; 01530 } 01531 01532 static char* get_sdp_iterate(int* iterator, struct mgcp_request *req, char *name) 01533 { 01534 int len = strlen(name); 01535 char *r; 01536 while (*iterator < req->lines) { 01537 r = get_sdp_by_line(req->line[(*iterator)++], name, len); 01538 if (r[0] != '\0') return r; 01539 } 01540 return ""; 01541 } 01542 01543 static char *__get_header(struct mgcp_request *req, char *name, int *start) 01544 { 01545 int x; 01546 int len = strlen(name); 01547 char *r; 01548 for (x=*start;x<req->headers;x++) { 01549 if (!strncasecmp(req->header[x], name, len) && 01550 (req->header[x][len] == ':')) { 01551 r = req->header[x] + len + 1; 01552 while(*r && (*r < 33)) 01553 r++; 01554 *start = x+1; 01555 return r; 01556 } 01557 } 01558 /* Don't return NULL, so get_header is always a valid pointer */ 01559 return ""; 01560 } 01561 01562 static char *get_header(struct mgcp_request *req, char *name) 01563 { 01564 int start = 0; 01565 return __get_header(req, name, &start); 01566 } 01567 01568 /*! \brief get_csv: (SC:) get comma separated value */ 01569 static char *get_csv(char *c, int *len, char **next) 01570 { 01571 char *s; 01572 01573 *next = NULL, *len = 0; 01574 if (!c) return NULL; 01575 01576 while (*c && (*c < 33 || *c == ',')) 01577 c++; 01578 01579 s = c; 01580 while (*c && (*c >= 33 && *c != ',')) 01581 c++, (*len)++; 01582 *next = c; 01583 01584 if (*len == 0) 01585 s = NULL, *next = NULL; 01586 01587 return s; 01588 } 01589 01590 static struct mgcp_subchannel *find_subchannel_and_lock(char *name, int msgid, struct sockaddr_in *sin) 01591 { 01592 struct mgcp_endpoint *p = NULL; 01593 struct mgcp_subchannel *sub = NULL; 01594 struct mgcp_gateway *g; 01595 char tmp[256] = ""; 01596 char *at = NULL, *c; 01597 int found = 0; 01598 if (name) { 01599 ast_copy_string(tmp, name, sizeof(tmp)); 01600 at = strchr(tmp, '@'); 01601 if (!at) { 01602 ast_log(LOG_NOTICE, "Endpoint '%s' has no at sign!\n", name); 01603 return NULL; 01604 } 01605 *at++ = '\0'; 01606 } 01607 ast_mutex_lock(&gatelock); 01608 if (at && (at[0] == '[')) { 01609 at++; 01610 c = strrchr(at, ']'); 01611 if (c) 01612 *c = '\0'; 01613 } 01614 g = gateways; 01615 while(g) { 01616 if ((!name || !strcasecmp(g->name, at)) && 01617 (sin || g->addr.sin_addr.s_addr || g->defaddr.sin_addr.s_addr)) { 01618 /* Found the gateway. If it's dynamic, save it's address -- now for the endpoint */ 01619 if (sin && g->dynamic && name) { 01620 if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) || 01621 (g->addr.sin_port != sin->sin_port)) { 01622 memcpy(&g->addr, sin, sizeof(g->addr)); 01623 if (ast_ouraddrfor(&g->addr.sin_addr, &g->ourip)) 01624 memcpy(&g->ourip, &__ourip, sizeof(g->ourip)); 01625 if (option_verbose > 2) 01626 ast_verbose(VERBOSE_PREFIX_3 "Registered MGCP gateway '%s' at %s port %d\n", g->name, ast_inet_ntoa(g->addr.sin_addr), ntohs(g->addr.sin_port)); 01627 } 01628 } 01629 /* not dynamic, check if the name matches */ 01630 else if (name) { 01631 if (strcasecmp(g->name, at)) { 01632 g = g->next; 01633 continue; 01634 } 01635 } 01636 /* not dynamic, no name, check if the addr matches */ 01637 else if (!name && sin) { 01638 if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) || 01639 (g->addr.sin_port != sin->sin_port)) { 01640 g = g->next; 01641 continue; 01642 } 01643 } else { 01644 g = g->next; 01645 continue; 01646 } 01647 /* SC */ 01648 p = g->endpoints; 01649 while(p) { 01650 if (option_debug) 01651 ast_log(LOG_DEBUG, "Searching on %s@%s for subchannel\n", 01652 p->name, g->name); 01653 if (msgid) { 01654 #if 0 /* new transport mech */ 01655 sub = p->sub; 01656 do { 01657 if (option_debug) 01658 ast_log(LOG_DEBUG, "Searching on %s@%s-%d for subchannel with lastout: %d\n", 01659 p->name, g->name, sub->id, msgid); 01660 if (sub->lastout == msgid) { 01661 if (option_debug) 01662 ast_log(LOG_DEBUG, "Found subchannel sub%d to handle request %d sub->lastout: %d\n", 01663 sub->id, msgid, sub->lastout); 01664 found = 1; 01665 break; 01666 } 01667 sub = sub->next; 01668 } while (sub != p->sub); 01669 if (found) { 01670 break; 01671 } 01672 #endif 01673 /* SC */ 01674 sub = p->sub; 01675 found = 1; 01676 /* SC */ 01677 break; 01678 } else if (name && !strcasecmp(p->name, tmp)) { 01679 if (option_debug) 01680 ast_log(LOG_DEBUG, "Coundn't determine subchannel, assuming current master %s@%s-%d\n", 01681 p->name, g->name, p->sub->id); 01682 sub = p->sub; 01683 found = 1; 01684 break; 01685 } 01686 p = p->next; 01687 } 01688 if (sub && found) { 01689 ast_mutex_lock(&sub->lock); 01690 break; 01691 } 01692 } 01693 g = g->next; 01694 } 01695 ast_mutex_unlock(&gatelock); 01696 if (!sub) { 01697 if (name) { 01698 if (g) 01699 ast_log(LOG_NOTICE, "Endpoint '%s' not found on gateway '%s'\n", tmp, at); 01700 else 01701 ast_log(LOG_NOTICE, "Gateway '%s' (and thus its endpoint '%s') does not exist\n", at, tmp); 01702 } 01703 } 01704 return sub; 01705 } 01706 01707 static void parse(struct mgcp_request *req) 01708 { 01709 /* Divide fields by NULL's */ 01710 char *c; 01711 int f = 0; 01712 c = req->data; 01713 01714 /* First header starts immediately */ 01715 req->header[f] = c; 01716 while(*c) { 01717 if (*c == '\n') { 01718 /* We've got a new header */ 01719 *c = 0; 01720 #if 0 01721 printf("Header: %s (%d)\n", req->header[f], strlen(req->header[f])); 01722 #endif 01723 if (ast_strlen_zero(req->header[f])) { 01724 /* Line by itself means we're now in content */ 01725 c++; 01726 break; 01727 } 01728 if (f >= MGCP_MAX_HEADERS - 1) { 01729 ast_log(LOG_WARNING, "Too many MGCP headers...\n"); 01730 } else 01731 f++; 01732 req->header[f] = c + 1; 01733 } else if (*c == '\r') { 01734 /* Ignore but eliminate \r's */ 01735 *c = 0; 01736 } 01737 c++; 01738 } 01739 /* Check for last header */ 01740 if (!ast_strlen_zero(req->header[f])) 01741 f++; 01742 req->headers = f; 01743 /* Now we process any mime content */ 01744 f = 0; 01745 req->line[f] = c; 01746 while(*c) { 01747 if (*c == '\n') { 01748 /* We've got a new line */ 01749 *c = 0; 01750 #if 0 01751 printf("Line: %s (%d)\n", req->line[f], strlen(req->line[f])); 01752 #endif 01753 if (f >= MGCP_MAX_LINES - 1) { 01754 ast_log(LOG_WARNING, "Too many SDP lines...\n"); 01755 } else 01756 f++; 01757 req->line[f] = c + 1; 01758 } else if (*c == '\r') { 01759 /* Ignore and eliminate \r's */ 01760 *c = 0; 01761 } 01762 c++; 01763 } 01764 /* Check for last line */ 01765 if (!ast_strlen_zero(req->line[f])) 01766 f++; 01767 req->lines = f; 01768 /* Parse up the initial header */ 01769 c = req->header[0]; 01770 while(*c && *c < 33) c++; 01771 /* First the verb */ 01772 req->verb = c; 01773 while(*c && (*c > 32)) c++; 01774 if (*c) { 01775 *c = '\0'; 01776 c++; 01777 while(*c && (*c < 33)) c++; 01778 req->identifier = c; 01779 while(*c && (*c > 32)) c++; 01780 if (*c) { 01781 *c = '\0'; 01782 c++; 01783 while(*c && (*c < 33)) c++; 01784 req->endpoint = c; 01785 while(*c && (*c > 32)) c++; 01786 if (*c) { 01787 *c = '\0'; 01788 c++; 01789 while(*c && (*c < 33)) c++; 01790 req->version = c; 01791 while(*c && (*c > 32)) c++; 01792 while(*c && (*c < 33)) c++; 01793 while(*c && (*c > 32)) c++; 01794 *c = '\0'; 01795 } 01796 } 01797 } 01798 01799 if (mgcpdebug) { 01800 ast_verbose("Verb: '%s', Identifier: '%s', Endpoint: '%s', Version: '%s'\n", 01801 req->verb, req->identifier, req->endpoint, req->version); 01802 ast_verbose("%d headers, %d lines\n", req->headers, req->lines); 01803 } 01804 if (*c) 01805 ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c); 01806 } 01807 01808 static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req) 01809 { 01810 char *m; 01811 char *c; 01812 char *a; 01813 char host[258]; 01814 int len; 01815 int portno; 01816 int peercapability, peerNonCodecCapability; 01817 struct sockaddr_in sin; 01818 char *codecs; 01819 struct ast_hostent ahp; struct hostent *hp; 01820 int codec, codec_count=0; 01821 int iterator; 01822 struct mgcp_endpoint *p = sub->parent; 01823 01824 /* Get codec and RTP info from SDP */ 01825 m = get_sdp(req, "m"); 01826 c = get_sdp(req, "c"); 01827 if (ast_strlen_zero(m) || ast_strlen_zero(c)) { 01828 ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s', c = '%s')\n", m, c); 01829 return -1; 01830 } 01831 if (sscanf(c, "IN IP4 %256s", host) != 1) { 01832 ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c); 01833 return -1; 01834 } 01835 /* XXX This could block for a long time, and block the main thread! XXX */ 01836 hp = ast_gethostbyname(host, &ahp); 01837 if (!hp) { 01838 ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c); 01839 return -1; 01840 } 01841 if (sscanf(m, "audio %d RTP/AVP %n", &portno, &len) != 1) { 01842 ast_log(LOG_WARNING, "Unable to determine port number for RTP in '%s'\n", m); 01843 return -1; 01844 } 01845 sin.sin_family = AF_INET; 01846 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr)); 01847 sin.sin_port = htons(portno); 01848 ast_rtp_set_peer(sub->rtp, &sin); 01849 #if 0 01850 printf("Peer RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); 01851 #endif 01852 /* Scan through the RTP payload types specified in a "m=" line: */ 01853 ast_rtp_pt_clear(sub->rtp); 01854 codecs = ast_strdupa(m + len); 01855 while (!ast_strlen_zero(codecs)) { 01856 if (sscanf(codecs, "%d%n", &codec, &len) != 1) { 01857 if (codec_count) 01858 break; 01859 ast_log(LOG_WARNING, "Error in codec string '%s' at '%s'\n", m, codecs); 01860 return -1; 01861 } 01862 ast_rtp_set_m_type(sub->rtp, codec); 01863 codec_count++; 01864 codecs += len; 01865 } 01866 01867 /* Next, scan through each "a=rtpmap:" line, noting each */ 01868 /* specified RTP payload type (with corresponding MIME subtype): */ 01869 sdpLineNum_iterator_init(&iterator); 01870 while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') { 01871 char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */ 01872 if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2) 01873 continue; 01874 /* Note: should really look at the 'freq' and '#chans' params too */ 01875 ast_rtp_set_rtpmap_type(sub->rtp, codec, "audio", mimeSubtype, 0); 01876 } 01877 01878 /* Now gather all of the codecs that were asked for: */ 01879 ast_rtp_get_current_formats(sub->rtp, &peercapability, &peerNonCodecCapability); 01880 p->capability = capability & peercapability; 01881 if (mgcpdebug) { 01882 ast_verbose("Capabilities: us - %d, them - %d, combined - %d\n", 01883 capability, peercapability, p->capability); 01884 ast_verbose("Non-codec capabilities: us - %d, them - %d, combined - %d\n", 01885 nonCodecCapability, peerNonCodecCapability, p->nonCodecCapability); 01886 } 01887 if (!p->capability) { 01888 ast_log(LOG_WARNING, "No compatible codecs!\n"); 01889 return -1; 01890 } 01891 return 0; 01892 } 01893 01894 static int add_header(struct mgcp_request *req, char *var, char *value) 01895 { 01896 if (req->len >= sizeof(req->data) - 4) { 01897 ast_log(LOG_WARNING, "Out of space, can't add anymore\n"); 01898 return -1; 01899 } 01900 if (req->lines) { 01901 ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n"); 01902 return -1; 01903 } 01904 req->header[req->headers] = req->data + req->len; 01905 snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s: %s\r\n", var, value); 01906 req->len += strlen(req->header[req->headers]); 01907 if (req->headers < MGCP_MAX_HEADERS) 01908 req->headers++; 01909 else { 01910 ast_log(LOG_WARNING, "Out of header space\n"); 01911 return -1; 01912 } 01913 return 0; 01914 } 01915 01916 static int add_line(struct mgcp_request *req, char *line) 01917 { 01918 if (req->len >= sizeof(req->data) - 4) { 01919 ast_log(LOG_WARNING, "Out of space, can't add anymore\n"); 01920 return -1; 01921 } 01922 if (!req->lines) { 01923 /* Add extra empty return */ 01924 snprintf(req->data + req->len, sizeof(req->data) - req->len, "\r\n"); 01925 req->len += strlen(req->data + req->len); 01926 } 01927 req->line[req->lines] = req->data + req->len; 01928 snprintf(req->line[req->lines], sizeof(req->data) - req->len, "%s", line); 01929 req->len += strlen(req->line[req->lines]); 01930 if (req->lines < MGCP_MAX_LINES) 01931 req->lines++; 01932 else { 01933 ast_log(LOG_WARNING, "Out of line space\n"); 01934 return -1; 01935 } 01936 return 0; 01937 } 01938 01939 static int init_resp(struct mgcp_request *req, char *resp, struct mgcp_request *orig, char *resprest) 01940 { 01941 /* Initialize a response */ 01942 if (req->headers || req->len) { 01943 ast_log(LOG_WARNING, "Request already initialized?!?\n"); 01944 return -1; 01945 } 01946 req->header[req->headers] = req->data + req->len; 01947 snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %s %s\r\n", resp, orig->identifier, resprest); 01948 req->len += strlen(req->header[req->headers]); 01949 if (req->headers < MGCP_MAX_HEADERS) 01950 req->headers++; 01951 else 01952 ast_log(LOG_WARNING, "Out of header space\n"); 01953 return 0; 01954 } 01955 01956 static int init_req(struct mgcp_endpoint *p, struct mgcp_request *req, char *verb) 01957 { 01958 /* Initialize a response */ 01959 if (req->headers || req->len) { 01960 ast_log(LOG_WARNING, "Request already initialized?!?\n"); 01961 return -1; 01962 } 01963 req->header[req->headers] = req->data + req->len; 01964 /* check if we need brackets around the gw name */ 01965 if (p->parent->isnamedottedip) 01966 snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@[%s] MGCP 1.0\r\n", verb, oseq, p->name, p->parent->name); 01967 else 01968 snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %d %s@%s MGCP 1.0\r\n", verb, oseq, p->name, p->parent->name); 01969 req->len += strlen(req->header[req->headers]); 01970 if (req->headers < MGCP_MAX_HEADERS) 01971 req->headers++; 01972 else 01973 ast_log(LOG_WARNING, "Out of header space\n"); 01974 return 0; 01975 } 01976 01977 01978 static int respprep(struct mgcp_request *resp, struct mgcp_endpoint *p, char *msg, struct mgcp_request *req, char *msgrest) 01979 { 01980 memset(resp, 0, sizeof(*resp)); 01981 init_resp(resp, msg, req, msgrest); 01982 return 0; 01983 } 01984 01985 static int reqprep(struct mgcp_request *req, struct mgcp_endpoint *p, char *verb) 01986 { 01987 memset(req, 0, sizeof(struct mgcp_request)); 01988 oseq++; 01989 if (oseq > 999999999) 01990 oseq = 1; 01991 init_req(p, req, verb); 01992 return 0; 01993 } 01994 01995 static int transmit_response(struct mgcp_subchannel *sub, char *msg, struct mgcp_request *req, char *msgrest) 01996 { 01997 struct mgcp_request resp; 01998 struct mgcp_endpoint *p = sub->parent; 01999 struct mgcp_response *mgr; 02000 02001 respprep(&resp, p, msg, req, msgrest); 02002 mgr = malloc(sizeof(struct mgcp_response) + resp.len + 1); 02003 if (mgr) { 02004 /* Store MGCP response in case we have to retransmit */ 02005 memset(mgr, 0, sizeof(struct mgcp_response)); 02006 sscanf(req->identifier, "%d", &mgr->seqno); 02007 time(&mgr->whensent); 02008 mgr->len = resp.len; 02009 memcpy(mgr->buf, resp.data, resp.len); 02010 mgr->buf[resp.len] = '\0'; 02011 mgr->next = p->parent->responses; 02012 p->parent->responses = mgr; 02013 } 02014 return send_response(sub, &resp); 02015 } 02016 02017 02018 static int add_sdp(struct mgcp_request *resp, struct mgcp_subchannel *sub, struct ast_rtp *rtp) 02019 { 02020 int len; 02021 int codec; 02022 char costr[80]; 02023 struct sockaddr_in sin; 02024 char v[256]; 02025 char s[256]; 02026 char o[256]; 02027 char c[256]; 02028 char t[256]; 02029 char m[256] = ""; 02030 char a[1024] = ""; 02031 int x; 02032 struct sockaddr_in dest; 02033 struct mgcp_endpoint *p = sub->parent; 02034 /* XXX We break with the "recommendation" and send our IP, in order that our 02035 peer doesn't have to ast_gethostbyname() us XXX */ 02036 len = 0; 02037 if (!sub->rtp) { 02038 ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n"); 02039 return -1; 02040 } 02041 ast_rtp_get_us(sub->rtp, &sin); 02042 if (rtp) { 02043 ast_rtp_get_peer(rtp, &dest); 02044 } else { 02045 if (sub->tmpdest.sin_addr.s_addr) { 02046 dest.sin_addr = sub->tmpdest.sin_addr; 02047 dest.sin_port = sub->tmpdest.sin_port; 02048 /* Reset temporary destination */ 02049 memset(&sub->tmpdest, 0, sizeof(sub->tmpdest)); 02050 } else { 02051 dest.sin_addr = p->parent->ourip; 02052 dest.sin_port = sin.sin_port; 02053 } 02054 } 02055 if (mgcpdebug) { 02056 ast_verbose("We're at %s port %d\n", ast_inet_ntoa(p->parent->ourip), ntohs(sin.sin_port)); 02057 } 02058 snprintf(v, sizeof(v), "v=0\r\n"); 02059 snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", getpid(), getpid(), ast_inet_ntoa(dest.sin_addr)); 02060 snprintf(s, sizeof(s), "s=session\r\n"); 02061 snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr)); 02062 snprintf(t, sizeof(t), "t=0 0\r\n"); 02063 snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port)); 02064 for (x = 1; x <= AST_FORMAT_MAX_AUDIO; x <<= 1) { 02065 if (p->capability & x) { 02066 if (mgcpdebug) { 02067 ast_verbose("Answering with capability %d\n", x); 02068 } 02069 codec = ast_rtp_lookup_code(sub->rtp, 1, x); 02070 if (codec > -1) { 02071 snprintf(costr, sizeof(costr), " %d", codec); 02072 strncat(m, costr, sizeof(m) - strlen(m) - 1); 02073 snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(1, x, 0)); 02074 strncat(a, costr, sizeof(a) - strlen(a) - 1); 02075 } 02076 } 02077 } 02078 for (x = 1; x <= AST_RTP_MAX; x <<= 1) { 02079 if (p->nonCodecCapability & x) { 02080 if (mgcpdebug) { 02081 ast_verbose("Answering with non-codec capability %d\n", x); 02082 } 02083 codec = ast_rtp_lookup_code(sub->rtp, 0, x); 02084 if (codec > -1) { 02085 snprintf(costr, sizeof(costr), " %d", codec); 02086 strncat(m, costr, sizeof(m) - strlen(m) - 1); 02087 snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(0, x, 0)); 02088 strncat(a, costr, sizeof(a) - strlen(a) - 1); 02089 if (x == AST_RTP_DTMF) { 02090 /* Indicate we support DTMF... Not sure about 16, 02091 but MSN supports it so dang it, we will too... */ 02092 snprintf(costr, sizeof costr, "a=fmtp:%d 0-16\r\n", codec); 02093 strncat(a, costr, sizeof(a) - strlen(a) - 1); 02094 } 02095 } 02096 } 02097 } 02098 strncat(m, "\r\n", sizeof(m) - strlen(m) - 1); 02099 len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a); 02100 snprintf(costr, sizeof(costr), "%d", len); 02101 add_line(resp, v); 02102 add_line(resp, o); 02103 add_line(resp, s); 02104 add_line(resp, c); 02105 add_line(resp, t); 02106 add_line(resp, m); 02107 add_line(resp, a); 02108 return 0; 02109 } 02110 02111 static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp, int codecs) 02112 { 02113 struct mgcp_request resp; 02114 char local[256]; 02115 char tmp[80]; 02116 int x; 02117 int capability; 02118 struct mgcp_endpoint *p = sub->parent; 02119 02120 capability = p->capability; 02121 if (codecs) 02122 capability = codecs; 02123 if (ast_strlen_zero(sub->cxident) && rtp) { 02124 /* We don't have a CXident yet, store the destination and 02125 wait a bit */ 02126 ast_rtp_get_peer(rtp, &sub->tmpdest); 02127 return 0; 02128 } 02129 snprintf(local, sizeof(local), "p:20"); 02130 for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) { 02131 if (p->capability & x) { 02132 snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0)); 02133 strncat(local, tmp, sizeof(local) - strlen(local) - 1); 02134 } 02135 } 02136 reqprep(&resp, p, "MDCX"); 02137 add_header(&resp, "C", sub->callid); 02138 add_header(&resp, "L", local); 02139 add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]); 02140 /* X header should not be sent. kept for compatibility */ 02141 add_header(&resp, "X", sub->txident); 02142 add_header(&resp, "I", sub->cxident); 02143 /*add_header(&resp, "S", "");*/ 02144 add_sdp(&resp, sub, rtp); 02145 /* fill in new fields */ 02146 resp.cmd = MGCP_CMD_MDCX; 02147 resp.trid = oseq; 02148 return send_request(p, sub, &resp, oseq); /* SC */ 02149 } 02150 02151 static int transmit_connect_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp) 02152 { 02153 struct mgcp_request resp; 02154 char local[256]; 02155 char tmp[80]; 02156 int x; 02157 struct mgcp_endpoint *p = sub->parent; 02158 02159 snprintf(local, sizeof(local), "p:20"); 02160 for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) { 02161 if (p->capability & x) { 02162 snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0)); 02163 strncat(local, tmp, sizeof(local) - strlen(local) - 1); 02164 } 02165 } 02166 if (mgcpdebug) { 02167 ast_verbose(VERBOSE_PREFIX_3 "Creating connection for %s@%s-%d in cxmode: %s callid: %s\n", 02168 p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid); 02169 } 02170 reqprep(&resp, p, "CRCX"); 02171 add_header(&resp, "C", sub->callid); 02172 add_header(&resp, "L", local); 02173 add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]); 02174 /* X header should not be sent. kept for compatibility */ 02175 add_header(&resp, "X", sub->txident); 02176 /*add_header(&resp, "S", "");*/ 02177 add_sdp(&resp, sub, rtp); 02178 /* fill in new fields */ 02179 resp.cmd = MGCP_CMD_CRCX; 02180 resp.trid = oseq; 02181 return send_request(p, sub, &resp, oseq); /* SC */ 02182 } 02183 02184 static int transmit_notify_request(struct mgcp_subchannel *sub, char *tone) 02185 { 02186 struct mgcp_request resp; 02187 struct mgcp_endpoint *p = sub->parent; 02188 02189 if (mgcpdebug) { 02190 ast_verbose(VERBOSE_PREFIX_3 "MGCP Asked to indicate tone: %s on %s@%s-%d in cxmode: %s\n", 02191 tone, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]); 02192 } 02193 ast_copy_string(p->curtone, tone, sizeof(p->curtone)); 02194 reqprep(&resp, p, "RQNT"); 02195 add_header(&resp, "X", p->rqnt_ident); /* SC */ 02196 switch (p->hookstate) { 02197 case MGCP_ONHOOK: 02198 add_header(&resp, "R", "L/hd(N)"); 02199 break; 02200 case MGCP_OFFHOOK: 02201 add_header(&resp, "R", (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N),L/hf(N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)"); 02202 break; 02203 } 02204 if (!ast_strlen_zero(tone)) { 02205 add_header(&resp, "S", tone); 02206 } 02207 /* fill in new fields */ 02208 resp.cmd = MGCP_CMD_RQNT; 02209 resp.trid = oseq; 02210 return send_request(p, NULL, &resp, oseq); /* SC */ 02211 } 02212 02213 static int transmit_notify_request_with_callerid(struct mgcp_subchannel *sub, char *tone, char *callernum, char *callername) 02214 { 02215 struct mgcp_request resp; 02216 char tone2[256]; 02217 char *l, *n; 02218 time_t t; 02219 struct tm tm; 02220 struct mgcp_endpoint *p = sub->parent; 02221 02222 time(&t); 02223 localtime_r(&t,&tm); 02224 n = callername; 02225 l = callernum; 02226 if (!n) 02227 n = ""; 02228 if (!l) 02229 l = ""; 02230 02231 /* Keep track of last callerid for blacklist and callreturn */ 02232 ast_copy_string(p->lastcallerid, l, sizeof(p->lastcallerid)); 02233 02234 snprintf(tone2, sizeof(tone2), "%s,L/ci(%02d/%02d/%02d/%02d,%s,%s)", tone, 02235 tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, l, n); 02236 ast_copy_string(p->curtone, tone, sizeof(p->curtone)); 02237 reqprep(&resp, p, "RQNT"); 02238 add_header(&resp, "X", p->rqnt_ident); /* SC */ 02239 switch (p->hookstate) { 02240 case MGCP_ONHOOK: 02241 add_header(&resp, "R", "L/hd(N)"); 02242 break; 02243 case MGCP_OFFHOOK: 02244 add_header(&resp, "R", (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N),L/hf(N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)"); 02245 break; 02246 } 02247 if (!ast_strlen_zero(tone2)) { 02248 add_header(&resp, "S", tone2); 02249 } 02250 if (mgcpdebug) { 02251 ast_verbose(VERBOSE_PREFIX_3 "MGCP Asked to indicate tone: %s on %s@%s-%d in cxmode: %s\n", 02252 tone2, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]); 02253 } 02254 /* fill in new fields */ 02255 resp.cmd = MGCP_CMD_RQNT; 02256 resp.trid = oseq; 02257 return send_request(p, NULL, &resp, oseq); /* SC */ 02258 } 02259 02260 static int transmit_modify_request(struct mgcp_subchannel *sub) 02261 { 02262 struct mgcp_request resp; 02263 struct mgcp_endpoint *p = sub->parent; 02264 02265 if (ast_strlen_zero(sub->cxident)) { 02266 /* We don't have a CXident yet, store the destination and 02267 wait a bit */ 02268 return 0; 02269 } 02270 if (mgcpdebug) { 02271 ast_verbose(VERBOSE_PREFIX_3 "Modified %s@%s-%d with new mode: %s on callid: %s\n", 02272 p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid); 02273 } 02274 reqprep(&resp, p, "MDCX"); 02275 add_header(&resp, "C", sub->callid); 02276 add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]); 02277 /* X header should not be sent. kept for compatibility */ 02278 add_header(&resp, "X", sub->txident); 02279 add_header(&resp, "I", sub->cxident); 02280 switch (sub->parent->hookstate) { 02281 case MGCP_ONHOOK: 02282 add_header(&resp, "R", "L/hd(N)"); 02283 break; 02284 case MGCP_OFFHOOK: 02285 add_header(&resp, "R", (sub->rtp && (p->dtmfmode & MGCP_DTMF_INBAND)) ? "L/hu(N), L/hf(N)" : "L/hu(N),L/hf(N),D/[0-9#*](N)"); 02286 break; 02287 } 02288 /* fill in new fields */ 02289 resp.cmd = MGCP_CMD_MDCX; 02290 resp.trid = oseq; 02291 return send_request(p, sub, &resp, oseq); /* SC */ 02292 } 02293 02294 02295 static int transmit_audit_endpoint(struct mgcp_endpoint *p) 02296 { 02297 struct mgcp_request resp; 02298 reqprep(&resp, p, "AUEP"); 02299 /* removed unknown param VS */ 02300 /*add_header(&resp, "F", "A,R,D,S,X,N,I,T,O,ES,E,MD,M");*/ 02301 add_header(&resp, "F", "A"); 02302 /* fill in new fields */ 02303 resp.cmd = MGCP_CMD_AUEP; 02304 resp.trid = oseq; 02305 return send_request(p, NULL, &resp, oseq); /* SC */ 02306 } 02307 02308 static int transmit_connection_del(struct mgcp_subchannel *sub) 02309 { 02310 struct mgcp_endpoint *p = sub->parent; 02311 struct mgcp_request resp; 02312 02313 if (mgcpdebug) { 02314 ast_verbose(VERBOSE_PREFIX_3 "Delete connection %s %s@%s-%d with new mode: %s on callid: %s\n", 02315 sub->cxident, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid); 02316 } 02317 reqprep(&resp, p, "DLCX"); 02318 /* check if call id is avail */ 02319 if (sub->callid[0]) 02320 add_header(&resp, "C", sub->callid); 02321 /* X header should not be sent. kept for compatibility */ 02322 add_header(&resp, "X", sub->txident); 02323 /* check if cxident is avail */ 02324 if (sub->cxident[0]) 02325 add_header(&resp, "I", sub->cxident); 02326 /* fill in new fields */ 02327 resp.cmd = MGCP_CMD_DLCX; 02328 resp.trid = oseq; 02329 return send_request(p, sub, &resp, oseq); /* SC */ 02330 } 02331 02332 static int transmit_connection_del_w_params(struct mgcp_endpoint *p, char *callid, char *cxident) 02333 { 02334 struct mgcp_request resp; 02335 02336 if (mgcpdebug) { 02337 ast_verbose(VERBOSE_PREFIX_3 "Delete connection %s %s@%s on callid: %s\n", 02338 cxident ? cxident : "", p->name, p->parent->name, callid ? callid : ""); 02339 } 02340 reqprep(&resp, p, "DLCX"); 02341 /* check if call id is avail */ 02342 if (callid && *callid) 02343 add_header(&resp, "C", callid); 02344 /* check if cxident is avail */ 02345 if (cxident && *cxident) 02346 add_header(&resp, "I", cxident); 02347 /* fill in new fields */ 02348 resp.cmd = MGCP_CMD_DLCX; 02349 resp.trid = oseq; 02350 return send_request(p, p->sub, &resp, oseq); 02351 } 02352 02353 /*! \brief dump_cmd_queues: (SC:) cleanup pending commands */ 02354 static void dump_cmd_queues(struct mgcp_endpoint *p, struct mgcp_subchannel *sub) 02355 { 02356 struct mgcp_request *t, *q; 02357 02358 if (p) { 02359 ast_mutex_lock(&p->rqnt_queue_lock); 02360 for (q = p->rqnt_queue; q; t = q->next, free(q), q=t); 02361 p->rqnt_queue = NULL; 02362 ast_mutex_unlock(&p->rqnt_queue_lock); 02363 02364 ast_mutex_lock(&p->cmd_queue_lock); 02365 for (q = p->cmd_queue; q; t = q->next, free(q), q=t); 02366 p->cmd_queue = NULL; 02367 ast_mutex_unlock(&p->cmd_queue_lock); 02368 02369 ast_mutex_lock(&p->sub->cx_queue_lock); 02370 for (q = p->sub->cx_queue; q; t = q->next, free(q), q=t); 02371 p->sub->cx_queue = NULL; 02372 ast_mutex_unlock(&p->sub->cx_queue_lock); 02373 02374 ast_mutex_lock(&p->sub->next->cx_queue_lock); 02375 for (q = p->sub->next->cx_queue; q; t = q->next, free(q), q=t); 02376 p->sub->next->cx_queue = NULL; 02377 ast_mutex_unlock(&p->sub->next->cx_queue_lock); 02378 } else if (sub) { 02379 ast_mutex_lock(&sub->cx_queue_lock); 02380 for (q = sub->cx_queue; q; t = q->next, free(q), q=t); 02381 sub->cx_queue = NULL; 02382 ast_mutex_unlock(&sub->cx_queue_lock); 02383 } 02384 } 02385 02386 02387 /*! \brief find_command: (SC:) remove command transaction from queue */ 02388 static struct mgcp_request *find_command(struct mgcp_endpoint *p, struct mgcp_subchannel *sub, 02389 struct mgcp_request **queue, ast_mutex_t *l, int ident) 02390 { 02391 struct mgcp_request *prev, *req; 02392 02393 ast_mutex_lock(l); 02394 for (prev = NULL, req = *queue; req; prev = req, req = req->next) { 02395 if (req->trid == ident) { 02396 /* remove from queue */ 02397 if (!prev) 02398 *queue = req->next; 02399 else 02400 prev->next = req->next; 02401 02402 /* send next pending command */ 02403 if (*queue) { 02404 if (mgcpdebug) { 02405 ast_verbose("Posting Queued Request:\n%s to %s:%d\n", (*queue)->data, 02406 ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port)); 02407 } 02408 02409 mgcp_postrequest(p, sub, (*queue)->data, (*queue)->len, (*queue)->trid); 02410 } 02411 break; 02412 } 02413 } 02414 ast_mutex_unlock(l); 02415 return req; 02416 } 02417 02418 /* modified for new transport mechanism */ 02419 static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub, 02420 int result, unsigned int ident, struct mgcp_request *resp) 02421 { 02422 char *c; 02423 struct mgcp_request *req; 02424 struct mgcp_gateway *gw = p->parent; 02425 02426 if (result < 200) { 02427 /* provisional response */ 02428 return; 02429 } 02430 02431 if (p->slowsequence) 02432 req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident); 02433 else if (sub) 02434 req = find_command(p, sub, &sub->cx_queue, &sub->cx_queue_lock, ident); 02435 else if (!(req = find_command(p, sub, &p->rqnt_queue, &p->rqnt_queue_lock, ident))) 02436 req = find_command(p, sub, &p->cmd_queue, &p->cmd_queue_lock, ident); 02437 02438 if (!req) { 02439 if (option_verbose > 2) { 02440 ast_verbose(VERBOSE_PREFIX_3 "No command found on [%s] for transaction %d. Ignoring...\n", 02441 gw->name, ident); 02442 } 02443 return; 02444 } 02445 02446 if (p && (result >= 400) && (result <= 599)) { 02447 switch (result) { 02448 case 401: 02449 p->hookstate = MGCP_OFFHOOK; 02450 break; 02451 case 402: 02452 p->hookstate = MGCP_ONHOOK; 02453 break; 02454 case 406: 02455 ast_log(LOG_NOTICE, "Transaction %d timed out\n", ident); 02456 break; 02457 case 407: 02458 ast_log(LOG_NOTICE, "Transaction %d aborted\n", ident); 02459 break; 02460 } 02461 if (sub) { 02462 if (sub->owner) { 02463 ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n", 02464 result, p->name, p->parent->name, sub ? sub->id:-1); 02465 mgcp_queue_hangup(sub); 02466 } 02467 } else { 02468 if (p->sub->next->owner) { 02469 ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n", 02470 result, p->name, p->parent->name, sub ? sub->id:-1); 02471 mgcp_queue_hangup(p->sub); 02472 } 02473 02474 if (p->sub->owner) { 02475 ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n", 02476 result, p->name, p->parent->name, sub ? sub->id:-1); 02477 mgcp_queue_hangup(p->sub); 02478 } 02479 02480 dump_cmd_queues(p, NULL); 02481 } 02482 } 02483 02484 if (resp) { 02485 if (req->cmd == MGCP_CMD_CRCX) { 02486 if ((c = get_header(resp, "I"))) { 02487 if (!ast_strlen_zero(c) && sub) { 02488 /* if we are hanging up do not process this conn. */ 02489 if (sub->owner) { 02490 if (!ast_strlen_zero(sub->cxident)) { 02491 if (strcasecmp(c, sub->cxident)) { 02492 ast_log(LOG_WARNING, "Subchannel already has a cxident. sub->cxident: %s requested %s\n", sub->cxident, c); 02493 } 02494 } 02495 ast_copy_string(sub->cxident, c, sizeof(sub->cxident)); 02496 if (sub->tmpdest.sin_addr.s_addr) { 02497 transmit_modify_with_sdp(sub, NULL, 0); 02498 } 02499 } else { 02500 /* XXX delete this one 02501 callid and conn id may already be lost. 02502 so the following del conn may have a side effect of 02503 cleaning up the next subchannel */ 02504 transmit_connection_del(sub); 02505 } 02506 } 02507 } 02508 } 02509 02510 if (req->cmd == MGCP_CMD_AUEP) { 02511 /* check stale connection ids */ 02512 if ((c = get_header(resp, "I"))) { 02513 char *v, *n; 02514 int len; 02515 while ((v = get_csv(c, &len, &n))) { 02516 if (len) { 02517 if (strncasecmp(v, p->sub->cxident, len) && 02518 strncasecmp(v, p->sub->next->cxident, len)) { 02519 /* connection id not found. delete it */ 02520 char cxident[80] = ""; 02521 02522 if (len > (sizeof(cxident) - 1)) 02523 len = sizeof(cxident) - 1; 02524 ast_copy_string(cxident, v, len); 02525 if (option_verbose > 2) { 02526 ast_verbose(VERBOSE_PREFIX_3 "Non existing connection id %s on %s@%s \n", 02527 cxident, p->name, gw->name); 02528 } 02529 transmit_connection_del_w_params(p, NULL, cxident); 02530 } 02531 } 02532 c = n; 02533 } 02534 } 02535 02536 /* Try to determine the hookstate returned from an audit endpoint command */ 02537 if ((c = get_header(resp, "ES"))) { 02538 if (!ast_strlen_zero(c)) { 02539 if (strstr(c, "hu")) { 02540 if (p->hookstate != MGCP_ONHOOK) { 02541 /* XXX cleanup if we think we are offhook XXX */ 02542 if ((p->sub->owner || p->sub->next->owner ) && 02543 p->hookstate == MGCP_OFFHOOK) 02544 mgcp_queue_hangup(sub); 02545 p->hookstate = MGCP_ONHOOK; 02546 02547 /* update the requested events according to the new hookstate */ 02548 transmit_notify_request(p->sub, ""); 02549 02550 /* verbose level check */ 02551 if (option_verbose > 2) { 02552 ast_verbose(VERBOSE_PREFIX_3 "Setting hookstate of %s@%s to ONHOOK\n", p->name, gw->name); 02553 } 02554 } 02555 } else if (strstr(c, "hd")) { 02556 if (p->hookstate != MGCP_OFFHOOK) { 02557 p->hookstate = MGCP_OFFHOOK; 02558 02559 /* update the requested events according to the new hookstate */ 02560 transmit_notify_request(p->sub, ""); 02561 02562 /* verbose level check */ 02563 if (option_verbose > 2) { 02564 ast_verbose(VERBOSE_PREFIX_3 "Setting hookstate of %s@%s to OFFHOOK\n", p->name, gw->name); 02565 } 02566 } 02567 } 02568 } 02569 } 02570 } 02571 02572 if (resp && resp->lines) { 02573 /* do not process sdp if we are hanging up. this may be a late response */ 02574 if (sub && sub->owner) { 02575 if (!sub->rtp) 02576 start_rtp(sub); 02577 if (sub->rtp) 02578 process_sdp(sub, resp); 02579 } 02580 } 02581 } 02582 02583 free(req); 02584 } 02585 02586 static void start_rtp(struct mgcp_subchannel *sub) 02587 { 02588 ast_mutex_lock(&sub->lock); 02589 /* check again to be on the safe side */ 02590 if (sub->rtp) { 02591 ast_rtp_destroy(sub->rtp); 02592 sub->rtp = NULL; 02593 } 02594 /* Allocate the RTP now */ 02595 sub->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr); 02596 if (sub->rtp && sub->owner) 02597 sub->owner->fds[0] = ast_rtp_fd(sub->rtp); 02598 if (sub->rtp) 02599 ast_rtp_setnat(sub->rtp, sub->nat); 02600 #if 0 02601 ast_rtp_set_callback(p->rtp, rtpready); 02602 ast_rtp_set_data(p->rtp, p); 02603 #endif 02604 /* Make a call*ID */ 02605 snprintf(sub->callid, sizeof(sub->callid), "%08lx%s", ast_random(), sub->txident); 02606 /* Transmit the connection create */ 02607 transmit_connect_with_sdp(sub, NULL); 02608 ast_mutex_unlock(&sub->lock); 02609 } 02610 02611 static void *mgcp_ss(void *data) 02612 { 02613 struct ast_channel *chan = data; 02614 struct mgcp_subchannel *sub = chan->tech_pvt; 02615 struct mgcp_endpoint *p = sub->parent; 02616 char exten[AST_MAX_EXTENSION] = ""; 02617 int len = 0; 02618 int timeout = firstdigittimeout; 02619 int res; 02620 int getforward = 0; 02621 02622 while(len < AST_MAX_EXTENSION-1) { 02623 res = ast_waitfordigit(chan, timeout); 02624 timeout = 0; 02625 if (res < 0) { 02626 if (option_debug) 02627 ast_log(LOG_DEBUG, "waitfordigit returned < 0...\n"); 02628 /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/ 02629 ast_indicate(chan, -1); 02630 ast_hangup(chan); 02631 return NULL; 02632 } else if (res) { 02633 exten[len++]=res; 02634 exten[len] = '\0'; 02635 } 02636 if (!ast_ignore_pattern(chan->context, exten)) { 02637 /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/ 02638 ast_indicate(chan, -1); 02639 } else { 02640 /* XXX Redundant? We should already be playing dialtone */ 02641 /*tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALTONE);*/ 02642 transmit_notify_request(sub, "L/dl"); 02643 } 02644 if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num)) { 02645 if (!res || !ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) { 02646 if (getforward) { 02647 /* Record this as the forwarding extension */ 02648 ast_copy_string(p->call_forward, exten, sizeof(p->call_forward)); 02649 if (option_verbose > 2) { 02650 ast_verbose(VERBOSE_PREFIX_3 "Setting call forward to '%s' on channel %s\n", 02651 p->call_forward, chan->name); 02652 } 02653 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/ 02654 transmit_notify_request(sub, "L/sl"); 02655 if (res) 02656 break; 02657 usleep(500000); 02658 /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/ 02659 ast_indicate(chan, -1); 02660 sleep(1); 02661 memset(exten, 0, sizeof(exten)); 02662 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALTONE);*/ 02663 transmit_notify_request(sub, "L/dl"); 02664 len = 0; 02665 getforward = 0; 02666 } else { 02667 /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/ 02668 ast_indicate(chan, -1); 02669 ast_copy_string(chan->exten, exten, sizeof(chan->exten)); 02670 ast_set_callerid(chan, 02671 p->hidecallerid ? "" : p->cid_num, 02672 p->hidecallerid ? "" : p->cid_name, 02673 chan->cid.cid_ani ? NULL : p->cid_num); 02674 ast_setstate(chan, AST_STATE_RING); 02675 /*zt_enable_ec(p);*/ 02676 if (p->dtmfmode & MGCP_DTMF_HYBRID) { 02677 p->dtmfmode |= MGCP_DTMF_INBAND; 02678 ast_indicate(chan, -1); 02679 } 02680 res = ast_pbx_run(chan); 02681 if (res) { 02682 ast_log(LOG_WARNING, "PBX exited non-zero\n"); 02683 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);*/ 02684 /*transmit_notify_request(p, "nbz", 1);*/ 02685 transmit_notify_request(sub, "G/cg"); 02686 } 02687 return NULL; 02688 } 02689 } else { 02690 /* It's a match, but they just typed a digit, and there is an ambiguous match, 02691 so just set the timeout to matchdigittimeout and wait some more */ 02692 timeout = matchdigittimeout; 02693 } 02694 } else if (res == 0) { 02695 if (option_debug) 02696 ast_log(LOG_DEBUG, "not enough digits (and no ambiguous match)...\n"); 02697 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);*/ 02698 transmit_notify_request(sub, "G/cg"); 02699 /*zt_wait_event(p->subs[index].zfd);*/ 02700 ast_hangup(chan); 02701 return NULL; 02702 } else if (p->hascallwaiting && p->callwaiting && !strcmp(exten, "*70")) { 02703 if (option_verbose > 2) { 02704 ast_verbose(VERBOSE_PREFIX_3 "Disabling call waiting on %s\n", chan->name); 02705 } 02706 /* Disable call waiting if enabled */ 02707 p->callwaiting = 0; 02708 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/ 02709 transmit_notify_request(sub, "L/sl"); 02710 len = 0; 02711 memset(exten, 0, sizeof(exten)); 02712 timeout = firstdigittimeout; 02713 } else if (!strcmp(exten,ast_pickup_ext())) { 02714 /* Scan all channels and see if any there 02715 * ringing channqels with that have call groups 02716 * that equal this channels pickup group 02717 */ 02718 if (ast_pickup_call(chan)) { 02719 ast_log(LOG_WARNING, "No call pickup possible...\n"); 02720 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);*/ 02721 transmit_notify_request(sub, "G/cg"); 02722 } 02723 ast_hangup(chan); 02724 return NULL; 02725 } else if (!p->hidecallerid && !strcmp(exten, "*67")) { 02726 if (option_verbose > 2) { 02727 ast_verbose(VERBOSE_PREFIX_3 "Disabling Caller*ID on %s\n", chan->name); 02728 } 02729 /* Disable Caller*ID if enabled */ 02730 p->hidecallerid = 1; 02731 ast_set_callerid(chan, "", "", NULL); 02732 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/ 02733 transmit_notify_request(sub, "L/sl"); 02734 len = 0; 02735 memset(exten, 0, sizeof(exten)); 02736 timeout = firstdigittimeout; 02737 } else if (p->callreturn && !strcmp(exten, "*69")) { 02738 res = 0; 02739 if (!ast_strlen_zero(p->lastcallerid)) { 02740 res = ast_say_digit_str(chan, p->lastcallerid, "", chan->language); 02741 } 02742 if (!res) 02743 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/ 02744 transmit_notify_request(sub, "L/sl"); 02745 break; 02746 } else if (!strcmp(exten, "*78")) { 02747 /* Do not disturb */ 02748 if (option_verbose > 2) { 02749 ast_verbose(VERBOSE_PREFIX_3 "Enabled DND on channel %s\n", chan->name); 02750 } 02751 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/ 02752 transmit_notify_request(sub, "L/sl"); 02753 p->dnd = 1; 02754 getforward = 0; 02755 memset(exten, 0, sizeof(exten)); 02756 len = 0; 02757 } else if (!strcmp(exten, "*79")) { 02758 /* Do not disturb */ 02759 if (option_verbose > 2) { 02760 ast_verbose(VERBOSE_PREFIX_3 "Disabled DND on channel %s\n", chan->name); 02761 } 02762 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/ 02763 transmit_notify_request(sub, "L/sl"); 02764 p->dnd = 0; 02765 getforward = 0; 02766 memset(exten, 0, sizeof(exten)); 02767 len = 0; 02768 } else if (p->cancallforward && !strcmp(exten, "*72")) { 02769 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/ 02770 transmit_notify_request(sub, "L/sl"); 02771 getforward = 1; 02772 memset(exten, 0, sizeof(exten)); 02773 len = 0; 02774 } else if (p->cancallforward && !strcmp(exten, "*73")) { 02775 if (option_verbose > 2) { 02776 ast_verbose(VERBOSE_PREFIX_3 "Cancelling call forwarding on channel %s\n", chan->name); 02777 } 02778 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/ 02779 transmit_notify_request(sub, "L/sl"); 02780 memset(p->call_forward, 0, sizeof(p->call_forward)); 02781 getforward = 0; 02782 memset(exten, 0, sizeof(exten)); 02783 len = 0; 02784 } else if (!strcmp(exten, ast_parking_ext()) && 02785 sub->next->owner && ast_bridged_channel(sub->next->owner)) { 02786 /* This is a three way call, the main call being a real channel, 02787 and we're parking the first call. */ 02788 ast_masq_park_call(ast_bridged_channel(sub->next->owner), chan, 0, NULL); 02789 if (option_verbose > 2) { 02790 ast_verbose(VERBOSE_PREFIX_3 "Parking call to '%s'\n", chan->name); 02791 } 02792 break; 02793 } else if (!ast_strlen_zero(p->lastcallerid) && !strcmp(exten, "*60")) { 02794 if (option_verbose > 2) { 02795 ast_verbose(VERBOSE_PREFIX_3 "Blacklisting number %s\n", p->lastcallerid); 02796 } 02797 res = ast_db_put("blacklist", p->lastcallerid, "1"); 02798 if (!res) { 02799 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/ 02800 transmit_notify_request(sub, "L/sl"); 02801 memset(exten, 0, sizeof(exten)); 02802 len = 0; 02803 } 02804 } else if (p->hidecallerid && !strcmp(exten, "*82")) { 02805 if (option_verbose > 2) { 02806 ast_verbose(VERBOSE_PREFIX_3 "Enabling Caller*ID on %s\n", chan->name); 02807 } 02808 /* Enable Caller*ID if enabled */ 02809 p->hidecallerid = 0; 02810 ast_set_callerid(chan, p->cid_num, p->cid_name, NULL); 02811 /*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALRECALL);*/ 02812 transmit_notify_request(sub, "L/sl"); 02813 len = 0; 02814 memset(exten, 0, sizeof(exten)); 02815 timeout = firstdigittimeout; 02816 } else if (!ast_canmatch_extension(chan, chan->context, exten, 1, chan->cid.cid_num) && 02817 ((exten[0] != '*') || (strlen(exten) > 2))) { 02818 if (option_debug) 02819 ast_log(LOG_DEBUG, "Can't match %s from '%s' in context %s\n", exten, chan->cid.cid_num ? chan->cid.cid_num : "<Unknown Caller>", chan->context); 02820 break; 02821 } 02822 if (!timeout) 02823 timeout = gendigittimeout; 02824 if (len && !ast_ignore_pattern(chan->context, exten)) 02825 /*tone_zone_play_tone(p->subs[index].zfd, -1);*/ 02826 ast_indicate(chan, -1); 02827 } 02828 #if 0 02829 for (;;) { 02830 res = ast_waitfordigit(chan, to); 02831 if (!res) { 02832 if (option_debug) 02833 ast_log(LOG_DEBUG, "Timeout...\n"); 02834 break; 02835 } 02836 if (res < 0) { 02837 if (option_debug) 02838 ast_log(LOG_DEBUG, "Got hangup...\n"); 02839 ast_hangup(chan); 02840 break; 02841 } 02842 exten[pos++] = res; 02843 if (!ast_ignore_pattern(chan->context, exten)) 02844 ast_indicate(chan, -1); 02845 if (ast_matchmore_extension(chan, chan->context, exten, 1, chan->callerid)) { 02846 if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid)) 02847 to = 3000; 02848 else 02849 to = 8000; 02850 } else 02851 break; 02852 } 02853 if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid)) { 02854 ast_copy_string(chan->exten, exten, sizeof(chan->exten)1); 02855 if (!p->rtp) { 02856 start_rtp(p); 02857 } 02858 ast_setstate(chan, AST_STATE_RING); 02859 chan->rings = 1; 02860 if (ast_pbx_run(chan)) { 02861 ast_log(LOG_WARNING, "Unable to launch PBX on %s\n", chan->name); 02862 } else 02863 return NULL; 02864 } 02865 #endif 02866 ast_hangup(chan); 02867 return NULL; 02868 } 02869 02870 static int attempt_transfer(struct mgcp_endpoint *p) 02871 { 02872 /* ************************* 02873 * I hope this works. 02874 * Copied out of chan_zap 02875 * Cross your fingers 02876 * *************************/ 02877 02878 /* In order to transfer, we need at least one of the channels to 02879 actually be in a call bridge. We can't conference two applications 02880 together (but then, why would we want to?) */ 02881 if (ast_bridged_channel(p->sub->owner)) { 02882 /* The three-way person we're about to transfer to could still be in MOH, so 02883 stop if now if appropriate */ 02884 if (ast_bridged_channel(p->sub->next->owner)) 02885 ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD); 02886 if (p->sub->owner->_state == AST_STATE_RINGING) { 02887 ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING); 02888 } 02889 if (ast_channel_masquerade(p->sub->next->owner, ast_bridged_channel(p->sub->owner))) { 02890 ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n", 02891 ast_bridged_channel(p->sub->owner)->name, p->sub->next->owner->name); 02892 return -1; 02893 } 02894 /* Orphan the channel */ 02895 unalloc_sub(p->sub->next); 02896 } else if (ast_bridged_channel(p->sub->next->owner)) { 02897 if (p->sub->owner->_state == AST_STATE_RINGING) { 02898 ast_indicate(ast_bridged_channel(p->sub->next->owner), AST_CONTROL_RINGING); 02899 } 02900 ast_queue_control(p->sub->next->owner, AST_CONTROL_UNHOLD); 02901 if (ast_channel_masquerade(p->sub->owner, ast_bridged_channel(p->sub->next->owner))) { 02902 ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n", 02903 ast_bridged_channel(p->sub->next->owner)->name, p->sub->owner->name); 02904 return -1; 02905 } 02906 /*swap_subs(p, SUB_THREEWAY, SUB_REAL);*/ 02907 if (option_verbose > 2) { 02908 ast_verbose(VERBOSE_PREFIX_3 "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name); 02909 } 02910 p->sub = p->sub->next; 02911 unalloc_sub(p->sub->next); 02912 /* Tell the caller not to hangup */ 02913 return 1; 02914 } else { 02915 if (option_debug) 02916 ast_log(LOG_DEBUG, "Neither %s nor %s are in a bridge, nothing to transfer\n", 02917 p->sub->owner->name, p->sub->next->owner->name); 02918 p->sub->next->owner->_softhangup |= AST_SOFTHANGUP_DEV; 02919 if (p->sub->next->owner) { 02920 p->sub->next->alreadygone = 1; 02921 mgcp_queue_hangup(p->sub->next); 02922 } 02923 } 02924 return 0; 02925 } 02926 02927 static void handle_hd_hf(struct mgcp_subchannel *sub, char *ev) 02928 { 02929 struct mgcp_endpoint *p = sub->parent; 02930 struct ast_channel *c; 02931 pthread_t t; 02932 pthread_attr_t attr; 02933 pthread_attr_init(&attr); 02934 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 02935 02936 /* Off hook / answer */ 02937 if (sub->outgoing) { 02938 /* Answered */ 02939 if (sub->owner) { 02940 if (ast_bridged_channel(sub->owner)) 02941 ast_queue_control(sub->owner, AST_CONTROL_UNHOLD); 02942 sub->cxmode = MGCP_CX_SENDRECV; 02943 if (!sub->rtp) { 02944 start_rtp(sub); 02945 } else { 02946 transmit_modify_request(sub); 02947 } 02948 /*transmit_notify_request(sub, "aw");*/ 02949 transmit_notify_request(sub, ""); 02950 mgcp_queue_control(sub, AST_CONTROL_ANSWER); 02951 } 02952 } else { 02953 /* Start switch */ 02954 /*sub->cxmode = MGCP_CX_SENDRECV;*/ 02955 if (!sub->owner) { 02956 if (!sub->rtp) { 02957 start_rtp(sub); 02958 } else { 02959 transmit_modify_request(sub); 02960 } 02961 if (p->immediate) { 02962 /* The channel is immediately up. Start right away */ 02963 #ifdef DLINK_BUGGY_FIRMWARE 02964 transmit_notify_request(sub, "rt"); 02965 #else 02966 transmit_notify_request(sub, "G/rt"); 02967 #endif 02968 c = mgcp_new(sub, AST_STATE_RING); 02969 if (!c) { 02970 ast_log(LOG_WARNING, "Unable to start PBX on channel %s@%s\n", p->name, p->parent->name); 02971 transmit_notify_request(sub, "G/cg"); 02972 ast_hangup(c); 02973 } 02974 } else { 02975 if (has_voicemail(p)) { 02976 transmit_notify_request(sub, "L/sl"); 02977 } else { 02978 transmit_notify_request(sub, "L/dl"); 02979 } 02980 c = mgcp_new(sub, AST_STATE_DOWN); 02981 if (c) { 02982 if (ast_pthread_create(&t, &attr, mgcp_ss, c)) { 02983 ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno)); 02984 ast_hangup(c); 02985 } 02986 } else { 02987 ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", p->name, p->parent->name); 02988 } 02989 } 02990 } else { 02991 if (p->hookstate == MGCP_OFFHOOK) { 02992 ast_log(LOG_WARNING, "Off hook, but already have owner on %s@%s\n", p->name, p->parent->name); 02993 } else { 02994 ast_log(LOG_WARNING, "On hook, but already have owner on %s@%s\n", p->name, p->parent->name); 02995 ast_log(LOG_WARNING, "If we're onhook why are we here trying to handle a hd or hf?\n"); 02996 } 02997 if (ast_bridged_channel(sub->owner)) 02998 ast_queue_control(sub->owner, AST_CONTROL_UNHOLD); 02999 sub->cxmode = MGCP_CX_SENDRECV; 03000 if (!sub->rtp) { 03001 start_rtp(sub); 03002 } else { 03003 transmit_modify_request(sub); 03004 } 03005 /*transmit_notify_request(sub, "aw");*/ 03006 transmit_notify_request(sub, ""); 03007 /*ast_queue_control(sub->owner, AST_CONTROL_ANSWER);*/ 03008 } 03009 } 03010 } 03011 03012 static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req, struct sockaddr_in *sin) 03013 { 03014 char *ev, *s; 03015 struct ast_frame f = { 0, }; 03016 struct mgcp_endpoint *p = sub->parent; 03017 struct mgcp_gateway *g = NULL; 03018 int res; 03019 03020 if (mgcpdebug) { 03021 ast_verbose("Handling request '%s' on %s@%s\n", req->verb, p->name, p->parent->name); 03022 } 03023 /* Clear out potential response */ 03024 if (!strcasecmp(req->verb, "RSIP")) { 03025 /* Test if this RSIP request is just a keepalive */ 03026 if(!strcasecmp( get_header(req, "RM"), "X-keepalive")) { 03027 if (option_verbose > 2) 03028 ast_verbose(VERBOSE_PREFIX_3 "Received keepalive request from %s@%s\n", p->name, p->parent->name); 03029 transmit_response(sub, "200", req, "OK"); 03030 } else { 03031 dump_queue(p->parent, p); 03032 dump_cmd_queues(p, NULL); 03033 03034 if (option_verbose > 2 && (strcmp(p->name, p->parent->wcardep) != 0)) { 03035 ast_verbose(VERBOSE_PREFIX_3 "Resetting interface %s@%s\n", p->name, p->parent->name); 03036 } 03037 /* For RSIP on wildcard we reset all endpoints */ 03038 if (!strcmp(p->name, p->parent->wcardep)) { 03039 /* Reset all endpoints */ 03040 struct mgcp_endpoint *tmp_ep; 03041 03042 g = p->parent; 03043 tmp_ep = g->endpoints; 03044 while (tmp_ep) { 03045 /*if ((strcmp(tmp_ep->name, "*") != 0) && (strcmp(tmp_ep->name, "aaln/" "*") != 0)) {*/ 03046 if (strcmp(tmp_ep->name, g->wcardep) != 0) { 03047 struct mgcp_subchannel *tmp_sub, *first_sub; 03048 if (option_verbose > 2) { 03049 ast_verbose(VERBOSE_PREFIX_3 "Resetting interface %s@%s\n", tmp_ep->name, p->parent->name); 03050 } 03051 03052 first_sub = tmp_ep->sub; 03053 tmp_sub = tmp_ep->sub; 03054 while (tmp_sub) { 03055 mgcp_queue_hangup(tmp_sub); 03056 tmp_sub = tmp_sub->next; 03057 if (tmp_sub == first_sub) 03058 break; 03059 } 03060 } 03061 tmp_ep = tmp_ep->next; 03062 } 03063 } else if (sub->owner) { 03064 mgcp_queue_hangup(sub); 03065 } 03066 transmit_response(sub, "200", req, "OK"); 03067 /* We dont send NTFY or AUEP to wildcard ep */ 03068 if (strcmp(p->name, p->parent->wcardep) != 0) { 03069 transmit_notify_request(sub, ""); 03070 /* Audit endpoint. 03071 Idea is to prevent lost lines due to race conditions 03072 */ 03073 transmit_audit_endpoint(p); 03074 } 03075 } 03076 } else if (!strcasecmp(req->verb, "NTFY")) { 03077 /* Acknowledge and be sure we keep looking for the same things */ 03078 transmit_response(sub, "200", req, "OK"); 03079 /* Notified of an event */ 03080 ev = get_header(req, "O"); 03081 s = strchr(ev, '/'); 03082 if (s) ev = s + 1; 03083 if (option_debug) 03084 ast_log(LOG_DEBUG, "Endpoint '%s@%s-%d' observed '%s'\n", p->name, p->parent->name, sub->id, ev); 03085 /* Keep looking for events unless this was a hangup */ 03086 if (strcasecmp(ev, "hu") && strcasecmp(ev, "hd") && strcasecmp(ev, "ping")) { 03087 transmit_notify_request(sub, p->curtone); 03088 } 03089 if (!strcasecmp(ev, "hd")) { 03090 p->hookstate = MGCP_OFFHOOK; 03091 sub->cxmode = MGCP_CX_SENDRECV; 03092 handle_hd_hf(sub, ev); 03093 } else if (!strcasecmp(ev, "hf")) { 03094 /* We can assume we are offhook if we received a hookflash */ 03095 /* First let's just do call wait and ignore threeway */ 03096 /* We're currently in charge */ 03097 if (p->hookstate != MGCP_OFFHOOK) { 03098 /* Cisco c7940 sends hf even if the phone is onhook */ 03099 /* Thanks to point on IRC for pointing this out */ 03100 return -1; 03101 } 03102 /* do not let * conference two down channels */ 03103 if (sub->owner && sub->owner->_state == AST_STATE_DOWN && !sub->next->owner) 03104 return -1; 03105 03106 if (p->callwaiting || p->transfer || p->threewaycalling) { 03107 if (option_verbose > 2) { 03108 ast_verbose(VERBOSE_PREFIX_3 "Swapping %d for %d on %s@%s\n", p->sub->id, p->sub->next->id, p->name, p->parent->name); 03109 } 03110 p->sub = p->sub->next; 03111 03112 /* transfer control to our next subchannel */ 03113 if (!sub->next->owner) { 03114 /* plave the first call on hold and start up a new call */ 03115 sub->cxmode = MGCP_CX_MUTE; 03116 if (option_verbose > 2) { 03117 ast_verbose(VERBOSE_PREFIX_3 "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name); 03118 } 03119 transmit_modify_request(sub); 03120 if (sub->owner && ast_bridged_channel(sub->owner)) 03121 ast_queue_control(sub->owner, AST_CONTROL_HOLD); 03122 sub->next->cxmode = MGCP_CX_RECVONLY; 03123 handle_hd_hf(sub->next, ev); 03124 } else if (sub->owner && sub->next->owner) { 03125 /* We've got two active calls lets decide whether or not to conference or just flip flop */ 03126 if ((!sub->outgoing) && (!sub->next->outgoing)) { 03127 /* We made both calls lets conferenct */ 03128 if (option_verbose > 2) { 03129 ast_verbose(VERBOSE_PREFIX_3 "MGCP Conferencing %d and %d on %s@%s\n", 03130 sub->id, sub->next->id, p->name, p->parent->name); 03131 } 03132 sub->cxmode = MGCP_CX_CONF; 03133 sub->next->cxmode = MGCP_CX_CONF; 03134 if (ast_bridged_channel(sub->next->owner)) 03135 ast_queue_control(sub->next->owner, AST_CONTROL_UNHOLD); 03136 transmit_modify_request(sub); 03137 transmit_modify_request(sub->next); 03138 } else { 03139 /* Let's flipflop between calls */ 03140 /* XXX Need to check for state up ??? */ 03141 /* XXX Need a way to indicate the current call, or maybe the call that's waiting */ 03142 if (option_verbose > 2) { 03143 ast_verbose(VERBOSE_PREFIX_3 "We didn't make one of the calls FLIPFLOP %d and %d on %s@%s\n", 03144 sub->id, sub->next->id, p->name, p->parent->name); 03145 } 03146 sub->cxmode = MGCP_CX_MUTE; 03147 if (option_verbose > 2) { 03148 ast_verbose(VERBOSE_PREFIX_3 "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name); 03149 } 03150 transmit_modify_request(sub); 03151 if (ast_bridged_channel(sub->owner)) 03152 ast_queue_control(sub->owner, AST_CONTROL_HOLD); 03153 03154 if (ast_bridged_channel(sub->next->owner)) 03155 ast_queue_control(sub->next->owner, AST_CONTROL_HOLD); 03156 03157 handle_hd_hf(sub->next, ev); 03158 } 03159 } else { 03160 /* We've most likely lost one of our calls find an active call and bring it up */ 03161 if (sub->owner) { 03162 p->sub = sub; 03163 } else if (sub->next->owner) { 03164 p->sub = sub->next; 03165 } else { 03166 /* We seem to have lost both our calls */ 03167 /* XXX - What do we do now? */ 03168 return -1; 03169 } 03170 if (ast_bridged_channel(p->sub->owner)) 03171 ast_queue_control(p->sub->owner, AST_CONTROL_UNHOLD); 03172 p->sub->cxmode = MGCP_CX_SENDRECV; 03173 transmit_modify_request(p->sub); 03174 } 03175 } else { 03176