00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "../../sr_module.h"
00030 #include "../../dprint.h"
00031 #include "../../data_lump.h"
00032 #include "../../data_lump_rpl.h"
00033 #include "../../error.h"
00034 #include "../../forward.h"
00035 #include "../../mem/mem.h"
00036 #include "../../mem/shm_mem.h"
00037 #include "../../atomic_ops.h"
00038 #include "../../parser/parse_content.h"
00039 #include "../../parser/parse_uri.h"
00040 #include "../../parser/parser_f.h"
00041 #include "../../parser/parse_body.h"
00042 #include "../../resolve.h"
00043 #include "../../trim.h"
00044 #include "../../ut.h"
00045 #include "../../msg_translator.h"
00046 #include "../../socket_info.h"
00047 #include "../../select.h"
00048 #include "../../select_buf.h"
00049 #include "../../script_cb.h"
00050 #include "../../cfg_parser.h"
00051 #include <sys/types.h>
00052 #include <sys/socket.h>
00053 #include <sys/time.h>
00054 #include <netinet/in.h>
00055 #include <arpa/inet.h>
00056 #include <sys/uio.h>
00057 #include <sys/un.h>
00058 #include <ctype.h>
00059 #include <errno.h>
00060 #include <netdb.h>
00061 #include <poll.h>
00062 #include <stdio.h>
00063 #include <stdlib.h>
00064 #include <string.h>
00065 #include <unistd.h>
00066 #include <linux/netfilter/xt_RTPPROXY.h>
00067 #include <arpa/inet.h>
00068
00069 MODULE_VERSION
00070
00071 #define MODULE_NAME "iptrtpproxy"
00072
00073
00074 #define MAX_MEDIA_NUMBER XT_RTPPROXY_MAX_ALLOC_SESSION
00075 #define MAX_CODEC_NUMBER MAX_MEDIA_NUMBER*5
00076 #define MAX_SWITCHBOARD_NAME_LEN 20
00077 #define MAX_AGGREGATED_NUMBER 30
00078
00079
00080 #define PTR2INT(v) (int)(long) (v)
00081 #define INT2PTR(v) (void*)(long) (v)
00082
00083 struct host_item_stat {
00084 int last_error_stamp;
00085 int last_ok_stamp;
00086 };
00087
00088 struct host_item {
00089 str name;
00090 struct xt_rtpproxy_connection_rpc_params rpc_params;
00091 int local;
00092 struct xt_rtpproxy_handle handle;
00093 int handle_is_opened;
00094
00095 struct host_item_stat *stat;
00096 struct host_item *next;
00097 };
00098
00099 struct switchboard_item_stat {
00100 atomic_t free;
00101 atomic_t alloc;
00102 };
00103
00104 struct switchboard_item {
00105 str name;
00106 struct xt_rtpproxy_switchboard_id switchboard_addr;
00107 unsigned int sip_ip;
00108 str hostname;
00109 struct host_item *host;
00110 unsigned int weight;
00111
00112 struct switchboard_item_stat *stat;
00113
00114 struct switchboard_item *next;
00115 };
00116
00117 enum sdp_media_type {
00118 sdpmtUnknown = 0,
00119 sdpmtAudio,
00120 sdpmtVideo,
00121 sdpmtApplication,
00122 sdpmtText,
00123 sdpmtMessage,
00124 sdpmtData,
00125 sdpmtControl
00126 };
00127
00128 #define NUM_MEDIA_TYPES (sdpmtControl+1)
00129 static str sdp_media_types_str[NUM_MEDIA_TYPES] = {
00130 STR_STATIC_INIT("unknown"),
00131 STR_STATIC_INIT("audio"),
00132 STR_STATIC_INIT("video"),
00133 STR_STATIC_INIT("application"),
00134 STR_STATIC_INIT("text"),
00135 STR_STATIC_INIT("message"),
00136 STR_STATIC_INIT("data"),
00137 STR_STATIC_INIT("control")
00138 };
00139
00140 struct aggregation_item {
00141 str name;
00142 unsigned int switchboard_count;
00143 unsigned int sip_ip;
00144 struct switchboard_item *(*switchboards)[];
00145 struct aggregation_item *next;
00146 };
00147
00148 struct codec_set_item_throttle {
00149 int max_streams;
00150 struct xt_rtpproxy_throttle_stat bandwidth[2];
00151 };
00152
00153 struct codec_set_item {
00154 str name;
00155 struct {
00156 struct codec_set_item_throttle throttle;
00157 unsigned int (*codec_rights)[];
00158 } media_types[NUM_MEDIA_TYPES];
00159 struct codec_set_item *next;
00160 };
00161
00162 struct ipt_session {
00163
00164 unsigned int session_count;
00165 struct xt_rtpproxy_sockopt_session sessions[MAX_MEDIA_NUMBER];
00166 unsigned int sdp_media_count;
00167 int sdp_media[MAX_MEDIA_NUMBER];
00168
00169 struct switchboard_item *switchboard;
00170 };
00171
00172 static struct {
00173 str session_ids;
00174 str sdp_ip;
00175 str oline_user;
00176 str oline_addr;
00177 struct switchboard_item *switchboard[2];
00178 struct aggregation_item *aggregation[2];
00179 int learning_timeout;
00180 int expiration_timeout;
00181 int ttl;
00182 int always_learn;
00183 struct {
00184 u_int32_t mark;
00185 struct xt_rtpproxy_throttle_stat bandwidth[2];
00186 } throttle;
00187 struct codec_set_item *codec_set;
00188 int remove_codec_mask;
00189 unsigned int auth_rights;
00190 struct ipt_session protected_sess;
00191 } global_params;
00192
00193 static struct switchboard_item *switchboards = NULL;
00194 static struct host_item *hosts = NULL;
00195 static struct aggregation_item *aggregations = NULL;
00196 static struct codec_set_item *codec_sets = NULL;
00197 static int switchboard_count = 0;
00198 static str iptrtpproxy_cfg_filename = STR_STATIC_INIT("/etc/iptrtpproxy.cfg");
00199 static int iptrtpproxy_cfg_flag = 0;
00200 static char* iptrtpproxy_cfg_hostname = NULL;
00201 static int rpc_heartbeat_timeout = 30;
00202 static int sdp_parsed = 999;
00203 static struct sdp_session global_sdp_sess;
00204
00205 #define declare_find_function(x) \
00206 static struct x##_item* find_##x(str *name, struct x##_item*** prev) { \
00207 struct x##_item* p;\
00208 struct x##_item** dummy;\
00209 if (!prev) \
00210 prev = &dummy;\
00211 for (p = x##s, *prev = &x##s; p; *prev = &(**prev)->next, p=p->next) {\
00212 int len, n;\
00213 len = (name->len < p->name.len) ? name->len : p->name.len;\
00214 n = strncasecmp(name->s, p->name.s, len);\
00215 if (n == 0) {\
00216 if (name->len == p->name.len) \
00217 return p;\
00218 else if (name->len < p->name.len)\
00219 return NULL;\
00220 }\
00221 else if (n < 0) { \
00222 return NULL;\
00223 }\
00224 }\
00225 return NULL;\
00226 }
00227
00228 declare_find_function(host)
00229 declare_find_function(switchboard)
00230 declare_find_function(aggregation)
00231 declare_find_function(codec_set)
00232
00233 static struct switchboard_item* find_switchboard_by_addr(struct xt_rtpproxy_switchboard_id *addr) {
00234 struct switchboard_item* p;
00235 for (p = switchboards; p; p=p->next) {
00236 if (addr->ip == p->switchboard_addr.ip && addr->port == p->switchboard_addr.port) break;
00237 }
00238 return p;
00239 }
00240
00241 enum {
00242 PAR_EXPIRATION_TIMEOUT,
00243 PAR_TTL,
00244 PAR_LEARNING_TIMEOUT,
00245 PAR_ALWAYS_LEARN,
00246 PAR_AGGREGATION_A, PAR_AGGREGATION_B,
00247 PAR_SWITCHBOARD_A, PAR_SWITCHBOARD_B,
00248 PAR_AGGREGATION_BY_SIP_IP_A, PAR_AGGREGATION_BY_SIP_IP_B,
00249 PAR_SWITCHBOARD_BY_SIP_IP_A, PAR_SWITCHBOARD_BY_SIP_IP_B,
00250 PAR_SESSION_IDS, PAR_PROTECTED_SESSION_IDS,
00251 PAR_SDP_IP, PAR_ACTIVE_MEDIA_NUM,
00252 PAR_OLINE_USER, PAR_OLINE_ADDR,
00253 PAR_THROTTLE_MARK,
00254 PAR_THROTTLE_RTP_MAX_BYTES, PAR_THROTTLE_RTP_MAX_PACKETS,
00255 PAR_THROTTLE_RTCP_MAX_BYTES, PAR_THROTTLE_RTCP_MAX_PACKETS,
00256 PAR_CODEC_SET, PAR_AUTH_RIGHTS, PAR_REMOVE_CODEC_MASK
00257 };
00258
00259 enum {
00260 PAR_READ=0x01, PAR_WRITE=0x02, PAR_INT=0x04, PAR_STR=0x08, PAR_DIR=0x10
00261 };
00262
00263 static struct {
00264 char *name;
00265 int id;
00266 int flags;
00267 } param_list[] = {
00268 {"expiration_timeout", PAR_EXPIRATION_TIMEOUT, PAR_READ|PAR_WRITE|PAR_INT},
00269 {"ttl", PAR_TTL, PAR_READ|PAR_WRITE|PAR_INT},
00270 {"learning_timeout", PAR_LEARNING_TIMEOUT, PAR_READ|PAR_WRITE|PAR_INT},
00271 {"always_learn", PAR_ALWAYS_LEARN, PAR_READ|PAR_WRITE|PAR_INT},
00272 {"aggregation_a", PAR_AGGREGATION_A, PAR_READ|PAR_WRITE|PAR_STR},
00273 {"aggregation_b", PAR_AGGREGATION_B, PAR_READ|PAR_WRITE|PAR_STR|PAR_DIR},
00274 {"switchboard_a", PAR_SWITCHBOARD_A, PAR_READ|PAR_WRITE|PAR_STR},
00275 {"switchboard_b", PAR_SWITCHBOARD_B, PAR_READ|PAR_WRITE|PAR_STR|PAR_DIR},
00276 {"aggregation_by_sip_ip_a", PAR_AGGREGATION_BY_SIP_IP_A, PAR_WRITE|PAR_STR},
00277 {"aggregation_by_sip_ip_b", PAR_AGGREGATION_BY_SIP_IP_B, PAR_WRITE|PAR_STR|PAR_DIR},
00278 {"switchboard_by_sip_ip_a", PAR_SWITCHBOARD_BY_SIP_IP_A, PAR_WRITE|PAR_STR},
00279 {"switchboard_by_sip_ip_b", PAR_SWITCHBOARD_BY_SIP_IP_B, PAR_WRITE|PAR_STR|PAR_DIR},
00280 {"session_ids", PAR_SESSION_IDS, PAR_READ|PAR_STR},
00281 {"protected_session_ids", PAR_PROTECTED_SESSION_IDS, PAR_WRITE|PAR_STR},
00282 {"sdp_ip", PAR_SDP_IP, PAR_READ|PAR_INT},
00283 {"active_media_num", PAR_ACTIVE_MEDIA_NUM, PAR_READ|PAR_INT},
00284 {"o_user", PAR_OLINE_USER, PAR_READ|PAR_WRITE|PAR_STR},
00285 {"o_addr", PAR_OLINE_ADDR, PAR_READ|PAR_WRITE|PAR_STR},
00286 {"throttle_mark", PAR_THROTTLE_MARK, PAR_READ|PAR_WRITE|PAR_INT},
00287 {"throttle_rtp_max_bytes", PAR_THROTTLE_RTP_MAX_BYTES, PAR_READ|PAR_WRITE|PAR_INT},
00288 {"throttle_rtp_max_packets", PAR_THROTTLE_RTP_MAX_PACKETS, PAR_READ|PAR_WRITE|PAR_INT},
00289 {"throttle_rtcp_max_bytes", PAR_THROTTLE_RTCP_MAX_BYTES, PAR_READ|PAR_WRITE|PAR_INT},
00290 {"throttle_rtcp_max_packets", PAR_THROTTLE_RTCP_MAX_PACKETS, PAR_READ|PAR_WRITE|PAR_INT},
00291 {"codec_set", PAR_CODEC_SET, PAR_READ|PAR_WRITE|PAR_STR},
00292 {"remove_codec_mask", PAR_REMOVE_CODEC_MASK, PAR_READ|PAR_WRITE|PAR_INT},
00293 {"auth_rights", PAR_AUTH_RIGHTS, PAR_READ|PAR_INT},
00294 { NULL }
00295 };
00296
00297 static int param2idx(str *name, int rw) {
00298 int i;
00299 for (i=0; param_list[i].name; i++) {
00300 if (strlen(param_list[i].name)==name->len &&
00301 strncasecmp(param_list[i].name, name->s, name->len) == 0 &&
00302 (rw & param_list[i].flags)) {
00303 return i;
00304 }
00305 }
00306 ERR(MODULE_NAME": param2idx: unknown param '%.*s', rw:0x%0x\n", STR_FMT(name), rw);
00307 return -1;
00308 }
00309
00313 static int rtpproxy_alloc_update_fixup(void** param, int param_no) {
00314 switch (param_no) {
00315 case 1:
00316 return fixup_var_int_12(param, param_no);
00317 case 2:
00318 return fixup_var_str_12(param, param_no);
00319 default:
00320 return 0;
00321 }
00322 }
00323
00324 static int rtpproxy_delete_fixup(void** param, int param_no) {
00325 switch (param_no) {
00326 case 1:
00327 return fixup_var_str_12(param, param_no);
00328 default:
00329 return 0;
00330 }
00331 }
00332
00333 static int rtpproxy_set_param_fixup(void** param, int param_no) {
00334 int idx;
00335 action_u_t *a;
00336 str s;
00337 switch (param_no) {
00338 case 1:
00339 s.s = (char*)*param;
00340 s.len = strlen(s.s);
00341 idx = param2idx(&s, PAR_WRITE);
00342 if (idx < 0) {
00343 return E_CFG;
00344 }
00345 *param = INT2PTR(idx);
00346 break;
00347 case 2:
00348 a = fixup_get_param(param, param_no, 1);
00349 idx = a->u.number;
00350 if (param_list[idx].flags & PAR_STR) {
00351 return fixup_var_str_12(param, param_no);
00352
00353 } else if (param_list[idx].flags & PAR_INT) {
00354 return fixup_var_int_12(param, param_no);
00355 }
00356 break;
00357 }
00358 return 0;
00359 }
00360
00361 static int name2media_type(str *name) {
00362 int i;
00363 for (i = 1; i<NUM_MEDIA_TYPES; i++) {
00364 if (name->len == sdp_media_types_str[i].len &&
00365 strncasecmp(name->s, sdp_media_types_str[i].s, name->len) == 0) {
00366 return i;
00367 }
00368 }
00369 return sdpmtUnknown;
00370 }
00371
00372 struct codec_entry {
00373 str name;
00374
00375 int payload_type;
00376 };
00377
00378 #define MAX_FIXED_PAYLOAD_TYPES 96
00379
00380 static struct codec_entry(*reg_codecs)[] = NULL;
00381 static int reg_codec_count = 0;
00382 static int reg_codec_alloc_count = 0;
00383 static struct {
00384 int codec_id;
00385 } fixed_payload_types[MAX_FIXED_PAYLOAD_TYPES];
00386
00387
00388
00389 static int name2codec_id(str *name, int *new_codec_id) {
00390 int i, j;
00391 i = 0;
00392 j = reg_codec_count - 1;
00393 while (i <= j) {
00394 int k, r;
00395 k = (i + j)/2;
00396 r = strncasecmp((*reg_codecs)[k].name.s, name->s, ((*reg_codecs)[k].name.len < name->len)?(*reg_codecs)[k].name.len:name->len);
00397 if (r == 0 && (*reg_codecs)[k].name.len == name->len) {
00398 return k+1;
00399 } else if (r > 0 || (r == 0 && (*reg_codecs)[k].name.len > name->len)) {
00400 j = k - 1;
00401 }
00402 else {
00403 i = k + 1;
00404 }
00405 }
00406 if (new_codec_id) {
00407 *new_codec_id = i + 1;
00408 }
00409 return 0;
00410 }
00411
00412
00413 static int register_codec(str *name) {
00414 int codec_id, new_codec_id = 0;
00415 if (!(codec_id = name2codec_id(name, &new_codec_id))) {
00416 int i;
00417 if (reg_codec_count + 1 > reg_codec_alloc_count) {
00418 void *p;
00419 reg_codec_alloc_count += 10;
00420 p = pkg_realloc(reg_codecs, sizeof((*reg_codecs)[0])*reg_codec_alloc_count);
00421 if (!p) {
00422 return E_OUT_OF_MEM;
00423 }
00424 reg_codecs = p;
00425 }
00426
00427
00428 for (i=reg_codec_count-1; i >= new_codec_id-1; i--) {
00429 (*reg_codecs)[i+1] = (*reg_codecs)[i];
00430 }
00431 reg_codec_count++;
00432 (*reg_codecs)[new_codec_id-1].name = *name;
00433 codec_id = new_codec_id;
00434
00435 }
00436 return codec_id;
00437 }
00438
00439 enum send_rec_modifier {
00440 sdpaattr_sendonly = 1,
00441 sdpaattr_recvonly = 2,
00442 sdpaattr_sendrecv = 3,
00443 sdpaattr_inactive = 4
00444 };
00445
00446 static str send_rec_modifiers[] = {
00447 STR_STATIC_INIT(""),
00448 STR_STATIC_INIT("sendonly"),
00449 STR_STATIC_INIT("recvonly"),
00450 STR_STATIC_INIT("sendrecv"),
00451 STR_STATIC_INIT("inactive"),
00452 };
00453
00454 struct sdp_codec {
00455 unsigned int payload_type;
00456 unsigned int codec_id;
00457 str mline_payload_type_s;
00458 str a_rtpmap_line_s;
00459 str a_fmtp_line_s;
00460 };
00461
00462 struct sdp_session {
00463 str oline_user_s;
00464 str oline_addr_s;
00465 unsigned int media_count;
00466 struct {
00467 int active;
00468 unsigned short port;
00469 unsigned int ip;
00470 str ip_s;
00471 str port_s;
00472 enum sdp_media_type media_type;
00473 enum send_rec_modifier send_rec_modifier;
00474 str send_rec_modifier_line_s;
00475 int codec_count;
00476 struct sdp_codec (*codecs)[];
00477 } media[MAX_MEDIA_NUMBER];
00478 };
00479
00480 static unsigned int s2ip4(str *s) {
00481 struct in_addr res;
00482 char c2;
00483 c2 = s->s[s->len];
00484 s->s[s->len] = '\0';
00485 if (!inet_aton(s->s, &res)) {
00486 s->s[s->len] = c2;
00487 return 0;
00488 }
00489 s->s[s->len] = c2;
00490 return res.s_addr;
00491 }
00492
00493 static void ip42s(unsigned int ip, str *s) {
00494 struct in_addr ip2 = { ip };
00495 s->s = inet_ntoa(ip2);
00496 s->len = strlen(s->s);
00497 }
00498
00499 #define is_alpha(_c) (((_c) >= 'a' && (_c) <= 'z') || ((_c) >= 'A' && (_c) <= 'Z') || ((_c) >= '0' && (_c) <= '9') || ((_c) == '_') || ((_c) == '-'))
00500
00501 inline static int next_sdp_line(char** p, char* pend, char *ltype, str* lvalue, str* line) {
00502 char *cp;
00503 while (*p < pend) {
00504 while (*p < pend && (**p == '\n' || **p == '\r')) (*p)++;
00505 for (cp = *p; cp < pend && *cp != '\n' && *cp != '\r'; cp++);
00506
00507 if (cp-*p > 2 && (*p)[1] == '=') {
00508 *ltype = **p;
00509 lvalue->s = (*p)+2;
00510 lvalue->len = cp-lvalue->s;
00511 while (cp < pend && (*cp == '\n' || *cp == '\r')) cp++;
00512 line->s = (*p);
00513 line->len = cp-line->s;
00514 *p = cp;
00515 return 0;
00516 }
00517 *p = cp;
00518 }
00519 return -1;
00520 };
00521
00522 static int name2enum(str *name, str (*list)[]) {
00523 int i;
00524 for (i = 0; (*list)[i].s != NULL; i++) {
00525 if (name->len == (*list)[i].len &&
00526 strncasecmp(name->s, (*list)[i].s, name->len) == 0) {
00527 return i;
00528 }
00529 }
00530 return -1;
00531 }
00532
00533 static int prefix2enum(str *line, str (*list)[]) {
00534 int i;
00535 for (i = 0; (*list)[i].s != NULL; i++) {
00536 if (line->len > (*list)[i].len &&
00537 strncmp(line->s, (*list)[i].s, (*list)[i].len) == 0) {
00538 return i;
00539 }
00540 }
00541 return -1;
00542 }
00543
00544
00545 static int parse_sdp_content(struct sip_msg* msg, struct sdp_session *sess) {
00546 char *p, *pend, *cp, *cp2, *lend;
00547 str line, lvalue, cline_ip_s, body;
00548 int sess_fl, i, cline_count, codec_count;
00549 char ltype, savec;
00550 unsigned int cline_ip;
00551 enum send_rec_modifier sess_send_rec_modifier;
00552
00553 static struct sdp_codec codecs[MAX_CODEC_NUMBER];
00554
00555 static str supported_protocols[] = {
00556 STR_STATIC_INIT("rtp/avp"),
00557 STR_STATIC_INIT("rtp/savp"),
00558 STR_STATIC_INIT("rtp/avpf"),
00559 STR_STATIC_INIT("rtp/savpf"),
00560 STR_STATIC_INIT("udp"),
00561 STR_STATIC_INIT("udptl"),
00562 STR_NULL
00563 };
00564
00565 enum a_attr {sdpaattr_rtpmap, sdpaattr_fmtp, sdpaattr_rtcp};
00566 static str a_attrs[] = {
00567 STR_STATIC_INIT("rtpmap:"),
00568 STR_STATIC_INIT("fmtp:"),
00569 STR_STATIC_INIT("rtcp:"),
00570 STR_NULL
00571 };
00572
00573 memset(sess, 0, sizeof(*sess));
00574
00575 body.s = get_body_part(msg, TYPE_APPLICATION, SUBTYPE_SDP, &body.len);
00576 if (!body.s) {
00577 ERR(MODULE_NAME": parse_sdp_content: failed to get the application/sdp body\n");
00578 return -1;
00579 }
00580
00581 #if 0
00582 body.s = get_body(msg);
00583 if (body.s==0) {
00584 ERR(MODULE_NAME": parse_sdp_content: failed to get the message body\n");
00585 return -1;
00586 }
00587 body.len = msg->len -(int)(body.s - msg->buf);
00588 if (body.len==0) {
00589 ERR(MODULE_NAME": parse_sdp_content: message body has length zero\n");
00590 return -1;
00591 }
00592
00593
00594 if (!msg->content_type)
00595 {
00596 WARN(MODULE_NAME": parse_sdp_content: Content-TYPE header absent!"
00597 "let's assume the content is text/plain\n");
00598 }
00599 else {
00600 trim_len(line.len, line.s, msg->content_type->body);
00601 if (line.len != sizeof("application/sdp")-1 || strncasecmp(line.s, "application/sdp", line.len) != 0) {
00602 ERR(MODULE_NAME": parse_sdp_content: bad content type '%.*s'\n", STR_FMT(&line));
00603 return -1;
00604 }
00605 }
00606 #endif
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624 p = body.s;
00625 pend = body.s + body.len;
00626 sess_fl = 0;
00627 sess->media_count = 0;
00628 cline_ip_s.s = NULL;
00629 cline_ip_s.len = 0;
00630 cline_ip = 0;
00631 cline_count = 0;
00632 codec_count = 0;
00633 memset(&codecs, 0, sizeof(codecs));
00634 sess_send_rec_modifier = 0;
00635 while (p < pend) {
00636 if (next_sdp_line(&p, pend, <ype, &lvalue, &line) < 0) break;
00637 lend = lvalue.s + lvalue.len;
00638 switch (ltype) {
00639 case 'v':
00640
00641 if (sess_fl != 0) {
00642 ERR(MODULE_NAME": parse_sdp_content: only one session allowed\n");
00643 return -1;
00644 }
00645 sess_fl = 1;
00646 break;
00647 case 'o':
00648
00649 if (sess_fl != 1) {
00650 ERR(MODULE_NAME": parse_sdp_content: o= line is not in session section\n");
00651 return -1;
00652 }
00653 for (i=0; i<6; i++)
00654 if (sess->oline_addr_s.s) {
00655 ERR(MODULE_NAME": parse_sdp_content: only one o= line allowed\n");
00656 return -1;
00657 }
00658 cp = eat_token_end(lvalue.s, lend);
00659 sess->oline_user_s.len = cp-lvalue.s;
00660 if (!sess->oline_user_s.len) goto invalid_o;
00661 sess->oline_user_s.s = lvalue.s;
00662 lvalue.s = eat_space_end(cp, lend);
00663 for (i=0; i<4; i++) {
00664 cp = eat_token_end(lvalue.s, lend);
00665 if (cp-lvalue.s == 0) goto invalid_o;
00666 lvalue.s = eat_space_end(cp, lend);
00667 }
00668 cp = eat_token_end(lvalue.s, lend);
00669 sess->oline_addr_s.len = cp-lvalue.s;
00670 if (!sess->oline_addr_s.len) goto invalid_o;
00671 sess->oline_addr_s.s = lvalue.s;
00672 break;
00673 invalid_o:
00674 ERR(MODULE_NAME": parse_sdp_content: invalid o= line '%.*s'\n", (int) (lend-line.s), line.s);
00675 return -1;
00676 case 'c':
00677
00678 switch (sess_fl) {
00679 case 0:
00680 ERR(MODULE_NAME": parse_sdp_content: c= line is not in session section\n");
00681 return -1;
00682 case 1:
00683 case 2:
00684 cline_count++;
00685 if (cline_count > 1) {
00686
00687 if (sess_fl == 2) {
00688 goto invalidate;
00689 }
00690 else {
00691 cline_ip_s.len = 0;
00692 }
00693 break;
00694 }
00695 cp = eat_token_end(lvalue.s, lend);
00696 if (cp-lvalue.s != 2 || memcmp(lvalue.s, "IN", 2) != 0) {
00697 goto invalidate;
00698 }
00699 cp = eat_space_end(cp, lend);
00700 lvalue.s = cp;
00701 cp = eat_token_end(cp, lend);
00702 if (cp-lvalue.s != 3 || memcmp(lvalue.s, "IP4", 3) != 0) {
00703 goto invalidate;
00704 }
00705 cp = eat_space_end(cp, lend);
00706 lvalue.s = cp;
00707 cp = eat_token_end(cp, lend);
00708 lvalue.len = cp-lvalue.s;
00709 if (lvalue.len == 0 || q_memchr(lvalue.s, '/', lvalue.len)) {
00710
00711 goto invalidate;
00712 }
00713 if (sess_fl == 1) {
00714 cline_ip_s = lvalue;
00715 cline_ip = s2ip4(&lvalue);
00716 }
00717 else {
00718 sess->media[sess->media_count-1].ip = s2ip4(&lvalue);
00719 sess->media[sess->media_count-1].active = sess->media[sess->media_count-1].port != 0;
00720 sess->media[sess->media_count-1].ip_s = lvalue;
00721 }
00722 break;
00723 default:
00724 ;
00725 }
00726 break;
00727 invalidate:
00728 if (sess_fl == 2) {
00729 sess->media[sess->media_count-1].active = 0;
00730 }
00731 break;
00732 case 'm':
00733
00734
00735 switch (sess_fl) {
00736 case 0:
00737 ERR(MODULE_NAME": parse_sdp_content: m= line is not in session section\n");
00738 return -1;
00739 case 1:
00740 case 2:
00741 if (sess->media_count >= MAX_MEDIA_NUMBER) {
00742 ERR(MODULE_NAME": parse_sdp_content: max.number of medias (%d) exceeded\n", MAX_MEDIA_NUMBER);
00743 return -1;
00744 }
00745 cline_count = 0;
00746 sess_fl = 2;
00747 sess->media_count++;
00748 sess->media[sess->media_count-1].active = 0;
00749 sess->media[sess->media_count-1].port = 0;
00750 sess->media[sess->media_count-1].send_rec_modifier = sess_send_rec_modifier;
00751 cp = eat_token_end(lvalue.s, lend);
00752 lvalue.len = cp-lvalue.s;
00753 sess->media[sess->media_count-1].media_type = name2media_type(&lvalue);;
00754 if (!lvalue.len) {
00755 break;
00756 }
00757 cp = eat_space_end(cp, lend);
00758 lvalue.s = cp;
00759 cp = eat_token_end(cp, lend);
00760 lvalue.len = cp-lvalue.s;
00761
00762 cp2 = q_memchr(lvalue.s, '/', lvalue.len);
00763 if (cp2) {
00764
00765 lvalue.len = cp2-lvalue.s;
00766 }
00767 sess->media[sess->media_count-1].port_s = lvalue;
00768 if (lvalue.len == 0) {
00769 break;
00770 }
00771 savec = lvalue.s[lvalue.len];
00772 lvalue.s[lvalue.len] = '\0';
00773 sess->media[sess->media_count-1].port = atol(lvalue.s);
00774 lvalue.s[lvalue.len] = savec;
00775 if (sess->media[sess->media_count-1].port == 0) {
00776 break;
00777 }
00778 cp = eat_space_end(cp, lend);
00779
00780 lvalue.s = cp;
00781 cp = eat_token_end(cp, lend);
00782 lvalue.len = cp-lvalue.s;
00783 if (name2enum(&lvalue, &supported_protocols) >= 0) {
00784 sess->media[sess->media_count-1].active = cline_ip_s.len != 0;
00785 sess->media[sess->media_count-1].ip_s = cline_ip_s;
00786 sess->media[sess->media_count-1].ip = cline_ip;
00787 }
00788
00789 sess->media[sess->media_count-1].codecs = (struct sdp_codec (*)[]) (codecs + codec_count);
00790 while (cp < lend) {
00791 if (codec_count >= MAX_CODEC_NUMBER) {
00792 ERR(MODULE_NAME": parse_sdp_content: max.number of codecs (%d) exceeded\n", MAX_CODEC_NUMBER);
00793 return -1;
00794 }
00795 codecs[codec_count].mline_payload_type_s.s = cp;
00796 cp = eat_space_end(cp, lend);
00797 lvalue.s = cp;
00798 cp = eat_token_end(cp, lend);
00799 codecs[codec_count].mline_payload_type_s.len = cp - codecs[codec_count].mline_payload_type_s.s;
00800 lvalue.len = cp-lvalue.s;
00801 savec = lvalue.s[lvalue.len];
00802 lvalue.s[lvalue.len] = '\0';
00803 codecs[codec_count].payload_type = atol(lvalue.s);
00804 if (codecs[codec_count].payload_type < MAX_FIXED_PAYLOAD_TYPES) {
00805 codecs[codec_count].codec_id = fixed_payload_types[codecs[codec_count].payload_type].codec_id;
00806 }
00807 lvalue.s[lvalue.len] = savec;
00808 for (i=0; i < sess->media[sess->media_count-1].codec_count; i++) {
00809 if (codecs[codec_count].payload_type == (*sess->media[sess->media_count-1].codecs)[i].payload_type) {
00810 ERR(MODULE_NAME": parse_sdp_content: duplicate payload type in '%.*s'\n", (int) (lend-line.s), line.s);
00811 return -1;
00812 }
00813 }
00814 codec_count++;
00815 sess->media[sess->media_count-1].codec_count++;
00816 }
00817 if (!sess->media[sess->media_count-1].codec_count) {
00818 ERR(MODULE_NAME": parse_sdp_content: no codec declared '%.*s'\n", (int) (lend-line.s), line.s);
00819 return -1;
00820 }
00821 break;
00822 default:
00823 ;
00824 }
00825
00826 break;
00827 case 'a':
00828 i = name2enum(&lvalue, &send_rec_modifiers);
00829 if (i > 0) {
00830 switch (sess_fl) {
00831 case 1:
00832 if (sess_send_rec_modifier) {
00833 ERR(MODULE_NAME": parse_sdp_content: duplicate send/recv modifier in session '%.*s'\n", (int) (lend-line.s), line.s);
00834 return -1;
00835 }
00836 sess_send_rec_modifier = i;
00837 break;
00838 case 2:
00839 if (sess->media[sess->media_count-1].send_rec_modifier_line_s.s) {
00840 ERR(MODULE_NAME": parse_sdp_content: duplicate send/recv modifier in stream '%.*s'\n", (int) (lend-line.s), line.s);
00841 return -1;
00842 }
00843 sess->media[sess->media_count-1].send_rec_modifier = i;
00844 sess->media[sess->media_count-1].send_rec_modifier_line_s = line;
00845 default:
00846 ;
00847 }
00848 }
00849 else if (sess_fl == 2) {
00850 int payload_type;
00851 int a_attr;
00852 a_attr = prefix2enum(&lvalue, &a_attrs);
00853 if (a_attr < 0) {
00854 break;
00855 }
00856 lend = lvalue.s + lvalue.len;
00857 lvalue.s += a_attrs[a_attr].len;
00858 switch (a_attr) {
00859 case sdpaattr_rtpmap:
00860
00861 case sdpaattr_fmtp:
00862
00863
00864
00865
00866
00867
00868
00869 cp = eat_token_end(lvalue.s, lend);
00870 lvalue.len = cp-lvalue.s;
00871 savec = lvalue.s[lvalue.len];
00872 lvalue.s[lvalue.len] = '\0';
00873 payload_type = atol(lvalue.s);
00874 lvalue.s[lvalue.len] = savec;
00875 for (i=0; i < sess->media[sess->media_count-1].codec_count; i++) {
00876 if ((*sess->media[sess->media_count-1].codecs)[i].payload_type == payload_type) {
00877 goto found;
00878 }
00879 }
00880 ERR(MODULE_NAME": parse_sdp_content: '%.*s' payload type (%d) has not been mentioned at m= line\n", (int) (lend-line.s), line.s, payload_type);
00881 return -1;
00882 found:
00883 cp = eat_space_end(cp, lend);
00884 switch (a_attr) {
00885 case sdpaattr_rtpmap:
00886 if ((*sess->media[sess->media_count-1].codecs)[i].a_rtpmap_line_s.s) {
00887 ERR(MODULE_NAME": parse_sdp_content: '%.*s' multiple a=rtpmap lines for payload type (%d)\n", (int) (lend-line.s), line.s, payload_type);
00888 return -1;
00889
00890 }
00891 (*sess->media[sess->media_count-1].codecs)[i].a_rtpmap_line_s = line;
00892 lvalue.s = cp;
00893 cp = eat_token2_end(cp, lend, '/');
00894 lvalue.len = cp-lvalue.s;
00895 (*sess->media[sess->media_count-1].codecs)[i].codec_id = name2codec_id(&lvalue, NULL);
00896 break;
00897 case sdpaattr_fmtp:
00898 if ((*sess->media[sess->media_count-1].codecs)[i].a_fmtp_line_s.s) {
00899 ERR(MODULE_NAME": parse_sdp_content: '%.*s' multiple a=fmtp lines for payload type (%d)\n", (int) (lend-line.s), line.s, payload_type);
00900 return -1;
00901 }
00902 (*sess->media[sess->media_count-1].codecs)[i].a_fmtp_line_s = line;
00903 break;
00904 default:
00905 break;
00906 }
00907 break;
00908 case sdpaattr_rtcp:
00909
00910 ERR(MODULE_NAME": parse_sdp_content: a=rtcp parameter is ignored '%.*s', RTCP relaying may fail\n", (int) (lend-line.s), line.s);
00911 break;
00912 default:
00913 ;
00914 }
00915 }
00916 break;
00917
00918 default:
00919 ;
00920 }
00921 }
00922 return 0;
00923 }
00924
00925
00926 static inline int check_parse_sdp_content(struct sip_msg* msg, struct sdp_session *sess) {
00927 switch (sdp_parsed) {
00928 case -1:
00929 case 0:
00930 return sdp_parsed;
00931 default:
00932 sdp_parsed = parse_sdp_content(msg, sess);
00933 return sdp_parsed;
00934 }
00935 }
00936
00937 static int prepare_lumps(struct sip_msg* msg, str* position, str* s) {
00938 struct lump* anchor;
00939 char *buf;
00940
00941 if (!position->s)
00942 return 0;
00943
00944 anchor = del_lump(msg, position->s - msg->buf, position->len, 0);
00945 if (anchor == NULL) {
00946 ERR(MODULE_NAME": prepare_lumps: del_lump failed\n");
00947 return -1;
00948 }
00949 if (!s || !s->len) return 0;
00950
00951 buf = pkg_malloc(s->len);
00952 if (buf == NULL) {
00953 ERR(MODULE_NAME": prepare_lumps: out of memory\n");
00954 return -1;
00955 }
00956 memcpy(buf, s->s, s->len);
00957 if (insert_new_lump_after(anchor, buf, s->len, 0) == 0) {
00958 ERR(MODULE_NAME": prepare_lumps: insert_new_lump_after failed\n");
00959 pkg_free(buf);
00960 return -1;
00961 }
00962 return 0;
00963 }
00964
00965 static int update_sdp_content(struct sip_msg* msg, int gate_a_to_b, struct sdp_session *sdp_sess, struct ipt_session *ipt_sess) {
00966 int i, j;
00967 str s;
00968
00969 global_params.sdp_ip.len = 0;
00970 for (i=0; i<sdp_sess->media_count; i++) {
00971 if (sdp_sess->media[i].active) {
00972 if (ipt_sess->sdp_media[i] < 0) {
00973 goto cline_fixed;
00974 }
00975 for (j=0; j<i; j++) {
00976 if (sdp_sess->media[j].active && sdp_sess->media[i].ip_s.s == sdp_sess->media[j].ip_s.s && ipt_sess->sdp_media[j] >= 0) {
00977 goto cline_fixed;
00978 }
00979 }
00980 if (global_params.sdp_ip.len == 0) {
00981
00982 global_params.sdp_ip = sdp_sess->media[i].ip_s;
00983 }
00984 if (sdp_sess->media[i].ip != 0) {
00985
00986 ip42s(ipt_sess->sessions[ipt_sess->sdp_media[i]].dir[!gate_a_to_b].switchboard.addr.ip, &s);
00987 if (prepare_lumps(msg, &sdp_sess->media[i].ip_s, &s) < 0)
00988 return -1;
00989 }
00990 cline_fixed:
00991
00992 s.s = int2str((ipt_sess->sdp_media[i]<0)? 0: ipt_sess->sessions[ipt_sess->sdp_media[i]].dir[!gate_a_to_b].stream[0].port, &s.len);
00993 if (prepare_lumps(msg, &sdp_sess->media[i].port_s, &s) < 0)
00994 return -1;
00995 }
00996 }
00997
00998 for (i=0; i<sdp_sess->media_count; i++) {
00999 if (sdp_sess->media[i].ip && (!sdp_sess->media[i].active || ipt_sess->sdp_media[i] < 0)) {
01000 for (j=0; j<i; j++) {
01001 if (sdp_sess->media[i].ip_s.s == sdp_sess->media[j].ip_s.s) {
01002 goto cline_fixed2;
01003 }
01004 }
01005 for (j=i+1; j<sdp_sess->media_count; j++) {
01006 if (sdp_sess->media[i].ip_s.s == sdp_sess->media[j].ip_s.s &&
01007 sdp_sess->media[i].active && ipt_sess->sdp_media[i] >= 0) {
01008 goto cline_fixed2;
01009 }
01010 }
01011
01012 ip42s(0, &s);
01013 if (prepare_lumps(msg, &sdp_sess->media[i].ip_s, &s) < 0)
01014 return -1;
01015 cline_fixed2:
01016 ;
01017 }
01018 }
01019
01020
01021 if (sdp_sess->oline_addr_s.s) {
01022 if (global_params.oline_user.len) {
01023 if (prepare_lumps(msg, &sdp_sess->oline_user_s, &global_params.oline_user) < 0)
01024 return -1;
01025 }
01026 if (global_params.oline_addr.len) {
01027 if (prepare_lumps(msg, &sdp_sess->oline_addr_s, &global_params.oline_addr) < 0)
01028 return -1;
01029 }
01030 }
01031 return 0;
01032 }
01033
01034
01035 static void serialize_ipt_session(struct ipt_session* sess, str* session_ids) {
01036 static char buf[MAX_SWITCHBOARD_NAME_LEN+1+(5+1+1+10)*MAX_MEDIA_NUMBER+1];
01037 char *p;
01038 int i;
01039 buf[0] = '\0';
01040 p = buf;
01041 if (sess->sdp_media_count) {
01042 if (sess->switchboard) {
01043 memcpy(p, sess->switchboard->name.s, sess->switchboard->name.len);
01044 p += sess->switchboard->name.len;
01045 }
01046 *p = ':';
01047 p++;
01048 for (i=0; i<sess->sdp_media_count; i++) {
01049 if (sess->sdp_media[i] >= 0) {
01050 p += sprintf(p, "%u/%u",
01051 sess->sessions[sess->sdp_media[i]].dir[0].sess_id,
01052 sess->sessions[sess->sdp_media[i]].sh.created
01053 );
01054 }
01055 *p = ',';
01056 p++;
01057 }
01058 p--;
01059 *p = '\0';
01060 }
01061 session_ids->s = buf;
01062 session_ids->len = p - buf;
01063 }
01064
01065
01066
01067 static int unserialize_ipt_session(str* session_ids, struct ipt_session* sess) {
01068 char *p, *pend, savec;
01069 str s;
01070 unsigned int sess_id, created, i;
01071
01072 memset(sess, 0, sizeof(*sess));
01073 if (session_ids->len == 0) {
01074 return 0;
01075 }
01076 p = session_ids->s;
01077 pend = session_ids->s+session_ids->len;
01078 s.s = p;
01079 while (p < pend && is_alpha(*p)) p++;
01080 s.len = p-s.s;
01081 sess->switchboard = find_switchboard(&s, NULL);
01082 global_params.switchboard[0] = sess->switchboard;
01083 if (s.len && !sess->switchboard) {
01084 ERR(MODULE_NAME": unserialize_ipt_session: '%.*s', switchboard '%.*s' not found\n", STR_FMT(session_ids), STR_FMT(&s));
01085 return -1;
01086 }
01087 if (p == pend) return 0;
01088 if (*p != ':') {
01089 ERR(MODULE_NAME": unserialize_ipt_session: '%.*s', colon expected near '%.*s'\n", STR_FMT(session_ids), PTR2INT(pend-p), p);
01090 return -1;
01091 }
01092 do {
01093 if (sess->sdp_media_count >= MAX_MEDIA_NUMBER) {
01094 ERR(MODULE_NAME": unserialize_ipt_session: '%.*s', max.media number (%d) exceeded\n", STR_FMT(session_ids), MAX_MEDIA_NUMBER);
01095 return -1;
01096 }
01097 sess->sdp_media[sess->sdp_media_count] = -1;
01098 p++;
01099 if (p < pend && *p != ',') {
01100 s.s = p;
01101 while (p < pend && (*p >= '0' && *p <= '9')) p++;
01102 s.len = p-s.s;
01103 if (s.len == 0 || p == pend || *p != '/') {
01104 ERR(MODULE_NAME": unserialize_ipt_session: '%.*s', '/' expected near '%.*s'\n", STR_FMT(session_ids), PTR2INT(pend-p), p);
01105 return -1;
01106 }
01107 savec = s.s[s.len];
01108 s.s[s.len] = '\0';
01109 sess_id = atol(s.s);
01110 s.s[s.len] = savec;
01111 p++;
01112 s.s = p;
01113 while (p < pend && (*p >= '0' && *p <= '9')) p++;
01114 s.len = p-s.s;
01115 if (s.len == 0 || (p != pend && *p != ',')) {
01116 ERR(MODULE_NAME": unserialize_ipt_session: '%.*s', comma expected near '%.*s'\n", STR_FMT(session_ids), PTR2INT(pend-p), p);
01117 return -1;
01118 }
01119 savec = s.s[s.len];
01120 s.s[s.len] = '\0';
01121 created = atol(s.s);
01122 s.s[s.len] = savec;
01123
01124 for (i=0; i<sess->sdp_media_count; i++) {
01125 if (sess->sdp_media[i] >= 0 && sess->sessions[sess->sdp_media[i]].dir[0].sess_id == sess_id) {
01126 if (sess->sessions[sess->sdp_media[i]].sh.created != created) {
01127 ERR(MODULE_NAME": unserialize_ipt_session: '%.*s', sess-id/created mismatch '%u/(%u!=%u)'\n",
01128 STR_FMT(session_ids), sess_id, sess->sessions[sess->sdp_media[i]].sh.created, created);
01129 return -1;
01130 }
01131 sess->sdp_media[sess->sdp_media_count] = sess->sdp_media[i];
01132 goto cont;
01133 }
01134 }
01135 sess->sessions[sess->session_count].dir[0].switchboard.addr = sess->switchboard->switchboard_addr;
01136 sess->sessions[sess->session_count].dir[0].sess_id = sess_id;
01137 sess->sessions[sess->session_count].sh.created = created;
01138 sess->sdp_media[sess->sdp_media_count] = sess->session_count;
01139 sess->session_count++;
01140 }
01141 cont:
01142 sess->sdp_media_count++;
01143 } while (p < pend);
01144 return 0;
01145 }
01146
01147 static inline int check_host_err(struct host_item *hi, int ret) {
01148 switch (hi->handle.err_no) {
01149 case XT_RTPPROXY_ERR_CANNOT_OPEN_SOCKET:
01150 case XT_RTPPROXY_ERR_RPC:
01151 atomic_set_int(&hi->stat->last_error_stamp, (int) time(NULL));
01152 break;
01153 default:
01154 atomic_set_int(&hi->stat->last_ok_stamp, (int) time(NULL));
01155 }
01156 return ret;
01157 }
01158
01159 static inline int check_open_handle(struct host_item* hi) {
01160 if (!hi->handle_is_opened) {
01161 if (hi->local) {
01162 if (check_host_err(hi, xt_RTPPROXY_open(&hi->handle, xt_rtpproxy_LOCAL, NULL)) < 0) goto err;
01163 } else {
01164 if (check_host_err(hi, xt_RTPPROXY_open(&hi->handle, xt_rtpproxy_REMOTE, &hi->rpc_params)) < 0) goto err;
01165 }
01166 hi->handle_is_opened = 1;
01167 }
01168 return 0;
01169 err:
01170 ERR(MODULE_NAME": %s (%d)\n", hi->handle.err_str, hi->handle.err_no);
01171 return -1;
01172 }
01173
01174
01175 static void delete_ipt_sessions(struct host_item* hi, struct ipt_session* ipt_sess, struct ipt_session *ipt_surviving_sess) {
01176 int i;
01177 for (i=0; i < ipt_sess->session_count; i++) {
01178 if (ipt_sess->switchboard == ipt_surviving_sess->switchboard) {
01179 int j;
01180 for (j=0; j < ipt_surviving_sess->session_count; j++) {
01181 if (ipt_sess->sessions[i].dir[0].sess_id == ipt_surviving_sess->sessions[j].dir[0].sess_id &&
01182 ipt_sess->sessions[i].sh.created == ipt_surviving_sess->sessions[j].sh.created ) {
01183 goto skip_del;
01184 }
01185 }
01186 }
01187 ipt_sess->sessions[i].sh.flags |= XT_RTPPROXY_SOCKOPT_FLAG_SESSION_DESTROY;
01188 skip_del:
01189 ;
01190 }
01191
01192
01193 if (check_host_err(hi, xt_RTPPROXY_update_sessions(&hi->handle, ipt_sess->session_count, &ipt_sess->sessions)) < 0) {
01194 ERR(MODULE_NAME": delete_ipt_sessions: xt_RTPPROXY_update_session error: %s (%d)\n", hi->handle.err_str, hi->handle.err_no);
01195
01196 }
01197 }
01198
01199 #define GATE_FLAG 0x01
01200 #define UPDATE_SDP_ONLY_FLAG 0x02
01201
01202
01203 #define GATE_A_TO_B(flags) (((flags) & GATE_FLAG) == 0)
01204
01205
01206 inline static void fill_in_session(int flags, int media_idx, struct sdp_session *sdp_sess, struct xt_rtpproxy_sockopt_session *in_session) {
01207 int j;
01208 for (j=0; j<2; j++) {
01209 if (sdp_sess) {
01210 in_session->dir[GATE_A_TO_B(flags)].stream[j].flags |= XT_RTPPROXY_SOCKOPT_FLAG_SESSION_ADDR;
01211 in_session->dir[GATE_A_TO_B(flags)].stream[j].source.ip = sdp_sess->media[media_idx].ip;
01212 in_session->dir[GATE_A_TO_B(flags)].stream[j].source.port = sdp_sess->media[media_idx].port+j;
01213 }
01214 if (global_params.learning_timeout > 0) {
01215 in_session->dir[GATE_A_TO_B(flags)].stream[j].flags |= XT_RTPPROXY_SOCKOPT_FLAG_SESSION_LEARNING_TIMEOUT;
01216 in_session->dir[GATE_A_TO_B(flags)].stream[j].learning_timeout = global_params.learning_timeout;
01217 }
01218 }
01219 if (global_params.always_learn >= 0) {
01220 in_session->dir[GATE_A_TO_B(flags)].always_learn = global_params.always_learn!=0;
01221 in_session->dir[GATE_A_TO_B(flags)].flags |= XT_RTPPROXY_SOCKOPT_FLAG_ALWAYS_LEARN;
01222 }
01223 if (global_params.expiration_timeout > 0) {
01224 in_session->sh.expires_timeout = global_params.expiration_timeout;
01225 in_session->sh.flags |= XT_RTPPROXY_SOCKOPT_FLAG_SESSION_EXPIRES;
01226 }
01227 if (global_params.ttl >= 0) {
01228 in_session->sh.ttl = global_params.ttl;
01229 in_session->sh.flags |= XT_RTPPROXY_SOCKOPT_FLAG_SESSION_TTL;
01230 }
01231 }
01232
01233 inline static void fill_in_session_throttle(int flags, int media_idx, struct xt_rtpproxy_sockopt_session *in_session) {
01234 int j;
01235 if (global_params.throttle.mark > 0) {
01236 for (j=0; j<2; j++) {
01237 in_session->dir[GATE_A_TO_B(flags)].stream[j].throttle.mark = global_params.throttle.mark;
01238 in_session->dir[GATE_A_TO_B(flags)].stream[j].flags |= XT_RTPPROXY_SOCKOPT_FLAG_THROTTLE_MARK;
01239 }
01240 }
01241 for (j=0; j<2; j++) {
01242 if (global_params.codec_set &&
01243 (global_params.codec_set->media_types[global_sdp_sess.media[media_idx].media_type].throttle.bandwidth[j].packets > 0 ||
01244 global_params.codec_set->media_types[global_sdp_sess.media[media_idx].media_type].throttle.bandwidth[j].bytes > 0)
01245 ) {
01246 in_session->dir[GATE_A_TO_B(flags)].stream[j].throttle.max_bandwidth = global_params.codec_set->media_types[global_sdp_sess.media[media_idx].media_type].throttle.bandwidth[j];
01247 in_session->dir[GATE_A_TO_B(flags)].stream[j].flags |= XT_RTPPROXY_SOCKOPT_FLAG_THROTTLE_BANDWIDTH;
01248 } else if (global_params.throttle.bandwidth[j].bytes > 0 || global_params.throttle.bandwidth[j].packets > 0 ) {
01249 in_session->dir[GATE_A_TO_B(flags)].stream[j].throttle.max_bandwidth = global_params.throttle.bandwidth[j];
01250 in_session->dir[GATE_A_TO_B(flags)].stream[j].flags |= XT_RTPPROXY_SOCKOPT_FLAG_THROTTLE_BANDWIDTH;
01251
01252 }
01253 }
01254 }
01255
01256 static int rtpproxy_alloc(struct sip_msg* msg, char* _flags, char* _dummy) {
01257 int flags;
01258 struct ipt_session ipt_sess;
01259 struct host_item* hi = NULL;
01260 struct xt_rtpproxy_switchboard_id aggregated_switchboards[MAX_AGGREGATED_NUMBER];
01261 time_t stamp;
01262
01263 xt_rtpproxy_sockopt_count cnt[2];
01264 str s;
01265 int i, aggr_fl, reuse_existing_count;
01266
01267 if (get_int_fparam(&flags, msg, (fparam_t*) _flags) < 0) {
01268 return -1;
01269 }
01270 if (check_parse_sdp_content(msg, &global_sdp_sess) < 0) return -1;
01271
01272 ERR("RTPPROXY_DEBUG: sdp.media_count: %d, flags: %d\n", global_sdp_sess.media_count, flags);
01273 if (global_params.protected_sess.switchboard) {
01274
01275 for (i = 0; i < global_params.protected_sess.session_count; i++) {
01276 global_params.protected_sess.sessions[i].sh.flags |= XT_RTPPROXY_SOCKOPT_FLAG_SESSION_INFO;
01277 }
01278 if (check_open_handle(global_params.protected_sess.switchboard->host) < 0) {
01279 return -1;
01280 }
01281 ERR("RTPPROXY_DEBUG: xt_RTPPROXY_update_sessions(sess#:%d, sdp#:%d, XT_RTPPROXY_SOCKOPT_FLAG_SESSION_INFO)\n", global_params.protected_sess.session_count, global_params.protected_sess.sdp_media_count);
01282 if (check_host_err(global_params.protected_sess.switchboard->host, xt_RTPPROXY_update_sessions(&global_params.protected_sess.switchboard->host->handle, global_params.protected_sess.session_count, &global_params.protected_sess.sessions)) < 0) {
01283 ERR(MODULE_NAME": rtpproxy_alloc: xt_RTPPROXY_update_session error when retrieving sessions: %s (%d)\n",
01284 global_params.protected_sess.switchboard->host->handle.err_str,
01285 global_params.protected_sess.switchboard->host->handle.err_no
01286 );
01287 return -1;
01288 }
01289 }
01290
01291 reuse_existing_count = 0;
01292 memset(&ipt_sess, 0, sizeof(ipt_sess));
01293 for (i = 0; i < global_sdp_sess.media_count; i++) {
01294 ipt_sess.sdp_media[i] = -1;
01295 if (global_sdp_sess.media[i].active) {
01296 int j;
01297 for (j = 0; j < i; j++) {
01298
01299 if (global_sdp_sess.media[j].active) {
01300 if (global_sdp_sess.media[i].ip == global_sdp_sess.media[j].ip && global_sdp_sess.media[i].port == global_sdp_sess.media[j].port) {
01301 if (global_sdp_sess.media[i].ip != 0) {
01302 ipt_sess.sdp_media[i] = ipt_sess.sdp_media[j];
01303 goto cont;
01304 } else if (i < global_params.protected_sess.sdp_media_count) {
01305 int k, l;
01306 k = global_params.protected_sess.sdp_media[i];
01307 l = global_params.protected_sess.sdp_media[j];
01308 if ((global_params.protected_sess.sessions[k].sh.flags & XT_RTPPROXY_SOCKOPT_FLAG_NOT_FOUND) == 0 &&
01309 global_params.protected_sess.sessions[k].dir[GATE_A_TO_B(flags)].stream[0].source.ip == global_params.protected_sess.sessions[l].dir[GATE_A_TO_B(flags)].stream[0].source.ip &&
01310 global_params.protected_sess.sessions[k].dir[GATE_A_TO_B(flags)].stream[0].source.port == global_params.protected_sess.sessions[l].dir[GATE_A_TO_B(flags)].stream[0].source.port) {
01311
01312
01313 ipt_sess.sdp_media[i] = ipt_sess.sdp_media[j];
01314 goto cont;
01315 }
01316 }
01317 }
01318 }
01319 }
01320
01321
01322 if (i < global_params.protected_sess.sdp_media_count) {
01323 int k;
01324 k = global_params.protected_sess.sdp_media[i];
01325 ERR("RTPPROXY_DEBUG: protected.sess media:%d -> sess:%d, flags: %d\n", i, k, global_params.protected_sess.sessions[k].sh.flags);
01326 if ((global_params.protected_sess.sessions[k].sh.flags & XT_RTPPROXY_SOCKOPT_FLAG_NOT_FOUND) == 0) {
01327 switch (global_params.protected_sess.sessions[k].sh.state) {
01328 case xt_rtpproxy_INIT1:
01329 case xt_rtpproxy_INIT2:
01330 case xt_rtpproxy_FORWARD1:
01331 case xt_rtpproxy_FORWARD2:
01332
01333
01334
01335
01336
01337
01338 ERR("DEBUG_RTPPROXY: module: CMP %x=%x & %d=%d\n", global_sdp_sess.media[i].ip, global_params.protected_sess.sessions[k].dir[GATE_A_TO_B(flags)].stream[0].source.ip, global_sdp_sess.media[i].port, global_params.protected_sess.sessions[k].dir[GATE_A_TO_B(flags)].stream[0].source.port);
01339 if ((global_sdp_sess.media[i].ip == 0 ||
01340 global_params.protected_sess.sessions[k].dir[GATE_A_TO_B(flags)].stream[0].source.ip == 0 ||
01341 global_params.protected_sess.sessions[k].dir[GATE_A_TO_B(flags)].stream[0].source.ip == global_sdp_sess.media[i].ip) &&
01342
01343 global_params.protected_sess.sessions[k].dir[GATE_A_TO_B(flags)].stream[0].source.port == global_sdp_sess.media[i].port) {
01344
01345 ERR("RTPPROXY_DEBUG: REUSE!\n");
01346 for (j=ipt_sess.session_count; j > 0; j--) {
01347 ipt_sess.sessions[j] = ipt_sess.sessions[j-1];
01348 }
01349 for (j=0; j < i; j++) {
01350 if (ipt_sess.sdp_media[j] >= 0) {
01351 ipt_sess.sdp_media[j]++;
01352 }
01353 }
01354
01355 for (j=0; j<2; j++) {
01356 ipt_sess.sessions[0].dir[j] = global_params.protected_sess.sessions[k].dir[j];
01357 }
01358 ipt_sess.sessions[0].sh = global_params.protected_sess.sessions[k].sh;
01359
01360 ipt_sess.sdp_media[i] = 0;
01361 reuse_existing_count++;
01362 goto skip_fill;
01363 }
01364 break;
01365 default:
01366 ;
01367 }
01368 }
01369
01370 }
01371 if (global_sdp_sess.media[i].ip == 0) {
01372 switch (global_sdp_sess.media[i].send_rec_modifier) {
01373 case sdpaattr_sendonly:
01374 case sdpaattr_sendrecv:
01375 break;
01376 default:
01377
01378 ERR("DEBUG_RTPPROXY: module: do not allocate session for on-hold stream unless reused\n");
01379 goto cont;
01380 }
01381 }
01382 fill_in_session(flags, i, &global_sdp_sess, ipt_sess.sessions+ipt_sess.session_count);
01383 fill_in_session_throttle(flags, i, ipt_sess.sessions+ipt_sess.session_count);
01384 ipt_sess.sdp_media[i] = ipt_sess.session_count;
01385 skip_fill:
01386 ipt_sess.session_count++;
01387 }
01388 cont:
01389 ;
01390 }
01391 ipt_sess.sdp_media_count = global_sdp_sess.media_count;
01392
01393 ERR("RTPPROXY_DEBUG: session_count: %d, reuse_existing_count: %d\n", global_sdp_sess.media_count, reuse_existing_count);
01394
01395 if (ipt_sess.session_count > reuse_existing_count) {
01396 stamp = time(NULL);
01397 if (reuse_existing_count > 0) {
01398
01399 aggr_fl = 0;
01400 hi = global_params.protected_sess.switchboard->host;
01401 ipt_sess.switchboard = global_params.protected_sess.switchboard;
01402 for (i=reuse_existing_count; i < ipt_sess.session_count; i++) {
01403 int j;
01404 for (j=0; j<2; j++) {
01405 ipt_sess.sessions[i].dir[j].switchboard.addr = ipt_sess.sessions[0].dir[j].switchboard.addr;
01406 }
01407 }
01408 } else {
01409 for (i=0; i<2; i++) {
01410 if (!global_params.switchboard[i] && !global_params.aggregation[i]) {
01411 ERR(MODULE_NAME": rtpproxy_alloc: aggregation/switchboard not set (dir:%d)\n", i);
01412 return -1;
01413 }
01414 }
01415 aggr_fl = global_params.aggregation[0] || global_params.aggregation[1];
01416 if (aggr_fl) {
01417 struct switchboard_item *si;
01418
01419
01420
01421
01422 for (si=switchboards; si; si=si->next) {
01423 unsigned int w;
01424 int a, f;
01425 time_t ok_stamp, err_stamp;
01426 a = f = 0;
01427 ok_stamp = atomic_get_int(&si->host->stat->last_ok_stamp);
01428 err_stamp = atomic_get_int(&si->host->stat->last_error_stamp);
01429 if (rpc_heartbeat_timeout > 0 && err_stamp > ok_stamp && (stamp-err_stamp) >= rpc_heartbeat_timeout) {
01430
01431 ok_stamp = err_stamp = 0;
01432 }
01433 if (err_stamp > ok_stamp) {
01434
01435
01436 w = time(NULL) - err_stamp + 1;
01437 if (w > 999) w = 999;
01438
01439 } else if (ok_stamp == 0) {
01440
01441 w = 100000000 + (rand() & 0xFFFF);
01442 } else {
01443
01444 w = 1000;
01445 a = atomic_get(&si->stat->alloc);
01446 f = atomic_get(&si->stat->free);
01447 if ((a + f) > 0) {
01448
01449 w += (1000*f)/(a+f);
01450 }
01451 }
01452 si->weight = w;
01453
01454 }
01455 hi = NULL;
01456 }
01457 else {
01458 if (global_params.switchboard[0]->host != global_params.switchboard[1]->host) {
01459 ERR(MODULE_NAME": rtpproxy_alloc: switchboard resides of different hosts '%.*s'!='%.*s'\n",
01460 STR_FMT(&global_params.switchboard[0]->host->name),
01461 STR_FMT(&global_params.switchboard[1]->host->name)
01462 );
01463 return -1;
01464 }
01465 hi = global_params.switchboard[0]->host;
01466 for (i=0; i < ipt_sess.session_count; i++) {
01467 int j;
01468 for (j=0; j<2; j++) {
01469 ipt_sess.sessions[i].dir[j].switchboard.addr = global_params.switchboard[j]->switchboard_addr;
01470 }
01471 }
01472 }
01473 }
01474 try_next_host:
01475 cnt[0] = cnt[1] = 0;
01476 if (aggr_fl) {
01477 int j;
01478 hi = NULL;
01479 if (global_params.aggregation[0] && global_params.aggregation[1]) {
01480 int w = 0;
01481
01482 for (i=0; i<global_params.aggregation[0]->switchboard_count; i++) {
01483 if ((*global_params.aggregation[0]->switchboards)[i]->weight > w) {
01484 time_t err_stamp;
01485 err_stamp = atomic_get_int(&(*global_params.aggregation[0]->switchboards)[i]->host->stat->last_error_stamp);
01486 if (err_stamp >= stamp) {
01487 if (w > 0) continue;
01488
01489 w = 1;
01490 } else {
01491 w = (*global_params.aggregation[0]->switchboards)[i]->weight;
01492 }
01493 hi = (*global_params.aggregation[0]->switchboards)[i]->host;
01494 }
01495 }
01496 } else {
01497 for (j=0; j<2; j++) {
01498 if (!global_params.aggregation[j] && global_params.switchboard[j]->weight) {
01499 hi = global_params.switchboard[j]->host;
01500 }
01501 }
01502 }
01503 if (!hi) {
01504 ERR(MODULE_NAME": rtpproxy_alloc: cannot allocate aggregated switchboard (#1)\n");
01505 return -1;
01506 }
01507 for (j=0; j<2; j++) {
01508 if (global_params.aggregation[j]) {
01509 struct switchboard_item *aggr_switchboards[MAX_AGGREGATED_NUMBER];
01510 for (i=0; i<global_params.aggregation[j]->switchboard_count; i++) {
01511 if ((*global_params.aggregation[j]->switchboards)[i]->weight &&
01512 (*global_params.aggregation[j]->switchboards)[i]->host == hi) {
01513 int k, l;
01514 if (cnt[0]+cnt[1] >= MAX_AGGREGATED_NUMBER) {
01515 ERR(MODULE_NAME": rtpproxy_alloc: number of aggregated switchboard exceeded limit %d\n", MAX_AGGREGATED_NUMBER);
01516 return -1;
01517 }
01518
01519 for (k=0; k<cnt[j] && aggr_switchboards[k]->weight >= (*global_params.aggregation[j]->switchboards)[i]->weight; k++);
01520 for (l=cnt[j]; l>k; l--) {
01521 aggr_switchboards[l] = aggr_switchboards[l-1];
01522 }
01523 aggr_switchboards[k] = (*global_params.aggregation[j]->switchboards)[i];
01524 cnt[j]++;
01525 }
01526 }
01527 if (!cnt[j]) {
01528 ERR(MODULE_NAME": rtpproxy_alloc: cannot allocate aggregated switchboard (#2)\n");
01529 return -1;
01530 }
01531 for (i = 0; i < cnt[j]; i++) {
01532 aggregated_switchboards[j*cnt[0]+i] = aggr_switchboards[i]->switchboard_addr;
01533 }
01534 }
01535 else {
01536 if (cnt[0]+cnt[1] >= MAX_AGGREGATED_NUMBER) {
01537 ERR(MODULE_NAME": rtpproxy_alloc: number of aggregated switchboard exceeded limit %d\n", MAX_AGGREGATED_NUMBER);
01538 return -1;
01539 }
01540 aggregated_switchboards[cnt[0]+cnt[1]] = global_params.switchboard[j]->switchboard_addr;
01541 cnt[j]++;
01542 }
01543 }
01544 for (j=0; j<2; j++) {
01545 if (global_params.aggregation[j]) {
01546 for (i=0; i<global_params.aggregation[j]->switchboard_count; i++) {
01547 if ((*global_params.aggregation[j]->switchboards)[i]->host == hi) {
01548
01549 (*global_params.aggregation[j]->switchboards)[i]->weight = 0;
01550 }
01551 }
01552 }
01553 else {
01554 global_params.switchboard[j]->weight = 0;
01555 }
01556 }
01557 }
01558
01559 if (reuse_existing_count < ipt_sess.session_count) {
01560 if (check_open_handle(hi) < 0) {
01561 if (aggr_fl) {
01562 goto try_next_host;
01563 }
01564 return -1;
01565 }
01566 ERR("DEBUG_RTPPROXY: module: rtpproxy_alloc: xt_RTPPROXY_alloc_sessions(%d/%d/%d), host: '%.*s', flags: %d\n", cnt[0], cnt[1], ipt_sess.session_count, STR_FMT(&hi->name), flags);
01567 if (check_host_err(hi, xt_RTPPROXY_alloc_sessions(&hi->handle,
01568 cnt[0],
01569 &aggregated_switchboards,
01570 cnt[1],
01571 (void*) &aggregated_switchboards[cnt[0]],
01572 ipt_sess.session_count-reuse_existing_count,
01573 &ipt_sess.sessions+reuse_existing_count
01574 )) < 0) {
01575 ERR(MODULE_NAME": rtpproxy_alloc: xt_RTPPROXY_alloc_session error: %s (%d)\n", hi->handle.err_str, hi->handle.err_no);
01576 if (aggr_fl) {
01577 goto try_next_host;
01578 }
01579 return -1;
01580 }
01581 }
01582 }
01583 if (update_sdp_content(msg, GATE_A_TO_B(flags), &global_sdp_sess, &ipt_sess) < 0) {
01584 delete_ipt_sessions(hi, &ipt_sess, &global_params.protected_sess);
01585 return -1;
01586 }
01587 if (ipt_sess.session_count) {
01588 ipt_sess.switchboard = find_switchboard_by_addr(&ipt_sess.sessions[0].dir[0].switchboard.addr);
01589 if (!ipt_sess.switchboard) {
01590 BUG(MODULE_NAME": rtpproxy_alloc: switchboard-a definition not found\n");
01591 return -1;
01592 }
01593
01594 global_params.switchboard[0] = ipt_sess.switchboard;
01595 global_params.switchboard[1] = find_switchboard_by_addr(&ipt_sess.sessions[0].dir[1].switchboard.addr);
01596 if (!global_params.switchboard[1]) {
01597 BUG(MODULE_NAME": rtpproxy_alloc: switchboard-b definition not found\n");
01598 return -1;
01599 }
01600
01601 atomic_set(&global_params.switchboard[0]->stat->free, ipt_sess.sessions[0].dir[0].switchboard.free);
01602 atomic_set(&global_params.switchboard[0]->stat->alloc, ipt_sess.sessions[0].dir[0].switchboard.alloc);
01603 if (global_params.switchboard[0] != global_params.switchboard[1]) {
01604 atomic_set(&global_params.switchboard[1]->stat->free, ipt_sess.sessions[0].dir[1].switchboard.free);
01605 atomic_set(&global_params.switchboard[1]->stat->alloc, ipt_sess.sessions[0].dir[1].switchboard.alloc);
01606 }
01607 }
01608 else {
01609 ipt_sess.switchboard = global_params.protected_sess.switchboard;
01610 global_params.switchboard[0] = ipt_sess.switchboard;
01611 }
01612 serialize_ipt_session(&ipt_sess, &s);
01613 global_params.session_ids = s;
01614 return 1;
01615 }
01616
01617 static int rtpproxy_update(struct sip_msg* msg, char* _flags, char* _session_ids) {
01618 str session_ids;
01619 int flags, i;
01620 struct ipt_session ipt_sess;
01621
01622 if (get_int_fparam(&flags, msg, (fparam_t*) _flags) < 0) {
01623 return -1;
01624 }
01625 if (get_str_fparam(&session_ids, msg, (fparam_t*) _session_ids) < 0) {
01626 return -1;
01627 }
01628 if (unserialize_ipt_session(&session_ids, &ipt_sess) < 0) {
01629 return -1;
01630 }
01631 if (check_parse_sdp_content(msg, &global_sdp_sess) < 0) return -1;
01632
01633 if (ipt_sess.sdp_media_count != global_sdp_sess.media_count) {
01634 ERR(MODULE_NAME": rtpproxy_update: number of m= item in offer (%d) and answer (%d) do not correspond\n", ipt_sess.sdp_media_count, global_sdp_sess.media_count);
01635 return -1;
01636 }
01637
01638 for (i = 0; i < global_sdp_sess.media_count; i++) {
01639 if (ipt_sess.sdp_media[i] >= 0 && global_sdp_sess.media[i].active) {
01640 int j;
01641 for (j = i+1; j < global_sdp_sess.media_count; j++) {
01642 if (ipt_sess.sdp_media[j] >= 0 && global_sdp_sess.media[j].active) {
01643
01644 if ( (global_sdp_sess.media[i].ip == global_sdp_sess.media[j].ip && global_sdp_sess.media[i].port == global_sdp_sess.media[j].port) ^
01645 (ipt_sess.sdp_media[i] == ipt_sess.sdp_media[j]) ) {
01646 ERR(MODULE_NAME": rtpproxy_update: media (%d,%d) violation number\n", i, j);
01647 return -1;
01648 }
01649 }
01650 }
01651 }
01652 }
01653
01654 if (flags & UPDATE_SDP_ONLY_FLAG) {
01655
01656 for (i = 0; i < ipt_sess.session_count; i++) {
01657 ipt_sess.sessions[i].sh.flags |= XT_RTPPROXY_SOCKOPT_FLAG_SESSION_INFO;
01658 }
01659 } else {
01660
01661 for (i = 0; i < global_sdp_sess.media_count; i++) {
01662 if (ipt_sess.sdp_media[i] >= 0) {
01663 if (!global_sdp_sess.media[i].active) {
01664 ipt_sess.sessions[ipt_sess.sdp_media[i]].sh.flags |= XT_RTPPROXY_SOCKOPT_FLAG_SESSION_DESTROY;
01665 ipt_sess.sdp_media[i] = -1;
01666 }
01667 }
01668 }
01669
01670 for (i = 0; i < global_sdp_sess.media_count; i++) {
01671 if (ipt_sess.sdp_media[i] >= 0) {
01672 if (global_sdp_sess.media[i].active) {
01673 fill_in_session(flags, i, &global_sdp_sess, ipt_sess.sessions+ipt_sess.sdp_media[i]);
01674 fill_in_session_throttle(flags, i, ipt_sess.sessions+ipt_sess.sdp_media[i]);
01675 ipt_sess.sessions[ipt_sess.sdp_media[i]].sh.flags &= ~XT_RTPPROXY_SOCKOPT_FLAG_SESSION_DESTROY;
01676 }
01677 }
01678 }
01679
01680 for (i = 0; i < ipt_sess.session_count; i++) {
01681 if (ipt_sess.sessions[i].sh.flags & XT_RTPPROXY_SOCKOPT_FLAG_SESSION_DESTROY) {
01682 if (ipt_sess.switchboard == global_params.protected_sess.switchboard) {
01683 int j;
01684 for (j=0; j < global_params.protected_sess.session_count; j++) {
01685 if (ipt_sess.sessions[i].dir[0].sess_id == global_params.protected_sess.sessions[j].dir[0].sess_id &&
01686 ipt_sess.sessions[i].sh.created == global_params.protected_sess.sessions[j].sh.created ) {
01687 ipt_sess.sessions[i].sh.flags &= ~XT_RTPPROXY_SOCKOPT_FLAG_SESSION_DESTROY;
01688 ipt_sess.sessions[i].sh.flags |= XT_RTPPROXY_SOCKOPT_FLAG_SESSION_INFO;
01689
01690 break;
01691 }
01692 }
01693 }
01694 }
01695 }
01696 }
01697
01698
01699 global_params.switchboard[0] = ipt_sess.switchboard;
01700 if (ipt_sess.switchboard) {
01701 if (check_open_handle(ipt_sess.switchboard->host) < 0) {
01702 return -1;
01703 }
01704 if (check_host_err(ipt_sess.switchboard->host, xt_RTPPROXY_update_sessions(&ipt_sess.switchboard->host->handle, ipt_sess.session_count, &ipt_sess.sessions)) < 0) {
01705 ERR(MODULE_NAME": rtpproxy_update: xt_RTPPROXY_update_session error: %s (%d)\n",
01706 ipt_sess.switchboard->host->handle.err_str,
01707 ipt_sess.switchboard->host->handle.err_no
01708 );
01709
01710 return -1;
01711 }
01712 global_params.switchboard[1] = find_switchboard_by_addr(&ipt_sess.sessions[0].dir[1].switchboard.addr);
01713 } else {
01714
01715 global_params.switchboard[1] = NULL;
01716 }
01717 if (update_sdp_content(msg, GATE_A_TO_B(flags), &global_sdp_sess, &ipt_sess) < 0) {
01718
01719 return -1;
01720 }
01721 serialize_ipt_session(&ipt_sess, &session_ids);
01722 global_params.session_ids = session_ids;
01723 return 1;
01724 }
01725
01726 static int rtpproxy_adjust_timeout(struct sip_msg* msg, char* _flags, char* _session_ids) {
01727 str session_ids;
01728 int flags, i;
01729 struct ipt_session ipt_sess;
01730
01731 if (get_int_fparam(&flags, msg, (fparam_t*) _flags) < 0) {
01732 return -1;
01733 }
01734 if (get_str_fparam(&session_ids, msg, (fparam_t*) _session_ids) < 0) {
01735 return -1;
01736 }
01737 if (unserialize_ipt_session(&session_ids, &ipt_sess) < 0) {
01738 return -1;
01739 }
01740 if (!ipt_sess.switchboard) {
01741 return 1;
01742 }
01743 for (i = 0; i < ipt_sess.sdp_media_count; i++) {
01744 if (ipt_sess.sdp_media[i] >= 0) {
01745 fill_in_session(flags, i, NULL, ipt_sess.sessions+ipt_sess.sdp_media[i]);
01746
01747 }
01748 }
01749
01750 if (check_open_handle(ipt_sess.switchboard->host) < 0) {
01751 return -1;
01752 }
01753 if (check_host_err(ipt_sess.switchboard->host, xt_RTPPROXY_update_sessions(&ipt_sess.switchboard->host->handle, ipt_sess.session_count, &ipt_sess.sessions)) < 0) {
01754 ERR(MODULE_NAME": rtpproxy_adjust_timeout: xt_RTPPROXY_adjust_timeout error: %s (%d)\n",
01755 ipt_sess.switchboard->host->handle.err_str,
01756 ipt_sess.switchboard->host->handle.err_no
01757 );
01758 return -1;
01759 }
01760
01761 return 1;
01762 }
01763
01764 static int rtpproxy_delete(struct sip_msg* msg, char* _session_ids, char* _dummy) {
01765 str session_ids;
01766 struct ipt_session ipt_sess;
01767 if (get_str_fparam(&session_ids, msg, (fparam_t*) _session_ids) < 0) {
01768 return -1;
01769 }
01770 if (!session_ids.len) return 1;
01771 if (unserialize_ipt_session(&session_ids, &ipt_sess) < 0) {
01772 return -1;
01773 }
01774
01775
01776 if (!ipt_sess.switchboard) {
01777 return 1;
01778 }
01779 if (check_open_handle(ipt_sess.switchboard->host) < 0) {
01780 return -1;
01781 }
01782 delete_ipt_sessions(ipt_sess.switchboard->host, &ipt_sess, &global_params.protected_sess);
01783
01784 return 1;
01785 }
01786
01787 static int rtpproxy_authorize_media(struct sip_msg* msg, char* _dummy1, char* _dummy2) {
01788 unsigned int media_count[MAX_MEDIA_NUMBER];
01789 int i;
01790 if (!global_params.codec_set) return 1;
01791
01792 if (check_parse_sdp_content(msg, &global_sdp_sess) < 0) return -1;
01793 global_params.auth_rights = 0;
01794 memset(&media_count, 0, sizeof(media_count));
01795
01796 for (i=0; i<global_sdp_sess.media_count; i++) {
01797 int j, n, fl;
01798 if (global_sdp_sess.media[i].active != 1) continue;
01799 n = 0;
01800 fl = media_count[global_sdp_sess.media[i].media_type] == global_params.codec_set->media_types[global_sdp_sess.media[i].media_type].throttle.max_streams;
01801 if (fl) {
01802 goto remove_stream;
01803 }
01804 for (j=0; j<global_sdp_sess.media[i].codec_count; j++) {
01805 unsigned int r;
01806 struct sdp_codec *c;
01807 c = &(*global_sdp_sess.media[i].codecs)[j];
01808
01809 if (!c->mline_payload_type_s.s) continue;
01810 r = (*global_params.codec_set->media_types[global_sdp_sess.media[i].media_type].codec_rights)[c->codec_id];
01811 if (r) {
01812 if (r > global_params.auth_rights) {
01813 global_params.auth_rights = r;
01814 }
01815 if (r & global_params.remove_codec_mask) {
01816
01817 n++;
01818 if (n < global_sdp_sess.media[i].codec_count) {
01819
01820 if (prepare_lumps(msg, &c->mline_payload_type_s, NULL) < 0)
01821 return -1;
01822 c->mline_payload_type_s.s = NULL;
01823 if (prepare_lumps(msg, &c->a_rtpmap_line_s, NULL) < 0)
01824 return -1;
01825 if (prepare_lumps(msg, &c->a_fmtp_line_s, NULL) < 0)
01826 return -1;
01827 }
01828 }
01829 }
01830 }
01831 remove_stream:
01832 if (n == global_sdp_sess.media[i].codec_count || fl) {
01833
01834 static str zero_s = STR_STATIC_INIT("0");
01835 if (prepare_lumps(msg, & global_sdp_sess.media[i].port_s, &zero_s) < 0)
01836 return -1;
01837 global_sdp_sess.media[i].active = 0;
01838 continue;
01839 }
01840 media_count[global_sdp_sess.media[i].media_type]++;
01841 }
01842 return 1;
01843 }
01844
01845 static int rtpproxy_set_param(struct sip_msg* msg, char* _idx, char* _value) {
01846 int idx, dir;
01847 unsigned int ip;
01848 idx = PTR2INT(_idx);
01849 union {
01850 str s;
01851 int i;
01852 } u;
01853 dir = (param_list[idx].flags & PAR_DIR) != 0;
01854 if (param_list[idx].flags & PAR_INT) {
01855 if (get_int_fparam(&u.i, msg, (fparam_t*) _value) < 0) {
01856 return -1;
01857 }
01858 } else {
01859 if (get_str_fparam(&u.s, msg, (fparam_t*) _value) < 0) {
01860 return -1;
01861 }
01862 }
01863 switch (param_list[idx].id) {
01864 case PAR_EXPIRATION_TIMEOUT:
01865 global_params.expiration_timeout = u.i;
01866 break;
01867 case PAR_TTL:
01868 global_params.ttl = u.i;
01869 break;
01870 case PAR_LEARNING_TIMEOUT:
01871 global_params.learning_timeout = u.i;
01872 break;
01873 case PAR_ALWAYS_LEARN:
01874 global_params.always_learn = u.i;
01875 break;
01876 case PAR_SWITCHBOARD_A:
01877 case PAR_SWITCHBOARD_B:
01878 if (!(global_params.switchboard[dir] = find_switchboard(&u.s, NULL)))
01879 return -1;
01880 break;
01881 case PAR_SWITCHBOARD_BY_SIP_IP_A:
01882 case PAR_SWITCHBOARD_BY_SIP_IP_B:
01883 ip = s2ip4(&u.s);
01884 for (global_params.switchboard[dir] = switchboards;
01885 global_params.switchboard[dir];
01886 global_params.switchboard[dir] = global_params.switchboard[dir]->next) {
01887
01888 if (ip == global_params.switchboard[dir]->sip_ip) {
01889 global_params.aggregation[dir] = NULL;
01890 return 1;
01891 }
01892 }
01893 return -1;
01894 case PAR_AGGREGATION_A:
01895 case PAR_AGGREGATION_B:
01896 if (!(global_params.aggregation[dir] = find_aggregation(&u.s, NULL)))
01897 return -1;
01898 break;
01899 case PAR_AGGREGATION_BY_SIP_IP_A:
01900 case PAR_AGGREGATION_BY_SIP_IP_B:
01901 ip = s2ip4(&u.s);
01902 for (global_params.aggregation[dir] = aggregations;
01903 global_params.aggregation[dir];
01904 global_params.aggregation[dir] = global_params.aggregation[dir]->next) {
01905
01906 if (ip == global_params.aggregation[dir]->sip_ip) {
01907 global_params.switchboard[dir] = NULL;
01908 return 1;
01909 }
01910 }
01911 return -1;
01912 case PAR_THROTTLE_MARK:
01913 global_params.throttle.mark = u.i;
01914 break;
01915 case PAR_THROTTLE_RTP_MAX_BYTES:
01916 case PAR_THROTTLE_RTCP_MAX_BYTES:
01917 global_params.throttle.bandwidth[param_list[idx].id==PAR_THROTTLE_RTCP_MAX_BYTES].bytes = u.i;
01918 break;
01919 case PAR_THROTTLE_RTP_MAX_PACKETS:
01920 case PAR_THROTTLE_RTCP_MAX_PACKETS:
01921 global_params.throttle.bandwidth[param_list[idx].id==PAR_THROTTLE_RTCP_MAX_PACKETS].packets = u.i;
01922 break;
01923
01924 case PAR_CODEC_SET:
01925 if (!(global_params.codec_set = find_codec_set(&u.s, NULL)))
01926 return -1;
01927 break;
01928 case PAR_REMOVE_CODEC_MASK:
01929 global_params.remove_codec_mask = u.i;
01930 break;
01931
01932 case PAR_OLINE_USER: {
01933 static char buf[30];
01934 if (u.s.len > sizeof(buf)) {
01935 return -1;
01936 }
01937 global_params.oline_user.len = u.s.len;
01938 if (u.s.len) {
01939 memcpy(buf, u.s.s, u.s.len);
01940 global_params.oline_user.s = buf;
01941 }
01942 break;
01943 }
01944 case PAR_OLINE_ADDR: {
01945 static char buf[30];
01946 if (u.s.len > sizeof(buf)) {
01947 return -1;
01948 }
01949 global_params.oline_addr.len = u.s.len;
01950 if (u.s.len) {
01951 memcpy(buf, u.s.s, u.s.len);
01952 global_params.oline_addr.s = buf;
01953 }
01954 break;
01955 }
01956 case PAR_PROTECTED_SESSION_IDS:
01957 memset(&global_params.protected_sess, 0, sizeof(global_params.protected_sess));
01958 if (!u.s.len) break;
01959 if (unserialize_ipt_session(&u.s, &global_params.protected_sess) < 0) {
01960 return -1;
01961 }
01962 if (!global_params.protected_sess.session_count) {
01963 global_params.protected_sess.switchboard = NULL;
01964 }
01965 break;
01966
01967 default:
01968 ;
01969 }
01970 return 1;
01971 }
01972
01973
01974 static int sel_rtpproxy(str* res, select_t* s, struct sip_msg* msg) {
01975 union {int i; str s;} u;
01976 int dir, idx;
01977 u.s.len = 0;
01978 if (msg == NULL && res == NULL) {
01979
01980 int idx;
01981 idx = param2idx(&s->params[1].v.s, PAR_READ);
01982 if (idx < 0) {
01983 return -1;
01984 }
01985 s->params[1].v.i = idx;
01986 s->params[1].type = SEL_PARAM_DIV;
01987 return 1;
01988 }
01989 idx = s->params[1].v.i;
01990 dir = (param_list[idx].flags & PAR_DIR) != 0;
01991 switch (param_list[idx].id) {
01992 case PAR_EXPIRATION_TIMEOUT:
01993 u.i = global_params.expiration_timeout;
01994 break;
01995 case PAR_TTL:
01996 u.i = global_params.ttl;
01997 break;
01998 case PAR_LEARNING_TIMEOUT:
01999 u.i = global_params.learning_timeout;
02000 break;
02001 case PAR_ALWAYS_LEARN:
02002 u.i = global_params.always_learn;
02003 break;
02004 case PAR_SWITCHBOARD_A:
02005 case PAR_SWITCHBOARD_B:
02006 if (global_params.switchboard[dir])
02007 u.s = global_params.switchboard[dir]->name;
02008 break;
02009 case PAR_AGGREGATION_A:
02010 case PAR_AGGREGATION_B:
02011 if (global_params.aggregation[dir])
02012 u.s = global_params.aggregation[dir]->name;
02013 break;
02014 case PAR_SDP_IP:
02015 u.s = global_params.sdp_ip;
02016 break;
02017 case PAR_ACTIVE_MEDIA_NUM: {
02018 int i;
02019 if (check_parse_sdp_content(msg, &global_sdp_sess) < 0) return -1;
02020 u.i = 0;
02021 for (i = 0; i < global_sdp_sess.media_count; i++) {
02022 if (global_sdp_sess.media[i].active) {
02023 u.i++;
02024 }
02025 }
02026 break;
02027 }
02028 case PAR_OLINE_USER:
02029 if (check_parse_sdp_content(msg, &global_sdp_sess) < 0) return -1;
02030 u.s = global_sdp_sess.oline_user_s;
02031 break;
02032 case PAR_OLINE_ADDR:
02033 if (check_parse_sdp_content(msg, &global_sdp_sess) < 0) return -1;
02034 u.s = global_sdp_sess.oline_addr_s;
02035 break;
02036 case PAR_SESSION_IDS:
02037 u.s = global_params.session_ids;
02038 break;
02039 case PAR_THROTTLE_MARK:
02040 u.i = global_params.throttle.mark;
02041 break;
02042 case PAR_THROTTLE_RTP_MAX_BYTES:
02043 case PAR_THROTTLE_RTCP_MAX_BYTES:
02044 u.i = global_params.throttle.bandwidth[param_list[idx].id==PAR_THROTTLE_RTCP_MAX_BYTES].bytes;
02045 break;
02046 case PAR_THROTTLE_RTP_MAX_PACKETS:
02047 case PAR_THROTTLE_RTCP_MAX_PACKETS:
02048 u.i = global_params.throttle.bandwidth[param_list[idx].id==PAR_THROTTLE_RTCP_MAX_PACKETS].packets;
02049 break;
02050 case PAR_CODEC_SET:
02051 if (global_params.codec_set)
02052 u.s = global_params.codec_set->name;
02053 break;
02054 case PAR_AUTH_RIGHTS:
02055 u.i = global_params.auth_rights;
02056 break;
02057 case PAR_REMOVE_CODEC_MASK:
02058 u.i = global_params.remove_codec_mask;
02059 break;
02060 default:
02061 ;
02062 }
02063 if (param_list[idx].flags & PAR_STR) {
02064 if (!u.s.len) return 1;
02065 *res = u.s;
02066 }
02067 else {
02068 return uint_to_static_buffer(res, u.i);
02069 }
02070 return 0;
02071 }
02072
02073 select_row_t sel_declaration[] = {
02074 { NULL, SEL_PARAM_STR, STR_STATIC_INIT(MODULE_NAME), sel_rtpproxy, CONSUME_NEXT_STR | FIXUP_CALL },
02075 { NULL, SEL_PARAM_INT, STR_NULL, NULL, 0}
02076 };
02077
02078 static int mod_pre_script_cb(struct sip_msg *msg, unsigned int flags, void *param) {
02079 memset(&global_params, 0, sizeof(global_params));
02080 global_params.always_learn = -1;
02081 global_params.ttl = -1;
02082 sdp_parsed = 999;
02083 return 1;
02084 }
02085
02086 static struct {
02087 enum {iptrtpproxy_default=0x01, iptrtpproxy_switchboard=0x02, iptrtpproxy_host=0x04} flag;
02088 str name;
02089 struct {
02090 struct {
02091 struct xt_rtpproxy_switchboard_id addr;
02092 str host;
02093 } switchboard;
02094 struct xt_rtpproxy_connection_rpc_params host;
02095 } dflt, parsed;
02096
02097 } parse_config_vals;
02098
02099 static int cfg_parse_addr(void* param, cfg_parser_t* st, unsigned int flags) {
02100 str val;
02101 char buff[50];
02102 val.s = buff;
02103 val.len = sizeof(buff)-1;
02104 if (cfg_parse_str(&val, st, CFG_EXTENDED_ALPHA|CFG_STR_STATIC) < 0) return -1;
02105 *(uint32_t*)param = s2ip4(&val);
02106 if (*(uint32_t*)param == 0) {
02107 ERR(MODULE_NAME": parse_addr: bad ip address '%.*s'\n", STR_FMT(&val));
02108 return -1;
02109 }
02110 return 0;
02111 }
02112
02113 static int cfg_parse_uint16(void* param, cfg_parser_t* st, unsigned int flags) {
02114 int val;
02115 if (cfg_parse_int(&val, st, 0) < 0)
02116 return -1;
02117 *(uint16_t *) param = val;
02118 return 0;
02119 }
02120
02121 static int cfg_parse_default(void* param, cfg_parser_t* st, unsigned int flags) {
02122 int ret;
02123 cfg_token_t t;
02124 str val, tok;
02125 cfg_option_t* opt;
02126 char buf[MAX_TOKEN_LEN];
02127
02128 tok.s = buf;
02129
02130 if (st->cur_opt->val.len >= sizeof(buf)-1) goto skip;
02131 memcpy(tok.s, st->cur_opt->val.s, st->cur_opt->val.len);
02132 tok.len = st->cur_opt->val.len;
02133
02134
02135 while (1) {
02136 ret = cfg_get_token(&t, st, 0);
02137 if (ret < 0) return ret;
02138 if (ret > 0) return 0;
02139 if (t.type == '=')
02140 break;
02141 if (tok.len+t.val.len >= sizeof(buf)-1) goto skip;
02142 memcpy(tok.s+tok.len, t.val.s, t.val.len);
02143 tok.len += t.val.len;
02144
02145 }
02146 tok.s[tok.len] = '\0';
02147 if ((opt = cfg_lookup_token(st->options+1, &tok)) && ((opt->flags & CFG_DEFAULT)== 0)) {
02148 st->cur_opt = &t;
02149 if (opt->f(opt->param, st, opt->flags) < 0) return -1;
02150 return 0;
02151 }
02152 skip:
02153 if (cfg_parse_str(&val, st, CFG_EXTENDED_ALPHA) < 0) return -1;
02154 return 0;
02155 }
02156
02157 static int safe_parsed_values() {
02158 #define PROC_DEFAULT(_f_, _def_) \
02159 if (!parse_config_vals.parsed._f_) {\
02160 parse_config_vals.parsed._f_ = parse_config_vals.dflt._f_?parse_config_vals.dflt._f_:_def_; \
02161 }
02162
02163 if (parse_config_vals.flag & iptrtpproxy_default) {
02164 if (parse_config_vals.flag & iptrtpproxy_switchboard)
02165 parse_config_vals.dflt.switchboard = parse_config_vals.parsed.switchboard;
02166 else if (parse_config_vals.flag & iptrtpproxy_host)
02167 parse_config_vals.dflt.host = parse_config_vals.parsed.host;
02168
02169 } else if (parse_config_vals.flag) {
02170 int fl, max_len, i;
02171 struct switchboard_item **prev_si = NULL;
02172 struct host_item **prev_hi = NULL;
02173 char *s;
02174 if (parse_config_vals.flag & iptrtpproxy_switchboard) {
02175 fl = find_switchboard(&parse_config_vals.name, &prev_si) != NULL;
02176 s = "switchboard";
02177 max_len = MAX_SWITCHBOARD_NAME_LEN;
02178 }
02179 else {
02180 struct host_item *p;
02181 p = find_host(&parse_config_vals.name, &prev_hi);
02182 fl = p != NULL;
02183 s = "host";
02184 max_len = HOST_NAME_MAX;
02185 if (p && p->local) {
02186 pkg_free(parse_config_vals.name.s);
02187 goto local;
02188 }
02189 }
02190 if (fl) {
02191 ERR(MODULE_NAME": safe_parsed_values: %s name '%.*s' already declared\n", s, STR_FMT(&parse_config_vals.name));
02192 return -1;
02193 }
02194 for (i=0; i<parse_config_vals.name.len; i++) {
02195 if (!is_alpha(parse_config_vals.name.s[i])) {
02196 ERR(MODULE_NAME": safe_parsed_values: bad %s name '%.*s'\n", s, STR_FMT(&parse_config_vals.name));
02197 return -1;
02198 }
02199 }
02200 if (parse_config_vals.name.len > max_len) {
02201 ERR(MODULE_NAME": safe_parsed_values: %s name '%.*s' is too long (%d>%d)\n", s, STR_FMT(&parse_config_vals.name), parse_config_vals.name.len, max_len);
02202 return -1;
02203 }
02204
02205 if (parse_config_vals.flag & iptrtpproxy_switchboard) {
02206 struct switchboard_item *si;
02207 si = pkg_malloc(sizeof(*si));
02208 if (!si) goto out_of_mem;
02209 memset(si, 0, sizeof(*si));
02210 si->name = parse_config_vals.name;
02211 si->next = (*prev_si);
02212 (*prev_si) = si;
02213 PROC_DEFAULT(switchboard.addr.ip, 0);
02214 PROC_DEFAULT(switchboard.addr.port, 0);
02215 if (parse_config_vals.parsed.switchboard.host.len) {
02216 si->hostname = parse_config_vals.parsed.switchboard.host;
02217 }
02218 else {
02219 si->hostname = parse_config_vals.dflt.switchboard.host;
02220 }
02221 if (!si->hostname.len) {
02222 si->hostname.s = iptrtpproxy_cfg_hostname;
02223 si->hostname.len = strlen(si->hostname.s);
02224 }
02225 si->switchboard_addr = parse_config_vals.parsed.switchboard.addr;
02226 }
02227 else {
02228 struct host_item *hi;
02229 hi = pkg_malloc(sizeof(*hi));
02230 if (!hi) goto out_of_mem;
02231 memset(hi, 0, sizeof(*hi));
02232 hi->name = parse_config_vals.name;
02233 hi->next = (*prev_hi);
02234 (*prev_hi) = hi;
02235 PROC_DEFAULT(host.addr, 0);
02236 PROC_DEFAULT(host.port, 0);
02237 PROC_DEFAULT(host.request_size, XT_RTPPROXY_RPC_DEFAULT_REQUEST_SIZE);
02238 PROC_DEFAULT(host.reply_size, XT_RTPPROXY_RPC_DEFAULT_REPLY_SIZE);
02239 PROC_DEFAULT(host.total_timeout, XT_RTPPROXY_RPC_DEFAULT_TOTAL_TIMEOUT);
02240 PROC_DEFAULT(host.udp_retry_timeout, XT_RTPPROXY_RPC_DEFAULT_UDP_REPLY_TIMEOUT);
02241 hi->rpc_params = parse_config_vals.parsed.host;
02242 }
02243 }
02244 local:
02245 memset(&parse_config_vals.parsed, 0, sizeof(parse_config_vals.parsed));
02246 memset(&parse_config_vals.name, 0, sizeof(parse_config_vals.name));
02247 return 0;
02248 out_of_mem:
02249 ERR(MODULE_NAME": safe_parsed_values: not enough pkg memory\n");
02250 return -1;
02251 }
02252
02253 static cfg_option_t section_switchboard_options[] = {
02254
02255 {NULL, .flags = CFG_DEFAULT, .f = cfg_parse_default},
02256
02257 {"addr", .f = cfg_parse_addr, .flags = CFG_CASE_SENSITIVE, .param = &parse_config_vals.parsed.switchboard.addr.ip},
02258 {"port", .f = cfg_parse_uint16, .flags = CFG_CASE_SENSITIVE, .param = &parse_config_vals.parsed.switchboard.addr.port},
02259 {"host", .f = cfg_parse_str, .flags = CFG_CASE_SENSITIVE|CFG_STR_PKGMEM, .param = &parse_config_vals.parsed.switchboard.host},
02260 {NULL, .flags = CFG_DEFAULT, .f = cfg_parse_default}
02261 };
02262
02263 static cfg_option_t protos[] = {
02264 {"udp", .param = &parse_config_vals.parsed.host.proto, .val = xt_rtpproxy_connection_UDP},
02265 {"tcp", .param = &parse_config_vals.parsed.host.proto, .val = xt_rtpproxy_connection_TCP},
02266 {NULL, .flags = 0}
02267 };
02268
02269 static cfg_option_t section_host_options[] = {
02270
02271 {NULL, .flags = CFG_DEFAULT, .f = cfg_parse_default},
02272
02273 {"rpc-addr", .f = cfg_parse_addr, .flags = CFG_CASE_SENSITIVE, .param = &parse_config_vals.parsed.host.addr},
02274 {"rpc-port", .f = cfg_parse_uint16, .flags = CFG_CASE_SENSITIVE, .param = &parse_config_vals.parsed.host.port},
02275 {"rpc-proto", .f = cfg_parse_enum, .flags = CFG_CASE_SENSITIVE, .param = protos},
02276 {"rpc-request-size", .f = cfg_parse_int, .flags = CFG_CASE_SENSITIVE, .param = &parse_config_vals.parsed.host.request_size},
02277 {"rpc-reply-size", .f = cfg_parse_int, .flags = CFG_CASE_SENSITIVE, .param = &parse_config_vals.parsed.host.reply_size},
02278 {"rpc-total-timeout", .f = cfg_parse_int, .flags = CFG_CASE_SENSITIVE, .param = &parse_config_vals.parsed.host.total_timeout},
02279 {"rpc-udp-retry-timeout", .f = cfg_parse_int, .flags = CFG_CASE_SENSITIVE, .param = &parse_config_vals.parsed.host.udp_retry_timeout},
02280 {NULL, .flags = CFG_DEFAULT, .f = cfg_parse_default}
02281 };
02282
02283 static cfg_option_t section_dummy_options[] = {
02284
02285 {NULL, .flags = CFG_DEFAULT, .f = cfg_parse_default},
02286
02287 {NULL, .flags = CFG_DEFAULT, .f = cfg_parse_default}
02288 };
02289
02290 #define DEFAULT_SECTION "default"
02291 #define SWITCHBOARD_PREFIX "switchboard"
02292 #define HOST_PREFIX "host"
02293
02294 static int parse_section_name(void* param, cfg_parser_t* st, unsigned int flags) {
02295 cfg_token_t t;
02296 int ret, fl;
02297 ret = safe_parsed_values();
02298 if (ret != 0) return ret;
02299
02300 cfg_set_options(st, section_dummy_options);
02301
02302 ret = cfg_get_token(&t, st, 0);
02303 if (ret != 0) return ret;
02304 if (t.type != CFG_TOKEN_ALPHA)
02305 goto skip;
02306 if (t.val.len == (sizeof(DEFAULT_SECTION)-1) && strncmp(t.val.s, DEFAULT_SECTION, t.val.len) == 0)
02307 fl = iptrtpproxy_default;
02308 else if (t.val.len == (sizeof(SWITCHBOARD_PREFIX)-1) && strncmp(t.val.s, SWITCHBOARD_PREFIX, t.val.len) == 0) {
02309 fl = iptrtpproxy_switchboard;
02310 } else if (t.val.len == (sizeof(HOST_PREFIX)-1) && strncmp(t.val.s, HOST_PREFIX, t.val.len) == 0) {
02311 fl = iptrtpproxy_host;
02312 }
02313 else
02314 goto skip;
02315 ret = cfg_get_token(&t, st, 0);
02316 if (ret != 0) return ret;
02317 if (t.type != ':')
02318 goto skip;
02319 ret = cfg_parse_section(&parse_config_vals.name, st, CFG_STR_PKGMEM);
02320 if (ret != 0) return ret;
02321
02322 if (fl==iptrtpproxy_default) {
02323 if (parse_config_vals.name.len == (sizeof(SWITCHBOARD_PREFIX)-1) && strncmp(parse_config_vals.name.s, SWITCHBOARD_PREFIX, parse_config_vals.name.len) == 0) {
02324 fl |= iptrtpproxy_switchboard;
02325 }
02326 else if (parse_config_vals.name.len == (sizeof(HOST_PREFIX)-1) && strncmp(parse_config_vals.name.s, HOST_PREFIX, parse_config_vals.name.len) == 0) {
02327 fl |= iptrtpproxy_host;
02328 }
02329 else {
02330 goto skip;
02331 }
02332 if (parse_config_vals.name.s) {
02333 pkg_free(parse_config_vals.name.s);
02334 parse_config_vals.name.s = NULL;
02335 }
02336 }
02337 cfg_set_options(st, section_dummy_options);
02338 if (fl) {
02339 if (fl & iptrtpproxy_switchboard) {
02340 cfg_set_options(st, section_switchboard_options);
02341 } else if (fl & iptrtpproxy_host) {
02342 cfg_set_options(st, section_host_options);
02343 }
02344 parse_config_vals.flag = fl;
02345 }
02346 return 0;
02347 skip:
02348 while (t.type != ']') {
02349 ret = cfg_get_token(&t, st, 0);
02350 if (ret != 0) return ret;
02351 }
02352 return cfg_eat_eol(st, 0);
02353 }
02354
02355 static int parse_iptrtpproxy_cfg() {
02356 cfg_parser_t* parser = NULL;
02357 static char buf[HOST_NAME_MAX+1];
02358 struct switchboard_item *si;
02359 if (!iptrtpproxy_cfg_hostname || !strlen(iptrtpproxy_cfg_hostname)) {
02360 if (gethostname(buf, sizeof(buf)-1) < 0) {
02361 ERR(MODULE_NAME"parse_iptrtpproxy_cfg: gethostname error\n");
02362 return E_CFG;
02363 }
02364 iptrtpproxy_cfg_hostname = buf;
02365 }
02366 hosts = pkg_malloc(sizeof(*hosts));
02367 if (!hosts) return -1;
02368 memset(hosts, 0, sizeof(*hosts));
02369 hosts->name.s = iptrtpproxy_cfg_hostname;
02370 hosts->name.len = strlen(hosts->name.s);
02371 hosts->local = 1;
02372
02373 if ((parser = cfg_parser_init(0, &iptrtpproxy_cfg_filename)) == NULL) {
02374 ERR(MODULE_NAME"parse_iptrtpproxy_cfg: Error while initializing configuration file parser.\n");
02375 return -1;
02376 }
02377 cfg_section_parser(parser, parse_section_name, NULL);
02378 memset(&parse_config_vals, 0, sizeof(parse_config_vals));
02379 if (sr_cfg_parse(parser)) {
02380 return -1;
02381 }
02382 cfg_parser_close(parser);
02383 if (safe_parsed_values() < 0) {
02384 return -1;
02385 }
02386 for (si = switchboards; si; si = si->next) {
02387 si->host = find_host(&si->hostname, NULL);
02388 if (!si->host) {
02389 ERR(MODULE_NAME"parse_iptrtpproxy_cfg: host '%.*s' not found.\n", STR_FMT(&si->hostname));
02390 return -1;
02391 }
02392 si->sip_ip = si->switchboard_addr.ip;
02393 }
02394 return 0;
02395 }
02396
02397 static struct {
02398 char *name;
02399 int payload_type;
02400 unsigned int media_type;
02401 int clock_rate;
02402 int channels;
02403 } def_codecs [] = {
02404 {"PCMU", 0, 1<<sdpmtAudio, 8000, 1},
02405 {"GSM", 3, 1<<sdpmtAudio, 8000, 1},
02406 {"G723", 4, 1<<sdpmtAudio, 8000, 1},
02407 {"DVI4", 5, 1<<sdpmtAudio, 8000, 1},
02408 {"DVI4", 6, 1<<sdpmtAudio, 16000, 1},
02409 {"LPC", 7, 1<<sdpmtAudio, 8000, 1},
02410 {"PCMA", 8, 1<<sdpmtAudio, 8000, 1},
02411 {"G722", 9, 1<<sdpmtAudio, 8000, 1},
02412 {"L16", 10, 1<<sdpmtAudio, 44100, 2},
02413 {"L16", 11, 1<<sdpmtAudio, 44100, 1},
02414 {"QCELP", 12, 1<<sdpmtAudio, 8000, 1},
02415 {"CN", 13, 1<<sdpmtAudio, 8000, 1},
02416 {"MPA", 14, 1<<sdpmtAudio, 90000},
02417 {"G728", 15, 1<<sdpmtAudio, 8000, 1},
02418 {"DVI4", 16, 1<<sdpmtAudio, 11025, 1},
02419 {"DVI4", 17, 1<<sdpmtAudio, 22050, 1},
02420 {"G729", 18, 1<<sdpmtAudio, 8000, 1},
02421 {"CelB", 25, 1<<sdpmtVideo, 90000},
02422 {"JPEG", 26, 1<<sdpmtVideo, 90000},
02423 {"nv", 28, 1<<sdpmtVideo, 90000},
02424 {"H261", 31, 1<<sdpmtVideo, 90000},
02425 {"MPV", 32, 1<<sdpmtVideo, 90000},
02426 {"MP2T", 33, 1<<sdpmtAudio | 1<<sdpmtVideo, 90000},
02427 {"H263", 34, 1<<sdpmtVideo, 90000},
02428 {"telephone-event", -1, 1<<sdpmtAudio},
02429 {"tone", -1, 1<<sdpmtAudio},
02430 {"red", -1, 1<<sdpmtAudio|1<<sdpmtText},
02431 {"rtx", -1, 1<<sdpmtAudio|1<<sdpmtVideo|1<<sdpmtApplication|1<<sdpmtText},
02432 {"parityfec", -1, 1<<sdpmtAudio|1<<sdpmtVideo|1<<sdpmtApplication|1<<sdpmtText},
02433 {"t140c", -1, 1<<sdpmtAudio},
02434 {"t38", -1, 1<<sdpmtAudio},
02435 {"AMR", -1, 1<<sdpmtAudio, 8000},
02436 {"AMR-WB", -1, 1<<sdpmtAudio, 16000},
02437 {"L8", -1, 1<<sdpmtAudio},
02438 {"L20", -1, 1<<sdpmtAudio},
02439 {"L24", -1, 1<<sdpmtAudio},
02440 {"DAT12", -1, 1<<sdpmtAudio},
02441
02442 {"raw", -1, 1<<sdpmtVideo},
02443 {"pointer", -1, 1<<sdpmtVideo},
02444
02445
02446 {NULL}
02447 };
02448
02449 static int declare_def_codecs() {
02450 int codec_id, i;
02451 i = 0;
02452 while (def_codecs[i].name) {
02453 str s;
02454 s.s = def_codecs[i].name;
02455 s.len = strlen(s.s);
02456 codec_id = register_codec(&s);
02457 if (codec_id < 0) return codec_id;
02458 i++;
02459 }
02460 return 0;
02461 }
02462
02463
02464 static int mod_init(void) {
02465 struct switchboard_item *si;
02466 struct aggregation_item *ai;
02467 struct host_item *hi;
02468 struct codec_set_item *ci;
02469 int i;
02470 if (iptrtpproxy_cfg_flag <= 1) {
02471 if (parse_iptrtpproxy_cfg() < 0)
02472 return E_CFG;
02473 }
02474
02475 for (si = switchboards; si; si=si->next) {
02476 str ips[2];
02477 char buf1[17];
02478 si->stat = shm_malloc(sizeof(*si->stat));
02479 if (!si->stat) return E_OUT_OF_MEM;
02480 memset(si->stat, 0, sizeof(*si->stat));
02481
02482 ip42s(si->switchboard_addr.ip, ips+0);
02483 strncpy(buf1, ips[0].s, sizeof(buf1)-1);
02484 ips[0].s = buf1;
02485 ip42s(si->sip_ip, ips+1);
02486
02487 INFO(MODULE_NAME": mod_init: switchboard_name=%.*s;addr=%.*s;port=%d;sip-addr=%.*s;hostname=%.*s\n",
02488 STR_FMT(&si->name),
02489 STR_FMT(ips+0),
02490 si->switchboard_addr.port,
02491 STR_FMT(ips+1),
02492 STR_FMT(&si->hostname)
02493 );
02494
02495 }
02496 for (ai = aggregations; ai; ai=ai->next) {
02497 str ips[1];
02498 ip42s(ai->sip_ip, ips+0);
02499 INFO(MODULE_NAME": mod_init: aggregation '%.*s';sip-addr=%.*s\n",
02500 STR_FMT(&ai->name),
02501 STR_FMT(ips+0)
02502 );
02503 for (i=0; i<ai->switchboard_count; i++) {
02504 ERR(MODULE_NAME": mod_init: '%.*s'\n", STR_FMT(&(*ai->switchboards)[i]->name));
02505 }
02506 }
02507 for (hi = hosts; hi; hi=hi->next) {
02508 str ips;
02509 hi->stat = shm_malloc(sizeof(*hi->stat));
02510 if (!hi->stat) return E_OUT_OF_MEM;
02511 memset(hi->stat, 0, sizeof(*hi->stat));
02512
02513 ip42s(hi->rpc_params.addr, &ips);
02514 INFO(MODULE_NAME": mod_init: host_name=%.*s;rpc-addr=%.*s;rpc-port=%d;rpc-proto=%d,request-size=%d,reply-size=%d,total-timeout=%d,udp-retry-timeout=%d\n",
02515 STR_FMT(&hi->name),
02516 STR_FMT(&ips),
02517 hi->rpc_params.port,
02518 hi->rpc_params.proto,
02519 hi->rpc_params.request_size,
02520 hi->rpc_params.reply_size,
02521 hi->rpc_params.total_timeout,
02522 hi->rpc_params.udp_retry_timeout
02523 );
02524 }
02525
02526 if (!reg_codecs) {
02527 int r;
02528 if ((r = declare_def_codecs()) < 0) {
02529 return r;
02530 }
02531 }
02532 memset(&fixed_payload_types, 0, sizeof(fixed_payload_types));
02533 i = 0;
02534 while (def_codecs[i].name && def_codecs[i].payload_type >= 0) {
02535 str s;
02536 int codec_id;
02537 s.s = def_codecs[i].name;
02538 s.len = strlen(s.s);
02539 codec_id = name2codec_id(&s, NULL);
02540 if (!codec_id) {
02541 BUG(MODULE_NAME": mod_init: def.codec '%s' not found\n", s.s);
02542 return -1;
02543 }
02544 fixed_payload_types[def_codecs[i].payload_type].codec_id = codec_id;
02545 i++;
02546 }
02547 #if 0
02548 for (i=0; i<MAX_FIXED_PAYLOAD_TYPES; i++) {
02549 if (fixed_payload_types[i].codec_id) {
02550 INFO(MODULE_NAME": mod_init: payload_type=%d, codec_name='%.*s'\n", i, STR_FMT(&(*reg_codecs)[fixed_payload_types[i].codec_id-1].name));
02551 }
02552 }
02553 for (i=0; i<reg_codec_count; i++) {
02554 INFO(MODULE_NAME": mod_init: codec_id=%d, codec_name='%.*s'\n", i+1, STR_FMT(&(*reg_codecs)[i].name));
02555 }
02556 #endif
02557 for (ci = codec_sets; ci; ci=ci->next) {
02558 int media_type;
02559 INFO(MODULE_NAME": mod_init: codec_set='%.*s'\n", STR_FMT(&ci->name));
02560 for (media_type=0; media_type<NUM_MEDIA_TYPES; media_type++) {
02561 INFO(MODULE_NAME": mod_init: media_type='%.*s';max_streams=%d;rtp_bytes=%d;rtcp_bytes=%d;rtp_packets=%d;rtcp_packets=%d\n",
02562 STR_FMT(sdp_media_types_str+media_type),
02563 ci->media_types[media_type].throttle.max_streams,
02564 ci->media_types[media_type].throttle.bandwidth[0].bytes,
02565 ci->media_types[media_type].throttle.bandwidth[1].bytes,
02566 ci->media_types[media_type].throttle.bandwidth[0].packets,
02567 ci->media_types[media_type].throttle.bandwidth[1].packets
02568 );
02569 if (ci->media_types[media_type].throttle.max_streams != 0) {
02570 for (i=0; i<reg_codec_count; i++) {
02571 if ((*ci->media_types[media_type].codec_rights)[i] > 0) {
02572 if (i > 0)
02573 INFO(MODULE_NAME": mod_init: codec='%.*s', right=%d\n", STR_FMT(&(*reg_codecs)[i-1].name), (*ci->media_types[media_type].codec_rights)[i]);
02574 else
02575 INFO(MODULE_NAME": mod_init: codec='?', right=%d\n", (*ci->media_types[media_type].codec_rights)[i]);
02576 }
02577 }
02578 }
02579 }
02580 }
02581
02582 register_script_cb(mod_pre_script_cb, REQUEST_CB | ONREPLY_CB| PRE_SCRIPT_CB, 0);
02583 register_select_table(sel_declaration);
02584 return 0;
02585 }
02586
02587 static void mod_cleanup(void) {
02588 struct host_item *hi;
02589 struct switchboard_item *si;
02590 for (si = switchboards; si; si = si->next) {
02591 if (si->stat) {
02592 shm_free(si->stat);
02593 si->stat = NULL;
02594 }
02595 }
02596 for (hi = hosts; hi; hi = hi->next) {
02597 if (hi->handle_is_opened) {
02598 xt_RTPPROXY_close(&hi->handle);
02599 hi->handle_is_opened = 0;
02600 }
02601 if (hi->stat) {
02602 shm_free(hi->stat);
02603 hi->stat = NULL;
02604 }
02605 }
02606 }
02607
02608 static int child_init(int rank) {
02609
02610 return 0;
02611 }
02612
02613
02614 #define eat_spaces(_p) \
02615 while( *(_p)==' ' || *(_p)=='\t' ){\
02616 (_p)++;}
02617
02618
02619 static int declare_config(modparam_t type, void* val) {
02620 if (!val) return 0;
02621 if (iptrtpproxy_cfg_flag <= 1) {
02622 iptrtpproxy_cfg_flag = 2;
02623 iptrtpproxy_cfg_filename = * (str*) val;
02624 if (parse_iptrtpproxy_cfg() == 0)
02625 return 0;
02626 }
02627 else {
02628 switch (iptrtpproxy_cfg_flag) {
02629 case 2:
02630 ERR(MODULE_NAME": declare_config: 'config' param may be used only once\n");
02631 break;
02632 case 3:
02633 ERR(MODULE_NAME": declare_config: 'config' param may not be used after 'switchboard'\n");
02634 break;
02635 default:
02636 BUG(MODULE_NAME": declare_config: unexpected 'iptrtpproxy_cfg_flag' value %d\n", iptrtpproxy_cfg_flag);
02637 }
02638 }
02639 return E_CFG;
02640 }
02641
02642 static int declare_hostname(modparam_t type, void* val) {
02643 if (!val) return 0;
02644 if (iptrtpproxy_cfg_flag == 0) {
02645 iptrtpproxy_cfg_hostname = (char*) val;
02646 return 0;
02647 }
02648 else {
02649 switch (iptrtpproxy_cfg_flag) {
02650 case 1:
02651 ERR(MODULE_NAME": declare_hostname: 'hostname' param may be used only once\n");
02652 break;
02653 case 2:
02654 case 3:
02655 ERR(MODULE_NAME": declare_hostname: 'hostname' param may not be used after 'switchboard' or 'config'\n");
02656 break;
02657 default:
02658 BUG(MODULE_NAME": declare_hostname: unexpected 'iptrtpproxy_cfg_flag' value %d\n", iptrtpproxy_cfg_flag);
02659 }
02660 }
02661 return E_CFG;
02662 }
02663
02664 struct parse_param_item {
02665 char *name;
02666 unsigned int id;
02667 };
02668
02669
02670 static int parse_next_param(char **s, struct parse_param_item (*params)[], str *val) {
02671 str p;
02672 int i;
02673 char *c;
02674
02675 eat_spaces(*s);
02676 c = *s;
02677 while ( is_alpha(*c) ) {
02678 c++;
02679 }
02680 if (c == *s) {
02681 ERR(MODULE_NAME": parse_next_param: param name expected near '%s'\n", *s);
02682 return -1;
02683 }
02684 p.s = *s;
02685 p.len = c-*s;
02686 eat_spaces(c);
02687 *s = c;
02688 if (*c != '=') {
02689 ERR(MODULE_NAME": parse_next_param: equal char expected near '%s'\n", *s);
02690 return -1;
02691 }
02692 c++;
02693 eat_spaces(c);
02694 *s = c;
02695 while (*c && *c != ';') c++;
02696 val->s = *s;
02697 val->len = c-*s;
02698 while (val->len > 0 && val->s[val->len-1]<=' ') val->len--;
02699 if (*c) c++;
02700 eat_spaces(c);
02701 *s = c;
02702 for (i=0; (*params)[i].name; i++) {
02703 if (strlen((*params)[i].name)==p.len && strncasecmp((*params)[i].name, p.s, p.len) == 0) {
02704 return i;
02705 }
02706 }
02707 ERR(MODULE_NAME": parse_next_param: unknown param name '%.*s'\n", STR_FMT(&p));
02708 return -1;
02709 }
02710
02711 static int declare_switchboard_param(modparam_t type, void* val) {
02712
02713 char *s;
02714 int all_flag;
02715 struct switchboard_item *si = NULL;
02716 enum param_id {
02717 par_Name = 0x000001,
02718 par_Aggregation = 0x000002,
02719 par_SipAddr = 0x000004
02720 };
02721 static struct parse_param_item params[] = {
02722 {.name = "name", .id = par_Name},
02723 {.name = "sip-addr", .id = par_SipAddr},
02724 {.name = "aggregation", .id = par_Aggregation},
02725
02726 {.name = 0, .id = 0}
02727 };
02728
02729 if (!val) return 0;
02730 if (iptrtpproxy_cfg_flag <= 1) {
02731 iptrtpproxy_cfg_flag = 3;
02732 if (parse_iptrtpproxy_cfg() < 0)
02733 return E_CFG;
02734 }
02735
02736 s = val;
02737 all_flag = -1;
02738
02739 eat_spaces(s);
02740 if (!*s) return 0;
02741
02742 while (*s) {
02743 str val;
02744 int idx;
02745
02746 idx = parse_next_param(&s, ¶ms, &val);
02747 if (idx < 0) goto err_E_CFG;
02748
02749 if (all_flag >= 0 && params[idx].id == par_Name) {
02750 ERR(MODULE_NAME": declare_switchboard_param: name must be the first param\n");
02751 goto err_E_CFG;
02752 }
02753 if (params[idx].id == par_Name) {
02754 all_flag = 0;
02755 si = find_switchboard(&val, NULL);
02756 if (!si) {
02757 if (val.len == 1 && val.s[0] == '*')
02758 all_flag = 1;
02759 else {
02760 ERR(MODULE_NAME": declare_switchboard_param: switchboard '%.*s' not found\n", STR_FMT(&val));
02761 goto err_E_CFG;
02762 }
02763 }
02764 }
02765 else {
02766 if (all_flag)
02767 si = switchboards;
02768 while (si) {
02769
02770 switch (params[idx].id) {
02771 case par_Name:
02772 break;
02773 case par_Aggregation: {
02774 struct aggregation_item *ai;
02775 struct aggregation_item **prev_ai;
02776 int i;
02777 ai = find_aggregation(&val, &prev_ai);
02778 if (!ai) {
02779 ai = pkg_malloc(sizeof(*ai));
02780 if (!ai) return E_OUT_OF_MEM;
02781 memset(ai, 0, sizeof(*ai));
02782 ai->name = val;
02783 ai->next = (*prev_ai);
02784 (*prev_ai) = ai;
02785 }
02786 for (i=0; i<ai->switchboard_count; i++) {
02787 if ((*ai->switchboards)[i] == si) goto aggr_found;
02788 }
02789 if (!ai->sip_ip) {
02790 ai->sip_ip = si->sip_ip;
02791 }
02792 ai->switchboards = pkg_realloc(ai->switchboards, sizeof((*ai->switchboards)[0])*(ai->switchboard_count+1));
02793 if (!ai->switchboards) return E_OUT_OF_MEM;
02794 (*ai->switchboards)[ai->switchboard_count] = si;
02795 ai->switchboard_count++;
02796 aggr_found:
02797 break;
02798 }
02799 case par_SipAddr:
02800 si->sip_ip = s2ip4(&val);
02801 if (si->sip_ip == 0) {
02802 goto err_E_CFG;
02803 }
02804 break;
02805
02806 default:
02807 BUG(MODULE_NAME": declare_switchboard_param: unknown id '%x\n", idx);
02808 goto err_E_CFG;
02809 }
02810 if (!all_flag) break;
02811 si = si->next;
02812 }
02813 }
02814 }
02815 if (all_flag) {
02816 return 0;
02817 }
02818
02819 switchboard_count++;
02820
02821 return 0;
02822
02823 err_E_CFG:
02824 ERR(MODULE_NAME": declare_switchboard_param(#%d): parse error near \"%s\"\n", switchboard_count, s);
02825
02826 return E_CFG;
02827 }
02828
02829 static int declare_codec(modparam_t type, void* val) {
02830 int r;
02831 str *s;
02832 s = val;
02833 if (!s || !s->len) return 0;
02834 if (codec_sets) {
02835 ERR(MODULE_NAME": declare_codec: codec declaration cannot follow codec set declaration\n");
02836 return E_CFG;
02837 }
02838
02839 if (!reg_codecs) {
02840 int r;
02841 if ((r = declare_def_codecs()) < 0) {
02842 return r;
02843 }
02844 }
02845 r = register_codec(s);
02846 if (r < 0) return r;
02847 return 0;
02848 }
02849
02850 static int declare_codec_set(modparam_t type, void* val) {
02851 char *s;
02852 unsigned int cur_rights = 0;
02853 unsigned int cur_media_type = 0;
02854 struct codec_set_item *ci = NULL;
02855 enum param_id {
02856 par_Name = 0x000001,
02857 par_Rights = 0x000002,
02858 par_Codecs = 0x000003,
02859 par_MediaType = 0x000004,
02860 par_MaxStreams = 0x000005,
02861 par_ThrottleRTPBytes = 0x000100,
02862 par_ThrottleRTCPBytes = 0x000101,
02863 par_ThrottleRTPPackets = 0x000200,
02864 par_ThrottleRTCPPackets = 0x000201
02865 };
02866 static struct parse_param_item params[] = {
02867 {.name = "name", .id = par_Name},
02868 {.name = "media_type", .id = par_MediaType},
02869 {.name = "rights", .id = par_Rights},
02870 {.name = "codecs", .id = par_Codecs},
02871 {.name = "max_streams", .id = par_MaxStreams},
02872 {.name = "rtp_bytes", .id = par_ThrottleRTPBytes},
02873 {.name = "rtcp_bytes", .id = par_ThrottleRTCPBytes},
02874 {.name = "rtp_packets", .id = par_ThrottleRTPPackets},
02875 {.name = "rtcp_packets", .id = par_ThrottleRTCPPackets},
02876
02877 {.name = 0, .id = 0}
02878 };
02879
02880 if (!val) return 0;
02881
02882 if (!reg_codecs) {
02883 int r;
02884 if ((r = declare_def_codecs()) < 0) {
02885 return r;
02886 }
02887 }
02888 s = val;
02889 eat_spaces(s);
02890 if (!*s) return 0;
02891
02892 while (*s) {
02893 str val;
02894 int idx, media_type;
02895 char *p, *pend;
02896 struct codec_set_item **prev_ci;
02897
02898 idx = parse_next_param(&s, ¶ms, &val);
02899 if (idx < 0) return E_CFG;
02900
02901 if (params[idx].id != par_Name && !ci) {
02902 ERR(MODULE_NAME": declare_codec_set: name must be the first param\n");
02903 return E_CFG;
02904 }
02905
02906 switch (params[idx].id) {
02907 case par_Name:
02908 ci = find_codec_set(&val, &prev_ci);
02909 if (!ci) {
02910 int media_type;
02911 ci = pkg_malloc(sizeof(*ci));
02912 if (!ci) return E_OUT_OF_MEM;
02913 memset(ci, 0, sizeof(*ci));
02914 for (media_type=0; media_type<NUM_MEDIA_TYPES; media_type++) {
02915 ci->media_types[media_type].codec_rights = pkg_malloc(sizeof((*ci->media_types[media_type].codec_rights)[0])*(reg_codec_count+1));
02916 if (!ci->media_types[media_type].codec_rights) return E_OUT_OF_MEM;
02917 memset(ci->media_types[media_type].codec_rights, 0, sizeof((*ci->media_types[media_type].codec_rights)[0])*(reg_codec_count+1));
02918 ci->media_types[media_type].throttle.max_streams = -1;
02919 }
02920 ci->name = val;
02921 ci->next = (*prev_ci);
02922 (*prev_ci) = ci;
02923 }
02924 break;
02925 case par_MediaType:
02926 cur_media_type = 0;
02927 if (val.len == 1 && val.s[0] == '*') {
02928 for (media_type=0; media_type<NUM_MEDIA_TYPES; media_type++) {
02929 cur_media_type |= 1 << media_type;
02930 }
02931 }
02932 else {
02933 p = val.s;
02934 pend = p + val.len;
02935 while (p < pend) {
02936 str s2;
02937 s2.s = p;
02938 while (p < pend && is_alpha(*p)) p++;
02939 s2.len = p - s2.s;
02940 cur_media_type |= 1 << name2media_type(&s2);
02941 while (p < pend && !is_alpha(*p)) p++;
02942 }
02943 }
02944 break;
02945 case par_Rights:
02946 val.s[val.len] = '\0';
02947 cur_rights = atol(val.s);
02948 break;
02949 case par_MaxStreams:
02950 val.s[val.len] = '\0';
02951 for (media_type=0; media_type<NUM_MEDIA_TYPES; media_type++) {
02952 if (cur_media_type & (1<<media_type)) {
02953 ci->media_types[media_type].throttle.max_streams = atol(val.s);
02954 }
02955 }
02956 break;
02957 case par_ThrottleRTPBytes:
02958 case par_ThrottleRTCPBytes:
02959 val.s[val.len] = '\0';
02960 for (media_type=0; media_type<NUM_MEDIA_TYPES; media_type++) {
02961 if (cur_media_type & (1<<media_type)) {
02962 ci->media_types[media_type].throttle.bandwidth[params[idx].id&1].bytes = atol(val.s);
02963 }
02964 }
02965 break;
02966 case par_ThrottleRTPPackets:
02967 case par_ThrottleRTCPPackets:
02968 val.s[val.len] = '\0';
02969 for (media_type=0; media_type<NUM_MEDIA_TYPES; media_type++) {
02970 if (cur_media_type & (1<<media_type)) {
02971 ci->media_types[media_type].throttle.bandwidth[params[idx].id&1].packets = atol(val.s);
02972 }
02973 }
02974 break;
02975 case par_Codecs:
02976 if (val.len == 1 && val.s[0] == '*') {
02977 int codec_id;
02978 for (media_type=0; media_type<NUM_MEDIA_TYPES; media_type++) {
02979 if (cur_media_type & (1<<media_type)) {
02980 for (codec_id=0; codec_id<reg_codec_count; codec_id++) {
02981 (*ci->media_types[media_type].codec_rights)[codec_id] = cur_rights;
02982 }
02983 }
02984 }
02985 }
02986 else {
02987 p = val.s;
02988 pend = p + val.len;
02989 while (p < pend) {
02990 str s2;
02991 s2.s = p;
02992 while (p < pend && is_alpha(*p)) p++;
02993 s2.len = p - s2.s;
02994 for (media_type=0; media_type<NUM_MEDIA_TYPES; media_type++) {
02995 if (cur_media_type & (1<<media_type)) {
02996 (*ci->media_types[media_type].codec_rights)[name2codec_id(&s2, NULL)] = cur_rights;
02997 }
02998 }
02999 while (p < pend && !is_alpha(*p)) p++;
03000 }
03001 }
03002 break;
03003 default:
03004 BUG(MODULE_NAME": declare_codec_set: unknown id '%x\n", params[idx].id);
03005 return E_CFG;
03006 }
03007
03008 }
03009
03010 return 0;
03011 }
03012
03013 static cmd_export_t cmds[] = {
03014 {MODULE_NAME "_alloc", rtpproxy_alloc, 1, rtpproxy_alloc_update_fixup, REQUEST_ROUTE | ONREPLY_ROUTE },
03015 {MODULE_NAME "_update", rtpproxy_update, 2, rtpproxy_alloc_update_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE },
03016 {MODULE_NAME "_adjust_timeout", rtpproxy_adjust_timeout, 2, rtpproxy_alloc_update_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE },
03017 {MODULE_NAME "_delete", rtpproxy_delete, 1, rtpproxy_delete_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE },
03018 {MODULE_NAME "_set_param", rtpproxy_set_param, 2, rtpproxy_set_param_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE },
03019 {MODULE_NAME "_authorize_media", rtpproxy_authorize_media, 0, NULL, REQUEST_ROUTE | ONREPLY_ROUTE },
03020
03021 {0, 0, 0, 0, 0}
03022 };
03023
03024 static param_export_t params[] = {
03025 {"config", PARAM_STR | PARAM_USE_FUNC, &declare_config},
03026 {"switchboard", PARAM_STRING | PARAM_USE_FUNC, &declare_switchboard_param},
03027 {"hostname", PARAM_STRING | PARAM_USE_FUNC, &declare_hostname},
03028 {"codec_set", PARAM_STRING | PARAM_USE_FUNC, &declare_codec_set},
03029 {"rpc_heartbeat_timeout", PARAM_INT, &rpc_heartbeat_timeout},
03030 {"declare_codec", PARAM_STR | PARAM_USE_FUNC, &declare_codec},
03031 {0, 0, 0}
03032 };
03033
03034 struct module_exports exports = {
03035 MODULE_NAME,
03036 cmds,
03037 0,
03038 params,
03039 mod_init,
03040 0,
03041 mod_cleanup,
03042 0,
03043 child_init
03044 };
03045
03046
03047 #if !defined(NO_SHARED_LIBS) || NO_SHARED_LIBS==0
03048
03049 #ifdef IPT_RTPPROXY_IPTABLES_API
03050 #include <iptables.h>
03051 #undef IPT_RTPPROXY_IPTABLES_API
03052 #else
03053 #include <xtables.h>
03054 #endif
03055
03056 #include <stdarg.h>
03057
03058 #ifdef xtables_error
03059
03060
03061 struct xtables_globals *xt_params = NULL;
03062 int xtables_check_inverse(const char option[], int *invert, int *optind, int argc, char **argv) {
03063 return FALSE;
03064 }
03065 void xtables_register_target(struct xtables_target *me) {
03066 }
03067
03068 #else
03069
03070 #ifdef _IPTABLES_COMMON_H
03071
03072
03073 #define IPT_RTPPROXY_IPTABLES_API 1
03074 #endif
03075
03076 #ifdef IPT_RTPPROXY_IPTABLES_API
03077 void register_target(struct iptables_target *me) {
03078 }
03079 #else
03080 void xtables_register_target(struct xtables_target *me) {
03081 }
03082 #endif
03083
03084 #if IPT_RTPPROXY_IPTABLES_API
03085 void exit_error(enum exittype status, char *msg, ...)
03086 #else
03087 void exit_error(enum exittype status, const char *msg, ...)
03088 #endif
03089 {
03090 va_list args;
03091
03092 va_start(args, msg);
03093
03094 ERR(MODULE_NAME": %s", msg);
03095 va_end(args);
03096 }
03097
03098 int check_inverse(const char option[], int *invert, int *optind, int argc) {
03099 return 0;
03100 }
03101 #endif
03102
03103 #endif
03104
03105