Browse code

sbc: strict control over hold offer

Conflicts:

apps/sbc/SBCCallProfile.h

Václav Kubart authored on 13/11/2013 09:29:14 • Stefan Sayer committed on 19/11/2013 13:38:03
Showing 5 changed files
... ...
@@ -1607,39 +1607,60 @@ void SBCCallLeg::resumeRejected()
1607 1607
   CallLeg::resumeRejected();
1608 1608
 }
1609 1609
 
1610
-static void zero_connection(SdpConnection &c)
1610
+static void replace_address(SdpConnection &c, const string &ip)
1611 1611
 {
1612 1612
   if (!c.address.empty()) {
1613
-    if (c.network == NT_IN) {
1614
-      if (c.addrType == AT_V4) {
1615
-        c.address = "0.0.0.0";
1616
-        return;
1617
-      }
1618
-      // TODO: IPv6?
1613
+    if (c.addrType == AT_V4) {
1614
+      c.address = ip;
1615
+      return;
1619 1616
     }
1617
+    // TODO: IPv6?
1618
+    DBG("unsupported address type for replacing IP");
1620 1619
   }
1621
-
1622
-  DBG("unsupported connection type for marking with 0.0.0.0");
1623 1620
 }
1624 1621
 
1625
-static void alterHoldRequest(AmSdp &sdp, bool mark_zero_con, bool enable_recv)
1622
+static void alterHoldRequest(AmSdp &sdp, SBCCallProfile::HoldSettings::Activity a, const string &ip)
1626 1623
 {
1627
-  if (mark_zero_con) zero_connection(sdp.conn);
1624
+  if (!ip.empty()) replace_address(sdp.conn, ip);
1628 1625
   for (vector<SdpMedia>::iterator m = sdp.media.begin(); m != sdp.media.end(); ++m) {
1629
-    if (mark_zero_con) zero_connection(m->conn);
1630
-    m->recv = enable_recv;
1626
+    if (!ip.empty()) replace_address(m->conn, ip);
1627
+    m->recv = (a == SBCCallProfile::HoldSettings::sendrecv || a == SBCCallProfile::HoldSettings::recvonly);
1628
+    m->send = (a == SBCCallProfile::HoldSettings::sendrecv || a == SBCCallProfile::HoldSettings::sendonly);
1629
+  }
1630
+}
1631
+
1632
+void SBCCallLeg::alterHoldRequestImpl(AmSdp &sdp)
1633
+{
1634
+  if (call_profile.hold_settings.mark_zero_connection(a_leg)) {
1635
+    static const string zero("0.0.0.0");
1636
+    ::alterHoldRequest(sdp, call_profile.hold_settings.activity(a_leg), zero);
1637
+  }
1638
+  else {
1639
+    if (getRtpRelayMode() == RTP_Direct) {
1640
+      // we can not put our IP there if not relaying, using empty not to
1641
+      // overwrite existing addresses
1642
+      static const string empty;
1643
+      ::alterHoldRequest(sdp, call_profile.hold_settings.activity(a_leg), empty);
1644
+    }
1645
+    else {
1646
+      // use public IP to be put into connection addresses (overwrite 0.0.0.0
1647
+      // there)
1648
+      ::alterHoldRequest(sdp, call_profile.hold_settings.activity(a_leg), advertisedIP());
1649
+    }
1631 1650
   }
1632 1651
 }
1633 1652
 
1634 1653
 void SBCCallLeg::alterHoldRequest(AmSdp &sdp)
1635 1654
 {
1636
-  TRACE("altering B2B hold request\n");
1655
+  TRACE("altering B2B hold request(%s, %s, %s)\n",
1656
+      call_profile.hold_settings.alter_b2b(a_leg) ? "alter B2B" : "do not alter B2B",
1657
+      call_profile.hold_settings.mark_zero_connection(a_leg) ? "0.0.0.0" : "own IP",
1658
+      call_profile.hold_settings.activity_str(a_leg).c_str()
1659
+      );
1637 1660
 
1638 1661
   if (!call_profile.hold_settings.alter_b2b(a_leg)) return;
1639 1662
 
1640
-  ::alterHoldRequest(sdp,
1641
-      call_profile.hold_settings.mark_zero_connection(a_leg),
1642
-      call_profile.hold_settings.recv(a_leg));
1663
+  alterHoldRequestImpl(sdp);
1643 1664
 }
1644 1665
 
1645 1666
 void SBCCallLeg::createHoldRequest(AmSdp &sdp)
... ...
@@ -1669,9 +1690,7 @@ void SBCCallLeg::createHoldRequest(AmSdp &sdp)
1669 1690
     m.payloads.push_back(SdpPayload(0));
1670 1691
   }
1671 1692
 
1672
-  ::alterHoldRequest(sdp,
1673
-      call_profile.hold_settings.mark_zero_connection(a_leg),
1674
-      call_profile.hold_settings.recv(a_leg));
1693
+  alterHoldRequestImpl(sdp);
1675 1694
 
1676 1695
   AmB2BMedia *ms = getMediaSession();
1677 1696
   if (ms) ms->replaceOffer(sdp, a_leg);
... ...
@@ -105,6 +105,7 @@ class SBCCallLeg : public CallLeg, public CredentialHolder
105 105
   void logCallStart(const AmSipReply& reply);
106 106
   void logCanceledCall();
107 107
 
108
+  void alterHoldRequestImpl(AmSdp &sdp); // do the SDP update (called by alterHoldRequest)
108 109
 
109 110
  public:
110 111
 
... ...
@@ -1652,23 +1652,40 @@ void SBCCallProfile::HoldSettings::readConfig(AmConfigReader &cfg)
1652 1652
 {
1653 1653
   // store string values for later evaluation
1654 1654
   aleg.mark_zero_connection_str = cfg.getParameter("hold_zero_connection_aleg");
1655
-  aleg.recv_str = cfg.getParameter("hold_enable_recv_aleg");
1655
+  aleg.activity_str = cfg.getParameter("hold_activity_aleg");
1656 1656
   aleg.alter_b2b_str = cfg.getParameter("hold_alter_b2b_aleg");
1657 1657
 
1658 1658
   bleg.mark_zero_connection_str = cfg.getParameter("hold_zero_connection_bleg");
1659
-  bleg.recv_str = cfg.getParameter("hold_enable_recv_bleg");
1659
+  bleg.activity_str = cfg.getParameter("hold_activity_bleg");
1660 1660
   bleg.alter_b2b_str = cfg.getParameter("hold_alter_b2b_bleg");
1661 1661
 }
1662 1662
 
1663
+bool SBCCallProfile::HoldSettings::HoldParams::setActivity(const string &s)
1664
+{
1665
+  if (s == "sendrecv") activity = sendrecv;
1666
+  else if (s == "sendonly") activity = sendonly;
1667
+  else if (s == "recvonly") activity = recvonly;
1668
+  else if (s == "inactive") activity = inactive;
1669
+  else {
1670
+    ERROR("unsupported hold stream activity: %s\n", s.c_str());
1671
+    return false;
1672
+  }
1673
+
1674
+  return true;
1675
+}
1676
+
1663 1677
 bool SBCCallProfile::HoldSettings::evaluate(ParamReplacerCtx& ctx, const AmSipRequest& req)
1664 1678
 {
1665 1679
   REPLACE_BOOL(aleg.mark_zero_connection_str, aleg.mark_zero_connection);
1666
-  REPLACE_BOOL(aleg.recv_str, aleg.recv);
1680
+  REPLACE_STR(aleg.activity_str);
1667 1681
   REPLACE_BOOL(aleg.alter_b2b_str, aleg.alter_b2b);
1668 1682
 
1669 1683
   REPLACE_BOOL(bleg.mark_zero_connection_str, bleg.mark_zero_connection);
1670
-  REPLACE_BOOL(bleg.recv_str, bleg.recv);
1684
+  REPLACE_STR(bleg.activity_str);
1671 1685
   REPLACE_BOOL(bleg.alter_b2b_str, bleg.alter_b2b);
1672 1686
 
1687
+  if (!aleg.activity_str.empty() && !aleg.setActivity(aleg.activity_str)) return false;
1688
+  if (!bleg.activity_str.empty() && !bleg.setActivity(bleg.activity_str)) return false;
1689
+
1673 1690
   return true;
1674 1691
 }
... ...
@@ -284,21 +284,26 @@ struct SBCCallProfile
284 284
 
285 285
   // hold settings
286 286
   class HoldSettings {
287
+    public:
288
+        enum Activity { sendrecv, sendonly, recvonly, inactive };
289
+
287 290
     private:
288 291
       struct HoldParams {
289 292
         // non-replaced params
290
-        string mark_zero_connection_str, recv_str, alter_b2b_str;
293
+        string mark_zero_connection_str, activity_str, alter_b2b_str;
291 294
 
292 295
         bool mark_zero_connection;
293
-        bool recv; // sendrecv/recvonly (if set) X sendonly/inactive (if unset)
296
+        Activity activity;
294 297
         bool alter_b2b; // transform B2B hold requests (not locally generated ones)
295 298
 
296
-        HoldParams(): mark_zero_connection(false), recv(true), alter_b2b(false) { }
299
+        bool setActivity(const string &s);
300
+        HoldParams(): mark_zero_connection(false), activity(sendonly), alter_b2b(false) { }
297 301
       } aleg, bleg;
298 302
 
299 303
     public:
300 304
       bool mark_zero_connection(bool a_leg) { return a_leg ? aleg.mark_zero_connection : bleg.mark_zero_connection; }
301
-      bool recv(bool a_leg) { return a_leg ? aleg.recv : bleg.recv; }
305
+      Activity activity(bool a_leg) { return a_leg ? aleg.activity : bleg.activity; }
306
+      const string &activity_str(bool a_leg) { return a_leg ? aleg.activity_str : bleg.activity_str; }
302 307
       bool alter_b2b(bool a_leg) { return a_leg ? aleg.alter_b2b : bleg.alter_b2b; }
303 308
 
304 309
       void readConfig(AmConfigReader &cfg);
... ...
@@ -604,6 +604,36 @@ enable_aleg_session_timer not set, SST is enabled for both
604 604
 legs. Likewise, if aleg_session_expires etc. is not set, the SST
605 605
 configuration of the B leg is used (session_expires, minimum_timer etc).
606 606
 
607
+
608
+Call hold configuration
609
+-----------------------
610
+
611
+SBC detects hold offer in SDP and according to configured parameters it can
612
+alter the hold requests passing through. (this may be handy for example if there
613
+is need to change "sendonly" to "sendrecv" for correct passing hold music
614
+through NATs)
615
+
616
+hold_alter_b2b_aleg / hold_alter_b2b_bleg
617
+
618
+  If set to "yes" SBC alters B2B hold requests according to hold settings.
619
+
620
+  If set to "no" hold settings is used for locally generated hold requests only.
621
+
622
+hold_zero_connection_aleg / hold_zero_connection_bleg
623
+
624
+  If set to "yes" all connections within SDP are replaced with 0.0.0.0.
625
+
626
+  If set to "no" SBC tries to put its own media IP everywhere (to replace
627
+  0.0.0.0). Note that if SBC is not doing rtp relay, it can not replace IP
628
+  with its own address and the original one is kept there.
629
+
630
+hold_activity_aleg / hold_activity_bleg
631
+
632
+  Force "stream activity" (send/recv) on hold offer.
633
+
634
+  Possible values: sendrecv, sendonly, recvonly, inactive
635
+
636
+
607 637
 Call control modules
608 638
 --------------------
609 639
 Call control (CC) modules for the sbc application implement business