1 /*
2 * Copyright (C) 2002-2003 Fhg Fokus
3 *
4 * This file is part of SEMS, a free SIP media server.
5 *
6 * SEMS is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version. This program is released under
10 * the GPL with the additional exemption that compiling, linking,
11 * and/or using OpenSSL is allowed.
12 *
13 * For a license to use the SEMS software under conditions
14 * other than those described here, or to purchase support for this
15 * software, please contact iptel.org by e-mail at the following addresses:
16 * info@iptel.org
17 *
18 * SEMS is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 */
27
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/ioctl.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <net/if.h>
34 #include <netdb.h>
35 #include <ifaddrs.h>
36 #include <stdio.h>
37
38 #include "AmConfig.h"
39 #include "sems.h"
40 #include "log.h"
41 #include "AmConfigReader.h"
42 #include "AmUtils.h"
43 #include "AmSessionContainer.h"
44 #include "Am100rel.h"
45 #include "sip/transport.h"
46 #include "sip/resolver.h"
47 #include "sip/ip_util.h"
48 #include "sip/sip_timers.h"
49 #include "sip/raw_sender.h"
50
51 #include <cctype>
52 #include <algorithm>
53
54 using std::make_pair;
55
56 string AmConfig::ConfigurationFile = CONFIG_FILE;
57 string AmConfig::ModConfigPath = MOD_CFG_PATH;
58 string AmConfig::PlugInPath = PLUG_IN_PATH;
59 string AmConfig::LoadPlugins = "";
60 string AmConfig::ExcludePlugins = "";
61 string AmConfig::ExcludePayloads = "";
62 int AmConfig::LogLevel = L_INFO;
63 bool AmConfig::LogStderr = false;
64
65 vector<AmConfig::SIP_interface> AmConfig::SIP_Ifs;
66 vector<AmConfig::RTP_interface> AmConfig::RTP_Ifs;
67 map<string,unsigned short> AmConfig::SIP_If_names;
68 map<string,unsigned short> AmConfig::RTP_If_names;
69 map<string,unsigned short> AmConfig::LocalSIPIP2If;
70 vector<AmConfig::SysIntf> AmConfig::SysIfs;
71
72 #ifndef DISABLE_DAEMON_MODE
73 bool AmConfig::DaemonMode = DEFAULT_DAEMON_MODE;
74 string AmConfig::DaemonPidFile = DEFAULT_DAEMON_PID_FILE;
75 string AmConfig::DaemonUid = DEFAULT_DAEMON_UID;
76 string AmConfig::DaemonGid = DEFAULT_DAEMON_GID;
77 #endif
78
79 unsigned int AmConfig::MaxShutdownTime = DEFAULT_MAX_SHUTDOWN_TIME;
80
81 unsigned int AmConfig::RtpMuxPort = 0;
82 string AmConfig::RtpMuxIP;
83 string AmConfig::RtpMuxOutInterface;
84 unsigned int AmConfig::RtpMuxMTUThreshold = DEFAULT_MUX_MTU_THRESHOLD;
85 unsigned int AmConfig::RtpMuxMaxFrameAgeMs = DEFAULT_MUX_MAX_FRAME_AGE_MS;
86
87 int AmConfig::SessionProcessorThreads = NUM_SESSION_PROCESSORS;
88 int AmConfig::MediaProcessorThreads = NUM_MEDIA_PROCESSORS;
89 int AmConfig::RTPReceiverThreads = NUM_RTP_RECEIVERS;
90 int AmConfig::SIPServerThreads = NUM_SIP_SERVERS;
91 string AmConfig::OutboundProxy = "";
92 bool AmConfig::ForceOutboundProxy = false;
93 string AmConfig::NextHop = "";
94 bool AmConfig::NextHop1stReq = false;
95 bool AmConfig::ProxyStickyAuth = false;
96 bool AmConfig::ForceOutboundIf = false;
97 bool AmConfig::ForceSymmetricRtp = false;
98 bool AmConfig::SipNATHandling = false;
99 bool AmConfig::UseRawSockets = false;
100 bool AmConfig::IgnoreNotifyLowerCSeq = false;
101 string AmConfig::Signature = "";
102 unsigned int AmConfig::MaxForwards = MAX_FORWARDS;
103 bool AmConfig::SingleCodecInOK = false;
104 unsigned int AmConfig::DeadRtpTime = DEAD_RTP_TIME;
105 bool AmConfig::IgnoreRTPXHdrs = false;
106 string AmConfig::Application = "";
107 AmConfig::ApplicationSelector AmConfig::AppSelect = AmConfig::App_SPECIFIED;
108 RegexMappingVector AmConfig::AppMapping;
109 bool AmConfig::LogSessions = false;
110 bool AmConfig::LogEvents = false;
111 int AmConfig::UnhandledReplyLoglevel = 0;
112
113 #ifdef WITH_ZRTP
114 bool AmConfig::enable_zrtp = true;
115 bool AmConfig::enable_zrtp_debuglog = true;
116 #endif
117
118 unsigned int AmConfig::SessionLimit = 0;
119 unsigned int AmConfig::SessionLimitErrCode = 503;
120 string AmConfig::SessionLimitErrReason = "Server overload";
121
122 unsigned int AmConfig::OptionsSessionLimit = 0;
123 unsigned int AmConfig::OptionsSessionLimitErrCode = 503;
124 string AmConfig::OptionsSessionLimitErrReason = "Server overload";
125
126 unsigned int AmConfig::CPSLimitErrCode = 503;
127 string AmConfig::CPSLimitErrReason = "Server overload";
128
129 bool AmConfig::AcceptForkedDialogs = true;
130
131 bool AmConfig::ShutdownMode = false;
132 unsigned int AmConfig::ShutdownModeErrCode = 503;
133 string AmConfig::ShutdownModeErrReason = "Server shutting down";
134
135 string AmConfig::OptionsTranscoderOutStatsHdr; // empty by default
136 string AmConfig::OptionsTranscoderInStatsHdr; // empty by default
137 string AmConfig::TranscoderOutStatsHdr; // empty by default
138 string AmConfig::TranscoderInStatsHdr; // empty by default
139
140 bool AmConfig::DumpConferenceStreams = false;
141 string AmConfig::DumpConferencePath = "/tmp";
142
143 Am100rel::State AmConfig::rel100 = Am100rel::REL100_SUPPORTED;
144
145 vector <string> AmConfig::CodecOrder;
146
147 Dtmf::InbandDetectorType
148 AmConfig::DefaultDTMFDetector = Dtmf::SEMSInternal;
149 bool AmConfig::IgnoreSIGCHLD = true;
150 bool AmConfig::IgnoreSIGPIPE = true;
151
152 #ifdef USE_LIBSAMPLERATE
153 #ifndef USE_INTERNAL_RESAMPLER
154 AmAudio::ResamplingImplementationType AmConfig::ResamplingImplementationType = AmAudio::LIBSAMPLERATE;
155 #endif
156 #endif
157 #ifdef USE_INTERNAL_RESAMPLER
158 AmAudio::ResamplingImplementationType AmConfig::ResamplingImplementationType = AmAudio::INTERNAL_RESAMPLER;
159 #endif
160 #ifndef USE_LIBSAMPLERATE
161 #ifndef USE_INTERNAL_RESAMPLER
162 AmAudio::ResamplingImplementationType AmConfig::ResamplingImplementationType = AmAudio::UNAVAILABLE;
163 #endif
164 #endif
165
166 static int readInterfaces(AmConfigReader& cfg);
167
IP_interface()168 AmConfig::IP_interface::IP_interface()
169 : LocalIP(),
170 PublicIP(),
171 NetIfIdx(0)
172 {
173 }
174
SIP_interface()175 AmConfig::SIP_interface::SIP_interface()
176 : IP_interface(),
177 LocalPort(5060),
178 SigSockOpts(0),
179 tcp_connect_timeout(DEFAULT_TCP_CONNECT_TIMEOUT),
180 tcp_idle_timeout(DEFAULT_TCP_IDLE_TIMEOUT),
181 RtpInterface(-1)
182 {
183 }
184
RTP_interface()185 AmConfig::RTP_interface::RTP_interface()
186 : IP_interface(),
187 RtpLowPort(RTP_LOWPORT),
188 RtpHighPort(RTP_HIGHPORT),
189 next_rtp_port(-1)
190 {
191 }
192
getNextRtpPort()193 int AmConfig::RTP_interface::getNextRtpPort()
194 {
195
196 int port=0;
197
198 next_rtp_port_mut.lock();
199 if(next_rtp_port < 0){
200 next_rtp_port = RtpLowPort;
201 }
202
203 port = next_rtp_port & 0xfffe;
204 next_rtp_port += 2;
205
206 if(next_rtp_port >= RtpHighPort){
207 next_rtp_port = RtpLowPort;
208 }
209 next_rtp_port_mut.unlock();
210
211 return port;
212 }
213
214
setLogLevel(const string & level,bool apply)215 int AmConfig::setLogLevel(const string& level, bool apply)
216 {
217 int n;
218
219 if (sscanf(level.c_str(), "%i", &n) == 1) {
220 if (n < L_ERR || n > L_DBG) {
221 return 0;
222 }
223 } else {
224 string s(level);
225 std::transform(s.begin(), s.end(), s.begin(), ::tolower);
226
227 if (s == "error" || s == "err") {
228 n = L_ERR;
229 } else if (s == "warning" || s == "warn") {
230 n = L_WARN;
231 } else if (s == "info") {
232 n = L_INFO;
233 } else if (s=="debug" || s == "dbg") {
234 n = L_DBG;
235 } else {
236 return 0;
237 }
238 }
239
240 LogLevel = n;
241 if (apply) {
242 log_level = LogLevel;
243 }
244 return 1;
245 }
246
setLogStderr(const string & s,bool apply)247 int AmConfig::setLogStderr(const string& s, bool apply)
248 {
249 if ( strcasecmp(s.c_str(), "yes") == 0 ) {
250 LogStderr = true;
251 } else if ( strcasecmp(s.c_str(), "no") == 0 ) {
252 LogStderr = false;
253 } else {
254 return 0;
255 }
256 if (apply) {
257 log_stderr = LogStderr;
258 }
259 return 1;
260 }
261
262 #ifndef DISABLE_DAEMON_MODE
263
setDaemonMode(const string & fork)264 int AmConfig::setDaemonMode(const string& fork) {
265 if ( strcasecmp(fork.c_str(), "yes") == 0 ) {
266 DaemonMode = true;
267 } else if ( strcasecmp(fork.c_str(), "no") == 0 ) {
268 DaemonMode = false;
269 } else {
270 return 0;
271 }
272 return 1;
273 }
274
275 #endif /* !DISABLE_DAEMON_MODE */
276
setSessionProcessorThreads(const string & th)277 int AmConfig::setSessionProcessorThreads(const string& th) {
278 if(sscanf(th.c_str(),"%u",&SessionProcessorThreads) != 1) {
279 return 0;
280 }
281 return 1;
282 }
283
setMediaProcessorThreads(const string & th)284 int AmConfig::setMediaProcessorThreads(const string& th) {
285 if(sscanf(th.c_str(),"%u",&MediaProcessorThreads) != 1) {
286 return 0;
287 }
288 return 1;
289 }
290
setRTPReceiverThreads(const string & th)291 int AmConfig::setRTPReceiverThreads(const string& th) {
292 if(sscanf(th.c_str(),"%u",&RTPReceiverThreads) != 1) {
293 return 0;
294 }
295 return 1;
296 }
297
setSIPServerThreads(const string & th)298 int AmConfig::setSIPServerThreads(const string& th){
299 if(sscanf(th.c_str(),"%u",&SIPServerThreads) != 1) {
300 return 0;
301 }
302 return 1;
303 }
304
305
setDeadRtpTime(const string & drt)306 int AmConfig::setDeadRtpTime(const string& drt)
307 {
308 if(sscanf(drt.c_str(),"%u",&DeadRtpTime) != 1) {
309 return 0;
310 }
311 return 1;
312 }
313
readConfiguration()314 int AmConfig::readConfiguration()
315 {
316 DBG("Reading configuration...\n");
317
318 AmConfigReader cfg;
319 int ret=0;
320
321 if(cfg.loadFile(AmConfig::ConfigurationFile.c_str())){
322 ERROR("while loading main configuration file\n");
323 return -1;
324 }
325
326 // take values from global configuration file
327 // they will be overwritten by command line args
328
329 // log_level
330 if(cfg.hasParameter("loglevel")){
331 if(!setLogLevel(cfg.getParameter("loglevel"))){
332 ERROR("invalid log level specified\n");
333 ret = -1;
334 }
335 }
336
337 // stderr
338 if(cfg.hasParameter("stderr")){
339 if(!setLogStderr(cfg.getParameter("stderr"), true)){
340 ERROR("invalid stderr value specified,"
341 " valid are only yes or no\n");
342 ret = -1;
343 }
344 }
345
346 #ifndef DISABLE_SYSLOG_LOG
347 if (cfg.hasParameter("syslog_facility")) {
348 set_syslog_facility(cfg.getParameter("syslog_facility").c_str());
349 }
350 #endif
351
352 // plugin_config_path
353 if (cfg.hasParameter("plugin_config_path")) {
354 ModConfigPath = cfg.getParameter("plugin_config_path",ModConfigPath);
355 }
356
357 if(!ModConfigPath.empty() && (ModConfigPath[ModConfigPath.length()-1] != '/'))
358 ModConfigPath += '/';
359
360 // Reads IP and port parameters
361 if(readInterfaces(cfg) == -1)
362 ret = -1;
363
364 // outbound_proxy
365 if (cfg.hasParameter("outbound_proxy"))
366 OutboundProxy = cfg.getParameter("outbound_proxy");
367
368 // force_outbound_proxy
369 if(cfg.hasParameter("force_outbound_proxy")) {
370 ForceOutboundProxy = (cfg.getParameter("force_outbound_proxy") == "yes");
371 }
372
373 if(cfg.hasParameter("next_hop")) {
374 NextHop = cfg.getParameter("next_hop");
375 NextHop1stReq = (cfg.getParameter("next_hop_1st_req") == "yes");
376 }
377
378 if(cfg.hasParameter("proxy_sticky_auth")) {
379 ProxyStickyAuth = (cfg.getParameter("proxy_sticky_auth") == "yes");
380 }
381
382 if(cfg.hasParameter("force_outbound_if")) {
383 ForceOutboundIf = (cfg.getParameter("force_outbound_if") == "yes");
384 }
385
386 if(cfg.hasParameter("use_raw_sockets")) {
387 UseRawSockets = (cfg.getParameter("use_raw_sockets") == "yes");
388 if(UseRawSockets && (raw_sender::init() < 0)) {
389 UseRawSockets = false;
390 }
391 }
392
393 if(cfg.hasParameter("ignore_notify_lower_cseq")) {
394 IgnoreNotifyLowerCSeq = (cfg.getParameter("ignore_notify_lower_cseq") == "yes");
395 }
396
397 if(cfg.hasParameter("force_symmetric_rtp")) {
398 ForceSymmetricRtp = (cfg.getParameter("force_symmetric_rtp") == "yes");
399 }
400
401 if(cfg.hasParameter("sip_nat_handling")) {
402 SipNATHandling = (cfg.getParameter("sip_nat_handling") == "yes");
403 }
404
405 if(cfg.hasParameter("disable_dns_srv")) {
406 _resolver::disable_srv = (cfg.getParameter("disable_dns_srv") == "yes");
407 }
408
409
410 for (int t = STIMER_A; t < __STIMER_MAX; t++) {
411
412 string timer_cfg = string("sip_timer_") + timer_name(t);
413 if(cfg.hasParameter(timer_cfg)) {
414
415 sip_timers[t] = cfg.getParameterInt(timer_cfg, sip_timers[t]);
416 INFO("Set SIP Timer '%s' to %u ms\n", timer_name(t), sip_timers[t]);
417 }
418 }
419
420 if (cfg.hasParameter("sip_timer_t2")) {
421 sip_timer_t2 = cfg.getParameterInt("sip_timer_t2", DEFAULT_T2_TIMER);
422 INFO("Set SIP Timer T2 to %u ms\n", sip_timer_t2);
423 }
424
425 // plugin_path
426 if (cfg.hasParameter("plugin_path"))
427 PlugInPath = cfg.getParameter("plugin_path");
428
429 // load_plugins
430 if (cfg.hasParameter("load_plugins"))
431 LoadPlugins = cfg.getParameter("load_plugins");
432
433 if (cfg.hasParameter("load_plugins_rtld_global")) {
434 vector<string> rtld_global_plugins =
435 explode(cfg.getParameter("load_plugins_rtld_global"), ",");
436 for (vector<string>::iterator it=
437 rtld_global_plugins.begin(); it != rtld_global_plugins.end(); it++) {
438 AmPlugIn::instance()->set_load_rtld_global(*it);
439 }
440 }
441
442
443 // exclude_plugins
444 if (cfg.hasParameter("exclude_plugins"))
445 ExcludePlugins = cfg.getParameter("exclude_plugins");
446
447 // exclude_plugins
448 if (cfg.hasParameter("exclude_payloads"))
449 ExcludePayloads = cfg.getParameter("exclude_payloads");
450
451 // user_agent
452 if (cfg.getParameter("use_default_signature")=="yes")
453 Signature = DEFAULT_SIGNATURE;
454 else
455 Signature = cfg.getParameter("signature");
456
457 if (cfg.hasParameter("max_forwards")) {
458 unsigned int mf=0;
459 if(str2i(cfg.getParameter("max_forwards"), mf)) {
460 ERROR("invalid max_forwards specified\n");
461 }
462 else {
463 MaxForwards = mf;
464 }
465 }
466
467 if(cfg.hasParameter("log_sessions"))
468 LogSessions = cfg.getParameter("log_sessions")=="yes";
469
470 if(cfg.hasParameter("log_events"))
471 LogEvents = cfg.getParameter("log_events")=="yes";
472
473 if (cfg.hasParameter("unhandled_reply_loglevel")) {
474 string msglog = cfg.getParameter("unhandled_reply_loglevel");
475 if (msglog == "no") UnhandledReplyLoglevel = -1;
476 else if (msglog == "error") UnhandledReplyLoglevel = 0;
477 else if (msglog == "warn") UnhandledReplyLoglevel = 1;
478 else if (msglog == "info") UnhandledReplyLoglevel = 2;
479 else if (msglog == "debug") UnhandledReplyLoglevel = 3;
480 else ERROR("Could not interpret unhandled_reply_loglevel \"%s\"\n",
481 msglog.c_str());
482 }
483
484 Application = cfg.getParameter("application");
485
486 if (Application == "$(ruri.user)") {
487 AppSelect = App_RURIUSER;
488 } else if (Application == "$(ruri.param)") {
489 AppSelect = App_RURIPARAM;
490 } else if (Application == "$(apphdr)") {
491 AppSelect = App_APPHDR;
492 } else if (Application == "$(mapping)") {
493 AppSelect = App_MAPPING;
494 string appcfg_fname = ModConfigPath + "app_mapping.conf";
495 DBG("Loading application mapping...\n");
496 if (!read_regex_mapping(appcfg_fname, "=>", "application mapping",
497 AppMapping)) {
498 ERROR("reading application mapping\n");
499 ret = -1;
500 }
501 } else {
502 AppSelect = App_SPECIFIED;
503 }
504
505 #ifndef DISABLE_DAEMON_MODE
506
507 // fork
508 if(cfg.hasParameter("fork")){
509 if(!setDaemonMode(cfg.getParameter("fork"))){
510 ERROR("invalid fork value specified,"
511 " valid are only yes or no\n");
512 ret = -1;
513 }
514 }
515
516 // daemon (alias for fork)
517 if(cfg.hasParameter("daemon")){
518 if(!setDaemonMode(cfg.getParameter("daemon"))){
519 ERROR("invalid daemon value specified,"
520 " valid are only yes or no\n");
521 ret = -1;
522 }
523 }
524
525 if(cfg.hasParameter("daemon_uid")){
526 DaemonUid = cfg.getParameter("daemon_uid");
527 }
528
529 if(cfg.hasParameter("daemon_gid")){
530 DaemonGid = cfg.getParameter("daemon_gid");
531 }
532
533 #endif /* !DISABLE_DAEMON_MODE */
534
535 MaxShutdownTime = cfg.getParameterInt("max_shutdown_time",
536 DEFAULT_MAX_SHUTDOWN_TIME);
537
538 RtpMuxPort = cfg.getParameterInt("rtp_mux_port", 0);
539 if (RtpMuxPort) {
540 INFO("Enabling RTP mux port %u\n", RtpMuxPort);
541 RtpMuxIP = cfg.getParameter("rtp_mux_ip");
542 } else {
543 INFO("Not Enabling RTP mux port.\n");
544 }
545 RtpMuxOutInterface = cfg.getParameter("rtp_mux_out_interface");
546 RtpMuxMTUThreshold = cfg.getParameterInt("rtp_mux_mtu_threshold", DEFAULT_MUX_MTU_THRESHOLD);
547 RtpMuxMaxFrameAgeMs = cfg.getParameterInt("rtp_mux_max_frame_age_ms", DEFAULT_MUX_MAX_FRAME_AGE_MS);
548
549 if(cfg.hasParameter("session_processor_threads")){
550 #ifdef SESSION_THREADPOOL
551 if(!setSessionProcessorThreads(cfg.getParameter("session_processor_threads"))){
552 ERROR("invalid session_processor_threads value specified\n");
553 ret = -1;
554 }
555 if (SessionProcessorThreads<1) {
556 ERROR("invalid session_processor_threads value specified."
557 " need at least one thread\n");
558 ret = -1;
559 }
560 #else
561 WARN("session_processor_threads specified in sems.conf,\n");
562 WARN("but SEMS is compiled without SESSION_THREADPOOL support.\n");
563 WARN("set USE_THREADPOOL in Makefile.defs to enable session thread pool.\n");
564 WARN("SEMS will start now, but every call will have its own thread.\n");
565 #endif
566 }
567
568 if(cfg.hasParameter("media_processor_threads")){
569 if(!setMediaProcessorThreads(cfg.getParameter("media_processor_threads"))){
570 ERROR("invalid media_processor_threads value specified");
571 ret = -1;
572 }
573 }
574
575 if(cfg.hasParameter("rtp_receiver_threads")){
576 if(!setRTPReceiverThreads(cfg.getParameter("rtp_receiver_threads"))){
577 ERROR("invalid rtp_receiver_threads value specified");
578 ret = -1;
579 }
580 }
581
582 if(cfg.hasParameter("sip_server_threads")){
583 if(!setSIPServerThreads(cfg.getParameter("sip_server_threads"))){
584 ERROR("invalid sip_server_threads value specified");
585 ret = -1;
586 }
587 }
588
589 // single codec in 200 OK
590 if(cfg.hasParameter("single_codec_in_ok")){
591 SingleCodecInOK = (cfg.getParameter("single_codec_in_ok") == "yes");
592 }
593
594 // single codec in 200 OK
595 if(cfg.hasParameter("ignore_rtpxheaders")){
596 IgnoreRTPXHdrs = (cfg.getParameter("ignore_rtpxheaders") == "yes");
597 }
598
599 // codec_order
600 CodecOrder = explode(cfg.getParameter("codec_order"), ",");
601
602 // dead_rtp_time
603 if(cfg.hasParameter("dead_rtp_time")){
604 if(!setDeadRtpTime(cfg.getParameter("dead_rtp_time"))){
605 ERROR("invalid dead_rtp_time value specified");
606 ret = -1;
607 }
608 }
609
610 if(cfg.hasParameter("dtmf_detector")){
611 if (cfg.getParameter("dtmf_detector") == "spandsp") {
612 #ifndef USE_SPANDSP
613 WARN("spandsp support not compiled in.\n");
614 #endif
615 DefaultDTMFDetector = Dtmf::SpanDSP;
616 }
617 }
618
619 #ifdef WITH_ZRTP
620 enable_zrtp = cfg.getParameter("enable_zrtp", "yes") == "yes";
621 INFO("ZRTP %sabled\n", enable_zrtp ? "en":"dis");
622
623 enable_zrtp_debuglog = cfg.getParameter("enable_zrtp_debuglog", "yes") == "yes";
624 INFO("ZRTP debug log %sabled\n", enable_zrtp_debuglog ? "en":"dis");
625 #endif
626
627 if(cfg.hasParameter("session_limit")){
628 vector<string> limit = explode(cfg.getParameter("session_limit"), ";");
629 if (limit.size() != 3) {
630 ERROR("invalid session_limit specified.\n");
631 } else {
632 if (str2i(limit[0], SessionLimit) || str2i(limit[1], SessionLimitErrCode)) {
633 ERROR("invalid session_limit specified.\n");
634 }
635 SessionLimitErrReason = limit[2];
636 }
637 }
638
639 if(cfg.hasParameter("options_session_limit")){
640 vector<string> limit = explode(cfg.getParameter("options_session_limit"), ";");
641 if (limit.size() != 3) {
642 ERROR("invalid options_session_limit specified.\n");
643 } else {
644 if (str2i(limit[0], OptionsSessionLimit) || str2i(limit[1], OptionsSessionLimitErrCode)) {
645 ERROR("invalid options_session_limit specified.\n");
646 }
647 OptionsSessionLimitErrReason = limit[2];
648 }
649 }
650
651 if(cfg.hasParameter("cps_limit")){
652 unsigned int CPSLimit = 0;
653 vector<string> limit = explode(cfg.getParameter("cps_limit"), ";");
654 if (limit.size() != 3) {
655 ERROR("invalid cps_limit specified.\n");
656 } else {
657 if (str2i(limit[0], CPSLimit) || str2i(limit[1], CPSLimitErrCode)) {
658 ERROR("invalid cps_limit specified.\n");
659 } else {
660 CPSLimitErrReason = limit[2];
661 AmSessionContainer::instance()->setCPSLimit(CPSLimit);
662 }
663 }
664 }
665
666 if(cfg.hasParameter("accept_forked_dialogs"))
667 AcceptForkedDialogs = !(cfg.getParameter("accept_forked_dialogs") == "no");
668
669 if(cfg.hasParameter("shutdown_mode_reply")){
670 string c_reply = cfg.getParameter("shutdown_mode_reply");
671 size_t spos = c_reply.find(" ");
672 if (spos == string::npos || spos == c_reply.length()) {
673 ERROR("invalid shutdown_mode_reply specified, expected \"<code> <reason>\","
674 "e.g. shutdown_mode_reply=\"503 Not At The Moment, Please\".\n");
675 ret = -1;
676
677 } else {
678 if (str2i(c_reply.substr(0, spos), ShutdownModeErrCode)) {
679 ERROR("invalid shutdown_mode_reply specified, expected \"<code> <reason>\","
680 "e.g. shutdown_mode_reply=\"503 Not At The Moment, Please\".\n");
681 ret = -1;
682 }
683 ShutdownModeErrReason = c_reply.substr(spos+1);
684 }
685 }
686
687 OptionsTranscoderOutStatsHdr = cfg.getParameter("options_transcoder_out_stats_hdr");
688 OptionsTranscoderInStatsHdr = cfg.getParameter("options_transcoder_in_stats_hdr");
689 TranscoderOutStatsHdr = cfg.getParameter("transcoder_out_stats_hdr");
690 TranscoderInStatsHdr = cfg.getParameter("transcoder_in_stats_hdr");
691
692 DumpConferenceStreams = cfg.getParameter("dump_conference_streams")=="true";
693 DumpConferencePath = cfg.getParameter("dump_conference_path");
694
695 if (cfg.hasParameter("100rel")) {
696 string rel100s = cfg.getParameter("100rel");
697 if (rel100s == "disabled" || rel100s == "off") {
698 rel100 = Am100rel::REL100_DISABLED;
699 } else if (rel100s == "supported") {
700 rel100 = Am100rel::REL100_SUPPORTED;
701 } else if (rel100s == "require") {
702 rel100 = Am100rel::REL100_REQUIRE;
703 } else {
704 ERROR("unknown setting for '100rel' config option: '%s'.\n",
705 rel100s.c_str());
706 ret = -1;
707 }
708 }
709
710 if (cfg.hasParameter("resampling_library")) {
711 string resamplings = cfg.getParameter("resampling_library");
712 if (resamplings == "libsamplerate") {
713 ResamplingImplementationType = AmAudio::LIBSAMPLERATE;
714 }
715 }
716
717 return ret;
718 }
719
insert_SIP_interface(const SIP_interface & intf)720 int AmConfig::insert_SIP_interface(const SIP_interface& intf)
721 {
722 if(SIP_If_names.find(intf.name) != SIP_If_names.end()) {
723
724 if(intf.name != "default") {
725 ERROR("duplicated interface name '%s'\n",intf.name.c_str());
726 return -1;
727 }
728
729 unsigned int idx = SIP_If_names[intf.name];
730 SIP_Ifs[idx] = intf;
731 return 0;
732 }
733
734 SIP_Ifs.push_back(intf);
735 unsigned int idx = SIP_Ifs.size()-1;
736 SIP_If_names[intf.name] = idx;
737 return 0;
738 }
739
insert_SIP_interface_mapping(const SIP_interface & intf)740 int AmConfig::insert_SIP_interface_mapping(const SIP_interface& intf) {
741 unsigned int idx = SIP_If_names[intf.name];
742
743 string if_local_ip = intf.LocalIP;
744
745 if(LocalSIPIP2If.find(if_local_ip) == LocalSIPIP2If.end()) {
746 LocalSIPIP2If.insert(make_pair(if_local_ip,idx));
747 } else {
748 map<string,unsigned short>::iterator it =
749 LocalSIPIP2If.find(if_local_ip);
750
751 const SIP_interface& old_intf = SIP_Ifs[it->second];
752 if(intf.LocalPort == old_intf.LocalPort) {
753 ERROR("duplicated signaling interfaces (%s and %s) detected using %s:%u",
754 old_intf.name.c_str(), intf.name.c_str(), if_local_ip.c_str(), intf.LocalPort);
755 return -1;
756 }
757 // two interfaces on the sample IP - the one on port 5060 has priority
758 if (intf.LocalPort == 5060)
759 LocalSIPIP2If.insert(make_pair(if_local_ip,idx));
760 }
761 return 0;
762 }
763
readSIPInterface(AmConfigReader & cfg,const string & i_name)764 static int readSIPInterface(AmConfigReader& cfg, const string& i_name)
765 {
766 AmConfig::SIP_interface intf;
767
768 string suffix;
769 if(!i_name.empty())
770 suffix = "_" + i_name;
771
772 // listen, sip_ip, sip_port, and media_ip
773 if(cfg.hasParameter("sip_ip" + suffix)) {
774 intf.LocalIP = cfg.getParameter("sip_ip" + suffix);
775 }
776 else {
777 // no sip_ip definition
778 return 0;
779 }
780
781 if(cfg.hasParameter("sip_port" + suffix)){
782 string sip_port_str = cfg.getParameter("sip_port" + suffix);
783 if(sscanf(sip_port_str.c_str(),"%u",
784 &(intf.LocalPort)) != 1){
785 ERROR("sip_port%s: invalid sip port specified (%s)\n",
786 suffix.c_str(),
787 sip_port_str.c_str());
788 return -1;
789 }
790 }
791
792 // public_ip
793 if(cfg.hasParameter("public_ip" + suffix)){
794 intf.PublicIP = cfg.getParameter("public_ip" + suffix);
795 }
796
797 if(cfg.hasParameter("sig_sock_opts" + suffix)){
798 vector<string> opt_strs = explode(cfg.getParameter("sig_sock_opts" + suffix),",");
799 unsigned int opts = 0;
800 for(vector<string>::iterator it_opt = opt_strs.begin();
801 it_opt != opt_strs.end(); ++it_opt) {
802 if(*it_opt == "force_via_address") {
803 opts |= trsp_socket::force_via_address;
804 } else if(*it_opt == "no_transport_in_contact") {
805 opts |= trsp_socket::no_transport_in_contact;
806 } else {
807 WARN("unknown signaling socket option '%s' set on interface '%s'\n",
808 it_opt->c_str(),i_name.c_str());
809 }
810 }
811 intf.SigSockOpts = opts;
812 }
813
814 intf.tcp_connect_timeout =
815 cfg.getParameterInt("tcp_connect_timeout" + suffix,
816 DEFAULT_TCP_CONNECT_TIMEOUT);
817
818 intf.tcp_idle_timeout =
819 cfg.getParameterInt("tcp_idle_timeout" + suffix, DEFAULT_TCP_IDLE_TIMEOUT);
820
821 if(!i_name.empty())
822 intf.name = i_name;
823 else
824 intf.name = "default";
825
826 return AmConfig::insert_SIP_interface(intf);
827 }
828
insert_RTP_interface(const RTP_interface & intf)829 int AmConfig::insert_RTP_interface(const RTP_interface& intf)
830 {
831 if(RTP_If_names.find(intf.name) !=
832 RTP_If_names.end()) {
833
834 if(intf.name != "default") {
835 ERROR("duplicated interface '%s'\n",intf.name.c_str());
836 return -1;
837 }
838
839 unsigned int idx = RTP_If_names[intf.name];
840 RTP_Ifs[idx] = intf;
841 }
842 else {
843 // insert interface
844 RTP_Ifs.push_back(intf);
845 unsigned short rtp_idx = RTP_Ifs.size()-1;
846 RTP_If_names[intf.name] = rtp_idx;
847
848 // fix RtpInterface index in SIP interface
849 map<string,unsigned short>::iterator sip_idx_it =
850 SIP_If_names.find(intf.name);
851
852 if((sip_idx_it != SIP_If_names.end()) &&
853 (SIP_Ifs.size() > sip_idx_it->second)) {
854 SIP_Ifs[sip_idx_it->second].RtpInterface = rtp_idx;
855 }
856 }
857
858 return 0;
859 }
860
readRTPInterface(AmConfigReader & cfg,const string & i_name)861 static int readRTPInterface(AmConfigReader& cfg, const string& i_name)
862 {
863 AmConfig::RTP_interface intf;
864
865 string suffix;
866 if(!i_name.empty())
867 suffix = "_" + i_name;
868
869 // media_ip
870 if(cfg.hasParameter("media_ip" + suffix)) {
871 intf.LocalIP = cfg.getParameter("media_ip" + suffix);
872 }
873 else {
874 // no media definition for this interface name
875 return 0;
876 }
877
878 // public_ip
879 if(cfg.hasParameter("public_ip" + suffix)){
880 intf.PublicIP = cfg.getParameter("public_ip" + suffix);
881 }
882
883 // rtp_low_port
884 if(cfg.hasParameter("rtp_low_port" + suffix)){
885 string rtp_low_port_str = cfg.getParameter("rtp_low_port" + suffix);
886 if(sscanf(rtp_low_port_str.c_str(),"%u",
887 &(intf.RtpLowPort)) != 1){
888 ERROR("rtp_low_port%s: invalid port number (%s)\n",
889 suffix.c_str(),rtp_low_port_str.c_str());
890 return -1;
891 }
892 }
893
894 // rtp_high_port
895 if(cfg.hasParameter("rtp_high_port" + suffix)){
896 string rtp_high_port_str = cfg.getParameter("rtp_high_port" + suffix);
897 if(sscanf(rtp_high_port_str.c_str(),"%u",
898 &(intf.RtpHighPort)) != 1){
899 ERROR("rtp_high_port%s: invalid port number (%s)\n",
900 suffix.c_str(),rtp_high_port_str.c_str());
901 return -1;
902 }
903 }
904
905 if(!i_name.empty())
906 intf.name = i_name;
907 else
908 intf.name = "default";
909
910 return AmConfig::insert_RTP_interface(intf);
911 }
912
readInterfaces(AmConfigReader & cfg)913 static int readInterfaces(AmConfigReader& cfg)
914 {
915 if(!cfg.hasParameter("interfaces")) {
916 // no interface list defined:
917 // read default params
918 readSIPInterface(cfg,"");
919 readRTPInterface(cfg,"");
920 return 0;
921 }
922
923 vector<string> if_names;
924 string ifs_str = cfg.getParameter("interfaces");
925 if(ifs_str.empty()) {
926 ERROR("empty interface list.\n");
927 return -1;
928 }
929
930 if_names = explode(ifs_str,",");
931 if(!if_names.size()) {
932 ERROR("could not parse interface list.\n");
933 return -1;
934 }
935
936 for(vector<string>::iterator it = if_names.begin();
937 it != if_names.end(); it++) {
938
939 readSIPInterface(cfg,*it);
940 readRTPInterface(cfg,*it);
941
942 if((AmConfig::SIP_If_names.find(*it) == AmConfig::SIP_If_names.end()) &&
943 (AmConfig::RTP_If_names.find(*it) == AmConfig::RTP_If_names.end())) {
944 ERROR("missing interface definition for '%s'\n",it->c_str());
945 return -1;
946 }
947 }
948
949 //TODO: check interfaces
950 return 0;
951 }
952
953 /** Get the list of network interfaces with the associated addresses & flags */
fillSysIntfList()954 static bool fillSysIntfList()
955 {
956 struct ifaddrs *ifap = NULL;
957
958 // socket to grab MTU
959 int fd = socket(AF_INET, SOCK_DGRAM, 0);
960 if(fd < 0) {
961 ERROR("socket() failed: %s",strerror(errno));
962 return false;
963 }
964
965 if(getifaddrs(&ifap) < 0){
966 ERROR("getifaddrs() failed: %s",strerror(errno));
967 return false;
968 }
969
970 char host[NI_MAXHOST];
971 for(struct ifaddrs *p_if = ifap; p_if != NULL; p_if = p_if->ifa_next) {
972
973 if(p_if->ifa_addr == NULL)
974 continue;
975
976 if( (p_if->ifa_addr->sa_family != AF_INET) &&
977 (p_if->ifa_addr->sa_family != AF_INET6) )
978 continue;
979
980 if( !(p_if->ifa_flags & IFF_UP) || !(p_if->ifa_flags & IFF_RUNNING) )
981 continue;
982
983 if(p_if->ifa_addr->sa_family == AF_INET6) {
984 #ifndef SUPPORT_IPV6
985 continue;
986 #endif
987
988 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p_if->ifa_addr;
989 if(IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)){
990 // sorry, we don't support link-local addresses...
991 continue;
992
993 // convert address from kernel-style to userland
994 // addr->sin6_scope_id = ntohs(*(uint16_t *)&addr->sin6_addr.s6_addr[2]);
995 // addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0;
996 }
997 }
998
999 if (am_inet_ntop((const sockaddr_storage*)p_if->ifa_addr,
1000 host, NI_MAXHOST) == NULL) {
1001 ERROR("am_inet_ntop() failed\n");
1002 continue;
1003 // freeifaddrs(ifap);
1004 // return false;
1005 }
1006
1007 string iface_name(p_if->ifa_name);
1008 vector<AmConfig::SysIntf>::iterator intf_it;
1009 for(intf_it = AmConfig::SysIfs.begin();
1010 intf_it != AmConfig::SysIfs.end(); ++intf_it) {
1011
1012 if(intf_it->name == iface_name)
1013 break;
1014 }
1015
1016 if(intf_it == AmConfig::SysIfs.end()){
1017 unsigned int sys_if_idx = if_nametoindex(iface_name.c_str());
1018 if(AmConfig::SysIfs.size() < sys_if_idx+1)
1019 AmConfig::SysIfs.resize(sys_if_idx+1);
1020
1021 intf_it = AmConfig::SysIfs.begin() + sys_if_idx;
1022 intf_it->name = iface_name;
1023 intf_it->flags = p_if->ifa_flags;
1024
1025 struct ifreq ifr;
1026 strncpy(ifr.ifr_name,p_if->ifa_name,sizeof(ifr.ifr_name)-1);
1027
1028 if (ioctl(fd, SIOCGIFMTU, &ifr) < 0 ) {
1029 ERROR("ioctl: %s",strerror(errno));
1030 ERROR("setting MTU for this interface to default (1500)");
1031 intf_it->mtu = 1500;
1032 }
1033 else {
1034 intf_it->mtu = ifr.ifr_mtu;
1035 }
1036 }
1037
1038 DBG("iface='%s';ip='%s';flags=0x%x\n",p_if->ifa_name,host,p_if->ifa_flags);
1039 intf_it->addrs.push_back(AmConfig::IPAddr(host,p_if->ifa_addr->sa_family));
1040 }
1041
1042 freeifaddrs(ifap);
1043 close(fd);
1044
1045 return true;
1046 }
1047
fillMissingLocalSIPIPfromSysIntfs()1048 static void fillMissingLocalSIPIPfromSysIntfs() {
1049 // add addresses from SysIntfList, if not present
1050 for(unsigned int idx = 0; idx < AmConfig::SIP_Ifs.size(); idx++) {
1051
1052 vector<AmConfig::SysIntf>::iterator intf_it = AmConfig::SysIfs.begin();
1053 for(;intf_it != AmConfig::SysIfs.end(); ++intf_it) {
1054
1055 list<AmConfig::IPAddr>::iterator addr_it = intf_it->addrs.begin();
1056 for(;addr_it != intf_it->addrs.end(); addr_it++) {
1057 if(addr_it->addr == AmConfig::SIP_Ifs[idx].LocalIP)
1058 break;
1059 }
1060
1061 // address not in this interface
1062 if(addr_it == intf_it->addrs.end())
1063 continue;
1064
1065 // address is primary
1066 if(addr_it == intf_it->addrs.begin())
1067 continue;
1068
1069 if(AmConfig::LocalSIPIP2If.find(intf_it->addrs.front().addr)
1070 == AmConfig::LocalSIPIP2If.end()) {
1071 DBG("mapping unmapped IP address '%s' to interface #%u \n",
1072 intf_it->addrs.front().addr.c_str(), idx);
1073 AmConfig::LocalSIPIP2If[intf_it->addrs.front().addr] = idx;
1074 }
1075 }
1076 }
1077 }
1078
1079
1080 /** Get the AF_INET[6] address associated with the network interface */
fixIface2IP(const string & dev_name,bool v6_for_sip)1081 string fixIface2IP(const string& dev_name, bool v6_for_sip)
1082 {
1083 struct sockaddr_storage ss;
1084 if(am_inet_pton(dev_name.c_str(), &ss)) {
1085 if(v6_for_sip && (ss.ss_family == AF_INET6) && (dev_name[0] != '['))
1086 return "[" + dev_name + "]";
1087 else
1088 return dev_name;
1089 }
1090
1091 for(vector<AmConfig::SysIntf>::iterator intf_it = AmConfig::SysIfs.begin();
1092 intf_it != AmConfig::SysIfs.end(); ++intf_it) {
1093
1094 if(intf_it->name != dev_name)
1095 continue;
1096
1097 if(intf_it->addrs.empty()){
1098 ERROR("No IP address for interface '%s'\n",intf_it->name.c_str());
1099 return "";
1100 }
1101
1102 DBG("dev_name = '%s'\n",dev_name.c_str());
1103 return intf_it->addrs.front().addr;
1104 }
1105
1106 return "";
1107 }
1108
1109 /** Get IP addrese from first non-loopback interface */
getDefaultIP()1110 static string getDefaultIP()
1111 {
1112 for(vector<AmConfig::SysIntf>::iterator intf_it = AmConfig::SysIfs.begin();
1113 intf_it != AmConfig::SysIfs.end(); ++intf_it) {
1114
1115 if(intf_it->flags & IFF_LOOPBACK)
1116 continue;
1117
1118 if(intf_it->addrs.empty())
1119 continue;
1120
1121 DBG("dev_name = '%s'\n",intf_it->name.c_str());
1122 return intf_it->addrs.front().addr;
1123 }
1124
1125 return "";
1126 }
1127
setNetInterface(AmConfig::IP_interface * ip_if)1128 static int setNetInterface(AmConfig::IP_interface* ip_if)
1129 {
1130 for(unsigned int i=0; i < AmConfig::SysIfs.size(); i++) {
1131
1132 list<AmConfig::IPAddr>::iterator addr_it = AmConfig::SysIfs[i].addrs.begin();
1133 while(addr_it != AmConfig::SysIfs[i].addrs.end()) {
1134 if(ip_if->LocalIP == addr_it->addr) {
1135 ip_if->NetIf = AmConfig::SysIfs[i].name;
1136 ip_if->NetIfIdx = i;
1137 return 0;
1138 }
1139 addr_it++;
1140 }
1141 }
1142
1143 // not interface found
1144 return -1;
1145 }
1146
finalizeIPConfig()1147 int AmConfig::finalizeIPConfig()
1148 {
1149 fillSysIntfList();
1150
1151 // replace system interface names with IPs
1152 for(vector<SIP_interface>::iterator it = SIP_Ifs.begin();
1153 it != SIP_Ifs.end(); it++) {
1154
1155 it->LocalIP = fixIface2IP(it->LocalIP,true);
1156 if(it->LocalIP.empty()) {
1157 ERROR("could not determine signaling IP for "
1158 "interface '%s'\n", it->name.c_str());
1159 return -1;
1160 }
1161
1162 if(!it->LocalPort)
1163 it->LocalPort = 5060;
1164
1165 if (insert_SIP_interface_mapping(*it)<0)
1166 return -1;
1167
1168 setNetInterface(&(*it));
1169 }
1170
1171 for(vector<RTP_interface>::iterator it = RTP_Ifs.begin();
1172 it != RTP_Ifs.end(); it++) {
1173
1174 if(it->LocalIP.empty()) {
1175 // try the IP from the signaling interface
1176 map<string, unsigned short>::iterator sip_if =
1177 SIP_If_names.find(it->name);
1178 if(sip_if != SIP_If_names.end()) {
1179 it->LocalIP = SIP_Ifs[sip_if->second].LocalIP;
1180 }
1181 else {
1182 ERROR("could not determine media IP for "
1183 "interface '%s'\n", it->name.c_str());
1184 return -1;
1185 }
1186 }
1187 else {
1188 it->LocalIP = fixIface2IP(it->LocalIP,false);
1189 if(it->LocalIP.empty()) {
1190 ERROR("could not determine media IP for "
1191 "interface '%s'\n", it->name.c_str());
1192 return -1;
1193 }
1194 }
1195
1196 setNetInterface(&(*it));
1197 }
1198
1199 if(!SIP_Ifs.size()) {
1200 SIP_interface intf;
1201 intf.LocalIP = getDefaultIP();
1202 if(intf.LocalIP.empty()){
1203 ERROR("could not determine default signaling IP.");
1204 return -1;
1205 }
1206 SIP_Ifs.push_back(intf);
1207 SIP_If_names["default"] = 0;
1208 }
1209
1210 if(!RTP_Ifs.size()) {
1211 RTP_interface intf;
1212 intf.LocalIP = SIP_Ifs[0].LocalIP;
1213 if(intf.LocalIP.empty()){
1214 ERROR("could not determine default media IP.");
1215 return -1;
1216 }
1217 RTP_Ifs.push_back(intf);
1218 RTP_If_names["default"] = 0;
1219 }
1220
1221 fillMissingLocalSIPIPfromSysIntfs();
1222
1223 return 0;
1224 }
1225
dump_Ifs()1226 void AmConfig::dump_Ifs()
1227 {
1228 INFO("Signaling interfaces:");
1229 for(int i=0; i<(int)SIP_Ifs.size(); i++) {
1230
1231 SIP_interface& it_ref = SIP_Ifs[i];
1232
1233 INFO("\t(%i) name='%s'" ";LocalIP='%s'"
1234 ";LocalPort='%u'" ";PublicIP='%s';TCP=%u/%u",
1235 i,it_ref.name.c_str(),it_ref.LocalIP.c_str(),
1236 it_ref.LocalPort,it_ref.PublicIP.c_str(),
1237 it_ref.tcp_connect_timeout,
1238 it_ref.tcp_idle_timeout);
1239 }
1240
1241 INFO("Signaling address map:");
1242 for(multimap<string,unsigned short>::iterator it = LocalSIPIP2If.begin();
1243 it != LocalSIPIP2If.end(); ++it) {
1244
1245 if(SIP_Ifs[it->second].name.empty()){
1246 INFO("\t%s -> default",it->first.c_str());
1247 }
1248 else {
1249 INFO("\t%s -> %s",it->first.c_str(),
1250 SIP_Ifs[it->second].name.c_str());
1251 }
1252 }
1253
1254 INFO("Media interfaces:");
1255 for(int i=0; i<(int)RTP_Ifs.size(); i++) {
1256
1257 RTP_interface& it_ref = RTP_Ifs[i];
1258
1259 INFO("\t(%i) name='%s'" ";LocalIP='%s'"
1260 ";Ports=[%u;%u]" ";PublicIP='%s'",
1261 i,it_ref.name.c_str(),it_ref.LocalIP.c_str(),
1262 it_ref.RtpLowPort,it_ref.RtpHighPort,
1263 it_ref.PublicIP.c_str());
1264 }
1265 }
1266