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