Browse code

Merge remote-tracking branch 'frafos/1.6-dev'

* frafos/1.6-dev: (138 commits)
core q/f: quick hack to avoid crashes when destroying sip_msg with incorrect type
CDR: destination_ip added into CDR variables
dsm: b/f: mark systemDSM monitoring entry finished at the end
b/f: core: init monitoring interface used by core after loading modules
sbc:dsm: support for noAudio event
sip: b/f: fix segfault in try_next_ip()
b/f: initialize AmRtpStream::force_receive_dtmf
b/f:sbc:apply rtprelay_dtmf_filtering and rtprelay_dtmf_detection also on B leg
core: add Referred-By to AmSipDialog::refer()
dsm:mod_utils: added utils.escapeCRLF($var) and utils.unescapeCRLF($var)
sbc b/f: handle reINVITE within disconnected B2B call better way
sbc: b/f: fixed use of setting for unsolicited NOTIFY forwarding
core: made allowUnsolicitedNotify() virtual
core: move str2bool() to AmUtils
sbc:dsm: rtp_interface for addCallee
c/f: fix outbound interface evaluation
c/f: fix outbound interface sbc sm option
sbc:dsm: outbound_interface for addCallee new call mode
sbc:dsm: next_hop options for addCallee with new call mode
core/sbc: added support for subscription-less NOTIFY forwarding
...

Stefan Sayer authored on 21/02/2014 16:51:44
Showing 64 changed files
... ...
@@ -7,6 +7,8 @@
7 7
 #include "DSMStateDiagramCollection.h"
8 8
 #include "../apps/jsonrpc/JsonRPCEvents.h" // todo!
9 9
 #include "AmSipSubscription.h"
10
+#include "AmSessionContainer.h"
11
+#include "ampi/MonitoringAPI.h"
10 12
 
11 13
 SystemDSM::SystemDSM(const DSMScriptConfig& config,
12 14
 		     const string& startDiagName,
... ...
@@ -31,6 +33,11 @@ SystemDSM::~SystemDSM() {
31 33
   for (std::set<DSMDisposable*>::iterator it=
32 34
 	 gc_trash.begin(); it != gc_trash.end(); it++)
33 35
     delete *it;
36
+
37
+#ifdef USE_MONITORING
38
+  MONITORING_MARK_FINISHED(dummy_session.getLocalTag());
39
+#endif
40
+
34 41
 }
35 42
 
36 43
 void SystemDSM::run() {
... ...
@@ -1,3 +1,29 @@
1
+/*
2
+ * Copyright (C) 2010-2011 Stefan Sayer
3
+ * Copyright (C) 2012-2013 FRAFOS GmbH
4
+ *
5
+ * This file is part of SEMS, a free SIP media server.
6
+ *
7
+ * SEMS is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version.
11
+ *
12
+ * For a license to use the SEMS software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * SEMS is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License
23
+ * along with this program; if not, write to the Free Software
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ */
26
+
1 27
 #include "CallLeg.h"
2 28
 #include "AmSessionContainer.h"
3 29
 #include "AmConfig.h"
... ...
@@ -1,3 +1,28 @@
1
+/*
2
+ * Copyright (C) 2010-2011 Stefan Sayer
3
+ * Copyright (C) 2012-2013 FRAFOS GmbH
4
+ *
5
+ * This file is part of SEMS, a free SIP media server.
6
+ *
7
+ * SEMS is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version.
11
+ *
12
+ * For a license to use the SEMS software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * SEMS is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License
23
+ * along with this program; if not, write to the Free Software
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ */
1 26
 #ifndef __AMB2BCALL_H
2 27
 #define __AMB2BCALL_H
3 28
 
... ...
@@ -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;
... ...
@@ -409,9 +416,6 @@ int RegisterDialog::initUAC(const AmSipRequest& req, const SBCCallProfile& cp)
409 416
   
410 417
   fixUacContactHosts(req,cp);
411 418
 
412
-  // patch initial CSeq to fix re-REGISTER with transparent-id enabled
413
-  cseq = req.cseq;
414
-
415 419
   return 0;
416 420
 }
417 421
 
... ...
@@ -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();
... ...
@@ -1,3 +1,29 @@
1
+/*
2
+ * Copyright (C) 2010-2013 Stefan Sayer
3
+ * Copyright (C) 2012-2013 FRAFOS GmbH
4
+ *
5
+ * This file is part of SEMS, a free SIP media server.
6
+ *
7
+ * SEMS is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version.
11
+ *
12
+ * For a license to use the SEMS software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * SEMS is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License
23
+ * along with this program; if not, write to the Free Software
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ */
26
+
1 27
 #include "SBCCallLeg.h"
2 28
 
3 29
 #include "SBCCallControlAPI.h"
... ...
@@ -22,6 +48,7 @@
22 48
 #include "ParamReplacer.h"
23 49
 #include "SDPFilter.h"
24 50
 #include "SBCEventLog.h"
51
+#include "SBC.h"
25 52
 
26 53
 #include <algorithm>
27 54
 
... ...
@@ -156,12 +183,14 @@ SBCCallLeg::SBCCallLeg(SBCCallLeg* caller, AmSipDialog* p_dlg,
156 183
     throw AmSession::Exception(500, SIP_REPLY_SERVER_INTERNAL_ERROR);
157 184
   }
158 185
 
159
-  if (!initCCExtModules()) {
186
+  if (!initCCExtModules(call_profile.cc_interfaces, cc_modules)) {
160 187
     ERROR("initializing extended call control modules\n");
161 188
     throw AmSession::Exception(500, SIP_REPLY_SERVER_INTERNAL_ERROR);
162 189
   }
163 190
 
164 191
   setLogger(caller->getLogger());
192
+
193
+  subs->allowUnsolicitedNotify(call_profile.allow_subless_notify);
165 194
 }
166 195
 
167 196
 SBCCallLeg::SBCCallLeg(AmSipDialog* p_dlg, AmSipSubscription* p_subs)
... ...
@@ -783,7 +812,7 @@ void SBCCallLeg::onInvite(const AmSipRequest& req)
783 812
     throw AmSession::Exception(500, SIP_REPLY_SERVER_INTERNAL_ERROR);
784 813
   }
785 814
 
786
-  if (!initCCExtModules()) {
815
+  if (!initCCExtModules(call_profile.cc_interfaces, cc_modules)) {
787 816
     ERROR("initializing extended call control modules\n");
788 817
     throw AmSession::Exception(500, SIP_REPLY_SERVER_INTERNAL_ERROR);    
789 818
   }
... ...
@@ -804,7 +833,7 @@ void SBCCallLeg::onInvite(const AmSipRequest& req)
804 833
   }
805 834
   else if(call_profile.reg_caching) {
806 835
     // REG-Cache lookup
807
-    uac_req.r_uri = call_profile.retarget(req.user,*dlg);
836
+    uac_req.r_uri = call_profile.retarget(req.user);
808 837
   }
809 838
 
810 839
   ruri = call_profile.ruri.empty() ? uac_req.r_uri : call_profile.ruri;
... ...
@@ -869,10 +898,14 @@ void SBCCallLeg::onInvite(const AmSipRequest& req)
869 898
   if(a_leg && call_profile.keep_vias)
870 899
     invite_req.hdrs = invite_req.vias + invite_req.hdrs;
871 900
 
901
+  subs->allowUnsolicitedNotify(call_profile.allow_subless_notify);
902
+
872 903
   // call extend call controls
873 904
   InitialInviteHandlerParams params(to, ruri, from, &req, &invite_req);
874 905
   for (vector<ExtendedCCInterface*>::iterator i = cc_ext.begin(); i != cc_ext.end(); ++i) {
875 906
     (*i)->onInitialInvite(this, params);
907
+    // initialize possibily added modules
908
+    initPendingCCExtModules();
876 909
   }
877 910
 
878 911
   if (getCallStatus() == Disconnected) {
... ...
@@ -1514,15 +1547,19 @@ bool SBCCallLeg::reinvite(const AmSdp &sdp, unsigned &request_cseq)
1514 1547
   return true;
1515 1548
 }
1516 1549
 
1517
-bool SBCCallLeg::initCCExtModules()
1550
+/**
1551
+ * initialize modules from @arg cc_module_list with DI interface instances from @arg cc_module_di
1552
+ * add sucessfull ext-API call control instances to cc_ext
1553
+ * @return true on success (all modules properly initialized)
1554
+*/
1555
+bool SBCCallLeg::initCCExtModules(const CCInterfaceListT& cc_module_list, const vector<AmDynInvoke*>& cc_module_di)
1518 1556
 {
1519 1557
   // init extended call control modules
1520
-  vector<AmDynInvoke*>::iterator cc_mod = cc_modules.begin();
1521
-  for (CCInterfaceListIteratorT cc_it=call_profile.cc_interfaces.begin();
1522
-       cc_it != call_profile.cc_interfaces.end(); cc_it++)
1558
+  vector<AmDynInvoke*>::const_iterator cc_mod = cc_module_di.begin();
1559
+  for (CCInterfaceListConstIteratorT cc_it = cc_module_list.begin(); cc_it != cc_module_list.end(); cc_it++)
1523 1560
   {
1524
-    CCInterface& cc_if = *cc_it;
1525
-    string& cc_module = cc_it->cc_module;
1561
+    const CCInterface& cc_if = *cc_it;
1562
+    const string& cc_module = cc_it->cc_module;
1526 1563
 
1527 1564
     // get extended CC interface
1528 1565
     try {
... ...
@@ -1533,7 +1570,7 @@ bool SBCCallLeg::initCCExtModules()
1533 1570
         DBG("extended CC interface offered by cc_module '%s'\n", cc_module.c_str());
1534 1571
         // module initialization
1535 1572
         if (!iface->init(this, cc_if.cc_values)) {
1536
-	  ERROR("initializing extended call control interface\n");
1573
+	  ERROR("initializing extended call control interface '%s'\n", cc_module.c_str());
1537 1574
 	  return false;
1538 1575
 	}
1539 1576
 
... ...
@@ -1552,9 +1589,42 @@ bool SBCCallLeg::initCCExtModules()
1552 1589
 
1553 1590
     ++cc_mod;
1554 1591
   }
1592
+
1593
+  if (!initPendingCCExtModules()) {
1594
+    return false;
1595
+  }
1596
+
1555 1597
   return true; // success
1556 1598
 }
1557 1599
 
1600
+/** init pending modules until queue is empty */
1601
+bool SBCCallLeg::initPendingCCExtModules() {
1602
+  while (cc_module_queue.size()) {
1603
+    // local copy
1604
+    CCInterfaceListT _cc_mod_queue = cc_module_queue;
1605
+    cc_module_queue.clear();
1606
+    vector<AmDynInvoke*> _cc_mod_ifs;
1607
+
1608
+    // get corresponding DI interfaces
1609
+    if (!::getCCInterfaces(_cc_mod_queue, _cc_mod_ifs))
1610
+      return false;
1611
+
1612
+    // add to call leg
1613
+    if (!initCCExtModules(_cc_mod_queue, _cc_mod_ifs)) {
1614
+      return false;
1615
+    }
1616
+  }
1617
+  return true;
1618
+}
1619
+
1620
+void SBCCallLeg::addPendingCCExtModule(const string& cc_name, const string& cc_module, const map<string, string>& cc_values) {
1621
+  cc_module_queue.push_back(CCInterface(cc_name));
1622
+  cc_module_queue.back().cc_module = cc_module;
1623
+  cc_module_queue.back().cc_values = cc_values;
1624
+  DBG("added module '%s' from module '%s' to pending CC Ext modules\n",
1625
+      cc_name.c_str(), cc_module.c_str());
1626
+}
1627
+
1558 1628
 #define CALL_EXT_CC_MODULES(method) \
1559 1629
   do { \
1560 1630
     for (vector<ExtendedCCInterface*>::iterator i = cc_ext.begin(); i != cc_ext.end(); ++i) { \
... ...
@@ -1,3 +1,29 @@
1
+/*
2
+ * Copyright (C) 2010-2011 Stefan Sayer
3
+ * Copyright (C) 2012-2013 FRAFOS GmbH
4
+ *
5
+ * This file is part of SEMS, a free SIP media server.
6
+ *
7
+ * SEMS is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version.
11
+ *
12
+ * For a license to use the SEMS software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * SEMS is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License
23
+ * along with this program; if not, write to the Free Software
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ */
26
+
1 27
 #ifndef __SBCCALL_LEG_H
2 28
 #define __SBCCALL_LEG_H
3 29
 
... ...
@@ -34,6 +60,9 @@ class SBCCallLeg : public CallLeg, public CredentialHolder
34 60
   vector<AmDynInvoke*> cc_modules;
35 61
   vector<ExtendedCCInterface*> cc_ext;
36 62
 
63
+  // modules to initialize
64
+  CCInterfaceListT cc_module_queue;
65
+
37 66
   // current timer ID - cc module setting timer will use this
38 67
   int cc_timer_id;
39 68
   int ext_cc_timer_id; // for assigning IDs to timers through "extended CC interface"
... ...
@@ -127,7 +156,9 @@ class SBCCallLeg : public CallLeg, public CredentialHolder
127 156
   UACAuthCred* getCredentials();
128 157
 
129 158
   void setAuthHandler(AmSessionEventHandler* h) { auth = h; }
130
-  bool initCCExtModules();
159
+  bool initCCExtModules(const CCInterfaceListT& cc_module_list, const vector<AmDynInvoke*>& cc_module_di);
160
+  bool initPendingCCExtModules();
161
+  void addPendingCCExtModule(const string& cc_name, const string& cc_module, const map<string, string>& cc_values);
131 162
 
132 163
   /** save call timer; only effective before call is connected */
133 164
   void saveCallTimer(int timer, double timeout);
... ...
@@ -681,21 +681,6 @@ string SBCCallProfile::print() const {
681 681
   return res;
682 682
 }
683 683
 
684
-/* translates string value into bool, returns false on error */
685
-static bool str2bool(const string &s, bool &dst)
686
-{
687
-  // TODO: optimize
688
-  if ((s == "yes") || (s == "true") || (s == "1")) {
689
-    dst = true;
690
-    return true;
691
-  }
692
-  if ((s == "no") || (s == "false") || (s == "0")) {
693
-    dst = false;
694
-    return true;
695
-  }
696
-  return false;
697
-}
698
-
699 684
 static bool isTranscoderNeeded(const AmSipRequest& req, vector<PayloadDesc> &caps,
700 685
 			       bool default_value)
701 686
 {
... ...
@@ -1244,6 +1229,33 @@ void SBCCallProfile::fix_reg_contact(ParamReplacerCtx& ctx,
1244 1229
   }
1245 1230
 }
1246 1231
 
1232
+string SBCCallProfile::retarget(const string& alias)
1233
+{
1234
+    // REG-Cache lookup
1235
+    AliasEntry alias_entry;
1236
+    if(!RegisterCache::instance()->findAliasEntry(alias, alias_entry)) {
1237
+      throw AmSession::Exception(404,"User not found");
1238
+    }
1239
+    string new_r_uri = alias_entry.contact_uri;
1240
+    DBG("setting from registration cache: r_uri='%s'\n",new_r_uri.c_str());
1241
+
1242
+    // fix NAT
1243
+    string nh = alias_entry.source_ip;
1244
+    if(alias_entry.source_port != 5060)
1245
+      nh += ":" + int2str(alias_entry.source_port);
1246
+
1247
+    DBG("setting from registration cache: next_hop='%s'\n", nh.c_str());
1248
+    next_hop = nh;
1249
+
1250
+    // sticky interface
1251
+    DBG("setting from registration cache: outbound_interface='%s'\n",
1252
+	AmConfig::SIP_Ifs[alias_entry.local_if].name.c_str());
1253
+    outbound_interface = AmConfig::SIP_Ifs[alias_entry.local_if].name;
1254
+    outbound_interface_value = alias_entry.local_if;
1255
+
1256
+    return new_r_uri;
1257
+}
1258
+
1247 1259
 string SBCCallProfile::retarget(const string& alias, AmBasicSipDialog& dlg) const
1248 1260
 {
1249 1261
     // REG-Cache lookup
... ...
@@ -59,6 +59,7 @@ struct CCInterface {
59 59
 
60 60
 typedef std::list<CCInterface> CCInterfaceListT;
61 61
 typedef CCInterfaceListT::iterator CCInterfaceListIteratorT;
62
+typedef CCInterfaceListT::const_iterator CCInterfaceListConstIteratorT;
62 63
 
63 64
 template <class T>
64 65
 class ref_counted_ptr
... ...
@@ -147,6 +148,8 @@ struct SBCCallProfile
147 148
 
148 149
   string aleg_next_hop;
149 150
 
151
+  bool allow_subless_notify;
152
+
150 153
   vector<FilterEntry> headerfilter;
151 154
   vector<FilterEntry> messagefilter;
152 155
 
... ...
@@ -348,7 +351,8 @@ struct SBCCallProfile
348 351
     log_sip(false),
349 352
     patch_ruri_next_hop(false),
350 353
     next_hop_1st_req(false),
351
-    next_hop_fixed(false)
354
+    next_hop_fixed(false),
355
+    allow_subless_notify(false)
352 356
   { }
353 357
 
354 358
   ~SBCCallProfile()
... ...
@@ -398,10 +402,18 @@ struct SBCCallProfile
398 402
   /**
399 403
    * Reg-cache lookup:
400 404
    * - searches for alias in the reg-cache.
401
-   * - sets next-hop & outbound_interface
405
+   * - sets next-hop & outbound_interface on the given dialog
402 406
    * @return retargeted R-URI
403 407
    */
404 408
   string retarget(const string& alias, AmBasicSipDialog& dlg) const;
409
+
410
+  /**
411
+   * Reg-cache lookup:
412
+   * - searches for alias in the reg-cache.
413
+   * - sets next-hop & outbound_interface in this profile
414
+   * @return retargeted R-URI
415
+   */
416
+  string retarget(const string& alias);
405 417
 };
406 418
 
407 419
 #endif // _SBCCallProfile_h
... ...
@@ -1,3 +1,27 @@
1
+/*
2
+ * Copyright (C) 2012-2013 FRAFOS GmbH
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.
10
+ *
11
+ * For a license to use the SEMS software under conditions
12
+ * other than those described here, or to purchase support for this
13
+ * software, please contact iptel.org by e-mail at the following addresses:
14
+ *    info@iptel.org
15
+ *
16
+ * SEMS is distributed in the hope that it will be useful,
17
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
+ * GNU General Public License for more details.
20
+ *
21
+ * You should have received a copy of the GNU General Public License
22
+ * along with this program; if not, write to the Free Software
23
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24
+ */
1 25
 #include "SBCEventLog.h"
2 26
 #include "AmAppTimer.h"
3 27
 
... ...
@@ -1,3 +1,28 @@
1
+/*
2
+ * Copyright (C) 2012-2013 FRAFOS GmbH
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.
10
+ *
11
+ * For a license to use the SEMS software under conditions
12
+ * other than those described here, or to purchase support for this
13
+ * software, please contact iptel.org by e-mail at the following addresses:
14
+ *    info@iptel.org
15
+ *
16
+ * SEMS is distributed in the hope that it will be useful,
17
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
+ * GNU General Public License for more details.
20
+ *
21
+ * You should have received a copy of the GNU General Public License
22
+ * along with this program; if not, write to the Free Software
23
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24
+ */
25
+
1 26
 #ifndef _SBCEventLog_h_
2 27
 #define _SBCEventLog_h_
3 28
 
... ...
@@ -363,6 +363,7 @@ int SimpleRelayDialog::initUAC(const AmSipRequest& req,
363 363
 
364 364
   if(cp.transparent_dlg_id){
365 365
     setExtLocalTag(req.from_tag);
366
+    cseq = req.cseq;
366 367
   }
367 368
   else if(n_req.callid == req.callid)
368 369
     n_req.callid = AmSession::getNewId();
... ...
@@ -42,10 +42,13 @@ SBCDSMInstance::SBCDSMInstance(SBCCallLeg *call, const VarMapT& values)
42 42
   : call(call), local_media_connected(false)
43 43
 {
44 44
   DBG("SBCDSMInstance::SBCDSMInstance()\n");
45
-  var = values;
45
+  VarMapT::const_iterator it = values.find(DSM_SBC_CCVAR_START_DIAG);
46
+  if (it != values.end())
47
+    startDiagName = it->second;
46 48
 
47
-  startDiagName = var[DSM_SBC_CCVAR_START_DIAG];
48
-  appBundle = var[DSM_SBC_CCVAR_APP_BUNDLE];
49
+  it = values.find(DSM_SBC_CCVAR_APP_BUNDLE);
50
+  if (it != values.end())
51
+    appBundle = it->second;
49 52
 
50 53
   if (startDiagName.empty()) {
51 54
     throw string("DSM SBC call control "DSM_SBC_CCVAR_START_DIAG" parameter not set (see call profile)'");
... ...
@@ -63,10 +66,15 @@ SBCDSMInstance::SBCDSMInstance(SBCCallLeg *call, const VarMapT& values)
63 66
     throw string("initializing call with DSM app bundle '" +appBundle);
64 67
   }
65 68
 
66
- for (map<string, string>::const_iterator it = 
69
+  for (map<string, string>::const_iterator it =
67 70
 	 config_vars.begin(); it != config_vars.end(); it++) 
68 71
     var["config."+it->first] = it->second;
69 72
 
73
+  // overwrite config. variables with cc-instance variables (map::insert doesn't overwrite)
74
+  for (VarMapT::const_iterator it = values.begin(); it != values.end(); it++) {
75
+    var[it->first] = it->second;
76
+  }
77
+
70 78
   DBG("Running init of SBCDSMInstance...\n");
71 79
   if (!engine.init(call, this, startDiagName, DSMCondition::Start)) {
72 80
     WARN("Initialization failed for SBCDSMInstance\n");
... ...
@@ -41,6 +41,7 @@
41 41
 #define HANGUP_CAUSE "hangup_cause"
42 42
 #define HANGUP_INITIATOR "hangup_initiator"
43 43
 #define DISPOSITION "disposition"
44
+#define DST_IP "destination_ip"
44 45
 
45 46
 
46 47
 struct HangupCause: public B2BEvent
... ...
@@ -374,21 +375,31 @@ void SyslogCDR::end(const string& ltag, SBCCallProfile* call_profile,
374 375
   DBG("written CDR '%s' to syslog\n", ltag.c_str());
375 376
 }
376 377
 
377
-void SyslogCDR::onStateChange(SBCCallLeg *call, const CallLeg::StatusChangeCause &cause)
378
-{
379
-  SBCCallProfile &prof = call->getCallProfile();
380 378
 
379
+static AmArg *getCDRVars(SBCCallProfile &prof)
380
+{
381 381
   SBCVarMapIteratorT i = prof.cc_vars.find(CDR_VARS);
382 382
   if (i == prof.cc_vars.end()) {
383 383
     prof.cc_vars[CDR_VARS] = AmArg();
384 384
     i = prof.cc_vars.find(CDR_VARS);
385 385
   }
386 386
   if (i == prof.cc_vars.end()) {
387
-    ERROR("can't update CDR\n");
387
+    return NULL;
388
+  }
389
+  return &i->second;
390
+}
391
+
392
+void SyslogCDR::onStateChange(SBCCallLeg *call, const CallLeg::StatusChangeCause &cause)
393
+{
394
+  SBCCallProfile &prof = call->getCallProfile();
395
+
396
+  AmArg *pcdr = getCDRVars(prof);
397
+  if (!pcdr) {
398
+    ERROR("can't update CDR variables upon call state change\n");
388 399
     return;
389 400
   }
390 401
 
391
-  AmArg &cdr = i->second;
402
+  AmArg &cdr = *pcdr;
392 403
 
393 404
   CallLeg::CallStatus s = call->getCallStatus();
394 405
 
... ...
@@ -518,5 +529,21 @@ CCChainProcessing SyslogCDR::onEvent(SBCCallLeg *call, AmEvent *e)
518 529
       return StopProcessing;
519 530
     }
520 531
   }
532
+
533
+  // determine destination IP address
534
+  if (e->event_id == B2BSipReply &&  // replies received in our peer leg
535
+      call->isALeg() &&
536
+      call->getCallStatus() != CallLeg::Connected) // just replies before we get connected, then no failover is expected
537
+  {
538
+    B2BSipReplyEvent *ev = dynamic_cast<B2BSipReplyEvent*>(e);
539
+    if (ev) {
540
+      AmArg *cdr = getCDRVars(call->getCallProfile());
541
+      if (cdr) {
542
+        (*cdr)[DST_IP] = ev->reply.remote_ip;
543
+      }
544
+      else ERROR("can't update CDR variables with destination IP\n");
545
+    }
546
+  }
547
+
521 548
   return ContinueProcessing;
522 549
 }
... ...
@@ -29,8 +29,9 @@
29 29
 
30 30
 #include "CCTemplate.h"
31 31
 
32
-#include "ampi/SBCCallControlAPI.h"
32
+#include "SBCCallControlAPI.h"
33 33
 
34
+#include "SBCCallLeg.h"
34 35
 #include <string.h>
35 36
 
36 37
 class CCTemplateFactory : public AmDynInvokeFactory
... ...
@@ -160,7 +161,13 @@ void CCTemplate::invoke(const string& method, const AmArg& args, AmArg& ret)
160 161
 	args[CC_API_PARAMS_TIMESTAMPS][CC_API_TS_END_SEC].asInt(),
161 162
 	args[CC_API_PARAMS_TIMESTAMPS][CC_API_TS_END_USEC].asInt()
162 163
 	);
163
-  } else if(method == "_list"){
164
+  }
165
+  // extended call control
166
+  // else if (method == "getExtendedInterfaceHandler") {
167
+  //   ret.push((AmObject*)this);
168
+  // }
169
+
170
+  else if(method == "_list"){
164 171
     ret.push("start");
165 172
     ret.push("connect");
166 173
     ret.push("end");
... ...
@@ -173,7 +180,7 @@ void CCTemplate::start(const string& cc_name, const string& ltag,
173 180
 		       SBCCallProfile* call_profile,
174 181
 		       int start_ts_sec, int start_ts_usec,
175 182
 		       const AmArg& values, int timer_id, AmArg& res) {
176
-  // start code here
183
+  // call start code here
177 184
   res.push(AmArg());
178 185
   AmArg& res_cmd = res[0];
179 186
 
... ...
@@ -194,13 +201,138 @@ void CCTemplate::connect(const string& cc_name, const string& ltag,
194 201
 			 SBCCallProfile* call_profile,
195 202
 			 const string& other_tag,
196 203
 			 int connect_ts_sec, int connect_ts_usec) {
197
-  // connect code here
204
+  // call connect code here
198 205
 
199 206
 }
200 207
 
201 208
 void CCTemplate::end(const string& cc_name, const string& ltag,
202 209
 		     SBCCallProfile* call_profile,
203 210
 		     int end_ts_sec, int end_ts_usec) {
204
-  // end code here
211
+  // call end code here
212
+
213
+}
214
+
215
+// ------- extended call control interface -------------------
216
+
217
+
218
+
219
+bool CCTemplate::init(SBCCallLeg *call, const map<string, string> &values)
220
+{
221
+  DBG("ExtCC: init - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
222
+
223
+  SBCCallProfile &profile = call->getCallProfile();
224
+
225
+  return true;
226
+}
227
+
228
+CCChainProcessing CCTemplate::onInitialInvite(SBCCallLeg *call, InitialInviteHandlerParams &params)
229
+{
230
+  DBG("ExtCC: onInitialInvite - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
231
+  return ContinueProcessing;
232
+}
233
+
234
+void CCTemplate::onStateChange(SBCCallLeg *call, const CallLeg::StatusChangeCause &cause) {
235
+  DBG("ExtCC: onStateChange - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
236
+};
237
+
238
+CCChainProcessing CCTemplate::onBLegRefused(SBCCallLeg *call, const AmSipReply& reply)
239
+{
240
+  DBG("ExtCC: onBLegRefused - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
241
+  return ContinueProcessing;
242
+}
243
+void CCTemplate::onDestroyLeg(SBCCallLeg *call) {
244
+  DBG("ExtCC: onDestroyLeg - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
245
+}
246
+
247
+/** called from A/B leg when in-dialog request comes in */
248
+CCChainProcessing CCTemplate::onInDialogRequest(SBCCallLeg *call, const AmSipRequest &req) {
249
+  DBG("ExtCC: onInDialogRequest - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
250
+  return ContinueProcessing;
251
+}
252
+
253
+CCChainProcessing CCTemplate::onInDialogReply(SBCCallLeg *call, const AmSipReply &reply) {
254
+  DBG("ExtCC: onInDialogReply - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
255
+  return ContinueProcessing;
256
+}
257
+
258
+/** called before any other processing for the event is done */
259
+CCChainProcessing CCTemplate::onEvent(SBCCallLeg *call, AmEvent *e) {
260
+  DBG("ExtCC: onEvent - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
261
+  return ContinueProcessing;
262
+}
263
+
264
+CCChainProcessing CCTemplate::onDtmf(SBCCallLeg *call, int event, int duration) { 
265
+  DBG("ExtCC: onDtmf(%i;%i) - call instance: '%p' isAleg==%s\n",
266
+      event, duration, call, call->isALeg()?"true":"false");
267
+  return ContinueProcessing;
268
+}
269
+
270
+// hold related functionality
271
+CCChainProcessing CCTemplate::putOnHold(SBCCallLeg *call) {
272
+  DBG("ExtCC: putOnHold - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
273
+  return ContinueProcessing;
274
+}
275
+
276
+CCChainProcessing CCTemplate::resumeHeld(SBCCallLeg *call, bool send_reinvite) {
277
+  DBG("ExtCC: resumeHeld - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
278
+  return ContinueProcessing;
279
+}
280
+
281
+CCChainProcessing CCTemplate::createHoldRequest(SBCCallLeg *call, AmSdp &sdp) {
282
+  DBG("ExtCC: createHoldRequest - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
283
+  return ContinueProcessing;
284
+}
285
+
286
+CCChainProcessing CCTemplate::handleHoldReply(SBCCallLeg *call, bool succeeded) {
287
+  DBG("ExtCC: handleHoldReply - call instance: '%p' isAleg==%s\n", call, call->isALeg()?"true":"false");
288
+  return ContinueProcessing;
289
+}
290
+
291
+/** Possibility to influence messages relayed to the B2B peer leg.
292
+    return value:
293
+    - lower than 0 means error (returned upstream, the one
294
+    returning error is responsible for destrying the event instance)
295
+    - greater than 0 means "stop processing and return 0 upstream"
296
+    - equal to 0 means "continue processing" */
297
+int CCTemplate::relayEvent(SBCCallLeg *call, AmEvent *e) {
298
+
299
+  return 0;
300
+}
301
+
302
+// using extended CC modules with simple relay - non-call relay
303
+
304
+bool CCTemplate::init(SBCCallProfile& profile, SimpleRelayDialog *relay, void *&user_data) {
305
+  DBG("init simple relay\n");
306
+  return true;
307
+}
308
+
309
+void CCTemplate::initUAC(const AmSipRequest &req, void *user_data) {
310
+  DBG("initUAC simple relay\n");
311
+}
312
+
313
+void CCTemplate::initUAS(const AmSipRequest &req, void *user_data) {
314
+  DBG("initUAS simple relay\n");
315
+}
316
+
317
+void CCTemplate::finalize(void *user_data) {
318
+  DBG("finalize simple relay\n");
319
+}
320
+
321
+void CCTemplate::onSipRequest(const AmSipRequest& req, void *user_data) {
322
+  DBG("onSipRequest simple relay\n");
323
+}
324
+
325
+void CCTemplate::onSipReply(const AmSipRequest& req,
326
+			     const AmSipReply& reply,
327
+			     AmBasicSipDialog::Status old_dlg_status,
328
+			     void *user_data) {
329
+  DBG("onSipReply simple relay\n");
330
+}
331
+
332
+void CCTemplate::onB2BRequest(const AmSipRequest& req, void *user_data) {
333
+  DBG("onB2BRequest simple relay\n");
334
+}
205 335
 
336
+void CCTemplate::onB2BReply(const AmSipReply& reply, void *user_data) {
337
+  DBG("onB2BReply simple relay\n");
206 338
 }
... ...
@@ -30,10 +30,15 @@
30 30
 
31 31
 #include "SBCCallProfile.h"
32 32
 
33
+#include "ExtendedCCInterface.h"
34
+
33 35
 /**
34 36
  * sample call control module
35 37
  */
36 38
 class CCTemplate : public AmDynInvoke
39
+/* 		   // extended CC interface  */
40
+/* , public AmObject, public ExtendedCCInterface */
41
+
37 42
 {
38 43
   static CCTemplate* _instance;
39 44
 
... ...
@@ -52,6 +57,36 @@ class CCTemplate : public AmDynInvoke
52 57
   static CCTemplate* instance();
53 58
   void invoke(const string& method, const AmArg& args, AmArg& ret);
54 59
   int onLoad();
60
+
61
+  /* // extended call control interface */
62
+  /* //    --- calls */
63
+  /* bool init(SBCCallLeg *call, const map<string, string> &values); */
64
+  /* CCChainProcessing onInitialInvite(SBCCallLeg *call, InitialInviteHandlerParams &params); */
65
+  /* CCChainProcessing onBLegRefused(SBCCallLeg *call, const AmSipReply& reply); */
66
+  /* void onDestroyLeg(SBCCallLeg *call); */
67
+  /* void onStateChange(SBCCallLeg *call, const CallLeg::StatusChangeCause &cause); */
68
+  /* CCChainProcessing onInDialogRequest(SBCCallLeg *call, const AmSipRequest &req); */
69
+  /* CCChainProcessing onInDialogReply(SBCCallLeg *call, const AmSipReply &reply); */
70
+  /* CCChainProcessing onEvent(SBCCallLeg *call, AmEvent *e); */
71
+  /* CCChainProcessing onDtmf(SBCCallLeg *call, int event, int duration); */
72
+  /* CCChainProcessing putOnHold(SBCCallLeg *call); */
73
+  /* CCChainProcessing resumeHeld(SBCCallLeg *call, bool send_reinvite); */
74
+  /* CCChainProcessing createHoldRequest(SBCCallLeg *call, AmSdp &sdp); */
75
+  /* CCChainProcessing handleHoldReply(SBCCallLeg *call, bool succeeded); */
76
+  /* int relayEvent(SBCCallLeg *call, AmEvent *e); */
77
+
78
+  /* //    --- simple relay */
79
+  /* bool init(SBCCallProfile &profile, SimpleRelayDialog *relay, void *&user_data); */
80
+  /* void initUAC(const AmSipRequest &req, void *user_data); */
81
+  /* void initUAS(const AmSipRequest &req, void *user_data); */
82
+  /* void finalize(void *user_data); */
83
+  /* void onSipRequest(const AmSipRequest& req, void *user_data); */
84
+  /* void onSipReply(const AmSipRequest& req, */
85
+  /* 		  const AmSipReply& reply, */
86
+  /* 		  AmBasicSipDialog::Status old_dlg_status, */
87
+  /* 		  void *user_data); */
88
+  /* void onB2BRequest(const AmSipRequest& req, void *user_data); */
89
+  /* void onB2BReply(const AmSipReply& reply, void *user_data); */
55 90
 };
56 91
 
57 92
 #endif 
... ...
@@ -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
... ...
@@ -64,7 +64,7 @@ AmSipDialog::AmSipDialog(AmSipDialogEventHandler* h)
64 64
   : AmBasicSipDialog(h),oa(this),rel100(this,h),
65 65
     offeranswer_enabled(true),
66 66
     early_session_started(false),session_started(false),
67
-    pending_invites(0),cancel_pending(false),
67
+    pending_invites(0),
68 68
     sdp_local(), sdp_remote()
69 69
 {
70 70
 }
... ...
@@ -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 {
... ...
@@ -372,10 +373,6 @@ bool AmSipDialog::onRxReplyStatus(const AmSipReply& reply,
372 373
 	setStatus(Disconnected);
373 374
 	setRemoteTag(reply.to_tag);
374 375
       }
375
-      else if(cancel_pending){
376
-	cancel_pending = false;
377
-	bye();
378
-      }
379 376
       break;
380 377
 
381 378
     case Early:
... ...
@@ -716,14 +713,11 @@ int AmSipDialog::cancel()
716 713
 	t != uac_trans.rend(); t++) {
717 714
 	
718 715
 	if(t->second.method == SIP_METH_INVITE){
719
-	  
720
-	  if(getStatus() == Trying){
721
-	    cancel_pending=true;
722
-	    return 0;
723
-	  }
724
-	  else if(getStatus() != Cancelling){
716
+
717
+	  if(getStatus() != Cancelling){
725 718
 	    setStatus(Cancelling);
726
-	    return SipCtrlInterface::cancel(&t->second.tt,t->second.hdrs);
719
+	    return SipCtrlInterface::cancel(&t->second.tt, local_tag,
720
+					    t->first, t->second.hdrs);
727 721
 	  }
728 722
 	  else {
729 723
 	    ERROR("INVITE transaction has already been cancelled\n");
... ...
@@ -46,10 +46,6 @@ protected:
46 46
   // Number of open UAS INVITE transactions
47 47
   unsigned int pending_invites;
48 48
 
49
-  // In case a CANCEL should have been sent
50
-  // while in 'Trying' state
51
-  bool         cancel_pending;
52
-
53 49
   AmSdp   sdp_local;
54 50
   AmSdp   sdp_remote;
55 51
 
... ...
@@ -105,28 +101,6 @@ protected:
105 101
 
106 102
   void uasTimeout(AmSipTimeoutEvent* to_ev);
107 103
 
108
-  /** @return 0 on success (deprecated) */
109
-  // int reply(const AmSipRequest& req,
110
-  // 	    unsigned int  code, 
111
-  // 	    const string& reason,
112
-  // 	    const AmMimeBody* body = NULL,
113
-  // 	    const string& hdrs = "",
114
-  // 	    int flags = 0);
115
-
116
-  /** @return 0 on success */
117
-  // int reply(const AmSipTransaction& t,
118
-  // 	    unsigned int  code, 
119
-  // 	    const string& reason,
120
-  // 	    const AmMimeBody* body = NULL,
121
-  // 	    const string& hdrs = "",
122
-  // 	    int flags = 0);
123
-
124
-  /** @return 0 on success */
125
-  // int sendRequest(const string& method, 
126
-  // 		  const AmMimeBody* body = NULL,
127
-  // 		  const string& hdrs = "",
128
-  // 		  int flags = 0);
129
-
130 104
   /** @return 0 on success */
131 105
   int send_200_ack(unsigned int inv_cseq,
132 106
 		   const AmMimeBody* body = NULL,
... ...
@@ -562,6 +562,12 @@ bool AmSipSubscription::onRequestIn(const AmSipRequest& req)
562 562
   // UAS side
563 563
   Subscriptions::iterator sub_it = matchSubscription(req,false);
564 564
   if((sub_it == subs.end()) || (*sub_it)->terminated()) {
565
+
566
+    if((sub_it == subs.end()) && (req.method == SIP_METH_NOTIFY)
567
+       && allow_subless_notify) {
568
+      return true;
569
+    }
570
+
565 571
     dlg->reply(req, 481, SIP_REPLY_NOT_EXIST);
566 572
     return false;
567 573
   }
... ...
@@ -576,6 +582,12 @@ void AmSipSubscription::onRequestSent(const AmSipRequest& req)
576 582
   // UAC side
577 583
   Subscriptions::iterator sub_it = matchSubscription(req,true);
578 584
   if(sub_it == subs.end()){
585
+
586
+    if((req.method == SIP_METH_NOTIFY)
587
+       && allow_subless_notify) {
588
+      return;
589
+    }
590
+
579 591
     // should we exclude this case in onSendRequest???
580 592
     ERROR("we just sent a request for which we could obtain no subscription\n");
581 593
     return;
...