--- chan_mgcp.c.v1-0 2004-10-26 16:40:00 +0300 +++ chan_mgcp.c.v1-0_MERGE 2004-11-18 13:50:28 +0200 @@ -570,6 +570,49 @@ } } +static void mgcp_queue_frame(struct mgcp_subchannel *sub, struct ast_frame *f) +{ + 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_mutex_unlock(&sub->lock); + usleep(1); + ast_mutex_lock(&sub->lock); + } + } else + break; + } +} + +static void mgcp_queue_hangup(struct mgcp_subchannel *sub) +{ + 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_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 +851,7 @@ } sub = ast->pvt->pvt; p = sub->parent; - + ast_mutex_lock(&sub->lock); switch (p->hookstate) { case MGCP_OFFHOOK: tone = "L/wt"; @@ -821,6 +864,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 +886,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 +897,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,24 +907,26 @@ 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; } + 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 ((p->dtmfmode & MGCP_DTMF_INBAND) && (p->dsp != NULL)){ + if ((p->dtmfmode & MGCP_DTMF_INBAND) && p->dsp) { /* SC: check whether other channel is active. */ - if (!sub->next->owner) - { + if (!sub->next->owner) { if (mgcpdebug) { ast_verbose(VERBOSE_PREFIX_2 "MGCP free dsp on %s@%s\n", p->name, p->parent->name); } @@ -887,7 +934,6 @@ p->dsp = NULL; } } - ast_mutex_lock(&sub->lock); sub->owner = NULL; if (strlen(sub->cxident)) { @@ -1054,6 +1100,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 +1118,7 @@ transmit_notify_request(sub, ""); transmit_modify_request(sub); } + ast_mutex_unlock(&sub->lock); return res; } @@ -1148,12 +1196,15 @@ static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) { struct mgcp_subchannel *sub = newchan->pvt->pvt; + 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 +1216,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 +1258,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,9 +1282,10 @@ 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) @@ -1311,7 +1367,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 +1378,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 +1391,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 +1454,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; @@ -1493,6 +1552,7 @@ p = p->next; } if (sub && found) { + ast_mutex_lock(&sub->lock); break; } } @@ -1694,7 +1754,6 @@ return -1; } return 0; - } static int add_header(struct mgcp_request *req, char *var, char *value) @@ -1710,9 +1769,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 +1792,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; } @@ -2279,20 +2338,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 +2417,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 +2799,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 +2829,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 */ @@ -2876,8 +2935,7 @@ 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; @@ -2886,7 +2944,7 @@ 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 */ @@ -2926,7 +2984,9 @@ return -1; } /* do not let * confrnce two down channels */ - if( sub->owner && sub->owner->_state == AST_STATE_DOWN && !sub->next->owner) return -1; + 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) { @@ -3026,21 +3086,25 @@ 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) { + ast_mutex_lock(&p->sub->next->lock); + res = attempt_transfer(p); + if (res < 0) { if (p->sub->next->owner) { sub->next->alreadygone = 1; - ast_queue_hangup(sub->next->owner); + 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; - ast_queue_hangup(sub->owner); + mgcp_queue_hangup(sub); } else { /* SC: verbose level check */ if (option_verbose > 2) { @@ -3071,19 +3135,19 @@ 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); + mgcp_queue_frame(sub, &f); + ast_mutex_lock(&sub->next->lock); if (sub->next->owner) { - ast_queue_frame(sub->next->owner, &f); + 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")) { + } 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 +3227,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 +3252,6 @@ } ast_mutex_unlock(&gw->msgs_lock); - if (cur) { handle_response(cur->owner_ep, cur->owner_sub, result, ident, &req); free(cur); @@ -3205,12 +3269,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; @@ -3255,10 +3320,10 @@ /* 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; @@ -3358,7 +3423,7 @@ 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; @@ -3380,11 +3445,14 @@ 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; } @@ -3746,6 +3814,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 +3906,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 +4229,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;