📄 mediaproxy.c
字号:
/* $Id: mediaproxy.c,v 1.23.2.4 2005/07/20 05:45:10 danp Exp $ * * Copyright (C) 2004 Dan Pascu * * This file is part of ser, a free SIP server. * * ser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * ser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */// TODO//// - make the asymmetric files use CFG_DIR// - find a way to install the config files with make install#include "../../sr_module.h"#include "../../dprint.h"#include "../../str.h"#include "../../error.h"#include "../../data_lump.h"#include "../../forward.h"#include "../../mem/mem.h"#include "../../resolve.h"#include "../../timer.h"#include "../../ut.h"#include "../../parser/parse_from.h"#include "../../parser/parse_to.h"#include "../../parser/parse_uri.h"#include "../../msg_translator.h"#include "../registrar/sip_msg.h"#include "../usrloc/usrloc.h"#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <ctype.h>#include <errno.h>#include <regex.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/un.h>MODULE_VERSION// Although `AF_LOCAL' is mandated by POSIX.1g, `AF_UNIX' is portable to// more systems. `AF_UNIX' was the traditional name stemming from BSD, so// even most POSIX systems support it. It is also the name of choice in// the Unix98 specification. So if there's no AF_LOCAL fallback to AF_UNIX#ifndef AF_LOCAL# define AF_LOCAL AF_UNIX#endif#define min(x, y) (((x) < (y)) ? (x) : (y))#define isAnyAddress(adr) ((adr).len==7 && memcmp("0.0.0.0", (adr).s, 7)==0)typedef int Bool;#define True 1#define False 0typedef int (*CheckLocalPartyProc)(struct sip_msg* msg, char* s1, char* s2);typedef Bool (*NatTestProc)(struct sip_msg* msg);typedef enum { NTNone=0, NTPrivateContact=1, NTSourceAddress=2, NTPrivateVia=4} NatTestType;typedef enum { STUnknown=0, STAudio, STVideo, STAudioVideo} StreamType;typedef struct { const char *name; uint32_t address; uint32_t mask;} NetInfo;typedef struct { str ip; str port; str type; // stream type (`audio', `video', ...) int localIP; // true if the IP is locally defined inside this media stream} StreamInfo;typedef struct { NatTestType test; NatTestProc proc;} NatTest;typedef struct { char *file; // the file which lists the asymmetric clients long timestamp; // for checking if it was modified regex_t **clients; // the asymmetric clients regular expressions int size; // size of array above int count; // how many clients are in array above} AsymmetricClients;/* Function prototypes */static int ClientNatTest(struct sip_msg *msg, char *str1, char *str2);static int FixContact(struct sip_msg *msg, char *str1, char *str2);static int UseMediaProxy(struct sip_msg *msg, char *str1, char *str2);static int EndMediaSession(struct sip_msg *msg, char *str1, char *str2);static int mod_init(void);static int fixstring2int(void **param, int param_count);static Bool testPrivateContact(struct sip_msg* msg);static Bool testSourceAddress(struct sip_msg* msg);static Bool testPrivateVia(struct sip_msg* msg);/* Local global variables */static char *mediaproxySocket = "/var/run/proxydispatcher.sock";static int natpingInterval = 60; // 60 secondsstatic usrloc_api_t userLocation;static AsymmetricClients sipAsymmetrics = { "/etc/ser/sip-asymmetric-clients", //CFG_DIR"/sip-asymmetric-clients", 0, NULL, 0, 0};static AsymmetricClients rtpAsymmetrics = { "/etc/ser/rtp-asymmetric-clients", 0, NULL, 0, 0};static CheckLocalPartyProc isFromLocal;//static CheckLocalPartyProc isToLocal;static CheckLocalPartyProc isDestinationLocal;NetInfo rfc1918nets[] = { {"10.0.0.0", 0x0a000000UL, 0xff000000UL}, {"172.16.0.0", 0xac100000UL, 0xfff00000UL}, {"192.168.0.0", 0xc0a80000UL, 0xffff0000UL}, {NULL, 0UL, 0UL}};NatTest natTests[] = { {NTPrivateContact, testPrivateContact}, {NTSourceAddress, testSourceAddress}, {NTPrivateVia, testPrivateVia}, {NTNone, NULL}};static cmd_export_t commands[] = { {"fix_contact", FixContact, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE }, {"use_media_proxy", UseMediaProxy, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE }, {"end_media_session", EndMediaSession, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE }, {"client_nat_test", ClientNatTest, 1, fixstring2int, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE }, {0, 0, 0, 0, 0}};static param_export_t parameters[] = { {"mediaproxy_socket", STR_PARAM, &mediaproxySocket}, {"sip_asymmetrics", STR_PARAM, &(sipAsymmetrics.file)}, {"rtp_asymmetrics", STR_PARAM, &(rtpAsymmetrics.file)}, {"natping_interval", INT_PARAM, &natpingInterval}, {0, 0, 0}};struct module_exports exports = { "mediaproxy", // module name commands, // module exported functions parameters, // module exported parameters mod_init, // module init (before any kid is created. kids will inherit) NULL, // reply processing NULL, // destroy function NULL, // on_break NULL // child_init};/* Helper functions */// Functions dealing with strings/* * strfind() finds the start of the first occurrence of the substring needle * of length nlen in the memory area haystack of length len. */static void*strfind(const void *haystack, size_t len, const void *needle, size_t nlen){ char *sp; /* Sanity check */ if(!(haystack && needle && nlen && len>=nlen)) return NULL; for (sp = (char*)haystack; sp <= (char*)haystack + len - nlen; sp++) { if (*sp == *(char*)needle && memcmp(sp, needle, nlen)==0) { return sp; } } return NULL;}/* * strcasefind() finds the start of the first occurrence of the substring * needle of length nlen in the memory area haystack of length len by doing * a case insensitive search */static void*strcasefind(const char *haystack, size_t len, const char *needle, size_t nlen){ char *sp; /* Sanity check */ if(!(haystack && needle && nlen && len>=nlen)) return NULL; for (sp = (char*)haystack; sp <= (char*)haystack + len - nlen; sp++) { if (tolower(*sp) == tolower(*(char*)needle) && strncasecmp(sp, needle, nlen)==0) { return sp; } } return NULL;}/* returns string with whitespace trimmed from left end */static inline voidltrim(str *string){ while (string->len>0 && isspace((int)*(string->s))) { string->len--; string->s++; }}/* returns string with whitespace trimmed from right end */static inline voidrtrim(str *string){ char *ptr; ptr = string->s + string->len - 1; while (string->len>0 && (*ptr==0 || isspace((int)*ptr))) { string->len--; ptr--; }}/* returns string with whitespace trimmed from both ends */static inline voidtrim(str *string){ ltrim(string); rtrim(string);}/* returns a pointer to first CR or LF char found or the end of string */static char*findendline(char *string, int len){ char *ptr = string; while(ptr - string < len && *ptr != '\n' && *ptr != '\r') ptr++; return ptr;}static intstrtoint(str *data){ long int result; char c; // hack to avoid copying the string c = data->s[data->len]; data->s[data->len] = 0; result = strtol(data->s, NULL, 10); data->s[data->len] = c; return (int)result;}/* Free the returned string with pkg_free() after you've done with it */static char*encodeQuopri(str buf){ char *result; int i, j; char c; result = pkg_malloc(buf.len*3+1); if (!result) { LOG(L_ERR, "error: mediaproxy/encodeQuopri(): out of memory\n"); return NULL; } for (i=0, j=0; i<buf.len; i++) { c = buf.s[i]; if ((c>0x20 && c<0x7f && c!='=') || c=='\n' || c=='\r') { result[j++] = c; } else { result[j++] = '='; sprintf(&result[j], "%02X", (c & 0xff)); j += 2; } } result[j] = 0; return result;}/* Find a line in str `block' that starts with `start'. */static char*findLineStartingWith(str *block, char *start, int ignoreCase){ char *ptr, *bend; str zone; int tlen; bend = block->s + block->len; tlen = strlen(start); ptr = NULL; for (zone = *block; zone.len > 0; zone.len = bend - zone.s) { if (ignoreCase) ptr = strcasefind(zone.s, zone.len, start, tlen); else ptr = strfind(zone.s, zone.len, start, tlen); if (!ptr || ptr==zone.s || ptr[-1]=='\n' || ptr[-1]=='\r') break; zone.s = ptr + tlen; } return ptr;}/* get up to `limit' whitespace separated tokens from `char *string' */static intgetTokens(char *string, str *tokens, int limit){ int i, len, size; char *ptr; if (!string) { return 0; } len = strlen(string); for (ptr=string, i=0; i<limit && len>0; i++) { size = strspn(ptr, " \t\n\r"); ptr += size; len -= size; if (len <= 0) break; size = strcspn(ptr, " \t\n\r"); if (size==0) break; tokens[i].s = ptr; tokens[i].len = size; ptr += size; len -= size; } return i;}/* get up to `limit' whitespace separated tokens from `str *string' */static intgetStrTokens(str *string, str *tokens, int limit){ int count; char c; if (!string || !string->s) { return 0; } c = string->s[string->len]; string->s[string->len] = 0; count = getTokens(string->s, tokens, limit); string->s[string->len] = c; return count;}/* Functions to extract the info we need from the SIP/SDP message *//* Extract Call-ID value. */static BoolgetCallId(struct sip_msg* msg, str *cid){ if (msg->callid == NULL) { if (parse_headers(msg, HDR_CALLID, 0) == -1) { return False; } if (msg->callid == NULL) { return False; } } *cid = msg->callid->body; trim(cid); return True;}/* Get caller domain */static strgetFromDomain(struct sip_msg* msg){ static char buf[16] = "unknown"; // buf is here for a reason. don't static str notfound = {buf, 7}; // use the constant string directly! static struct sip_uri puri; str uri; if (parse_from_header(msg) < 0) { LOG(L_ERR, "error: mediaproxy/getFromDomain(): error parsing `From' header\n"); return notfound; } uri = get_from(msg)->uri; if (parse_uri(uri.s, uri.len, &puri) < 0) { LOG(L_ERR, "error: mediaproxy/getFromDomain(): error parsing `From' URI\n"); return notfound; } else if (puri.host.len == 0) { return notfound; } return puri.host;}/* Get called domain */static strgetToDomain(struct sip_msg* msg){ static char buf[16] = "unknown"; // buf is here for a reason. don't static str notfound = {buf, 7}; // use the constant string directly! static struct sip_uri puri; str uri; uri = get_to(msg)->uri; if (parse_uri(uri.s, uri.len, &puri) < 0) { LOG(L_ERR, "error: mediaproxy/getToDomain(): error parsing `To' URI\n"); return notfound; } else if (puri.host.len == 0) { return notfound; } return puri.host;}/* Get destination domain */// This function only works when called for a request although it's more// reliable than the getToDomain function.static strgetDestinationDomain(struct sip_msg* msg){ static char buf[16] = "unknown"; // buf is here for a reason. don't static str notfound = {buf, 7}; // use the constant string directly! if (parse_sip_msg_uri(msg) < 0) { LOG(L_ERR, "error: mediaproxy/getDestinationDomain(): error parsing destination URI\n"); return notfound; } else if (msg->parsed_uri.host.len==0) { return notfound; } return msg->parsed_uri.host;}/* Get From tag */static strgetFromAddress(struct sip_msg *msg){ static char buf[16] = "unknown"; // buf is here for a reason. don't static str notfound = {buf, 7}; // use the constant string directly! str uri; char *ptr; if (parse_from_header(msg) == -1) { LOG(L_ERR, "error: mediaproxy/getFromAddress(): error parsing From: field\n"); return notfound;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -