mediaproxy.c 59 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122
  1. /*
  2. * Copyright (C) 2004-2008 Dan Pascu
  3. * Copyright (C) 2009 Juha Heinanen (multipart hack)
  4. *
  5. * This file is part of SIP-Router, a free SIP server.
  6. *
  7. * SIP-router is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version
  11. *
  12. * SIP-router is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. */
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <unistd.h>
  24. #include <string.h>
  25. #include <time.h>
  26. #include <ctype.h>
  27. #include <errno.h>
  28. #include <arpa/inet.h>
  29. #include <sys/time.h>
  30. #include <sys/types.h>
  31. #include <sys/socket.h>
  32. #include <sys/select.h>
  33. #include <sys/un.h>
  34. #include "../../sr_module.h"
  35. #include "../../dprint.h"
  36. #include "../../str.h"
  37. #include "../../pvar.h"
  38. #include "../../error.h"
  39. #include "../../data_lump.h"
  40. #include "../../mem/mem.h"
  41. #include "../../ut.h"
  42. #include "../../parser/msg_parser.h"
  43. #include "../../parser/parse_from.h"
  44. #include "../../parser/parse_to.h"
  45. #include "../../parser/parse_param.h"
  46. #include "../../msg_translator.h"
  47. #include "../../modules/dialog/dlg_load.h"
  48. #include "../../modules/dialog/dlg_hash.h"
  49. MODULE_VERSION
  50. #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
  51. # define INLINE inline
  52. #else
  53. # define INLINE
  54. #endif
  55. /* WARNING: Keep this aligned with parser/msg_parser.h! */
  56. #define FL_USE_MEDIA_PROXY (1<<30)
  57. #define SIGNALING_IP_AVP_SPEC "$avp(s:signaling_ip)"
  58. #define MEDIA_RELAY_AVP_SPEC "$avp(s:media_relay)"
  59. #define ICE_CANDIDATE_AVP_SPEC "$avp(s:ice_candidate)"
  60. #define NO_CANDIDATE -1
  61. // Although `AF_LOCAL' is mandated by POSIX.1g, `AF_UNIX' is portable to
  62. // more systems. `AF_UNIX' was the traditional name stemming from BSD, so
  63. // even most POSIX systems support it. It is also the name of choice in
  64. // the Unix98 specification. So if there's no AF_LOCAL fallback to AF_UNIX
  65. #ifndef AF_LOCAL
  66. # define AF_LOCAL AF_UNIX
  67. #endif
  68. // As Solaris does not have the MSG_NOSIGNAL flag for send(2) syscall,
  69. // it is defined as 0
  70. #ifndef MSG_NOSIGNAL
  71. # define MSG_NOSIGNAL 0
  72. #endif
  73. #define isnulladdr(adr) ((adr).len==7 && memcmp("0.0.0.0", (adr).s, 7)==0)
  74. #define isnullport(port) ((port).len==1 && (port).s[0]=='0')
  75. #define STR_MATCH(str, buf) ((str).len==strlen(buf) && memcmp(buf, (str).s, (str).len)==0)
  76. #define STR_IMATCH(str, buf) ((str).len==strlen(buf) && strncasecmp(buf, (str).s, (str).len)==0)
  77. #define STR_HAS_PREFIX(str, prefix) ((str).len>=(prefix).len && memcmp((prefix).s, (str).s, (prefix).len)==0)
  78. #define STR_HAS_IPREFIX(str, prefix) ((str).len>=(prefix).len && strncasecmp((prefix).s, (str).s, (prefix).len)==0)
  79. typedef int Bool;
  80. #define True 1
  81. #define False 0
  82. typedef Bool (*NatTestFunction)(struct sip_msg *msg);
  83. typedef enum {
  84. TNone=0,
  85. TSupported,
  86. TUnsupported
  87. } TransportType;
  88. #define RETRY_INTERVAL 10
  89. #define BUFFER_SIZE 8192
  90. typedef struct MediaproxySocket {
  91. char *name; // name
  92. int sock; // socket
  93. int timeout; // how many miliseconds to wait for an answer
  94. time_t last_failure; // time of the last failure
  95. char data[BUFFER_SIZE]; // buffer for the answer data
  96. } MediaproxySocket;
  97. typedef struct {
  98. const char *name;
  99. uint32_t address;
  100. uint32_t mask;
  101. } NetInfo;
  102. typedef struct {
  103. str type; // stream type (`audio', `video', `image', ...)
  104. str ip;
  105. str port;
  106. str rtcp_ip; // pointer to the rtcp IP if explicitly specified by stream
  107. str rtcp_port; // pointer to the rtcp port if explicitly specified by stream
  108. str direction;
  109. Bool local_ip; // true if the IP is locally defined inside this media stream
  110. Bool has_ice;
  111. Bool has_rtcp_ice;
  112. TransportType transport;
  113. char *start_line;
  114. char *next_line;
  115. char *first_ice_candidate;
  116. } StreamInfo;
  117. #define MAX_STREAMS 32
  118. typedef struct SessionInfo {
  119. str ip;
  120. str ip_line; // pointer to the whole session level ip line
  121. str direction;
  122. str separator;
  123. StreamInfo streams[MAX_STREAMS];
  124. unsigned int stream_count;
  125. unsigned int supported_count;
  126. } SessionInfo;
  127. typedef struct AVP_Param {
  128. str spec;
  129. int_str name;
  130. unsigned short type;
  131. } AVP_Param;
  132. typedef struct ice_candidate_data {
  133. unsigned int priority;
  134. Bool skip_next_reply;
  135. } ice_candidate_data;
  136. // Function prototypes
  137. //
  138. static int EngageMediaProxy(struct sip_msg *msg);
  139. static int UseMediaProxy(struct sip_msg *msg);
  140. static int EndMediaSession(struct sip_msg *msg);
  141. static int mod_init(void);
  142. static int child_init(int rank);
  143. // Module global variables and state
  144. //
  145. static int mediaproxy_disabled = False;
  146. static str ice_candidate = str_init("none");
  147. static MediaproxySocket mediaproxy_socket = {
  148. "/var/run/mediaproxy/dispatcher.sock", // name
  149. -1, // sock
  150. 500, // timeout in 500 miliseconds if there is no answer
  151. 0, // time of the last failure
  152. "" // data
  153. };
  154. struct dlg_binds dlg_api;
  155. Bool have_dlg_api = False;
  156. static int dialog_flag = -1;
  157. // The AVP where the caller signaling IP is stored (if defined)
  158. static AVP_Param signaling_ip_avp = {str_init(SIGNALING_IP_AVP_SPEC), {0}, 0};
  159. // The AVP where the application-defined media relay IP is stored
  160. static AVP_Param media_relay_avp = {str_init(MEDIA_RELAY_AVP_SPEC), {0}, 0};
  161. // The AVP where the ICE candidate priority is stored (if defined)
  162. static AVP_Param ice_candidate_avp = {str_init(ICE_CANDIDATE_AVP_SPEC), {0}, 0};
  163. static cmd_export_t commands[] = {
  164. {"engage_media_proxy", (cmd_function)EngageMediaProxy, 0, 0, 0, REQUEST_ROUTE},
  165. {"use_media_proxy", (cmd_function)UseMediaProxy, 0, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | LOCAL_ROUTE},
  166. {"end_media_session", (cmd_function)EndMediaSession, 0, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | LOCAL_ROUTE},
  167. {0, 0, 0, 0, 0, 0}
  168. };
  169. static param_export_t parameters[] = {
  170. {"disable", INT_PARAM, &mediaproxy_disabled},
  171. {"mediaproxy_socket", STR_PARAM, &(mediaproxy_socket.name)},
  172. {"mediaproxy_timeout", INT_PARAM, &(mediaproxy_socket.timeout)},
  173. {"signaling_ip_avp", STR_PARAM, &(signaling_ip_avp.spec.s)},
  174. {"media_relay_avp", STR_PARAM, &(media_relay_avp.spec.s)},
  175. {"ice_candidate", STR_PARAM, &(ice_candidate.s)},
  176. {"ice_candidate_avp", STR_PARAM, &(ice_candidate_avp.spec.s)},
  177. {0, 0, 0}
  178. };
  179. struct module_exports exports = {
  180. "mediaproxy", // module name
  181. DEFAULT_DLFLAGS, // dlopen flags
  182. commands, // exported functions
  183. parameters, // exported parameters
  184. NULL, // exported statistics
  185. NULL, // exported MI functions
  186. NULL, // exported pseudo-variables
  187. NULL, // extra processes
  188. mod_init, // module init function (before fork. kids will inherit)
  189. NULL, // reply processing function
  190. NULL, // destroy function
  191. child_init // child init function
  192. };
  193. // String processing functions
  194. //
  195. // strfind() finds the start of the first occurrence of the substring needle
  196. // of length nlen in the memory area haystack of length len.
  197. static void*
  198. strfind(const void *haystack, size_t len, const void *needle, size_t nlen)
  199. {
  200. char *sp;
  201. // Sanity check
  202. if(!(haystack && needle && nlen && len>=nlen))
  203. return NULL;
  204. for (sp = (char*)haystack; sp <= (char*)haystack + len - nlen; sp++) {
  205. if (*sp == *(char*)needle && memcmp(sp, needle, nlen)==0) {
  206. return sp;
  207. }
  208. }
  209. return NULL;
  210. }
  211. // strcasefind() finds the start of the first occurrence of the substring
  212. // needle of length nlen in the memory area haystack of length len by doing
  213. // a case insensitive search
  214. static void*
  215. strcasefind(const char *haystack, size_t len, const char *needle, size_t nlen)
  216. {
  217. char *sp;
  218. // Sanity check
  219. if(!(haystack && needle && nlen && len>=nlen))
  220. return NULL;
  221. for (sp = (char*)haystack; sp <= (char*)haystack + len - nlen; sp++) {
  222. if (tolower(*sp) == tolower(*(char*)needle) &&
  223. strncasecmp(sp, needle, nlen)==0) {
  224. return sp;
  225. }
  226. }
  227. return NULL;
  228. }
  229. // returns string with whitespace trimmed from left end
  230. static INLINE void
  231. ltrim(str *string)
  232. {
  233. while (string->len>0 && isspace((int)*(string->s))) {
  234. string->len--;
  235. string->s++;
  236. }
  237. }
  238. // returns string with whitespace trimmed from right end
  239. static INLINE void
  240. rtrim(str *string)
  241. {
  242. char *ptr;
  243. ptr = string->s + string->len - 1;
  244. while (string->len>0 && (*ptr==0 || isspace((int)*ptr))) {
  245. string->len--;
  246. ptr--;
  247. }
  248. }
  249. // returns string with whitespace trimmed from both ends
  250. static INLINE void
  251. trim(str *string)
  252. {
  253. ltrim(string);
  254. rtrim(string);
  255. }
  256. // returns a pointer to first CR or LF char found or the end of string
  257. static char*
  258. findendline(char *string, int len)
  259. {
  260. char *ptr = string;
  261. while(ptr - string < len && *ptr != '\n' && *ptr != '\r')
  262. ptr++;
  263. return ptr;
  264. }
  265. static int
  266. strtoint(str *data)
  267. {
  268. long int result;
  269. char c;
  270. // hack to avoid copying the string
  271. c = data->s[data->len];
  272. data->s[data->len] = 0;
  273. result = strtol(data->s, NULL, 10);
  274. data->s[data->len] = c;
  275. return (int)result;
  276. }
  277. // find a line in str `block' that starts with `start'.
  278. static char*
  279. find_line_starting_with(str *block, char *start, int ignoreCase)
  280. {
  281. char *ptr, *bend;
  282. str zone;
  283. int tlen;
  284. bend = block->s + block->len;
  285. tlen = strlen(start);
  286. ptr = NULL;
  287. for (zone = *block; zone.len > 0; zone.len = bend - zone.s) {
  288. if (ignoreCase)
  289. ptr = strcasefind(zone.s, zone.len, start, tlen);
  290. else
  291. ptr = strfind(zone.s, zone.len, start, tlen);
  292. if (!ptr || ptr==block->s || ptr[-1]=='\n' || ptr[-1]=='\r')
  293. break;
  294. zone.s = ptr + tlen;
  295. }
  296. return ptr;
  297. }
  298. // count all lines in str `block' that starts with `start'.
  299. static unsigned int
  300. count_lines_starting_with(str *block, char *start, int ignoreCase)
  301. {
  302. char *ptr, *bend;
  303. str zone;
  304. int tlen;
  305. unsigned count;
  306. bend = block->s + block->len;
  307. tlen = strlen(start);
  308. count = 0;
  309. for (zone = *block; zone.len > 0; zone.len = bend - zone.s) {
  310. if (ignoreCase)
  311. ptr = strcasefind(zone.s, zone.len, start, tlen);
  312. else
  313. ptr = strfind(zone.s, zone.len, start, tlen);
  314. if (!ptr)
  315. break;
  316. if (ptr==block->s || ptr[-1]=='\n' || ptr[-1]=='\r')
  317. count++;
  318. zone.s = ptr + tlen;
  319. }
  320. return count;
  321. }
  322. // get up to `limit' whitespace separated tokens from `char *string'
  323. static int
  324. get_tokens(char *string, str *tokens, int limit)
  325. {
  326. int i, len, size;
  327. char *ptr;
  328. if (!string) {
  329. return 0;
  330. }
  331. len = strlen(string);
  332. for (ptr=string, i=0; i<limit && len>0; i++) {
  333. size = strspn(ptr, " \t\n\r");
  334. ptr += size;
  335. len -= size;
  336. if (len <= 0)
  337. break;
  338. size = strcspn(ptr, " \t\n\r");
  339. if (size==0)
  340. break;
  341. tokens[i].s = ptr;
  342. tokens[i].len = size;
  343. ptr += size;
  344. len -= size;
  345. }
  346. return i;
  347. }
  348. // get up to `limit' whitespace separated tokens from `str *string'
  349. static int
  350. get_str_tokens(str *string, str *tokens, int limit)
  351. {
  352. int count;
  353. char c;
  354. if (!string || !string->s) {
  355. return 0;
  356. }
  357. c = string->s[string->len];
  358. string->s[string->len] = 0;
  359. count = get_tokens(string->s, tokens, limit);
  360. string->s[string->len] = c;
  361. return count;
  362. }
  363. // Functions to extract the info we need from the SIP/SDP message
  364. //
  365. static Bool
  366. get_callid(struct sip_msg* msg, str *cid)
  367. {
  368. if (msg->callid == NULL) {
  369. if (parse_headers(msg, HDR_CALLID_F, 0) == -1) {
  370. LM_ERR("cannot parse Call-ID header\n");
  371. return False;
  372. }
  373. if (msg->callid == NULL) {
  374. LM_ERR("missing Call-ID header\n");
  375. return False;
  376. }
  377. }
  378. *cid = msg->callid->body;
  379. trim(cid);
  380. return True;
  381. }
  382. static Bool
  383. get_cseq_number(struct sip_msg *msg, str *cseq)
  384. {
  385. if (msg->cseq == NULL) {
  386. if (parse_headers(msg, HDR_CSEQ_F, 0)==-1) {
  387. LM_ERR("cannot parse CSeq header\n");
  388. return False;
  389. }
  390. if (msg->cseq == NULL) {
  391. LM_ERR("missing CSeq header\n");
  392. return False;
  393. }
  394. }
  395. *cseq = get_cseq(msg)->number;
  396. if (cseq->s==NULL || cseq->len==0) {
  397. LM_ERR("missing CSeq number\n");
  398. return False;
  399. }
  400. return True;
  401. }
  402. static str
  403. get_from_uri(struct sip_msg *msg)
  404. {
  405. static str unknown = str_init("unknown");
  406. str uri;
  407. char *ptr;
  408. if (parse_from_header(msg) < 0) {
  409. LM_ERR("cannot parse the From header\n");
  410. return unknown;
  411. }
  412. uri = get_from(msg)->uri;
  413. if (uri.len == 0)
  414. return unknown;
  415. if (strncasecmp(uri.s, "sip:", 4)==0) {
  416. uri.s += 4;
  417. uri.len -= 4;
  418. }
  419. if ((ptr = strfind(uri.s, uri.len, ";", 1))!=NULL) {
  420. uri.len = ptr - uri.s;
  421. }
  422. return uri;
  423. }
  424. static str
  425. get_to_uri(struct sip_msg *msg)
  426. {
  427. static str unknown = str_init("unknown");
  428. str uri;
  429. char *ptr;
  430. if (!msg->to) {
  431. LM_ERR("missing To header\n");
  432. return unknown;
  433. }
  434. uri = get_to(msg)->uri;
  435. if (uri.len == 0)
  436. return unknown;
  437. if (strncasecmp(uri.s, "sip:", 4)==0) {
  438. uri.s += 4;
  439. uri.len -= 4;
  440. }
  441. if ((ptr = strfind(uri.s, uri.len, ";", 1))!=NULL) {
  442. uri.len = ptr - uri.s;
  443. }
  444. return uri;
  445. }
  446. static str
  447. get_from_tag(struct sip_msg *msg)
  448. {
  449. static str undefined = str_init("");
  450. str tag;
  451. if (parse_from_header(msg) < 0) {
  452. LM_ERR("cannot parse the From header\n");
  453. return undefined;
  454. }
  455. tag = get_from(msg)->tag_value;
  456. if (tag.len == 0)
  457. return undefined;
  458. return tag;
  459. }
  460. static str
  461. get_to_tag(struct sip_msg *msg)
  462. {
  463. static str undefined = str_init("");
  464. str tag;
  465. if (msg->first_line.type==SIP_REPLY && msg->REPLY_STATUS<200) {
  466. // Ignore the To tag for provisional replies
  467. return undefined;
  468. }
  469. if (!msg->to) {
  470. LM_ERR("missing To header\n");
  471. return undefined;
  472. }
  473. tag = get_to(msg)->tag_value;
  474. if (tag.len == 0)
  475. return undefined;
  476. return tag;
  477. }
  478. static str
  479. get_user_agent(struct sip_msg* msg)
  480. {
  481. static str unknown = str_init("unknown agent");
  482. str block, server;
  483. char *ptr;
  484. if (parse_headers(msg, HDR_USERAGENT_F, 0)==0 && msg->user_agent &&
  485. msg->user_agent->body.s && msg->user_agent->body.len>0) {
  486. return msg->user_agent->body;
  487. }
  488. // If we can't find user-agent, look after the `Server' header
  489. // This is a temporary hack. Normally it should be extracted by sip-router.
  490. block.s = msg->buf;
  491. block.len = msg->len;
  492. ptr = find_line_starting_with(&block, "Server:", True);
  493. if (!ptr)
  494. return unknown;
  495. server.s = ptr + 7;
  496. server.len = findendline(server.s, block.s+block.len-server.s) - server.s;
  497. trim(&server);
  498. if (server.len == 0)
  499. return unknown;
  500. return server;
  501. }
  502. // Get caller signaling IP
  503. static str
  504. get_signaling_ip(struct sip_msg* msg)
  505. {
  506. int_str value;
  507. if (!search_first_avp(signaling_ip_avp.type | AVP_VAL_STR,
  508. signaling_ip_avp.name, &value, NULL) ||
  509. value.s.s==NULL || value.s.len==0) {
  510. value.s.s = ip_addr2a(&msg->rcv.src_ip);
  511. value.s.len = strlen(value.s.s);
  512. }
  513. return value.s;
  514. }
  515. // Get the application-defined media_relay if defined
  516. static str
  517. get_media_relay(struct sip_msg* msg)
  518. {
  519. static str undefined = str_init("");
  520. int_str value;
  521. if (!search_first_avp(media_relay_avp.type | AVP_VAL_STR,
  522. media_relay_avp.name, &value, NULL) || value.s.s==NULL || value.s.len==0) {
  523. return undefined;
  524. }
  525. return value.s;
  526. }
  527. // Functions to manipulate the SDP message body
  528. //
  529. static int
  530. find_content_type_application_sdp(struct sip_msg *msg, str *sdp)
  531. {
  532. str type, params, boundary;
  533. char *start, *s;
  534. unsigned int len;
  535. Bool done;
  536. param_hooks_t hooks;
  537. param_t *p, *list;
  538. if (!msg->content_type) {
  539. LM_WARN("the Content-Type header is missing! Assume the content type is text/plain\n");
  540. return 1;
  541. }
  542. type = msg->content_type->body;
  543. trim(&type);
  544. if (strncasecmp(type.s, "application/sdp", 15) == 0) {
  545. done = True;
  546. } else if (strncasecmp(type.s, "multipart/mixed", 15) == 0) {
  547. done = False;
  548. } else {
  549. LM_ERR("invalid Content-Type for SDP: %.*s\n", type.len, type.s);
  550. return -1;
  551. }
  552. if (!(isspace((int)type.s[15]) || type.s[15] == ';' || type.s[15] == 0)) {
  553. LM_ERR("invalid character after Content-Type: `%c'\n", type.s[15]);
  554. return -1;
  555. }
  556. if (done) return 1;
  557. // Hack to find application/sdp bodypart
  558. params.s = memchr(msg->content_type->body.s, ';',
  559. msg->content_type->body.len);
  560. if (params.s == NULL) {
  561. LM_ERR("Content-Type hdr has no params\n");
  562. return -1;
  563. }
  564. params.len = msg->content_type->body.len -
  565. (params.s - msg->content_type->body.s);
  566. if (parse_params(&params, CLASS_ANY, &hooks, &list) < 0) {
  567. LM_ERR("while parsing Content-Type params\n");
  568. return -1;
  569. }
  570. boundary.s = NULL;
  571. boundary.len = 0;
  572. for (p = list; p; p = p->next) {
  573. if ((p->name.len == 8)
  574. && (strncasecmp(p->name.s, "boundary", 8) == 0)) {
  575. boundary.s = pkg_malloc(p->body.len + 2 + 1);
  576. if (boundary.s == NULL) {
  577. free_params(list);
  578. LM_ERR("no memory for boundary string\n");
  579. return -1;
  580. }
  581. *(boundary.s) = '-';
  582. *(boundary.s + 1) = '-';
  583. memcpy(boundary.s + 2, p->body.s, p->body.len);
  584. boundary.len = 2 + p->body.len;
  585. *(boundary.s + boundary.len) = 0;
  586. LM_DBG("boundary is <%.*s>\n", boundary.len, boundary.s);
  587. break;
  588. }
  589. }
  590. free_params(list);
  591. if (boundary.s == NULL) {
  592. LM_ERR("no mandatory param \";boundary\"\n");
  593. return -1;
  594. }
  595. while ((s = find_line_starting_with(sdp, "Content-Type: ", True))) {
  596. start = s + 14;
  597. len = sdp->len - (s - sdp->s) - 14;
  598. if (len > 15 + 2) {
  599. if (strncasecmp(start, "application/sdp", 15) == 0) {
  600. start = start + 15;
  601. if ((*start != 13) || (*(start + 1) != 10)) {
  602. LM_ERR("no CRLF found after content type\n");
  603. goto err;
  604. }
  605. start = start + 2;
  606. len = len - 15 - 2;
  607. while ((len > 0) && ((*start == 13) || (*start == 10))) {
  608. len = len - 1;
  609. start = start + 1;
  610. }
  611. sdp->s = start;
  612. sdp->len = len;
  613. s = find_line_starting_with(sdp, boundary.s, False);
  614. if (s == NULL) {
  615. LM_ERR("boundary not found after bodypart\n");
  616. goto err;
  617. }
  618. sdp->len = s - start - 2;
  619. pkg_free(boundary.s);
  620. return 1;
  621. }
  622. }
  623. }
  624. LM_ERR("no application/sdp bodypart found\n");
  625. err:
  626. pkg_free(boundary.s);
  627. return -1;
  628. }
  629. // Get the SDP message from SIP message and check it's Content-Type
  630. // Return values:
  631. // 1 - success
  632. // -1 - error in getting body or invalid content type
  633. // -2 - empty message
  634. static int
  635. get_sdp_message(struct sip_msg *msg, str *sdp)
  636. {
  637. sdp->s = get_body(msg);
  638. if (sdp->s==NULL) {
  639. LM_ERR("cannot get the SDP body\n");
  640. return -1;
  641. }
  642. sdp->len = msg->buf + msg->len - sdp->s;
  643. if (sdp->len == 0)
  644. return -2;
  645. return find_content_type_application_sdp(msg, sdp);
  646. }
  647. // Return a str containing the line separator used in the SDP body
  648. static str
  649. get_sdp_line_separator(str *sdp)
  650. {
  651. char *ptr, *end_ptr, *sdp_end;
  652. str separator;
  653. sdp_end = sdp->s + sdp->len;
  654. ptr = find_line_starting_with(sdp, "v=", False);
  655. end_ptr = findendline(ptr, sdp_end-ptr);
  656. separator.s = ptr = end_ptr;
  657. while ((*ptr=='\n' || *ptr=='\r') && ptr<sdp_end)
  658. ptr++;
  659. separator.len = ptr - separator.s;
  660. if (separator.len > 2)
  661. separator.len = 2; // safety check
  662. return separator;
  663. }
  664. // will return the direction attribute defined in the given block.
  665. // if missing, default is used if provided, else `sendrecv' is used.
  666. static str
  667. get_direction_attribute(str *block, str *default_direction)
  668. {
  669. str direction, zone, line;
  670. char *ptr;
  671. for (zone=*block;;) {
  672. ptr = find_line_starting_with(&zone, "a=", False);
  673. if (!ptr) {
  674. if (default_direction)
  675. return *default_direction;
  676. direction.s = "sendrecv";
  677. direction.len = 8;
  678. return direction;
  679. }
  680. line.s = ptr + 2;
  681. line.len = findendline(line.s, zone.s + zone.len - line.s) - line.s;
  682. if (line.len==8) {
  683. if (strncasecmp(line.s, "sendrecv", 8)==0 || strncasecmp(line.s, "sendonly", 8)==0 ||
  684. strncasecmp(line.s, "recvonly", 8)==0 || strncasecmp(line.s, "inactive", 8)==0) {
  685. return line;
  686. }
  687. }
  688. zone.s = line.s + line.len;
  689. zone.len = block->s + block->len - zone.s;
  690. }
  691. }
  692. // will return the rtcp port of the stream in the given block
  693. // if defined by the stream, otherwise will return {NULL, 0}.
  694. static str
  695. get_rtcp_port_attribute(str *block)
  696. {
  697. str zone, rtcp_port, undefined = {NULL, 0};
  698. char *ptr;
  699. int count;
  700. ptr = find_line_starting_with(block, "a=rtcp:", False);
  701. if (!ptr)
  702. return undefined;
  703. zone.s = ptr + 7;
  704. zone.len = findendline(zone.s, block->s + block->len - zone.s) - zone.s;
  705. count = get_str_tokens(&zone, &rtcp_port, 1);
  706. if (count != 1) {
  707. LM_ERR("invalid `a=rtcp' line in SDP body\n");
  708. return undefined;
  709. }
  710. return rtcp_port;
  711. }
  712. // will return the rtcp IP of the stream in the given block
  713. // if defined by the stream, otherwise will return {NULL, 0}.
  714. static str
  715. get_rtcp_ip_attribute(str *block)
  716. {
  717. str zone, tokens[4], undefined = {NULL, 0};
  718. char *ptr;
  719. int count;
  720. ptr = find_line_starting_with(block, "a=rtcp:", False);
  721. if (!ptr)
  722. return undefined;
  723. zone.s = ptr + 7;
  724. zone.len = findendline(zone.s, block->s + block->len - zone.s) - zone.s;
  725. count = get_str_tokens(&zone, tokens, 4);
  726. if (count != 4) {
  727. return undefined;
  728. }
  729. return tokens[3];
  730. }
  731. // will return true if the given block has both
  732. // a=ice-pwd and a=ice-ufrag attributes.
  733. static Bool
  734. has_ice_attributes(str *block)
  735. {
  736. char *ptr;
  737. ptr = find_line_starting_with(block, "a=ice-pwd:", False);
  738. if (ptr) {
  739. ptr = find_line_starting_with(block, "a=ice-ufrag:", False);
  740. if (ptr) {
  741. return True;
  742. }
  743. }
  744. return False;
  745. }
  746. // will return true if the given SDP has both
  747. // a=ice-pwd and a=ice-ufrag attributes at the
  748. // session level.
  749. static Bool
  750. has_session_ice_attributes(str *sdp)
  751. {
  752. str block;
  753. char *ptr;
  754. // session level ICE attributes can be found from the beginning up to the first media block
  755. ptr = find_line_starting_with(sdp, "m=", False);
  756. if (ptr) {
  757. block.s = sdp->s;
  758. block.len = ptr - block.s;
  759. } else {
  760. block = *sdp;
  761. }
  762. return has_ice_attributes(&block);
  763. }
  764. // will return true if the given block contains
  765. // a a=candidate attribute. This should be called
  766. // for a stream, as a=candidate attribute is not
  767. // allowed at the session level
  768. static Bool
  769. has_ice_candidates(str *block)
  770. {
  771. char *ptr;
  772. ptr = find_line_starting_with(block, "a=candidate:", False);
  773. if (ptr) {
  774. return True;
  775. }
  776. return False;
  777. }
  778. // will return true if given block contains an ICE
  779. // candidate with the given component ID
  780. static Bool
  781. has_ice_candidate_component(str *block, int id)
  782. {
  783. char *ptr, *block_end;
  784. int i, components, count;
  785. str chunk, zone, tokens[2];
  786. block_end = block->s + block->len;
  787. components = count_lines_starting_with(block, "a=candidate:", False);
  788. for (i=0, chunk=*block; i<components; i++) {
  789. ptr = find_line_starting_with(&chunk, "a=candidate:", False);
  790. if (!ptr)
  791. break;
  792. zone.s = ptr + 12;
  793. zone.len = findendline(zone.s, block_end - zone.s) - zone.s;
  794. count = get_str_tokens(&zone, tokens, 2);
  795. if (count == 2) {
  796. if (strtoint(&tokens[1]) == id) {
  797. return True;
  798. }
  799. }
  800. chunk.s = zone.s + zone.len;
  801. chunk.len = block_end - chunk.s;
  802. }
  803. return False;
  804. }
  805. // will return the priority (string value) that will be used
  806. // for the candidate(s) inserted
  807. static str
  808. get_ice_candidate(void)
  809. {
  810. int_str value;
  811. if (!search_first_avp(ice_candidate_avp.type | AVP_VAL_STR,
  812. ice_candidate_avp.name, &value, NULL) || value.s.s==NULL || value.s.len==0) {
  813. // if AVP is not set use global module parameter
  814. return ice_candidate;
  815. } else {
  816. return value.s;
  817. }
  818. }
  819. // will return the priority (integer value) that will be used
  820. // for the candidate(s) inserted
  821. static unsigned int
  822. get_ice_candidate_priority(str priority)
  823. {
  824. int type_pref;
  825. if (STR_IMATCH(priority, "high-priority")) {
  826. // Use type preference even higher than host candidates
  827. type_pref = 130;
  828. } else if (STR_IMATCH(priority, "low-priority")) {
  829. type_pref = 0;
  830. } else {
  831. return NO_CANDIDATE;
  832. }
  833. // This will return the priority for the RTP component, the RTCP
  834. // component is RTP - 1
  835. return ((type_pref << 24) + 16777215);
  836. }
  837. // will return the ip address present in a `c=' line in the given block
  838. // returns: -1 on error, 0 if not found, 1 if found
  839. static int
  840. get_media_ip_from_block(str *block, str *mediaip)
  841. {
  842. str tokens[3], zone;
  843. char *ptr;
  844. int count;
  845. ptr = find_line_starting_with(block, "c=", False);
  846. if (!ptr) {
  847. mediaip->s = NULL;
  848. mediaip->len = 0;
  849. return 0;
  850. }
  851. zone.s = ptr + 2;
  852. zone.len = findendline(zone.s, block->s + block->len - zone.s) - zone.s;
  853. count = get_str_tokens(&zone, tokens, 3);
  854. if (count != 3) {
  855. LM_ERR("invalid `c=' line in SDP body\n");
  856. return -1;
  857. }
  858. // can also check if tokens[1] == 'IP4'
  859. *mediaip = tokens[2];
  860. return 1;
  861. }
  862. static Bool
  863. get_sdp_session_ip(str *sdp, str *mediaip, str *ip_line)
  864. {
  865. char *ptr, *end_ptr;
  866. str block;
  867. // session IP can be found from the beginning up to the first media block
  868. ptr = find_line_starting_with(sdp, "m=", False);
  869. if (ptr) {
  870. block.s = sdp->s;
  871. block.len = ptr - block.s;
  872. } else {
  873. block = *sdp;
  874. }
  875. if (get_media_ip_from_block(&block, mediaip) == -1) {
  876. LM_ERR("parse error while getting session-level media IP from SDP\n");
  877. return False;
  878. }
  879. if (ip_line != NULL) {
  880. ptr = find_line_starting_with(&block, "c=", False);
  881. if (!ptr) {
  882. ip_line->s = NULL;
  883. ip_line->len = 0;
  884. } else {
  885. end_ptr = findendline(ptr, block.s + block.len - ptr);
  886. while ((*end_ptr=='\n' || *end_ptr=='\r'))
  887. end_ptr++;
  888. ip_line->s = ptr;
  889. ip_line->len = end_ptr - ptr;
  890. }
  891. }
  892. // it's not an error to be missing. it can be locally defined
  893. // by each media stream. thus we return true even if not found
  894. return True;
  895. }
  896. // will return the direction as defined at the session level
  897. // in the SDP. if missing, `sendrecv' is used.
  898. static str
  899. get_session_direction(str *sdp)
  900. {
  901. static str default_direction = str_init("sendrecv");
  902. str block;
  903. char *ptr;
  904. // session level direction can be found from the beginning up to the first media block
  905. ptr = find_line_starting_with(sdp, "m=", False);
  906. if (ptr) {
  907. block.s = sdp->s;
  908. block.len = ptr - block.s;
  909. } else {
  910. block = *sdp;
  911. }
  912. return get_direction_attribute(&block, &default_direction);
  913. }
  914. // will return the method ID for a reply by inspecting the Cseq header
  915. static int
  916. get_method_from_reply(struct sip_msg *reply)
  917. {
  918. struct cseq_body *cseq;
  919. if (reply->first_line.type != SIP_REPLY)
  920. return -1;
  921. if (!reply->cseq && parse_headers(reply, HDR_CSEQ_F, 0) < 0) {
  922. LM_ERR("failed to parse the CSeq header\n");
  923. return -1;
  924. }
  925. if (!reply->cseq) {
  926. LM_ERR("missing CSeq header\n");
  927. return -1;
  928. }
  929. cseq = reply->cseq->parsed;
  930. return cseq->method_id;
  931. }
  932. static Bool
  933. supported_transport(str transport)
  934. {
  935. // supported transports: RTP/AVP, RTP/AVPF, RTP/SAVP, RTP/SAVPF, udp, udptl
  936. str prefixes[] = {str_init("RTP"), str_init("udp"), {NULL, 0}};
  937. int i;
  938. for (i=0; prefixes[i].s != NULL; i++) {
  939. if (STR_HAS_IPREFIX(transport, prefixes[i])) {
  940. return True;
  941. }
  942. }
  943. return False;
  944. }
  945. static int
  946. get_session_info(str *sdp, SessionInfo *session)
  947. {
  948. str tokens[3], ip, ip_line, block, zone;
  949. char *ptr, *sdp_end;
  950. int i, count, result;
  951. count = count_lines_starting_with(sdp, "v=", False);
  952. if (count != 1) {
  953. LM_ERR("cannot handle more than 1 media session in SDP\n");
  954. return -1;
  955. }
  956. count = count_lines_starting_with(sdp, "m=", False);
  957. if (count > MAX_STREAMS) {
  958. LM_ERR("cannot handle more than %d media streams in SDP\n", MAX_STREAMS);
  959. return -1;
  960. }
  961. memset(session, 0, sizeof(SessionInfo));
  962. if (count == 0)
  963. return 0;
  964. if (!get_sdp_session_ip(sdp, &ip, &ip_line)) {
  965. LM_ERR("failed to parse the SDP message\n");
  966. return -1;
  967. }
  968. ptr = memchr(ip.s, '/', ip.len);
  969. if (ptr) {
  970. LM_ERR("unsupported multicast IP specification in SDP: %.*s\n", ip.len, ip.s);
  971. return -1;
  972. }
  973. session->ip = ip;
  974. session->ip_line = ip_line;
  975. session->direction = get_session_direction(sdp);
  976. session->separator = get_sdp_line_separator(sdp);
  977. session->stream_count = count;
  978. sdp_end = sdp->s + sdp->len;
  979. for (i=0, block=*sdp; i<MAX_STREAMS; i++) {
  980. ptr = find_line_starting_with(&block, "m=", False);
  981. if (!ptr)
  982. break;
  983. zone.s = ptr + 2;
  984. zone.len = findendline(zone.s, sdp_end - zone.s) - zone.s;
  985. count = get_str_tokens(&zone, tokens, 3);
  986. if (count != 3) {
  987. LM_ERR("invalid `m=' line in the SDP body\n");
  988. return -1;
  989. }
  990. session->streams[i].start_line = ptr;
  991. session->streams[i].next_line = zone.s + zone.len + session->separator.len;
  992. if (session->streams[i].next_line > sdp_end)
  993. session->streams[i].next_line = sdp_end; //safety check
  994. if (supported_transport(tokens[2])) {
  995. // handle case where port is specified like <port>/<nr_of_ports>
  996. // as defined by RFC2327. ex: m=audio 5012/1 RTP/AVP 18 0 8
  997. // TODO: also handle case where nr_of_ports > 1 -Dan
  998. ptr = memchr(tokens[1].s, '/', tokens[1].len);
  999. if (ptr != NULL) {
  1000. str port_nr;
  1001. port_nr.s = ptr + 1;
  1002. port_nr.len = tokens[1].s + tokens[1].len - port_nr.s;
  1003. if (port_nr.len==0) {
  1004. LM_ERR("invalid port specification in `m=' line: %.*s\n", tokens[1].len, tokens[1].s);
  1005. return -1;
  1006. }
  1007. if (!(port_nr.len==1 && port_nr.s[0]=='1')) {
  1008. LM_ERR("unsupported number of ports specified in `m=' line\n");
  1009. return -1;
  1010. }
  1011. tokens[1].len = ptr - tokens[1].s;
  1012. }
  1013. session->streams[i].type = tokens[0];
  1014. session->streams[i].port = tokens[1];
  1015. session->streams[i].transport = TSupported;
  1016. session->supported_count++;
  1017. } else {
  1018. // mark that we have an unsupported transport so we can ignore this stream later
  1019. LM_INFO("unsupported transport in stream nr %d's `m=' line: %.*s\n", i+1, tokens[2].len, tokens[2].s);
  1020. session->streams[i].type = tokens[0];
  1021. session->streams[i].port = tokens[1];
  1022. session->streams[i].transport = TUnsupported;
  1023. }
  1024. block.s = zone.s + zone.len;
  1025. block.len = sdp_end - block.s;
  1026. }
  1027. for (i=0; i<session->stream_count; i++) {
  1028. block.s = session->streams[i].port.s;
  1029. if (i < session->stream_count-1)
  1030. block.len = session->streams[i+1].port.s - block.s;
  1031. else
  1032. block.len = sdp_end - block.s;
  1033. result = get_media_ip_from_block(&block, &ip);
  1034. if (result == -1) {
  1035. LM_ERR("parse error while getting the contact IP for the "
  1036. "media stream number %d\n", i+1);
  1037. return -1;
  1038. } else if (result == 0) {
  1039. if (session->ip.s == NULL) {
  1040. LM_ERR("media stream number %d doesn't define a contact IP "
  1041. "and the session-level IP is missing\n", i+1);
  1042. return -1;
  1043. }
  1044. session->streams[i].ip = session->ip;
  1045. session->streams[i].local_ip = 0;
  1046. } else {
  1047. if (session->streams[i].transport == TSupported) {
  1048. ptr = memchr(ip.s, '/', ip.len);
  1049. if (ptr) {
  1050. LM_ERR("unsupported multicast IP specification in stream nr %d: %.*s\n", i+1, ip.len, ip.s);
  1051. return -1;
  1052. }
  1053. }
  1054. session->streams[i].ip = ip;
  1055. session->streams[i].local_ip = 1;
  1056. }
  1057. session->streams[i].rtcp_ip = get_rtcp_ip_attribute(&block);
  1058. session->streams[i].rtcp_port = get_rtcp_port_attribute(&block);
  1059. session->streams[i].direction = get_direction_attribute(&block, &session->direction);
  1060. session->streams[i].has_ice = ((has_ice_attributes(&block) || has_session_ice_attributes(sdp)) && has_ice_candidates(&block));
  1061. session->streams[i].has_rtcp_ice = has_ice_candidate_component(&block, 2);
  1062. session->streams[i].first_ice_candidate = find_line_starting_with(&block, "a=candidate:", False);
  1063. }
  1064. return session->stream_count;
  1065. }
  1066. static Bool
  1067. insert_element(struct sip_msg *msg, char *position, char *element)
  1068. {
  1069. struct lump *anchor;
  1070. char *buf;
  1071. int len;
  1072. len = strlen(element);
  1073. buf = pkg_malloc(len);
  1074. if (!buf) {
  1075. LM_ERR("out of memory\n");
  1076. return False;
  1077. }
  1078. anchor = anchor_lump(msg, position - msg->buf, 0, 0);
  1079. if (!anchor) {
  1080. LM_ERR("failed to get anchor for new element\n");
  1081. pkg_free(buf);
  1082. return False;
  1083. }
  1084. memcpy(buf, element, len);
  1085. if (insert_new_lump_after(anchor, buf, len, 0)==0) {
  1086. LM_ERR("failed to insert new element\n");
  1087. pkg_free(buf);
  1088. return False;
  1089. }
  1090. return True;
  1091. }
  1092. static Bool
  1093. replace_element(struct sip_msg *msg, str *old_element, str *new_element)
  1094. {
  1095. struct lump *anchor;
  1096. char *buf;
  1097. if (new_element->len==old_element->len &&
  1098. memcmp(new_element->s, old_element->s, new_element->len)==0) {
  1099. return True;
  1100. }
  1101. buf = pkg_malloc(new_element->len);
  1102. if (!buf) {
  1103. LM_ERR("out of memory\n");
  1104. return False;
  1105. }
  1106. anchor = del_lump(msg, old_element->s - msg->buf, old_element->len, 0);
  1107. if (!anchor) {
  1108. LM_ERR("failed to delete old element\n");
  1109. pkg_free(buf);
  1110. return False;
  1111. }
  1112. memcpy(buf, new_element->s, new_element->len);
  1113. if (insert_new_lump_after(anchor, buf, new_element->len, 0)==0) {
  1114. LM_ERR("failed to insert new element\n");
  1115. pkg_free(buf);
  1116. return False;
  1117. }
  1118. return True;
  1119. }
  1120. static Bool
  1121. remove_element(struct sip_msg *msg, str *element)
  1122. {
  1123. if (!del_lump(msg, element->s - msg->buf, element->len, 0)) {
  1124. LM_ERR("failed to delete old element\n");
  1125. return False;
  1126. }
  1127. return True;
  1128. }
  1129. // Functions dealing with the external mediaproxy helper
  1130. //
  1131. static Bool
  1132. mediaproxy_connect(void)
  1133. {
  1134. struct sockaddr_un addr;
  1135. if (mediaproxy_socket.sock >= 0)
  1136. return True;
  1137. if (mediaproxy_socket.last_failure + RETRY_INTERVAL > time(NULL))
  1138. return False;
  1139. memset(&addr, 0, sizeof(addr));
  1140. addr.sun_family = AF_LOCAL;
  1141. strncpy(addr.sun_path, mediaproxy_socket.name, sizeof(addr.sun_path) - 1);
  1142. #ifdef HAVE_SOCKADDR_SA_LEN
  1143. addr.sun_len = strlen(addr.sun_path);
  1144. #endif
  1145. mediaproxy_socket.sock = socket(AF_LOCAL, SOCK_STREAM, 0);
  1146. if (mediaproxy_socket.sock < 0) {
  1147. LM_ERR("can't create socket\n");
  1148. mediaproxy_socket.last_failure = time(NULL);
  1149. return False;
  1150. }
  1151. if (connect(mediaproxy_socket.sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
  1152. LM_ERR("failed to connect to %s: %s\n", mediaproxy_socket.name, strerror(errno));
  1153. close(mediaproxy_socket.sock);
  1154. mediaproxy_socket.sock = -1;
  1155. mediaproxy_socket.last_failure = time(NULL);
  1156. return False;
  1157. }
  1158. return True;
  1159. }
  1160. static void
  1161. mediaproxy_disconnect(void)
  1162. {
  1163. if (mediaproxy_socket.sock < 0)
  1164. return;
  1165. close(mediaproxy_socket.sock);
  1166. mediaproxy_socket.sock = -1;
  1167. mediaproxy_socket.last_failure = time(NULL);
  1168. }
  1169. static char*
  1170. send_command(char *command)
  1171. {
  1172. int cmd_len, bytes, tries, sent, received, count;
  1173. struct timeval timeout;
  1174. fd_set rset;
  1175. if (!mediaproxy_connect())
  1176. return NULL;
  1177. cmd_len = strlen(command);
  1178. for (sent=0, tries=0; sent<cmd_len && tries<3; tries++, sent+=bytes) {
  1179. do
  1180. bytes = send(mediaproxy_socket.sock, command+sent, cmd_len-sent, MSG_DONTWAIT|MSG_NOSIGNAL);
  1181. while (bytes == -1 && errno == EINTR);
  1182. if (bytes == -1) {
  1183. switch (errno) {
  1184. case ECONNRESET:
  1185. case EPIPE:
  1186. mediaproxy_disconnect();
  1187. mediaproxy_socket.last_failure = 0; // we want to reconnect immediately
  1188. if (mediaproxy_connect()) {
  1189. sent = bytes = 0;
  1190. continue;
  1191. } else {
  1192. LM_ERR("connection with mediaproxy did die\n");
  1193. }
  1194. break;
  1195. case EACCES:
  1196. LM_ERR("got permission denied while sending to %s\n", mediaproxy_socket.name);
  1197. break;
  1198. case EWOULDBLOCK:
  1199. // this shouldn't happen as we read back all the answer after a request.
  1200. // if it would block, it means there is an error.
  1201. LM_ERR("sending command would block!\n");
  1202. break;
  1203. default:
  1204. LM_ERR("%d: %s\n", errno, strerror(errno));
  1205. break;
  1206. }
  1207. mediaproxy_disconnect();
  1208. return NULL;
  1209. }
  1210. }
  1211. if (sent < cmd_len) {
  1212. LM_ERR("couldn't send complete command after 3 tries\n");
  1213. mediaproxy_disconnect();
  1214. return NULL;
  1215. }
  1216. mediaproxy_socket.data[0] = 0;
  1217. received = 0;
  1218. while (True) {
  1219. FD_ZERO(&rset);
  1220. FD_SET(mediaproxy_socket.sock, &rset);
  1221. timeout.tv_sec = mediaproxy_socket.timeout / 1000;
  1222. timeout.tv_usec = (mediaproxy_socket.timeout % 1000) * 1000;
  1223. do
  1224. count = select(mediaproxy_socket.sock + 1, &rset, NULL, NULL, &timeout);
  1225. while (count == -1 && errno == EINTR);
  1226. if (count == -1) {
  1227. LM_ERR("select failed: %d: %s\n", errno, strerror(errno));
  1228. mediaproxy_disconnect();
  1229. return NULL;
  1230. } else if (count == 0) {
  1231. LM_ERR("did timeout waiting for an answer\n");
  1232. mediaproxy_disconnect();
  1233. return NULL;
  1234. } else {
  1235. do
  1236. bytes = recv(mediaproxy_socket.sock, mediaproxy_socket.data+received, BUFFER_SIZE-1-received, 0);
  1237. while (bytes == -1 && errno == EINTR);
  1238. if (bytes == -1) {
  1239. LM_ERR("failed to read answer: %d: %s\n", errno, strerror(errno));
  1240. mediaproxy_disconnect();
  1241. return NULL;
  1242. } else if (bytes == 0) {
  1243. LM_ERR("connection with mediaproxy closed\n");
  1244. mediaproxy_disconnect();
  1245. return NULL;
  1246. } else {
  1247. mediaproxy_socket.data[received+bytes] = 0;
  1248. if (strstr(mediaproxy_socket.data+received, "\r\n")!=NULL) {
  1249. break;
  1250. }
  1251. received += bytes;
  1252. }
  1253. }
  1254. }
  1255. return mediaproxy_socket.data;
  1256. }
  1257. // Exported API implementation
  1258. //
  1259. // ice_candidate_data: it carries data across the dialog when using engage_media_proxy:
  1260. // - priority: the priority that should be used for the ICE candidate
  1261. // * -1: no candidate should be added.
  1262. // * other: the specified type preference should be used for calculating
  1263. // - skip_next_reply: flag for knowing the fact that the next reply with SDP must be skipped
  1264. // because it is a reply to a re-INVITE or UPDATE *after* the ICE negotiation
  1265. static int
  1266. use_media_proxy(struct sip_msg *msg, char *dialog_id, ice_candidate_data *ice_data)
  1267. {
  1268. str callid, cseq, from_uri, to_uri, from_tag, to_tag, user_agent;
  1269. str signaling_ip, media_relay, sdp, str_buf, tokens[MAX_STREAMS+1];
  1270. str priority_str, candidate;
  1271. char request[8192], media_str[4096], buf[128], *result, *type;
  1272. int i, j, port, len, status;
  1273. Bool removed_session_ip, have_sdp;
  1274. SessionInfo session;
  1275. StreamInfo stream;
  1276. unsigned int priority;
  1277. if (msg == NULL)
  1278. return -1;
  1279. if (msg->first_line.type == SIP_REQUEST) {
  1280. type = "request";
  1281. } else if (msg->first_line.type == SIP_REPLY) {
  1282. if (ice_data != NULL && ice_data->skip_next_reply) {
  1283. // we don't process replies to ICE negotiation end requests
  1284. // (those containing a=remote-candidates)
  1285. ice_data->skip_next_reply = False;
  1286. return -1;
  1287. }
  1288. type = "reply";
  1289. } else {
  1290. return -1;
  1291. }
  1292. if (!get_callid(msg, &callid)) {
  1293. LM_ERR("failed to get Call-ID\n");
  1294. return -1;
  1295. }
  1296. if (!get_cseq_number(msg, &cseq)) {
  1297. LM_ERR("failed to get CSeq\n");
  1298. return -1;
  1299. }
  1300. status = get_sdp_message(msg, &sdp);
  1301. // status = -1 is error, -2 is missing SDP body
  1302. if (status == -1 || (status == -2 && msg->first_line.type == SIP_REQUEST)) {
  1303. return status;
  1304. } else if (status == -2 && !(msg->REPLY_STATUS == 200 && get_method_from_reply(msg) == METHOD_INVITE)) {
  1305. return -2;
  1306. }
  1307. have_sdp = (status == 1);
  1308. if (have_sdp) {
  1309. if (msg->first_line.type == SIP_REQUEST && find_line_starting_with(&sdp, "a=remote-candidates", False)) {
  1310. // we don't process requests with a=remote-candidates, this indicates the end of an ICE
  1311. // negotiation and we must not mangle the SDP.
  1312. if (ice_data != NULL) {
  1313. ice_data->skip_next_reply = True;
  1314. }
  1315. return -1;
  1316. }
  1317. status = get_session_info(&sdp, &session);
  1318. if (status < 0) {
  1319. LM_ERR("can't extract media streams from the SDP message\n");
  1320. return -1;
  1321. }
  1322. if (session.supported_count == 0)
  1323. return 1; // there are no supported media streams. we have nothing to do.
  1324. len = sprintf(media_str, "%s", "media: ");
  1325. for (i=0, str_buf.len=sizeof(media_str)-len-2, str_buf.s=media_str+len; i<session.stream_count; i++) {
  1326. stream = session.streams[i];
  1327. if (stream.transport != TSupported)
  1328. continue; // skip streams with unsupported transports
  1329. if (stream.type.len + stream.ip.len + stream.port.len + stream.direction.len + 4 > str_buf.len) {
  1330. LM_ERR("media stream description is longer than %lu bytes\n", (unsigned long)sizeof(media_str));
  1331. return -1;
  1332. }
  1333. len = sprintf(str_buf.s, "%.*s:%.*s:%.*s:%.*s:%s,",
  1334. stream.type.len, stream.type.s,
  1335. stream.ip.len, stream.ip.s,
  1336. stream.port.len, stream.port.s,
  1337. stream.direction.len, stream.direction.s,
  1338. stream.has_ice?"ice=yes":"ice=no");
  1339. str_buf.s += len;
  1340. str_buf.len -= len;
  1341. }
  1342. *(str_buf.s-1) = 0; // remove the last comma
  1343. sprintf(str_buf.s-1, "%s", "\r\n");
  1344. } else {
  1345. media_str[0] = 0;
  1346. }
  1347. from_uri = get_from_uri(msg);
  1348. to_uri = get_to_uri(msg);
  1349. from_tag = get_from_tag(msg);
  1350. to_tag = get_to_tag(msg);
  1351. user_agent = get_user_agent(msg);
  1352. signaling_ip = get_signaling_ip(msg);
  1353. media_relay = get_media_relay(msg);
  1354. len = snprintf(request, sizeof(request),
  1355. "update\r\n"
  1356. "type: %s\r\n"
  1357. "dialog_id: %s\r\n"
  1358. "call_id: %.*s\r\n"
  1359. "cseq: %.*s\r\n"
  1360. "from_uri: %.*s\r\n"
  1361. "to_uri: %.*s\r\n"
  1362. "from_tag: %.*s\r\n"
  1363. "to_tag: %.*s\r\n"
  1364. "user_agent: %.*s\r\n"
  1365. "signaling_ip: %.*s\r\n"
  1366. "media_relay: %.*s\r\n"
  1367. "%s"
  1368. "\r\n",
  1369. type, dialog_id, callid.len, callid.s, cseq.len, cseq.s,
  1370. from_uri.len, from_uri.s, to_uri.len, to_uri.s,
  1371. from_tag.len, from_tag.s, to_tag.len, to_tag.s,
  1372. user_agent.len, user_agent.s,
  1373. signaling_ip.len, signaling_ip.s,
  1374. media_relay.len, media_relay.s, media_str);
  1375. if (len >= sizeof(request)) {
  1376. LM_ERR("mediaproxy request is longer than %lu bytes\n", (unsigned long)sizeof(request));
  1377. return -1;
  1378. }
  1379. result = send_command(request);
  1380. if (result == NULL)
  1381. return -1;
  1382. if (!have_sdp) {
  1383. // we updated the dispatcher, we can't do anything else as
  1384. // there is no SDP
  1385. return 1;
  1386. }
  1387. len = get_tokens(result, tokens, sizeof(tokens)/sizeof(str));
  1388. if (len == 0) {
  1389. LM_ERR("empty response from mediaproxy\n");
  1390. return -1;
  1391. } else if (len==1 && STR_MATCH(tokens[0], "error")) {
  1392. LM_ERR("mediaproxy returned error\n");
  1393. return -1;
  1394. } else if (len<session.supported_count+1) {
  1395. if (msg->first_line.type == SIP_REQUEST) {
  1396. LM_ERR("insufficient ports returned from mediaproxy: got %d, "
  1397. "expected %d\n", len-1, session.supported_count);
  1398. return -1;
  1399. } else {
  1400. LM_WARN("broken client. Called UA added extra media stream(s) "
  1401. "in the OK reply\n");
  1402. }
  1403. }
  1404. removed_session_ip = False;
  1405. // only replace the session ip if there are no streams with unsupported
  1406. // transports otherwise we insert an ip line in the supported streams
  1407. // and remove the session level ip
  1408. if (session.ip.s && !isnulladdr(session.ip)) {
  1409. if (session.stream_count == session.supported_count) {
  1410. if (!replace_element(msg, &session.ip, &tokens[0])) {
  1411. LM_ERR("failed to replace session-level media IP in the SDP body\n");
  1412. return -1;
  1413. }
  1414. } else {
  1415. if (!remove_element(msg, &session.ip_line)) {
  1416. LM_ERR("failed to remove session-level media IP in the SDP body\n");
  1417. return -1;
  1418. }
  1419. removed_session_ip = True;
  1420. }
  1421. }
  1422. for (i=0, j=1; i<session.stream_count; i++) {
  1423. stream = session.streams[i];
  1424. if (stream.transport != TSupported) {
  1425. if (!stream.local_ip && removed_session_ip) {
  1426. strcpy(buf, "c=IN IP4 ");
  1427. strncat(buf, session.ip.s, session.ip.len);
  1428. strncat(buf, session.separator.s, session.separator.len);
  1429. if (!insert_element(msg, stream.next_line, buf)) {
  1430. LM_ERR("failed to insert IP address in media stream number %d\n", i+1);
  1431. return -1;
  1432. }
  1433. }
  1434. continue;
  1435. }
  1436. if (j >= len) {
  1437. break;
  1438. }
  1439. if (!isnullport(stream.port)) {
  1440. if (!replace_element(msg, &stream.port, &tokens[j])) {
  1441. LM_ERR("failed to replace port in media stream number %d\n", i+1);
  1442. return -1;
  1443. }
  1444. }
  1445. if (stream.rtcp_port.len>0 && !isnullport(stream.rtcp_port)) {
  1446. str rtcp_port;
  1447. port = strtoint(&tokens[j]);
  1448. rtcp_port.s = int2str(port+1, &rtcp_port.len);
  1449. if (!replace_element(msg, &stream.rtcp_port, &rtcp_port)) {
  1450. LM_ERR("failed to replace RTCP port in media stream number %d\n", i+1);
  1451. return -1;
  1452. }
  1453. }
  1454. if (stream.rtcp_ip.len > 0) {
  1455. if (!replace_element(msg, &stream.rtcp_ip, &tokens[0])) {
  1456. LM_ERR("failed to replace RTCP IP in media stream number %d\n", i+1);
  1457. return -1;
  1458. }
  1459. }
  1460. if (stream.local_ip && !isnulladdr(stream.ip)) {
  1461. if (!replace_element(msg, &stream.ip, &tokens[0])) {
  1462. LM_ERR("failed to replace IP address in media stream number %d\n", i+1);
  1463. return -1;
  1464. }
  1465. } else if (!stream.local_ip && removed_session_ip) {
  1466. strcpy(buf, "c=IN IP4 ");
  1467. strncat(buf, tokens[0].s, tokens[0].len);
  1468. strncat(buf, session.separator.s, session.separator.len);
  1469. if (!insert_element(msg, stream.next_line, buf)) {
  1470. LM_ERR("failed to insert IP address in media stream number %d\n", i+1);
  1471. return -1;
  1472. }
  1473. }
  1474. if (ice_data == NULL) {
  1475. priority_str = get_ice_candidate();
  1476. } else if (ice_data->priority == NO_CANDIDATE) {
  1477. priority_str.s = "none";
  1478. } else {
  1479. // we don't need the string value, we'll use the number
  1480. priority_str.s = "";
  1481. }
  1482. priority_str.len = strlen(priority_str.s);
  1483. if (stream.has_ice && stream.first_ice_candidate && !STR_IMATCH(priority_str, "none")) {
  1484. // add some pseudo-random string to the foundation
  1485. struct in_addr hexip;
  1486. inet_aton(tokens[0].s, &hexip);
  1487. priority = (ice_data == NULL)?get_ice_candidate_priority(priority_str):ice_data->priority;
  1488. port = strtoint(&tokens[j]);
  1489. candidate.s = buf;
  1490. candidate.len = sprintf(candidate.s, "a=candidate:R%x 1 UDP %u %.*s %i typ relay%.*s",
  1491. hexip.s_addr,
  1492. priority,
  1493. tokens[0].len, tokens[0].s,
  1494. port,
  1495. session.separator.len, session.separator.s);
  1496. if (!insert_element(msg, stream.first_ice_candidate, candidate.s)) {
  1497. LM_ERR("failed to insert ICE candidate in media stream number %d\n", i+1);
  1498. return -1;
  1499. }
  1500. if (stream.has_rtcp_ice) {
  1501. candidate.s = buf;
  1502. candidate.len = sprintf(candidate.s, "a=candidate:R%x 2 UDP %u %.*s %i typ relay%.*s",
  1503. hexip.s_addr,
  1504. priority-1,
  1505. tokens[0].len, tokens[0].s,
  1506. port+1,
  1507. session.separator.len, session.separator.s);
  1508. if (!insert_element(msg, stream.first_ice_candidate, candidate.s)) {
  1509. LM_ERR("failed to insert ICE candidate in media stream number %d\n", i+1);
  1510. return -1;
  1511. }
  1512. }
  1513. }
  1514. j++;
  1515. }
  1516. return 1;
  1517. }
  1518. static int
  1519. end_media_session(str callid, str from_tag, str to_tag)
  1520. {
  1521. char request[2048], *result;
  1522. int len;
  1523. len = snprintf(request, sizeof(request),
  1524. "remove\r\n"
  1525. "call_id: %.*s\r\n"
  1526. "from_tag: %.*s\r\n"
  1527. "to_tag: %.*s\r\n"
  1528. "\r\n",
  1529. callid.len, callid.s,
  1530. from_tag.len, from_tag.s,
  1531. to_tag.len, to_tag.s);
  1532. if (len >= sizeof(request)) {
  1533. LM_ERR("mediaproxy request is longer than %lu bytes\n", (unsigned long)sizeof(request));
  1534. return -1;
  1535. }
  1536. result = send_command(request);
  1537. return result==NULL ? -1 : 1;
  1538. }
  1539. // Dialog callbacks and helpers
  1540. //
  1541. typedef enum {
  1542. MPInactive = 0,
  1543. MPActive
  1544. } MediaProxyState;
  1545. static INLINE char*
  1546. get_dialog_id(struct dlg_cell *dlg)
  1547. {
  1548. static char buffer[64];
  1549. snprintf(buffer, sizeof(buffer), "%d:%d", dlg->h_entry, dlg->h_id);
  1550. return buffer;
  1551. }
  1552. static void
  1553. __free_dialog_data(void *data)
  1554. {
  1555. shm_free((ice_candidate_data*)data);
  1556. }
  1557. static void
  1558. __dialog_requests(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params)
  1559. {
  1560. use_media_proxy(_params->req, get_dialog_id(dlg), (ice_candidate_data*)*_params->param);
  1561. }
  1562. static void
  1563. __dialog_replies(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params)
  1564. {
  1565. struct sip_msg *reply = _params->rpl;
  1566. if (reply == FAKED_REPLY)
  1567. return;
  1568. if (reply->REPLY_STATUS>100 && reply->REPLY_STATUS<300) {
  1569. use_media_proxy(reply, get_dialog_id(dlg), (ice_candidate_data*)*_params->param);
  1570. }
  1571. }
  1572. static void
  1573. __dialog_ended(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params)
  1574. {
  1575. if ((int)(long)*_params->param == MPActive) {
  1576. end_media_session(dlg->callid, dlg->tag[DLG_CALLER_LEG], dlg->tag[DLG_CALLEE_LEG]);
  1577. *_params->param = MPInactive;
  1578. }
  1579. }
  1580. static void
  1581. __dialog_created(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params)
  1582. {
  1583. struct sip_msg *request = _params->req;
  1584. ice_candidate_data *ice_data;
  1585. if (request->REQ_METHOD != METHOD_INVITE)
  1586. return;
  1587. if ((request->msg_flags & FL_USE_MEDIA_PROXY) == 0)
  1588. return;
  1589. ice_data = (ice_candidate_data*)shm_malloc(sizeof(ice_candidate_data));
  1590. if (!ice_data) {
  1591. LM_ERR("failed to allocate shm memory for ice_candidate_data\n");
  1592. return;
  1593. }
  1594. ice_data->priority = get_ice_candidate_priority(get_ice_candidate());
  1595. ice_data->skip_next_reply = False;
  1596. if (dlg_api.register_dlgcb(dlg, DLGCB_REQ_WITHIN | DLGCB_CONFIRMED, __dialog_requests, (void*)ice_data, __free_dialog_data) != 0)
  1597. LM_ERR("cannot register callback for in-dialog requests\n");
  1598. if (dlg_api.register_dlgcb(dlg, DLGCB_RESPONSE_FWDED | DLGCB_RESPONSE_WITHIN, __dialog_replies, (void*)ice_data, NULL) != 0)
  1599. LM_ERR("cannot register callback for dialog and in-dialog replies\n");
  1600. if (dlg_api.register_dlgcb(dlg, DLGCB_TERMINATED | DLGCB_FAILED | DLGCB_EXPIRED | DLGCB_DESTROY, __dialog_ended, (void*)MPActive, NULL) != 0)
  1601. LM_ERR("cannot register callback for dialog termination\n");
  1602. use_media_proxy(request, get_dialog_id(dlg), ice_data);
  1603. }
  1604. //
  1605. // The public functions that are exported by this module
  1606. //
  1607. static int
  1608. EngageMediaProxy(struct sip_msg *msg)
  1609. {
  1610. if (mediaproxy_disabled)
  1611. return -1;
  1612. if (!have_dlg_api) {
  1613. LM_ERR("engage_media_proxy requires the dialog module to be loaded and configured\n");
  1614. return -1;
  1615. }
  1616. msg->msg_flags |= FL_USE_MEDIA_PROXY;
  1617. setflag(msg, dialog_flag); // have the dialog module trace this dialog
  1618. return 1;
  1619. }
  1620. static int
  1621. UseMediaProxy(struct sip_msg *msg)
  1622. {
  1623. if (mediaproxy_disabled)
  1624. return -1;
  1625. return use_media_proxy(msg, "", NULL);
  1626. }
  1627. static int
  1628. EndMediaSession(struct sip_msg *msg)
  1629. {
  1630. str callid, from_tag, to_tag;
  1631. if (mediaproxy_disabled)
  1632. return -1;
  1633. if (!get_callid(msg, &callid)) {
  1634. LM_ERR("failed to get Call-ID\n");
  1635. return -1;
  1636. }
  1637. from_tag = get_from_tag(msg);
  1638. to_tag = get_to_tag(msg);
  1639. return end_media_session(callid, from_tag, to_tag);
  1640. }
  1641. //
  1642. // Module management: initialization/destroy/function-parameter-fixing/...
  1643. //
  1644. static int
  1645. mod_init(void)
  1646. {
  1647. pv_spec_t avp_spec;
  1648. int *param;
  1649. modparam_t type;
  1650. // initialize the signaling_ip_avp structure
  1651. if (signaling_ip_avp.spec.s==NULL || *(signaling_ip_avp.spec.s)==0) {
  1652. LM_WARN("missing/empty signaling_ip_avp parameter. will use default.\n");
  1653. signaling_ip_avp.spec.s = SIGNALING_IP_AVP_SPEC;
  1654. }
  1655. signaling_ip_avp.spec.len = strlen(signaling_ip_avp.spec.s);
  1656. if (pv_parse_spec(&(signaling_ip_avp.spec), &avp_spec)==0 || avp_spec.type!=PVT_AVP) {
  1657. LM_CRIT("invalid AVP specification for signaling_ip_avp: `%s'\n", signaling_ip_avp.spec.s);
  1658. return -1;
  1659. }
  1660. if (pv_get_avp_name(0, &(avp_spec.pvp), &(signaling_ip_avp.name), &(signaling_ip_avp.type))!=0) {
  1661. LM_CRIT("invalid AVP specification for signaling_ip_avp: `%s'\n", signaling_ip_avp.spec.s);
  1662. return -1;
  1663. }
  1664. // initialize the media_relay_avp structure
  1665. if (media_relay_avp.spec.s==NULL || *(media_relay_avp.spec.s)==0) {
  1666. LM_WARN("missing/empty media_relay_avp parameter. will use default.\n");
  1667. media_relay_avp.spec.s = MEDIA_RELAY_AVP_SPEC;
  1668. }
  1669. media_relay_avp.spec.len = strlen(media_relay_avp.spec.s);
  1670. if (pv_parse_spec(&(media_relay_avp.spec), &avp_spec)==0 || avp_spec.type!=PVT_AVP) {
  1671. LM_CRIT("invalid AVP specification for media_relay_avp: `%s'\n", media_relay_avp.spec.s);
  1672. return -1;
  1673. }
  1674. if (pv_get_avp_name(0, &(avp_spec.pvp), &(media_relay_avp.name), &(media_relay_avp.type))!=0) {
  1675. LM_CRIT("invalid AVP specification for media_relay_avp: `%s'\n", media_relay_avp.spec.s);
  1676. return -1;
  1677. }
  1678. // initialize the ice_candidate_avp structure
  1679. if (ice_candidate_avp.spec.s==NULL || *(ice_candidate_avp.spec.s)==0) {
  1680. LM_WARN("missing/empty ice_candidate_avp parameter. will use default.\n");
  1681. ice_candidate_avp.spec.s = ICE_CANDIDATE_AVP_SPEC;
  1682. }
  1683. ice_candidate_avp.spec.len = strlen(ice_candidate_avp.spec.s);
  1684. if (pv_parse_spec(&(ice_candidate_avp.spec), &avp_spec)==0 || avp_spec.type!=PVT_AVP) {
  1685. LM_CRIT("invalid AVP specification for ice_candidate_avp: `%s'\n", ice_candidate_avp.spec.s);
  1686. return -1;
  1687. }
  1688. if (pv_get_avp_name(0, &(avp_spec.pvp), &(ice_candidate_avp.name), &(ice_candidate_avp.type))!=0) {
  1689. LM_CRIT("invalid AVP specification for ice_candidate_avp: `%s'\n", ice_candidate_avp.spec.s);
  1690. return -1;
  1691. }
  1692. // initialize ice_candidate module parameter
  1693. ice_candidate.len = strlen(ice_candidate.s);
  1694. if (!STR_IMATCH(ice_candidate, "none") && !STR_IMATCH(ice_candidate, "low-priority") && !STR_IMATCH(ice_candidate, "high-priority")) {
  1695. LM_CRIT("invalid value specified for ice_candidate: `%s'\n", ice_candidate.s);
  1696. return -1;
  1697. }
  1698. // bind to the dialog API
  1699. if (load_dlg_api(&dlg_api)==0) {
  1700. have_dlg_api = True;
  1701. // load dlg_flag and default_timeout parameters from the dialog module
  1702. param = find_param_export(find_module_by_name("dialog"), "dlg_flag", INT_PARAM, &type);
  1703. if (!param) {
  1704. LM_CRIT("cannot find dlg_flag parameter in the dialog module\n");
  1705. return -1;
  1706. }
  1707. if (type != INT_PARAM) {
  1708. LM_CRIT("dlg_flag parameter found but with wrong type: %d\n", type);
  1709. return -1;
  1710. }
  1711. dialog_flag = *param;
  1712. // register dialog creation callback
  1713. if (dlg_api.register_dlgcb(NULL, DLGCB_CREATED, __dialog_created, NULL, NULL) != 0) {
  1714. LM_CRIT("cannot register callback for dialog creation\n");
  1715. return -1;
  1716. }
  1717. } else {
  1718. LM_NOTICE("engage_media_proxy() will not work because the dialog module is not loaded\n");
  1719. }
  1720. return 0;
  1721. }
  1722. static int
  1723. child_init(int rank)
  1724. {
  1725. // initialize the connection to mediaproxy if needed
  1726. if (!mediaproxy_disabled && rank > PROC_MAIN)
  1727. mediaproxy_connect();
  1728. return 0;
  1729. }