reSIProcate/stack  9694
testStack.cxx
Go to the documentation of this file.
00001 #if defined(HAVE_CONFIG_H)
00002 #include "config.h"
00003 #endif
00004 
00005 #if defined (HAVE_POPT_H)
00006 #include <popt.h>
00007 #else
00008 #ifndef WIN32
00009 #warning "will not work very well without libpopt"
00010 #endif
00011 #endif
00012 
00013 #include <sys/types.h>
00014 #include <iostream>
00015 #include <memory>
00016 
00017 #include "rutil/GeneralCongestionManager.hxx"
00018 #include "rutil/DnsUtil.hxx"
00019 #include "rutil/Inserter.hxx"
00020 #include "rutil/Logger.hxx"
00021 #include "resip/stack/DeprecatedDialog.hxx"
00022 #include "resip/stack/Helper.hxx"
00023 #include "resip/stack/SipMessage.hxx"
00024 #include "resip/stack/SipStack.hxx"
00025 #include "resip/stack/StackThread.hxx"
00026 #include "rutil/SelectInterruptor.hxx"
00027 #include "resip/stack/TransportThread.hxx"
00028 #include "resip/stack/InterruptableStackThread.hxx"
00029 #include "resip/stack/EventStackThread.hxx"
00030 #include "resip/stack/Uri.hxx"
00031 
00032 using namespace resip;
00033 using namespace std;
00034 
00035 #define RESIPROCATE_SUBSYSTEM Subsystem::TEST
00036 
00037 /************************************************************************
00038 
00039   This application tests the core resip stack as a whole. It does
00040   this by creating two instances of SipStack, and sending messages
00041   (transactions) between them.
00042 
00043   Resiprocate is designed to support a variety of threading modeling
00044   and event handling models (e.g., select, poll, epoll system calls),
00045   and this test application can excercise various combinations.
00046 
00047   =============================================
00048   Options: --thread-type, --seltime, --intepoll
00049   The various permutations and are controlled via the --thread-type
00050   option.  Note that because this test application runs two stacks, its
00051   threading models are unusual, and not a good template for a "normal"
00052   application.
00053 
00054   The default thread-type is now "event" to better model "typical"
00055   applications.  The old behavior (pre-2011) can be obtained with
00056   "--thread-type=common"; this is useful for debugging stack internal
00057   issues since fewer threads running around.
00058 
00059   Values are:
00060 
00061     none        Everything (both stacks and test application) run in same
00062                 thread. App block for time specified by --seltime each
00063                 message cycle.  This defaults to zero, meaning app will
00064                 loop without every waiting, looking for any work to do.
00065                 When non-zero, app will wait this before checking queues.
00066                 Because of the endless spinning checking for work to do,
00067                 this mode is not useful for profiling.
00068 
00069     common      Like "none", everything (both stacks and test application)
00070                 run in same thread. Thread blocks until something to do,
00071                 and stacks will be configured to break the wait loop
00072                 when there is something for app to do. This avoids the
00073                 endless spinning of "none", and is useful for profiling.
00074 
00075     std         Each stack runs in its own thread, and that thread is
00076                 a "standard" select-based thread. This mode is now obsolete.
00077 
00078     intr        Each stack runs in its own thread, and that thread
00079                 is an interruptable select-based thread. Here, interruptable
00080                 means that when the app gives the thread work to do, it will
00081                 immediate wake up and do it, instead of waiting for
00082                 the select interval to expire. This mode is now obsolete.
00083 
00084     event       Each stack runs in its own thread, and that thread
00085                 is an interruptable event-loop based thread. The specific
00086                 type of event-loop depends upon the underlying platform
00087                 and how you compiled the stack.
00088 
00089     epoll       Like "event", but specifically uses the epoll implmentation.
00090 
00091     fdset       Like "event", but specifically uses the FdSet/select
00092                 implmentation.
00093 
00094   ===============
00095   Option: --bind
00096   The test application creates two stack and sends messages (requests
00097   and responses) between them using UDP or TCP transports. The --bind
00098   option controls where the UAS side is listening. This defaults to
00099   "127.0.0.1"; we use this as default because it avoids any dependency on DNS.
00100 
00101   If DNS is working on your system, then you can set this to the DNS name
00102   of one of your interfaces. Or you can use --bind=='' and we'll try
00103   to figure out your local DNS name.
00104 
00105 
00106 ************************************************************************/
00107 
00108 class SharedAsyncNotify : public AsyncProcessHandler
00109 {
00110    public:
00111       SharedAsyncNotify() { };
00112       virtual ~SharedAsyncNotify() { };
00113 
00114       virtual void handleProcessNotification();
00115 
00116       bool waitNotify(int ms);
00117 
00118    protected:
00119       Mutex mMutex;
00120       Condition mCondition;
00121 };
00122 
00123 void
00124 SharedAsyncNotify::handleProcessNotification()
00125 {
00126    Lock lock(mMutex); (void)lock;
00127    mCondition.signal();
00128 }
00129 
00137 bool
00138 SharedAsyncNotify::waitNotify(int ms)
00139 {
00140    Lock lock(mMutex); (void)lock;
00141 
00142    if (ms<0)
00143    {
00144       mCondition.wait(mMutex);
00145       return true;
00146    }
00147    else
00148    {
00149       return mCondition.wait(mMutex, ms);
00150    }
00151 }
00152 
00153 class SipStackAndThread
00154 {
00155    public:
00156       SipStackAndThread(const char *tType,
00157         AsyncProcessHandler *notifyDn=0,
00158         AsyncProcessHandler *notifyUp=0);
00159          ~SipStackAndThread() {
00160          destroy();
00161       }
00162 
00163       SipStack&         getStack() const { assert(mStack); return *mStack; }
00164 
00165       // I don't know if these are such a good idea
00166       SipStack&         operator*() const { assert(mStack); return *mStack; }
00167       SipStack*         operator->() const { return mStack; }
00168 
00169       void setCongestionManager(CongestionManager* cm)
00170       {
00171          mStack->setCongestionManager(cm);
00172       }
00173 
00174       void              run() 
00175       {
00176          if ( mThread ) mThread->run();
00177          if ( mMultiThreadedStack ) mStack->run();
00178       }
00179       void              shutdown()
00180       {
00181          if ( mThread ) mThread->shutdown();
00182       }
00183       void              join()
00184       {
00185          if ( mThread ) mThread->join();
00186          if ( mMultiThreadedStack ) mStack->shutdownAndJoinThreads();
00187       }
00188 
00189       void              destroy();
00190 
00191       // dis-allowed by not-implemented
00192       SipStackAndThread& operator=(SipStackAndThread&);
00193 
00194    protected:
00195 
00196       SipStack          *mStack;
00197       ThreadIf          *mThread;
00198       SelectInterruptor *mSelIntr;
00199       FdPollGrp         *mPollGrp;
00200       EventThreadInterruptor    *mEventIntr;
00201       bool mMultiThreadedStack;
00202 };
00203 
00204 
00205 SipStackAndThread::SipStackAndThread(const char *tType,
00206  AsyncProcessHandler *notifyDn, AsyncProcessHandler *notifyUp)
00207   : mStack(0), 
00208       mThread(0), 
00209       mSelIntr(0), 
00210       mPollGrp(0), 
00211       mEventIntr(0), 
00212       mMultiThreadedStack(false)
00213 {
00214    bool doStd = false;
00215 
00216    assert( tType );
00217 
00218    if (strcmp(tType,"intr")==0) 
00219    {
00220       mSelIntr = new SelectInterruptor();
00221    }
00222    else if ( strcmp(tType,"event")==0
00223           || strcmp(tType,"epoll")==0
00224           || strcmp(tType,"fdset")==0 )
00225    {
00226       mPollGrp = FdPollGrp::create(tType);
00227       mEventIntr = new EventThreadInterruptor(*mPollGrp);
00228    }
00229    else if ( strcmp(tType,"std")==0 ) 
00230    {
00231       doStd = true;
00232    } 
00233    else if ( strcmp(tType,"none")==0 ) 
00234    {
00235    }
00236    else if ( strcmp(tType,"multithreadedstack")==0 )
00237    {
00238       mMultiThreadedStack=true;
00239       mPollGrp = FdPollGrp::create("event");
00240       mEventIntr = new EventThreadInterruptor(*mPollGrp);
00241    }
00242    else 
00243    {
00244       CritLog(<<"Bad thread-type: "<<tType);
00245       exit(1);
00246    }
00247    SipStackOptions options;
00248    options.mAsyncProcessHandler = mEventIntr?mEventIntr
00249       :(mSelIntr?mSelIntr:notifyDn);
00250    options.mPollGrp = mPollGrp;
00251    mStack = new SipStack(options);
00252    
00253    mStack->setFallbackPostNotify(notifyUp);
00254    if (mEventIntr) 
00255    {
00256       mThread = new EventStackThread(*mStack, *mEventIntr, *mPollGrp);
00257    } 
00258    else 
00259    if (mSelIntr) 
00260    {
00261       mThread = new InterruptableStackThread(*mStack, *mSelIntr);
00262    } 
00263    else if (doStd) 
00264    {
00265       mThread = new StackThread(*mStack);
00266    }
00267 }
00268 
00269 void
00270 SipStackAndThread::destroy()
00271 {
00272    if ( mThread )
00273    {
00274       delete mThread;
00275       mThread = 0;
00276    }
00277    if ( mStack )
00278    {
00279       delete mStack;
00280       mStack = 0;
00281    }
00282    if ( mSelIntr )
00283    {
00284       delete mSelIntr;
00285       mSelIntr = 0;
00286    }
00287    if ( mEventIntr )
00288    {
00289       delete mEventIntr;
00290       mEventIntr = 0;
00291    }
00292    if ( mPollGrp )
00293    {
00294       delete mPollGrp;
00295       mPollGrp = 0;
00296    }
00297 }
00298 
00299 static void
00300 waitForTwoStacks(SipStackAndThread& receiver, SipStackAndThread& sender,
00301                  SelectInterruptor *commonIntr, int& thisseltime, bool& isStrange)
00302 {
00303    FdSet fdset;
00304    receiver->buildFdSet(fdset);
00305    sender->buildFdSet(fdset);
00306    if ( commonIntr )
00307    {
00308       commonIntr->buildFdSet(fdset);
00309    }
00310 
00311    if ( thisseltime > 0 )
00312    {
00313       unsigned int stackMs = resipMin(
00314               receiver->getTimeTillNextProcessMS(),
00315               sender->getTimeTillNextProcessMS());
00316       thisseltime = resipMin((unsigned)thisseltime, stackMs);
00317    }
00318    int numReady = fdset.selectMilliSeconds(thisseltime);
00319 
00320    isStrange = (thisseltime > 4000 && numReady==0);
00321    if ( commonIntr )
00322    {
00323       commonIntr->process(fdset);
00324    }
00325    receiver->process(fdset);
00326    sender->process(fdset);
00327 }
00328 
00329 struct StackThreadPair
00330 {
00331    StackThreadPair(SipStackAndThread& receiver,
00332      SipStackAndThread& sender, SharedAsyncNotify& sharedUp)
00333       : mReceiver(receiver), mSender(sender), mSharedUp(sharedUp),
00334        mSeltime(0), mNoStackThread(false), mCommonIntr(0)
00335    {
00336    }
00337 
00338    bool wait(int& thisseltime);
00339 
00340    SipStackAndThread& mReceiver;
00341    SipStackAndThread& mSender;
00342    SharedAsyncNotify& mSharedUp;
00343    int mSeltime;
00344    bool mNoStackThread;
00345    SelectInterruptor *mCommonIntr;
00346 };
00347 
00348 bool
00349 StackThreadPair::wait(int& thisseltime) {
00350    if(mReceiver.getStack().hasMessage() || mSender.getStack().hasMessage())
00351    {
00352       return false;
00353    }
00354 
00355    thisseltime = mSeltime;
00356    bool isStrange = false;
00357    if ( mNoStackThread )
00358    {
00359       // handles 'none' and 'common' thread-type
00360       // if none, then commonIntr will be NULL
00361       waitForTwoStacks( mReceiver, mSender, mCommonIntr, thisseltime, isStrange);
00362    }
00363    else
00364    {
00365       thisseltime = 4000;
00366       bool gotPost = mSharedUp.waitNotify(thisseltime);
00367       isStrange = !gotPost;
00368    }
00369    return isStrange;
00370 }
00371 
00372 
00373 static void
00374 performTest(int verbose, int runs, int window, int invite,
00375       Data& bindIfAddr,
00376       int numPorts, int senderPort, int registrarPort, const char *proto,
00377       int sendSleepUs,
00378       StackThreadPair& pair)
00379 {
00380    NameAddr target;
00381    target.uri().scheme() = "sip";
00382    target.uri().user() = "fluffy";
00383    target.uri().host() = bindIfAddr;
00384    target.uri().port() = registrarPort;
00385    target.uri().param(p_transport) = proto;
00386 
00387    NameAddr contact;
00388    contact.uri().scheme() = "sip";
00389    contact.uri().user() = "fluffy";
00390 
00391    NameAddr from = target;
00392    from.uri().port() = senderPort;
00393 
00394    UInt64 startTime = Timer::getTimeMs();
00395    int outstanding=0;
00396    int count = 0;
00397    int sent = 0;
00398 
00399    int rxReqTryCnt = 0, rxReqHitCnt = 0;
00400    int rxRspTryCnt = 0, rxRspHitCnt = 0;
00401 
00402    while (count < runs)
00403    {
00404       //InfoLog (<< "count=" << count << " messages=" << messages.size());
00405 
00406       // load up the send window
00407       for (int i=0; i<64 && sent < runs && outstanding < window; ++i)
00408       {
00409          DebugLog (<< "Sending " << count << " / " << runs << " (" << outstanding << ")");
00410          target.uri().port() = registrarPort + (sent%numPorts);
00411 
00412          SipMessage* next=0;
00413          if (invite)
00414          {
00415             next = Helper::makeInvite( target, from, contact);
00416          }
00417          else
00418          {
00419             next = Helper::makeRegister( target, from, contact);
00420          }
00421 
00422          // The Via header serves two purposes:
00423          // (1) tells the recipient where to send the response,
00424          // (2) selects which Transport we send from
00425          if (!bindIfAddr.empty() && numPorts > 1)
00426          {
00427              // currently TCP only honors Via if host is populated
00428              // the "numPorts>1" test is for backwards compat
00429              next->header(h_Vias).front().sentHost() = bindIfAddr;
00430          }
00431          next->header(h_Vias).front().sentPort() = senderPort + (sent%numPorts);
00432          pair.mSender->send(std::auto_ptr<SipMessage>(next));
00433          next = 0; // DON'T delete next; consumed by send above
00434          outstanding++;
00435          sent++;
00436 #ifndef WIN32
00437          if (sendSleepUs>0)
00438             usleep(sendSleepUs);
00439 #endif
00440       }
00441 
00442       int thisseltime = 0;
00443       bool isStrange = pair.wait(thisseltime);
00444       if (isStrange)
00445       {
00446          cout << "STRANGE: Stuck for long time: "
00447              <<" sent="<<sent
00448              <<" done="<<count
00449              <<" thisseltime="<<thisseltime
00450              <<endl;
00451       }
00452 
00453       for (int i=0;i<64;++i)
00454       {
00455          static NameAddr contact;
00456 
00457          ++rxReqTryCnt;
00458          SipMessage* request = pair.mReceiver->receive();
00459           if (request==NULL)
00460              break;
00461          ++rxReqHitCnt;
00462          assert(request->isRequest());
00463          SipMessage response;
00464          switch (request->header(h_RequestLine).getMethod())
00465          {
00466             case INVITE:
00467             {
00468                DeprecatedDialog dlg(contact);
00469                dlg.makeResponse(*request, response, 180);
00470                pair.mReceiver->send(response);
00471                dlg.makeResponse(*request, response, 200);
00472                pair.mReceiver->send(response);
00473                break;
00474             }
00475 
00476             case ACK:
00477                break;
00478 
00479             case BYE:
00480                Helper::makeResponse(response, *request, 200);
00481                pair.mReceiver->send(response);
00482                break;
00483 
00484             case REGISTER:
00485                Helper::makeResponse(response, *request, 200);
00486                pair.mReceiver->send(response);
00487                break;
00488             default:
00489                assert(0);
00490                break;
00491          }
00492          delete request;
00493       }
00494 
00495       for (int i=0;i<64;++i)
00496       {
00497          ++rxRspTryCnt;
00498          SipMessage* response = pair.mSender->receive();
00499          if (response==NULL)
00500             break;
00501          ++rxRspHitCnt;
00502          assert(response->isResponse());
00503          switch(response->header(h_CSeq).method())
00504          {
00505             case REGISTER:
00506                outstanding--;
00507                if (response->header(h_StatusLine).statusCode() == 200)
00508                {
00509                   count++;
00510                }
00511                else
00512                {
00513                   --sent;
00514                }
00515                break;
00516 
00517             case INVITE:
00518                if (response->header(h_StatusLine).statusCode() == 200)
00519                {
00520                   outstanding--;
00521                   count++;
00522 
00523                   DeprecatedDialog dlg(contact);
00524                   dlg.createDialogAsUAC(*response);
00525                   SipMessage* ack = dlg.makeAck();
00526                   pair.mSender->send(*ack);
00527                   delete ack;
00528 
00529                   SipMessage* bye = dlg.makeBye();
00530                   pair.mSender->send(*bye);
00531                   delete bye;
00532                }
00533                break;
00534 
00535             case BYE:
00536                break;
00537 
00538             default:
00539                assert(0);
00540                break;
00541          }
00542 
00543          delete response;
00544       }
00545    }
00546    InfoLog (<< "Finished " << count << " runs");
00547 
00548    UInt64 elapsed = Timer::getTimeMs() - startTime;
00549    if (!invite)
00550    {
00551       cout << runs << " registrations performed in " << elapsed << " ms, a rate of "
00552            << runs / ((float) elapsed / 1000.0) << " transactions per second." << endl;
00553    }
00554    else
00555    {
00556       cout << runs << " calls performed in " << elapsed << " ms, a rate of "
00557            << runs / ((float) elapsed / 1000.0) << " calls per second." << endl;
00558    }
00559    if ( verbose )
00560    {
00561       cout << "Note: this test runs both sides (client and server)" << endl;
00562 
00563       cout << "RxCnts: "
00564         <<" Req="<<rxReqHitCnt<<"/"<<rxReqTryCnt
00565         <<" ("<<(rxReqHitCnt*100/rxReqTryCnt)<<"%)"
00566         <<" Rsp="<<rxRspHitCnt<<"/"<<rxRspTryCnt
00567         <<" ("<<(rxRspHitCnt*100/rxRspTryCnt)<<"%)"
00568         << endl;
00569    }
00570 }
00571 
00572 int
00573 main(int argc, char* argv[])
00574 {
00575 
00576    const char* logType = "cout";
00577    const char* logLevel = "WARNING";
00578    const char* proto = "tcp";
00579    const char* bindAddr = "127.0.0.1";
00580    int doListen = 1;
00581 
00582    int verbose = 0;
00583    int runs = 10000;
00584    int window = 100;
00585    int seltime = 0;
00586    int v6 = 0;
00587    int invite=0;
00588    int numPorts = 1;
00589    int portBase = 0;
00590    const char* threadType = "event";
00591    int tpFlags = 0;
00592    int sendSleepUs = 0;
00593    int cManager=0;
00594    int statisticsInterval=60;
00595 
00596 #if defined(HAVE_POPT_H)
00597 
00598    char threadTypeDesc[200];
00599    strcpy(threadTypeDesc, "none|common|std|intr|multithreadedstack|");
00600    strcat(threadTypeDesc, FdPollGrp::getImplList());
00601 
00602    struct poptOption table[] = {
00603       {"log-type",    'l', POPT_ARG_STRING, &logType,   0, "where to send logging messages", "syslog|cerr|cout"},
00604       {"log-level",   'v', POPT_ARG_STRING, &logLevel,  0, "specify the default log level", "DEBUG|INFO|WARNING|ALERT"},
00605       {"num-runs",    'r', POPT_ARG_INT,    &runs,      0, "number of runs (SIP requests) in test", 0},
00606       {"window-size", 'w', POPT_ARG_INT,    &window,    0, "number of concurrent transactions", 0},
00607       {"select-time", 's', POPT_ARG_INT,    &seltime,   0, "polling interval (ms) for stack thread", 0},
00608       {"protocol",    'p', POPT_ARG_STRING, &proto,     0, "protocol to use (tcp | udp)", 0},
00609       {"bind",        'b', POPT_ARG_STRING, &bindAddr,  0, "interface address to bind to",0},
00610       {"listen",      0,   POPT_ARG_INT,    &doListen,  0, "do not bind/listen sender ports", 0},
00611       {"verbose",     0,   POPT_ARG_INT,    &verbose,   0, "verbose", 0},
00612       {"v6",          '6', POPT_ARG_NONE,   &v6     ,   0, "ipv6", 0},
00613       {"invite",      'i', POPT_ARG_NONE,   &invite ,   0, "send INVITE/BYE instead of REGISTER", 0},
00614       {"port",        0,   POPT_ARG_INT,    &portBase,  0, "first port to use", 0},
00615       {"numports",    'n', POPT_ARG_INT,    &numPorts,  0, "number of parallel sessions(ports)", 0},
00616       {"thread-type", 't', POPT_ARG_STRING, &threadType,0, "stack thread type", threadTypeDesc},
00617       {"tf",          0,   POPT_ARG_INT,    &tpFlags,   0, "bit encoding of transportFlags", 0},
00618       {"sleep",       0,   POPT_ARG_INT,    &sendSleepUs,0, "time (us) to sleep after each sent request", 0},
00619       {"use-congestion-manager",0, POPT_ARG_NONE, &cManager ,   0, "use a CongestionManager", 0},
00620       {"statistics-interval",       0,   POPT_ARG_INT,    &statisticsInterval,0, "time in seconds between statistics logging", 0},
00621       POPT_AUTOHELP
00622       { NULL, 0, 0, NULL, 0 }
00623    };
00624 
00625    poptContext context = poptGetContext(NULL, argc, const_cast<const char**>(argv), table, 0);
00626    int pret=poptGetNextOpt(context);
00627    assert(pret==-1);
00628    assert( poptGetArg(context)==NULL);
00629 #endif  // popt
00630    Log::initialize(logType, logLevel, argv[0]);
00631 
00632    Data bindIfAddr(bindAddr);
00633    if ( bindIfAddr.size()==0 )
00634    {
00635       bindIfAddr = DnsUtil::getLocalHostName();
00636    }
00637 
00638    cout << "Performing " << runs << " runs with"
00639      <<" win="<<window
00640      <<" ip"<<(v6?"v4":"v4")
00641      <<" proto="<<proto
00642      <<" numports="<<numPorts
00643      <<" thread="<<threadType
00644      <<" bindIf="<<bindIfAddr
00645      <<" listen="<<doListen
00646      <<" tf="<<tpFlags
00647      <<"." << endl;
00648 
00649    const char *eachThreadType = threadType;
00650    SelectInterruptor *commonIntr = NULL;
00651    AsyncProcessHandler *notifyUp = NULL;
00652    bool noStackThread = false;
00653    SharedAsyncNotify sharedUp;
00654    if ( strcmp(eachThreadType,"none")==0 )
00655    {
00656       // Everything runs in single thread,
00657       // and we spin, just keep cycling thru looking for stuff to do.
00658       // Default seltime is zero, so no delay at all. This isn't
00659       // very useful for profiling because we spend all our time checking
00660       // stuff to do.
00661       noStackThread = true;
00662    }
00663    else if ( strcmp(eachThreadType,"common")==0 )
00664    {
00665       // Everything runs in single thread, but thread blocks
00666       // until there is something to do. When there is something
00667       // to do within the stack (notifyDn) or app (notifyUp) the
00668       // common interruptor is invoked and it breaks the select loop.
00669       seltime = 10*1000;
00670       commonIntr = new SelectInterruptor();
00671       notifyUp = commonIntr;
00672       noStackThread = true;
00673       eachThreadType = "none";
00674    }
00675    else
00676    {
00677       notifyUp = &sharedUp;
00678    }
00679    SipStackAndThread receiver(eachThreadType, commonIntr, notifyUp);
00680    SipStackAndThread sender(eachThreadType, commonIntr, notifyUp);
00681    receiver.getStack().setStatisticsInterval(statisticsInterval);
00682    sender.getStack().setStatisticsInterval(statisticsInterval);
00683 
00684    IpVersion version = (v6 ? V6 : V4);
00685 
00686    // estimate number of sockets we need:
00687    // 2x for sender and receiver
00688    // 3 for UDP (listen + select interruptor) 
00689    // 4 for TCP (listen + connection + select interruptor)
00690    // ~30 for misc (DNS, SelectInterruptors)
00691    int needFds = numPorts * 14 + 30;
00692    increaseLimitFds(needFds);
00693 
00694    /* On linux, the client TCP connection port range is controll by
00695     * /proc/sys/net/ipv4/ip_local_port_range, and defaults to [32768,61000].
00696     * To avoid conflicts when binding, the bound ports below should
00697     * stay out of the range (e.g., below 32768)
00698     */
00699 
00700 
00701    int senderPort = portBase;
00702    if ( senderPort==0 )
00703       senderPort = numPorts==1 ? 25060+(rand()&0x0fff) : 11000;
00704    int registrarPort = senderPort + numPorts;
00705 
00706    int idx;
00707    std::vector<Transport*> transports;
00708    for (idx=0; idx < numPorts; idx++)
00709    {
00710       transports.push_back(sender->addTransport(UDP, 
00711                            senderPort+idx, 
00712                            version, 
00713                            StunDisabled, 
00714                            bindIfAddr,
00715                            /*sipDomain*/Data::Empty, 
00716                            /*keypass*/Data::Empty, 
00717                            SecurityTypes::TLSv1,
00718                            tpFlags));
00719 
00720       // NOBIND doesn't make sense for UDP
00721       transports.push_back(sender->addTransport(TCP, 
00722                            senderPort+idx, 
00723                            version, 
00724                            StunDisabled, 
00725                            bindIfAddr,
00726                            /*sipDomain*/Data::Empty, 
00727                            /*keypass*/Data::Empty, 
00728                            SecurityTypes::TLSv1,
00729                            tpFlags|(doListen?0:RESIP_TRANSPORT_FLAG_NOBIND)));
00730 
00731       // NOTE: we could also bind receive to bindIfAddr, but existing code
00732       // doesn't do this. Responses are sent from here, so why don't we?
00733       transports.push_back(receiver->addTransport(UDP, 
00734                              registrarPort+idx, 
00735                              version, 
00736                              StunDisabled,
00737                              /*ipInterface*/Data::Empty,
00738                              /*sipDomain*/Data::Empty, 
00739                              /*keypass*/Data::Empty, 
00740                              SecurityTypes::TLSv1,
00741                              tpFlags));
00742 
00743       transports.push_back(receiver->addTransport(TCP, 
00744                              registrarPort+idx, 
00745                              version, 
00746                              StunDisabled,
00747                              /*ipInterface*/Data::Empty,
00748                              /*sipDomain*/Data::Empty, 
00749                              /*keypass*/Data::Empty, 
00750                              SecurityTypes::TLSv1,
00751                              tpFlags));
00752    }
00753 
00754    std::auto_ptr<CongestionManager> senderCongestionManager;
00755    std::auto_ptr<CongestionManager> receiverCongestionManager;
00756    if(cManager)
00757    {
00758       senderCongestionManager.reset(new GeneralCongestionManager(
00759                                     GeneralCongestionManager::WAIT_TIME,
00760                                     200));
00761       receiverCongestionManager.reset(new GeneralCongestionManager(
00762                                     GeneralCongestionManager::WAIT_TIME,
00763                                     200));
00764       sender.setCongestionManager(senderCongestionManager.get());
00765       receiver.setCongestionManager(receiverCongestionManager.get());
00766    }
00767 
00768    std::vector<TransportThread*> transportThreads;
00769    if(tpFlags & RESIP_TRANSPORT_FLAG_OWNTHREAD)
00770    {
00771       while(!transports.empty())
00772       {
00773          transportThreads.push_back(new TransportThread(*transports.back()));
00774          transportThreads.back()->run();
00775          transports.pop_back();
00776       }
00777    }
00778 
00779    sender.run();
00780    receiver.run();
00781 
00782    StackThreadPair pair(receiver, sender, sharedUp);
00783    pair.mSeltime = seltime;
00784    pair.mCommonIntr = commonIntr;
00785    pair.mNoStackThread = noStackThread;
00786 
00787    performTest(verbose, runs, window, invite,
00788       bindIfAddr, numPorts, senderPort, registrarPort, proto,
00789       sendSleepUs, pair);
00790 
00791    sender.shutdown();
00792    receiver.shutdown();
00793 
00794    sender.join();
00795    receiver.join();
00796 
00797    sender.setCongestionManager(0);
00798    receiver.setCongestionManager(0);
00799 
00800    if(tpFlags&RESIP_TRANSPORT_FLAG_OWNTHREAD)
00801    {
00802       while(!transportThreads.empty())
00803       {
00804          transportThreads.back()->shutdown();
00805          transportThreads.back()->join();
00806          delete transportThreads.back();
00807          transportThreads.pop_back();
00808       }
00809    }
00810 
00811    sender.destroy();
00812    receiver.destroy();
00813 
00814    if ( commonIntr )
00815    {
00816        delete commonIntr;
00817        commonIntr = NULL;
00818    }
00819 
00820 #if defined(HAVE_POPT_H)
00821    poptFreeContext(context);
00822 #endif
00823    return 0;
00824 }
00825 /* ====================================================================
00826  * The Vovida Software License, Version 1.0
00827  *
00828  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00829  *
00830  * Redistribution and use in source and binary forms, with or without
00831  * modification, are permitted provided that the following conditions
00832  * are met:
00833  *
00834  * 1. Redistributions of source code must retain the above copyright
00835  *    notice, this list of conditions and the following disclaimer.
00836  *
00837  * 2. Redistributions in binary form must reproduce the above copyright
00838  *    notice, this list of conditions and the following disclaimer in
00839  *    the documentation and/or other materials provided with the
00840  *    distribution.
00841  *
00842  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00843  *    and "Vovida Open Communication Application Library (VOCAL)" must
00844  *    not be used to endorse or promote products derived from this
00845  *    software without prior written permission. For written
00846  *    permission, please contact vocal@vovida.org.
00847  *
00848  * 4. Products derived from this software may not be called "VOCAL", nor
00849  *    may "VOCAL" appear in their name, without prior written
00850  *    permission of Vovida Networks, Inc.
00851  *
00852  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00853  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00854  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00855  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00856  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00857  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00858  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00859  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00860  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00861  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00862  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00863  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00864  * DAMAGE.
00865  *
00866  * ====================================================================
00867  *
00868  * This software consists of voluntary contributions made by Vovida
00869  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00870  * Inc.  For more information on Vovida Networks, Inc., please see
00871  * <http://www.vovida.org/>.
00872  *
00873  * vi: set shiftwidth=3 expandtab:
00874  */