Browse code

Merge branch 'tcp-trsp' into 1.6-dev-ccdsm

Raphael Coeffic authored on 27/11/2013 15:15:04
Showing 38 changed files
... ...
@@ -90,7 +90,6 @@ void AorBucket::gbc(RegCacheStorageHandler* h, long int now,
90 90
 	      del_it->first.c_str(),binding->alias.c_str(),
91 91
 	      binding->reg_expire,now);
92 92
 
93
-	  if(h) h->onDelete(it->first,del_it->first,binding->alias);
94 93
 	  delete binding;
95 94
 	  aor_e->erase(del_it);
96 95
 	  continue;
... ...
@@ -277,46 +277,15 @@ void RegisterDialog::fixUacContactHosts(const AmSipRequest& req,
277 277
     if(contact_hiding) {
278 278
       uac_contacts[i].uri_user = encodeUsername(uac_contacts[i],
279 279
 						req,cp,ctx);
280
-
281
-      list<sip_avp*> uri_params;
282
-      const string& old_params = uac_contacts[i].uri_param;
283
-      const char* c = old_params.c_str();
284
-
285
-      if(parse_gen_params(&uri_params,&c,old_params.length(),0) < 0) {
286
-
287
-	DBG("could not parse Contact URI parameters: '%s'",
288
-	    uac_contacts[i].uri_param.c_str());
289
-	free_gen_params(&uri_params);
290
-	continue;
291
-      }
292
-
293
-      // Suppress transport parameter
294
-      // hack to suppress transport=tcp
295
-      string new_params;
296
-      for(list<sip_avp*>::iterator p_it = uri_params.begin();
297
-	  p_it != uri_params.end(); p_it++) {
298
-
299
-	DBG("parsed");
300
-	if( ((*p_it)->name.len == (sizeof("transport")-1)) &&
301
-	    !memcmp((*p_it)->name.s,"transport",sizeof("transport")-1) ) {
302
-	  continue;
303
-	}
304
-
305
-	if(!new_params.empty()) new_params += ";";
306
-	new_params += c2stlstr((*p_it)->name);
307
-	if((*p_it)->value.len) {
308
-	  new_params += "=" + c2stlstr((*p_it)->value);
309
-	}
310
-      }
311
-
312
-      free_gen_params(&uri_params);
313
-      uac_contacts[i].uri_param = new_params;
314 280
     }
315 281
     else if(!reg_caching) {
316 282
       cp.fix_reg_contact(ctx,req,uac_contacts[i]);
317 283
       continue;
318 284
     }
319 285
 
286
+    // remove 'transport' param from Contact
287
+    removeTransport(uac_contacts[i]);
288
+
320 289
     // patch host & port
321 290
     uac_contacts[i].uri_host = AmConfig::SIP_Ifs[oif].getIP();
322 291
 
... ...
@@ -325,11 +294,49 @@ void RegisterDialog::fixUacContactHosts(const AmSipRequest& req,
325 294
     else
326 295
       uac_contacts[i].uri_port = int2str(AmConfig::SIP_Ifs[oif].LocalPort);
327 296
       
328
-    DBG("Patching host and port for Contact-HF: host='%s';port='%s'",
297
+    DBG("Patching host, port and transport for Contact-HF: host='%s';port='%s'",
329 298
 	uac_contacts[i].uri_host.c_str(),uac_contacts[i].uri_port.c_str());
330 299
   }
331 300
 }
332 301
 
302
+int RegisterDialog::removeTransport(AmUriParser& uri)
303
+{
304
+  list<sip_avp*> uri_params;
305
+  string old_params = uri.uri_param;
306
+  const char* c = old_params.c_str();
307
+
308
+  if(parse_gen_params(&uri_params,&c,old_params.length(),0) < 0) {
309
+
310
+    DBG("could not parse Contact URI parameters: '%s'",
311
+	uri.uri_param.c_str());
312
+    free_gen_params(&uri_params);
313
+    return -1;
314
+  }
315
+
316
+  // Suppress transport parameter
317
+  // hack to suppress transport=tcp
318
+  string new_params;
319
+  for(list<sip_avp*>::iterator p_it = uri_params.begin();
320
+      p_it != uri_params.end(); p_it++) {
321
+
322
+    DBG("parsed");
323
+    if( ((*p_it)->name.len == (sizeof("transport")-1)) &&
324
+	!memcmp((*p_it)->name.s,"transport",sizeof("transport")-1) ) {
325
+      continue;
326
+    }
327
+
328
+    if(!new_params.empty()) new_params += ";";
329
+    new_params += c2stlstr((*p_it)->name);
330
+    if((*p_it)->value.len) {
331
+      new_params += "=" + c2stlstr((*p_it)->value);
332
+    }
333
+  }
334
+
335
+  free_gen_params(&uri_params);
336
+  uri.uri_param = new_params;
337
+  return 0;
338
+}
339
+
333 340
 int RegisterDialog::initAor(const AmSipRequest& req)
334 341
 {
335 342
   AmUriParser from_parser;
... ...
@@ -55,6 +55,9 @@ class RegisterDialog
55 55
   // so that getOutboundIf() can be called
56 56
   void fixUacContactHosts(const AmSipRequest& req, const SBCCallProfile& cp);
57 57
 
58
+  // remove the transport parameter from a URI
59
+  int removeTransport(AmUriParser& uri);
60
+
58 61
 public:
59 62
   RegisterDialog(SBCCallProfile &profile, vector<AmDynInvoke*> &cc_modules);
60 63
   ~RegisterDialog();
... ...
@@ -326,8 +326,10 @@ void AmBasicSipDialog::onRxRequest(const AmSipRequest& req)
326 326
     if (remote_uri != req.from_uri) {
327 327
       setRemoteUri(req.from_uri);
328 328
       if(nat_handling && req.first_hop) {
329
-	setNextHop(req.remote_ip + ":"
330
-		   + int2str(req.remote_port));
329
+	string nh = req.remote_ip + ":"
330
+	  + int2str(req.remote_port)
331
+	  + "/" + req.trsp;
332
+	setNextHop(nh);
331 333
 	setNextHop1stReq(false);
332 334
       }
333 335
     }
... ...
@@ -470,11 +472,11 @@ void AmBasicSipDialog::updateDialogTarget(const AmSipReply& reply)
470 472
        (reply.cseq_method == SIP_METH_SUBSCRIBE)) ) {
471 473
     
472 474
     setRemoteUri(reply.to_uri);
473
-    if(!getNextHop().empty() && !next_hop_fixed) {
474
-      DBG("updating next_hop from reply to %s:%u\n",
475
-	  reply.remote_ip.c_str(), reply.remote_port);
476
-      setNextHop(reply.remote_ip + ":"
477
-		 + int2str(reply.remote_port));
475
+    if(!getNextHop().empty()) {
476
+      string nh = reply.remote_ip 
477
+	+ ":" + int2str(reply.remote_port)
478
+	+ "/" + reply.trsp;
479
+      setNextHop(nh);
478 480
     }
479 481
 
480 482
     string ua = getHeader(reply.hdrs,"Server");
... ...
@@ -43,6 +43,7 @@
43 43
 #include "AmSessionContainer.h"
44 44
 #include "Am100rel.h"
45 45
 #include "sip/transport.h"
46
+#include "sip/resolver.h"
46 47
 #include "sip/ip_util.h"
47 48
 #include "sip/sip_timers.h"
48 49
 #include "sip/raw_sender.h"
... ...
@@ -91,7 +92,6 @@ bool         AmConfig::ForceSymmetricRtp       = false;
91 92
 bool         AmConfig::SipNATHandling          = false;
92 93
 bool         AmConfig::UseRawSockets           = false;
93 94
 bool         AmConfig::IgnoreNotifyLowerCSeq   = false;
94
-bool         AmConfig::DisableDNSSRV           = false;
95 95
 string       AmConfig::Signature               = "";
96 96
 unsigned int AmConfig::MaxForwards             = MAX_FORWARDS;
97 97
 bool	     AmConfig::SingleCodecInOK	       = false;
... ...
@@ -386,7 +386,7 @@ int AmConfig::readConfiguration()
386 386
   }
387 387
 
388 388
   if(cfg.hasParameter("disable_dns_srv")) {
389
-    DisableDNSSRV = (cfg.getParameter("disable_dns_srv") == "yes");
389
+    _resolver::disable_srv = (cfg.getParameter("disable_dns_srv") == "yes");
390 390
   }
391 391
   
392 392
 
... ...
@@ -713,6 +713,7 @@ int AmConfig::insert_SIP_interface(const SIP_interface& intf)
713 713
 
714 714
 	return -1;
715 715
       }
716
+      //FIXME: what happens now? shouldn't we insert the interface????
716 717
     }
717 718
   }
718 719
 
... ...
@@ -769,6 +770,13 @@ static int readSIPInterface(AmConfigReader& cfg, const string& i_name)
769 770
     intf.SigSockOpts = opts;
770 771
   }
771 772
 
773
+  intf.tcp_connect_timeout =
774
+    cfg.getParameterInt("tcp_connect_timeout" + suffix,
775
+			DEFAULT_TCP_CONNECT_TIMEOUT);
776
+
777
+  intf.tcp_idle_timeout =
778
+    cfg.getParameterInt("tcp_idle_timeout" + suffix, DEFAULT_TCP_IDLE_TIMEOUT);
779
+
772 780
   if(!i_name.empty())
773 781
     intf.name = i_name;
774 782
   else
... ...
@@ -1171,9 +1179,11 @@ void AmConfig::dump_Ifs()
1171 1179
     SIP_interface& it_ref = SIP_Ifs[i];
1172 1180
 
1173 1181
     INFO("\t(%i) name='%s'" ";LocalIP='%s'" 
1174
-	 ";LocalPort='%u'" ";PublicIP='%s'",
1182
+	 ";LocalPort='%u'" ";PublicIP='%s';TCP=%u/%u",
1175 1183
 	 i,it_ref.name.c_str(),it_ref.LocalIP.c_str(),
1176
-	 it_ref.LocalPort,it_ref.PublicIP.c_str());
1184
+	 it_ref.LocalPort,it_ref.PublicIP.c_str(),
1185
+	 it_ref.tcp_connect_timeout,
1186
+	 it_ref.tcp_idle_timeout);
1177 1187
   }
1178 1188
   
1179 1189
   INFO("Signaling address map:");
... ...
@@ -110,6 +110,9 @@ struct AmConfig
110 110
      */
111 111
     unsigned int SigSockOpts;
112 112
 
113
+    unsigned int tcp_connect_timeout;
114
+    unsigned int tcp_idle_timeout;
115
+
113 116
     /** RTP interface index */
114 117
     int RtpInterface;
115 118
 
... ...
@@ -193,8 +196,6 @@ struct AmConfig
193 196
   static bool UseRawSockets;
194 197
   /** Ignore Low CSeq on NOTIFY  - for RFC 3265 instead of 5057 */
195 198
   static bool IgnoreNotifyLowerCSeq;
196
-  /** skip DNS SRV lookup for resolving destination address*/
197
-  static bool DisableDNSSRV;
198 199
   /** Server/User-Agent header (optional) */
199 200
   static string Signature;
200 201
   /** Value of Max-Forward header field for new requests */
... ...
@@ -38,16 +38,6 @@
38 38
 #include <strings.h>
39 39
 #endif
40 40
 
41
-#include <sys/time.h>
42
-#include <sys/poll.h>
43
-
44
-#ifndef MAX_RTP_SESSIONS
45
-#define MAX_RTP_SESSIONS 2048
46
-#endif 
47
-
48
-#define RTP_POLL_TIMEOUT 50 /*50 ms*/
49
-
50
-
51 41
 _AmRtpReceiver::_AmRtpReceiver()
52 42
 {
53 43
   n_receivers = AmConfig::RTPReceiverThreads;
... ...
@@ -62,20 +52,20 @@ _AmRtpReceiver::~_AmRtpReceiver()
62 52
 AmRtpReceiverThread::AmRtpReceiverThread()
63 53
   : stop_requested(false)
64 54
 {
65
-  fds  = new struct pollfd[MAX_RTP_SESSIONS];
66
-  nfds = 0;
55
+  // libevent event base
56
+  ev_base = event_base_new();
67 57
 }
68 58
 
69 59
 AmRtpReceiverThread::~AmRtpReceiverThread()
70 60
 {
71
-  delete [] (fds);
61
+  event_base_free(ev_base);
72 62
   INFO("RTP receiver has been recycled.\n");
73 63
 }
74 64
 
75 65
 void AmRtpReceiverThread::on_stop()
76 66
 {
77 67
   INFO("requesting RTP receiver to stop.\n");
78
-  stop_requested.set(true);
68
+  event_base_loopbreak(ev_base);
79 69
 }
80 70
 
81 71
 void AmRtpReceiverThread::stop_and_wait()
... ...
@@ -97,44 +87,43 @@ void _AmRtpReceiver::dispose()
97 87
 
98 88
 void AmRtpReceiverThread::run()
99 89
 {
100
-  unsigned int   tmp_nfds = 0;
101
-  struct pollfd* tmp_fds  = new struct pollfd[MAX_RTP_SESSIONS];
102
-
103
-  while(!stop_requested.get()){
104
-	
105
-    streams_mut.lock();
106
-    tmp_nfds = nfds;
107
-    memcpy(tmp_fds,fds,nfds*sizeof(struct pollfd));
108
-    streams_mut.unlock();
109
-
110
-    int ret = poll(tmp_fds,tmp_nfds,RTP_POLL_TIMEOUT);
111
-    if(ret < 0 && errno != EINTR)
112
-      ERROR("AmRtpReceiver: poll: %s\n",strerror(errno));
113
-
114
-    if(ret < 1)
115
-      continue;
116
-
117
-    for(unsigned int i=0; i<tmp_nfds; i++) {
90
+  // fake event to prevent the event loop from exiting
91
+  int fake_fds[2];
92
+  pipe(fake_fds);
93
+  struct event* ev_default =
94
+    event_new(ev_base,fake_fds[0],
95
+	      EV_READ|EV_PERSIST,
96
+	      NULL,NULL);
97
+  event_add(ev_default,NULL);
98
+
99
+  // run the event loop
100
+  event_base_loop(ev_base,0);
101
+
102
+  // clean-up fake fds/event
103
+  event_free(ev_default);
104
+  close(fake_fds[0]);
105
+  close(fake_fds[1]);
106
+}
118 107
 
119
-      if(!(tmp_fds[i].revents & POLLIN))
120
-	continue;
108
+void AmRtpReceiverThread::_rtp_receiver_read_cb(evutil_socket_t sd, 
109
+						short what, void* arg)
110
+{
111
+  AmRtpReceiverThread::StreamInfo* p_si =
112
+    static_cast<AmRtpReceiverThread::StreamInfo*>(arg);
121 113
 
122
-      streams_mut.lock();
123
-      Streams::iterator it = streams.find(tmp_fds[i].fd);
124
-      if(it != streams.end()) {
125
-	it->second.stream->recvPacket(tmp_fds[i].fd);
126
-      }
127
-      streams_mut.unlock();      
128
-    }
114
+  p_si->thread->streams_mut.lock();
115
+  if(!p_si->stream) {
116
+    // we are about to get removed...
117
+    p_si->thread->streams_mut.unlock();
118
+    return;
129 119
   }
130
-
131
-  delete[] (tmp_fds);
120
+  p_si->stream->recvPacket(sd);
121
+  p_si->thread->streams_mut.unlock();
132 122
 }
133 123
 
134 124
 void AmRtpReceiverThread::addStream(int sd, AmRtpStream* stream)
135 125
 {
136 126
   streams_mut.lock();
137
-
138 127
   if(streams.find(sd) != streams.end()) {
139 128
     ERROR("trying to insert existing stream [%p] with sd=%i\n",
140 129
 	  stream,sd);
... ...
@@ -142,43 +131,50 @@ void AmRtpReceiverThread::addStream(int sd, AmRtpStream* stream)
142 131
     return;
143 132
   }
144 133
 
145
-  if(nfds >= MAX_RTP_SESSIONS){
146
-    streams_mut.unlock();
147
-    ERROR("maximum number of sessions reached (%i)\n",
148
-	  MAX_RTP_SESSIONS);
149
-    throw string("maximum number of sessions reached");
150
-  }
151
-
152
-  fds[nfds].fd      = sd;
153
-  fds[nfds].events  = POLLIN;
154
-  fds[nfds].revents = 0;
155
-
156
-  streams.insert(std::make_pair(sd,StreamInfo(nfds,stream)));
157
-  nfds++;
158
-
134
+  StreamInfo& si = streams[sd];
135
+  si.stream = stream;
136
+  event* ev_read = event_new(ev_base,sd,EV_READ|EV_PERSIST,
137
+			     AmRtpReceiverThread::_rtp_receiver_read_cb,&si);
138
+  si.ev_read = ev_read;
139
+  si.thread = this;
159 140
   streams_mut.unlock();
141
+
142
+  // This must be done when 
143
+  // streams_mut is NOT locked
144
+  event_add(ev_read,NULL);
160 145
 }
161 146
 
162 147
 void AmRtpReceiverThread::removeStream(int sd)
163 148
 {
164 149
   streams_mut.lock();
165
-
166 150
   Streams::iterator sit = streams.find(sd);
167 151
   if(sit == streams.end()) {
168 152
     streams_mut.unlock();
169 153
     return;
170 154
   }
171 155
 
172
-  unsigned int i = sit->second.index;
173
-  if(--nfds && (i < nfds)) {
174
-    fds[i] = fds[nfds];
175
-    sit = streams.find(fds[nfds].fd);
176
-    if(sit != streams.end()) {
177
-      sit->second.index = i;
178
-    }
156
+  StreamInfo& si = sit->second;
157
+  if(!si.stream || !si.ev_read){
158
+    streams_mut.unlock();
159
+    return;
179 160
   }
180
-  streams.erase(sd);
181 161
 
162
+  si.stream = NULL;
163
+  event* ev_read = si.ev_read;
164
+  si.ev_read = NULL;
165
+
166
+  streams_mut.unlock();
167
+
168
+  // This must be done while
169
+  // streams_mut is NOT locked
170
+  event_free(ev_read);
171
+
172
+  streams_mut.lock();
173
+  // this must be done AFTER event_free()
174
+  // so that the StreamInfo does not get
175
+  // deleted while in recvPaket()
176
+  // (see recv callback)
177
+  streams.erase(sd);
182 178
   streams_mut.unlock();
183 179
 }
184 180
 
... ...
@@ -32,7 +32,7 @@
32 32
 #include "atomic_types.h"
33 33
 #include "singleton.h"
34 34
 
35
-#include <sys/select.h>
35
+#include <event2/event.h>
36 36
 
37 37
 #include <map>
38 38
 using std::greater;
... ...
@@ -47,37 +47,45 @@ class _AmRtpReceiver;
47 47
  * that are registered to it. It places the received packets in 
48 48
  * the stream's buffer. 
49 49
  */
50
-class AmRtpReceiverThread: public AmThread {
51
-
52
-  struct StreamInfo {
53
-    unsigned int index; // index into fds table
50
+class AmRtpReceiverThread
51
+  : public AmThread
52
+{
53
+  struct StreamInfo 
54
+  {
54 55
     AmRtpStream* stream;
55
-
56
-    StreamInfo(unsigned int i, AmRtpStream* s)
57
-      : index(i), stream(s) {}
56
+    struct event* ev_read;
57
+    AmRtpReceiverThread* thread;
58
+
59
+    StreamInfo()
60
+      : stream(NULL),
61
+	ev_read(NULL),
62
+	thread(NULL)
63
+    {}
58 64
   };
59 65
 
60
-  typedef std::map<int, StreamInfo, greater<int> > Streams;
66
+  typedef std::map<int, StreamInfo> Streams;
67
+
68
+  struct event_base* ev_base;
69
+  struct event*      ev_default;
61 70
 
62 71
   Streams  streams;
63 72
   AmMutex  streams_mut;
64 73
 
65
-  struct pollfd* fds;
66
-  unsigned int   nfds;
67
-    
74
+  AmSharedVar<bool> stop_requested;
75
+
76
+  static void _rtp_receiver_read_cb(evutil_socket_t sd, short what, void* arg);
77
+
78
+public:    
68 79
   AmRtpReceiverThread();
69 80
   ~AmRtpReceiverThread();
70 81
     
71 82
   void run();
72 83
   void on_stop();
73
-  AmSharedVar<bool> stop_requested;
74 84
 
75 85
   void addStream(int sd, AmRtpStream* stream);
76 86
   void removeStream(int sd);
77 87
 
78 88
   void stop_and_wait();
79
-
80
-  friend class _AmRtpReceiver;
81 89
 };
82 90
 
83 91
 class _AmRtpReceiver
... ...
@@ -361,6 +361,7 @@ bool AmSipDialog::onRxReplyStatus(const AmSipReply& reply,
361 361
 	  DBG("received 2xx reply without to-tag "
362 362
 	      "(callid=%s): sending BYE\n",reply.callid.c_str());
363 363
 
364
+	  send_200_ack(reply.cseq);
364 365
 	  sendRequest(SIP_METH_BYE);
365 366
 	}
366 367
 	else {
... ...
@@ -50,6 +50,7 @@ core: $(OBJS) ../Makefile.defs
50 50
 include ../Makefile.defs
51 51
 
52 52
 CPPFLAGS += -I$(COREPATH) -fno-strict-aliasing
53
+LDFLAGS += -levent -levent_pthreads
53 54
 
54 55
 ifdef USE_LIBSAMPLERATE
55 56
 CPPFLAGS += -DUSE_LIBSAMPLERATE
... ...
@@ -46,6 +46,7 @@
46 46
 #include "sip/msg_hdrs.h"
47 47
 #include "sip/udp_trsp.h"
48 48
 #include "sip/ip_util.h"
49
+#include "sip/tcp_trsp.h"
49 50
 
50 51
 #include "log.h"
51 52
 
... ...
@@ -60,6 +61,108 @@
60 61
 bool _SipCtrlInterface::log_parsed_messages = true;
61 62
 int _SipCtrlInterface::udp_rcvbuf = -1;
62 63
 
64
+int _SipCtrlInterface::alloc_udp_structs()
65
+{
66
+    udp_sockets = new udp_trsp_socket*[ AmConfig::SIP_Ifs.size() ];
67
+    udp_servers = new udp_trsp* [ AmConfig::SIPServerThreads
68
+				  * AmConfig::SIP_Ifs.size() ];
69
+
70
+    if(udp_sockets && udp_servers)
71
+	return 0;
72
+
73
+    return -1;
74
+}
75
+
76
+int _SipCtrlInterface::init_udp_servers(int if_num)
77
+{
78
+    udp_trsp_socket* udp_socket = 
79
+	new udp_trsp_socket(if_num,AmConfig::SIP_Ifs[if_num].SigSockOpts
80
+			    | (AmConfig::ForceOutboundIf ? 
81
+			       trsp_socket::force_outbound_if : 0)
82
+			    | (AmConfig::UseRawSockets ?
83
+			       trsp_socket::use_raw_sockets : 0),
84
+			    AmConfig::SIP_Ifs[if_num].NetIfIdx);
85
+	
86
+    if(!AmConfig::SIP_Ifs[if_num].PublicIP.empty()) {
87
+	udp_socket->set_public_ip(AmConfig::SIP_Ifs[if_num].PublicIP);
88
+    }
89
+
90
+    if(udp_socket->bind(AmConfig::SIP_Ifs[if_num].LocalIP,
91
+			AmConfig::SIP_Ifs[if_num].LocalPort) < 0){
92
+
93
+	ERROR("Could not bind SIP/UDP socket to %s:%i",
94
+	      AmConfig::SIP_Ifs[if_num].LocalIP.c_str(),
95
+	      AmConfig::SIP_Ifs[if_num].LocalPort);
96
+
97
+	delete udp_socket;
98
+	return -1;
99
+    }
100
+
101
+    if(udp_rcvbuf > 0) {
102
+	udp_socket->set_recvbuf_size(udp_rcvbuf);
103
+    }
104
+
105
+    trans_layer::instance()->register_transport(udp_socket);
106
+    udp_sockets[if_num] = udp_socket;
107
+    inc_ref(udp_socket);
108
+    nr_udp_sockets++;
109
+
110
+    for(int j=0; j<AmConfig::SIPServerThreads;j++){
111
+	udp_servers[if_num * AmConfig::SIPServerThreads + j] = 
112
+	    new udp_trsp(udp_socket);
113
+	nr_udp_servers++;
114
+    }
115
+
116
+    return 0;
117
+}
118
+
119
+int _SipCtrlInterface::alloc_tcp_structs()
120
+{
121
+    tcp_sockets = new tcp_server_socket*[ AmConfig::SIP_Ifs.size() ];
122
+    tcp_servers = new tcp_trsp* [ AmConfig::SIP_Ifs.size() ];
123
+
124
+    if(tcp_sockets && tcp_servers)
125
+	return 0;
126
+
127
+    return -1;
128
+}
129
+
130
+int _SipCtrlInterface::init_tcp_servers(int if_num)
131
+{
132
+    tcp_server_socket* tcp_socket = new tcp_server_socket(if_num);
133
+
134
+    if(!AmConfig::SIP_Ifs[if_num].PublicIP.empty()) {
135
+     	tcp_socket->set_public_ip(AmConfig::SIP_Ifs[if_num].PublicIP);
136
+    }
137
+
138
+    tcp_socket->set_connect_timeout(AmConfig::SIP_Ifs[if_num].tcp_connect_timeout);
139
+    tcp_socket->set_idle_timeout(AmConfig::SIP_Ifs[if_num].tcp_idle_timeout);
140
+
141
+    if(tcp_socket->bind(AmConfig::SIP_Ifs[if_num].LocalIP,
142
+			AmConfig::SIP_Ifs[if_num].LocalPort) < 0){
143
+
144
+	ERROR("Could not bind SIP/TCP socket to %s:%i",
145
+	      AmConfig::SIP_Ifs[if_num].LocalIP.c_str(),
146
+	      AmConfig::SIP_Ifs[if_num].LocalPort);
147
+
148
+	delete tcp_socket;
149
+	return -1;
150
+    }
151
+
152
+    //TODO: add some more threads
153
+    tcp_socket->add_threads(AmConfig::SIPServerThreads);
154
+
155
+    trans_layer::instance()->register_transport(tcp_socket);
156
+    tcp_sockets[if_num] = tcp_socket;
157
+    inc_ref(tcp_socket);
158
+    nr_tcp_sockets++;
159
+
160
+    tcp_servers[if_num] = new tcp_trsp(tcp_socket);
161
+    nr_tcp_servers++;
162
+
163
+    return 0;
164
+}
165
+
63 166
 int _SipCtrlInterface::load()
64 167
 {
65 168
     if (!AmConfig::OutboundProxy.empty()) {
... ...
@@ -119,48 +222,27 @@ int _SipCtrlInterface::load()
119 222
 	DBG("assuming SIP default settings.\n");
120 223
     }
121 224
 
122
-    udp_sockets = new udp_trsp_socket*[AmConfig::SIP_Ifs.size()];
123
-    udp_servers = new udp_trsp*[AmConfig::SIPServerThreads * AmConfig::SIP_Ifs.size()];
225
+    if(alloc_udp_structs() < 0) {
226
+	ERROR("no enough memory to alloc UDP structs");
227
+	return -1;
228
+    }
124 229
 
125
-    // Init transport instances
230
+    // Init UDP transport instances
126 231
     for(unsigned int i=0; i<AmConfig::SIP_Ifs.size();i++) {
127
-
128
-	udp_trsp_socket* udp_socket = 
129
-	    new udp_trsp_socket(i,AmConfig::SIP_Ifs[i].SigSockOpts
130
-				| (AmConfig::ForceOutboundIf ? 
131
-				   trsp_socket::force_outbound_if : 0)
132
-				| (AmConfig::UseRawSockets ?
133
-				   trsp_socket::use_raw_sockets : 0),
134
-				AmConfig::SIP_Ifs[i].NetIfIdx);
135
-	
136
-	if(!AmConfig::SIP_Ifs[i].PublicIP.empty()) {
137
-	    udp_socket->set_public_ip(AmConfig::SIP_Ifs[i].PublicIP);
138
-	}
139
-
140
-	if(udp_socket->bind(AmConfig::SIP_Ifs[i].LocalIP,
141
-			    AmConfig::SIP_Ifs[i].LocalPort) < 0){
142
-
143
-	    ERROR("Could not bind SIP/UDP socket to %s:%i",
144
-		  AmConfig::SIP_Ifs[i].LocalIP.c_str(),
145
-		  AmConfig::SIP_Ifs[i].LocalPort);
146
-
147
-	    delete udp_socket;
232
+	if(init_udp_servers(i) < 0) {
148 233
 	    return -1;
149 234
 	}
235
+    }
150 236
 
151
-	if(udp_rcvbuf > 0) {
152
-	    udp_socket->set_recvbuf_size(udp_rcvbuf);
153
-	}
154
-
155
-	trans_layer::instance()->register_transport(udp_socket);
156
-	udp_sockets[i] = udp_socket;
157
-	inc_ref(udp_socket);
158
-	nr_udp_sockets++;
237
+    if(alloc_tcp_structs() < 0) {
238
+	ERROR("no enough memory to alloc TCP structs");
239
+	return -1;
240
+    }
159 241
 
160
-	for(int j=0; j<AmConfig::SIPServerThreads;j++){
161
-	    udp_servers[i*AmConfig::SIPServerThreads + j] = 
162
-		new udp_trsp(udp_socket);
163
-	    nr_udp_servers++;
242
+    // Init TCP transport instances
243
+    for(unsigned int i=0; i<AmConfig::SIP_Ifs.size();i++) {
244
+	if(init_tcp_servers(i) < 0) {
245
+	    return -1;
164 246
 	}
165 247
     }
166 248
 
... ...
@@ -168,8 +250,11 @@ int _SipCtrlInterface::load()
168 250
 }
169 251
 
170 252
 _SipCtrlInterface::_SipCtrlInterface()
171
-    : stopped(false), udp_servers(NULL), udp_sockets(NULL),
172
-      nr_udp_sockets(0), nr_udp_servers(0)
253
+    : stopped(false),
254
+      udp_servers(NULL), udp_sockets(NULL),
255
+      nr_udp_sockets(0), nr_udp_servers(0),
256
+      tcp_servers(NULL), tcp_sockets(NULL),
257
+      nr_tcp_sockets(0), nr_tcp_servers(0)
173 258
 {
174 259
     trans_layer::instance()->register_ua(this);
175 260
 }
... ...
@@ -300,6 +385,12 @@ int _SipCtrlInterface::run()
300 385
 	}
301 386
     }
302 387
 
388
+    if (NULL != tcp_servers) {
389
+	for(int i=0; i<nr_tcp_servers;i++){
390
+	    tcp_servers[i]->start();
391
+	}
392
+    }
393
+
303 394
     while (!stopped.get()) {
304 395
         stopped.wait_for();
305 396
     }
... ...
@@ -329,11 +420,22 @@ void _SipCtrlInterface::cleanup()
329 420
 	nr_udp_servers = 0;
330 421
     }
331 422
 
423
+    if (NULL != tcp_servers) {
424
+	for(int i=0; i<nr_tcp_servers;i++){
425
+	    tcp_servers[i]->stop();
426
+	    tcp_servers[i]->join();
427
+	    delete tcp_servers[i];
428
+	}
429
+
430
+	delete [] tcp_servers;
431
+	tcp_servers = NULL;
432
+	nr_tcp_servers = 0;
433
+    }
434
+
332 435
     trans_layer::instance()->clear_transports();
333 436
 
334 437
     if (NULL != udp_sockets) {
335 438
 	for(int i=0; i<nr_udp_sockets;i++){
336
-	    //delete udp_sockets[i];
337 439
 	    DBG("dec_ref(%p)",udp_sockets[i]);
338 440
 	    dec_ref(udp_sockets[i]);
339 441
 	}
... ...
@@ -342,6 +444,17 @@ void _SipCtrlInterface::cleanup()
342 444
 	udp_sockets = NULL;
343 445
 	nr_udp_sockets = 0;
344 446
     }
447
+
448
+    if (NULL != tcp_sockets) {
449
+	for(int i=0; i<nr_tcp_sockets;i++){
450
+	    DBG("dec_ref(%p)",tcp_sockets[i]);
451
+	    dec_ref(tcp_sockets[i]);
452
+	}
453
+
454
+	delete [] tcp_sockets;
455
+	tcp_sockets = NULL;
456
+	nr_tcp_sockets = 0;
457
+    }
345 458
 }
346 459
 
347 460
 int _SipCtrlInterface::send(const AmSipReply &rep, const string& dialog_id,
... ...
@@ -369,8 +482,6 @@ int _SipCtrlInterface::send(const AmSipReply &rep, const string& dialog_id,
369 482
 	}
370 483
     }
371 484
 
372
-    unsigned int hdrs_len = copy_hdrs_len(msg.hdrs);
373
-
374 485
     string body;
375 486
     string content_type;
376 487
     if(!rep.body.empty()) {
... ...
@@ -380,34 +491,18 @@ int _SipCtrlInterface::send(const AmSipReply &rep, const string& dialog_id,
380 491
     	    ERROR("Reply does not contain a Content-Type whereby body is not empty\n");
381 492
     	    return -1;
382 493
     	}
383
-	hdrs_len += content_type_len(stl2cstr(content_type));
494
+	msg.body = stl2cstr(body);
495
+	msg.hdrs.push_back(new sip_header(sip_header::H_CONTENT_TYPE,
496
+					  SIP_HDR_CONTENT_TYPE,
497
+					  stl2cstr(content_type)));
384 498
     }
385 499
 
386
-    char* hdrs_buf = NULL;
387
-    char* c = hdrs_buf;
500
+    msg.u.reply = new sip_reply(rep.code,stl2cstr(rep.reason));
388 501
 
389
-    if (hdrs_len) {
390
-	
391
-	c = hdrs_buf = new char[hdrs_len];
392
-	
393
-	copy_hdrs_wr(&c,msg.hdrs);
394
-		
395
-	if(!rep.body.empty()) {
396
-	    content_type_wr(&c,stl2cstr(content_type));
397
-	}
398
-    }
399
-
400
-    int ret =
401
-	trans_layer::instance()->send_reply((trans_ticket*)&rep.tt,
502
+    return
503
+	trans_layer::instance()->send_reply(&msg,(trans_ticket*)&rep.tt,
402 504
 					    stl2cstr(dialog_id),
403
-					    rep.code,stl2cstr(rep.reason),
404
-					    stl2cstr(rep.to_tag),
405
-					    cstring(hdrs_buf,hdrs_len), 
406
-					    stl2cstr(body),logger);
407
-
408
-    delete [] hdrs_buf;
409
-
410
-    return ret;
505
+					    stl2cstr(rep.to_tag),logger);
411 506
 }
412 507
 
413 508
 
... ...
@@ -642,6 +737,9 @@ inline bool _SipCtrlInterface::sip_msg2am_reply(sip_msg *msg, AmSipReply &reply)
642 737
     reply.local_ip = get_addr_str(&msg->local_ip);
643 738
     reply.local_port = am_get_port(&msg->local_ip);
644 739
 
740
+    if(msg->local_socket)
741
+	reply.trsp = msg->local_socket->get_transport();
742
+
645 743
     return true;
646 744
 }
647 745
 
... ...
@@ -48,6 +48,9 @@ class trans_ticket;
48 48
 class udp_trsp_socket;
49 49
 class udp_trsp;
50 50
 
51
+class tcp_server_socket;
52
+class tcp_trsp;
53
+
51 54
 class _SipCtrlInterface:
52 55
     public sip_ua
53 56
 {
... ...
@@ -67,6 +70,18 @@ class _SipCtrlInterface:
67 70
     unsigned short    nr_udp_servers;
68 71
     udp_trsp**        udp_servers;
69 72
 
73
+    unsigned short    nr_tcp_sockets;
74
+    tcp_server_socket** tcp_sockets;
75
+
76
+    unsigned short    nr_tcp_servers;
77
+    tcp_trsp**        tcp_servers;
78
+
79
+    int alloc_udp_structs();
80
+    int init_udp_servers(int if_num);
81
+
82
+    int alloc_tcp_structs();
83
+    int init_tcp_servers(int if_num);
84
+
70 85
 public:
71 86
 
72 87
     static string outbound_host;
... ...
@@ -53,12 +53,12 @@
53 53
 #include <grp.h>
54 54
 #include <pwd.h>
55 55
 
56
-//#include <sys/wait.h>
57
-//#include <sys/socket.h>
58 56
 #include <sys/types.h>
59 57
 #include <sys/stat.h>
60 58
 #include <fcntl.h>
61 59
 
60
+#include <event2/thread.h>
61
+
62 62
 #ifdef PROPAGATE_COREDUMP_SETTINGS
63 63
 #include <sys/resource.h>
64 64
 #include <sys/prctl.h>
... ...
@@ -572,11 +572,20 @@ int main(int argc, char* argv[])
572 572
   INFO("Starting media processor\n");
573 573
   AmMediaProcessor::instance()->init();
574 574
 
575
+  // init thread usage with libevent
576
+  // before it's too late
577
+  if(evthread_use_pthreads() != 0) {
578
+    ERROR("cannot init thread usage with libevent");
579
+    goto error;
580
+  }
581
+
575 582
   INFO("Starting RTP receiver\n");
576 583
   AmRtpReceiver::instance()->start();
577 584
 
578 585
   INFO("Starting SIP stack (control interface)\n");
579
-  sip_ctrl.load();
586
+  if(sip_ctrl.load()) {
587
+    goto error;
588
+  }
580 589
   
581 590
   INFO("Loading plug-ins\n");
582 591
   AmPlugIn::instance()->init();
... ...
@@ -59,6 +59,27 @@ int  copy_hdrs_len_no_via(const list<sip_header*>& hdrs)
59 59
     return ret;
60 60
 }
61 61
 
62
+int  copy_hdrs_len_no_via_contact(const list<sip_header*>& hdrs)
63
+{
64
+    int ret = 0;
65
+
66
+    list<sip_header*>::const_iterator it = hdrs.begin();
67
+    for(;it != hdrs.end(); ++it){
68
+
69
+      switch((*it)->type) {
70
+      case sip_header::H_VIA:
71
+      case sip_header::H_CONTACT:
72
+	continue;
73
+
74
+      default:
75
+	ret += copy_hdr_len(*it);
76
+	break;
77
+      }
78
+    }
79
+    
80
+    return ret;
81
+}
82
+
62 83
 void copy_hdrs_wr(char** c, const list<sip_header*>& hdrs)
63 84
 {
64 85
     list<sip_header*>::const_iterator it = hdrs.begin();
... ...
@@ -77,3 +98,20 @@ void copy_hdrs_wr_no_via(char** c, const list<sip_header*>& hdrs)
77 98
         copy_hdr_wr(c,*it);
78 99
     }
79 100
 }
101
+
102
+void copy_hdrs_wr_no_via_contact(char** c, const list<sip_header*>& hdrs)
103
+{
104
+    list<sip_header*>::const_iterator it = hdrs.begin();
105
+    for(;it != hdrs.end(); ++it){
106
+
107
+      switch((*it)->type) {
108
+      case sip_header::H_VIA:
109
+      case sip_header::H_CONTACT:
110
+	continue;
111
+
112
+      default:
113
+	copy_hdr_wr(c,*it);
114
+	break;
115
+      }
116
+    }
117
+}
... ...
@@ -73,20 +73,30 @@ inline void contact_wr(char** c,const cstring& contact)
73 73
     *((*c)++) = LF;
74 74
 }
75 75
 
76
-inline int via_len(const cstring& addr, const cstring& branch, bool rport)
76
+inline int via_len(const cstring& trsp, const cstring& addr, 
77
+		   const cstring& branch, bool rport)
77 78
 {
78
-    return 19/*'Via: SIP/2.0/UDP ' + CRLF*/
79
+    return 16/* 'Via: SIP/2.0/' + SP + CRLF */
80
+        + trsp.len
79 81
 	+ addr.len
80 82
 	+ 8 + MAGIC_BRANCH_LEN/*';branch=' + MAGIC_BRANCH_COOKIE*/
81 83
 	+ branch.len
82 84
         + (rport ? 6/*;rport*/ : 0 );
83 85
 }
84 86
 
85
-inline void via_wr(char** c, const cstring& addr, const cstring& branch, bool rport)
87
+inline void via_wr(char** c, const cstring& trsp, const cstring& addr, 
88
+		   const cstring& branch, bool rport)
86 89
 {
87
-    memcpy(*c,"Via: SIP/2.0/UDP ",17);
88
-    *c += 17/*'Via: SIP/2.0/UDP '*/;
90
+    memcpy(*c,"Via: SIP/2.0/",13);
91
+    *c += 13/*'Via: SIP/2.0/'*/;
92
+
93
+    for(unsigned int i=0; i<trsp.len; i++) {
94
+      if(trsp.s[i] >= 'a' && trsp.s[i] <= 'z')
95
+	*((*c)++) = trsp.s[i] - 'a' + 'A';
96
+    }
89 97
     
98
+    *((*c)++) = SP;
99
+
90 100
     memcpy(*c,addr.s,addr.len);
91 101
     *c += addr.len;
92 102
 
... ...
@@ -169,10 +179,11 @@ using std::list;
169 179
 
170 180
 
171 181
 int  copy_hdrs_len(const list<sip_header*>& hdrs);
172
-int  copy_hdrs_len_no_via(const list<sip_header*>& hdrs);
182
+int  copy_hdrs_len_no_via_contact(const list<sip_header*>& hdrs);
173 183
 
174 184
 void copy_hdrs_wr(char** c, const list<sip_header*>& hdrs);
175 185
 void copy_hdrs_wr_no_via(char** c, const list<sip_header*>& hdrs);
186
+void copy_hdrs_wr_no_via_contact(char** c, const list<sip_header*>& hdrs);
176 187
 
177 188
 
178 189
 #endif
... ...
@@ -113,8 +113,7 @@ using std::list;
113 113
 enum {
114 114
     ST_CR=100,
115 115
     ST_LF,
116
-    ST_CRLF,
117
-    ST_EoL_WSP // [CR] LF WSP
116
+    ST_CRLF
118 117
 };
119 118
 
120 119
 #define case_CR_LF \
... ...
@@ -184,6 +183,11 @@ inline int lower_cmp_n(const char* l, int llen, const char* r, int rlen)
184 183
     return lower_cmp(l,r,rlen);
185 184
 }
186 185
 
186
+inline int lower_cmp_n(const cstring& l, const cstring& r)
187
+{
188
+    return lower_cmp_n(l.s,l.len,r.s,r.len);
189
+}
190
+
187 191
 int parse_sip_version(const char* beg, int len);
188 192
 
189 193
 /** 
... ...
@@ -80,6 +80,8 @@ struct sip_header
80 80
     ~sip_header();
81 81
 };
82 82
 
83
+int parse_header_type(sip_header* h);
84
+
83 85
 int parse_headers(list<sip_header*>& hdrs, char** c, char* end);
84 86
 void free_headers(list<sip_header*>& hdrs);
85 87
 
... ...
@@ -229,6 +229,23 @@ int parse_nameaddr(sip_nameaddr* na, const char** c, int len)
229 229
     return parse_gen_params_sc(&na->params,c, end-*c, 0);
230 230
 }
231 231
 
232
+int parse_nameaddr_uri(sip_nameaddr* na, const char** c, int len)
233
+{
234
+    if(parse_nameaddr(na, c, len) < 0) {
235
+      
236
+      DBG("Parsing name-addr failed\n");
237
+      return -1;
238
+    }
239
+    
240
+    if(parse_uri(&na->uri,na->addr.s,na->addr.len) < 0) {
241
+	
242
+	DBG("Parsing uri failed\n");
243
+	return -1;
244
+    }
245
+
246
+    return 0;
247
+}
248
+
232 249
 static int skip_2_next_nameaddr(const char*& c, 
233 250
 				const char*& na_end,
234 251
 				const char*  end)
... ...
@@ -45,6 +45,7 @@ struct sip_nameaddr
45 45
 };
46 46
 
47 47
 int parse_nameaddr(sip_nameaddr* na, const char** c, int len);
48
+int parse_nameaddr_uri(sip_nameaddr* na, const char** c, int len);
48 49
 int parse_first_nameaddr(sip_nameaddr* na, const char* c, int len);
49 50
 int parse_nameaddr_list(list<cstring>& nas, const char* c, int len);
50 51
 
... ...
@@ -12,7 +12,6 @@ int parse_next_hop(const cstring& next_hop,
12 12
     IPL_V6,
13 13
     IPL_HOST_SEP,
14 14
     IPL_PORT,
15
-    IPL_TRSP_SEP,
16 15
     IPL_TRSP
17 16
   };
18 17
 
... ...
@@ -54,6 +53,7 @@ int parse_next_hop(const cstring& next_hop,
54 53
       case '/':
55 54
 	st = IPL_TRSP;
56 55
 	dest.host.set(beg,c-beg);
56
+	beg = c+1;
57 57
 	break;
58 58
       case ',':
59 59
 	st = IPL_BEG;
... ...
@@ -91,7 +91,8 @@ int parse_next_hop(const cstring& next_hop,
91 91
 	dest_list.push_back(dest);
92 92
 	break;
93 93
       case '/':
94
-	st = IPL_TRSP_SEP;
94
+	st = IPL_TRSP;
95
+	beg = c+1;
95 96
 	break;
96 97
       default:
97 98
 	// syntax error
... ...
@@ -103,7 +104,8 @@ int parse_next_hop(const cstring& next_hop,
103 104
     case IPL_PORT:
104 105
       switch(*c){
105 106
       case '/':
106
-	st = IPL_TRSP_SEP;
107
+	st = IPL_TRSP;
108
+	beg = c+1;
107 109
 	break;
108 110
       case ',':
109 111
 	st = IPL_BEG;
... ...
@@ -122,21 +124,6 @@ int parse_next_hop(const cstring& next_hop,
122 124
       }
123 125
       break;
124 126
 
125
-    case IPL_TRSP_SEP:
126
-      switch(*c){
127
-      case ',':
128
-	st = IPL_BEG;
129
-	dest_list.push_back(dest);
130
-	break;
131
-      case SP:
132
-      case HTAB:
133
-	break;
134
-      default:
135
-	beg = c;
136
-	st = IPL_TRSP;
137
-	break;
138
-      }
139
-      break;
140 127
 
141 128
     case IPL_TRSP:
142 129
       switch(*c){
... ...
@@ -179,11 +179,6 @@ static int parse_sip_uri(sip_uri* uri, const char* beg, int len)
179 179
 		//    tmp1.len, tmp1.s,
180 180
 		//    tmp2.len, tmp2.s);
181 181
 
182
-		if(!lower_cmp_n(tmp1.s,tmp1.len,
183
-				"transport",9)) {
184
-		    uri->trsp = uri->params.back();
185
-		}
186
-
187 182
 		tmp1.s = c+1;
188 183
 		st = URI_PNAME;
189 184
 		break;
... ...
@@ -342,6 +337,15 @@ static int parse_sip_uri(sip_uri* uri, const char* beg, int len)
342 337
     DBG("Converted URI port (%.*s) to int (%i)\n",
343 338
 	uri->port_str.len,uri->port_str.s,uri->port);
344 339
 
340
+    for(list<sip_avp*>::iterator it = uri->params.begin();
341
+	it != uri->params.end(); it++) {
342
+
343
+	if(!lower_cmp_n((*it)->name.s,(*it)->name.len,
344
+			"transport",9)) {
345
+	    uri->trsp = *it;
346
+	}
347
+    }
348
+
345 349
     return 0;
346 350
 }
347 351
 
... ...
@@ -43,10 +43,10 @@ int raw_sender::send(const char* buf, unsigned int len, int sys_if_idx,
43 43
     return ret;
44 44
   }
45 45
 
46
-  if((unsigned int)ret < len) {
47
-    DBG("incomplete udp send (%i instead of %i)",ret,len);
48
-    return -1;
49
-  }
46
+  // if((unsigned int)ret < len) {
47
+  //   ERROR("incomplete udp send (%i instead of %i)",ret,len);
48
+  //   return -1;
49
+  // }
50 50
 
51 51
   return 0;
52 52
 }
... ...
@@ -31,7 +31,10 @@
31 31
 #include "hash.h"
32 32
 
33 33
 #include "parse_dns.h"
34
+#include "parse_common.h"
34 35
 #include "ip_util.h"
36
+#include "trans_layer.h"
37
+#include "tr_blacklist.h"
35 38
 
36 39
 #include <sys/socket.h> 
37 40
 #include <netdb.h>
... ...
@@ -95,7 +98,8 @@ int dns_ip_entry::next_ip(dns_handle* h, sockaddr_storage* sa)
95 98
     }
96 99
     
97 100
     int& index = h->ip_n;
98
-    if(index >= (int)ip_vec.size()) return -1;
101
+    if((index < 0) || (index >= (int)ip_vec.size()))
102
+	return -1;
99 103
     
100 104
     //copy address
101 105
     ((ip_entry*)ip_vec[index++])->to_sa(sa);
... ...
@@ -176,8 +180,6 @@ public:
176 180
     int next_ip(dns_handle* h, sockaddr_storage* sa)
177 181
     {
178 182
 	int& index = h->srv_n;
179
-	if(index >= (int)ip_vec.size()) return -1;
180
-	
181 183
 	if(h->srv_e != this){
182 184
 	    if(h->srv_e) dec_ref(h->srv_e);
183 185
 	    h->srv_e = this;
... ...
@@ -186,15 +188,17 @@ public:
186 188
 	}
187 189
 	else if(h->ip_n != -1){
188 190
 	    if(h->port) {
189
-		DBG("setting port to %i",ntohs(h->port));
190 191
 		((sockaddr_in*)sa)->sin_port = h->port;
191 192
 	    }
192 193
 	    else {
193
-		DBG("setting port to 5060");
194 194
 		((sockaddr_in*)sa)->sin_port = htons(5060);
195 195
 	    }
196 196
 	    return h->ip_e->next_ip(h,sa);
197 197
 	}
198
+
199
+	if((index < 0) ||
200
+	   (index >= (int)ip_vec.size()))
201
+	    return -1;
198 202
 	
199 203
 	// reset IP record
200 204
 	if(h->ip_e){
... ...
@@ -269,24 +273,20 @@ public:
269 273
 	//TODO: find a solution for IPv6
270 274
 	h->port = htons(e->port);
271 275
 	if(h->port) {
272
-	    DBG("setting port to %i",e->port);
273 276
 	    ((sockaddr_in*)sa)->sin_port = h->port;
274 277
 	}
275 278
 	else {
276
-	    DBG("setting port to 5060");
277 279
 	    ((sockaddr_in*)sa)->sin_port = htons(5060);
278 280
 	}
279 281
 
280 282
 	// check if name is an IP address
281 283
 	if(am_inet_pton(e->target.c_str(),sa) == 1) {
282
-	    DBG("target is an IP address !!! (%i)",
283
-		ntohs(((sockaddr_in*)sa)->sin_port));
284
+	    // target is an IP address
284 285
 	    h->ip_n = -1; // flag end of IP list
285 286
 	    return 0;
286 287
 	}
287 288
 
288
-	DBG("target must be resolved first !!! (%i)",
289
-	    ntohs(((sockaddr_in*)sa)->sin_port));
289
+	// target must be resolved first
290 290
 	return resolver::instance()->resolve_name(e->target.c_str(),h,sa,IPv4);
291 291
     }
292 292
 };
... ...
@@ -417,7 +417,6 @@ static void dns_error(int error, const char* domain)
417 417
 
418 418
 void ip_entry::to_sa(sockaddr_storage* sa)
419 419
 {
420
-    DBG("copying ip_entry...");
421 420
     switch(type){
422 421
     case IPv4:
423 422
 	{
... ...
@@ -438,7 +437,6 @@ void ip_entry::to_sa(sockaddr_storage* sa)
438 437
 
439 438
 void ip_port_entry::to_sa(sockaddr_storage* sa)
440 439
 {
441
-    DBG("copying ip_port_entry...");
442 440
     switch(type){
443 441
     case IPv4:
444 442
 	{
... ...
@@ -596,6 +594,84 @@ const dns_handle& dns_handle::operator = (const dns_handle& rh)
596 594
     return *this;
597 595
 }
598 596
 
597
+sip_target::sip_target() {}
598
+
599
+sip_target::sip_target(const sip_target& target)
600
+{
601
+    *this = target;
602
+}
603
+
604
+const sip_target& sip_target::operator = (const sip_target& target)
605
+{
606
+    memcpy(&ss,&target.ss,sizeof(sockaddr_storage));
607
+    memcpy(trsp,target.trsp,SIP_TRSP_SIZE_MAX+1);
608
+    return target;
609
+}
610
+
611
+void sip_target::clear()
612
+{
613
+    memset(&ss,0,sizeof(sockaddr_storage));
614
+    memset(trsp,'\0',SIP_TRSP_SIZE_MAX+1);
615
+}
616
+
617
+sip_target_set::sip_target_set()
618
+    : dest_list(),
619
+      dest_list_it(dest_list.begin())
620
+{}
621
+
622
+void sip_target_set::reset_iterator()
623
+{
624
+    dest_list_it = dest_list.begin();
625
+}
626
+
627
+bool sip_target_set::has_next()
628
+{
629
+    return dest_list_it != dest_list.end();
630
+}
631
+
632
+int sip_target_set::get_next(sockaddr_storage* ss, cstring& next_trsp,
633
+			     unsigned int flags)
634
+{
635
+    do {
636
+	if(!has_next())
637
+	    return -1;
638
+
639
+	sip_target& t = *dest_list_it;
640
+	memcpy(ss,&t.ss,sizeof(sockaddr_storage));
641
+	next_trsp = cstring(t.trsp);
642
+
643
+	next();
644
+
645
+	// set default transport to UDP
646
+	if(!next_trsp.len)
647
+	    next_trsp = cstring("udp");
648
+
649
+    } while(!(flags & TR_FLAG_DISABLE_BL) &&
650
+	    tr_blacklist::instance()->exist(ss));
651
+
652
+    return 0;
653
+}
654
+
655
+bool sip_target_set::next()
656
+{
657
+    dest_list_it++;
658
+    return has_next();
659
+}
660
+
661
+void sip_target_set::debug()
662
+{
663
+    DBG("target list:");
664
+
665
+    for(list<sip_target>::iterator it = dest_list.begin();
666
+	it != dest_list.end(); it++) {
667
+
668
+	DBG("\t%s:%u/%s to target list",
669
+	    am_inet_ntop(&it->ss).c_str(),
670
+	    am_get_port(&it->ss),it->trsp);
671
+    }
672
+}
673
+
674
+bool _resolver::disable_srv = false;
599 675
 
600 676
 _resolver::_resolver()
601 677
     : cache(DNS_CACHE_SIZE)
... ...
@@ -719,7 +795,8 @@ int _resolver::str2ip(const char* name,
719 795
 	    return 1;
720 796
 	}
721 797
 	else if(ret < 0) {
722
-	    ERROR("while trying to detect an IPv4 address '%s': %s",name,strerror(errno));
798
+	    ERROR("while trying to detect an IPv4 address '%s': %s",
799
+		  name,strerror(errno));
723 800
 	    return ret;
724 801
 	}
725 802
     }
... ...
@@ -731,7 +808,8 @@ int _resolver::str2ip(const char* name,
731 808
 	    return 1;
732 809
 	}
733 810
 	else if(ret < 0) {
734
-	    ERROR("while trying to detect an IPv6 address '%s': %s",name,strerror(errno));
811
+	    ERROR("while trying to detect an IPv6 address '%s': %s",
812
+		  name,strerror(errno));
735 813
 	    return ret;
736 814
 	}
737 815
     }
... ...
@@ -739,6 +817,113 @@ int _resolver::str2ip(const char* name,
739 817
     return 0;
740 818
 }
741 819
 
820
+int _resolver::set_destination_ip(const cstring& next_hop,
821
+				  unsigned short next_port,
822
+				  const cstring& next_trsp,
823
+				  sockaddr_storage* remote_ip,
824
+				  dns_handle* h_dns)
825
+{
826
+
827
+    string nh = c2stlstr(next_hop);
828
+
829
+    DBG("checking whether '%s' is IP address...\n", nh.c_str());
830
+    if (am_inet_pton(nh.c_str(), remote_ip) != 1) {
831
+
832
+	// nh does NOT contain a valid IP address
833
+    
834
+	if(!next_port) {
835
+	    // no explicit port specified,
836
+	    // try SRV first
837
+	    if (disable_srv) {
838
+		DBG("no port specified, but DNS SRV disabled (skipping).\n");
839
+	    } else {
840
+		string srv_name = "_sip._";
841
+		if(!next_trsp.len || !lower_cmp_n(next_trsp,"udp")){
842
+		    srv_name += "udp";
843
+		}
844
+		else if(!lower_cmp_n(next_trsp,"tcp")) {
845
+		    srv_name += "tcp";
846
+		}
847
+		else {
848
+		    DBG("unsupported transport: skip SRV lookup");
849
+		    goto no_SRV;
850
+		}
851
+
852
+		srv_name += "." + nh;
853
+
854
+		DBG("no port specified, looking up SRV '%s'...\n",
855
+		    srv_name.c_str());
856
+
857
+		if(!resolver::instance()->resolve_name(srv_name.c_str(),
858
+						       h_dns,remote_ip,
859
+						       IPv4)){
860
+		    return 0;
861
+		}
862
+
863
+		DBG("no SRV record for %s",srv_name.c_str());
864
+	    }
865
+	}
866
+
867
+    no_SRV:
868
+	memset(remote_ip,0,sizeof(sockaddr_storage));
869
+	int err = resolver::instance()->resolve_name(nh.c_str(),
870
+						     h_dns,remote_ip,
871
+						     IPv4);
872
+	if(err < 0){
873
+	    ERROR("Unresolvable Request URI domain\n");
874
+	    return -478;
875
+	}
876
+    }
877
+    else {
878
+	am_set_port(remote_ip,next_port);
879
+    }
880
+
881
+    if(!am_get_port(remote_ip)) {
882
+	if(!next_port) next_port = 5060;
883
+	am_set_port(remote_ip,next_port);
884
+    }
885
+
886
+    DBG("set destination to %s:%u\n",
887
+	nh.c_str(), am_get_port(remote_ip));
888
+    
889
+    return 0;
890
+}
891
+
892
+int _resolver::resolve_targets(const list<sip_destination>& dest_list,
893
+			       sip_target_set* targets)
894
+{
895
+    for(list<sip_destination>::const_iterator it = dest_list.begin();
896
+	it != dest_list.end(); it++) {
897
+	
898
+	sip_target t;
899
+	dns_handle h_dns;