📄 chan_mgcp.c
字号:
sub->callid[0] = '\0'; sub->cxmode = MGCP_CX_INACTIVE; sub->outgoing = 0; sub->alreadygone = 0; memset(&sub->tmpdest, 0, sizeof(sub->tmpdest)); if (sub->rtp) { ast_rtp_destroy(sub->rtp); sub->rtp = NULL; } dump_cmd_queues(NULL, sub); /* SC */ return 0;}/* modified for new transport mechanism */static int __mgcp_xmit(struct mgcp_gateway *gw, char *data, int len){ int res; if (gw->addr.sin_addr.s_addr) res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->addr, sizeof(struct sockaddr_in)); else res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&gw->defaddr, sizeof(struct sockaddr_in)); if (res != len) { ast_log(LOG_WARNING, "mgcp_xmit returned %d: %s\n", res, strerror(errno)); } return res;}static int resend_response(struct mgcp_subchannel *sub, struct mgcp_response *resp){ struct mgcp_endpoint *p = sub->parent; int res; if (mgcpdebug) { 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)); } res = __mgcp_xmit(p->parent, resp->buf, resp->len); if (res > 0) res = 0; return res;}static int send_response(struct mgcp_subchannel *sub, struct mgcp_request *req){ struct mgcp_endpoint *p = sub->parent; int res; if (mgcpdebug) { 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)); } res = __mgcp_xmit(p->parent, req->data, req->len); if (res > 0) res = 0; return res;}/* modified for new transport framework */static void dump_queue(struct mgcp_gateway *gw, struct mgcp_endpoint *p){ struct mgcp_message *cur, *q = NULL, *w, *prev; ast_mutex_lock(&gw->msgs_lock); prev = NULL, cur = gw->msgs; while (cur) { if (!p || cur->owner_ep == p) { if (prev) prev->next = cur->next; else gw->msgs = cur->next; ast_log(LOG_NOTICE, "Removing message from %s transaction %u\n", gw->name, cur->seqno); w = cur; cur = cur->next; if (q) { w->next = q; } else { w->next = NULL; } q = w; } else { prev = cur, cur=cur->next; } } ast_mutex_unlock(&gw->msgs_lock); while (q) { cur = q; q = q->next; free(cur); }}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 { DEADLOCK_AVOIDANCE(&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 { DEADLOCK_AVOIDANCE(&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(const void *data){ struct mgcp_gateway *gw = (struct mgcp_gateway *)data; struct mgcp_message *cur, *exq = NULL, *w, *prev; int res = 0; /* find out expired msgs */ ast_mutex_lock(&gw->msgs_lock); prev = NULL, cur = gw->msgs; while (cur) { if (cur->retrans < MAX_RETRANS) { cur->retrans++; if (mgcpdebug) { ast_verbose("Retransmitting #%d transaction %u on [%s]\n", cur->retrans, cur->seqno, gw->name); } __mgcp_xmit(gw, cur->buf, cur->len); prev = cur; cur = cur->next; } else { if (prev) prev->next = cur->next; else gw->msgs = cur->next; ast_log(LOG_WARNING, "Maximum retries exceeded for transaction %u on [%s]\n", cur->seqno, gw->name); w = cur; cur = cur->next; if (exq) { w->next = exq; } else { w->next = NULL; } exq = w; } } if (!gw->msgs) { gw->retransid = -1; res = 0; } else { res = 1; } ast_mutex_unlock(&gw->msgs_lock); while (exq) { cur = exq; /* time-out transaction */ handle_response(cur->owner_ep, cur->owner_sub, 406, cur->seqno, NULL); exq = exq->next; free(cur); } return res;}/* modified for the new transaction mechanism */static int mgcp_postrequest(struct mgcp_endpoint *p, struct mgcp_subchannel *sub, char *data, int len, unsigned int seqno){ struct mgcp_message *msg = malloc(sizeof(struct mgcp_message) + len); struct mgcp_message *cur; struct mgcp_gateway *gw = ((p && p->parent) ? p->parent : NULL); struct timeval tv; if (!msg) { return -1; } if (!gw) { return -1; }/* SC time(&t); if (gw->messagepending && (gw->lastouttime + 20 < t)) { ast_log(LOG_NOTICE, "Timeout waiting for response to message:%d, lastouttime: %ld, now: %ld. Dumping pending queue\n", gw->msgs ? gw->msgs->seqno : -1, (long) gw->lastouttime, (long) t); dump_queue(sub->parent); }*/ msg->owner_sub = sub; msg->owner_ep = p; msg->seqno = seqno; msg->next = NULL; msg->len = len; msg->retrans = 0; memcpy(msg->buf, data, msg->len); ast_mutex_lock(&gw->msgs_lock); cur = gw->msgs; if (cur) { while(cur->next) cur = cur->next; cur->next = msg; } else { gw->msgs = msg; } if (gettimeofday(&tv, NULL) < 0) { /* This shouldn't ever happen, but let's be sure */ ast_log(LOG_NOTICE, "gettimeofday() failed!\n"); } else { msg->expire = tv.tv_sec * 1000 + tv.tv_usec / 1000 + DEFAULT_RETRANS; if (gw->retransid == -1) gw->retransid = ast_sched_add(sched, DEFAULT_RETRANS, retrans_pkt, (void *)gw); } ast_mutex_unlock(&gw->msgs_lock);/* SC if (!gw->messagepending) { gw->messagepending = 1; gw->lastout = seqno; gw->lastouttime = t;*/ __mgcp_xmit(gw, msg->buf, msg->len); /* XXX Should schedule retransmission XXX *//* SC } else ast_log(LOG_DEBUG, "Deferring transmission of transaction %d\n", seqno);*/ return 0;}/* modified for new transport */static int send_request(struct mgcp_endpoint *p, struct mgcp_subchannel *sub, struct mgcp_request *req, unsigned int seqno){ int res = 0; struct mgcp_request **queue, *q, *r, *t; ast_mutex_t *l; ast_log(LOG_DEBUG, "Slow sequence is %d\n", p->slowsequence); if (p->slowsequence) { queue = &p->cmd_queue; l = &p->cmd_queue_lock; ast_mutex_lock(l); } else { switch (req->cmd) { case MGCP_CMD_DLCX: queue = &sub->cx_queue; l = &sub->cx_queue_lock; ast_mutex_lock(l); q = sub->cx_queue; /* delete pending cx cmds */ while (q) { r = q->next; free(q); q = r; } *queue = NULL; break; case MGCP_CMD_CRCX: case MGCP_CMD_MDCX: queue = &sub->cx_queue; l = &sub->cx_queue_lock; ast_mutex_lock(l); break; case MGCP_CMD_RQNT: queue = &p->rqnt_queue; l = &p->rqnt_queue_lock; ast_mutex_lock(l); break; default: queue = &p->cmd_queue; l = &p->cmd_queue_lock; ast_mutex_lock(l); break; } } r = (struct mgcp_request *) malloc (sizeof(struct mgcp_request)); if (!r) { ast_log(LOG_WARNING, "Cannot post MGCP request: insufficient memory\n"); ast_mutex_unlock(l); return -1; } memcpy(r, req, sizeof(struct mgcp_request)); if (!(*queue)) { if (mgcpdebug) { ast_verbose("Posting Request:\n%s to %s:%d\n", req->data, ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port)); } res = mgcp_postrequest(p, sub, req->data, req->len, seqno); } else { if (mgcpdebug) { ast_verbose("Queueing Request:\n%s to %s:%d\n", req->data, ast_inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port)); } } /* XXX find tail. We could also keep tail in the data struct for faster access */ for (t = *queue; t && t->next; t = t->next); r->next = NULL; if (t) t->next = r; else *queue = r; ast_mutex_unlock(l); return res;}static int mgcp_call(struct ast_channel *ast, char *dest, int timeout){ int res; struct mgcp_endpoint *p; struct mgcp_subchannel *sub; char tone[50] = ""; const char *distinctive_ring = NULL; struct varshead *headp; struct ast_var_t *current; if (mgcpdebug) { ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_call(%s)\n", ast->name); } sub = ast->tech_pvt; p = sub->parent; headp = &ast->varshead; AST_LIST_TRAVERSE(headp,current,entries) { /* Check whether there is an ALERT_INFO variable */ if (strcasecmp(ast_var_name(current),"ALERT_INFO") == 0) { distinctive_ring = ast_var_value(current); } } ast_mutex_lock(&sub->lock); switch (p->hookstate) { case MGCP_OFFHOOK: if (!ast_strlen_zero(distinctive_ring)) { snprintf(tone, sizeof(tone), "L/wt%s", distinctive_ring); if (mgcpdebug) { ast_verbose(VERBOSE_PREFIX_3 "MGCP distinctive callwait %s\n", tone); } } else { snprintf(tone, sizeof(tone), "L/wt"); if (mgcpdebug) { ast_verbose(VERBOSE_PREFIX_3 "MGCP normal callwait %s\n", tone); } } break; case MGCP_ONHOOK: default: if (!ast_strlen_zero(distinctive_ring)) { snprintf(tone, sizeof(tone), "L/r%s", distinctive_ring); if (mgcpdebug) { ast_verbose(VERBOSE_PREFIX_3 "MGCP distinctive ring %s\n", tone); } } else { snprintf(tone, sizeof(tone), "L/rg"); if (mgcpdebug) { ast_verbose(VERBOSE_PREFIX_3 "MGCP default ring\n"); } } break; } 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; } res = 0; sub->outgoing = 1; sub->cxmode = MGCP_CX_RECVONLY; if (p->type == TYPE_LINE) { if (!sub->rtp) { start_rtp(sub); } else { transmit_modify_request(sub); } if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) { /* try to prevent a callwait from disturbing the other connection */ sub->next->cxmode = MGCP_CX_RECVONLY; transmit_modify_request(sub->next); } transmit_notify_request_with_callerid(sub, tone, ast->cid.cid_num, ast->cid.cid_name); ast_setstate(ast, AST_STATE_RINGING); if (sub->next->owner && !ast_strlen_zero(sub->next->cxident) && !ast_strlen_zero(sub->next->callid)) { /* Put the connection back in sendrecv */ sub->next->cxmode = MGCP_CX_SENDRECV; transmit_modify_request(sub->next); } } else { 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;}static int mgcp_hangup(struct ast_channel *ast){ struct mgcp_subchannel *sub = ast->tech_pvt; struct mgcp_endpoint *p = sub->parent; if (option_debug) { ast_log(LOG_DEBUG, "mgcp_hangup(%s)\n", ast->name); } if (!ast->tech_pvt) { ast_log(LOG_DEBUG, "Asked to hangup channel not connected\n"); return 0; } if (strcmp(sub->magic, MGCP_SUBCHANNEL_MAGIC)) { ast_log(LOG_DEBUG, "Invalid magic. MGCP subchannel freed up already.\n"); return 0; } ast_mutex_lock(&sub->lock); 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) { /* check whether other channel is active. */ if (!sub->next->owner) { if (p->dtmfmode & MGCP_DTMF_HYBRID) p->dtmfmode &= ~MGCP_DTMF_INBAND; 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 (!ast_strlen_zero(sub->cxident)) { transmit_connection_del(sub); } sub->cxident[0] = '\0'; if ((sub == p->sub) && sub->next->owner) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -