3
// The first argument to this program needs to be a file that has a test in it.
5
// Clauses in this file can be: inject_wire, expect_wire, expect_tu,
6
// inject_tu, and delay. A keyword needs to be by itself on a line. They
7
// need to be in this form
9
// inject_wire (or inject_tu)
11
// ...put a SIP message here that has a CRLF after each line...
14
// expect_wire (or expect_tu)
16
// status=100 (or method=REGISTER)
25
// The inject_* clauses inject the SIP message described at the "wire"
26
// or the "tu" level. The expect_* clauses indicate that the test
27
// specification expects to read a certain response (distinguished only
28
// by its response code) or request (distinguished only by its method
29
// name). The expect_* clauses don't block but will queue the
30
// expectation for the duration of the timeout specified. When you
31
// really want to sit and wait for a message, insert a delay clause.
32
// This is used as a "barrier" at which you want all the above timeouts
33
// to happen. You'll want one at the end of your test, for example.
38
#include <sys/types.h>
39
#include <sys/socket.h>
41
#include <netinet/in.h>
42
#include <arpa/inet.h>
56
#include "rutil/Data.hxx"
57
#include "rutil/DataStream.hxx"
58
#include "rutil/Logger.hxx"
59
#include "rutil/Socket.hxx"
61
#include "resip/stack/test/TestSupport.hxx"
62
#include "resip/stack/MethodTypes.hxx"
63
#include "resip/stack/SipStack.hxx"
64
#include "resip/stack/SipMessage.hxx"
65
#include "resip/stack/Symbols.hxx"
66
#include "resip/stack/Transport.hxx"
67
#include "rutil/ParseBuffer.hxx"
69
using namespace resip;
72
#define RESIPROCATE_SUBSYSTEM Subsystem::TEST
76
// --------------------------------------------------
80
class TestFSM // this class is a friend of the SipStack and can directly access private stuff
83
static void addMessage(SipStack* stack,SipMessage* message)
85
stack->mTransactionController->mStateMacFifo.add(message);
91
struct timeval mExpiry;
98
// --------------------------------------------------
100
char* ProgramName = 0;
101
char* TestSpecBuf = 0;
102
ParseBuffer* TestSpecParseBuf = 0;
103
list<WaitNode*> WaitQueue;
104
SipStack* client = 0;
106
struct sockaddr_in clientSa;
108
Fifo<SipMessage> fakeTxFifo;
111
// --------------------------------------------------
113
// This is pure evil. We interpose our own version of sendto
114
// so that this gets called by the UDP transport instead of the libc
117
sendto(int s, const void *msg, size_t len, int flags,
118
const struct sockaddr *to, int tolen)
120
fakeTxFifo.add(TestSupport::makeMessage(Data((const char *)msg, (int)len), true));
124
// --------------------------------------------------
130
cerr << "Usage: " << ProgramName << " ";
131
cerr << "<testfileofsipmessagesandstuff>" << endl;
135
extern "C" { void processTimeouts(int arg); }
138
processTimeouts(int arg)
140
client->buildFdSet(clientFdSet);
141
client->process(clientFdSet);
143
if (WaitQueue.empty())
147
SipMessage* message = 0;
150
#if defined(UGLY) || 1
152
// 1. Take all messages from the "wire" and "tu" fifos
153
// 2. For each message, look through the WaitQueue and see
154
// if the new message matches something we were waiting for.
155
// If yes, through away the queue entry, else raise a warning.
156
// 3. When all messages from the "wire" and "tu" have been
157
// examined, see if anything in the queue has expired.
158
// If yes, warn, else just continue.
160
// First go through the "wire" data
161
while (fakeTxFifo.messageAvailable())
163
message = fakeTxFifo.getNext();
164
for (list<WaitNode*>::iterator i = WaitQueue.begin();
165
i != WaitQueue.end();
166
/* don't increment */)
168
if ((*i)->mIsRequest && message->isRequest())
170
if ((*i)->mMethod == message->header(h_RequestLine).getMethod())
172
// We matched something we expected.
176
WaitQueue.erase(i++);
184
else if (!(*i)->mIsRequest && message->isResponse())
186
if ((*i)->mResponseCode ==
187
message->header(h_StatusLine).responseCode())
189
// We matched something we expected.
193
WaitQueue.erase(i++);
208
DebugLog( << "Warning: unexpected message seen at the transport: "
213
DebugLog( << "Success: expected message seen at the transport");
218
// Now go through the data at the TU.
219
while (0 != (message = client->receive()))
221
for (list<WaitNode*>::iterator i = WaitQueue.begin();
222
i != WaitQueue.end();
223
/* don't increment */)
225
if ((*i)->mIsRequest && message->isRequest())
228
message->header(h_RequestLine).getMethod())
230
// We matched something we expected.
234
WaitQueue.erase(i++);
242
else if (!(*i)->mIsRequest && message->isResponse())
244
if ((*i)->mResponseCode ==
245
message->header(h_StatusLine).responseCode())
247
// We matched something we expected.
251
WaitQueue.erase(i++);
266
DebugLog( << "Warning: unexpected message seen at the TU: "
272
DebugLog( << "Success: expected message seen at TU");
276
// Print the list of expected events that have failed to happen withing
277
// the specified timeout.
278
for (list<WaitNode*>::iterator i = WaitQueue.begin();
279
i != WaitQueue.end();
280
/* don't increment */)
283
gettimeofday(&tv, NULL);
284
if ((*i)->mExpiry.tv_sec < tv.tv_sec ||
285
((*i)->mExpiry.tv_sec == tv.tv_sec &&
286
(*i)->mExpiry.tv_usec < tv.tv_usec))
288
if ((*i)->mIsRequest)
290
DebugLog(<< "Error: timeout waiting for "
291
<< getMethodName((*i)->mMethod) << " method");
296
DebugLog(<< "Error: timeout waiting for "
297
<< (*i)->mResponseCode << " status code");
301
WaitQueue.erase(i++);
306
cerr << "Still waiting for: ";
307
if ((*i)->mIsRequest)
309
cerr << MethodNames[(*i)->mMethod] << " method" << endl;
313
cerr << (*i)->mResponseCode << " status code" << endl;
321
signal(SIGALRM, processTimeouts);
327
const char* start = TestSpecParseBuf->position();
329
bool isWireInject = false;
331
if (!strncasecmp(start, "inject_wire", strlen("inject_wire")))
335
else if (!strncasecmp(start, "inject_tu", strlen("inject_tu")))
337
isWireInject = false;
341
DebugLog(<< "Warning: error parsing test specification.");
342
TestSpecParseBuf->skipToChar('}');
343
TestSpecParseBuf->skipChar();
347
TestSpecParseBuf->skipToChar('{');
348
TestSpecParseBuf->skipChar();
349
TestSpecParseBuf->skipWhitespace();
351
start = TestSpecParseBuf->position();
352
now = TestSpecParseBuf->skipToChar('}');
353
*const_cast<char*>(now) = 0;
354
DebugLog(<< "Injecting (isWireInject=" << isWireInject << "): " << start);
355
TestSpecParseBuf->skipChar();
358
// sendToWire() is a helper function for TestTransport stuff.
359
// sendToWire(start);
360
SipMessage* message = TestSupport::makeMessage(start, true);
363
TestFSM::addMessage(client,message); // does a client->mStateMacFifo.add(message);
368
SipMessage* message = TestSupport::makeMessage(start, false);
370
client->send(*message);
377
const char* start = TestSpecParseBuf->position();
379
unsigned int expireTime = 1;
380
WaitNode* thisWait = new WaitNode;
382
thisWait->mResponseCode = 0;
384
if (!strncasecmp(start, "expect_wire", strlen("expect_wire")))
386
thisWait->mIsTransport = true;
388
else if (!strncasecmp(start, "expect_tu", strlen("expect_tu")))
390
thisWait->mIsTransport = false;
394
DebugLog(<< "Warning: error parsing test specification");
395
TestSpecParseBuf->skipToChar('}');
396
TestSpecParseBuf->skipChar();
401
TestSpecParseBuf->skipToChar('{');
402
TestSpecParseBuf->skipChar();
403
TestSpecParseBuf->skipWhitespace();
404
start = TestSpecParseBuf->position();
406
// We will want to get two of these in an expect_ clause.
407
for (int i = 0; i < 2; i++)
409
TestSpecParseBuf->skipToChar('=');
410
TestSpecParseBuf->skipChar();
411
TestSpecParseBuf->skipWhitespace();
412
if (!strncasecmp(start, "method", strlen("method")))
414
start = TestSpecParseBuf->position();
415
now = TestSpecParseBuf->skipToOneOf(ParseBuffer::Whitespace);
416
thisWait->mIsRequest = true;
417
thisWait->mMethod = getMethodType(start, now-start);
419
else if (!strncasecmp(start, "status", strlen("status")))
421
TestSpecParseBuf->skipToOneOf("0123456789");
422
thisWait->mIsRequest = false;
423
thisWait->mResponseCode = TestSpecParseBuf->integer();
425
else if (!strncasecmp(start, "timeout", strlen("timeout")))
427
TestSpecParseBuf->skipToOneOf("0123456789");
428
expireTime = TestSpecParseBuf->integer();
432
DebugLog(<< "Warning: error parsing test specification");
433
TestSpecParseBuf->skipToChar('}');
434
TestSpecParseBuf->skipChar();
438
TestSpecParseBuf->skipWhitespace();
439
start = TestSpecParseBuf->position();
444
gettimeofday(&thisWait->mExpiry, NULL);
445
thisWait->mExpiry.tv_sec += expireTime / 1000;
446
thisWait->mExpiry.tv_usec += (expireTime % 1000) * 1000;
447
WaitQueue.push_front(thisWait);
449
TestSpecParseBuf->skipToChar('}');
450
TestSpecParseBuf->skipChar();
453
cerr << "-> Expecting " << endl;
454
cerr << " mIsTransport = " << (thisWait->mIsTransport == true) << endl;
455
cerr << " mIsRequest = " << (thisWait->mIsRequest == true) << endl;
456
cerr << " mResponseCode = " << (thisWait->mResponseCode) << endl;
457
cerr << " mExpiry = " << (thisWait->mExpiry.tv_sec) << endl;
464
TestSpecParseBuf->skipToChar('{');
465
TestSpecParseBuf->skipChar();
466
TestSpecParseBuf->skipWhitespace();
468
TestSpecParseBuf->skipToOneOf("0123456789");
469
int sleepLength = TestSpecParseBuf->integer();
471
DebugLog( << "Pausing for " << sleepLength << " ms");
473
// We sleep this way to avoid conflict with SIGALRM from alarm().
474
struct timespec ts, remainder;
475
ts.tv_sec = sleepLength / 1000;
476
ts.tv_nsec = (sleepLength % 1000) * 1000000;
477
while (nanosleep(&ts, &remainder) < 0)
482
TestSpecParseBuf->skipToChar('}');
483
TestSpecParseBuf->skipChar();
489
TestSpecParseBuf->skipWhitespace();
491
// Look for 'i'/'e'/'d' for inject... or expect... or delay respectively.
492
const char* now = TestSpecParseBuf->skipToOneOf("ied#");
505
TestSpecParseBuf->skipToChar('\n');
506
TestSpecParseBuf->skipChar();
509
DebugLog(<< "Warning: error parsing test specification");
510
TestSpecParseBuf->skipToChar('}');
511
TestSpecParseBuf->skipChar();
514
TestSpecParseBuf->skipWhitespace();
515
return !TestSpecParseBuf->eof();
519
main(int argc, char *argv[])
521
ProgramName = argv[0];
523
if (NULL == argv[1]) {
528
if (stat(argv[1], &buf) < 0)
530
cerr << "Error: " << strerror(errno) << endl;
535
testSpec.open(argv[1], ifstream::in);
536
if (!testSpec.is_open())
538
cerr << "Error: could not open "<< argv[1] << endl;
542
TestSpecBuf = new char[buf.st_size+1];
544
testSpec.read(TestSpecBuf, buf.st_size);
545
TestSpecParseBuf = new ParseBuffer(TestSpecBuf, buf.st_size);
546
assert(TestSpecParseBuf);
548
int clientFd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
549
clientSa.sin_family = PF_INET;
550
clientSa.sin_addr.s_addr = inet_addr("127.0.0.1");
551
clientSa.sin_port = htons(PORT);
552
int clientFdFlags = fcntl(clientFd, F_GETFL, 0);
553
fcntl(clientFd, F_SETFL, clientFdFlags | O_NONBLOCK);
555
client = new SipStack();
557
client->addTransport(UDP, PORT);
559
signal(SIGALRM, processTimeouts);
561
// Cause a signal to be generated with setitimer for its resolution
562
struct itimerval timer;
563
timer.it_value.tv_sec = 0;
564
timer.it_value.tv_usec = 100000; // 100 ms resolution
565
timer.it_interval.tv_sec = 0;
566
timer.it_interval.tv_usec = 100000; // 100 ms resolution
567
setitimer(ITIMER_REAL, &timer, NULL);
569
while (processClause())
573
// Catch any remaining events.
575
if (!WaitQueue.empty())
577
DebugLog( << "Warning: ending with expect clauses outstanding");
583
cerr << "FAIL" << endl;
587
cerr << "PASS" << endl;
595
main(int argc, char *argv[])
597
std::cout << argv[0] << ": Sorry. This test driver hasn't been ported "
598
"to Windows yet." << std::endl;
602
/* ====================================================================
603
* The Vovida Software License, Version 1.0
605
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
607
* Redistribution and use in source and binary forms, with or without
608
* modification, are permitted provided that the following conditions
611
* 1. Redistributions of source code must retain the above copyright
612
* notice, this list of conditions and the following disclaimer.
614
* 2. Redistributions in binary form must reproduce the above copyright
615
* notice, this list of conditions and the following disclaimer in
616
* the documentation and/or other materials provided with the
619
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
620
* and "Vovida Open Communication Application Library (VOCAL)" must
621
* not be used to endorse or promote products derived from this
622
* software without prior written permission. For written
623
* permission, please contact vocal@vovida.org.
625
* 4. Products derived from this software may not be called "VOCAL", nor
626
* may "VOCAL" appear in their name, without prior written
627
* permission of Vovida Networks, Inc.
629
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
630
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
631
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
632
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
633
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
634
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
635
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
636
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
637
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
638
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
639
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
640
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
643
* ====================================================================
645
* This software consists of voluntary contributions made by Vovida
646
* Networks, Inc. and many individuals on behalf of Vovida Networks,
647
* Inc. For more information on Vovida Networks, Inc., please see
648
* <http://www.vovida.org/>.