Index: chan_mgcp.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_mgcp.c,v retrieving revision 1.79.2.5 diff -u -r1.79.2.5 chan_mgcp.c --- chan_mgcp.c 26 Oct 2004 15:34:30 -0000 1.79.2.5 +++ chan_mgcp.c 26 Nov 2004 09:53:48 -0000 @@ -570,6 +570,53 @@ } } +static void mgcp_queue_frame(struct mgcp_subchannel *sub, struct ast_frame *f) +{ + int i = 0; + for(;;) { + if (sub->owner) { + if (!ast_mutex_trylock(&sub->owner->lock)) { + ast_queue_frame(sub->owner, f); + ast_mutex_unlock(&sub->owner->lock); + break; + } else { + ast_log(LOG_ERROR, "Unable to aquire lock (n=%d)\n", ++i); + ast_mutex_unlock(&sub->lock); + usleep(1); + ast_mutex_lock(&sub->lock); + } + } else + break; + } +} + +static void mgcp_queue_hangup(struct mgcp_subchannel *sub) +{ + int i = 0; + for(;;) { + if (sub->owner) { + if (!ast_mutex_trylock(&sub->owner->lock)) { + ast_queue_hangup(sub->owner); + ast_mutex_unlock(&sub->owner->lock); + break; + } else { + ast_log(LOG_ERROR, "Unable to aquire lock (n=%d)\n", ++i); + ast_mutex_unlock(&sub->lock); + usleep(1); + ast_mutex_lock(&sub->lock); + } + } else + break; + } +} + +static void mgcp_queue_control(struct mgcp_subchannel *sub, int control) +{ + struct ast_frame f = { AST_FRAME_CONTROL, }; + f.subclass = control; + return mgcp_queue_frame(sub, &f); +} + static int retrans_pkt(void *data) { struct mgcp_gateway *gw = (struct mgcp_gateway *)data; @@ -808,7 +855,7 @@ } sub = ast->pvt->pvt; p = sub->parent; - + ast_mutex_lock(&sub->lock); switch (p->hookstate) { case MGCP_OFFHOOK: tone = "L/wt"; @@ -821,6 +868,7 @@ if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) { ast_log(LOG_WARNING, "mgcp_call called on %s, neither down nor reserved\n", ast->name); + ast_mutex_unlock(&sub->lock); return -1; } @@ -842,7 +890,6 @@ transmit_notify_request_with_callerid(sub, tone, ast->callerid); ast_setstate(ast, AST_STATE_RINGING); - ast_queue_control(ast, AST_CONTROL_RINGING); if (sub->next->owner && strlen(sub->next->cxident) && strlen(sub->next->callid)) { /* Put the connection back in sendrecv */ @@ -854,6 +901,8 @@ ast_log(LOG_NOTICE, "Don't know how to dial on trunks yet\n"); res = -1; } + ast_mutex_unlock(&sub->lock); + ast_queue_control(ast, AST_CONTROL_RINGING); return res; } @@ -862,60 +911,61 @@ struct mgcp_subchannel *sub = ast->pvt->pvt; struct mgcp_endpoint *p = sub->parent; - if (option_debug) + if (option_debug) { ast_log(LOG_DEBUG, "mgcp_hangup(%s)\n", ast->name); + } if (!ast->pvt->pvt) { ast_log(LOG_DEBUG, "Asked to hangup channel not connected\n"); return 0; } - if (strcmp(sub->magic, MGCP_SUBCHANNEL_MAGIC)) { + ast_mutex_lock(&sub->lock); + if (strcmp(sub->magic, MGCP_SUBCHANNEL_MAGIC)) { ast_log(LOG_DEBUG, "Invalid magic. MGCP subchannel freed up already.\n"); + ast_mutex_unlock(&sub->lock); return 0; - } - if (mgcpdebug) { - ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s\n", ast->name, p->name, p->parent->name); - } + } + if (mgcpdebug) { + ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s\n", ast->name, p->name, p->parent->name); + } - if ((p->dtmfmode & MGCP_DTMF_INBAND) && (p->dsp != NULL)){ - /* SC: check whether other channel is active. */ - if (!sub->next->owner) - { - if (mgcpdebug) { - ast_verbose(VERBOSE_PREFIX_2 "MGCP free dsp on %s@%s\n", p->name, p->parent->name); - } - ast_dsp_free(p->dsp); - p->dsp = NULL; - } - } - ast_mutex_lock(&sub->lock); + if ((p->dtmfmode & MGCP_DTMF_INBAND) && p->dsp) { + /* SC: check whether other channel is active. */ + if (!sub->next->owner) { + if (mgcpdebug) { + ast_verbose(VERBOSE_PREFIX_2 "MGCP free dsp on %s@%s\n", p->name, p->parent->name); + } + ast_dsp_free(p->dsp); + p->dsp = NULL; + } + } sub->owner = NULL; if (strlen(sub->cxident)) { transmit_connection_del(sub); - } - sub->cxident[0] = '\0'; - if ((sub == p->sub) && sub->next->owner) { - if (p->hookstate == MGCP_OFFHOOK) { - if (sub->next->owner && sub->next->owner->bridge) { - transmit_notify_request_with_callerid(p->sub, "L/wt", sub->next->owner->bridge->callerid); - } - } else { - /* set our other connection as the primary and swith over to it */ - p->sub = sub->next; - p->sub->cxmode = MGCP_CX_RECVONLY; - transmit_modify_request(p->sub); - if (sub->next->owner && sub->next->owner->bridge) { - transmit_notify_request_with_callerid(p->sub, "L/rg", sub->next->owner->callerid); - } - } + } + sub->cxident[0] = '\0'; + if ((sub == p->sub) && sub->next->owner) { + if (p->hookstate == MGCP_OFFHOOK) { + if (sub->next->owner && sub->next->owner->bridge) { + transmit_notify_request_with_callerid(p->sub, "L/wt", sub->next->owner->bridge->callerid); + } + } else { + /* set our other connection as the primary and swith over to it */ + p->sub = sub->next; + p->sub->cxmode = MGCP_CX_RECVONLY; + transmit_modify_request(p->sub); + if (sub->next->owner && sub->next->owner->bridge) { + transmit_notify_request_with_callerid(p->sub, "L/rg", sub->next->owner->callerid); + } + } - } else if ((sub == p->sub->next) && p->hookstate == MGCP_OFFHOOK) { - transmit_notify_request(sub, "L/v"); - } else if (p->hookstate == MGCP_OFFHOOK) { - transmit_notify_request(sub, "L/ro"); - } else { - transmit_notify_request(sub, ""); - } + } else if ((sub == p->sub->next) && p->hookstate == MGCP_OFFHOOK) { + transmit_notify_request(sub, "L/v"); + } else if (p->hookstate == MGCP_OFFHOOK) { + transmit_notify_request(sub, "L/ro"); + } else { + transmit_notify_request(sub, ""); + } ast->pvt->pvt = NULL; sub->alreadygone = 0; @@ -930,25 +980,25 @@ } /* SC: Decrement use count */ - ast_mutex_lock(&usecnt_lock); + ast_mutex_lock(&usecnt_lock); usecnt--; ast_mutex_unlock(&usecnt_lock); ast_update_use_count(); - /* SC: Decrement use count */ + /* SC: Decrement use count */ - if ((p->hookstate == MGCP_ONHOOK) && (!sub->next->rtp)) { - if (has_voicemail(p)) { - if (mgcpdebug) { - ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s set vmwi(+)\n", ast->name, p->name, p->parent->name); - } - transmit_notify_request(sub, "L/vmwi(+)"); - } else { - if (mgcpdebug) { - ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s set vmwi(-)\n", ast->name, p->name, p->parent->name); - } - transmit_notify_request(sub, "L/vmwi(-)"); - } - } + if ((p->hookstate == MGCP_ONHOOK) && (!sub->next->rtp)) { + if (has_voicemail(p)) { + if (mgcpdebug) { + ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s set vmwi(+)\n", ast->name, p->name, p->parent->name); + } + transmit_notify_request(sub, "L/vmwi(+)"); + } else { + if (mgcpdebug) { + ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s set vmwi(-)\n", ast->name, p->name, p->parent->name); + } + transmit_notify_request(sub, "L/vmwi(-)"); + } + } ast_mutex_unlock(&sub->lock); return 0; } @@ -1054,6 +1104,7 @@ int res = 0; struct mgcp_subchannel *sub = ast->pvt->pvt; struct mgcp_endpoint *p = sub->parent; + ast_mutex_lock(&sub->lock); sub->cxmode = MGCP_CX_SENDRECV; if (!sub->rtp) { start_rtp(sub); @@ -1071,6 +1122,7 @@ transmit_notify_request(sub, ""); transmit_modify_request(sub); } + ast_mutex_unlock(&sub->lock); return res; } @@ -1148,12 +1200,15 @@ static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) { struct mgcp_subchannel *sub = newchan->pvt->pvt; - ast_log(LOG_NOTICE, "mgcp_fixup(%s, %s)\n", oldchan->name, newchan->name); + ast_mutex_lock(&sub->lock); + ast_log(LOG_NOTICE, "mgcp_fixup(%s, %s)\n", oldchan->name, newchan->name); if (sub->owner != oldchan) { + ast_mutex_unlock(&sub->lock); ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner); return -1; } sub->owner = newchan; + ast_mutex_unlock(&sub->lock); return 0; } @@ -1165,7 +1220,9 @@ tmp[1] = '/'; tmp[2] = digit; tmp[3] = '\0'; + ast_mutex_lock(&sub->lock); transmit_notify_request(sub, tmp); + ast_mutex_unlock(&sub->lock); return -1; } @@ -1205,9 +1262,11 @@ static int mgcp_indicate(struct ast_channel *ast, int ind) { struct mgcp_subchannel *sub = ast->pvt->pvt; + int res = 0; if (mgcpdebug) { ast_verbose(VERBOSE_PREFIX_3 "MGCP asked to indicate %d '%s' condition on channel %s\n", ind, control2str(ind), ast->name); } + ast_mutex_lock(&sub->lock); switch(ind) { case AST_CONTROL_RINGING: #ifdef DLINK_BUGGY_FIRMWARE @@ -1227,17 +1286,18 @@ break; default: ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind); - return -1; + res = -1; } - return 0; + ast_mutex_unlock(&sub->lock); + return res; } static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state) { struct ast_channel *tmp; - struct mgcp_endpoint *i = sub->parent; + struct mgcp_endpoint *i = sub->parent; int fmt; - i = sub->parent; + i = sub->parent; tmp = ast_channel_alloc(1); if (tmp) { tmp->nativeformats = i->capability; @@ -1311,7 +1371,8 @@ return tmp; } -static char* get_sdp_by_line(char* line, char *name, int nameLen) { +static char* get_sdp_by_line(char* line, char *name, int nameLen) +{ if (strncasecmp(line, name, nameLen) == 0 && line[nameLen] == '=') { char* r = line + nameLen + 1; while (*r && (*r < 33)) ++r; @@ -1321,7 +1382,8 @@ return ""; } -static char *get_sdp(struct mgcp_request *req, char *name) { +static char *get_sdp(struct mgcp_request *req, char *name) +{ int x; int len = strlen(name); char *r; @@ -1333,12 +1395,13 @@ return ""; } -static void sdpLineNum_iterator_init(int* iterator) { +static void sdpLineNum_iterator_init(int* iterator) +{ *iterator = 0; } -static char* get_sdp_iterate(int* iterator, - struct mgcp_request *req, char *name) { +static char* get_sdp_iterate(int* iterator, struct mgcp_request *req, char *name) +{ int len = strlen(name); char *r; while (*iterator < req->lines) { @@ -1395,7 +1458,7 @@ return s; } -static struct mgcp_subchannel *find_subchannel(char *name, int msgid, struct sockaddr_in *sin) +static struct mgcp_subchannel *find_subchannel_and_lock(char *name, int msgid, struct sockaddr_in *sin) { struct mgcp_endpoint *p = NULL; struct mgcp_subchannel *sub = NULL; @@ -1403,7 +1466,7 @@ char iabuf[INET_ADDRSTRLEN]; char tmp[256] = ""; char *at = NULL, *c; - int found = 0; + int found = 0; if (name) { strncpy(tmp, name, sizeof(tmp) - 1); at = strchr(tmp, '@'); @@ -1493,6 +1556,7 @@ p = p->next; } if (sub && found) { + ast_mutex_lock(&sub->lock); break; } } @@ -1626,7 +1690,7 @@ struct ast_hostent ahp; struct hostent *hp; int codec; int iterator; - struct mgcp_endpoint *p = sub->parent; + struct mgcp_endpoint *p = sub->parent; /* Get codec and RTP info from SDP */ m = get_sdp(req, "m"); @@ -1657,7 +1721,7 @@ printf("Peer RTP is at port %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port)); #endif // Scan through the RTP payload types specified in a "m=" line: - ast_rtp_pt_clear(sub->rtp); + ast_rtp_pt_clear(sub->rtp); codecs = m + len; while(strlen(codecs)) { if (sscanf(codecs, "%d %n", &codec, &len) != 1) { @@ -1694,7 +1758,6 @@ return -1; } return 0; - } static int add_header(struct mgcp_request *req, char *var, char *value) @@ -1710,9 +1773,9 @@ req->header[req->headers] = req->data + req->len; snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s: %s\r\n", var, value); req->len += strlen(req->header[req->headers]); - if (req->headers < MGCP_MAX_HEADERS) + if (req->headers < MGCP_MAX_HEADERS) { req->headers++; - else { + } else { ast_log(LOG_WARNING, "Out of header space\n"); return -1; } @@ -1733,9 +1796,9 @@ req->line[req->lines] = req->data + req->len; snprintf(req->line[req->lines], sizeof(req->data) - req->len, "%s", line); req->len += strlen(req->line[req->lines]); - if (req->lines < MGCP_MAX_LINES) + if (req->lines < MGCP_MAX_LINES) { req->lines++; - else { + } else { ast_log(LOG_WARNING, "Out of line space\n"); return -1; } @@ -1801,7 +1864,7 @@ static int transmit_response(struct mgcp_subchannel *sub, char *msg, struct mgcp_request *req, char *msgrest) { struct mgcp_request resp; - struct mgcp_endpoint *p = sub->parent; + struct mgcp_endpoint *p = sub->parent; struct mgcp_response *mgr; respprep(&resp, p, msg, req, msgrest); mgr = malloc(sizeof(struct mgcp_response) + resp.len + 1); @@ -1836,7 +1899,7 @@ char iabuf[INET_ADDRSTRLEN]; int x; struct sockaddr_in dest; - struct mgcp_endpoint *p = sub->parent; + struct mgcp_endpoint *p = sub->parent; /* XXX We break with the "recommendation" and send our IP, in order that our peer doesn't have to ast_gethostbyname() us XXX */ len = 0; @@ -1860,7 +1923,7 @@ } if (mgcpdebug) { ast_verbose("We're at %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->parent->ourip), ntohs(sin.sin_port)); - } + } snprintf(v, sizeof(v), "v=0\r\n"); snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", getpid(), getpid(), ast_inet_ntoa(iabuf, sizeof(iabuf), dest.sin_addr)); snprintf(s, sizeof(s), "s=session\r\n"); @@ -1920,7 +1983,7 @@ char tmp[80]; int x; int capability; - struct mgcp_endpoint *p = sub->parent; + struct mgcp_endpoint *p = sub->parent; capability = p->capability; if (codecs) capability = codecs; @@ -1941,15 +2004,15 @@ add_header(&resp, "C", sub->callid); add_header(&resp, "L", local); add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]); - /* SC: X header should not be sent. kept for compatibility */ + /* SC: X header should not be sent. kept for compatibility */ add_header(&resp, "X", sub->txident); add_header(&resp, "I", sub->cxident); /*add_header(&resp, "S", "");*/ ast_rtp_offered_from_local(sub->rtp, 0); add_sdp(&resp, sub, rtp); - /* SC: fill in new fields */ - resp.cmd = MGCP_CMD_MDCX; - resp.trid = oseq; + /* SC: fill in new fields */ + resp.cmd = MGCP_CMD_MDCX; + resp.trid = oseq; return send_request(p, sub, &resp, oseq); /* SC */ } @@ -1959,7 +2022,7 @@ char local[256]; char tmp[80]; int x; - struct mgcp_endpoint *p = sub->parent; + struct mgcp_endpoint *p = sub->parent; snprintf(local, sizeof(local), "p:20"); for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) { @@ -1968,22 +2031,22 @@ strncat(local, tmp, sizeof(local) - strlen(local) - 1); } } - if (mgcpdebug) { - ast_verbose(VERBOSE_PREFIX_3 "Creating connection for %s@%s-%d in cxmode: %s callid: %s\n", - p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid); - } + if (mgcpdebug) { + ast_verbose(VERBOSE_PREFIX_3 "Creating connection for %s@%s-%d in cxmode: %s callid: %s\n", + p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid); + } reqprep(&resp, p, "CRCX"); add_header(&resp, "C", sub->callid); add_header(&resp, "L", local); add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]); - /* SC: X header should not be sent. kept for compatibility */ + /* SC: X header should not be sent. kept for compatibility */ add_header(&resp, "X", sub->txident); /*add_header(&resp, "S", "");*/ ast_rtp_offered_from_local(sub->rtp, 1); add_sdp(&resp, sub, rtp); - /* SC: fill in new fields */ - resp.cmd = MGCP_CMD_CRCX; - resp.trid = oseq; + /* SC: fill in new fields */ + resp.cmd = MGCP_CMD_CRCX; + resp.trid = oseq; return send_request(p, sub, &resp, oseq); /* SC */ } @@ -2024,7 +2087,7 @@ char *l, *n; time_t t; struct tm tm; - struct mgcp_endpoint *p = sub->parent; + struct mgcp_endpoint *p = sub->parent; time(&t); localtime_r(&t,&tm); @@ -2045,65 +2108,65 @@ if (!l) l = ""; - /* Keep track of last callerid for blacklist and callreturn */ - strncpy(p->lastcallerid, l, sizeof(p->lastcallerid) - 1); + /* Keep track of last callerid for blacklist and callreturn */ + strncpy(p->lastcallerid, l, sizeof(p->lastcallerid) - 1); snprintf(tone2, sizeof(tone2), "%s,L/ci(%02d/%02d/%02d/%02d,%s,%s)", tone, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, l, n); strncpy(p->curtone, tone, sizeof(p->curtone) - 1); reqprep(&resp, p, "RQNT"); add_header(&resp, "X", p->rqnt_ident); /* SC */ - switch (p->hookstate) { - case MGCP_ONHOOK: - add_header(&resp, "R", "L/hd(N)"); - break; - case MGCP_OFFHOOK: - 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)"); - break; - } - if (strlen(tone2)) { - add_header(&resp, "S", tone2); - } - if (mgcpdebug) { - ast_verbose(VERBOSE_PREFIX_3 "MGCP Asked to indicate tone: %s on %s@%s-%d in cxmode: %s\n", - tone2, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]); - } - /* SC: fill in new fields */ - resp.cmd = MGCP_CMD_RQNT; - resp.trid = oseq; + switch (p->hookstate) { + case MGCP_ONHOOK: + add_header(&resp, "R", "L/hd(N)"); + break; + case MGCP_OFFHOOK: + 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)"); + break; + } + if (strlen(tone2)) { + add_header(&resp, "S", tone2); + } + if (mgcpdebug) { + ast_verbose(VERBOSE_PREFIX_3 "MGCP Asked to indicate tone: %s on %s@%s-%d in cxmode: %s\n", + tone2, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]); + } + /* SC: fill in new fields */ + resp.cmd = MGCP_CMD_RQNT; + resp.trid = oseq; return send_request(p, NULL, &resp, oseq); /* SC */ } static int transmit_modify_request(struct mgcp_subchannel *sub) { struct mgcp_request resp; - struct mgcp_endpoint *p = sub->parent; + struct mgcp_endpoint *p = sub->parent; if (!strlen(sub->cxident)) { /* We don't have a CXident yet, store the destination and wait a bit */ return 0; } - if (mgcpdebug) { - ast_verbose(VERBOSE_PREFIX_3 "Modified %s@%s-%d with new mode: %s on callid: %s\n", - p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid); - } + if (mgcpdebug) { + ast_verbose(VERBOSE_PREFIX_3 "Modified %s@%s-%d with new mode: %s on callid: %s\n", + p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid); + } reqprep(&resp, p, "MDCX"); add_header(&resp, "C", sub->callid); add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]); - /* SC: X header should not be sent. kept for compatibility */ + /* SC: X header should not be sent. kept for compatibility */ add_header(&resp, "X", sub->txident); add_header(&resp, "I", sub->cxident); - switch (sub->parent->hookstate) { + switch (sub->parent->hookstate) { case MGCP_ONHOOK: add_header(&resp, "R", "L/hd(N)"); break; - case MGCP_OFFHOOK: + case MGCP_OFFHOOK: 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)"); break; - } - /* SC: fill in new fields */ - resp.cmd = MGCP_CMD_MDCX; - resp.trid = oseq; + } + /* SC: fill in new fields */ + resp.cmd = MGCP_CMD_MDCX; + resp.trid = oseq; return send_request(p, sub, &resp, oseq); /* SC */ } @@ -2112,55 +2175,55 @@ { struct mgcp_request resp; reqprep(&resp, p, "AUEP"); - /* SC: removed unknown param VS */ + /* SC: removed unknown param VS */ //add_header(&resp, "F", "A,R,D,S,X,N,I,T,O,ES,E,MD,M"); add_header(&resp, "F", "A"); - /* SC: fill in new fields */ - resp.cmd = MGCP_CMD_AUEP; - resp.trid = oseq; + /* SC: fill in new fields */ + resp.cmd = MGCP_CMD_AUEP; + resp.trid = oseq; return send_request(p, NULL, &resp, oseq); /* SC */ } static int transmit_connection_del(struct mgcp_subchannel *sub) { - struct mgcp_endpoint *p = sub->parent; + struct mgcp_endpoint *p = sub->parent; struct mgcp_request resp; - if (mgcpdebug) { - ast_verbose(VERBOSE_PREFIX_3 "Delete connection %s %s@%s-%d with new mode: %s on callid: %s\n", - sub->cxident, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid); - } + if (mgcpdebug) { + ast_verbose(VERBOSE_PREFIX_3 "Delete connection %s %s@%s-%d with new mode: %s on callid: %s\n", + sub->cxident, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode], sub->callid); + } reqprep(&resp, p, "DLCX"); - /* SC: check if call id is avail */ - if (sub->callid[0]) - add_header(&resp, "C", sub->callid); - /* SC: X header should not be sent. kept for compatibility */ + /* SC: check if call id is avail */ + if (sub->callid[0]) + add_header(&resp, "C", sub->callid); + /* SC: X header should not be sent. kept for compatibility */ add_header(&resp, "X", sub->txident); - /* SC: check if cxident is avail */ - if (sub->cxident[0]) - add_header(&resp, "I", sub->cxident); - /* SC: fill in new fields */ - resp.cmd = MGCP_CMD_DLCX; - resp.trid = oseq; + /* SC: check if cxident is avail */ + if (sub->cxident[0]) + add_header(&resp, "I", sub->cxident); + /* SC: fill in new fields */ + resp.cmd = MGCP_CMD_DLCX; + resp.trid = oseq; return send_request(p, sub, &resp, oseq); /* SC */ } static int transmit_connection_del_w_params(struct mgcp_endpoint *p, char *callid, char *cxident) { struct mgcp_request resp; - if (mgcpdebug) { - ast_verbose(VERBOSE_PREFIX_3 "Delete connection %s %s@%s on callid: %s\n", - cxident ? cxident : "", p->name, p->parent->name, callid ? callid : ""); - } + if (mgcpdebug) { + ast_verbose(VERBOSE_PREFIX_3 "Delete connection %s %s@%s on callid: %s\n", + cxident ? cxident : "", p->name, p->parent->name, callid ? callid : ""); + } reqprep(&resp, p, "DLCX"); - /* SC: check if call id is avail */ - if (callid && *callid) - add_header(&resp, "C", callid); - /* SC: check if cxident is avail */ - if (cxident && *cxident) - add_header(&resp, "I", cxident); - /* SC: fill in new fields */ - resp.cmd = MGCP_CMD_DLCX; - resp.trid = oseq; + /* SC: check if call id is avail */ + if (callid && *callid) + add_header(&resp, "C", callid); + /* SC: check if cxident is avail */ + if (cxident && *cxident) + add_header(&resp, "I", cxident); + /* SC: fill in new fields */ + resp.cmd = MGCP_CMD_DLCX; + resp.trid = oseq; return send_request(p, p->sub, &resp, oseq); } @@ -2279,20 +2342,20 @@ if (sub->owner) { ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n", result, p->name, p->parent->name, sub ? sub->id:-1); - ast_softhangup(sub->owner, AST_SOFTHANGUP_DEV); + mgcp_queue_hangup(sub); } } else { if (p->sub->next->owner) { ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n", result, p->name, p->parent->name, sub ? sub->id:-1); - ast_softhangup(p->sub->next->owner, AST_SOFTHANGUP_DEV); + mgcp_queue_hangup(p->sub); } if (p->sub->owner) { ast_log(LOG_NOTICE, "Terminating on result %d from %s@%s-%d\n", result, p->name, p->parent->name, sub ? sub->id:-1); - ast_softhangup(p->sub->owner, AST_SOFTHANGUP_DEV); + mgcp_queue_hangup(p->sub); } dump_cmd_queues(p, NULL); @@ -2358,7 +2421,7 @@ /* SC: XXX cleanup if we think we are offhook XXX */ if ((p->sub->owner || p->sub->next->owner ) && p->hookstate == MGCP_OFFHOOK) - ast_softhangup(sub->owner, AST_SOFTHANGUP_DEV); + mgcp_queue_hangup(sub); p->hookstate = MGCP_ONHOOK; /* SC: update the requested events according to the new hookstate */ @@ -2740,7 +2803,7 @@ p->sub->next->owner->_softhangup |= AST_SOFTHANGUP_DEV; if (p->sub->next->owner) { p->sub->next->alreadygone = 1; - ast_queue_hangup(p->sub->next->owner); + mgcp_queue_hangup(p->sub->next); } } return 0; @@ -2770,7 +2833,7 @@ } /*transmit_notify_request(sub, "aw");*/ transmit_notify_request(sub, ""); - ast_queue_control(sub->owner, AST_CONTROL_ANSWER); + mgcp_queue_control(sub, AST_CONTROL_ANSWER); } } else { /* Start switch */ @@ -2837,13 +2900,13 @@ { char *ev, *s; struct ast_frame f = { 0, }; - struct mgcp_endpoint *p = sub->parent; - struct mgcp_gateway *g = NULL; + struct mgcp_endpoint *p = sub->parent; + struct mgcp_gateway *g = NULL; char iabuf[INET_ADDRSTRLEN]; - int res; + int res; if (mgcpdebug) { ast_verbose("Handling request '%s' on %s@%s\n", req->verb, p->name, p->parent->name); - } + } /* Clear out potential response */ if (!strcasecmp(req->verb, "RSIP")) { /* Test if this RSIP request is just a keepalive */ @@ -2853,10 +2916,10 @@ transmit_response(sub, "200", req, "OK"); } else { dump_queue(p->parent, p); - dump_cmd_queues(p, NULL); + dump_cmd_queues(p, NULL); if (option_verbose > 2 && (strcmp(p->name, p->parent->wcardep) != 0)) { - ast_verbose(VERBOSE_PREFIX_3 "Resetting interface %s@%s\n", p->name, p->parent->name); + ast_verbose(VERBOSE_PREFIX_3 "Resetting interface %s@%s\n", p->name, p->parent->name); } // JS: For RSIP on wildcard we reset all endpoints if (!strcmp(p->name, p->parent->wcardep)) { @@ -2876,23 +2939,22 @@ first_sub = tmp_ep->sub; tmp_sub = tmp_ep->sub; while (tmp_sub) { - if (tmp_sub->owner) - ast_softhangup(tmp_sub->owner, AST_SOFTHANGUP_DEV); + mgcp_queue_hangup(tmp_sub); tmp_sub = tmp_sub->next; if (tmp_sub == first_sub) break; - } + } } tmp_ep = tmp_ep->next; } } else if (sub->owner) { - ast_softhangup(sub->owner, AST_SOFTHANGUP_DEV); + mgcp_queue_hangup(sub); } transmit_response(sub, "200", req, "OK"); /* JS: We dont send NTFY or AUEP to wildcard ep */ if (strcmp(p->name, p->parent->wcardep) != 0) { transmit_notify_request(sub, ""); - /* SC: Audit endpoint. + /* SC: Audit endpoint. Idea is to prevent lost lines due to race conditions */ transmit_audit_endpoint(p); @@ -2905,185 +2967,191 @@ ev = get_header(req, "O"); s = strchr(ev, '/'); if (s) ev = s + 1; - if (option_verbose > 2) { - ast_verbose(VERBOSE_PREFIX_3 "Endpoint '%s@%s-%d' observed '%s'\n", p->name, p->parent->name, sub->id, ev); - } + if (option_verbose > 2) { + ast_verbose(VERBOSE_PREFIX_3 "Endpoint '%s@%s-%d' observed '%s'\n", p->name, p->parent->name, sub->id, ev); + } /* Keep looking for events unless this was a hangup */ if (strcasecmp(ev, "hu") && strcasecmp(ev, "hd") && strcasecmp(ev, "ping")) { transmit_notify_request(sub, p->curtone); - } + } if (!strcasecmp(ev, "hd")) { - p->hookstate = MGCP_OFFHOOK; - sub->cxmode = MGCP_CX_SENDRECV; - handle_hd_hf(sub, ev); + p->hookstate = MGCP_OFFHOOK; + sub->cxmode = MGCP_CX_SENDRECV; + handle_hd_hf(sub, ev); } else if (!strcasecmp(ev, "hf")) { - /* We can assume we are offhook if we received a hookflash */ - /* First let's just do call wait and ignore threeway */ - /* We're currently in charge */ - if (p->hookstate != MGCP_OFFHOOK) { - /* Cisco c7940 sends hf even if the phone is onhook */ - /* Thanks to point on IRC for pointing this out */ - return -1; - } - /* do not let * confrnce two down channels */ - if( sub->owner && sub->owner->_state == AST_STATE_DOWN && !sub->next->owner) return -1; - - if (p->callwaiting || p->transfer || p->threewaycalling) { - if (option_verbose > 2) { - 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); - } - p->sub = p->sub->next; + /* We can assume we are offhook if we received a hookflash */ + /* First let's just do call wait and ignore threeway */ + /* We're currently in charge */ + if (p->hookstate != MGCP_OFFHOOK) { + /* Cisco c7940 sends hf even if the phone is onhook */ + /* Thanks to point on IRC for pointing this out */ + return -1; + } + /* do not let * confrnce two down channels */ + if( sub->owner && sub->owner->_state == AST_STATE_DOWN && !sub->next->owner) { + return -1; + } - /* transfer control to our next subchannel */ - if (!sub->next->owner) { - /* plave the first call on hold and start up a new call */ - sub->cxmode = MGCP_CX_MUTE; - if (option_verbose > 2) { - ast_verbose(VERBOSE_PREFIX_3 "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name); - } - transmit_modify_request(sub); - if (sub->owner && sub->owner->bridge) { - ast_moh_start(sub->owner->bridge, NULL); - } - sub->next->cxmode = MGCP_CX_RECVONLY; - handle_hd_hf(sub->next, ev); - } else if (sub->owner && sub->next->owner) { - /* We've got two active calls lets decide whether or not to conference or just flip flop */ - if ((!sub->outgoing) && (!sub->next->outgoing)) { - /* We made both calls lets conferenct */ - if (option_verbose > 2) { - ast_verbose(VERBOSE_PREFIX_3 "MGCP Conferencing %d and %d on %s@%s\n", - sub->id, sub->next->id, p->name, p->parent->name); - } - sub->cxmode = MGCP_CX_CONF; - sub->next->cxmode = MGCP_CX_CONF; - if (sub->next->owner->bridge) { - ast_moh_stop(sub->next->owner->bridge); - } - transmit_modify_request(sub); - transmit_modify_request(sub->next); - } else { - /* Let's flipflop between calls */ - /* XXX Need to check for state up ??? */ - /* XXX Need a way to indicate the current call, or maybe the call that's waiting */ - if (option_verbose > 2) { - ast_verbose(VERBOSE_PREFIX_3 "We didn't make one of the calls FLIPFLOP %d and %d on %s@%s\n", - sub->id, sub->next->id, p->name, p->parent->name); - } - sub->cxmode = MGCP_CX_MUTE; - if (option_verbose > 2) { - ast_verbose(VERBOSE_PREFIX_3 "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name); - } - transmit_modify_request(sub); - if (sub->owner->bridge) { - ast_moh_start(sub->owner->bridge, NULL); - } - if (sub->next->owner->bridge) { - ast_moh_stop(sub->next->owner->bridge); - } - handle_hd_hf(sub->next, ev); + if (p->callwaiting || p->transfer || p->threewaycalling) { + if (option_verbose > 2) { + 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); + } + p->sub = p->sub->next; + + /* transfer control to our next subchannel */ + if (!sub->next->owner) { + /* plave the first call on hold and start up a new call */ + sub->cxmode = MGCP_CX_MUTE; + if (option_verbose > 2) { + ast_verbose(VERBOSE_PREFIX_3 "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name); + } + transmit_modify_request(sub); + if (sub->owner && sub->owner->bridge) { + ast_moh_start(sub->owner->bridge, NULL); + } + sub->next->cxmode = MGCP_CX_RECVONLY; + handle_hd_hf(sub->next, ev); + } else if (sub->owner && sub->next->owner) { + /* We've got two active calls lets decide whether or not to conference or just flip flop */ + if ((!sub->outgoing) && (!sub->next->outgoing)) { + /* We made both calls lets conferenct */ + if (option_verbose > 2) { + ast_verbose(VERBOSE_PREFIX_3 "MGCP Conferencing %d and %d on %s@%s\n", + sub->id, sub->next->id, p->name, p->parent->name); + } + sub->cxmode = MGCP_CX_CONF; + sub->next->cxmode = MGCP_CX_CONF; + if (sub->next->owner->bridge) { + ast_moh_stop(sub->next->owner->bridge); + } + transmit_modify_request(sub); + transmit_modify_request(sub->next); + } else { + /* Let's flipflop between calls */ + /* XXX Need to check for state up ??? */ + /* XXX Need a way to indicate the current call, or maybe the call that's waiting */ + if (option_verbose > 2) { + ast_verbose(VERBOSE_PREFIX_3 "We didn't make one of the calls FLIPFLOP %d and %d on %s@%s\n", + sub->id, sub->next->id, p->name, p->parent->name); + } + sub->cxmode = MGCP_CX_MUTE; + if (option_verbose > 2) { + ast_verbose(VERBOSE_PREFIX_3 "MGCP Muting %d on %s@%s\n", sub->id, p->name, p->parent->name); + } + transmit_modify_request(sub); + if (sub->owner->bridge) { + ast_moh_start(sub->owner->bridge, NULL); + } + if (sub->next->owner->bridge) { + ast_moh_stop(sub->next->owner->bridge); + } + handle_hd_hf(sub->next, ev); #if 0 - if (sub->next->owner && (sub->next->owner->_state != AST_STATE_UP)) { - handle_hd_hf(sub->next, ev); - } else { - ast_verbose(VERBOSE_PREFIX_3 "MGCP Unmuting %d on %s@%s\n", sub->next->id, p->name, p->parent->name); - sub->next->cxmode = MGCP_CX_SENDRECV; - transmit_modify_request(sub->next); - } + if (sub->next->owner && (sub->next->owner->_state != AST_STATE_UP)) { + handle_hd_hf(sub->next, ev); + } else { + ast_verbose(VERBOSE_PREFIX_3 "MGCP Unmuting %d on %s@%s\n", sub->next->id, p->name, p->parent->name); + sub->next->cxmode = MGCP_CX_SENDRECV; + transmit_modify_request(sub->next); + } #endif - } - } else { - /* We've most likely lost one of our calls find an active call and bring it up */ - if (sub->owner) { - p->sub = sub; - } else if (sub->next->owner) { - p->sub = sub->next; - } else { - /* We seem to have lost both our calls */ - /* XXX - What do we do now? */ - return -1; - } - if (p->sub->owner->bridge) { - ast_moh_stop(p->sub->owner->bridge); - } - p->sub->cxmode = MGCP_CX_SENDRECV; - transmit_modify_request(p->sub); - } - } else { - ast_log(LOG_WARNING, "Callwaiting, call transfer or threeway calling not enabled on endpoint %s@%s\n", - p->name, p->parent->name); - } - /* ast_moh_stop(sub->owner->bridge); */ + } + } else { + /* We've most likely lost one of our calls find an active call and bring it up */ + if (sub->owner) { + p->sub = sub; + } else if (sub->next->owner) { + p->sub = sub->next; + } else { + /* We seem to have lost both our calls */ + /* XXX - What do we do now? */ + return -1; + } + if (p->sub->owner->bridge) { + ast_moh_stop(p->sub->owner->bridge); + } + p->sub->cxmode = MGCP_CX_SENDRECV; + transmit_modify_request(p->sub); + } + } else { + ast_log(LOG_WARNING, "Callwaiting, call transfer or threeway calling not enabled on endpoint %s@%s\n", + p->name, p->parent->name); + } + /* ast_moh_stop(sub->owner->bridge); */ } else if (!strcasecmp(ev, "hu")) { - p->hookstate = MGCP_ONHOOK; - sub->cxmode = MGCP_CX_RECVONLY; - ast_log(LOG_DEBUG, "MGCP %s@%s Went on hook\n", p->name, p->parent->name); - /* JS: Do we need to send MDCX before a DLCX ? - if (sub->rtp) { - transmit_modify_request(sub); - } - */ - if (p->transfer && (sub->owner && sub->next->owner) && ((!sub->outgoing) || (!sub->next->outgoing))) { - /* We're allowed to transfer, we have two avtive calls and */ - /* we made at least one of the calls. Let's try and transfer */ - if ((res = attempt_transfer(p)) < 0) { - if (p->sub->next->owner) { - sub->next->alreadygone = 1; - ast_queue_hangup(sub->next->owner); - } - } else if (res) { - ast_log(LOG_WARNING, "Transfer attempt failed\n"); - return -1; - } - } else { - /* Hangup the current call */ - /* If there is another active call, mgcp_hangup will ring the phone with the other call */ - if (sub->owner) { - sub->alreadygone = 1; - ast_queue_hangup(sub->owner); - } else { - /* SC: verbose level check */ - if (option_verbose > 2) { - ast_verbose(VERBOSE_PREFIX_3 "MGCP handle_request(%s@%s-%d) ast_channel already destroyed\n", - p->name, p->parent->name, sub->id); - } - } - } - if ((p->hookstate == MGCP_ONHOOK) && (!sub->rtp) && (!sub->next->rtp)) { - if (has_voicemail(p)) { - if (option_verbose > 2) { - ast_verbose(VERBOSE_PREFIX_3 "MGCP handle_request(%s@%s) set vmwi(+)\n", p->name, p->parent->name); - } - transmit_notify_request(sub, "L/vmwi(+)"); - } else { - if (option_verbose > 2) { - ast_verbose(VERBOSE_PREFIX_3 "MGCP handle_request(%s@%s) set vmwi(-)\n", p->name, p->parent->name); - } - transmit_notify_request(sub, "L/vmwi(-)"); - } - } + p->hookstate = MGCP_ONHOOK; + sub->cxmode = MGCP_CX_RECVONLY; + ast_log(LOG_DEBUG, "MGCP %s@%s Went on hook\n", p->name, p->parent->name); + /* JS: Do we need to send MDCX before a DLCX ? + if (sub->rtp) { + transmit_modify_request(sub); + } + */ + if (p->transfer && (sub->owner && sub->next->owner) && ((!sub->outgoing) || (!sub->next->outgoing))) { + /* We're allowed to transfer, we have two avtive calls and */ + /* we made at least one of the calls. Let's try and transfer */ + ast_mutex_lock(&p->sub->next->lock); + res = attempt_transfer(p); + if (res < 0) { + if (p->sub->next->owner) { + sub->next->alreadygone = 1; + mgcp_queue_hangup(sub->next); + } + } else if (res) { + ast_log(LOG_WARNING, "Transfer attempt failed\n"); + ast_mutex_unlock(&p->sub->next->lock); + return -1; + } + ast_mutex_unlock(&p->sub->next->lock); + } else { + /* Hangup the current call */ + /* If there is another active call, mgcp_hangup will ring the phone with the other call */ + if (sub->owner) { + sub->alreadygone = 1; + mgcp_queue_hangup(sub); + } else { + /* SC: verbose level check */ + if (option_verbose > 2) { + ast_verbose(VERBOSE_PREFIX_3 "MGCP handle_request(%s@%s-%d) ast_channel already destroyed\n", + p->name, p->parent->name, sub->id); + } + } + } + if ((p->hookstate == MGCP_ONHOOK) && (!sub->rtp) && (!sub->next->rtp)) { + if (has_voicemail(p)) { + if (option_verbose > 2) { + ast_verbose(VERBOSE_PREFIX_3 "MGCP handle_request(%s@%s) set vmwi(+)\n", p->name, p->parent->name); + } + transmit_notify_request(sub, "L/vmwi(+)"); + } else { + if (option_verbose > 2) { + ast_verbose(VERBOSE_PREFIX_3 "MGCP handle_request(%s@%s) set vmwi(-)\n", p->name, p->parent->name); + } + transmit_notify_request(sub, "L/vmwi(-)"); + } + } } else if ((strlen(ev) == 1) && - (((ev[0] >= '0') && (ev[0] <= '9')) || - ((ev[0] >= 'A') && (ev[0] <= 'D')) || - (ev[0] == '*') || (ev[0] == '#'))) { + (((ev[0] >= '0') && (ev[0] <= '9')) || + ((ev[0] >= 'A') && (ev[0] <= 'D')) || + (ev[0] == '*') || (ev[0] == '#'))) { f.frametype = AST_FRAME_DTMF; f.subclass = ev[0]; f.src = "mgcp"; if (sub->owner) { - /* XXX MUST queue this frame to all subs in threeway call if threeway call is active */ - ast_queue_frame(sub->owner, &f); - if (sub->next->owner) { - ast_queue_frame(sub->next->owner, &f); - } - } - if (strstr(p->curtone, "wt") && (ev[0] == 'A')) { - memset(p->curtone, 0, sizeof(p->curtone)); - } - } - else if (!strcasecmp(ev, "T")) { + /* XXX MUST queue this frame to all subs in threeway call if threeway call is active */ + mgcp_queue_frame(sub, &f); + ast_mutex_lock(&sub->next->lock); + if (sub->next->owner) { + mgcp_queue_frame(sub->next, &f); + } + ast_mutex_unlock(&sub->next->lock); + } + if (strstr(p->curtone, "wt") && (ev[0] == 'A')) { + memset(p->curtone, 0, sizeof(p->curtone)); + } + } else if (!strcasecmp(ev, "T")) { /* Digit timeout -- unimportant */ - } - else if (!strcasecmp(ev, "ping")) { + } else if (!strcasecmp(ev, "ping")) { /* ping -- unimportant */ } else { ast_log(LOG_NOTICE, "Received unknown event '%s' from %s@%s\n", ev, p->name, p->parent->name); @@ -3163,11 +3231,12 @@ if (sscanf(req.verb, "%d", &result) && sscanf(req.identifier, "%d", &ident)) { /* Try to find who this message is for, if it's important */ - sub = find_subchannel(NULL, ident, &sin); + sub = find_subchannel_and_lock(NULL, ident, &sin); if (sub) { struct mgcp_gateway *gw = sub->parent->parent; struct mgcp_message *cur, *prev; + ast_mutex_unlock(&sub->lock); ast_mutex_lock(&gw->msgs_lock); for (prev = NULL, cur = gw->msgs; cur; prev = cur, cur = cur->next) { if (cur->seqno == ident) { @@ -3187,7 +3256,6 @@ } ast_mutex_unlock(&gw->msgs_lock); - if (cur) { handle_response(cur->owner_ep, cur->owner_sub, result, ident, &req); free(cur); @@ -3205,12 +3273,13 @@ return 1; } /* Process request, with iflock held */ - sub = find_subchannel(req.endpoint, 0, &sin); + sub = find_subchannel_and_lock(req.endpoint, 0, &sin); if (sub) { /* look first to find a matching response in the queue */ if (!find_and_retrans(sub, &req)) /* pass the request off to the currently mastering subchannel */ handle_request(sub, &req, &sin); + ast_mutex_unlock(&sub->lock); } } return 1; @@ -3222,8 +3291,8 @@ { int res; int reloading; - /* struct mgcp_gateway *g; */ - /* struct mgcp_endpoint *e; */ + /* struct mgcp_gateway *g; */ + /* struct mgcp_endpoint *e; */ /*time_t thispass = 0, lastpass = 0;*/ /* Add an I/O event to our UDP socket */ @@ -3248,17 +3317,17 @@ mgcpsock_read_id = ast_io_add(io, mgcpsock, mgcpsock_read, AST_IO_IN, NULL); } - /* Check for interfaces needing to be killed */ + /* Check for interfaces needing to be killed */ /* Don't let anybody kill us right away. Nobody should lock the interface list and wait for the monitor list, but the other way around is okay. */ ast_mutex_lock(&monlock); /* Lock the network interface */ ast_mutex_lock(&netlock); +#if 0 /* XXX THIS IS COMPLETELY HOSED */ /* The gateway goes into a state of panic */ /* If the vmwi indicator is sent while it is reseting interfaces */ -#if 0 lastpass = thispass; thispass = time(NULL); g = gateways; @@ -3292,7 +3361,7 @@ pthread_testcancel(); /* Wait for sched or io */ res = ast_sched_wait(sched); - /* SC: copied from chan_sip.c */ + /* SC: copied from chan_sip.c */ if ((res < 0) || (res > 1000)) res = 1000; res = ast_io_wait(io, res); @@ -3358,33 +3427,36 @@ ast_log(LOG_NOTICE, "MGCP Channels require an endpoint\n"); return NULL; } - sub = find_subchannel(tmp, 0, NULL); + sub = find_subchannel_and_lock(tmp, 0, NULL); if (!sub) { ast_log(LOG_WARNING, "Unable to find MGCP endpoint '%s'\n", tmp); return NULL; } - if (option_verbose > 2) { - ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_request(%s)\n", tmp); - ast_verbose(VERBOSE_PREFIX_3 "MGCP cw: %d, dnd: %d, so: %d, sno: %d\n", - sub->parent->callwaiting, sub->parent->dnd, sub->owner ? 1 : 0, sub->next->owner ? 1: 0); - } + if (option_verbose > 2) { + ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_request(%s)\n", tmp); + ast_verbose(VERBOSE_PREFIX_3 "MGCP cw: %d, dnd: %d, so: %d, sno: %d\n", + sub->parent->callwaiting, sub->parent->dnd, sub->owner ? 1 : 0, sub->next->owner ? 1: 0); + } /* Must be busy */ if (((sub->parent->callwaiting) && ((sub->owner) && (sub->next->owner))) || - ((!sub->parent->callwaiting) && (sub->owner)) || - (sub->parent->dnd && (!strlen(sub->parent->call_forward)))) { - if (sub->parent->hookstate == MGCP_ONHOOK) { - if (has_voicemail(sub->parent)) { - transmit_notify_request(sub,"L/vmwi(+)"); - } else { - transmit_notify_request(sub,"L/vmwi(-)"); - } - } + ((!sub->parent->callwaiting) && (sub->owner)) || + (sub->parent->dnd && (!strlen(sub->parent->call_forward)))) { + if (sub->parent->hookstate == MGCP_ONHOOK) { + if (has_voicemail(sub->parent)) { + transmit_notify_request(sub,"L/vmwi(+)"); + } else { + transmit_notify_request(sub,"L/vmwi(-)"); + } + } + ast_mutex_unlock(&sub->lock); return NULL; - } + } tmpc = mgcp_new(sub->owner ? sub->next : sub, AST_STATE_DOWN); - if (!tmpc) + ast_mutex_unlock(&sub->lock); + if (!tmpc) { ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp); + } restart_monitor(); return tmpc; } @@ -3394,11 +3466,11 @@ { struct mgcp_gateway *gw; struct mgcp_endpoint *e; - struct mgcp_subchannel *sub; - /*char txident[80];*/ - int i=0, y=0; - int gw_reload = 0; - int ep_reload = 0; + struct mgcp_subchannel *sub; + /*char txident[80];*/ + int i=0, y=0; + int gw_reload = 0; + int ep_reload = 0; canreinvite = CANREINVITE; /* SC: locate existing gateway */ @@ -3746,6 +3818,8 @@ } return NULL; } + gw->defaddr.sin_family = AF_INET; + gw->addr.sin_family = AF_INET; if (gw->defaddr.sin_addr.s_addr && !ntohs(gw->defaddr.sin_port)) gw->defaddr.sin_port = htons(DEFAULT_MGCP_GW_PORT); if (gw->addr.sin_addr.s_addr && !ntohs(gw->addr.sin_port)) @@ -3836,9 +3910,7 @@ sub->rtp = NULL; } memset(sub->magic, 0, sizeof(sub->magic)); - if (sub->owner) { - ast_softhangup(sub->owner, AST_SOFTHANGUP_DEV); - } + mgcp_queue_hangup(sub); dump_cmd_queues(NULL, sub); ast_mutex_unlock(&sub->lock); sub = sub->next; @@ -4161,8 +4233,7 @@ /* Hangup all interfaces if they have an owner */ p = iflist; while(p) { - if (p->owner) - ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); + mgcp_queue_hangup(p); p = p->next; } iflist = NULL;