|
reSIProcate/stack
9694
|
00001 // How this works: 00002 // 00003 // The first argument to this program needs to be a file that has a test in it. 00004 // 00005 // Clauses in this file can be: inject_wire, expect_wire, expect_tu, 00006 // inject_tu, and delay. A keyword needs to be by itself on a line. They 00007 // need to be in this form 00008 // 00009 // inject_wire (or inject_tu) 00010 // { 00011 // ...put a SIP message here that has a CRLF after each line... 00012 // } 00013 // 00014 // expect_wire (or expect_tu) 00015 // { 00016 // status=100 (or method=REGISTER) 00017 // timeout=32 00018 // } 00019 // 00020 // delay 00021 // { 00022 // timeout=48 00023 // } 00024 // 00025 // The inject_* clauses inject the SIP message described at the "wire" 00026 // or the "tu" level. The expect_* clauses indicate that the test 00027 // specification expects to read a certain response (distinguished only 00028 // by its response code) or request (distinguished only by its method 00029 // name). The expect_* clauses don't block but will queue the 00030 // expectation for the duration of the timeout specified. When you 00031 // really want to sit and wait for a message, insert a delay clause. 00032 // This is used as a "barrier" at which you want all the above timeouts 00033 // to happen. You'll want one at the end of your test, for example. 00034 00035 #ifndef __MINGW32__ 00036 00037 #include <sys/time.h> 00038 #include <sys/types.h> 00039 #include <sys/socket.h> 00040 #include <sys/stat.h> 00041 #include <netinet/in.h> 00042 #include <arpa/inet.h> 00043 #include <errno.h> 00044 #include <fcntl.h> 00045 #include <signal.h> 00046 #include <stdlib.h> 00047 #include <string.h> 00048 #include <time.h> 00049 #include <unistd.h> 00050 00051 #include <list> 00052 #include <iostream> 00053 #include <fstream> 00054 #include <string> 00055 00056 #include "rutil/Data.hxx" 00057 #include "rutil/DataStream.hxx" 00058 #include "rutil/Logger.hxx" 00059 #include "rutil/Socket.hxx" 00060 00061 #include "resip/stack/test/TestSupport.hxx" 00062 #include "resip/stack/MethodTypes.hxx" 00063 #include "resip/stack/SipStack.hxx" 00064 #include "resip/stack/SipMessage.hxx" 00065 #include "resip/stack/Symbols.hxx" 00066 #include "resip/stack/Transport.hxx" 00067 #include "rutil/ParseBuffer.hxx" 00068 00069 using namespace resip; 00070 using namespace std; 00071 00072 #define RESIPROCATE_SUBSYSTEM Subsystem::TEST 00073 #define PORT 5060 00074 00075 00076 // -------------------------------------------------- 00077 00078 namespace resip 00079 { 00080 class TestFSM // this class is a friend of the SipStack and can directly access private stuff 00081 { 00082 public: 00083 static void addMessage(SipStack* stack,SipMessage* message) 00084 { 00085 stack->mTransactionController->mStateMacFifo.add(message); 00086 } 00087 }; 00088 } 00089 00090 typedef struct { 00091 struct timeval mExpiry; 00092 bool mIsRequest; 00093 bool mIsTransport; 00094 int mResponseCode; 00095 MethodTypes mMethod; 00096 } WaitNode; 00097 00098 // -------------------------------------------------- 00099 00100 char* ProgramName = 0; 00101 char* TestSpecBuf = 0; 00102 ParseBuffer* TestSpecParseBuf = 0; 00103 list<WaitNode*> WaitQueue; 00104 SipStack* client = 0; 00105 FdSet clientFdSet; 00106 struct sockaddr_in clientSa; 00107 int clientFd; 00108 Fifo<SipMessage> fakeTxFifo; 00109 int errorCount = 0; 00110 00111 // -------------------------------------------------- 00112 00113 // This is pure evil. We interpose our own version of sendto 00114 // so that this gets called by the UDP transport instead of the libc 00115 // version. 00116 int 00117 sendto(int s, const void *msg, size_t len, int flags, 00118 const struct sockaddr *to, int tolen) 00119 { 00120 fakeTxFifo.add(TestSupport::makeMessage(Data((const char *)msg, (int)len), true)); 00121 return len; 00122 } 00123 00124 // -------------------------------------------------- 00125 00126 00127 void 00128 exitusage() 00129 { 00130 cerr << "Usage: " << ProgramName << " "; 00131 cerr << "<testfileofsipmessagesandstuff>" << endl; 00132 exit(1); 00133 } 00134 00135 extern "C" { void processTimeouts(int arg); } 00136 00137 void 00138 processTimeouts(int arg) 00139 { 00140 client->buildFdSet(clientFdSet); 00141 client->process(clientFdSet); 00142 00143 if (WaitQueue.empty()) 00144 { 00145 return; 00146 } 00147 SipMessage* message = 0; 00148 00149 00150 #if defined(UGLY) || 1 00151 // This should: 00152 // 1. Take all messages from the "wire" and "tu" fifos 00153 // 2. For each message, look through the WaitQueue and see 00154 // if the new message matches something we were waiting for. 00155 // If yes, through away the queue entry, else raise a warning. 00156 // 3. When all messages from the "wire" and "tu" have been 00157 // examined, see if anything in the queue has expired. 00158 // If yes, warn, else just continue. 00159 00160 // First go through the "wire" data 00161 while (fakeTxFifo.messageAvailable()) 00162 { 00163 message = fakeTxFifo.getNext(); 00164 for (list<WaitNode*>::iterator i = WaitQueue.begin(); 00165 i != WaitQueue.end(); 00166 /* don't increment */) 00167 { 00168 if ((*i)->mIsRequest && message->isRequest()) 00169 { 00170 if ((*i)->mMethod == message->header(h_RequestLine).getMethod()) 00171 { 00172 // We matched something we expected. 00173 delete message; 00174 message = 0; 00175 delete *i; 00176 WaitQueue.erase(i++); 00177 break; 00178 } 00179 else 00180 { 00181 ++i; 00182 } 00183 } 00184 else if (!(*i)->mIsRequest && message->isResponse()) 00185 { 00186 if ((*i)->mResponseCode == 00187 message->header(h_StatusLine).responseCode()) 00188 { 00189 // We matched something we expected. 00190 delete message; 00191 message = 0; 00192 delete *i; 00193 WaitQueue.erase(i++); 00194 break; 00195 } 00196 else 00197 { 00198 ++i; 00199 } 00200 } 00201 else 00202 { 00203 ++i; 00204 } 00205 } 00206 if (message) 00207 { 00208 DebugLog( << "Warning: unexpected message seen at the transport: " 00209 << message); 00210 } 00211 else 00212 { 00213 DebugLog( << "Success: expected message seen at the transport"); 00214 } 00215 delete message; 00216 } 00217 00218 // Now go through the data at the TU. 00219 while (0 != (message = client->receive())) 00220 { 00221 for (list<WaitNode*>::iterator i = WaitQueue.begin(); 00222 i != WaitQueue.end(); 00223 /* don't increment */) 00224 { 00225 if ((*i)->mIsRequest && message->isRequest()) 00226 { 00227 if ((*i)->mMethod == 00228 message->header(h_RequestLine).getMethod()) 00229 { 00230 // We matched something we expected. 00231 delete message; 00232 message = 0; 00233 delete *i; 00234 WaitQueue.erase(i++); 00235 break; 00236 } 00237 else 00238 { 00239 ++i; 00240 } 00241 } 00242 else if (!(*i)->mIsRequest && message->isResponse()) 00243 { 00244 if ((*i)->mResponseCode == 00245 message->header(h_StatusLine).responseCode()) 00246 { 00247 // We matched something we expected. 00248 delete message; 00249 message = 0; 00250 delete *i; 00251 WaitQueue.erase(i++); 00252 break; 00253 } 00254 else 00255 { 00256 ++i; 00257 } 00258 } 00259 else 00260 { 00261 ++i; 00262 } 00263 } 00264 if (message) 00265 { 00266 DebugLog( << "Warning: unexpected message seen at the TU: " 00267 << *message); 00268 delete message; 00269 } 00270 else 00271 { 00272 DebugLog( << "Success: expected message seen at TU"); 00273 } 00274 } 00275 00276 // Print the list of expected events that have failed to happen withing 00277 // the specified timeout. 00278 for (list<WaitNode*>::iterator i = WaitQueue.begin(); 00279 i != WaitQueue.end(); 00280 /* don't increment */) 00281 { 00282 struct timeval tv; 00283 gettimeofday(&tv, NULL); 00284 if ((*i)->mExpiry.tv_sec < tv.tv_sec || 00285 ((*i)->mExpiry.tv_sec == tv.tv_sec && 00286 (*i)->mExpiry.tv_usec < tv.tv_usec)) 00287 { 00288 if ((*i)->mIsRequest) 00289 { 00290 DebugLog(<< "Error: timeout waiting for " 00291 << getMethodName((*i)->mMethod) << " method"); 00292 ++errorCount; 00293 } 00294 else 00295 { 00296 DebugLog(<< "Error: timeout waiting for " 00297 << (*i)->mResponseCode << " status code"); 00298 ++errorCount; 00299 } 00300 delete *i; 00301 WaitQueue.erase(i++); 00302 } 00303 else 00304 { 00305 /* 00306 cerr << "Still waiting for: "; 00307 if ((*i)->mIsRequest) 00308 { 00309 cerr << MethodNames[(*i)->mMethod] << " method" << endl; 00310 } 00311 else 00312 { 00313 cerr << (*i)->mResponseCode << " status code" << endl; 00314 } 00315 */ 00316 ++i; 00317 } 00318 } 00319 #endif 00320 00321 signal(SIGALRM, processTimeouts); 00322 } 00323 00324 void 00325 processInject() 00326 { 00327 const char* start = TestSpecParseBuf->position(); 00328 const char* now; 00329 bool isWireInject = false; 00330 00331 if (!strncasecmp(start, "inject_wire", strlen("inject_wire"))) 00332 { 00333 isWireInject = true; 00334 } 00335 else if (!strncasecmp(start, "inject_tu", strlen("inject_tu"))) 00336 { 00337 isWireInject = false; 00338 } 00339 else 00340 { 00341 DebugLog(<< "Warning: error parsing test specification."); 00342 TestSpecParseBuf->skipToChar('}'); 00343 TestSpecParseBuf->skipChar(); 00344 return; 00345 } 00346 00347 TestSpecParseBuf->skipToChar('{'); 00348 TestSpecParseBuf->skipChar(); 00349 TestSpecParseBuf->skipWhitespace(); 00350 00351 start = TestSpecParseBuf->position(); 00352 now = TestSpecParseBuf->skipToChar('}'); 00353 *const_cast<char*>(now) = 0; 00354 DebugLog(<< "Injecting (isWireInject=" << isWireInject << "): " << start); 00355 TestSpecParseBuf->skipChar(); 00356 if (isWireInject) 00357 { 00358 // sendToWire() is a helper function for TestTransport stuff. 00359 // sendToWire(start); 00360 SipMessage* message = TestSupport::makeMessage(start, true); 00361 assert(message); 00362 00363 TestFSM::addMessage(client,message); // does a client->mStateMacFifo.add(message); 00364 00365 } 00366 else 00367 { 00368 SipMessage* message = TestSupport::makeMessage(start, false); 00369 assert(message); 00370 client->send(*message); 00371 } 00372 } 00373 00374 void 00375 processExpect() 00376 { 00377 const char* start = TestSpecParseBuf->position(); 00378 const char* now; 00379 unsigned int expireTime = 1; 00380 WaitNode* thisWait = new WaitNode; 00381 assert(thisWait); 00382 thisWait->mResponseCode = 0; 00383 00384 if (!strncasecmp(start, "expect_wire", strlen("expect_wire"))) 00385 { 00386 thisWait->mIsTransport = true; 00387 } 00388 else if (!strncasecmp(start, "expect_tu", strlen("expect_tu"))) 00389 { 00390 thisWait->mIsTransport = false; 00391 } 00392 else 00393 { 00394 DebugLog(<< "Warning: error parsing test specification"); 00395 TestSpecParseBuf->skipToChar('}'); 00396 TestSpecParseBuf->skipChar(); 00397 delete thisWait; 00398 return; 00399 } 00400 00401 TestSpecParseBuf->skipToChar('{'); 00402 TestSpecParseBuf->skipChar(); 00403 TestSpecParseBuf->skipWhitespace(); 00404 start = TestSpecParseBuf->position(); 00405 00406 // We will want to get two of these in an expect_ clause. 00407 for (int i = 0; i < 2; i++) 00408 { 00409 TestSpecParseBuf->skipToChar('='); 00410 TestSpecParseBuf->skipChar(); 00411 TestSpecParseBuf->skipWhitespace(); 00412 if (!strncasecmp(start, "method", strlen("method"))) 00413 { 00414 start = TestSpecParseBuf->position(); 00415 now = TestSpecParseBuf->skipToOneOf(ParseBuffer::Whitespace); 00416 thisWait->mIsRequest = true; 00417 thisWait->mMethod = getMethodType(start, now-start); 00418 } 00419 else if (!strncasecmp(start, "status", strlen("status"))) 00420 { 00421 TestSpecParseBuf->skipToOneOf("0123456789"); 00422 thisWait->mIsRequest = false; 00423 thisWait->mResponseCode = TestSpecParseBuf->integer(); 00424 } 00425 else if (!strncasecmp(start, "timeout", strlen("timeout"))) 00426 { 00427 TestSpecParseBuf->skipToOneOf("0123456789"); 00428 expireTime = TestSpecParseBuf->integer(); 00429 } 00430 else 00431 { 00432 DebugLog(<< "Warning: error parsing test specification"); 00433 TestSpecParseBuf->skipToChar('}'); 00434 TestSpecParseBuf->skipChar(); 00435 delete thisWait; 00436 return; 00437 } 00438 TestSpecParseBuf->skipWhitespace(); 00439 start = TestSpecParseBuf->position(); 00440 } 00441 00442 assert(thisWait); 00443 00444 gettimeofday(&thisWait->mExpiry, NULL); 00445 thisWait->mExpiry.tv_sec += expireTime / 1000; 00446 thisWait->mExpiry.tv_usec += (expireTime % 1000) * 1000; 00447 WaitQueue.push_front(thisWait); 00448 00449 TestSpecParseBuf->skipToChar('}'); 00450 TestSpecParseBuf->skipChar(); 00451 00452 /* 00453 cerr << "-> Expecting " << endl; 00454 cerr << " mIsTransport = " << (thisWait->mIsTransport == true) << endl; 00455 cerr << " mIsRequest = " << (thisWait->mIsRequest == true) << endl; 00456 cerr << " mResponseCode = " << (thisWait->mResponseCode) << endl; 00457 cerr << " mExpiry = " << (thisWait->mExpiry.tv_sec) << endl; 00458 */ 00459 } 00460 00461 void 00462 processDelays() 00463 { 00464 TestSpecParseBuf->skipToChar('{'); 00465 TestSpecParseBuf->skipChar(); 00466 TestSpecParseBuf->skipWhitespace(); 00467 00468 TestSpecParseBuf->skipToOneOf("0123456789"); 00469 int sleepLength = TestSpecParseBuf->integer(); 00470 00471 DebugLog( << "Pausing for " << sleepLength << " ms"); 00472 00473 // We sleep this way to avoid conflict with SIGALRM from alarm(). 00474 struct timespec ts, remainder; 00475 ts.tv_sec = sleepLength / 1000; 00476 ts.tv_nsec = (sleepLength % 1000) * 1000000; 00477 while (nanosleep(&ts, &remainder) < 0) 00478 { 00479 ts = remainder; 00480 } 00481 00482 TestSpecParseBuf->skipToChar('}'); 00483 TestSpecParseBuf->skipChar(); 00484 } 00485 00486 bool 00487 processClause() 00488 { 00489 TestSpecParseBuf->skipWhitespace(); 00490 00491 // Look for 'i'/'e'/'d' for inject... or expect... or delay respectively. 00492 const char* now = TestSpecParseBuf->skipToOneOf("ied#"); 00493 switch (*now) 00494 { 00495 case 'i': 00496 processInject(); 00497 break; 00498 case 'e': 00499 processExpect(); 00500 break; 00501 case 'd': 00502 processDelays(); 00503 break; 00504 case '#': 00505 TestSpecParseBuf->skipToChar('\n'); 00506 TestSpecParseBuf->skipChar(); 00507 break; 00508 default: 00509 DebugLog(<< "Warning: error parsing test specification"); 00510 TestSpecParseBuf->skipToChar('}'); 00511 TestSpecParseBuf->skipChar(); 00512 } 00513 00514 TestSpecParseBuf->skipWhitespace(); 00515 return !TestSpecParseBuf->eof(); 00516 } 00517 00518 int 00519 main(int argc, char *argv[]) 00520 { 00521 ProgramName = argv[0]; 00522 00523 if (NULL == argv[1]) { 00524 exitusage(); 00525 } 00526 00527 struct stat buf; 00528 if (stat(argv[1], &buf) < 0) 00529 { 00530 cerr << "Error: " << strerror(errno) << endl; 00531 exitusage(); 00532 } 00533 00534 ifstream testSpec; 00535 testSpec.open(argv[1], ifstream::in); 00536 if (!testSpec.is_open()) 00537 { 00538 cerr << "Error: could not open "<< argv[1] << endl; 00539 exitusage(); 00540 } 00541 00542 TestSpecBuf = new char[buf.st_size+1]; 00543 assert(TestSpecBuf); 00544 testSpec.read(TestSpecBuf, buf.st_size); 00545 TestSpecParseBuf = new ParseBuffer(TestSpecBuf, buf.st_size); 00546 assert(TestSpecParseBuf); 00547 00548 int clientFd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 00549 clientSa.sin_family = PF_INET; 00550 clientSa.sin_addr.s_addr = inet_addr("127.0.0.1"); 00551 clientSa.sin_port = htons(PORT); 00552 int clientFdFlags = fcntl(clientFd, F_GETFL, 0); 00553 fcntl(clientFd, F_SETFL, clientFdFlags | O_NONBLOCK); 00554 00555 client = new SipStack(); 00556 assert(client); 00557 client->addTransport(UDP, PORT); 00558 00559 signal(SIGALRM, processTimeouts); 00560 00561 // Cause a signal to be generated with setitimer for its resolution 00562 struct itimerval timer; 00563 timer.it_value.tv_sec = 0; 00564 timer.it_value.tv_usec = 100000; // 100 ms resolution 00565 timer.it_interval.tv_sec = 0; 00566 timer.it_interval.tv_usec = 100000; // 100 ms resolution 00567 setitimer(ITIMER_REAL, &timer, NULL); 00568 00569 while (processClause()) 00570 { 00571 } 00572 00573 // Catch any remaining events. 00574 processTimeouts(0); 00575 if (!WaitQueue.empty()) 00576 { 00577 DebugLog( << "Warning: ending with expect clauses outstanding"); 00578 ++errorCount; 00579 } 00580 00581 if (errorCount > 0) 00582 { 00583 cerr << "FAIL" << endl; 00584 } 00585 else 00586 { 00587 cerr << "PASS" << endl; 00588 } 00589 00590 return errorCount; 00591 } 00592 #else 00593 #include <iostream> 00594 int 00595 main(int argc, char *argv[]) 00596 { 00597 std::cout << argv[0] << ": Sorry. This test driver hasn't been ported " 00598 "to Windows yet." << std::endl; 00599 return -1; 00600 } 00601 #endif 00602 /* ==================================================================== 00603 * The Vovida Software License, Version 1.0 00604 * 00605 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. 00606 * 00607 * Redistribution and use in source and binary forms, with or without 00608 * modification, are permitted provided that the following conditions 00609 * are met: 00610 * 00611 * 1. Redistributions of source code must retain the above copyright 00612 * notice, this list of conditions and the following disclaimer. 00613 * 00614 * 2. Redistributions in binary form must reproduce the above copyright 00615 * notice, this list of conditions and the following disclaimer in 00616 * the documentation and/or other materials provided with the 00617 * distribution. 00618 * 00619 * 3. The names "VOCAL", "Vovida Open Communication Application Library", 00620 * and "Vovida Open Communication Application Library (VOCAL)" must 00621 * not be used to endorse or promote products derived from this 00622 * software without prior written permission. For written 00623 * permission, please contact vocal@vovida.org. 00624 * 00625 * 4. Products derived from this software may not be called "VOCAL", nor 00626 * may "VOCAL" appear in their name, without prior written 00627 * permission of Vovida Networks, Inc. 00628 * 00629 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 00630 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00631 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND 00632 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA 00633 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES 00634 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, 00635 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00636 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00637 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 00638 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00639 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 00640 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 00641 * DAMAGE. 00642 * 00643 * ==================================================================== 00644 * 00645 * This software consists of voluntary contributions made by Vovida 00646 * Networks, Inc. and many individuals on behalf of Vovida Networks, 00647 * Inc. For more information on Vovida Networks, Inc., please see 00648 * <http://www.vovida.org/>. 00649 * 00650 */
1.7.5.1