📄 mediaproxy.c
字号:
// initial size of array // (hopefully not reached so we won't need to realloc) size = 32; aptr->clients = (regex_t**)pkg_malloc(size*sizeof(regex_t**)); if (!aptr->clients) { LOG(L_WARN, "warning: mediaproxy/checkAsymmetricFile() cannot " "allocate memory for the %s asymmetric client list. " "%s asymmetric clients will not be handled properly.\n", which, which); return; // ignore as it is not fatal } aptr->size = size; aptr->count = 0; firstTime = True; } else { // else clean old stuff for (i=0; i<aptr->count; i++) { regfree(aptr->clients[i]); pkg_free(aptr->clients[i]); aptr->clients[i] = NULL; } aptr->count = 0; } // read new file = fopen(aptr->file, "r"); i = 0; // this will count on which line are we in the file while (!feof(file)) { if (!fgets(buf, 512, file)) break; i++; line.s = buf; line.len = strlen(buf); trim(&line); if (line.len == 0 || line.s[0] == '#') continue; // comment or empty line. ignore line.s[line.len] = 0; re = (regex_t*)pkg_malloc(sizeof(regex_t)); if (!re) { LOG(L_WARN, "warning: mediaproxy/checkAsymmetricFile(): " "cannot allocate memory for all the %s asymmetric " "clients listed in file. Some of them will not be " "handled properly.\n", which); break; } code = regcomp(re, line.s, REG_EXTENDED|REG_ICASE|REG_NOSUB); if (code == 0) { if (aptr->count+1 > aptr->size) { size = aptr->size * 2; regs = aptr->clients; regs = (regex_t**)pkg_realloc(regs, size*sizeof(regex_t**)); if (!regs) { LOG(L_WARN, "warning: mediaproxy/checkAsymmetricFile(): " "cannot allocate memory for all the %s asymmetric " "clients listed in file. Some of them will not be " "handled properly.\n", which); break; } aptr->clients = regs; aptr->size = size; } aptr->clients[aptr->count] = re; aptr->count++; } else { regerror(code, re, errbuf, 256); LOG(L_WARN, "warning: mediaproxy/checkAsymmetricFile(): cannot " "compile line %d of the %s asymmetric clients file into a " "regular expression (will be ignored): %s", i, which, errbuf); pkg_free(re); } } aptr->timestamp = statbuf.st_mtime; LOG(L_INFO, "info: mediaproxy: %sloaded %s asymmetric clients file " "containing %d entr%s.\n", firstTime ? "" : "re", which, aptr->count, aptr->count==1 ? "y" : "ies");}//// This is a hack. Until a I find a better way to allow all children to update// the asymmetric client list when the files change on disk, it stays as it is// A timer registered from mod_init() only runs in one of the ser processes// and the others will always see the file that was read at startup.//#include <time.h>#define CHECK_INTERVAL 5static voidperiodicAsymmetricsCheck(void){ static time_t last = 0; time_t now; // this is not guaranteed to run at every CHECK_INTERVAL. // it is only guaranteed that the files won't be checked more often. now = time(NULL); if (now > last + CHECK_INTERVAL) { checkAsymmetricFile(&sipAsymmetrics); checkAsymmetricFile(&rtpAsymmetrics); last = now; }}static BoolisSIPAsymmetric(str userAgent){ int i, code; char c; periodicAsymmetricsCheck(); if (!sipAsymmetrics.clients || sipAsymmetrics.count==0) return False; c = userAgent.s[userAgent.len]; userAgent.s[userAgent.len] = 0; for (i=0; i<sipAsymmetrics.count; i++) { code = regexec(sipAsymmetrics.clients[i], userAgent.s, 0, NULL, 0); if (code == 0) { userAgent.s[userAgent.len] = c; return True; } else if (code != REG_NOMATCH) { char errbuf[256]; regerror(code, sipAsymmetrics.clients[i], errbuf, 256); LOG(L_WARN, "warning: mediaproxy/isSIPAsymmetric() failed to " "match regexp: %s\n", errbuf); } } userAgent.s[userAgent.len] = c; return False;}static BoolisRTPAsymmetric(str userAgent){ int i, code; char c; periodicAsymmetricsCheck(); if (!rtpAsymmetrics.clients || rtpAsymmetrics.count==0) return False; c = userAgent.s[userAgent.len]; userAgent.s[userAgent.len] = 0; for (i=0; i<rtpAsymmetrics.count; i++) { code = regexec(rtpAsymmetrics.clients[i], userAgent.s, 0, NULL, 0); if (code == 0) { userAgent.s[userAgent.len] = c; return True; } else if (code != REG_NOMATCH) { char errbuf[256]; regerror(code, rtpAsymmetrics.clients[i], errbuf, 256); LOG(L_WARN, "warning: mediaproxy/isRTPAsymmetric() failed to " "match regexp: %s\n", errbuf); } } userAgent.s[userAgent.len] = c; return False;}// NAT tests/* tests if address of signaling is different from address in 1st Via field */static BooltestSourceAddress(struct sip_msg* msg){ Bool diffIP, diffPort; int via1Port; diffIP = received_test(msg); if (isSIPAsymmetric(getUserAgent(msg))) { // ignore port test for asymmetric clients (it's always different) diffPort = False; } else { via1Port = (msg->via1->port ? msg->via1->port : SIP_PORT); diffPort = (msg->rcv.src_port != via1Port); } return (diffIP || diffPort);}/* tests if Contact field contains a private IP address as defined in RFC1918 */static BooltestPrivateContact(struct sip_msg* msg){ struct sip_uri uri; contact_t* contact; if (!getContactURI(msg, &uri, &contact)) return False; return isPrivateAddress(&(uri.host));}/* tests if top Via field contains a private IP address as defined in RFC1918 */static BooltestPrivateVia(struct sip_msg* msg){ return isPrivateAddress(&(msg->via1->host));}#include "functions.h"/* The public functions that are exported by this module */static intClientNatTest(struct sip_msg* msg, char* str1, char* str2){ int tests, i; tests = (int)(long)str1; for (i=0; natTests[i].test!=NTNone; i++) { if ((tests & natTests[i].test)!=0 && natTests[i].proc(msg)) { return 1; } } return -1; // all failed}static intEndMediaSession(struct sip_msg* msg, char* str1, char* str2){ char *command, *result; str callId; if (!getCallId(msg, &callId)) { LOG(L_ERR, "error: end_media_session(): can't get Call-Id\n"); return -1; } command = pkg_malloc(callId.len + 20); if (command == NULL) { LOG(L_ERR, "error: end_media_session(): out of memory\n"); return -1; } sprintf(command, "delete %.*s info=\n", callId.len, callId.s); result = sendMediaproxyCommand(command); pkg_free(command); return result==NULL ? -1 : 1;}#define MSG_UNKNOWN 0#define MSG_INVITE 1#define MSG_ACK 2#define MSG_REPLY 3static intUseMediaProxy(struct sip_msg* msg, char* str1, char* str2){ str sdp, sessionIP, callId, fromDomain, toDomain, userAgent, tokens[64]; str fromAddr, toAddr, fromTag, toTag; char *clientIP, *ptr, *command, *result, *agent, *fromType, *toType, *info; int streamCount, i, port, count, portCount, cmdlen, infolen, success, type; StreamInfo streams[64], stream; Bool request; if (msg->first_line.type == SIP_REQUEST) { if (msg->first_line.u.request.method_value == METHOD_INVITE) type = MSG_INVITE; else if (msg->first_line.u.request.method_value == METHOD_ACK) type = MSG_ACK; else type = MSG_UNKNOWN; } else if (msg->first_line.type == SIP_REPLY) { type = MSG_REPLY; } else { type = MSG_UNKNOWN; } if (type==MSG_INVITE || type==MSG_ACK) { request = True; } else if (type==MSG_REPLY) { request = False; } else { return -1; } if (!getCallId(msg, &callId)) { LOG(L_ERR, "error: use_media_proxy(): can't get Call-Id\n"); return -1; } success = getSDPMessage(msg, &sdp); if (success==0 && type==MSG_ACK) { return 1; // nothing to do. it's ok for ACK to not have a SDP body } else if (success <= 0) { LOG(L_ERR, "error: use_media_proxy(): failed to get the SDP message\n"); return -1; } if (!getSessionLevelMediaIP(&sdp, &sessionIP)) { LOG(L_ERR, "error: use_media_proxy(): error parsing the SDP message\n"); return -1; } streamCount = getMediaStreams(&sdp, &sessionIP, streams, 64); if (streamCount == -1) { LOG(L_ERR, "error: use_media_proxy(): can't extract media streams " "from the SDP message\n"); return -1; } if (streamCount == 0) { // there are no media streams. we have nothing to do. return 1; } fromDomain = getFromDomain(msg); fromType = (isFromLocal(msg, NULL, NULL)>0) ? "local" : "remote"; fromAddr = getFromAddress(msg); toAddr = getToAddress(msg); fromTag = getFromTag(msg); toTag = getToTag(msg); userAgent = getUserAgent(msg); if (request) { toDomain = getDestinationDomain(msg); // call only for requests toType = (isDestinationLocal(msg, NULL, NULL)>0) ? "local" : "remote"; } else { toDomain = getToDomain(msg); toType = "unknown"; //there's no function to check if To domain is local } clientIP = ip_addr2a(&msg->rcv.src_ip); infolen = fromAddr.len + toAddr.len + fromTag.len + toTag.len + 64; cmdlen = callId.len + strlen(clientIP) + fromDomain.len + toDomain.len + userAgent.len*3 + infolen + 128; for (i=0; i<streamCount; i++) { stream = streams[i]; cmdlen += stream.ip.len + stream.port.len + stream.type.len + 4; } command = pkg_malloc(cmdlen); if (!command) { LOG(L_ERR, "error: use_media_proxy(): out of memory\n"); return -1; } if (request) count = sprintf(command, "request %.*s", callId.len, callId.s); else count = sprintf(command, "lookup %.*s", callId.len, callId.s); for (i=0, ptr=command+count; i<streamCount; i++) { char c = (i==0 ? ' ' : ','); count = sprintf(ptr, "%c%.*s:%.*s:%.*s", c, streams[i].ip.len, streams[i].ip.s, streams[i].port.len, streams[i].port.s, streams[i].type.len, streams[i].type.s); ptr += count; } agent = encodeQuopri(userAgent); if (!agent) { LOG(L_ERR, "error: use_media_proxy(): out of memory\n"); pkg_free(command); return -1; } info = pkg_malloc(infolen); if (!info) { LOG(L_ERR, "error: use_media_proxy(): out of memory\n"); pkg_free(command); pkg_free(agent); return -1; } sprintf(info, "from:%.*s,to:%.*s,fromtag:%.*s,totag:%.*s", fromAddr.len, fromAddr.s, toAddr.len, toAddr.s, fromTag.len, fromTag.s, toTag.len, toTag.s); if (isRTPAsymmetric(userAgent)) { strcat(info, ",asymmetric"); } snprintf(ptr, command + cmdlen - ptr, " %s %.*s %s %.*s %s %s info=%s\n", clientIP, fromDomain.len, fromDomain.s, fromType, toDomain.len, toDomain.s, toType, agent, info); pkg_free(info); pkg_free(agent); result = sendMediaproxyCommand(command); pkg_free(command); if (result == NULL) return -1; count = getTokens(result, tokens, sizeof(tokens)/sizeof(str)); if (count == 0) { LOG(L_ERR, "error: use_media_proxy(): empty response from mediaproxy\n"); return -1; } else if (count<streamCount+1) { if (request) { LOG(L_ERR, "error: use_media_proxy(): insufficient ports returned " "from mediaproxy: got %d, expected %d\n", count-1, streamCount); return -1; } else { LOG(L_WARN, "warning: use_media_proxy(): broken client. Called UA " "added extra media stream(s) in the OK reply\n"); } } if (sessionIP.s && !isAnyAddress(sessionIP)) { success = replaceElement(msg, &sessionIP, &tokens[0]); if (!success) { LOG(L_ERR, "error: use_media_proxy(): failed to replace " "session-level media IP in SDP body\n"); return -1; } } portCount = min(count-1, streamCount); for (i=0; i<portCount; i++) { // check. is this really necessary? port = strtoint(&tokens[i+1]); if (port <= 0 || port > 65535) { LOG(L_ERR, "error: use_media_proxy(): invalid port returned " "by mediaproxy: %.*s\n", tokens[i+1].len, tokens[i+1].s); //return -1; continue; } if (streams[i].port.len!=1 || streams[i].port.s[0]!='0') { success = replaceElement(msg, &(streams[i].port), &tokens[i+1]); if (!success) { LOG(L_ERR, "error: use_media_proxy(): failed to replace " "port in media stream nr. %d\n", i+1); return -1; } } if (streams[i].localIP && !isAnyAddress(streams[i].ip)) { success = replaceElement(msg, &(streams[i].ip), &tokens[0]); if (!success) { LOG(L_ERR, "error: use_media_proxy(): failed to replace " "IP address in media stream nr. %d\n", i+1); return -1; } } } return 1;}/* Module management: initialization/destroy/function-parameter-fixing/... */static intmod_init(void){ bind_usrloc_t ul_bind_usrloc; isFromLocal = (CheckLocalPartyProc)find_export("is_from_local", 0, 0); isDestinationLocal = (CheckLocalPartyProc)find_export("is_uri_host_local", 0, 0); if (!isFromLocal || !isDestinationLocal) { LOG(L_ERR, "error: mediaproxy/mod_init(): can't find is_from_local " "and/or is_uri_host_local functions. Check if domain.so is loaded\n"); return -1; } if (natpingInterval > 0) { ul_bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0); if (!ul_bind_usrloc) { LOG(L_ERR, "error: mediaproxy/mod_init(): can't find the usrloc " "module. Check if usrloc.so is loaded.\n"); return -1; } if (ul_bind_usrloc(&userLocation) < 0) { LOG(L_ERR, "error: mediaproxy/mod_init(): can't access the usrloc module.\n"); return -1; } register_timer(pingClients, NULL, natpingInterval); } checkAsymmetricFile(&sipAsymmetrics); checkAsymmetricFile(&rtpAsymmetrics); // children won't benefit from this. figure another way //register_timer(checkAsymmetricFiles, NULL, 5); return 0;}// convert string parameter to integer for functions that expect an integerstatic intfixstring2int(void **param, int param_count){ unsigned long number; int err; if (param_count == 1) { number = str2s(*param, strlen(*param), &err); if (err == 0) { pkg_free(*param); *param = (void*)number; return 0; } else { LOG(L_ERR, "error: mediaproxy/fixstring2int(): bad number `%s'\n", (char*)(*param)); return E_CFG; } } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -