|
reSIProcate/stack
9694
|
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 */
1.7.5.1