reSIProcate/DialogUsageManager  9694
KeepAliveManager.cxx
Go to the documentation of this file.
00001 #include "resip/stack/KeepAliveMessage.hxx"
00002 #include "resip/stack/InteropHelper.hxx"
00003 #include "resip/dum/KeepAliveManager.hxx"
00004 #include "resip/dum/KeepAliveTimeout.hxx"
00005 #include "resip/dum/DialogUsageManager.hxx"
00006 #include "resip/stack/Helper.hxx"
00007 #include "rutil/Logger.hxx"
00008 #include "resip/stack/SipStack.hxx"
00009 
00010 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
00011 
00012 using namespace resip;
00013 using namespace std;
00014 
00015 int KeepAliveManager::mKeepAlivePongTimeoutMs = 10000;  // Defaults to 10000ms (10s) as specified in RFC5626 section 4.4.1
00016 
00017 void 
00018 KeepAliveManager::add(const Tuple& target, int keepAliveInterval, bool targetSupportsOutbound)
00019 {
00020    assert(mDum);
00021    NetworkAssociationMap::iterator it = mNetworkAssociations.find(target);
00022    if (it == mNetworkAssociations.end())
00023    {
00024       DebugLog(<< "First keep alive for id=" << mCurrentId << ": " << target << ", interval=" 
00025                << keepAliveInterval << "s, supportsOutbound=" << (targetSupportsOutbound ? "true" : "false"));
00026 
00027       NetworkAssociationInfo info;
00028       info.refCount = 1;
00029       info.keepAliveInterval = keepAliveInterval;
00030       info.id = mCurrentId;
00031       info.supportsOutbound = targetSupportsOutbound;
00032       info.pongReceivedForLastPing = false;
00033       mNetworkAssociations.insert(NetworkAssociationMap::value_type(target, info));
00034       KeepAliveTimeout t(target, mCurrentId);
00035       SipStack &stack = mDum->getSipStack();
00036       if(targetSupportsOutbound)
00037       {
00038          // Used randomized timeout between 80% and 100% of keepalivetime
00039          stack.post(t, Helper::jitterValue(keepAliveInterval, 80, 100), mDum);
00040       }
00041       else
00042       {
00043          stack.post(t, keepAliveInterval, mDum);
00044       }
00045       ++mCurrentId;
00046    }
00047    else
00048    {
00049       it->second.refCount++;
00050       if(keepAliveInterval < it->second.keepAliveInterval || targetSupportsOutbound)  // if targetSupportsOutbound, then always update the interval, as value may be from Flow-Timer header
00051       {
00052          // ?slg? only allow value to be shortened???  What if 2 different profiles 
00053          // with different keepAliveTime settings are sharing this network association?         
00054          it->second.keepAliveInterval = keepAliveInterval;  
00055       }
00056       if(targetSupportsOutbound)
00057       {
00058          // allow this to be updated to true only.  If any usage get's an indication of 
00059          // outbound support on this flow, then we accept it
00060          it->second.supportsOutbound = targetSupportsOutbound;  
00061       }
00062       DebugLog(<< "Association added for keep alive id=" << it->second.id << ": " << target 
00063                << ", interval=" << it->second.keepAliveInterval << "s, supportsOutbound=" 
00064                << (it->second.supportsOutbound ? "true" : "false") 
00065                << ", refCount=" << it->second.refCount);
00066    }
00067 }
00068 
00069 void 
00070 KeepAliveManager::remove(const Tuple& target)
00071 {
00072    NetworkAssociationMap::iterator it = mNetworkAssociations.find(target);
00073    if (it != mNetworkAssociations.end())
00074    {
00075       if (0 == --it->second.refCount)
00076       {
00077          DebugLog(<< "Last association removed for keep alive id=" << it->second.id << ": " << target);
00078          mNetworkAssociations.erase(it);
00079       }
00080       else
00081       {
00082          DebugLog(<< "Association removed for keep alive id=" << it->second.id << ": " << target << ", refCount=" << it->second.refCount);
00083       }
00084    }
00085 }
00086 
00087 void 
00088 KeepAliveManager::process(KeepAliveTimeout& timeout)
00089 {
00090    assert(mDum);
00091    static KeepAliveMessage msg;
00092    NetworkAssociationMap::iterator it = mNetworkAssociations.find(timeout.target());
00093    if (it != mNetworkAssociations.end() && timeout.id() == it->second.id)
00094    {
00095       SipStack &stack = mDum->getSipStack();
00096       DebugLog(<< "Refreshing keepalive for id=" << it->second.id << ": " << it->first
00097                << ", interval=" << it->second.keepAliveInterval << "s, supportsOutbound=" 
00098                << (it->second.supportsOutbound ? "true" : "false") 
00099                << ", refCount=" << it->second.refCount);
00100 
00101       if(InteropHelper::getOutboundVersion()>=8 && it->second.supportsOutbound && mKeepAlivePongTimeoutMs > 0)
00102       {
00103          // Assert if keep alive interval is too short in order to properly detect
00104          // missing pong responses - ie. interval must be greater than 10s
00105          assert((it->second.keepAliveInterval*1000) > mKeepAlivePongTimeoutMs);
00106 
00107          // Start pong timeout if transport is TCP based (note: pong processing of Stun messaging is currently not implemented)
00108          if(it->first.getType() == TCP || it->first.getType() == TLS)
00109          {
00110             DebugLog( << "Starting pong timeout for keepalive id " << it->second.id);
00111             KeepAlivePongTimeout t(it->first, it->second.id);
00112             stack.postMS(t, mKeepAlivePongTimeoutMs, mDum);
00113          }
00114       }
00115       it->second.pongReceivedForLastPing = false;  // reset flag
00116 
00117       stack.sendTo(msg, timeout.target(), mDum);
00118       KeepAliveTimeout t(it->first, it->second.id);
00119       if(it->second.supportsOutbound)
00120       {
00121          // Used randomized timeout between 80% and 100% of keepalivetime
00122          stack.post(t, Helper::jitterValue(it->second.keepAliveInterval, 80, 100), mDum);
00123       }
00124       else
00125       {
00126          stack.post(t, it->second.keepAliveInterval, mDum);
00127       }
00128    }
00129 }
00130 
00131 void 
00132 KeepAliveManager::process(KeepAlivePongTimeout& timeout)
00133 {
00134    assert(mDum);
00135    NetworkAssociationMap::iterator it = mNetworkAssociations.find(timeout.target());
00136    if (it != mNetworkAssociations.end() && timeout.id() == it->second.id)
00137    {
00138       if(!it->second.pongReceivedForLastPing)
00139       {
00140          // Timeout expecting pong response
00141          InfoLog(<< "Timed out expecting pong response for keep alive id=" << it->second.id << ": " << it->first);
00142          mDum->getSipStack().terminateFlow(it->first);
00143       }
00144    }
00145 }
00146 
00147 void 
00148 KeepAliveManager::receivedPong(const Tuple& flow)
00149 {
00150    NetworkAssociationMap::iterator it = mNetworkAssociations.find(flow);
00151    if (it != mNetworkAssociations.end())
00152    {
00153       DebugLog(<< "Received pong response for keep alive id=" << it->second.id << ": " << it->first);
00154       it->second.pongReceivedForLastPing = true;
00155    }
00156 }
00157 
00158 
00159 /* ====================================================================
00160  * The Vovida Software License, Version 1.0 
00161  * 
00162  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00163  * 
00164  * Redistribution and use in source and binary forms, with or without
00165  * modification, are permitted provided that the following conditions
00166  * are met:
00167  * 
00168  * 1. Redistributions of source code must retain the above copyright
00169  *    notice, this list of conditions and the following disclaimer.
00170  * 
00171  * 2. Redistributions in binary form must reproduce the above copyright
00172  *    notice, this list of conditions and the following disclaimer in
00173  *    the documentation and/or other materials provided with the
00174  *    distribution.
00175  * 
00176  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00177  *    and "Vovida Open Communication Application Library (VOCAL)" must
00178  *    not be used to endorse or promote products derived from this
00179  *    software without prior written permission. For written
00180  *    permission, please contact vocal@vovida.org.
00181  *
00182  * 4. Products derived from this software may not be called "VOCAL", nor
00183  *    may "VOCAL" appear in their name, without prior written
00184  *    permission of Vovida Networks, Inc.
00185  * 
00186  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00187  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00188  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00189  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00190  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00191  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00192  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00193  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00194  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00195  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00196  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00197  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00198  * DAMAGE.
00199  * 
00200  * ====================================================================
00201  * 
00202  * This software consists of voluntary contributions made by Vovida
00203  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00204  * Inc.  For more information on Vovida Networks, Inc., please see
00205  * <http://www.vovida.org/>.
00206  *
00207  */