00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <unistd.h>
00025 #include <string.h>
00026 #include <time.h>
00027 #include <ctype.h>
00028 #include <errno.h>
00029 #include <arpa/inet.h>
00030 #include <sys/time.h>
00031 #include <sys/types.h>
00032 #include <sys/socket.h>
00033 #include <sys/select.h>
00034 #include <sys/un.h>
00035
00036 #include "../../sr_module.h"
00037 #include "../../dprint.h"
00038 #include "../../str.h"
00039 #include "../../pvar.h"
00040 #include "../../error.h"
00041 #include "../../data_lump.h"
00042 #include "../../mem/mem.h"
00043 #include "../../ut.h"
00044 #include "../../parser/msg_parser.h"
00045 #include "../../parser/parse_from.h"
00046 #include "../../parser/parse_to.h"
00047 #include "../../parser/parse_param.h"
00048 #include "../../msg_translator.h"
00049 #include "../../modules_k/dialog/dlg_load.h"
00050 #include "../../modules_k/dialog/dlg_hash.h"
00051
00052
00053 MODULE_VERSION
00054
00055
00056 #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
00057 # define INLINE inline
00058 #else
00059 # define INLINE
00060 #endif
00061
00062
00063 #define FL_USE_MEDIA_PROXY (1<<30)
00064
00065 #define SIGNALING_IP_AVP_SPEC "$avp(s:signaling_ip)"
00066 #define MEDIA_RELAY_AVP_SPEC "$avp(s:media_relay)"
00067 #define ICE_CANDIDATE_AVP_SPEC "$avp(s:ice_candidate)"
00068
00069 #define NO_CANDIDATE -1
00070
00071
00072
00073
00074
00075 #ifndef AF_LOCAL
00076 # define AF_LOCAL AF_UNIX
00077 #endif
00078
00079
00080
00081 #ifndef MSG_NOSIGNAL
00082 # define MSG_NOSIGNAL 0
00083 #endif
00084
00085
00086 #define isnulladdr(adr) ((adr).len==7 && memcmp("0.0.0.0", (adr).s, 7)==0)
00087 #define isnullport(port) ((port).len==1 && (port).s[0]=='0')
00088
00089 #define STR_MATCH(str, buf) ((str).len==strlen(buf) && memcmp(buf, (str).s, (str).len)==0)
00090 #define STR_IMATCH(str, buf) ((str).len==strlen(buf) && strncasecmp(buf, (str).s, (str).len)==0)
00091
00092 #define STR_HAS_PREFIX(str, prefix) ((str).len>=(prefix).len && memcmp((prefix).s, (str).s, (prefix).len)==0)
00093 #define STR_HAS_IPREFIX(str, prefix) ((str).len>=(prefix).len && strncasecmp((prefix).s, (str).s, (prefix).len)==0)
00094
00095
00096 typedef int Bool;
00097 #define True 1
00098 #define False 0
00099
00100
00101 typedef Bool (*NatTestFunction)(struct sip_msg *msg);
00102
00103
00104 typedef enum {
00105 TNone=0,
00106 TSupported,
00107 TUnsupported
00108 } TransportType;
00109
00110 #define RETRY_INTERVAL 10
00111 #define BUFFER_SIZE 8192
00112
00113 typedef struct MediaproxySocket {
00114 char *name;
00115 int sock;
00116 int timeout;
00117 time_t last_failure;
00118 char data[BUFFER_SIZE];
00119 } MediaproxySocket;
00120
00121
00122 typedef struct {
00123 const char *name;
00124 uint32_t address;
00125 uint32_t mask;
00126 } NetInfo;
00127
00128 typedef struct {
00129 str type;
00130 str ip;
00131 str port;
00132 str rtcp_ip;
00133 str rtcp_port;
00134 str direction;
00135 Bool local_ip;
00136 Bool has_ice;
00137 Bool has_rtcp_ice;
00138 TransportType transport;
00139 char *start_line;
00140 char *next_line;
00141 char *first_ice_candidate;
00142 } StreamInfo;
00143
00144 #define MAX_STREAMS 32
00145 typedef struct SessionInfo {
00146 str ip;
00147 str ip_line;
00148 str direction;
00149 str separator;
00150 StreamInfo streams[MAX_STREAMS];
00151 unsigned int stream_count;
00152 unsigned int supported_count;
00153 } SessionInfo;
00154
00155 typedef struct AVP_Param {
00156 str spec;
00157 int_str name;
00158 unsigned short type;
00159 } AVP_Param;
00160
00161 typedef struct ice_candidate_data {
00162 unsigned int priority;
00163 Bool skip_next_reply;
00164 } ice_candidate_data;
00165
00166
00167
00168 static int EngageMediaProxy(struct sip_msg *msg);
00169 static int UseMediaProxy(struct sip_msg *msg);
00170 static int EndMediaSession(struct sip_msg *msg);
00171
00172 static int mod_init(void);
00173 static int child_init(int rank);
00174
00175
00176
00177
00178 static int mediaproxy_disabled = False;
00179 static str ice_candidate = str_init("none");
00180
00181 static MediaproxySocket mediaproxy_socket = {
00182 "/var/run/mediaproxy/dispatcher.sock",
00183 -1,
00184 500,
00185 0,
00186 ""
00187 };
00188
00189
00190 struct dlg_binds dlg_api;
00191 Bool have_dlg_api = False;
00192 static int dialog_flag = -1;
00193
00194
00195 static AVP_Param signaling_ip_avp = {str_init(SIGNALING_IP_AVP_SPEC), {0}, 0};
00196
00197
00198 static AVP_Param media_relay_avp = {str_init(MEDIA_RELAY_AVP_SPEC), {0}, 0};
00199
00200
00201 static AVP_Param ice_candidate_avp = {str_init(ICE_CANDIDATE_AVP_SPEC), {0}, 0};
00202
00203 static cmd_export_t commands[] = {
00204 {"engage_media_proxy", (cmd_function)EngageMediaProxy, 0, 0, 0, REQUEST_ROUTE},
00205 {"use_media_proxy", (cmd_function)UseMediaProxy, 0, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | LOCAL_ROUTE},
00206 {"end_media_session", (cmd_function)EndMediaSession, 0, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | LOCAL_ROUTE},
00207 {0, 0, 0, 0, 0, 0}
00208 };
00209
00210 static param_export_t parameters[] = {
00211 {"disable", INT_PARAM, &mediaproxy_disabled},
00212 {"mediaproxy_socket", STR_PARAM, &(mediaproxy_socket.name)},
00213 {"mediaproxy_timeout", INT_PARAM, &(mediaproxy_socket.timeout)},
00214 {"signaling_ip_avp", STR_PARAM, &(signaling_ip_avp.spec.s)},
00215 {"media_relay_avp", STR_PARAM, &(media_relay_avp.spec.s)},
00216 {"ice_candidate", STR_PARAM, &(ice_candidate.s)},
00217 {"ice_candidate_avp", STR_PARAM, &(ice_candidate_avp.spec.s)},
00218 {0, 0, 0}
00219 };
00220
00221 struct module_exports exports = {
00222 "mediaproxy",
00223 DEFAULT_DLFLAGS,
00224 commands,
00225 parameters,
00226 NULL,
00227 NULL,
00228 NULL,
00229 NULL,
00230 mod_init,
00231 NULL,
00232 NULL,
00233 child_init
00234 };
00235
00236
00237
00238
00239
00240
00241
00242
00243 static void*
00244 strfind(const void *haystack, size_t len, const void *needle, size_t nlen)
00245 {
00246 char *sp;
00247
00248
00249 if(!(haystack && needle && nlen && len>=nlen))
00250 return NULL;
00251
00252 for (sp = (char*)haystack; sp <= (char*)haystack + len - nlen; sp++) {
00253 if (*sp == *(char*)needle && memcmp(sp, needle, nlen)==0) {
00254 return sp;
00255 }
00256 }
00257
00258 return NULL;
00259 }
00260
00261
00262
00263
00264 static void*
00265 strcasefind(const char *haystack, size_t len, const char *needle, size_t nlen)
00266 {
00267 char *sp;
00268
00269
00270 if(!(haystack && needle && nlen && len>=nlen))
00271 return NULL;
00272
00273 for (sp = (char*)haystack; sp <= (char*)haystack + len - nlen; sp++) {
00274 if (tolower(*sp) == tolower(*(char*)needle) &&
00275 strncasecmp(sp, needle, nlen)==0) {
00276 return sp;
00277 }
00278 }
00279
00280 return NULL;
00281 }
00282
00283
00284 static INLINE void
00285 ltrim(str *string)
00286 {
00287 while (string->len>0 && isspace((int)*(string->s))) {
00288 string->len--;
00289 string->s++;
00290 }
00291 }
00292
00293
00294 static INLINE void
00295 rtrim(str *string)
00296 {
00297 char *ptr;
00298
00299 ptr = string->s + string->len - 1;
00300 while (string->len>0 && (*ptr==0 || isspace((int)*ptr))) {
00301 string->len--;
00302 ptr--;
00303 }
00304 }
00305
00306
00307 static INLINE void
00308 trim(str *string)
00309 {
00310 ltrim(string);
00311 rtrim(string);
00312 }
00313
00314
00315 static char*
00316 findendline(char *string, int len)
00317 {
00318 char *ptr = string;
00319
00320 while(ptr - string < len && *ptr != '\n' && *ptr != '\r')
00321 ptr++;
00322
00323 return ptr;
00324 }
00325
00326
00327 static int
00328 strtoint(str *data)
00329 {
00330 long int result;
00331 char c;
00332
00333
00334 c = data->s[data->len];
00335 data->s[data->len] = 0;
00336 result = strtol(data->s, NULL, 10);
00337 data->s[data->len] = c;
00338
00339 return (int)result;
00340 }
00341
00342
00343
00344 static char*
00345 find_line_starting_with(str *block, char *start, int ignoreCase)
00346 {
00347 char *ptr, *bend;
00348 str zone;
00349 int tlen;
00350
00351 bend = block->s + block->len;
00352 tlen = strlen(start);
00353 ptr = NULL;
00354
00355 for (zone = *block; zone.len > 0; zone.len = bend - zone.s) {
00356 if (ignoreCase)
00357 ptr = strcasefind(zone.s, zone.len, start, tlen);
00358 else
00359 ptr = strfind(zone.s, zone.len, start, tlen);
00360 if (!ptr || ptr==block->s || ptr[-1]=='\n' || ptr[-1]=='\r')
00361 break;
00362 zone.s = ptr + tlen;
00363 }
00364
00365 return ptr;
00366 }
00367
00368
00369
00370 static unsigned int
00371 count_lines_starting_with(str *block, char *start, int ignoreCase)
00372 {
00373 char *ptr, *bend;
00374 str zone;
00375 int tlen;
00376 unsigned count;
00377
00378 bend = block->s + block->len;
00379 tlen = strlen(start);
00380
00381 count = 0;
00382
00383 for (zone = *block; zone.len > 0; zone.len = bend - zone.s) {
00384 if (ignoreCase)
00385 ptr = strcasefind(zone.s, zone.len, start, tlen);
00386 else
00387 ptr = strfind(zone.s, zone.len, start, tlen);
00388 if (!ptr)
00389 break;
00390 if (ptr==block->s || ptr[-1]=='\n' || ptr[-1]=='\r')
00391 count++;
00392 zone.s = ptr + tlen;
00393 }
00394
00395 return count;
00396 }
00397
00398
00399
00400 static int
00401 get_tokens(char *string, str *tokens, int limit)
00402 {
00403 int i, len, size;
00404 char *ptr;
00405
00406 if (!string) {
00407 return 0;
00408 }
00409
00410 len = strlen(string);
00411
00412 for (ptr=string, i=0; i<limit && len>0; i++) {
00413 size = strspn(ptr, " \t\n\r");
00414 ptr += size;
00415 len -= size;
00416 if (len <= 0)
00417 break;
00418 size = strcspn(ptr, " \t\n\r");
00419 if (size==0)
00420 break;
00421 tokens[i].s = ptr;
00422 tokens[i].len = size;
00423 ptr += size;
00424 len -= size;
00425 }
00426
00427 return i;
00428 }
00429
00430
00431 static int
00432 get_str_tokens(str *string, str *tokens, int limit)
00433 {
00434 int count;
00435 char c;
00436
00437 if (!string || !string->s) {
00438 return 0;
00439 }
00440
00441 c = string->s[string->len];
00442 string->s[string->len] = 0;
00443
00444 count = get_tokens(string->s, tokens, limit);
00445
00446 string->s[string->len] = c;
00447
00448 return count;
00449 }
00450
00451
00452
00453
00454
00455 static Bool
00456 get_callid(struct sip_msg* msg, str *cid)
00457 {
00458 if (msg->callid == NULL) {
00459 if (parse_headers(msg, HDR_CALLID_F, 0) == -1) {
00460 LM_ERR("cannot parse Call-ID header\n");
00461 return False;
00462 }
00463 if (msg->callid == NULL) {
00464 LM_ERR("missing Call-ID header\n");
00465 return False;
00466 }
00467 }
00468
00469 *cid = msg->callid->body;
00470
00471 trim(cid);
00472
00473 return True;
00474 }
00475
00476 static Bool
00477 get_cseq_number(struct sip_msg *msg, str *cseq)
00478 {
00479 if (msg->cseq == NULL) {
00480 if (parse_headers(msg, HDR_CSEQ_F, 0)==-1) {
00481 LM_ERR("cannot parse CSeq header\n");
00482 return False;
00483 }
00484 if (msg->cseq == NULL) {
00485 LM_ERR("missing CSeq header\n");
00486 return False;
00487 }
00488 }
00489
00490 *cseq = get_cseq(msg)->number;
00491
00492 if (cseq->s==NULL || cseq->len==0) {
00493 LM_ERR("missing CSeq number\n");
00494 return False;
00495 }
00496
00497 return True;
00498 }
00499
00500 static str
00501 get_from_uri(struct sip_msg *msg)
00502 {
00503 static str unknown = str_init("unknown");
00504 str uri;
00505 char *ptr;
00506
00507 if (parse_from_header(msg) < 0) {
00508 LM_ERR("cannot parse the From header\n");
00509 return unknown;
00510 }
00511
00512 uri = get_from(msg)->uri;
00513
00514 if (uri.len == 0)
00515 return unknown;
00516
00517 if (strncasecmp(uri.s, "sip:", 4)==0) {
00518 uri.s += 4;
00519 uri.len -= 4;
00520 }
00521
00522 if ((ptr = strfind(uri.s, uri.len, ";", 1))!=NULL) {
00523 uri.len = ptr - uri.s;
00524 }
00525
00526 return uri;
00527 }
00528
00529
00530 static str
00531 get_to_uri(struct sip_msg *msg)
00532 {
00533 static str unknown = str_init("unknown");
00534 str uri;
00535 char *ptr;
00536
00537 if (!msg->to) {
00538 LM_ERR("missing To header\n");
00539 return unknown;
00540 }
00541
00542 uri = get_to(msg)->uri;
00543
00544 if (uri.len == 0)
00545 return unknown;
00546
00547 if (strncasecmp(uri.s, "sip:", 4)==0) {
00548 uri.s += 4;
00549 uri.len -= 4;
00550 }
00551
00552 if ((ptr = strfind(uri.s, uri.len, ";", 1))!=NULL) {
00553 uri.len = ptr - uri.s;
00554 }
00555
00556 return uri;
00557 }
00558
00559
00560 static str
00561 get_from_tag(struct sip_msg *msg)
00562 {
00563 static str undefined = str_init("");
00564 str tag;
00565
00566 if (parse_from_header(msg) < 0) {
00567 LM_ERR("cannot parse the From header\n");
00568 return undefined;
00569 }
00570
00571 tag = get_from(msg)->tag_value;
00572
00573 if (tag.len == 0)
00574 return undefined;
00575
00576 return tag;
00577 }
00578
00579
00580 static str
00581 get_to_tag(struct sip_msg *msg)
00582 {
00583 static str undefined = str_init("");
00584 str tag;
00585
00586 if (msg->first_line.type==SIP_REPLY && msg->REPLY_STATUS<200) {
00587
00588 return undefined;
00589 }
00590
00591 if (!msg->to) {
00592 LM_ERR("missing To header\n");
00593 return undefined;
00594 }
00595
00596 tag = get_to(msg)->tag_value;
00597
00598 if (tag.len == 0)
00599 return undefined;
00600
00601 return tag;
00602 }
00603
00604
00605 static str
00606 get_user_agent(struct sip_msg* msg)
00607 {
00608 static str unknown = str_init("unknown agent");
00609 str block, server;
00610 char *ptr;
00611
00612 if (parse_headers(msg, HDR_USERAGENT_F, 0)==0 && msg->user_agent &&
00613 msg->user_agent->body.s && msg->user_agent->body.len>0) {
00614 return msg->user_agent->body;
00615 }
00616
00617
00618
00619
00620 block.s = msg->buf;
00621 block.len = msg->len;
00622
00623 ptr = find_line_starting_with(&block, "Server:", True);
00624 if (!ptr)
00625 return unknown;
00626
00627 server.s = ptr + 7;
00628 server.len = findendline(server.s, block.s+block.len-server.s) - server.s;
00629
00630 trim(&server);
00631 if (server.len == 0)
00632 return unknown;
00633
00634 return server;
00635 }
00636
00637
00638
00639 static str
00640 get_signaling_ip(struct sip_msg* msg)
00641 {
00642 int_str value;
00643
00644 if (!search_first_avp(signaling_ip_avp.type | AVP_VAL_STR,
00645 signaling_ip_avp.name, &value, NULL) ||
00646 value.s.s==NULL || value.s.len==0) {
00647
00648 value.s.s = ip_addr2a(&msg->rcv.src_ip);
00649 value.s.len = strlen(value.s.s);
00650 }
00651
00652 return value.s;
00653 }
00654
00655
00656 static str
00657 get_media_relay(struct sip_msg* msg)
00658 {
00659 static str undefined = str_init("");
00660 int_str value;
00661
00662 if (!search_first_avp(media_relay_avp.type | AVP_VAL_STR,
00663 media_relay_avp.name, &value, NULL) || value.s.s==NULL || value.s.len==0) {
00664 return undefined;
00665 }
00666
00667 return value.s;
00668 }
00669
00670
00671
00672
00673
00674
00675 static int
00676 find_content_type_application_sdp(struct sip_msg *msg, str *sdp)
00677 {
00678 str type, params, boundary;
00679 char *start, *s;
00680 unsigned int len;
00681 Bool done;
00682 param_hooks_t hooks;
00683 param_t *p, *list;
00684
00685 if (!msg->content_type) {
00686 LM_WARN("the Content-Type header is missing! Assume the content type is text/plain\n");
00687 return 1;
00688 }
00689
00690 type = msg->content_type->body;
00691 trim(&type);
00692
00693 if (strncasecmp(type.s, "application/sdp", 15) == 0) {
00694 done = True;
00695 } else if (strncasecmp(type.s, "multipart/mixed", 15) == 0) {
00696 done = False;
00697 } else {
00698 LM_ERR("invalid Content-Type for SDP: %.*s\n", type.len, type.s);
00699 return -1;
00700 }
00701
00702 if (!(isspace((int)type.s[15]) || type.s[15] == ';' || type.s[15] == 0)) {
00703 LM_ERR("invalid character after Content-Type: `%c'\n", type.s[15]);
00704 return -1;
00705 }
00706
00707 if (done) return 1;
00708
00709
00710 params.s = memchr(msg->content_type->body.s, ';',
00711 msg->content_type->body.len);
00712 if (params.s == NULL) {
00713 LM_ERR("Content-Type hdr has no params\n");
00714 return -1;
00715 }
00716 params.len = msg->content_type->body.len -
00717 (params.s - msg->content_type->body.s);
00718 if (parse_params(¶ms, CLASS_ANY, &hooks, &list) < 0) {
00719 LM_ERR("while parsing Content-Type params\n");
00720 return -1;
00721 }
00722 boundary.s = NULL;
00723 boundary.len = 0;
00724 for (p = list; p; p = p->next) {
00725 if ((p->name.len == 8)
00726 && (strncasecmp(p->name.s, "boundary", 8) == 0)) {
00727 boundary.s = pkg_malloc(p->body.len + 2 + 1);
00728 if (boundary.s == NULL) {
00729 free_params(list);
00730 LM_ERR("no memory for boundary string\n");
00731 return -1;
00732 }
00733 *(boundary.s) = '-';
00734 *(boundary.s + 1) = '-';
00735 memcpy(boundary.s + 2, p->body.s, p->body.len);
00736 boundary.len = 2 + p->body.len;
00737 *(boundary.s + boundary.len) = 0;
00738 LM_DBG("boundary is <%.*s>\n", boundary.len, boundary.s);
00739 break;
00740 }
00741 }
00742 free_params(list);
00743 if (boundary.s == NULL) {
00744 LM_ERR("no mandatory param \";boundary\"\n");
00745 return -1;
00746 }
00747
00748 while ((s = find_line_starting_with(sdp, "Content-Type: ", True))) {
00749 start = s + 14;
00750 len = sdp->len - (s - sdp->s) - 14;
00751 if (len > 15 + 2) {
00752 if (strncasecmp(start, "application/sdp", 15) == 0) {
00753 start = start + 15;
00754 if ((*start != 13) || (*(start + 1) != 10)) {
00755 LM_ERR("no CRLF found after content type\n");
00756 goto err;
00757 }
00758 start = start + 2;
00759 len = len - 15 - 2;
00760 while ((len > 0) && ((*start == 13) || (*start == 10))) {
00761 len = len - 1;
00762 start = start + 1;
00763 }
00764 sdp->s = start;
00765 sdp->len = len;
00766 s = find_line_starting_with(sdp, boundary.s, False);
00767 if (s == NULL) {
00768 LM_ERR("boundary not found after bodypart\n");
00769 goto err;
00770 }
00771 sdp->len = s - start - 2;
00772 pkg_free(boundary.s);
00773 return 1;
00774 }
00775 }
00776 }
00777 LM_ERR("no application/sdp bodypart found\n");
00778
00779 err:
00780 pkg_free(boundary.s);
00781 return -1;
00782 }
00783
00784
00785
00786
00787
00788
00789
00790 static int
00791 get_sdp_message(struct sip_msg *msg, str *sdp)
00792 {
00793 sdp->s = get_body(msg);
00794 if (sdp->s==NULL) {
00795 LM_ERR("cannot get the SDP body\n");
00796 return -1;
00797 }
00798
00799 sdp->len = msg->buf + msg->len - sdp->s;
00800 if (sdp->len == 0)
00801 return -2;
00802
00803 return find_content_type_application_sdp(msg, sdp);
00804 }
00805
00806
00807
00808 static str
00809 get_sdp_line_separator(str *sdp)
00810 {
00811 char *ptr, *end_ptr, *sdp_end;
00812 str separator;
00813
00814 sdp_end = sdp->s + sdp->len;
00815
00816 ptr = find_line_starting_with(sdp, "v=", False);
00817 end_ptr = findendline(ptr, sdp_end-ptr);
00818 separator.s = ptr = end_ptr;
00819 while ((*ptr=='\n' || *ptr=='\r') && ptr<sdp_end)
00820 ptr++;
00821 separator.len = ptr - separator.s;
00822 if (separator.len > 2)
00823 separator.len = 2;
00824
00825 return separator;
00826 }
00827
00828
00829
00830
00831 static str
00832 get_direction_attribute(str *block, str *default_direction)
00833 {
00834 str direction, zone, line;
00835 char *ptr;
00836
00837 for (zone=*block;;) {
00838 ptr = find_line_starting_with(&zone, "a=", False);
00839 if (!ptr) {
00840 if (default_direction)
00841 return *default_direction;
00842 direction.s = "sendrecv";
00843 direction.len = 8;
00844 return direction;
00845 }
00846
00847 line.s = ptr + 2;
00848 line.len = findendline(line.s, zone.s + zone.len - line.s) - line.s;
00849
00850 if (line.len==8) {
00851 if (strncasecmp(line.s, "sendrecv", 8)==0 || strncasecmp(line.s, "sendonly", 8)==0 ||
00852 strncasecmp(line.s, "recvonly", 8)==0 || strncasecmp(line.s, "inactive", 8)==0) {
00853 return line;
00854 }
00855 }
00856
00857 zone.s = line.s + line.len;
00858 zone.len = block->s + block->len - zone.s;
00859 }
00860 }
00861
00862
00863
00864
00865 static str
00866 get_rtcp_port_attribute(str *block)
00867 {
00868 str zone, rtcp_port, undefined = {NULL, 0};
00869 char *ptr;
00870 int count;
00871
00872 ptr = find_line_starting_with(block, "a=rtcp:", False);
00873
00874 if (!ptr)
00875 return undefined;
00876
00877 zone.s = ptr + 7;
00878 zone.len = findendline(zone.s, block->s + block->len - zone.s) - zone.s;
00879
00880 count = get_str_tokens(&zone, &rtcp_port, 1);
00881
00882 if (count != 1) {
00883 LM_ERR("invalid `a=rtcp' line in SDP body\n");
00884 return undefined;
00885 }
00886
00887 return rtcp_port;
00888 }
00889
00890
00891
00892
00893 static str
00894 get_rtcp_ip_attribute(str *block)
00895 {
00896 str zone, tokens[4], undefined = {NULL, 0};
00897 char *ptr;
00898 int count;
00899
00900 ptr = find_line_starting_with(block, "a=rtcp:", False);
00901
00902 if (!ptr)
00903 return undefined;
00904
00905 zone.s = ptr + 7;
00906 zone.len = findendline(zone.s, block->s + block->len - zone.s) - zone.s;
00907
00908 count = get_str_tokens(&zone, tokens, 4);
00909
00910 if (count != 4) {
00911 return undefined;
00912 }
00913
00914 return tokens[3];
00915 }
00916
00917
00918
00919
00920 static Bool
00921 has_ice_attributes(str *block)
00922 {
00923 char *ptr;
00924 ptr = find_line_starting_with(block, "a=ice-pwd:", False);
00925 if (ptr) {
00926 ptr = find_line_starting_with(block, "a=ice-ufrag:", False);
00927 if (ptr) {
00928 return True;
00929 }
00930 }
00931 return False;
00932 }
00933
00934
00935
00936
00937
00938 static Bool
00939 has_session_ice_attributes(str *sdp)
00940 {
00941 str block;
00942 char *ptr;
00943
00944
00945 ptr = find_line_starting_with(sdp, "m=", False);
00946 if (ptr) {
00947 block.s = sdp->s;
00948 block.len = ptr - block.s;
00949 } else {
00950 block = *sdp;
00951 }
00952
00953 return has_ice_attributes(&block);
00954 }
00955
00956
00957
00958
00959
00960
00961 static Bool
00962 has_ice_candidates(str *block)
00963 {
00964 char *ptr;
00965 ptr = find_line_starting_with(block, "a=candidate:", False);
00966 if (ptr) {
00967 return True;
00968 }
00969 return False;
00970 }
00971
00972
00973
00974
00975 static Bool
00976 has_ice_candidate_component(str *block, int id)
00977 {
00978 char *ptr, *block_end;
00979 int i, components, count;
00980 str chunk, zone, tokens[2];
00981
00982 block_end = block->s + block->len;
00983 components = count_lines_starting_with(block, "a=candidate:", False);
00984 for (i=0, chunk=*block; i<components; i++) {
00985 ptr = find_line_starting_with(&chunk, "a=candidate:", False);
00986 if (!ptr)
00987 break;
00988
00989 zone.s = ptr + 12;
00990 zone.len = findendline(zone.s, block_end - zone.s) - zone.s;
00991 count = get_str_tokens(&zone, tokens, 2);
00992
00993 if (count == 2) {
00994 if (strtoint(&tokens[1]) == id) {
00995 return True;
00996 }
00997 }
00998
00999 chunk.s = zone.s + zone.len;
01000 chunk.len = block_end - chunk.s;
01001 }
01002 return False;
01003 }
01004
01005
01006
01007
01008 static str
01009 get_ice_candidate(void)
01010 {
01011 int_str value;
01012
01013 if (!search_first_avp(ice_candidate_avp.type | AVP_VAL_STR,
01014 ice_candidate_avp.name, &value, NULL) || value.s.s==NULL || value.s.len==0) {
01015
01016 return ice_candidate;
01017 } else {
01018 return value.s;
01019 }
01020 }
01021
01022
01023
01024
01025 static unsigned int
01026 get_ice_candidate_priority(str priority)
01027 {
01028 int type_pref;
01029
01030 if (STR_IMATCH(priority, "high-priority")) {
01031
01032 type_pref = 130;
01033 } else if (STR_IMATCH(priority, "low-priority")) {
01034 type_pref = 0;
01035 } else {
01036 return NO_CANDIDATE;
01037 }
01038
01039
01040 return ((type_pref << 24) + 16777215);
01041 }
01042
01043
01044
01045
01046 static int
01047 get_media_ip_from_block(str *block, str *mediaip)
01048 {
01049 str tokens[3], zone;
01050 char *ptr;
01051 int count;
01052
01053 ptr = find_line_starting_with(block, "c=", False);
01054
01055 if (!ptr) {
01056 mediaip->s = NULL;
01057 mediaip->len = 0;
01058 return 0;
01059 }
01060
01061 zone.s = ptr + 2;
01062 zone.len = findendline(zone.s, block->s + block->len - zone.s) - zone.s;
01063
01064 count = get_str_tokens(&zone, tokens, 3);
01065
01066 if (count != 3) {
01067 LM_ERR("invalid `c=' line in SDP body\n");
01068 return -1;
01069 }
01070
01071
01072 *mediaip = tokens[2];
01073
01074 return 1;
01075 }
01076
01077
01078 static Bool
01079 get_sdp_session_ip(str *sdp, str *mediaip, str *ip_line)
01080 {
01081 char *ptr, *end_ptr;
01082 str block;
01083
01084
01085 ptr = find_line_starting_with(sdp, "m=", False);
01086 if (ptr) {
01087 block.s = sdp->s;
01088 block.len = ptr - block.s;
01089 } else {
01090 block = *sdp;
01091 }
01092
01093 if (get_media_ip_from_block(&block, mediaip) == -1) {
01094 LM_ERR("parse error while getting session-level media IP from SDP\n");
01095 return False;
01096 }
01097
01098 if (ip_line != NULL) {
01099 ptr = find_line_starting_with(&block, "c=", False);
01100 if (!ptr) {
01101 ip_line->s = NULL;
01102 ip_line->len = 0;
01103 } else {
01104 end_ptr = findendline(ptr, block.s + block.len - ptr);
01105 while ((*end_ptr=='\n' || *end_ptr=='\r'))
01106 end_ptr++;
01107 ip_line->s = ptr;
01108 ip_line->len = end_ptr - ptr;
01109 }
01110 }
01111
01112
01113
01114 return True;
01115 }
01116
01117
01118
01119
01120 static str
01121 get_session_direction(str *sdp)
01122 {
01123 static str default_direction = str_init("sendrecv");
01124 str block;
01125 char *ptr;
01126
01127
01128 ptr = find_line_starting_with(sdp, "m=", False);
01129 if (ptr) {
01130 block.s = sdp->s;
01131 block.len = ptr - block.s;
01132 } else {
01133 block = *sdp;
01134 }
01135
01136 return get_direction_attribute(&block, &default_direction);
01137 }
01138
01139
01140
01141 static int
01142 get_method_from_reply(struct sip_msg *reply)
01143 {
01144 struct cseq_body *cseq;
01145
01146 if (reply->first_line.type != SIP_REPLY)
01147 return -1;
01148
01149 if (!reply->cseq && parse_headers(reply, HDR_CSEQ_F, 0) < 0) {
01150 LM_ERR("failed to parse the CSeq header\n");
01151 return -1;
01152 }
01153 if (!reply->cseq) {
01154 LM_ERR("missing CSeq header\n");
01155 return -1;
01156 }
01157 cseq = reply->cseq->parsed;
01158 return cseq->method_id;
01159 }
01160
01161 static Bool
01162 supported_transport(str transport)
01163 {
01164
01165 str prefixes[] = {str_init("RTP"), str_init("udp"), {NULL, 0}};
01166 int i;
01167
01168 for (i=0; prefixes[i].s != NULL; i++) {
01169 if (STR_HAS_IPREFIX(transport, prefixes[i])) {
01170 return True;
01171 }
01172 }
01173
01174 return False;
01175 }
01176
01177
01178 static int
01179 get_session_info(str *sdp, SessionInfo *session)
01180 {
01181 str tokens[3], ip, ip_line, block, zone;
01182 char *ptr, *sdp_end;
01183 int i, count, result;
01184
01185 count = count_lines_starting_with(sdp, "v=", False);
01186 if (count != 1) {
01187 LM_ERR("cannot handle more than 1 media session in SDP\n");
01188 return -1;
01189 }
01190
01191 count = count_lines_starting_with(sdp, "m=", False);
01192 if (count > MAX_STREAMS) {
01193 LM_ERR("cannot handle more than %d media streams in SDP\n", MAX_STREAMS);
01194 return -1;
01195 }
01196
01197 memset(session, 0, sizeof(SessionInfo));
01198
01199 if (count == 0)
01200 return 0;
01201
01202 if (!get_sdp_session_ip(sdp, &ip, &ip_line)) {
01203 LM_ERR("failed to parse the SDP message\n");
01204 return -1;
01205 }
01206
01207 ptr = memchr(ip.s, '/', ip.len);
01208 if (ptr) {
01209 LM_ERR("unsupported multicast IP specification in SDP: %.*s\n", ip.len, ip.s);
01210 return -1;
01211 }
01212
01213 session->ip = ip;
01214 session->ip_line = ip_line;
01215 session->direction = get_session_direction(sdp);
01216 session->separator = get_sdp_line_separator(sdp);
01217 session->stream_count = count;
01218
01219 sdp_end = sdp->s + sdp->len;
01220
01221 for (i=0, block=*sdp; i<MAX_STREAMS; i++) {
01222 ptr = find_line_starting_with(&block, "m=", False);
01223
01224 if (!ptr)
01225 break;
01226
01227 zone.s = ptr + 2;
01228 zone.len = findendline(zone.s, sdp_end - zone.s) - zone.s;
01229
01230 count = get_str_tokens(&zone, tokens, 3);
01231 if (count != 3) {
01232 LM_ERR("invalid `m=' line in the SDP body\n");
01233 return -1;
01234 }
01235
01236 session->streams[i].start_line = ptr;
01237 session->streams[i].next_line = zone.s + zone.len + session->separator.len;
01238 if (session->streams[i].next_line > sdp_end)
01239 session->streams[i].next_line = sdp_end;
01240
01241 if (supported_transport(tokens[2])) {
01242
01243
01244
01245 ptr = memchr(tokens[1].s, '/', tokens[1].len);
01246 if (ptr != NULL) {
01247 str port_nr;
01248
01249 port_nr.s = ptr + 1;
01250 port_nr.len = tokens[1].s + tokens[1].len - port_nr.s;
01251 if (port_nr.len==0) {
01252 LM_ERR("invalid port specification in `m=' line: %.*s\n", tokens[1].len, tokens[1].s);
01253 return -1;
01254 }
01255 if (!(port_nr.len==1 && port_nr.s[0]=='1')) {
01256 LM_ERR("unsupported number of ports specified in `m=' line\n");
01257 return -1;
01258 }
01259 tokens[1].len = ptr - tokens[1].s;
01260 }
01261
01262 session->streams[i].type = tokens[0];
01263 session->streams[i].port = tokens[1];
01264
01265 session->streams[i].transport = TSupported;
01266 session->supported_count++;
01267 } else {
01268
01269 LM_INFO("unsupported transport in stream nr %d's `m=' line: %.*s\n", i+1, tokens[2].len, tokens[2].s);
01270 session->streams[i].type = tokens[0];
01271 session->streams[i].port = tokens[1];
01272 session->streams[i].transport = TUnsupported;
01273 }
01274
01275 block.s = zone.s + zone.len;
01276 block.len = sdp_end - block.s;
01277 }
01278
01279 for (i=0; i<session->stream_count; i++) {
01280 block.s = session->streams[i].port.s;
01281 if (i < session->stream_count-1)
01282 block.len = session->streams[i+1].port.s - block.s;
01283 else
01284 block.len = sdp_end - block.s;
01285
01286 result = get_media_ip_from_block(&block, &ip);
01287 if (result == -1) {
01288 LM_ERR("parse error while getting the contact IP for the "
01289 "media stream number %d\n", i+1);
01290 return -1;
01291 } else if (result == 0) {
01292 if (session->ip.s == NULL) {
01293 LM_ERR("media stream number %d doesn't define a contact IP "
01294 "and the session-level IP is missing\n", i+1);
01295 return -1;
01296 }
01297 session->streams[i].ip = session->ip;
01298 session->streams[i].local_ip = 0;
01299 } else {
01300 if (session->streams[i].transport == TSupported) {
01301 ptr = memchr(ip.s, '/', ip.len);
01302 if (ptr) {
01303 LM_ERR("unsupported multicast IP specification in stream nr %d: %.*s\n", i+1, ip.len, ip.s);
01304 return -1;
01305 }
01306 }
01307 session->streams[i].ip = ip;
01308 session->streams[i].local_ip = 1;
01309 }
01310
01311 session->streams[i].rtcp_ip = get_rtcp_ip_attribute(&block);
01312 session->streams[i].rtcp_port = get_rtcp_port_attribute(&block);
01313 session->streams[i].direction = get_direction_attribute(&block, &session->direction);
01314 session->streams[i].has_ice = ((has_ice_attributes(&block) || has_session_ice_attributes(sdp)) && has_ice_candidates(&block));
01315 session->streams[i].has_rtcp_ice = has_ice_candidate_component(&block, 2);
01316 session->streams[i].first_ice_candidate = find_line_starting_with(&block, "a=candidate:", False);
01317 }
01318
01319 return session->stream_count;
01320 }
01321
01322
01323 static Bool
01324 insert_element(struct sip_msg *msg, char *position, char *element)
01325 {
01326 struct lump *anchor;
01327 char *buf;
01328 int len;
01329
01330 len = strlen(element);
01331
01332 buf = pkg_malloc(len);
01333 if (!buf) {
01334 LM_ERR("out of memory\n");
01335 return False;
01336 }
01337
01338 anchor = anchor_lump(msg, position - msg->buf, 0, 0);
01339 if (!anchor) {
01340 LM_ERR("failed to get anchor for new element\n");
01341 pkg_free(buf);
01342 return False;
01343 }
01344
01345 memcpy(buf, element, len);
01346
01347 if (insert_new_lump_after(anchor, buf, len, 0)==0) {
01348 LM_ERR("failed to insert new element\n");
01349 pkg_free(buf);
01350 return False;
01351 }
01352
01353 return True;
01354 }
01355
01356
01357 static Bool
01358 replace_element(struct sip_msg *msg, str *old_element, str *new_element)
01359 {
01360 struct lump *anchor;
01361 char *buf;
01362
01363 if (new_element->len==old_element->len &&
01364 memcmp(new_element->s, old_element->s, new_element->len)==0) {
01365 return True;
01366 }
01367
01368 buf = pkg_malloc(new_element->len);
01369 if (!buf) {
01370 LM_ERR("out of memory\n");
01371 return False;
01372 }
01373
01374 anchor = del_lump(msg, old_element->s - msg->buf, old_element->len, 0);
01375 if (!anchor) {
01376 LM_ERR("failed to delete old element\n");
01377 pkg_free(buf);
01378 return False;
01379 }
01380
01381 memcpy(buf, new_element->s, new_element->len);
01382
01383 if (insert_new_lump_after(anchor, buf, new_element->len, 0)==0) {
01384 LM_ERR("failed to insert new element\n");
01385 pkg_free(buf);
01386 return False;
01387 }
01388
01389 return True;
01390 }
01391
01392
01393 static Bool
01394 remove_element(struct sip_msg *msg, str *element)
01395 {
01396 if (!del_lump(msg, element->s - msg->buf, element->len, 0)) {
01397 LM_ERR("failed to delete old element\n");
01398 return False;
01399 }
01400
01401 return True;
01402 }
01403
01404
01405
01406
01407
01408 static Bool
01409 mediaproxy_connect(void)
01410 {
01411 struct sockaddr_un addr;
01412
01413 if (mediaproxy_socket.sock >= 0)
01414 return True;
01415
01416 if (mediaproxy_socket.last_failure + RETRY_INTERVAL > time(NULL))
01417 return False;
01418
01419 memset(&addr, 0, sizeof(addr));
01420 addr.sun_family = AF_LOCAL;
01421 strncpy(addr.sun_path, mediaproxy_socket.name, sizeof(addr.sun_path) - 1);
01422 #ifdef HAVE_SOCKADDR_SA_LEN
01423 addr.sun_len = strlen(addr.sun_path);
01424 #endif
01425
01426 mediaproxy_socket.sock = socket(AF_LOCAL, SOCK_STREAM, 0);
01427 if (mediaproxy_socket.sock < 0) {
01428 LM_ERR("can't create socket\n");
01429 mediaproxy_socket.last_failure = time(NULL);
01430 return False;
01431 }
01432 if (connect(mediaproxy_socket.sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
01433 LM_ERR("failed to connect to %s: %s\n", mediaproxy_socket.name, strerror(errno));
01434 close(mediaproxy_socket.sock);
01435 mediaproxy_socket.sock = -1;
01436 mediaproxy_socket.last_failure = time(NULL);
01437 return False;
01438 }
01439
01440 return True;
01441 }
01442
01443 static void
01444 mediaproxy_disconnect(void)
01445 {
01446 if (mediaproxy_socket.sock < 0)
01447 return;
01448
01449 close(mediaproxy_socket.sock);
01450 mediaproxy_socket.sock = -1;
01451 mediaproxy_socket.last_failure = time(NULL);
01452 }
01453
01454 static char*
01455 send_command(char *command)
01456 {
01457 int cmd_len, bytes, tries, sent, received, count;
01458 struct timeval timeout;
01459 fd_set rset;
01460
01461 if (!mediaproxy_connect())
01462 return NULL;
01463
01464 cmd_len = strlen(command);
01465
01466 for (sent=0, tries=0; sent<cmd_len && tries<3; tries++, sent+=bytes) {
01467 do
01468 bytes = send(mediaproxy_socket.sock, command+sent, cmd_len-sent, MSG_DONTWAIT|MSG_NOSIGNAL);
01469 while (bytes == -1 && errno == EINTR);
01470 if (bytes == -1) {
01471 switch (errno) {
01472 case ECONNRESET:
01473 case EPIPE:
01474 mediaproxy_disconnect();
01475 mediaproxy_socket.last_failure = 0;
01476 if (mediaproxy_connect()) {
01477 sent = bytes = 0;
01478 continue;
01479 } else {
01480 LM_ERR("connection with mediaproxy did die\n");
01481 }
01482 break;
01483 case EACCES:
01484 LM_ERR("got permission denied while sending to %s\n", mediaproxy_socket.name);
01485 break;
01486 case EWOULDBLOCK:
01487
01488
01489 LM_ERR("sending command would block!\n");
01490 break;
01491 default:
01492 LM_ERR("%d: %s\n", errno, strerror(errno));
01493 break;
01494 }
01495 mediaproxy_disconnect();
01496 return NULL;
01497 }
01498 }
01499 if (sent < cmd_len) {
01500 LM_ERR("couldn't send complete command after 3 tries\n");
01501 mediaproxy_disconnect();
01502 return NULL;
01503 }
01504
01505 mediaproxy_socket.data[0] = 0;
01506 received = 0;
01507 while (True) {
01508 FD_ZERO(&rset);
01509 FD_SET(mediaproxy_socket.sock, &rset);
01510 timeout.tv_sec = mediaproxy_socket.timeout / 1000;
01511 timeout.tv_usec = (mediaproxy_socket.timeout % 1000) * 1000;
01512
01513 do
01514 count = select(mediaproxy_socket.sock + 1, &rset, NULL, NULL, &timeout);
01515 while (count == -1 && errno == EINTR);
01516
01517 if (count == -1) {
01518 LM_ERR("select failed: %d: %s\n", errno, strerror(errno));
01519 mediaproxy_disconnect();
01520 return NULL;
01521 } else if (count == 0) {
01522 LM_ERR("did timeout waiting for an answer\n");
01523 mediaproxy_disconnect();
01524 return NULL;
01525 } else {
01526 do
01527 bytes = recv(mediaproxy_socket.sock, mediaproxy_socket.data+received, BUFFER_SIZE-1-received, 0);
01528 while (bytes == -1 && errno == EINTR);
01529 if (bytes == -1) {
01530 LM_ERR("failed to read answer: %d: %s\n", errno, strerror(errno));
01531 mediaproxy_disconnect();
01532 return NULL;
01533 } else if (bytes == 0) {
01534 LM_ERR("connection with mediaproxy closed\n");
01535 mediaproxy_disconnect();
01536 return NULL;
01537 } else {
01538 mediaproxy_socket.data[received+bytes] = 0;
01539 if (strstr(mediaproxy_socket.data+received, "\r\n")!=NULL) {
01540 break;
01541 }
01542 received += bytes;
01543 }
01544 }
01545 }
01546
01547 return mediaproxy_socket.data;
01548 }
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560 static int
01561 use_media_proxy(struct sip_msg *msg, char *dialog_id, ice_candidate_data *ice_data)
01562 {
01563 str callid, cseq, from_uri, to_uri, from_tag, to_tag, user_agent;
01564 str signaling_ip, media_relay, sdp, str_buf, tokens[MAX_STREAMS+1];
01565 str priority_str, candidate;
01566 char request[8192], media_str[4096], buf[128], *result, *type;
01567 int i, j, port, len, status;
01568 Bool removed_session_ip, have_sdp;
01569 SessionInfo session;
01570 StreamInfo stream;
01571 unsigned int priority;
01572
01573 if (msg == NULL)
01574 return -1;
01575
01576 if (msg->first_line.type == SIP_REQUEST) {
01577 type = "request";
01578 } else if (msg->first_line.type == SIP_REPLY) {
01579 if (ice_data != NULL && ice_data->skip_next_reply) {
01580
01581
01582 ice_data->skip_next_reply = False;
01583 return -1;
01584 }
01585 type = "reply";
01586 } else {
01587 return -1;
01588 }
01589
01590 if (!get_callid(msg, &callid)) {
01591 LM_ERR("failed to get Call-ID\n");
01592 return -1;
01593 }
01594
01595 if (!get_cseq_number(msg, &cseq)) {
01596 LM_ERR("failed to get CSeq\n");
01597 return -1;
01598 }
01599
01600 status = get_sdp_message(msg, &sdp);
01601
01602 if (status == -1 || (status == -2 && msg->first_line.type == SIP_REQUEST)) {
01603 return status;
01604 } else if (status == -2 && !(msg->REPLY_STATUS == 200 && get_method_from_reply(msg) == METHOD_INVITE)) {
01605 return -2;
01606 }
01607 have_sdp = (status == 1);
01608
01609 if (have_sdp) {
01610 if (msg->first_line.type == SIP_REQUEST && find_line_starting_with(&sdp, "a=remote-candidates", False)) {
01611
01612
01613 if (ice_data != NULL) {
01614 ice_data->skip_next_reply = True;
01615 }
01616 return -1;
01617 }
01618
01619 status = get_session_info(&sdp, &session);
01620 if (status < 0) {
01621 LM_ERR("can't extract media streams from the SDP message\n");
01622 return -1;
01623 }
01624
01625 if (session.supported_count == 0)
01626 return 1;
01627
01628 len = sprintf(media_str, "%s", "media: ");
01629 for (i=0, str_buf.len=sizeof(media_str)-len-2, str_buf.s=media_str+len; i<session.stream_count; i++) {
01630 stream = session.streams[i];
01631 if (stream.transport != TSupported)
01632 continue;
01633 if (stream.type.len + stream.ip.len + stream.port.len + stream.direction.len + 4 > str_buf.len) {
01634 LM_ERR("media stream description is longer than %lu bytes\n", (unsigned long)sizeof(media_str));
01635 return -1;
01636 }
01637 len = sprintf(str_buf.s, "%.*s:%.*s:%.*s:%.*s:%s,",
01638 stream.type.len, stream.type.s,
01639 stream.ip.len, stream.ip.s,
01640 stream.port.len, stream.port.s,
01641 stream.direction.len, stream.direction.s,
01642 stream.has_ice?"ice=yes":"ice=no");
01643 str_buf.s += len;
01644 str_buf.len -= len;
01645 }
01646 *(str_buf.s-1) = 0;
01647 sprintf(str_buf.s-1, "%s", "\r\n");
01648 } else {
01649 media_str[0] = 0;
01650 }
01651
01652 from_uri = get_from_uri(msg);
01653 to_uri = get_to_uri(msg);
01654 from_tag = get_from_tag(msg);
01655 to_tag = get_to_tag(msg);
01656 user_agent = get_user_agent(msg);
01657 signaling_ip = get_signaling_ip(msg);
01658 media_relay = get_media_relay(msg);
01659
01660 len = snprintf(request, sizeof(request),
01661 "update\r\n"
01662 "type: %s\r\n"
01663 "dialog_id: %s\r\n"
01664 "call_id: %.*s\r\n"
01665 "cseq: %.*s\r\n"
01666 "from_uri: %.*s\r\n"
01667 "to_uri: %.*s\r\n"
01668 "from_tag: %.*s\r\n"
01669 "to_tag: %.*s\r\n"
01670 "user_agent: %.*s\r\n"
01671 "signaling_ip: %.*s\r\n"
01672 "media_relay: %.*s\r\n"
01673 "%s"
01674 "\r\n",
01675 type, dialog_id, callid.len, callid.s, cseq.len, cseq.s,
01676 from_uri.len, from_uri.s, to_uri.len, to_uri.s,
01677 from_tag.len, from_tag.s, to_tag.len, to_tag.s,
01678 user_agent.len, user_agent.s,
01679 signaling_ip.len, signaling_ip.s,
01680 media_relay.len, media_relay.s, media_str);
01681
01682 if (len >= sizeof(request)) {
01683 LM_ERR("mediaproxy request is longer than %lu bytes\n", (unsigned long)sizeof(request));
01684 return -1;
01685 }
01686
01687 result = send_command(request);
01688
01689 if (result == NULL)
01690 return -1;
01691
01692 if (!have_sdp) {
01693
01694
01695 return 1;
01696 }
01697
01698 len = get_tokens(result, tokens, sizeof(tokens)/sizeof(str));
01699
01700 if (len == 0) {
01701 LM_ERR("empty response from mediaproxy\n");
01702 return -1;
01703 } else if (len==1 && STR_MATCH(tokens[0], "error")) {
01704 LM_ERR("mediaproxy returned error\n");
01705 return -1;
01706 } else if (len<session.supported_count+1) {
01707 if (msg->first_line.type == SIP_REQUEST) {
01708 LM_ERR("insufficient ports returned from mediaproxy: got %d, "
01709 "expected %d\n", len-1, session.supported_count);
01710 return -1;
01711 } else {
01712 LM_WARN("broken client. Called UA added extra media stream(s) "
01713 "in the OK reply\n");
01714 }
01715 }
01716
01717 removed_session_ip = False;
01718
01719
01720
01721
01722 if (session.ip.s && !isnulladdr(session.ip)) {
01723 if (session.stream_count == session.supported_count) {
01724 if (!replace_element(msg, &session.ip, &tokens[0])) {
01725 LM_ERR("failed to replace session-level media IP in the SDP body\n");
01726 return -1;
01727 }
01728 } else {
01729 if (!remove_element(msg, &session.ip_line)) {
01730 LM_ERR("failed to remove session-level media IP in the SDP body\n");
01731 return -1;
01732 }
01733 removed_session_ip = True;
01734 }
01735 }
01736
01737 for (i=0, j=1; i<session.stream_count; i++) {
01738 stream = session.streams[i];
01739 if (stream.transport != TSupported) {
01740 if (!stream.local_ip && removed_session_ip) {
01741 strcpy(buf, "c=IN IP4 ");
01742 strncat(buf, session.ip.s, session.ip.len);
01743 strncat(buf, session.separator.s, session.separator.len);
01744 if (!insert_element(msg, stream.next_line, buf)) {
01745 LM_ERR("failed to insert IP address in media stream number %d\n", i+1);
01746 return -1;
01747 }
01748 }
01749 continue;
01750 }
01751
01752 if (j >= len) {
01753 break;
01754 }
01755
01756 if (!isnullport(stream.port)) {
01757 if (!replace_element(msg, &stream.port, &tokens[j])) {
01758 LM_ERR("failed to replace port in media stream number %d\n", i+1);
01759 return -1;
01760 }
01761 }
01762
01763 if (stream.rtcp_port.len>0 && !isnullport(stream.rtcp_port)) {
01764 str rtcp_port;
01765
01766 port = strtoint(&tokens[j]);
01767 rtcp_port.s = int2str(port+1, &rtcp_port.len);
01768 if (!replace_element(msg, &stream.rtcp_port, &rtcp_port)) {
01769 LM_ERR("failed to replace RTCP port in media stream number %d\n", i+1);
01770 return -1;
01771 }
01772 }
01773
01774 if (stream.rtcp_ip.len > 0) {
01775 if (!replace_element(msg, &stream.rtcp_ip, &tokens[0])) {
01776 LM_ERR("failed to replace RTCP IP in media stream number %d\n", i+1);
01777 return -1;
01778 }
01779 }
01780
01781 if (stream.local_ip && !isnulladdr(stream.ip)) {
01782 if (!replace_element(msg, &stream.ip, &tokens[0])) {
01783 LM_ERR("failed to replace IP address in media stream number %d\n", i+1);
01784 return -1;
01785 }
01786 } else if (!stream.local_ip && removed_session_ip) {
01787 strcpy(buf, "c=IN IP4 ");
01788 strncat(buf, tokens[0].s, tokens[0].len);
01789 strncat(buf, session.separator.s, session.separator.len);
01790 if (!insert_element(msg, stream.next_line, buf)) {
01791 LM_ERR("failed to insert IP address in media stream number %d\n", i+1);
01792 return -1;
01793 }
01794 }
01795
01796 if (ice_data == NULL) {
01797 priority_str = get_ice_candidate();
01798 } else if (ice_data->priority == NO_CANDIDATE) {
01799 priority_str.s = "none";
01800 } else {
01801
01802 priority_str.s = "";
01803 }
01804 priority_str.len = strlen(priority_str.s);
01805
01806 if (stream.has_ice && stream.first_ice_candidate && !STR_IMATCH(priority_str, "none")) {
01807
01808 struct in_addr hexip;
01809 inet_aton(tokens[0].s, &hexip);
01810
01811 priority = (ice_data == NULL)?get_ice_candidate_priority(priority_str):ice_data->priority;
01812 port = strtoint(&tokens[j]);
01813 candidate.s = buf;
01814 candidate.len = sprintf(candidate.s, "a=candidate:R%x 1 UDP %u %.*s %i typ relay%.*s",
01815 hexip.s_addr,
01816 priority,
01817 tokens[0].len, tokens[0].s,
01818 port,
01819 session.separator.len, session.separator.s);
01820
01821 if (!insert_element(msg, stream.first_ice_candidate, candidate.s)) {
01822 LM_ERR("failed to insert ICE candidate in media stream number %d\n", i+1);
01823 return -1;
01824 }
01825
01826 if (stream.has_rtcp_ice) {
01827 candidate.s = buf;
01828 candidate.len = sprintf(candidate.s, "a=candidate:R%x 2 UDP %u %.*s %i typ relay%.*s",
01829 hexip.s_addr,
01830 priority-1,
01831 tokens[0].len, tokens[0].s,
01832 port+1,
01833 session.separator.len, session.separator.s);
01834
01835 if (!insert_element(msg, stream.first_ice_candidate, candidate.s)) {
01836 LM_ERR("failed to insert ICE candidate in media stream number %d\n", i+1);
01837 return -1;
01838 }
01839 }
01840 }
01841
01842 j++;
01843 }
01844
01845 return 1;
01846 }
01847
01848
01849 static int
01850 end_media_session(str callid, str from_tag, str to_tag)
01851 {
01852 char request[2048], *result;
01853 int len;
01854
01855 len = snprintf(request, sizeof(request),
01856 "remove\r\n"
01857 "call_id: %.*s\r\n"
01858 "from_tag: %.*s\r\n"
01859 "to_tag: %.*s\r\n"
01860 "\r\n",
01861 callid.len, callid.s,
01862 from_tag.len, from_tag.s,
01863 to_tag.len, to_tag.s);
01864
01865 if (len >= sizeof(request)) {
01866 LM_ERR("mediaproxy request is longer than %lu bytes\n", (unsigned long)sizeof(request));
01867 return -1;
01868 }
01869
01870 result = send_command(request);
01871
01872 return result==NULL ? -1 : 1;
01873 }
01874
01875
01876
01877
01878
01879 typedef enum {
01880 MPInactive = 0,
01881 MPActive
01882 } MediaProxyState;
01883
01884
01885 static INLINE char*
01886 get_dialog_id(struct dlg_cell *dlg)
01887 {
01888 static char buffer[64];
01889
01890 snprintf(buffer, sizeof(buffer), "%d:%d", dlg->h_entry, dlg->h_id);
01891
01892 return buffer;
01893 }
01894
01895
01896 static void
01897 __free_dialog_data(void *data)
01898 {
01899 shm_free((ice_candidate_data*)data);
01900 }
01901
01902
01903 static void
01904 __dialog_requests(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params)
01905 {
01906 use_media_proxy(_params->req, get_dialog_id(dlg), (ice_candidate_data*)*_params->param);
01907 }
01908
01909
01910 static void
01911 __dialog_replies(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params)
01912 {
01913 struct sip_msg *reply = _params->rpl;
01914
01915 if (reply == FAKED_REPLY)
01916 return;
01917
01918 if (reply->REPLY_STATUS>100 && reply->REPLY_STATUS<300) {
01919 use_media_proxy(reply, get_dialog_id(dlg), (ice_candidate_data*)*_params->param);
01920 }
01921 }
01922
01923
01924 static void
01925 __dialog_ended(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params)
01926 {
01927 if ((int)(long)*_params->param == MPActive) {
01928 end_media_session(dlg->callid, dlg->tag[DLG_CALLER_LEG], dlg->tag[DLG_CALLEE_LEG]);
01929 *_params->param = MPInactive;
01930 }
01931 }
01932
01933
01934 static void
01935 __dialog_created(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params)
01936 {
01937 struct sip_msg *request = _params->req;
01938 ice_candidate_data *ice_data;
01939
01940 if (request->REQ_METHOD != METHOD_INVITE)
01941 return;
01942
01943 if ((request->msg_flags & FL_USE_MEDIA_PROXY) == 0)
01944 return;
01945
01946 ice_data = (ice_candidate_data*)shm_malloc(sizeof(ice_candidate_data));
01947 if (!ice_data) {
01948 LM_ERR("failed to allocate shm memory for ice_candidate_data\n");
01949 return;
01950 }
01951
01952 ice_data->priority = get_ice_candidate_priority(get_ice_candidate());
01953 ice_data->skip_next_reply = False;
01954
01955 if (dlg_api.register_dlgcb(dlg, DLGCB_REQ_WITHIN | DLGCB_CONFIRMED, __dialog_requests, (void*)ice_data, __free_dialog_data) != 0)
01956 LM_ERR("cannot register callback for in-dialog requests\n");
01957 if (dlg_api.register_dlgcb(dlg, DLGCB_RESPONSE_FWDED | DLGCB_RESPONSE_WITHIN, __dialog_replies, (void*)ice_data, NULL) != 0)
01958 LM_ERR("cannot register callback for dialog and in-dialog replies\n");
01959 if (dlg_api.register_dlgcb(dlg, DLGCB_TERMINATED | DLGCB_FAILED | DLGCB_EXPIRED | DLGCB_DESTROY, __dialog_ended, (void*)MPActive, NULL) != 0)
01960 LM_ERR("cannot register callback for dialog termination\n");
01961
01962 use_media_proxy(request, get_dialog_id(dlg), ice_data);
01963 }
01964
01965
01966
01967
01968
01969
01970
01971 static int
01972 EngageMediaProxy(struct sip_msg *msg)
01973 {
01974 if (mediaproxy_disabled)
01975 return -1;
01976
01977 if (!have_dlg_api) {
01978 LM_ERR("engage_media_proxy requires the dialog module to be loaded and configured\n");
01979 return -1;
01980 }
01981 msg->msg_flags |= FL_USE_MEDIA_PROXY;
01982 setflag(msg, dialog_flag);
01983 return 1;
01984 }
01985
01986
01987 static int
01988 UseMediaProxy(struct sip_msg *msg)
01989 {
01990 if (mediaproxy_disabled)
01991 return -1;
01992
01993 return use_media_proxy(msg, "", NULL);
01994 }
01995
01996
01997 static int
01998 EndMediaSession(struct sip_msg *msg)
01999 {
02000 str callid, from_tag, to_tag;
02001
02002 if (mediaproxy_disabled)
02003 return -1;
02004
02005 if (!get_callid(msg, &callid)) {
02006 LM_ERR("failed to get Call-ID\n");
02007 return -1;
02008 }
02009
02010 from_tag = get_from_tag(msg);
02011 to_tag = get_to_tag(msg);
02012
02013 return end_media_session(callid, from_tag, to_tag);
02014 }
02015
02016
02017
02018
02019
02020
02021
02022 static int
02023 mod_init(void)
02024 {
02025 pv_spec_t avp_spec;
02026 int *param;
02027 modparam_t type;
02028
02029
02030 if (signaling_ip_avp.spec.s==NULL || *(signaling_ip_avp.spec.s)==0) {
02031 LM_WARN("missing/empty signaling_ip_avp parameter. will use default.\n");
02032 signaling_ip_avp.spec.s = SIGNALING_IP_AVP_SPEC;
02033 }
02034 signaling_ip_avp.spec.len = strlen(signaling_ip_avp.spec.s);
02035 if (pv_parse_spec(&(signaling_ip_avp.spec), &avp_spec)==0 || avp_spec.type!=PVT_AVP) {
02036 LM_CRIT("invalid AVP specification for signaling_ip_avp: `%s'\n", signaling_ip_avp.spec.s);
02037 return -1;
02038 }
02039 if (pv_get_avp_name(0, &(avp_spec.pvp), &(signaling_ip_avp.name), &(signaling_ip_avp.type))!=0) {
02040 LM_CRIT("invalid AVP specification for signaling_ip_avp: `%s'\n", signaling_ip_avp.spec.s);
02041 return -1;
02042 }
02043
02044
02045 if (media_relay_avp.spec.s==NULL || *(media_relay_avp.spec.s)==0) {
02046 LM_WARN("missing/empty media_relay_avp parameter. will use default.\n");
02047 media_relay_avp.spec.s = MEDIA_RELAY_AVP_SPEC;
02048 }
02049 media_relay_avp.spec.len = strlen(media_relay_avp.spec.s);
02050 if (pv_parse_spec(&(media_relay_avp.spec), &avp_spec)==0 || avp_spec.type!=PVT_AVP) {
02051 LM_CRIT("invalid AVP specification for media_relay_avp: `%s'\n", media_relay_avp.spec.s);
02052 return -1;
02053 }
02054 if (pv_get_avp_name(0, &(avp_spec.pvp), &(media_relay_avp.name), &(media_relay_avp.type))!=0) {
02055 LM_CRIT("invalid AVP specification for media_relay_avp: `%s'\n", media_relay_avp.spec.s);
02056 return -1;
02057 }
02058
02059
02060 if (ice_candidate_avp.spec.s==NULL || *(ice_candidate_avp.spec.s)==0) {
02061 LM_WARN("missing/empty ice_candidate_avp parameter. will use default.\n");
02062 ice_candidate_avp.spec.s = ICE_CANDIDATE_AVP_SPEC;
02063 }
02064 ice_candidate_avp.spec.len = strlen(ice_candidate_avp.spec.s);
02065 if (pv_parse_spec(&(ice_candidate_avp.spec), &avp_spec)==0 || avp_spec.type!=PVT_AVP) {
02066 LM_CRIT("invalid AVP specification for ice_candidate_avp: `%s'\n", ice_candidate_avp.spec.s);
02067 return -1;
02068 }
02069 if (pv_get_avp_name(0, &(avp_spec.pvp), &(ice_candidate_avp.name), &(ice_candidate_avp.type))!=0) {
02070 LM_CRIT("invalid AVP specification for ice_candidate_avp: `%s'\n", ice_candidate_avp.spec.s);
02071 return -1;
02072 }
02073
02074
02075 ice_candidate.len = strlen(ice_candidate.s);
02076 if (!STR_IMATCH(ice_candidate, "none") && !STR_IMATCH(ice_candidate, "low-priority") && !STR_IMATCH(ice_candidate, "high-priority")) {
02077 LM_CRIT("invalid value specified for ice_candidate: `%s'\n", ice_candidate.s);
02078 return -1;
02079 }
02080
02081
02082 if (load_dlg_api(&dlg_api)==0) {
02083 have_dlg_api = True;
02084
02085
02086 param = find_param_export(find_module_by_name("dialog"), "dlg_flag", INT_PARAM, &type);
02087 if (!param) {
02088 LM_CRIT("cannot find dlg_flag parameter in the dialog module\n");
02089 return -1;
02090 }
02091
02092 if (type != INT_PARAM) {
02093 LM_CRIT("dlg_flag parameter found but with wrong type: %d\n", type);
02094 return -1;
02095 }
02096
02097 dialog_flag = *param;
02098
02099
02100 if (dlg_api.register_dlgcb(NULL, DLGCB_CREATED, __dialog_created, NULL, NULL) != 0) {
02101 LM_CRIT("cannot register callback for dialog creation\n");
02102 return -1;
02103 }
02104 } else {
02105 LM_NOTICE("engage_media_proxy() will not work because the dialog module is not loaded\n");
02106 }
02107
02108 return 0;
02109 }
02110
02111
02112 static int
02113 child_init(int rank)
02114 {
02115
02116 if (!mediaproxy_disabled)
02117 mediaproxy_connect();
02118
02119 return 0;
02120 }
02121
02122