reSIProcate/stack  9694
TransactionController.cxx
Go to the documentation of this file.
00001 #if defined(HAVE_CONFIG_H)
00002 #include "config.h"
00003 #endif
00004 
00005 #include "resip/stack/AbandonServerTransaction.hxx"
00006 #include "resip/stack/ApplicationMessage.hxx"
00007 #include "resip/stack/CancelClientInviteTransaction.hxx"
00008 #include "resip/stack/Helper.hxx"
00009 #include "resip/stack/TerminateFlow.hxx"
00010 #include "resip/stack/EnableFlowTimer.hxx"
00011 #include "resip/stack/ZeroOutStatistics.hxx"
00012 #include "resip/stack/PollStatistics.hxx"
00013 #include "resip/stack/ShutdownMessage.hxx"
00014 #include "resip/stack/SipMessage.hxx"
00015 #include "resip/stack/TransactionController.hxx"
00016 #include "resip/stack/TransactionState.hxx"
00017 #ifdef USE_SSL
00018 #include "resip/stack/ssl/Security.hxx"
00019 #endif
00020 #include "rutil/CongestionManager.hxx"
00021 #include "rutil/DnsUtil.hxx"
00022 #include "rutil/Logger.hxx"
00023 #include "resip/stack/SipStack.hxx"
00024 #include "rutil/WinLeakCheck.hxx"
00025 
00026 using namespace resip;
00027 
00028 #define RESIPROCATE_SUBSYSTEM Subsystem::TRANSACTION
00029 
00030 #if defined(WIN32) && !defined (__GNUC__)
00031 #pragma warning( disable : 4355 ) // using this in base member initializer list 
00032 #endif
00033 
00034 unsigned int TransactionController::MaxTUFifoSize = 0;
00035 unsigned int TransactionController::MaxTUFifoTimeDepthSecs = 0;
00036 
00037 TransactionController::TransactionController(SipStack& stack, 
00038                                                 AsyncProcessHandler* handler) :
00039    mStack(stack),
00040    mDiscardStrayResponses(true),
00041    mFixBadDialogIdentifiers(true),
00042    mFixBadCSeqNumbers(true),
00043    mStateMacFifo(handler),
00044    mStateMacFifoOutBuffer(mStateMacFifo),
00045    mCongestionManager(0),
00046    mTuSelector(stack.mTuSelector),
00047    mTransportSelector(mStateMacFifo,
00048                       stack.getSecurity(),
00049                       stack.getDnsStub(),
00050                       stack.getCompression()),
00051    mTimers(mTimerFifo),
00052    mShuttingDown(false),
00053    mStatsManager(stack.mStatsManager),
00054    mHostname(DnsUtil::getLocalHostName())
00055 {
00056    mStateMacFifo.setDescription("TransactionController::mStateMacFifo");
00057 }
00058 
00059 #if defined(WIN32) && !defined(__GNUC__)
00060 #pragma warning( default : 4355 )
00061 #endif
00062 
00063 TransactionController::~TransactionController()
00064 {
00065    if(mClientTransactionMap.size())
00066    {
00067       WarningLog(<< "On shutdown, there are Client TransactionStates remaining!");
00068    }
00069 
00070    if(mServerTransactionMap.size())
00071    {
00072       WarningLog(<< "On shutdown, there are Server TransactionStates remaining!");
00073    }
00074 }
00075 
00076 
00077 bool 
00078 TransactionController::isTUOverloaded() const
00079 {
00080    return !mTuSelector.wouldAccept(TimeLimitFifo<Message>::EnforceTimeDepth);
00081 }
00082 
00083 void
00084 TransactionController::shutdown()
00085 {
00086    mShuttingDown = true;
00087    mTransportSelector.shutdown();
00088 }
00089 
00090 void
00091 TransactionController::process(int timeout)
00092 {
00093    if (mShuttingDown && 
00094        //mTimers.empty() && 
00095        !mStateMacFifoOutBuffer.messageAvailable() && // !dcm! -- see below 
00096        !mStack.mTUFifo.messageAvailable() &&
00097        mTransportSelector.isFinished())
00098 // !dcm! -- why would one wait for the Tu's fifo to be empty before delivering a
00099 // shutdown message?
00100    {
00102       mTuSelector.add(new ShutdownMessage, TimeLimitFifo<Message>::InternalElement);
00103    }
00104    else
00105    {
00106       unsigned int nextTimer(mTimers.msTillNextTimer());
00107       timeout=resipMin((int)nextTimer, timeout);
00108       if(timeout==0)
00109       {
00110          // *sigh*
00111          timeout=-1;
00112       }
00113 
00114       // If non-zero is passed for timeout, we understand that the caller is ok
00115       // with us waiting up to that long on this call. A non-zero timeout is
00116       // passed by TransactionControllerThread, for example. This gets us 
00117       // something approximating a blocking wait on both the state machine fifo 
00118       // and the timer queue.
00119       TransactionMessage* message=mStateMacFifoOutBuffer.getNext(timeout);
00120 
00121       // If we either had timers ready to go at the beginning of this call, or
00122       // the getNext() call above timed out, our timer queue is likely ready to 
00123       // be serviced.
00124       if(!message || nextTimer==0)
00125       {
00126          mTimers.process();
00127          TimerMessage* timer;
00128          while ((timer=mTimerFifo.getNext(-1)))
00129          {
00130             TransactionState::processTimer(*this,timer);
00131          }
00132       }
00133 
00134       if(message)
00135       {
00136          // Only do 16 at a time; don't let the timer queue (or other 
00137          // processing) starve.
00138          int runs=16;
00139          while(message)
00140          {
00141             TransactionState::process(*this, message);
00142             if(--runs==0)
00143             {
00144                break;
00145             }
00146             message = mStateMacFifoOutBuffer.getNext(-1);
00147          }
00148 
00149          mTransportSelector.poke();
00150       }
00151    }
00152 }
00153 
00154 unsigned int 
00155 TransactionController::getTimeTillNextProcessMS()
00156 {
00157    if ( mStateMacFifoOutBuffer.messageAvailable() ) 
00158    {
00159       return 0;
00160    }
00161    return mTimers.msTillNextTimer();
00162 } 
00163 
00164 void
00165 TransactionController::send(SipMessage* msg)
00166 {
00167    if(msg->isRequest() && 
00168       msg->method() != ACK && 
00169       getRejectionBehavior()!=CongestionManager::NORMAL)
00170    {
00171       // Need to 503 this.
00172       SipMessage* resp(Helper::makeResponse(*msg, 503));
00173       resp->header(h_RetryAfter).value()=(UInt32)mStateMacFifo.expectedWaitTimeMilliSec()/1000;
00174       resp->setTransactionUser(msg->getTransactionUser());
00175       mTuSelector.add(resp, TimeLimitFifo<Message>::InternalElement);
00176       delete msg;
00177       return;
00178    }
00179    mStateMacFifo.add(msg);
00180 }
00181 
00182 
00183 unsigned int 
00184 TransactionController::getTuFifoSize() const
00185 {
00186    return mTuSelector.size();
00187 }
00188 
00189 unsigned int 
00190 TransactionController::sumTransportFifoSizes() const
00191 {
00192    return mTransportSelector.sumTransportFifoSizes();
00193 }
00194 
00195 unsigned int 
00196 TransactionController::getTransactionFifoSize() const
00197 {
00198    // Should we include the stuff in mStateMacFifoOutBuffer here too? This is
00199    // likely to be called from other threads...
00200    return mStateMacFifo.size();
00201 }
00202 
00203 unsigned int 
00204 TransactionController::getNumClientTransactions() const
00205 {
00206    return mClientTransactionMap.size();
00207 }
00208 
00209 unsigned int 
00210 TransactionController::getNumServerTransactions() const
00211 {
00212    return mServerTransactionMap.size();
00213 }
00214 
00215 unsigned int 
00216 TransactionController::getTimerQueueSize() const
00217 {
00218    return mTimers.size();
00219 }
00220 
00221 void 
00222 TransactionController::zeroOutStatistics()
00223 {
00224    mStateMacFifo.add(new ZeroOutStatistics());
00225 }
00226 
00227 void 
00228 TransactionController::pollStatistics()
00229 {
00230    mStateMacFifo.add(new PollStatistics());
00231 }
00232 
00233 void
00234 TransactionController::registerMarkListener(MarkListener* listener)
00235 {
00236    mTransportSelector.registerMarkListener(listener);
00237 }
00238 
00239 void TransactionController::unregisterMarkListener(MarkListener* listener)
00240 {
00241    mTransportSelector.unregisterMarkListener(listener);
00242 }
00243 
00244 void 
00245 TransactionController::abandonServerTransaction(const Data& tid)
00246 {
00247    mStateMacFifo.add(new AbandonServerTransaction(tid));
00248 }
00249 
00250 void 
00251 TransactionController::cancelClientInviteTransaction(const Data& tid)
00252 {
00253    mStateMacFifo.add(new CancelClientInviteTransaction(tid));
00254 }
00255 
00256 void
00257 TransactionController::terminateFlow(const resip::Tuple& flow)
00258 {
00259    mStateMacFifo.add(new TerminateFlow(flow));
00260 }
00261 
00262 void
00263 TransactionController::enableFlowTimer(const resip::Tuple& flow)
00264 {
00265    mStateMacFifo.add(new EnableFlowTimer(flow));
00266 }
00267 
00268 void 
00269 TransactionController::setInterruptor(AsyncProcessHandler* handler)
00270 {
00271    mStateMacFifo.setInterruptor(handler);
00272 }
00273 
00274 /* ====================================================================
00275  * The Vovida Software License, Version 1.0 
00276  * 
00277  * Copyright (c) 2004 Vovida Networks, Inc.  All rights reserved.
00278  * 
00279  * Redistribution and use in source and binary forms, with or without
00280  * modification, are permitted provided that the following conditions
00281  * are met:
00282  * 
00283  * 1. Redistributions of source code must retain the above copyright
00284  *    notice, this list of conditions and the following disclaimer.
00285  * 
00286  * 2. Redistributions in binary form must reproduce the above copyright
00287  *    notice, this list of conditions and the following disclaimer in
00288  *    the documentation and/or other materials provided with the
00289  *    distribution.
00290  * 
00291  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00292  *    and "Vovida Open Communication Application Library (VOCAL)" must
00293  *    not be used to endorse or promote products derived from this
00294  *    software without prior written permission. For written
00295  *    permission, please contact vocal@vovida.org.
00296  *
00297  * 4. Products derived from this software may not be called "VOCAL", nor
00298  *    may "VOCAL" appear in their name, without prior written
00299  *    permission of Vovida Networks, Inc.
00300  * 
00301  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00302  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00303  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00304  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00305  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00306  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00307  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00308  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00309  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00310  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00311  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00312  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00313  * DAMAGE.
00314  * 
00315  * ====================================================================
00316  * 
00317  * This software consists of voluntary contributions made by Vovida
00318  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00319  * Inc.  For more information on Vovida Networks, Inc., please see
00320  * <http://www.vovida.org/>.
00321  *
00322  * vi: set shiftwidth=3 expandtab:
00323  */