Author: sayer
Date: 2010-04-23 20:47:07 +0200 (Fri, 23 Apr 2010)
New Revision: 1821

Added:
   trunk/apps/sst_b2b/
   trunk/apps/sst_b2b/CMakeLists.txt
   trunk/apps/sst_b2b/Makefile
   trunk/apps/sst_b2b/SSTB2B.cpp
   trunk/apps/sst_b2b/SSTB2B.h
   trunk/apps/sst_b2b/etc/
   trunk/apps/sst_b2b/etc/sst_b2b.conf
Modified:
   trunk/core/AmB2BSession.cpp
   trunk/core/AmB2BSession.h
Log:
first version of a SST enabled B2B application. 

The incoming INVITE establishind a call is passed in 
signaling only B2B mode to the B leg, which tries to 
send it to the request URI.

SIP Session Timers are enabled on both legs. When the 
timer expires, an empty INVITE is sent, and the resulting 
SDP offer from body of the 200 is relayed into the other 
leg, where it is sent out as INVITE with the offer. The 
answer from B leg is relayed into A leg and sent as body
in ACK message.

SST expiration is configurable in confi file. 



Added: trunk/apps/sst_b2b/CMakeLists.txt
===================================================================
--- trunk/apps/sst_b2b/CMakeLists.txt   2010-04-23 18:24:33 UTC (rev 1820)
+++ trunk/apps/sst_b2b/CMakeLists.txt   2010-04-23 18:47:07 UTC (rev 1821)
@@ -0,0 +1,7 @@
+set (sst_b2b_SRCS
+SSTB2B.cpp
+)
+
+SET(sems_module_name sst_b2b)
+INCLUDE(${CMAKE_SOURCE_DIR}/cmake/module.rules.txt)
+INCLUDE(${CMAKE_SOURCE_DIR}/cmake/config.rules.txt)

Added: trunk/apps/sst_b2b/Makefile
===================================================================
--- trunk/apps/sst_b2b/Makefile 2010-04-23 18:24:33 UTC (rev 1820)
+++ trunk/apps/sst_b2b/Makefile 2010-04-23 18:47:07 UTC (rev 1821)
@@ -0,0 +1,7 @@
+plug_in_name = sst_b2b
+
+module_ldflags =
+module_cflags  = -DMOD_NAME=\"$(plug_in_name)\"
+
+COREPATH ?= ../../core
+include $(COREPATH)/plug-in/Makefile.app_module

Added: trunk/apps/sst_b2b/SSTB2B.cpp
===================================================================
--- trunk/apps/sst_b2b/SSTB2B.cpp       2010-04-23 18:24:33 UTC (rev 1820)
+++ trunk/apps/sst_b2b/SSTB2B.cpp       2010-04-23 18:47:07 UTC (rev 1821)
@@ -0,0 +1,392 @@
+/*
+ * $Id: SSTB2B.cpp 1784 2010-04-15 13:01:00Z sayer $
+ *
+ * Copyright (C) 2010 Stefan Sayer
+ *
+ * This file is part of SEMS, a free SIP media server.
+ *
+ * SEMS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * For a license to use the SEMS software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * SEMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "SSTB2B.h"
+
+#include "log.h"
+#include "AmUtils.h"
+#include "AmAudio.h"
+#include "AmPlugIn.h"
+#include "AmMediaProcessor.h"
+#include "AmConfigReader.h"
+#include "AmSessionContainer.h"
+
+string SSTB2BFactory::user;
+string SSTB2BFactory::domain;
+string SSTB2BFactory::pwd;
+AmConfigReader SSTB2BFactory::cfg;
+AmSessionEventHandlerFactory* SSTB2BFactory::session_timer_fact = NULL;
+
+EXPORT_SESSION_FACTORY(SSTB2BFactory,MOD_NAME);
+
+SSTB2BFactory::SSTB2BFactory(const string& _app_name)
+: AmSessionFactory(_app_name)
+{
+}
+
+
+int SSTB2BFactory::onLoad()
+{
+  if(cfg.loadFile(AmConfig::ModConfigPath + string(MOD_NAME ".conf"))) {
+    INFO("No configuration for sst_b2b present (%s)\n",
+        (AmConfig::ModConfigPath + string(MOD_NAME ".conf")).c_str()
+        );
+  }
+
+  session_timer_fact = AmPlugIn::instance()->getFactory4Seh("session_timer");
+  if(!session_timer_fact) {
+    ERROR("could not load session_timer from session_timer plug-in\n");
+    return -1;
+  }
+
+  return 0;
+}
+
+
+AmSession* SSTB2BFactory::onInvite(const AmSipRequest& req)
+{
+
+  SSTB2BDialog* b2b_dlg = new SSTB2BDialog();
+  AmSessionEventHandler* h = session_timer_fact->getHandler(b2b_dlg);
+  if(!h) {
+    ERROR("could not get a session timer event handler\n");
+    throw AmSession::Exception(500,"Server internal error");
+  }
+  if(h->configure(cfg)){
+    ERROR("Could not configure the session timer: disabling session 
timers.\n");
+    delete h;
+  } else {
+    b2b_dlg->addHandler(h);
+  }
+
+  return b2b_dlg;
+}
+
+
+SSTB2BDialog::SSTB2BDialog() // AmDynInvoke* user_timer)
+: m_state(BB_Init),
+  AmB2BCallerSession()
+
+{
+  set_sip_relay_only(false);
+}
+
+
+SSTB2BDialog::~SSTB2BDialog()
+{
+}
+
+
+void SSTB2BDialog::onInvite(const AmSipRequest& req)
+{
+  DBG("onINVITE -------------------------------\n");
+  // this will prevent us from being added to media processor
+  setInOut(NULL,NULL); 
+
+  from = req.from;
+  to = req.to;
+
+  m_state = BB_Dialing;
+
+  if(dlg.reply(req, 100, "Connecting") != 0) {
+    throw AmSession::Exception(500,"Failed to reply 100");
+  }
+
+  invite_req = req;
+
+  removeHeader(invite_req.hdrs,PARAM_HDR);
+  removeHeader(invite_req.hdrs,"P-App-Name");
+
+  dlg.updateStatus(req);
+  recvd_req.insert(std::make_pair(req.cseq,req));
+  
+  set_sip_relay_only(true);
+  connectCallee("<" + req.r_uri + ">", req.r_uri, true);
+}
+
+void SSTB2BDialog::sendReinvite(bool updateSDP, const string& headers) {
+  if (sip_relay_only) {
+    // we send empty reinvite 
+    DBG("sending empty reinvite in callee session\n");
+    dlg.reinvite(headers, "", ""); 
+  } else {
+    AmB2BCallerSession::sendReinvite(updateSDP, headers);
+  }
+
+  // // we send empty reinvite
+  // dlg.reinvite(headers, "", "");
+  // we send reinvite with the last body we got from the other side
+  // last_otherleg_content_type, last_otherleg_body);
+}
+
+void SSTB2BDialog::process(AmEvent* ev)
+{
+  AmB2BCallerSession::process(ev);
+}
+
+void SSTB2BDialog::onSipRequest(const AmSipRequest& req) {
+  // AmB2BSession does not call AmSession::onSipRequest for 
+  // forwarded requests - so lets call event handlers here
+  // todo: this is a hack, replace this by calling proper session 
+  // event handler in AmB2BSession
+  bool fwd = sip_relay_only &&
+    (req.method != "BYE") &&
+    (req.method != "CANCEL");
+  if (fwd) {
+      CALL_EVENT_H(onSipRequest,req);
+  }
+
+  AmB2BCallerSession::onSipRequest(req);
+}
+
+void SSTB2BDialog::onSipReply(const AmSipReply& reply) {
+  TransMap::iterator t = relayed_req.find(reply.cseq);
+  bool fwd = t != relayed_req.end();
+
+  DBG("onSipReply: %i %s (fwd=%i)\n",reply.code,reply.reason.c_str(),fwd);
+  DBG("onSipReply: content-type = %s\n",reply.content_type.c_str());
+  if (fwd) {
+      CALL_EVENT_H(onSipReply,reply);    
+  }
+
+  AmB2BCallerSession::onSipReply(reply);
+}
+
+bool SSTB2BDialog::onOtherReply(const AmSipReply& reply)
+{
+  bool ret = false;
+
+  if ((m_state == BB_Dialing) && (reply.cseq == invite_req.cseq)) {
+    if (reply.code < 200) {
+      DBG("Callee is trying... code %d\n", reply.code);
+    }
+    else if(reply.code < 300) {
+      if(getCalleeStatus()  == Connected) {
+        m_state = BB_Connected;
+        setInOut(NULL, NULL);
+      }
+    }
+    else if(reply.code == 487 && dlg.getStatus() == AmSipDialog::Pending) {
+      DBG("Stopping leg A on 487 from B with 487\n");
+      dlg.reply(invite_req, 487, "Request terminated");
+      setStopped();
+      ret = true;
+    }
+    else if (reply.code >= 300 && dlg.getStatus() == AmSipDialog::Connected) {
+      DBG("Callee final error in connected state with code %d\n",reply.code);
+      terminateLeg();
+    }
+    else {
+      DBG("Callee final error with code %d\n",reply.code);
+      AmB2BCallerSession::onOtherReply(reply);
+    }
+  }
+  return ret;
+}
+
+
+void SSTB2BDialog::onOtherBye(const AmSipRequest& req)
+{
+//   stopAccounting();
+  AmB2BCallerSession::onOtherBye(req);
+}
+
+
+void SSTB2BDialog::onBye(const AmSipRequest& req)
+{
+  if (m_state == BB_Connected) {
+//     stopAccounting();
+  }
+  terminateOtherLeg();
+  setStopped();
+}
+
+
+void SSTB2BDialog::onCancel()
+{
+  if(dlg.getStatus() == AmSipDialog::Pending) {
+    DBG("Wait for leg B to terminate");
+  } else {
+    DBG("Canceling leg A on CANCEL since dialog is not pending");
+    dlg.reply(invite_req, 487, "Request terminated");
+    setStopped();
+  }
+}
+
+void SSTB2BDialog::createCalleeSession()
+{
+  SSTB2BCalleeSession* callee_session = new SSTB2BCalleeSession(this, user, 
password);
+  
+  // adding auth handler
+  AmSessionEventHandlerFactory* uac_auth_f = 
+    AmPlugIn::instance()->getFactory4Seh("uac_auth");
+  if (NULL == uac_auth_f)  {
+    INFO("uac_auth module not loaded. uac auth NOT enabled for callee 
session.\n");
+  } else {
+    AmSessionEventHandler* h = uac_auth_f->getHandler(callee_session);
+
+    // we cannot use the generic AmSessionEventHandler hooks, 
+    // because the hooks don't work in AmB2BSession
+    callee_session->setAuthHandler(h);
+    DBG("uac auth enabled for callee session.\n");
+  }
+
+  AmSessionEventHandler* h = 
SSTB2BFactory::session_timer_fact->getHandler(callee_session);
+  if(!h) {
+    ERROR("could not get a session timer event handler\n");
+    delete callee_session;
+    throw AmSession::Exception(500,"Server internal error");
+  }
+  if(h->configure(SSTB2BFactory::cfg)){
+    ERROR("Could not configure the session timer: disabling session 
timers.\n");
+    delete h;
+  } else {
+    callee_session->addHandler(h);
+  }
+  
+  AmSipDialog& callee_dlg = callee_session->dlg;
+  
+  other_id = AmSession::getNewId();
+  
+  callee_dlg.local_tag    = other_id;
+  callee_dlg.callid       = AmSession::getNewId() + "@" + AmConfig::LocalIP;
+  
+  // this will be overwritten by ConnectLeg event 
+  callee_dlg.remote_party = dlg.local_party;
+  callee_dlg.remote_uri   = dlg.local_uri;
+
+  // if given as parameters, use these
+  callee_dlg.local_party  = from; 
+  callee_dlg.local_uri    = from; 
+  
+  DBG("Created B2BUA callee leg, From: %s\n",
+      from.c_str());
+
+  if (AmConfig::LogSessions) {
+    INFO("Starting B2B callee session %s app %s\n",
+        callee_session->getLocalTag().c_str(), invite_req.cmd.c_str());
+  }
+
+  MONITORING_LOG5(other_id.c_str(), 
+                 "app",  invite_req.cmd.c_str(),
+                 "dir",  "out",
+                 "from", callee_dlg.local_party.c_str(),
+                 "to",   callee_dlg.remote_party.c_str(),
+                 "ruri", callee_dlg.remote_uri.c_str());
+
+  callee_session->start();
+  
+  AmSessionContainer* sess_cont = AmSessionContainer::instance();
+  sess_cont->addSession(other_id,callee_session);
+}
+
+SSTB2BCalleeSession::SSTB2BCalleeSession(const AmB2BCallerSession* caller,
+                                          const string& user, const string& 
pwd) 
+  : auth(NULL), 
+    credentials("", user, pwd), // domain (realm) is unused in credentials 
+    AmB2BCalleeSession(caller) {
+}
+
+SSTB2BCalleeSession::~SSTB2BCalleeSession() {
+  if (auth) 
+    delete auth;
+}
+
+inline UACAuthCred* SSTB2BCalleeSession::getCredentials() {
+  return &credentials;
+}
+
+void SSTB2BCalleeSession::onSipRequest(const AmSipRequest& req) {
+  // AmB2BSession does not call AmSession::onSipRequest for 
+  // forwarded requests - so lets call event handlers here
+  // todo: this is a hack, replace this by calling proper session 
+  // event handler in AmB2BSession
+  bool fwd = sip_relay_only &&
+    (req.method != "BYE") &&
+    (req.method != "CANCEL");
+  if (fwd) {
+      CALL_EVENT_H(onSipRequest,req);
+  }
+
+  AmB2BCalleeSession::onSipRequest(req);
+}
+
+void SSTB2BCalleeSession::onSipReply(const AmSipReply& reply) {
+  // call event handlers where it is not done 
+  TransMap::iterator t = relayed_req.find(reply.cseq);
+  bool fwd = t != relayed_req.end();
+  DBG("onSipReply: %i %s (fwd=%i)\n",reply.code,reply.reason.c_str(),fwd);
+  DBG("onSipReply: content-type = %s\n",reply.content_type.c_str());
+  if(fwd) {
+      CALL_EVENT_H(onSipReply,reply);    
+  }
+
+  if (NULL == auth) {    
+    AmB2BCalleeSession::onSipReply(reply);
+    return;
+  }
+  
+  int cseq_before = dlg.cseq;
+  if (!auth->onSipReply(reply)) {
+    AmB2BCalleeSession::onSipReply(reply);
+  } else {
+    if (cseq_before != dlg.cseq) {
+      DBG("uac_auth consumed reply with cseq %d and resent with cseq %d; "
+          "updating relayed_req map\n", 
+         reply.cseq, cseq_before);
+      TransMap::iterator it=relayed_req.find(reply.cseq);
+      if (it != relayed_req.end()) {
+       relayed_req[cseq_before] = it->second;
+       relayed_req.erase(it);
+      }
+    }
+  }
+}
+
+void SSTB2BCalleeSession::onSendRequest(const string& method, const string& 
content_type,
+                             const string& body, string& hdrs, int flags, 
unsigned int cseq)
+{
+  if (NULL != auth) {
+    DBG("auth->onSendRequest cseq = %d\n", cseq);
+    auth->onSendRequest(method, content_type,
+                       body, hdrs, flags, cseq);
+  }
+  
+  AmB2BCalleeSession::onSendRequest(method, content_type,
+                                    body, hdrs, flags, cseq);
+}
+
+void SSTB2BCalleeSession::sendReinvite(bool updateSDP, const string& headers) {
+  if (sip_relay_only) {
+    // we send empty reinvite 
+    DBG("sending empty reinvite in callee session\n");
+    dlg.reinvite(headers, "", ""); 
+  } else {
+    AmB2BCalleeSession::sendReinvite(updateSDP, headers);
+  }
+}
+

Added: trunk/apps/sst_b2b/SSTB2B.h
===================================================================
--- trunk/apps/sst_b2b/SSTB2B.h 2010-04-23 18:24:33 UTC (rev 1820)
+++ trunk/apps/sst_b2b/SSTB2B.h 2010-04-23 18:47:07 UTC (rev 1821)
@@ -0,0 +1,134 @@
+/*
+ * $Id: AuthB2B.h 1252 2009-02-01 12:51:06Z sayer $
+ *
+ * Copyright (C) 2010 Stefan Sayer
+ *
+ * This file is part of SEMS, a free SIP media server.
+ *
+ * SEMS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * For a license to use the SEMS software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * SEMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _SST_B2B_H
+#define _SST_B2B_H
+
+#include "AmB2BSession.h"
+#include "ampi/UACAuthAPI.h"
+
+#include "AmConfigReader.h"
+
+using std::string;
+
+class SSTB2BFactory: public AmSessionFactory
+{
+/*   AmDynInvokeFactory* user_timer_fact; */
+
+
+ public:
+  SSTB2BFactory(const string& _app_name);
+  
+  int onLoad();
+  AmSession* onInvite(const AmSipRequest& req);
+  static string user;
+  static string domain;
+  static string pwd;
+
+  static AmConfigReader cfg;
+  static AmSessionEventHandlerFactory* session_timer_fact;
+};
+
+class SSTB2BDialog : public AmB2BCallerSession
+{
+  enum {
+    BB_Init = 0,
+    BB_Dialing,
+    BB_Connected,
+    BB_Teardown
+  } CallerState;
+
+  int m_state;
+
+  string domain;
+  string user;
+  string password;
+
+  string from;
+  string to;
+
+  string last_otherleg_content_type;
+  string last_otherleg_body;
+
+  string last_content_type;
+  string last_body;
+
+/*   AmDynInvoke* m_user_timer; */
+  /* set<int> b2b_reinvite_cseqs; // cseqs of reinvite we sent from the middle 
*/
+
+ public:
+
+  SSTB2BDialog(); //AmDynInvoke* user_timer);
+  ~SSTB2BDialog();
+  
+  void process(AmEvent* ev);
+  void onBye(const AmSipRequest& req);
+  void onInvite(const AmSipRequest& req);
+  void onCancel();
+
+  void sendReinvite(bool updateSDP, const string& headers);
+
+ protected:
+  void onSipReply(const AmSipReply& reply);
+  void onSipRequest(const AmSipRequest& req);  
+
+ protected:
+  
+  bool onOtherReply(const AmSipReply& reply);
+  void onOtherBye(const AmSipRequest& req);
+
+  void createCalleeSession();
+};
+
+class SSTB2BCalleeSession 
+: public AmB2BCalleeSession, public CredentialHolder
+{
+  UACAuthCred credentials;
+  AmSessionEventHandler* auth;
+
+  /* string last_otherleg_content_type; */
+  /* string last_otherleg_body; */
+
+ protected:
+  void onSipRequest(const AmSipRequest& req);
+  void onSipReply(const AmSipReply& reply);
+  void onSendRequest(const string& method, const string& content_type,
+                    const string& body, string& hdrs, int flags, unsigned int 
cseq);
+
+  /* bool onOtherReply(const AmSipReply& reply); */
+
+ public:
+  SSTB2BCalleeSession(const AmB2BCallerSession* caller, const string& user, 
const string& pwd); 
+  ~SSTB2BCalleeSession();
+
+  inline UACAuthCred* getCredentials();
+  
+  void setAuthHandler(AmSessionEventHandler* h) { auth = h; }
+
+  void sendReinvite(bool updateSDP, const string& headers);
+};
+#endif                           

Added: trunk/apps/sst_b2b/etc/sst_b2b.conf
===================================================================
--- trunk/apps/sst_b2b/etc/sst_b2b.conf 2010-04-23 18:24:33 UTC (rev 1820)
+++ trunk/apps/sst_b2b/etc/sst_b2b.conf 2010-04-23 18:47:07 UTC (rev 1821)
@@ -0,0 +1,10 @@
+# session timer configuration:
+enable_session_timer=yes
+session_expires=90
+minimum_timer=10
+
+#authentication (questionable whether that works)
+# user=someuser
+# domain=somedomain.net
+# pwd=sompwd
+

Modified: trunk/core/AmB2BSession.cpp
===================================================================
--- trunk/core/AmB2BSession.cpp 2010-04-23 18:24:33 UTC (rev 1820)
+++ trunk/core/AmB2BSession.cpp 2010-04-23 18:47:07 UTC (rev 1821)
@@ -135,6 +135,45 @@
   case B2BTerminateLeg:
     terminateLeg();
     break;
+
+  case B2BMsgBody:
+    {
+      if (!sip_relay_only) {
+       ERROR("relayed message body received but not in sip_relay_only mode\n");
+       return;
+      }
+
+      B2BMsgBodyEvent* body_ev = dynamic_cast<B2BMsgBodyEvent*>(ev);
+      assert(body_ev);
+
+      DBG("received B2B Msg body event; is_offer=%s, r_cseq=%d\n",
+         body_ev->is_offer?"true":"false", body_ev->r_cseq);
+      
+      if (body_ev->is_offer) {
+       // send INVITE with SDP
+       trans_ticket tt; // empty transaction ticket
+       relayed_body_req[dlg.cseq] = AmSipTransaction("INVITE", 
body_ev->r_cseq, tt);
+       if (dlg.reinvite("", body_ev->content_type, body_ev->body)) {
+          ERROR("sending reinvite with relayed body\n");
+          relayed_body_req.erase(dlg.cseq);
+          // TODO?: relay error back instead?
+          // tear down:
+          DBG("error sending reinvite - terminating this and the other leg\n");
+          terminateOtherLeg();    
+          terminateLeg();
+       }
+      } else {
+       // is_answer - send 200 ACK
+       // todo: use that from uas_trans? 
+       trans_ticket tt; // not used for ACK
+       AmSipTransaction trans("INVITE", body_ev->r_cseq, tt);
+       if (dlg.send_200_ack(trans, body_ev->content_type, body_ev->body, 
+                            "" /* hdrs - todo */, SIP_FLAGS_VERBATIM)) {
+         ERROR("sending ACK with SDP\n");
+       }
+      }
+      return; 
+    }; break;
   }
 
   //ERROR("unknown event caught\n");
@@ -177,7 +216,46 @@
        relayed_req.erase(t);
     }
   } else {
-    AmSession::onSipReply(reply);
+    bool relay_body = 
+    // is a reply to request we sent, 
+    // even though we are in sip_relay_only  mode
+      (sip_relay_only && 
+       // positive reply
+       (200 <= reply.code) && (reply.code < 300) 
+       // with body
+       && !reply.body.empty()); // todo: && method == INVITE???
+    
+    if (relay_body) {
+      // is it an answer to a relayed body, or an answer to empty re-INVITE? 
+      TransMap::iterator rel_body_it = relayed_body_req.find(reply.cseq);
+      bool is_offer =  (rel_body_it == relayed_body_req.end());
+      // answer to empty re-INVITE we have sent
+      relayEvent(new B2BMsgBodyEvent(reply.content_type, reply.body, 
+                                    is_offer, is_offer ? reply.cseq : 
rel_body_it->second.cseq));
+
+      if (is_offer) {  
+       // onSipReply from AmSession without do_200_ack in 
dlg.updateStatus(reply)
+       // todo (?): add do_200_ack flag to AmSession::onSipReply and call 
AmSession::onSipReply
+       CALL_EVENT_H(onSipReply,reply);
+       
+       int status = dlg.getStatus();
+       dlg.updateStatus(reply, false);
+       
+       if (status != dlg.getStatus())
+         DBG("Dialog status changed %s -> %s (stopped=%s) \n", 
+             AmSipDialog::status2str[status], 
+             AmSipDialog::status2str[dlg.getStatus()],
+             getStopped() ? "true" : "false");
+       else 
+         DBG("Dialog status stays %s (stopped=%s)\n", 
AmSipDialog::status2str[status], 
+             getStopped() ? "true" : "false");
+      } else {
+       relayed_body_req.erase(rel_body_it);
+       AmSession::onSipReply(reply);
+      }      
+    } else {
+      AmSession::onSipReply(reply);
+    }
     relayEvent(new B2BSipReplyEvent(reply,false));
   }
 }
@@ -305,7 +383,11 @@
       if(reply.code < 200){
        if ((!sip_relay_only) && sip_relay_early_media_sdp && 
            reply.code>=180 && reply.code<=183 && (!reply.body.empty())) {
-         reinviteCaller(reply);
+         if (reinviteCaller(reply)) {
+           ERROR("re-INVITEing caller for early session - stopping this and 
other leg\n");
+           terminateOtherLeg();
+           terminateLeg();
+         }
        }
          
        callee_status = Ringing;
@@ -316,7 +398,11 @@
          
        if (!sip_relay_only) {
          sip_relay_only = true;
-         reinviteCaller(reply);
+         if (reinviteCaller(reply)) {
+           ERROR("re-INVITEing caller - stopping this and other leg\n");
+           terminateOtherLeg();
+           terminateLeg();
+         }
        }
       }
       else {

Modified: trunk/core/AmB2BSession.h
===================================================================
--- trunk/core/AmB2BSession.h   2010-04-23 18:24:33 UTC (rev 1820)
+++ trunk/core/AmB2BSession.h   2010-04-23 18:47:07 UTC (rev 1821)
@@ -35,7 +35,8 @@
        B2BConnectLeg, 
        B2BCallAccepted, 
        B2BSipRequest, 
-       B2BSipReply };
+       B2BSipReply,
+       B2BMsgBody };
 
 /** \brief base class for event in B2B session */
 struct B2BEvent: public AmEvent
@@ -78,6 +79,25 @@
   {}
 };
 
+/** \brief relay a message body to other leg in B2B session */
+struct B2BMsgBodyEvent : public B2BEvent {
+  string content_type;
+  string body;
+
+  bool is_offer;
+  unsigned int r_cseq;
+
+  B2BMsgBodyEvent(const string& content_type, 
+              const string& body, 
+              bool is_offer,
+              unsigned int r_cseq)
+    : B2BEvent(B2BMsgBody),
+    content_type(content_type), body(body), 
+    is_offer(is_offer), r_cseq(r_cseq)  {
+  }
+  ~B2BMsgBodyEvent() { }
+};
+
 /** \brief trigger connecting the callee leg in B2B session */
 struct B2BConnectEvent: public B2BEvent
 {
@@ -94,8 +114,10 @@
   B2BConnectEvent(const string& remote_party,
                  const string& remote_uri)
     : B2BEvent(B2BConnectLeg),
-       remote_party(remote_party),
-       remote_uri(remote_uri)
+    remote_party(remote_party),
+    remote_uri(remote_uri),
+    relayed_invite(false),
+    r_cseq(0)
   {}
 };
 
@@ -116,11 +138,19 @@
    */
   bool sip_relay_only;
 
-  /** Requests which
+  /** 
+   * Requests which
    * have been relayed (sent)
    */
   TransMap relayed_req;
 
+  /** 
+   * Requests which have been originated 
+   * from local dialog but with 
+   * relayed body
+   */
+  TransMap relayed_body_req;
+
   /** Requests received for relaying */
   std::map<int,AmSipRequest> recvd_req;
 

_______________________________________________
Semsdev mailing list
[email protected]
http://lists.iptel.org/mailman/listinfo/semsdev

Reply via email to