📄 chan_mgcp.c
字号:
p->capability = capability & peercapability; if (mgcpdebug) { ast_verbose("Capabilities: us - %d, them - %d, combined - %d\n", capability, peercapability, p->capability); ast_verbose("Non-codec capabilities: us - %d, them - %d, combined - %d\n", nonCodecCapability, peerNonCodecCapability, p->nonCodecCapability); } if (!p->capability) { ast_log(LOG_WARNING, "No compatible codecs!\n"); return -1; } return 0;}static int add_header(struct mgcp_request *req, char *var, char *value){ if (req->len >= sizeof(req->data) - 4) { ast_log(LOG_WARNING, "Out of space, can't add anymore\n"); return -1; } if (req->lines) { ast_log(LOG_WARNING, "Can't add more headers when lines have been added\n"); return -1; } 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) req->headers++; else { ast_log(LOG_WARNING, "Out of header space\n"); return -1; } return 0; }static int add_line(struct mgcp_request *req, char *line){ if (req->len >= sizeof(req->data) - 4) { ast_log(LOG_WARNING, "Out of space, can't add anymore\n"); return -1; } if (!req->lines) { /* Add extra empty return */ snprintf(req->data + req->len, sizeof(req->data) - req->len, "\r\n"); req->len += strlen(req->data + req->len); } 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) req->lines++; else { ast_log(LOG_WARNING, "Out of line space\n"); return -1; } return 0; }static int init_resp(struct mgcp_request *req, char *resp, struct mgcp_request *orig, char *resprest){ /* Initialize a response */ if (req->headers || req->len) { ast_log(LOG_WARNING, "Request already initialized?!?\n"); return -1; } req->header[req->headers] = req->data + req->len; snprintf(req->header[req->headers], sizeof(req->data) - req->len, "%s %s %s\r\n", resp, orig->identifier, resprest); req->len += strlen(req->header[req->headers]); if (req->headers < MGCP_MAX_HEADERS) req->headers++; else ast_log(LOG_WARNING, "Out of header space\n"); return 0;}static int init_req(struct mgcp_endpoint *p, struct mgcp_request *req, char *verb){ /* Initialize a response */ if (req->headers || req->len) { ast_log(LOG_WARNING, "Request already initialized?!?\n"); return -1; } req->header[req->headers] = req->data + req->len; /* check if we need brackets around the gw name */ if (p->parent->isnamedottedip) 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); else 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); req->len += strlen(req->header[req->headers]); if (req->headers < MGCP_MAX_HEADERS) req->headers++; else ast_log(LOG_WARNING, "Out of header space\n"); return 0;}static int respprep(struct mgcp_request *resp, struct mgcp_endpoint *p, char *msg, struct mgcp_request *req, char *msgrest){ memset(resp, 0, sizeof(*resp)); init_resp(resp, msg, req, msgrest); return 0;}static int reqprep(struct mgcp_request *req, struct mgcp_endpoint *p, char *verb){ memset(req, 0, sizeof(struct mgcp_request)); oseq++; if (oseq > 999999999) oseq = 1; init_req(p, req, verb); return 0;}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_response *mgr; respprep(&resp, p, msg, req, msgrest); mgr = malloc(sizeof(struct mgcp_response) + resp.len + 1); if (mgr) { /* Store MGCP response in case we have to retransmit */ memset(mgr, 0, sizeof(struct mgcp_response)); sscanf(req->identifier, "%d", &mgr->seqno); time(&mgr->whensent); mgr->len = resp.len; memcpy(mgr->buf, resp.data, resp.len); mgr->buf[resp.len] = '\0'; mgr->next = p->parent->responses; p->parent->responses = mgr; } return send_response(sub, &resp);}static int add_sdp(struct mgcp_request *resp, struct mgcp_subchannel *sub, struct ast_rtp *rtp){ int len; int codec; char costr[80]; struct sockaddr_in sin; char v[256]; char s[256]; char o[256]; char c[256]; char t[256]; char m[256] = ""; char a[1024] = ""; int x; struct sockaddr_in dest; 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; if (!sub->rtp) { ast_log(LOG_WARNING, "No way to add SDP without an RTP structure\n"); return -1; } ast_rtp_get_us(sub->rtp, &sin); if (rtp) { ast_rtp_get_peer(rtp, &dest); } else { if (sub->tmpdest.sin_addr.s_addr) { dest.sin_addr = sub->tmpdest.sin_addr; dest.sin_port = sub->tmpdest.sin_port; /* Reset temporary destination */ memset(&sub->tmpdest, 0, sizeof(sub->tmpdest)); } else { dest.sin_addr = p->parent->ourip; dest.sin_port = sin.sin_port; } } if (mgcpdebug) { ast_verbose("We're at %s port %d\n", ast_inet_ntoa(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", (int)getpid(), (int)getpid(), ast_inet_ntoa(dest.sin_addr)); snprintf(s, sizeof(s), "s=session\r\n"); snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr)); snprintf(t, sizeof(t), "t=0 0\r\n"); snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port)); for (x = 1; x <= AST_FORMAT_MAX_AUDIO; x <<= 1) { if (p->capability & x) { if (mgcpdebug) { ast_verbose("Answering with capability %d\n", x); } codec = ast_rtp_lookup_code(sub->rtp, 1, x); if (codec > -1) { snprintf(costr, sizeof(costr), " %d", codec); strncat(m, costr, sizeof(m) - strlen(m) - 1); snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(1, x, 0)); strncat(a, costr, sizeof(a) - strlen(a) - 1); } } } for (x = 1; x <= AST_RTP_MAX; x <<= 1) { if (p->nonCodecCapability & x) { if (mgcpdebug) { ast_verbose("Answering with non-codec capability %d\n", x); } codec = ast_rtp_lookup_code(sub->rtp, 0, x); if (codec > -1) { snprintf(costr, sizeof(costr), " %d", codec); strncat(m, costr, sizeof(m) - strlen(m) - 1); snprintf(costr, sizeof(costr), "a=rtpmap:%d %s/8000\r\n", codec, ast_rtp_lookup_mime_subtype(0, x, 0)); strncat(a, costr, sizeof(a) - strlen(a) - 1); if (x == AST_RTP_DTMF) { /* Indicate we support DTMF... Not sure about 16, but MSN supports it so dang it, we will too... */ snprintf(costr, sizeof costr, "a=fmtp:%d 0-16\r\n", codec); strncat(a, costr, sizeof(a) - strlen(a) - 1); } } } } strncat(m, "\r\n", sizeof(m) - strlen(m) - 1); len = strlen(v) + strlen(s) + strlen(o) + strlen(c) + strlen(t) + strlen(m) + strlen(a); snprintf(costr, sizeof(costr), "%d", len); add_line(resp, v); add_line(resp, o); add_line(resp, s); add_line(resp, c); add_line(resp, t); add_line(resp, m); add_line(resp, a); return 0;}static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp, int codecs){ struct mgcp_request resp; char local[256]; char tmp[80]; int x; int capability; struct mgcp_endpoint *p = sub->parent; capability = p->capability; if (codecs) capability = codecs; if (ast_strlen_zero(sub->cxident) && rtp) { /* We don't have a CXident yet, store the destination and wait a bit */ ast_rtp_get_peer(rtp, &sub->tmpdest); return 0; } snprintf(local, sizeof(local), "p:20"); for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) { if (p->capability & x) { snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0)); strncat(local, tmp, sizeof(local) - strlen(local) - 1); } } reqprep(&resp, p, "MDCX"); add_header(&resp, "C", sub->callid); add_header(&resp, "L", local); add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]); /* 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", "");*/ add_sdp(&resp, sub, rtp); /* fill in new fields */ resp.cmd = MGCP_CMD_MDCX; resp.trid = oseq; return send_request(p, sub, &resp, oseq); /* SC */}static int transmit_connect_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp *rtp){ struct mgcp_request resp; char local[256]; char tmp[80]; int x; struct mgcp_endpoint *p = sub->parent; snprintf(local, sizeof(local), "p:20"); for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) { if (p->capability & x) { snprintf(tmp, sizeof(tmp), ", a:%s", ast_rtp_lookup_mime_subtype(1, x, 0)); 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); } reqprep(&resp, p, "CRCX"); add_header(&resp, "C", sub->callid); add_header(&resp, "L", local); add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]); /* X header should not be sent. kept for compatibility */ add_header(&resp, "X", sub->txident); /*add_header(&resp, "S", "");*/ add_sdp(&resp, sub, rtp); /* fill in new fields */ resp.cmd = MGCP_CMD_CRCX; resp.trid = oseq; return send_request(p, sub, &resp, oseq); /* SC */}static int transmit_notify_request(struct mgcp_subchannel *sub, char *tone){ struct mgcp_request resp; struct mgcp_endpoint *p = sub->parent; if (mgcpdebug) { ast_verbose(VERBOSE_PREFIX_3 "MGCP Asked to indicate tone: %s on %s@%s-%d in cxmode: %s\n", tone, p->name, p->parent->name, sub->id, mgcp_cxmodes[sub->cxmode]); } ast_copy_string(p->curtone, tone, sizeof(p->curtone)); 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_offhook(sub, &resp); break; } if (!ast_strlen_zero(tone)) { add_header(&resp, "S", tone); } /* fill in new fields */ resp.cmd = MGCP_CMD_RQNT; resp.trid = oseq; return send_request(p, NULL, &resp, oseq); /* SC */}static int transmit_notify_request_with_callerid(struct mgcp_subchannel *sub, char *tone, char *callernum, char *callername){ struct mgcp_request resp; char tone2[256]; char *l, *n; time_t t; struct tm tm; struct mgcp_endpoint *p = sub->parent; time(&t); ast_localtime(&t, &tm, NULL); n = callername; l = callernum; if (!n) n = ""; if (!l) l = ""; /* Keep track of last callerid for blacklist and callreturn */ ast_copy_string(p->lastcallerid, l, sizeof(p->lastcallerid)); 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); ast_copy_string(p->curtone, tone, sizeof(p->curtone)); 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_offhook(sub, &resp); break; } if (!ast_strlen_zero(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]); } /* 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; if (ast_strlen_zero(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); } reqprep(&resp, p, "MDCX"); add_header(&resp, "C", sub->callid); add_header(&resp, "M", mgcp_cxmodes[sub->cxmode]); /* 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) { case MGCP_ONHOOK: add_header(&resp, "R", "L/hd(N)"); break; case MGCP_OFFHOOK: add_header_offhook(sub, &resp); break; } /* fill in new fields */ resp.cmd = MGCP_CMD_MDCX; resp.trid = oseq; return send_request(p, sub, &resp, oseq); /* SC */}static void add_header_offhook(struct mgcp_subchannel *sub, struct mgcp_request *resp){ struct mgcp_endpoint *p = sub->parent; if (p && p->sub && p->sub->owner && p->sub->owner->_state >= AST_STATE_RINGING && (p->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID))) add_header(resp, "R", "L/hu(N),L/hf(N)"); else add_header(resp, "R", "L/hu(N),L/hf(N),D/[0-9#*](N)");}static int transmit_audit_endpoint(struct mgcp_endpoint *p){ struct mgcp_request resp; reqprep(&resp, p, "AUEP"); /* 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"); /* 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_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); } reqprep(&resp, p, "DLCX"); /* check if call id is avail */ if (sub->callid[0]) add_header(&resp, "C", sub->callid); /* X header should not be sent. kept for compatibility */ add_header(&resp, "X", sub->txident); /* check if cxident is avail */ if (sub->cxident[0]) add_header(&resp, "I", sub->cxident); /* 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 : ""); } reqprep(&resp, p, "DLCX"); /* check if call id is avail */ if (callid && *callid) add_heade
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -