📄 chan_mgcp.c
字号:
transmit_notify_request(sub, "G/rt");#endif break; case AST_CONTROL_BUSY: transmit_notify_request(sub, "L/bz"); break; case AST_CONTROL_CONGESTION: transmit_notify_request(sub, "G/cg"); break; case AST_CONTROL_HOLD: ast_moh_start(ast, data, NULL); break; case AST_CONTROL_UNHOLD: ast_moh_stop(ast); break; case AST_CONTROL_SRCUPDATE: ast_rtp_new_source(sub->rtp); break; case -1: transmit_notify_request(sub, ""); break; default: ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind); res = -1; } 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; int fmt; tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id); if (tmp) { tmp->tech = &mgcp_tech; tmp->nativeformats = i->capability; if (!tmp->nativeformats) tmp->nativeformats = capability; fmt = ast_best_codec(tmp->nativeformats); ast_string_field_build(tmp, name, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id); if (sub->rtp) tmp->fds[0] = ast_rtp_fd(sub->rtp); if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) { i->dsp = ast_dsp_new(); ast_dsp_set_features(i->dsp,DSP_FEATURE_DTMF_DETECT); /* this is to prevent clipping of dtmf tones during dsp processing */ ast_dsp_digitmode(i->dsp, DSP_DIGITMODE_NOQUELCH); } else { i->dsp = NULL; } if (state == AST_STATE_RING) tmp->rings = 1; tmp->writeformat = fmt; tmp->rawwriteformat = fmt; tmp->readformat = fmt; tmp->rawreadformat = fmt; tmp->tech_pvt = sub; if (!ast_strlen_zero(i->language)) ast_string_field_set(tmp, language, i->language); if (!ast_strlen_zero(i->accountcode)) ast_string_field_set(tmp, accountcode, i->accountcode); if (i->amaflags) tmp->amaflags = i->amaflags; sub->owner = tmp; ast_module_ref(ast_module_info->self); tmp->callgroup = i->callgroup; tmp->pickupgroup = i->pickupgroup; ast_string_field_set(tmp, call_forward, i->call_forward); ast_copy_string(tmp->context, i->context, sizeof(tmp->context)); ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten)); /* Don't use ast_set_callerid() here because it will * generate a needless NewCallerID event */ tmp->cid.cid_ani = ast_strdup(i->cid_num); if (!i->adsi) tmp->adsicpe = AST_ADSI_UNAVAILABLE; tmp->priority = 1; if (sub->rtp) ast_jb_configure(tmp, &global_jbconf); if (state != AST_STATE_DOWN) { if (ast_pbx_start(tmp)) { ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name); ast_hangup(tmp); tmp = NULL; } } /* verbose level check */ if (option_verbose > 2) { ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_new(%s) created in state: %s\n", tmp->name, ast_state2str(state)); } } else { ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); } return tmp;}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; return r; } return "";}static char *get_sdp(struct mgcp_request *req, char *name){ int x; int len = strlen(name); char *r; for (x=0; x<req->lines; x++) { r = get_sdp_by_line(req->line[x], name, len); if (r[0] != '\0') return r; } return "";}static void sdpLineNum_iterator_init(int* iterator){ *iterator = 0;}static char* get_sdp_iterate(int* iterator, struct mgcp_request *req, char *name){ int len = strlen(name); char *r; while (*iterator < req->lines) { r = get_sdp_by_line(req->line[(*iterator)++], name, len); if (r[0] != '\0') return r; } return "";}static char *__get_header(struct mgcp_request *req, char *name, int *start){ int x; int len = strlen(name); char *r; for (x=*start;x<req->headers;x++) { if (!strncasecmp(req->header[x], name, len) && (req->header[x][len] == ':')) { r = req->header[x] + len + 1; while(*r && (*r < 33)) r++; *start = x+1; return r; } } /* Don't return NULL, so get_header is always a valid pointer */ return "";}static char *get_header(struct mgcp_request *req, char *name){ int start = 0; return __get_header(req, name, &start);}/*! \brief get_csv: (SC:) get comma separated value */static char *get_csv(char *c, int *len, char **next) { char *s; *next = NULL, *len = 0; if (!c) return NULL; while (*c && (*c < 33 || *c == ',')) c++; s = c; while (*c && (*c >= 33 && *c != ',')) c++, (*len)++; *next = c; if (*len == 0) s = NULL, *next = NULL; return s;}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; struct mgcp_gateway *g; char tmp[256] = ""; char *at = NULL, *c; int found = 0; if (name) { ast_copy_string(tmp, name, sizeof(tmp)); at = strchr(tmp, '@'); if (!at) { ast_log(LOG_NOTICE, "Endpoint '%s' has no at sign!\n", name); return NULL; } *at++ = '\0'; } ast_mutex_lock(&gatelock); if (at && (at[0] == '[')) { at++; c = strrchr(at, ']'); if (c) *c = '\0'; } g = gateways; while(g) { if ((!name || !strcasecmp(g->name, at)) && (sin || g->addr.sin_addr.s_addr || g->defaddr.sin_addr.s_addr)) { /* Found the gateway. If it's dynamic, save it's address -- now for the endpoint */ if (sin && g->dynamic && name) { if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) || (g->addr.sin_port != sin->sin_port)) { memcpy(&g->addr, sin, sizeof(g->addr)); if (ast_ouraddrfor(&g->addr.sin_addr, &g->ourip)) memcpy(&g->ourip, &__ourip, sizeof(g->ourip)); if (option_verbose > 2) 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)); } } /* not dynamic, check if the name matches */ else if (name) { if (strcasecmp(g->name, at)) { g = g->next; continue; } } /* not dynamic, no name, check if the addr matches */ else if (!name && sin) { if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) || (g->addr.sin_port != sin->sin_port)) { g = g->next; continue; } } else { g = g->next; continue; } /* SC */ p = g->endpoints; while(p) { if (option_debug) ast_log(LOG_DEBUG, "Searching on %s@%s for subchannel\n", p->name, g->name); if (msgid) {#if 0 /* new transport mech */ sub = p->sub; do { if (option_debug) ast_log(LOG_DEBUG, "Searching on %s@%s-%d for subchannel with lastout: %d\n", p->name, g->name, sub->id, msgid); if (sub->lastout == msgid) { if (option_debug) ast_log(LOG_DEBUG, "Found subchannel sub%d to handle request %d sub->lastout: %d\n", sub->id, msgid, sub->lastout); found = 1; break; } sub = sub->next; } while (sub != p->sub); if (found) { break; }#endif /* SC */ sub = p->sub; found = 1; /* SC */ break; } else if (name && !strcasecmp(p->name, tmp)) { ast_log(LOG_DEBUG, "Coundn't determine subchannel, assuming current master %s@%s-%d\n", p->name, g->name, p->sub->id); sub = p->sub; found = 1; break; } p = p->next; } if (sub && found) { ast_mutex_lock(&sub->lock); break; } } g = g->next; } ast_mutex_unlock(&gatelock); if (!sub) { if (name) { if (g) ast_log(LOG_NOTICE, "Endpoint '%s' not found on gateway '%s'\n", tmp, at); else ast_log(LOG_NOTICE, "Gateway '%s' (and thus its endpoint '%s') does not exist\n", at, tmp); } } return sub;}static void parse(struct mgcp_request *req){ /* Divide fields by NULL's */ char *c; int f = 0; c = req->data; /* First header starts immediately */ req->header[f] = c; while(*c) { if (*c == '\n') { /* We've got a new header */ *c = 0;#if 0 printf("Header: %s (%d)\n", req->header[f], strlen(req->header[f]));#endif if (ast_strlen_zero(req->header[f])) { /* Line by itself means we're now in content */ c++; break; } if (f >= MGCP_MAX_HEADERS - 1) { ast_log(LOG_WARNING, "Too many MGCP headers...\n"); } else f++; req->header[f] = c + 1; } else if (*c == '\r') { /* Ignore but eliminate \r's */ *c = 0; } c++; } /* Check for last header */ if (!ast_strlen_zero(req->header[f])) f++; req->headers = f; /* Now we process any mime content */ f = 0; req->line[f] = c; while(*c) { if (*c == '\n') { /* We've got a new line */ *c = 0;#if 0 printf("Line: %s (%d)\n", req->line[f], strlen(req->line[f]));#endif if (f >= MGCP_MAX_LINES - 1) { ast_log(LOG_WARNING, "Too many SDP lines...\n"); } else f++; req->line[f] = c + 1; } else if (*c == '\r') { /* Ignore and eliminate \r's */ *c = 0; } c++; } /* Check for last line */ if (!ast_strlen_zero(req->line[f])) f++; req->lines = f; /* Parse up the initial header */ c = req->header[0]; while(*c && *c < 33) c++; /* First the verb */ req->verb = c; while(*c && (*c > 32)) c++; if (*c) { *c = '\0'; c++; while(*c && (*c < 33)) c++; req->identifier = c; while(*c && (*c > 32)) c++; if (*c) { *c = '\0'; c++; while(*c && (*c < 33)) c++; req->endpoint = c; while(*c && (*c > 32)) c++; if (*c) { *c = '\0'; c++; while(*c && (*c < 33)) c++; req->version = c; while(*c && (*c > 32)) c++; while(*c && (*c < 33)) c++; while(*c && (*c > 32)) c++; *c = '\0'; } } } if (mgcpdebug) { ast_verbose("Verb: '%s', Identifier: '%s', Endpoint: '%s', Version: '%s'\n", req->verb, req->identifier, req->endpoint, req->version); ast_verbose("%d headers, %d lines\n", req->headers, req->lines); } if (*c) ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c);}static int process_sdp(struct mgcp_subchannel *sub, struct mgcp_request *req){ char *m; char *c; char *a; char host[258]; int len; int portno; int peercapability, peerNonCodecCapability; struct sockaddr_in sin; char *codecs; struct ast_hostent ahp; struct hostent *hp; int codec, codec_count=0; int iterator; struct mgcp_endpoint *p = sub->parent; /* Get codec and RTP info from SDP */ m = get_sdp(req, "m"); c = get_sdp(req, "c"); if (ast_strlen_zero(m) || ast_strlen_zero(c)) { ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s', c = '%s')\n", m, c); return -1; } if (sscanf(c, "IN IP4 %256s", host) != 1) { ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c); return -1; } /* XXX This could block for a long time, and block the main thread! XXX */ hp = ast_gethostbyname(host, &ahp); if (!hp) { ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c); return -1; } if (sscanf(m, "audio %d RTP/AVP %n", &portno, &len) != 1) { ast_log(LOG_WARNING, "Unable to determine port number for RTP in '%s'\n", m); return -1; } sin.sin_family = AF_INET; memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr)); sin.sin_port = htons(portno); ast_rtp_set_peer(sub->rtp, &sin);#if 0 printf("Peer RTP is at port %s:%d\n", ast_inet_ntoa(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); codecs = ast_strdupa(m + len); while (!ast_strlen_zero(codecs)) { if (sscanf(codecs, "%d%n", &codec, &len) != 1) { if (codec_count) break; ast_log(LOG_WARNING, "Error in codec string '%s' at '%s'\n", m, codecs); return -1; } ast_rtp_set_m_type(sub->rtp, codec); codec_count++; codecs += len; } /* Next, scan through each "a=rtpmap:" line, noting each */ /* specified RTP payload type (with corresponding MIME subtype): */ sdpLineNum_iterator_init(&iterator); while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') { char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */ if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) != 2) continue; /* Note: should really look at the 'freq' and '#chans' params too */ ast_rtp_set_rtpmap_type(sub->rtp, codec, "audio", mimeSubtype, 0); } /* Now gather all of the codecs that were asked for: */ ast_rtp_get_current_formats(sub->rtp, &peercapability, &peerNonCodecCapability);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -