[asterisk-scf-commits] asterisk-scf/integration/mediatransportudptl.git branch "retry_deux" updated.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Tue Apr 3 14:11:44 CDT 2012


branch "retry_deux" has been updated
       via  39d7496a81d17eec4845d2ddb2be2eb9f286b5d5 (commit)
       via  9d285b8ef5f79eb86242083652c7fc0790b57caa (commit)
       via  1743a767617e9192c422ecb1967c85982c63fec2 (commit)
       via  cf436d1ce94dc3e14c1ecdd9c953ea9609820b54 (commit)
       via  c45133e77350087a3dd56b2e0ddecf7557b9cce0 (commit)
       via  bc0debcd8a9a26d25ee86d698074376512e2a2d5 (commit)
       via  9351c7272480d96c45b95aa76ce0f0c821a2e650 (commit)
       via  e05943212a4295dbce188bb45a7f4cb2fe34e5b7 (commit)
       via  45313f9d69d147e81e320937daff31060c1bd182 (commit)
      from  b541fe5476289769c612f5f231cb6e048da0b19a (commit)

Summary of changes:
 src/Component.cpp                    |   58 ++++++++++---
 src/ICETransport.cpp                 |   48 ++++++-----
 src/UDPTLConfiguration.cpp           |    4 +-
 src/UDPTLSession.cpp                 |   39 +++++++--
 src/UDPTLSink.cpp                    |   70 +++++++++++++---
 src/UDPTLSource.cpp                  |    3 +
 src/UdptlStateReplicatorListener.cpp |  153 +++++++++++++++++++--------------
 test/TestMediaTransportUDPTL.cpp     |   73 ++++++++++++++++-
 8 files changed, 327 insertions(+), 121 deletions(-)


- Log -----------------------------------------------------------------
commit 39d7496a81d17eec4845d2ddb2be2eb9f286b5d5
Author: David M. Lee <dlee at digium.com>
Date:   Tue Apr 3 13:59:23 2012 -0500

    Adding thread safety and retry logic to UdptlStateReplicatorListener

diff --git a/src/UdptlStateReplicatorListener.cpp b/src/UdptlStateReplicatorListener.cpp
index cd454f7..61acb1d 100644
--- a/src/UdptlStateReplicatorListener.cpp
+++ b/src/UdptlStateReplicatorListener.cpp
@@ -20,15 +20,20 @@
 #include <boost/shared_ptr.hpp>
 
 #include <AsteriskSCF/System/Component/ReplicaIf.h>
+#include <AsteriskSCF/Operations/OperationContextCache.h>
 
 #include "UdptlStateReplicator.h"
 #include "ReplicationAdapter.h"
 #include "UDPTLSession.h"
 
-using namespace std;
 using namespace AsteriskSCF::Media::UDPTL::V1;
-using namespace AsteriskSCF::UDPTL;
+using namespace AsteriskSCF::Operations;
 using namespace AsteriskSCF::Replication::UDPTL::V1;
+using namespace AsteriskSCF::System::V1;
+using namespace AsteriskSCF::UDPTL;
+using namespace std;
+
+const int TTL_SECONDS = 180;
 
 class UdptlStateReplicatorItem
 {
@@ -61,93 +66,108 @@ struct UdptlStateReplicatorListenerImpl
 {
 public:
     UdptlStateReplicatorListenerImpl(const Ice::ObjectAdapterPtr& adapter,
-                                     const PJMediaEnvironmentPtr& env, 
+                                     const PJMediaEnvironmentPtr& env,
                                      const UdptlGeneralStateItemPtr& generalState,
                                      const UdptlReplicationContextPtr& replicationContext,
                                      const ConfigurationServiceImplPtr& configurationService)
-        : mId(IceUtil::generateUUID()), 
-          mAdapter(adapter), 
+        : mOperationContextCache(OperationContextCache::create(TTL_SECONDS)),
+          mId(IceUtil::generateUUID()),
+          mAdapter(adapter),
           mEnvironment(env),
           mGeneralState(generalState),
           mReplicationContext(replicationContext),
           mConfigurationService(configurationService) {}
-    
-    void removeStateNoticeImpl(const Ice::StringSeq& itemKeys)
+
+    void removeStateNoticeImpl(const AsteriskSCF::System::V1::OperationContextPtr& context, const Ice::StringSeq& itemKeys)
     {
+        boost::mutex::scoped_lock lock(mMutex);
+        if (!mOperationContextCache->addOperationContext(context))
+        {
+            // retry detected
+            return;
+        }
         for (Ice::StringSeq::const_iterator key = itemKeys.begin(); key != itemKeys.end(); ++key)
         {
             // Just erasing this from the map will cause the destructor to actually shut things down
             mStateItems.erase((*key));
         }
     }
-    
-    void setStateNoticeImpl(const UdptlStateItemSeq& items)
-    {
-    class visitor : public AsteriskSCF::Replication::UDPTL::V1::UdptlStateItemVisitor
-    {
-    public:
-            visitor(UdptlStateReplicatorListenerImpl *impl) : mImpl(impl)
-        {
-        }
 
-    private:
-        UdptlStateReplicatorListenerImpl *mImpl;
+    void setStateNoticeImpl(const AsteriskSCF::System::V1::OperationContextPtr& context, const UdptlStateItemSeq& items)
+    {
+        boost::mutex::scoped_lock lock(mMutex);
 
-        void visitUdptlGeneralStateItem(const UdptlGeneralStateItemPtr &item)
+        if (!mOperationContextCache->addOperationContext(context))
         {
-            mImpl->mGeneralState->serviceManagement = item->serviceManagement;
+            // retry detected
+            return;
         }
-            
-        void visitUdptlSessionStateItem(const UdptlSessionStateItemPtr &item)
-        {
-            map<string, boost::shared_ptr<UdptlStateReplicatorItem> >::iterator i = mImpl->mStateItems.find(item->sessionId);
-            boost::shared_ptr<UdptlStateReplicatorItem> localitem;
 
-            if (i == mImpl->mStateItems.end())
+        class visitor : public AsteriskSCF::Replication::UDPTL::V1::UdptlStateItemVisitor
+        {
+        public:
+            visitor(UdptlStateReplicatorListenerImpl *impl) : mImpl(impl)
             {
-                boost::shared_ptr<UdptlStateReplicatorItem> newitem(new UdptlStateReplicatorItem());
-                localitem = newitem;
-                mImpl->mStateItems.insert(make_pair(item->sessionId, newitem));
-
-                localitem->setSession(
-                    AsteriskSCF::UDPTL::UDPTLSession::create(mImpl->mAdapter, mImpl->mEnvironment, item,
-                                                             mImpl->mReplicationContext, mImpl->mConfigurationService));
             }
-            else
+
+        private:
+            UdptlStateReplicatorListenerImpl *mImpl;
+
+            void visitUdptlGeneralStateItem(const UdptlGeneralStateItemPtr &item)
             {
-                localitem = i->second;
+                mImpl->mGeneralState->serviceManagement = item->serviceManagement;
             }
-        
-            //
-            // TODO: This appears to happen in testing on occasion. Should verify if this should be
-            // expected.
-            //
-            if (localitem)
+
+            void visitUdptlSessionStateItem(const UdptlSessionStateItemPtr &item)
             {
-                localitem->getSession()->update(item);
+                map<string, boost::shared_ptr<UdptlStateReplicatorItem> >::iterator i = mImpl->mStateItems.find(item->sessionId);
+                boost::shared_ptr<UdptlStateReplicatorItem> localitem;
+
+                if (i == mImpl->mStateItems.end())
+                {
+                    boost::shared_ptr<UdptlStateReplicatorItem> newitem(new UdptlStateReplicatorItem());
+                    localitem = newitem;
+                    mImpl->mStateItems.insert(make_pair(item->sessionId, newitem));
+
+                    localitem->setSession(
+                        AsteriskSCF::UDPTL::UDPTLSession::create(mImpl->mAdapter, mImpl->mEnvironment, item,
+                            mImpl->mReplicationContext, mImpl->mConfigurationService));
+                }
+                else
+                {
+                    localitem = i->second;
+                }
+
+                //
+                // TODO: This appears to happen in testing on occasion. Should verify if this should be
+                // expected.
+                //
+                if (localitem)
+                {
+                    localitem->getSession()->update(item);
+                }
             }
-        }
-            
-        void visitUdptlStreamSinkStateItem(const UdptlStreamSinkStateItemPtr &item)
-        {
-            map<string, boost::shared_ptr<UdptlStateReplicatorItem> >::iterator i =
-                        mImpl->mStateItems.find(item->sessionId);
-            if (i != mImpl->mStateItems.end())
+
+            void visitUdptlStreamSinkStateItem(const UdptlStreamSinkStateItemPtr &item)
             {
-                i->second->getSession()->update(item);
-            }
-        }
-            
-        void visitUdptlStreamSourceStateItem(const UdptlStreamSourceStateItemPtr &item)
-        {
-            map<string, boost::shared_ptr<UdptlStateReplicatorItem> >::iterator i =
+                map<string, boost::shared_ptr<UdptlStateReplicatorItem> >::iterator i =
                     mImpl->mStateItems.find(item->sessionId);
-            if (i != mImpl->mStateItems.end())
+                if (i != mImpl->mStateItems.end())
+                {
+                    i->second->getSession()->update(item);
+                }
+            }
+
+            void visitUdptlStreamSourceStateItem(const UdptlStreamSourceStateItemPtr &item)
             {
-                i->second->getSession()->update(item);
+                map<string, boost::shared_ptr<UdptlStateReplicatorItem> >::iterator i =
+                    mImpl->mStateItems.find(item->sessionId);
+                if (i != mImpl->mStateItems.end())
+                {
+                    i->second->getSession()->update(item);
+                }
             }
-        }
-    };
+        };
 
         AsteriskSCF::Replication::UDPTL::V1::UdptlStateItemVisitorPtr v = new visitor(this);
 
@@ -157,7 +177,9 @@ public:
         }
     }
 
-    string mId;
+    boost::mutex mMutex;
+    OperationContextCachePtr mOperationContextCache;
+    const string mId;
     map<string, boost::shared_ptr<UdptlStateReplicatorItem> > mStateItems;
     Ice::ObjectAdapterPtr mAdapter;
     PJMediaEnvironmentPtr mEnvironment;
@@ -177,17 +199,18 @@ UdptlStateReplicatorListenerI::~UdptlStateReplicatorListenerI()
 {
 }
 
-void UdptlStateReplicatorListenerI::stateRemoved(const AsteriskSCF::System::V1::OperationContextPtr&, const Ice::StringSeq& itemKeys, const Ice::Current&)
+void UdptlStateReplicatorListenerI::stateRemoved(const AsteriskSCF::System::V1::OperationContextPtr& context, const Ice::StringSeq& itemKeys, const Ice::Current&)
 {
-    mImpl->removeStateNoticeImpl(itemKeys);
+    mImpl->removeStateNoticeImpl(context, itemKeys);
 }
 
-void UdptlStateReplicatorListenerI::stateSet(const AsteriskSCF::System::V1::OperationContextPtr&, const UdptlStateItemSeq& items, const Ice::Current&)
+void UdptlStateReplicatorListenerI::stateSet(const AsteriskSCF::System::V1::OperationContextPtr& context, const UdptlStateItemSeq& items, const Ice::Current&)
 {
-    mImpl->setStateNoticeImpl(items);
+    mImpl->setStateNoticeImpl(context, items);
 }
 
 bool UdptlStateReplicatorListenerI::operator==(const UdptlStateReplicatorListenerI &rhs)
 {
+    // reading immutable variables; no lock needed
     return mImpl->mId == rhs.mImpl->mId;
 }

commit 9d285b8ef5f79eb86242083652c7fc0790b57caa
Author: David M. Lee <dlee at digium.com>
Date:   Tue Apr 3 11:06:56 2012 -0500

    Retry logic for UDPTLSource

diff --git a/src/UDPTLSource.cpp b/src/UDPTLSource.cpp
index f3c828f..a1961bc 100644
--- a/src/UDPTLSource.cpp
+++ b/src/UDPTLSource.cpp
@@ -123,6 +123,7 @@ StreamSourceUDPTLImpl::StreamSourceUDPTLImpl(const SessionAdapterPtr& session,
  */
 void StreamSourceUDPTLImpl::addSink(const AsteriskSCF::System::V1::OperationContextPtr&, const AsteriskSCF::Media::V1::StreamSinkPrx& sink, const Ice::Current&)
 {
+    // naturally idempotent - no extra retry logic needed
     boost::unique_lock<boost::shared_mutex> lock(mImpl->mLock);
 
     // Do not allow the same sink to be added multiple times
@@ -144,6 +145,7 @@ void StreamSourceUDPTLImpl::addSink(const AsteriskSCF::System::V1::OperationCont
  */
 void StreamSourceUDPTLImpl::removeSink(const AsteriskSCF::System::V1::OperationContextPtr&, const AsteriskSCF::Media::V1::StreamSinkPrx& sink, const Ice::Current&)
 {
+    // naturally idempotent - no extra retry logic needed
     boost::unique_lock<boost::shared_mutex> lock(mImpl->mLock);
 
     mImpl->mSourceStateItem->sinks.erase(std::remove(mImpl->mSourceStateItem->sinks.begin(),
@@ -184,6 +186,7 @@ std::string StreamSourceUDPTLImpl::getId(const Ice::Current&)
  */
 void StreamSourceUDPTLImpl::requestFormat(const AsteriskSCF::System::V1::OperationContextPtr&, const AsteriskSCF::Media::V1::FormatPtr&, const Ice::Current&)
 {
+    // naturally idempotent - no extra retry logic needed
     // We do not currently support switching formats. 
     throw MediaFormatSwitchException();
 }

commit 1743a767617e9192c422ecb1967c85982c63fec2
Author: David M. Lee <dlee at digium.com>
Date:   Mon Apr 2 15:23:17 2012 -0500

    Retry logic for StreamSinkUDPTLImpl

diff --git a/src/UDPTLSink.cpp b/src/UDPTLSink.cpp
index f6f9ae4..61bfc4d 100644
--- a/src/UDPTLSink.cpp
+++ b/src/UDPTLSink.cpp
@@ -59,6 +59,8 @@ public:
 
     boost::shared_mutex mMutex;
 
+    OperationContextCachePtr mOperationContextCache;
+
     /**
      * A pointer to the UDPTL session we are associated with.
      */
@@ -149,7 +151,7 @@ void StreamSinkUDPTLImpl::write(const AsteriskSCF::Media::V1::FrameSeq& frames,
 /**
  * Implementation of the setSource method as defined in MediaIf.ice
  */
-void StreamSinkUDPTLImpl::setSource(const AsteriskSCF::System::V1::OperationContextPtr&, const AsteriskSCF::Media::V1::StreamSourcePrx& source, const Ice::Current&)
+void StreamSinkUDPTLImpl::setSource(const AsteriskSCF::System::V1::OperationContextPtr& context, const AsteriskSCF::Media::V1::StreamSourcePrx& source, const Ice::Current&)
 {
     // multiple sets naturally idempotent
     boost::unique_lock<boost::shared_mutex> lock(mImpl->mMutex);
@@ -191,11 +193,16 @@ std::string StreamSinkUDPTLImpl::getId(const Ice::Current&)
  * Implementation of the setRemoteDetails method as defined in NetworkIf.ice
  */
 void StreamSinkUDPTLImpl::setRemoteDetails(
-    const AsteriskSCF::System::V1::OperationContextPtr&,
+    const AsteriskSCF::System::V1::OperationContextPtr& context,
     const string& address, Ice::Int port,
     const Ice::Current&)
 {
     boost::unique_lock<boost::shared_mutex> lock(mImpl->mMutex);
+    if (!mImpl->mOperationContextCache->addOperationContext(context))
+    {
+        // retry detected
+        return;
+    }
     mImpl->mSessionAdapter->setRemoteDetails(address, port);
 
     mImpl->mSinkStateItem->remoteAddress = address;
@@ -216,9 +223,14 @@ AddressInformation StreamSinkUDPTLImpl::getRemoteDetails(const Ice::Current&)
 /**
  * Implemnentation of the setFarMaxDatagram method as defined in MediaUDPTLIf.ice
  */
-void StreamSinkUDPTLImpl::setFarMaxDatagram(const AsteriskSCF::System::V1::OperationContextPtr&, int datagram, const Ice::Current&)
+void StreamSinkUDPTLImpl::setFarMaxDatagram(const AsteriskSCF::System::V1::OperationContextPtr& context, int datagram, const Ice::Current&)
 {
     boost::unique_lock<boost::shared_mutex> lock(mImpl->mMutex);
+    if (!mImpl->mOperationContextCache->addOperationContext(context))
+    {
+        // retry detected
+        return;
+    }
     udptl_set_far_max_datagram(mImpl->mUdptl, datagram);
 
     mImpl->mSinkStateItem->farMaxDatagram = datagram;
@@ -247,9 +259,14 @@ Ice::Int StreamSinkUDPTLImpl::getFarMaxIFP(const Ice::Current&)
  * Implemnentation of the setErrorCorrectionScheme method as defined in MediaUDPTLIf.ice
  */
 void StreamSinkUDPTLImpl::setErrorCorrectionScheme(
-    const AsteriskSCF::System::V1::OperationContextPtr&, ErrorCorrectionScheme scheme, const Ice::Current&)
+    const AsteriskSCF::System::V1::OperationContextPtr& context, ErrorCorrectionScheme scheme, const Ice::Current&)
 {
     boost::unique_lock<boost::shared_mutex> lock(mImpl->mMutex);
+    if (!mImpl->mOperationContextCache->addOperationContext(context))
+    {
+        // retry detected
+        return;
+    }
     enum t38_ec_modes mode;
 
     if (scheme == FEC)

commit cf436d1ce94dc3e14c1ecdd9c953ea9609820b54
Author: David M. Lee <dlee at digium.com>
Date:   Mon Apr 2 15:06:10 2012 -0500

    Thread safety for StreamSinkUDPTLImpl

diff --git a/src/UDPTLSink.cpp b/src/UDPTLSink.cpp
index a9ba634..f6f9ae4 100644
--- a/src/UDPTLSink.cpp
+++ b/src/UDPTLSink.cpp
@@ -1,7 +1,7 @@
 /*
  * Asterisk SCF -- An open-source communications framework.
  *
- * Copyright (C) 2011, Digium, Inc.
+ * Copyright (C) 2011-2012, Digium, Inc.
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk SCF project. Please do not directly contact
@@ -20,22 +20,28 @@
 #include <pjlib.h>
 #include <pjmedia.h>
 
+#include <boost/thread.hpp>
+
 #include <Ice/Ice.h>
 #include <IceUtil/UUID.h>
 
 #include <AsteriskSCF/Media/MediaIf.h>
 #include <AsteriskSCF/Media/UDPTL/MediaUDPTLIf.h>
 #include <AsteriskSCF/System/Component/ReplicaIf.h>
+#include <AsteriskSCF/Operations/OperationContextCache.h>
 
 #include "udptl.h"
 
-using namespace std;
 using namespace AsteriskSCF::Core::Discovery::V1;
-using namespace AsteriskSCF::Media::V1;
 using namespace AsteriskSCF::Media::UDPTL::V1;
+using namespace AsteriskSCF::Media::V1;
 using namespace AsteriskSCF::Network::V1;
-using namespace AsteriskSCF::UDPTL;
+using namespace AsteriskSCF::Operations;
 using namespace AsteriskSCF::Replication::UDPTL::V1;
+using namespace AsteriskSCF::UDPTL;
+using namespace std;
+
+const int TTL_SECONDS = 180;
 
 /**
  * Private implementation details for the StreamSinkUDPTLImpl class.
@@ -46,11 +52,13 @@ public:
     /**
      * Constructor for our StreamSinkUDPTLImplPriv class.
      */
-    StreamSinkUDPTLImplPriv(const SessionAdapterPtr& sessionAdapter, 
+    StreamSinkUDPTLImplPriv(const SessionAdapterPtr& sessionAdapter,
                             const PJMediaTransportPtr& transport,
                             const std::string&,
                             struct udptl *udptl);
 
+    boost::shared_mutex mMutex;
+
     /**
      * A pointer to the UDPTL session we are associated with.
      */
@@ -80,13 +88,14 @@ public:
 /**
  * Constructor for the StreamSinkUDPTLImplPriv class.
  */
-StreamSinkUDPTLImplPriv::StreamSinkUDPTLImplPriv(const SessionAdapterPtr& session, 
+StreamSinkUDPTLImplPriv::StreamSinkUDPTLImplPriv(const SessionAdapterPtr& session,
                                                  const PJMediaTransportPtr& transport,
                                                  const string& sessionId,
                                                  struct udptl *udptl) :
+    mOperationContextCache(OperationContextCache::create(TTL_SECONDS)),
     mSessionAdapter(session),
     mTransport(transport),
-    mSinkStateItem(new UdptlStreamSinkStateItem), 
+    mSinkStateItem(new UdptlStreamSinkStateItem),
     mSessionId(sessionId),
     mUdptl(udptl)
 {
@@ -111,6 +120,7 @@ StreamSinkUDPTLImpl::StreamSinkUDPTLImpl(const SessionAdapterPtr& session,
  */
 void StreamSinkUDPTLImpl::write(const AsteriskSCF::Media::V1::FrameSeq& frames, const Ice::Current&)
 {
+    boost::unique_lock<boost::shared_mutex> lock(mImpl->mMutex);
     // Don't even bother if no remote address information is present
     if (mImpl->mSinkStateItem->remoteAddress.empty() || !mImpl->mSinkStateItem->remotePort)
     {
@@ -141,6 +151,8 @@ void StreamSinkUDPTLImpl::write(const AsteriskSCF::Media::V1::FrameSeq& frames,
  */
 void StreamSinkUDPTLImpl::setSource(const AsteriskSCF::System::V1::OperationContextPtr&, const AsteriskSCF::Media::V1::StreamSourcePrx& source, const Ice::Current&)
 {
+    // multiple sets naturally idempotent
+    boost::unique_lock<boost::shared_mutex> lock(mImpl->mMutex);
     mImpl->mSinkStateItem->source = source;
 
     mImpl->mSessionAdapter->replicateState(mImpl->mSinkStateItem);
@@ -151,6 +163,7 @@ void StreamSinkUDPTLImpl::setSource(const AsteriskSCF::System::V1::OperationCont
  */
 AsteriskSCF::Media::V1::StreamSourcePrx StreamSinkUDPTLImpl::getSource(const Ice::Current&)
 {
+    boost::shared_lock<boost::shared_mutex> lock(mImpl->mMutex);
     return mImpl->mSinkStateItem->source;
 }
 
@@ -159,6 +172,7 @@ AsteriskSCF::Media::V1::StreamSourcePrx StreamSinkUDPTLImpl::getSource(const Ice
  */
 AsteriskSCF::Media::V1::FormatSeq StreamSinkUDPTLImpl::getFormats(const Ice::Current&)
 {
+    // no access to local state - no need to lock
     FormatSeq formats;
     return formats;
 }
@@ -168,6 +182,7 @@ AsteriskSCF::Media::V1::FormatSeq StreamSinkUDPTLImpl::getFormats(const Ice::Cur
  */
 std::string StreamSinkUDPTLImpl::getId(const Ice::Current&)
 {
+    boost::shared_lock<boost::shared_mutex> lock(mImpl->mMutex);
     /* For now utilize the id of the session */
     return mImpl->mSessionId;
 }
@@ -176,10 +191,11 @@ std::string StreamSinkUDPTLImpl::getId(const Ice::Current&)
  * Implementation of the setRemoteDetails method as defined in NetworkIf.ice
  */
 void StreamSinkUDPTLImpl::setRemoteDetails(
-    const AsteriskSCF::System::V1::OperationContextPtr&, 
-    const string& address, Ice::Int port, 
+    const AsteriskSCF::System::V1::OperationContextPtr&,
+    const string& address, Ice::Int port,
     const Ice::Current&)
 {
+    boost::unique_lock<boost::shared_mutex> lock(mImpl->mMutex);
     mImpl->mSessionAdapter->setRemoteDetails(address, port);
 
     mImpl->mSinkStateItem->remoteAddress = address;
@@ -193,6 +209,7 @@ void StreamSinkUDPTLImpl::setRemoteDetails(
  */
 AddressInformation StreamSinkUDPTLImpl::getRemoteDetails(const Ice::Current&)
 {
+    boost::shared_lock<boost::shared_mutex> lock(mImpl->mMutex);
     return AddressInformation(mImpl->mSinkStateItem->remoteAddress, mImpl->mSinkStateItem->remotePort);
 }
 
@@ -201,6 +218,7 @@ AddressInformation StreamSinkUDPTLImpl::getRemoteDetails(const Ice::Current&)
  */
 void StreamSinkUDPTLImpl::setFarMaxDatagram(const AsteriskSCF::System::V1::OperationContextPtr&, int datagram, const Ice::Current&)
 {
+    boost::unique_lock<boost::shared_mutex> lock(mImpl->mMutex);
     udptl_set_far_max_datagram(mImpl->mUdptl, datagram);
 
     mImpl->mSinkStateItem->farMaxDatagram = datagram;
@@ -212,6 +230,7 @@ void StreamSinkUDPTLImpl::setFarMaxDatagram(const AsteriskSCF::System::V1::Opera
  */
 Ice::Int StreamSinkUDPTLImpl::getFarMaxDatagram(const Ice::Current&)
 {
+    boost::shared_lock<boost::shared_mutex> lock(mImpl->mMutex);
     return udptl_get_far_max_datagram(mImpl->mUdptl);
 }
 
@@ -220,6 +239,7 @@ Ice::Int StreamSinkUDPTLImpl::getFarMaxDatagram(const Ice::Current&)
  */
 Ice::Int StreamSinkUDPTLImpl::getFarMaxIFP(const Ice::Current&)
 {
+    boost::shared_lock<boost::shared_mutex> lock(mImpl->mMutex);
     return udptl_get_far_max_ifp(mImpl->mUdptl);
 }
 
@@ -229,6 +249,7 @@ Ice::Int StreamSinkUDPTLImpl::getFarMaxIFP(const Ice::Current&)
 void StreamSinkUDPTLImpl::setErrorCorrectionScheme(
     const AsteriskSCF::System::V1::OperationContextPtr&, ErrorCorrectionScheme scheme, const Ice::Current&)
 {
+    boost::unique_lock<boost::shared_mutex> lock(mImpl->mMutex);
     enum t38_ec_modes mode;
 
     if (scheme == FEC)
@@ -255,6 +276,7 @@ void StreamSinkUDPTLImpl::setErrorCorrectionScheme(
  */
 ErrorCorrectionScheme StreamSinkUDPTLImpl::getErrorCorrectionScheme(const Ice::Current&)
 {
+    boost::shared_lock<boost::shared_mutex> lock(mImpl->mMutex);
     enum t38_ec_modes mode = udptl_get_error_correction_scheme(mImpl->mUdptl);
 
     if (mode == UDPTL_ERROR_CORRECTION_FEC)
@@ -276,27 +298,32 @@ ErrorCorrectionScheme StreamSinkUDPTLImpl::getErrorCorrectionScheme(const Ice::C
  */
 UdptlStreamSinkStateItemPtr StreamSinkUDPTLImpl::getStateItem()
 {
+    boost::shared_lock<boost::shared_mutex> lock(mImpl->mMutex);
     return mImpl->mSinkStateItem;
 }
 
 void StreamSinkUDPTLImpl::setRemoteDetailsImpl(const std::string& host, Ice::Int port)
 {
+    boost::unique_lock<boost::shared_mutex> lock(mImpl->mMutex);
     mImpl->mSinkStateItem->remoteAddress = host;
     mImpl->mSinkStateItem->remotePort = port;
 }
 
 void StreamSinkUDPTLImpl::setSourceImpl(const AsteriskSCF::Media::V1::StreamSourcePrx& proxy)
 {
+    boost::unique_lock<boost::shared_mutex> lock(mImpl->mMutex);
     mImpl->mSinkStateItem->source = proxy;
 }
 
 void StreamSinkUDPTLImpl::setFarMaxDatagramImpl(int datagram)
 {
+    boost::unique_lock<boost::shared_mutex> lock(mImpl->mMutex);
     udptl_set_far_max_datagram(mImpl->mUdptl, datagram);
 }
 
 void StreamSinkUDPTLImpl::setErrorCorrectionSchemeImpl(ErrorCorrectionScheme scheme)
 {
+    boost::unique_lock<boost::shared_mutex> lock(mImpl->mMutex);
     enum t38_ec_modes mode;
 
     if (scheme == FEC)
@@ -313,4 +340,4 @@ void StreamSinkUDPTLImpl::setErrorCorrectionSchemeImpl(ErrorCorrectionScheme sch
     }
 
     udptl_set_error_correction_scheme(mImpl->mUdptl, mode);
-}    
+}

commit c45133e77350087a3dd56b2e0ddecf7557b9cce0
Author: David M. Lee <dlee at digium.com>
Date:   Mon Apr 2 15:05:05 2012 -0500

    Retry logic for UDPTLSessionImpl

diff --git a/src/UDPTLSession.cpp b/src/UDPTLSession.cpp
index a2ff51c..243132a 100644
--- a/src/UDPTLSession.cpp
+++ b/src/UDPTLSession.cpp
@@ -1,7 +1,7 @@
 /*
  * Asterisk SCF -- An open-source communications framework.
  *
- * Copyright (C) 2011, Digium, Inc.
+ * Copyright (C) 2011-2012, Digium, Inc.
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk SCF project. Please do not directly contact
@@ -34,18 +34,23 @@
 #include <AsteriskSCF/Media/UDPTL/MediaUDPTLIf.h>
 #include <AsteriskSCF/System/Component/ReplicaIf.h>
 #include <AsteriskSCF/Operations/OperationContext.h>
+#include <AsteriskSCF/Operations/OperationContextCache.h>
 
 #include "udptl.h"
 
-using namespace std;
 using namespace AsteriskSCF::Core::Discovery::V1;
-using namespace AsteriskSCF::Media::V1;
+using namespace AsteriskSCF::Discovery;
 using namespace AsteriskSCF::Media::UDPTL::V1;
+using namespace AsteriskSCF::Media::V1;
 using namespace AsteriskSCF::Media;
+using namespace AsteriskSCF::Operations;
 using namespace AsteriskSCF::Replication::UDPTL::V1;
 using namespace AsteriskSCF::System::Component::V1;
-using namespace AsteriskSCF::Discovery;
+using namespace AsteriskSCF::System::V1;
 using namespace AsteriskSCF::UDPTL;
+using namespace std;
+
+const int TTL_SECONDS = 180;
 
 /**
  * Implementation of the UDPTLSession interface as defined in MediaUDPTLIf.ice
@@ -114,6 +119,8 @@ private:
 
     boost::shared_mutex mLock;
 
+    OperationContextCachePtr mOperationContextCache;
+
     /**
      * Instance of the session adapter to be passed to sinks, sources, configuration, etc.
      */
@@ -223,7 +230,8 @@ UDPTLSessionImpl::UDPTLSessionImpl(const Ice::ObjectAdapterPtr& adapter,
                                    const PJMediaEnvironmentPtr& env,
                                    const UDPTLServiceLocatorParamsPtr& params,
                                    const UdptlReplicationContextPtr& replicationContext,
-                                   const ConfigurationServiceImplPtr& configurationService) : 
+                                   const ConfigurationServiceImplPtr& configurationService) :
+    mOperationContextCache(OperationContextCache::create(TTL_SECONDS)),
     mEnvironment(env),
     mEndpoint(PJMediaEndpoint::create(env)),
     mId(id),
@@ -265,6 +273,7 @@ UDPTLSessionImpl::UDPTLSessionImpl(const Ice::ObjectAdapterPtr& adapter,
                                    bool ipv6,
                                    const UdptlReplicationContextPtr& replicationContext,
                                    const ConfigurationServiceImplPtr& configurationService) :
+    mOperationContextCache(OperationContextCache::create(TTL_SECONDS)),
     mEnvironment(env),
     mEndpoint(PJMediaEndpoint::create(env)),
     mId(sessionIdentity),
@@ -328,11 +337,17 @@ void UDPTLSessionImpl::setCookies(const AsteriskSCF::Media::V1::SessionCookieDic
 /**
  * Support for the corresponding API call.
  */
-void UDPTLSessionImpl::setCookies(const AsteriskSCF::System::V1::OperationContextPtr&, const AsteriskSCF::Media::V1::SessionCookies& cookies,
-                                  const Ice::Current&)
+void UDPTLSessionImpl::setCookies(const AsteriskSCF::System::V1::OperationContextPtr& context,
+    const AsteriskSCF::Media::V1::SessionCookies& cookies,
+    const Ice::Current&)
 {
     { // scope the lock
         boost::unique_lock<boost::shared_mutex> lock(mLock);
+        if (!mOperationContextCache->addOperationContext(context))
+        {
+            // retry detected
+            return;
+        }
         for (AsteriskSCF::Media::V1::SessionCookies::const_iterator i = cookies.begin();
              i != cookies.end();  ++i)
         {
@@ -377,11 +392,17 @@ void UDPTLSessionImpl::getCookies_async(
 /**
  * Implementation of the corresponding API call.
  */
-void UDPTLSessionImpl::removeCookies(const AsteriskSCF::System::V1::OperationContextPtr&, const AsteriskSCF::Media::V1::SessionCookies& cookies,
-                                   const Ice::Current&)
+void UDPTLSessionImpl::removeCookies(const AsteriskSCF::System::V1::OperationContextPtr& context,
+    const AsteriskSCF::Media::V1::SessionCookies& cookies,
+    const Ice::Current&)
 {
     { // scope the lock
         boost::unique_lock<boost::shared_mutex> lock(mLock);
+        if (!mOperationContextCache->addOperationContext(context))
+        {
+            // retry detected
+            return;
+        }
         for (AsteriskSCF::Media::V1::SessionCookies::const_iterator i = cookies.begin();
              i != cookies.end(); ++i)
         {

commit bc0debcd8a9a26d25ee86d698074376512e2a2d5
Author: David M. Lee <dlee at digium.com>
Date:   Mon Apr 2 15:04:40 2012 -0500

    Retry comments for ConfigurationServiceServant

diff --git a/src/UDPTLConfiguration.cpp b/src/UDPTLConfiguration.cpp
index a3d5b2c..ce0f987 100644
--- a/src/UDPTLConfiguration.cpp
+++ b/src/UDPTLConfiguration.cpp
@@ -21,7 +21,6 @@
 #include <AsteriskSCF/System/Component/ConfigurationIf.h>
 
 #include <boost/thread.hpp>
-#include <boost/thread/shared_mutex.hpp>
 
 #include "udptl.h"
 
@@ -287,6 +286,7 @@ void ConfigurationServiceServant::setConfiguration(
     const ConfigurationGroupSeq& groups,
     const Ice::Current&)
 {
+    // config's serial number already handles idempotency
     class GroupVisitor : public UdptlConfigurationGroupVisitor
     {
     public:
@@ -474,6 +474,7 @@ void ConfigurationServiceServant::setConfiguration(
 void ConfigurationServiceServant::removeConfigurationItems(const AsteriskSCF::System::V1::OperationContextPtr&, 
     const AsteriskSCF::System::Configuration::V1::ConfigurationGroupSeq& groups, const Ice::Current&)
 {
+    // multiple removes would be naturally idempotent
     class GroupVisitor : public UdptlConfigurationGroupVisitor
     {
     public:
@@ -628,6 +629,7 @@ void ConfigurationServiceServant::removeConfigurationItems(const AsteriskSCF::Sy
 void ConfigurationServiceServant::removeConfigurationGroups(const AsteriskSCF::System::V1::OperationContextPtr&, 
     const ConfigurationGroupSeq& groups, const Ice::Current&)
 {
+    // multiple removes would be naturally idempotent
     class GroupVisitor : public UdptlConfigurationGroupVisitor
     {
     public:

commit 9351c7272480d96c45b95aa76ce0f0c821a2e650
Author: David M. Lee <dlee at digium.com>
Date:   Mon Apr 2 10:42:01 2012 -0500

    Added retry logic to ICEAgentImpl.
    
    Fixes some style issues while I was at it.

diff --git a/src/ICETransport.cpp b/src/ICETransport.cpp
index 1b1ddd9..ae798d6 100644
--- a/src/ICETransport.cpp
+++ b/src/ICETransport.cpp
@@ -1,7 +1,7 @@
 /*
  * Asterisk SCF -- An open-source communications framework.
  *
- * Copyright (C) 2010, Digium, Inc.
+ * Copyright (C) 2010,2012, Digium, Inc.
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk SCF project. Please do not directly contact
@@ -14,39 +14,41 @@
  * at the top of the source tree.
  */
 
-#include "ICETransport.h"
-#include "PJUtil.h"
+#include <map>
+#include <sstream>
 
-#include <pjmedia.h>
-#include <pjlib.h>
-#include <pjnath.h>
+#include <Ice/Ice.h>
+#include <IceUtil/UUID.h>
 
-#include <AsteriskSCF/System/ExceptionsIf.h>
-#include <map>
 #include <boost/thread.hpp>
 #include <boost/thread/shared_mutex.hpp>
 
+#include <pjlib.h>
+#include <pjmedia.h>
+#include <pjnath.h>
+
+#include <AsteriskSCF/System/ExceptionsIf.h>
 #include <AsteriskSCF/System/NAT/NATTraversalIf.h>
-#include <Ice/Ice.h>
-#include <sstream>
+#include <AsteriskSCF/Operations/OperationContextCache.h>
 #include <AsteriskSCF/Logger.h>
-#include <IceUtil/UUID.h>
 
-using namespace AsteriskSCF::UDPTL;
-using namespace AsteriskSCF::System::V1;
-using namespace AsteriskSCF::PJUtil;
-using namespace std;
+#include "ICETransport.h"
+#include "PJUtil.h"
+
 using namespace AsteriskSCF::Helpers;
+using namespace AsteriskSCF::Operations;
+using namespace AsteriskSCF::PJUtil;
 using namespace AsteriskSCF::System::Logging;
 using namespace AsteriskSCF::System::NAT::V1;
+using namespace AsteriskSCF::System::V1;
+using namespace AsteriskSCF::UDPTL;
+using namespace std;
 
 namespace
 {
 Logger logger = getLoggerFactory().getLogger("AsteriskSCF.MediaUDPTL");
-}
 
-namespace 
-{
+const int TTL_SECONDS = 180;
 
 class ICEAgentImpl : public InteractiveConnectionAgent
 {
@@ -54,6 +56,7 @@ public:
 
     ICEAgentImpl(const Ice::ObjectAdapterPtr& adapter, const Ice::Identity& id, const PJMediaEnvironmentPtr& env,
         const PJMediaEndpointPtr& ep) :
+        mOperationContextCache(OperationContextCache::create(TTL_SECONDS)),
         mAdapter(adapter),
         mId(id),
         mShuttingDown(false),
@@ -85,11 +88,15 @@ public:
     }
 
     void negotiate_async(const AMD_InteractiveConnectionAgent_negotiatePtr& callback,
-        const AsteriskSCF::System::V1::OperationContextPtr&,
+        const AsteriskSCF::System::V1::OperationContextPtr& context,
         const string& hostname, Ice::Int port, const CandidateSeq& candidates,
         const Ice::Current&)
     {
-
+        if (!mOperationContextCache->addOperationContext(context))
+        {
+            // retry detected; ignore
+            return;
+        }
         boost::unique_lock<boost::shared_mutex> lock(mLock);
         stateCheck();
         if (mCurrentNegotiation)
@@ -494,6 +501,7 @@ public:
 
 private:
     boost::shared_mutex mLock;
+    OperationContextCachePtr mOperationContextCache;
     Ice::ObjectAdapterPtr mAdapter;
     Ice::Identity mId;
     bool mShuttingDown;

commit e05943212a4295dbce188bb45a7f4cb2fe34e5b7
Author: David M. Lee <dlee at digium.com>
Date:   Thu Mar 29 18:01:05 2012 -0500

    Extracted testOrSetAndLock to ice-util-cpp.
    
    Changed 27 lines of code to 10 FTW.

diff --git a/src/Component.cpp b/src/Component.cpp
index 9375e56..7bab1b3 100644
--- a/src/Component.cpp
+++ b/src/Component.cpp
@@ -63,13 +63,7 @@ const string ReplicaServiceId("MediaUdptlReplica");
 const string MediaServiceId("UDPTLMediaService");
 const int TTL_SECONDS = 180;
 
-class UDPTLSessionPrxCookie : public ValueOperationContextCookie<UDPTLSessionPrx>
-{
-public:
-    boost::mutex &getMutex() { return mMutex; }
-private:
-    boost::mutex mMutex;
-};
+typedef ValueOperationContextCookieWithLock<UDPTLSessionPrx> UDPTLSessionPrxCookie;
 
 typedef boost::shared_ptr<UDPTLSessionPrxCookie> UDPTLSessionPrxCookiePtr;
 }
@@ -94,41 +88,30 @@ public:
     UDPTLSessionPrx allocate(const AsteriskSCF::System::V1::OperationContextPtr& operationContext,
         const UDPTLServiceLocatorParamsPtr& params, const Ice::Current&)
     {
-        // The service itself doesn't need a lock, so we'll lock the cookie instead to reduce needless
-        // contention.
-        const UDPTLSessionPrxCookiePtr cookie(new UDPTLSessionPrxCookie);
-        OperationContextCookiePtr existingCookie;
-        // lock this cookie so that no one will get our results prematurely
-        boost::lock_guard<boost::mutex> lock(cookie->getMutex());
-        mOperationContextCache->addOperationContext(operationContext, cookie, existingCookie);
-
-        if (existingCookie)
+        std::pair<bool, UDPTLSessionPrxCookiePtr> cacheHit =
+            testOrSetAndLock<UDPTLSessionPrxCookie>(mOperationContextCache, operationContext);
+        boost::mutex::scoped_lock lock(cacheHit.second->getMutex(), boost::adopt_lock);
+
+        if (cacheHit.first)
         {
-            // retry detected!
-            UDPTLSessionPrxCookiePtr c =
-                boost::dynamic_pointer_cast<UDPTLSessionPrxCookie>(existingCookie);
-            assert(c);
-            // Even though we're holding a lock on cookie, it's never left this function; no one can be waiting on it.
-            // There's no danger of deadlocking while waiting on the lock for existingCookie.
-            boost::lock_guard<boost::mutex> lockExistingCookie(c->getMutex());
-            return c->get();
+            return cacheHit.second->get();
         }
 
         try
         {
             UDPTLSessionPrx r = AsteriskSCF::UDPTL::UDPTLSession::create(mAdapter, IceUtil::generateUUID(),
                 mEnvironment, params, mReplicationContext, mConfigurationService);
-            cookie->set(r);
+            cacheHit.second->set(r);
             return r;
         }
         catch (const std::exception& e)
         {
-            cookie->setException(e);
+            cacheHit.second->setException(e);
             throw;
         }
         catch (...)
         {
-            cookie->setException();
+            cacheHit.second->setException();
             throw;
         }
     };

commit 45313f9d69d147e81e320937daff31060c1bd182
Author: David M. Lee <dlee at digium.com>
Date:   Thu Mar 29 15:50:12 2012 -0500

    Retry logic for UDPTLMediaServiceImpl::allocate

diff --git a/src/Component.cpp b/src/Component.cpp
index 2082485..9375e56 100644
--- a/src/Component.cpp
+++ b/src/Component.cpp
@@ -1,7 +1,7 @@
 /*
  * Asterisk SCF -- An open-source communications framework.
  *
- * Copyright (C) 2011, Digium, Inc.
+ * Copyright (C) 2011-2012, Digium, Inc.
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk SCF project. Please do not directly contact
@@ -32,6 +32,7 @@
 #include <AsteriskSCF/Discovery/SmartProxy.h>
 #include <AsteriskSCF/Component/Component.h>
 #include <AsteriskSCF/Operations/OperationContext.h>
+#include <AsteriskSCF/Operations/OperationContextCache.h>
 
 #include "UdptlReplicationContext.h"
 #include "UDPTLSession.h"
@@ -41,25 +42,37 @@
 #include "PJMediaEnvironment.h"
 
 using namespace std;
+using namespace AsteriskSCF::Configuration::UDPTL::V1;
 using namespace AsteriskSCF::Core::Discovery::V1;
-using namespace AsteriskSCF::Media::V1;
+using namespace AsteriskSCF::Discovery;
 using namespace AsteriskSCF::Media::UDPTL::V1;
+using namespace AsteriskSCF::Media::V1;
+using namespace AsteriskSCF::Operations;
 using namespace AsteriskSCF::Replication::UDPTL::V1;
-using namespace AsteriskSCF::Configuration::UDPTL::V1;
-using namespace AsteriskSCF::System::Configuration::V1;
+using namespace AsteriskSCF::Replication;
 using namespace AsteriskSCF::System::Component::V1;
+using namespace AsteriskSCF::System::Configuration::V1;
 using namespace AsteriskSCF::System::Logging;
-using namespace AsteriskSCF::Discovery;
-using namespace AsteriskSCF::Replication;
 using namespace AsteriskSCF::UDPTL;
 
 namespace
 {
 Logger lg = getLoggerFactory().getLogger("AsteriskSCF.MediaUDPTL");
-}
 
-static const string ReplicaServiceId("MediaUdptlReplica");
-static const string MediaServiceId("UDPTLMediaService");
+const string ReplicaServiceId("MediaUdptlReplica");
+const string MediaServiceId("UDPTLMediaService");
+const int TTL_SECONDS = 180;
+
+class UDPTLSessionPrxCookie : public ValueOperationContextCookie<UDPTLSessionPrx>
+{
+public:
+    boost::mutex &getMutex() { return mMutex; }
+private:
+    boost::mutex mMutex;
+};
+
+typedef boost::shared_ptr<UDPTLSessionPrxCookie> UDPTLSessionPrxCookiePtr;
+}
 
 /**
  * Implementation of the UDPTLMediaService interface as defined in MediaUDPTLIf.ice
@@ -70,6 +83,7 @@ public:
     UDPTLMediaServiceImpl(const Ice::ObjectAdapterPtr& adapter,
                           const UdptlReplicationContextPtr& replicationContext,
                           const ConfigurationServiceImplPtr& configurationService) :
+        mOperationContextCache(OperationContextCache::create(TTL_SECONDS)),
         mAdapter(adapter),
         mEnvironment(PJMediaEnvironment::create(adapter->getCommunicator()->getProperties(), configurationService)),
         mReplicationContext(replicationContext),
@@ -77,10 +91,46 @@ public:
     {
     };
 
-    UDPTLSessionPrx allocate(const AsteriskSCF::System::V1::OperationContextPtr&, const UDPTLServiceLocatorParamsPtr& params, const Ice::Current&)
+    UDPTLSessionPrx allocate(const AsteriskSCF::System::V1::OperationContextPtr& operationContext,
+        const UDPTLServiceLocatorParamsPtr& params, const Ice::Current&)
     {
-        return AsteriskSCF::UDPTL::UDPTLSession::create(mAdapter, IceUtil::generateUUID(), mEnvironment, params,
-                                                        mReplicationContext, mConfigurationService);
+        // The service itself doesn't need a lock, so we'll lock the cookie instead to reduce needless
+        // contention.
+        const UDPTLSessionPrxCookiePtr cookie(new UDPTLSessionPrxCookie);
+        OperationContextCookiePtr existingCookie;
+        // lock this cookie so that no one will get our results prematurely
+        boost::lock_guard<boost::mutex> lock(cookie->getMutex());
+        mOperationContextCache->addOperationContext(operationContext, cookie, existingCookie);
+
+        if (existingCookie)
+        {
+            // retry detected!
+            UDPTLSessionPrxCookiePtr c =
+                boost::dynamic_pointer_cast<UDPTLSessionPrxCookie>(existingCookie);
+            assert(c);
+            // Even though we're holding a lock on cookie, it's never left this function; no one can be waiting on it.
+            // There's no danger of deadlocking while waiting on the lock for existingCookie.
+            boost::lock_guard<boost::mutex> lockExistingCookie(c->getMutex());
+            return c->get();
+        }
+
+        try
+        {
+            UDPTLSessionPrx r = AsteriskSCF::UDPTL::UDPTLSession::create(mAdapter, IceUtil::generateUUID(),
+                mEnvironment, params, mReplicationContext, mConfigurationService);
+            cookie->set(r);
+            return r;
+        }
+        catch (const std::exception& e)
+        {
+            cookie->setException(e);
+            throw;
+        }
+        catch (...)
+        {
+            cookie->setException();
+            throw;
+        }
     };
 
     pj_pool_factory *getPoolFactory() { return mEnvironment->poolFactory(); };
@@ -91,6 +141,7 @@ public:
     }
 
 private:
+    AsteriskSCF::Operations::OperationContextCachePtr mOperationContextCache;
     Ice::ObjectAdapterPtr mAdapter;
     PJMediaEnvironmentPtr mEnvironment;
     UdptlReplicationContextPtr mReplicationContext;
diff --git a/test/TestMediaTransportUDPTL.cpp b/test/TestMediaTransportUDPTL.cpp
index 201650e..de5471a 100644
--- a/test/TestMediaTransportUDPTL.cpp
+++ b/test/TestMediaTransportUDPTL.cpp
@@ -428,7 +428,7 @@ BOOST_AUTO_TEST_CASE(AllocateUDPTLSession)
         params->category = "udptl";
         params->service = "";
 #ifdef IPV6_TEST
-    params->ipv6 = true;
+        params->ipv6 = true;
 #endif
 
         UDPTLMediaServicePrx service = UDPTLMediaServicePrx::uncheckedCast(Testbed.locator->locate(params));
@@ -1017,6 +1017,77 @@ BOOST_AUTO_TEST_CASE(ReleaseUDPTLSession)
     BOOST_CHECK(released);
 }
 
+/**
+ * Ensure that multiple calls to allocate return different proxies.
+ */
+BOOST_AUTO_TEST_CASE(AllocateDoubleCalls)
+{
+    UDPTLServiceLocatorParamsPtr params = new UDPTLServiceLocatorParams();
+    params->category = "udptl";
+    params->service = "";
+
+    UDPTLMediaServicePrx service = UDPTLMediaServicePrx::uncheckedCast(Testbed.locator->locate(params));
+
+    UDPTLSessionPrx expected = service->allocate(AsteriskSCF::Operations::createContext(), params);
+    UDPTLSessionPrx actual = service->allocate(AsteriskSCF::Operations::createContext(), params);
+
+    BOOST_REQUIRE_NE(expected, actual);
+}
+
+/**
+ * Test retry logic in ::allocate
+ */
+BOOST_AUTO_TEST_CASE(AllocateRetry)
+{
+    UDPTLServiceLocatorParamsPtr params = new UDPTLServiceLocatorParams();
+    params->category = "udptl";
+    params->service = "";
+
+    UDPTLMediaServicePrx service = UDPTLMediaServicePrx::uncheckedCast(Testbed.locator->locate(params));
+    AsteriskSCF::System::V1::OperationContextPtr context = AsteriskSCF::Operations::createContext();
+
+    UDPTLSessionPrx expected = service->allocate(context, params);
+    UDPTLSessionPrx actual = service->allocate(context, params);
+
+    BOOST_REQUIRE_EQUAL(expected, actual);
+}
+
+/**
+ * Test retry logic in ::allocate, when it throws an exception
+ */
+BOOST_AUTO_TEST_CASE(ThrowingAllocateRetry)
+{
+    UDPTLOverICEServiceLocatorParamsPtr params = new UDPTLOverICEServiceLocatorParams();
+    params->category = "udptl";
+    params->service = "";
+
+    UDPTLMediaServicePrx service = UDPTLMediaServicePrx::uncheckedCast(Testbed.locator->locate(params));
+    AsteriskSCF::System::V1::OperationContextPtr context = AsteriskSCF::Operations::createContext();
+
+    // allocating for ICE when ICE isn't enabled should throw an exception
+    params->enableICE = true;
+
+    try
+    {
+        service->allocate(context, params);
+        BOOST_FAIL("Expected allocation to throw an exception");
+    }
+    catch (const SessionAllocationFailure&)
+    {
+        // expected
+    }
+
+    try
+    {
+        service->allocate(context, params);
+        BOOST_FAIL("Expected allocation to throw an exception");
+    }
+    catch (const SessionAllocationFailure&)
+    {
+        // expected
+    }
+}
+
 void UDPTLTest::start(std::string const& name,
     Ice::CommunicatorPtr const&,
     Ice::StringSeq const& args)

-----------------------------------------------------------------------


-- 
asterisk-scf/integration/mediatransportudptl.git



More information about the asterisk-scf-commits mailing list