|
reSIProcate/stack
9694
|
#include <sys/time.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/stat.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#include <fcntl.h>#include <signal.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <unistd.h>#include <list>#include <iostream>#include <fstream>#include <string>#include "rutil/Data.hxx"#include "rutil/DataStream.hxx"#include "rutil/Logger.hxx"#include "rutil/Socket.hxx"#include "resip/stack/test/TestSupport.hxx"#include "resip/stack/MethodTypes.hxx"#include "resip/stack/SipStack.hxx"#include "resip/stack/SipMessage.hxx"#include "resip/stack/Symbols.hxx"#include "resip/stack/Transport.hxx"#include "rutil/ParseBuffer.hxx"
Go to the source code of this file.
Classes | |
| class | resip::TestFSM |
| struct | WaitNode |
Namespaces | |
| namespace | resip |
SERNonceHelper implements the makeNonce function in the same way as SIP Express Router (SER) - http://www.iptel.org/ser. | |
Defines | |
| #define | RESIPROCATE_SUBSYSTEM Subsystem::TEST |
| #define | PORT 5060 |
Functions | |
| int | sendto (int s, const void *msg, size_t len, int flags, const struct sockaddr *to, int tolen) |
| void | exitusage () |
| void | processTimeouts (int arg) |
| void | processInject () |
| void | processExpect () |
| void | processDelays () |
| bool | processClause () |
| int | main (int argc, char *argv[]) |
Variables | |
| char * | ProgramName = 0 |
| char * | TestSpecBuf = 0 |
| ParseBuffer * | TestSpecParseBuf = 0 |
| list< WaitNode * > | WaitQueue |
| SipStack * | client = 0 |
| FdSet | clientFdSet |
| struct sockaddr_in | clientSa |
| int | clientFd |
| Fifo< SipMessage > | fakeTxFifo |
| int | errorCount = 0 |
| #define PORT 5060 |
Definition at line 73 of file testTransactionFSM.cxx.
Referenced by main().
| #define RESIPROCATE_SUBSYSTEM Subsystem::TEST |
Definition at line 72 of file testTransactionFSM.cxx.
| void exitusage | ( | ) |
Definition at line 128 of file testTransactionFSM.cxx.
References ProgramName.
Referenced by main().
{
cerr << "Usage: " << ProgramName << " ";
cerr << "<testfileofsipmessagesandstuff>" << endl;
exit(1);
}
| int main | ( | int | argc, |
| char * | argv[] | ||
| ) |
Definition at line 519 of file testTransactionFSM.cxx.
References resip::SipStack::addTransport(), client, clientFd, clientSa, DebugLog, errno, errorCount, exitusage(), PORT, processClause(), processTimeouts(), ProgramName, strerror(), TestSpecBuf, TestSpecParseBuf, resip::UDP, and WaitQueue.
{
ProgramName = argv[0];
if (NULL == argv[1]) {
exitusage();
}
struct stat buf;
if (stat(argv[1], &buf) < 0)
{
cerr << "Error: " << strerror(errno) << endl;
exitusage();
}
ifstream testSpec;
testSpec.open(argv[1], ifstream::in);
if (!testSpec.is_open())
{
cerr << "Error: could not open "<< argv[1] << endl;
exitusage();
}
TestSpecBuf = new char[buf.st_size+1];
assert(TestSpecBuf);
testSpec.read(TestSpecBuf, buf.st_size);
TestSpecParseBuf = new ParseBuffer(TestSpecBuf, buf.st_size);
assert(TestSpecParseBuf);
int clientFd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
clientSa.sin_family = PF_INET;
clientSa.sin_addr.s_addr = inet_addr("127.0.0.1");
clientSa.sin_port = htons(PORT);
int clientFdFlags = fcntl(clientFd, F_GETFL, 0);
fcntl(clientFd, F_SETFL, clientFdFlags | O_NONBLOCK);
client = new SipStack();
assert(client);
client->addTransport(UDP, PORT);
signal(SIGALRM, processTimeouts);
// Cause a signal to be generated with setitimer for its resolution
struct itimerval timer;
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 100000; // 100 ms resolution
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 100000; // 100 ms resolution
setitimer(ITIMER_REAL, &timer, NULL);
while (processClause())
{
}
// Catch any remaining events.
processTimeouts(0);
if (!WaitQueue.empty())
{
DebugLog( << "Warning: ending with expect clauses outstanding");
++errorCount;
}
if (errorCount > 0)
{
cerr << "FAIL" << endl;
}
else
{
cerr << "PASS" << endl;
}
return errorCount;
}

| bool processClause | ( | ) |
Definition at line 487 of file testTransactionFSM.cxx.
References DebugLog, resip::ParseBuffer::eof(), processDelays(), processExpect(), processInject(), resip::ParseBuffer::skipChar(), resip::ParseBuffer::skipToChar(), resip::ParseBuffer::skipToOneOf(), resip::ParseBuffer::skipWhitespace(), and TestSpecParseBuf.
Referenced by main().
{
TestSpecParseBuf->skipWhitespace();
// Look for 'i'/'e'/'d' for inject... or expect... or delay respectively.
const char* now = TestSpecParseBuf->skipToOneOf("ied#");
switch (*now)
{
case 'i':
processInject();
break;
case 'e':
processExpect();
break;
case 'd':
processDelays();
break;
case '#':
TestSpecParseBuf->skipToChar('\n');
TestSpecParseBuf->skipChar();
break;
default:
DebugLog(<< "Warning: error parsing test specification");
TestSpecParseBuf->skipToChar('}');
TestSpecParseBuf->skipChar();
}
TestSpecParseBuf->skipWhitespace();
return !TestSpecParseBuf->eof();
}

| void processDelays | ( | ) |
Definition at line 462 of file testTransactionFSM.cxx.
References DebugLog, resip::ParseBuffer::integer(), resip::ParseBuffer::skipChar(), resip::ParseBuffer::skipToChar(), resip::ParseBuffer::skipToOneOf(), resip::ParseBuffer::skipWhitespace(), and TestSpecParseBuf.
Referenced by processClause().
{
TestSpecParseBuf->skipToChar('{');
TestSpecParseBuf->skipChar();
TestSpecParseBuf->skipWhitespace();
TestSpecParseBuf->skipToOneOf("0123456789");
int sleepLength = TestSpecParseBuf->integer();
DebugLog( << "Pausing for " << sleepLength << " ms");
// We sleep this way to avoid conflict with SIGALRM from alarm().
struct timespec ts, remainder;
ts.tv_sec = sleepLength / 1000;
ts.tv_nsec = (sleepLength % 1000) * 1000000;
while (nanosleep(&ts, &remainder) < 0)
{
ts = remainder;
}
TestSpecParseBuf->skipToChar('}');
TestSpecParseBuf->skipChar();
}

| void processExpect | ( | ) |
Definition at line 375 of file testTransactionFSM.cxx.
References DebugLog, resip::ParseBuffer::integer(), WaitNode::mExpiry, WaitNode::mIsRequest, WaitNode::mIsTransport, WaitNode::mMethod, WaitNode::mResponseCode, resip::ParseBuffer::position(), resip::ParseBuffer::skipChar(), resip::ParseBuffer::skipToChar(), resip::ParseBuffer::skipToOneOf(), resip::ParseBuffer::skipWhitespace(), strncasecmp(), TestSpecParseBuf, WaitQueue, and resip::ParseBuffer::Whitespace.
Referenced by processClause().
{
const char* start = TestSpecParseBuf->position();
const char* now;
unsigned int expireTime = 1;
WaitNode* thisWait = new WaitNode;
assert(thisWait);
thisWait->mResponseCode = 0;
if (!strncasecmp(start, "expect_wire", strlen("expect_wire")))
{
thisWait->mIsTransport = true;
}
else if (!strncasecmp(start, "expect_tu", strlen("expect_tu")))
{
thisWait->mIsTransport = false;
}
else
{
DebugLog(<< "Warning: error parsing test specification");
TestSpecParseBuf->skipToChar('}');
TestSpecParseBuf->skipChar();
delete thisWait;
return;
}
TestSpecParseBuf->skipToChar('{');
TestSpecParseBuf->skipChar();
TestSpecParseBuf->skipWhitespace();
start = TestSpecParseBuf->position();
// We will want to get two of these in an expect_ clause.
for (int i = 0; i < 2; i++)
{
TestSpecParseBuf->skipToChar('=');
TestSpecParseBuf->skipChar();
TestSpecParseBuf->skipWhitespace();
if (!strncasecmp(start, "method", strlen("method")))
{
start = TestSpecParseBuf->position();
now = TestSpecParseBuf->skipToOneOf(ParseBuffer::Whitespace);
thisWait->mIsRequest = true;
thisWait->mMethod = getMethodType(start, now-start);
}
else if (!strncasecmp(start, "status", strlen("status")))
{
TestSpecParseBuf->skipToOneOf("0123456789");
thisWait->mIsRequest = false;
thisWait->mResponseCode = TestSpecParseBuf->integer();
}
else if (!strncasecmp(start, "timeout", strlen("timeout")))
{
TestSpecParseBuf->skipToOneOf("0123456789");
expireTime = TestSpecParseBuf->integer();
}
else
{
DebugLog(<< "Warning: error parsing test specification");
TestSpecParseBuf->skipToChar('}');
TestSpecParseBuf->skipChar();
delete thisWait;
return;
}
TestSpecParseBuf->skipWhitespace();
start = TestSpecParseBuf->position();
}
assert(thisWait);
gettimeofday(&thisWait->mExpiry, NULL);
thisWait->mExpiry.tv_sec += expireTime / 1000;
thisWait->mExpiry.tv_usec += (expireTime % 1000) * 1000;
WaitQueue.push_front(thisWait);
TestSpecParseBuf->skipToChar('}');
TestSpecParseBuf->skipChar();
/*
cerr << "-> Expecting " << endl;
cerr << " mIsTransport = " << (thisWait->mIsTransport == true) << endl;
cerr << " mIsRequest = " << (thisWait->mIsRequest == true) << endl;
cerr << " mResponseCode = " << (thisWait->mResponseCode) << endl;
cerr << " mExpiry = " << (thisWait->mExpiry.tv_sec) << endl;
*/
}

| void processInject | ( | ) |
Definition at line 325 of file testTransactionFSM.cxx.
References resip::TestFSM::addMessage(), client, DebugLog, resip::TestSupport::makeMessage(), resip::ParseBuffer::position(), resip::SipStack::send(), resip::ParseBuffer::skipChar(), resip::ParseBuffer::skipToChar(), resip::ParseBuffer::skipWhitespace(), strncasecmp(), and TestSpecParseBuf.
Referenced by processClause().
{
const char* start = TestSpecParseBuf->position();
const char* now;
bool isWireInject = false;
if (!strncasecmp(start, "inject_wire", strlen("inject_wire")))
{
isWireInject = true;
}
else if (!strncasecmp(start, "inject_tu", strlen("inject_tu")))
{
isWireInject = false;
}
else
{
DebugLog(<< "Warning: error parsing test specification.");
TestSpecParseBuf->skipToChar('}');
TestSpecParseBuf->skipChar();
return;
}
TestSpecParseBuf->skipToChar('{');
TestSpecParseBuf->skipChar();
TestSpecParseBuf->skipWhitespace();
start = TestSpecParseBuf->position();
now = TestSpecParseBuf->skipToChar('}');
*const_cast<char*>(now) = 0;
DebugLog(<< "Injecting (isWireInject=" << isWireInject << "): " << start);
TestSpecParseBuf->skipChar();
if (isWireInject)
{
// sendToWire() is a helper function for TestTransport stuff.
// sendToWire(start);
SipMessage* message = TestSupport::makeMessage(start, true);
assert(message);
TestFSM::addMessage(client,message); // does a client->mStateMacFifo.add(message);
}
else
{
SipMessage* message = TestSupport::makeMessage(start, false);
assert(message);
client->send(*message);
}
}

| void processTimeouts | ( | int | arg | ) |
Definition at line 138 of file testTransactionFSM.cxx.
References resip::SipStack::buildFdSet(), client, clientFdSet, DebugLog, errorCount, fakeTxFifo, resip::RequestLine::getMethod(), resip::SipMessage::header(), resip::SipMessage::isRequest(), resip::SipMessage::isResponse(), resip::SipStack::process(), resip::SipStack::receive(), and WaitQueue.
Referenced by main().
{
client->buildFdSet(clientFdSet);
client->process(clientFdSet);
if (WaitQueue.empty())
{
return;
}
SipMessage* message = 0;
#if defined(UGLY) || 1
// This should:
// 1. Take all messages from the "wire" and "tu" fifos
// 2. For each message, look through the WaitQueue and see
// if the new message matches something we were waiting for.
// If yes, through away the queue entry, else raise a warning.
// 3. When all messages from the "wire" and "tu" have been
// examined, see if anything in the queue has expired.
// If yes, warn, else just continue.
// First go through the "wire" data
while (fakeTxFifo.messageAvailable())
{
message = fakeTxFifo.getNext();
for (list<WaitNode*>::iterator i = WaitQueue.begin();
i != WaitQueue.end();
/* don't increment */)
{
if ((*i)->mIsRequest && message->isRequest())
{
if ((*i)->mMethod == message->header(h_RequestLine).getMethod())
{
// We matched something we expected.
delete message;
message = 0;
delete *i;
WaitQueue.erase(i++);
break;
}
else
{
++i;
}
}
else if (!(*i)->mIsRequest && message->isResponse())
{
if ((*i)->mResponseCode ==
message->header(h_StatusLine).responseCode())
{
// We matched something we expected.
delete message;
message = 0;
delete *i;
WaitQueue.erase(i++);
break;
}
else
{
++i;
}
}
else
{
++i;
}
}
if (message)
{
DebugLog( << "Warning: unexpected message seen at the transport: "
<< message);
}
else
{
DebugLog( << "Success: expected message seen at the transport");
}
delete message;
}
// Now go through the data at the TU.
while (0 != (message = client->receive()))
{
for (list<WaitNode*>::iterator i = WaitQueue.begin();
i != WaitQueue.end();
/* don't increment */)
{
if ((*i)->mIsRequest && message->isRequest())
{
if ((*i)->mMethod ==
message->header(h_RequestLine).getMethod())
{
// We matched something we expected.
delete message;
message = 0;
delete *i;
WaitQueue.erase(i++);
break;
}
else
{
++i;
}
}
else if (!(*i)->mIsRequest && message->isResponse())
{
if ((*i)->mResponseCode ==
message->header(h_StatusLine).responseCode())
{
// We matched something we expected.
delete message;
message = 0;
delete *i;
WaitQueue.erase(i++);
break;
}
else
{
++i;
}
}
else
{
++i;
}
}
if (message)
{
DebugLog( << "Warning: unexpected message seen at the TU: "
<< *message);
delete message;
}
else
{
DebugLog( << "Success: expected message seen at TU");
}
}
// Print the list of expected events that have failed to happen withing
// the specified timeout.
for (list<WaitNode*>::iterator i = WaitQueue.begin();
i != WaitQueue.end();
/* don't increment */)
{
struct timeval tv;
gettimeofday(&tv, NULL);
if ((*i)->mExpiry.tv_sec < tv.tv_sec ||
((*i)->mExpiry.tv_sec == tv.tv_sec &&
(*i)->mExpiry.tv_usec < tv.tv_usec))
{
if ((*i)->mIsRequest)
{
DebugLog(<< "Error: timeout waiting for "
<< getMethodName((*i)->mMethod) << " method");
++errorCount;
}
else
{
DebugLog(<< "Error: timeout waiting for "
<< (*i)->mResponseCode << " status code");
++errorCount;
}
delete *i;
WaitQueue.erase(i++);
}
else
{
/*
cerr << "Still waiting for: ";
if ((*i)->mIsRequest)
{
cerr << MethodNames[(*i)->mMethod] << " method" << endl;
}
else
{
cerr << (*i)->mResponseCode << " status code" << endl;
}
*/
++i;
}
}
#endif
signal(SIGALRM, processTimeouts);
}

| int sendto | ( | int | s, |
| const void * | msg, | ||
| size_t | len, | ||
| int | flags, | ||
| const struct sockaddr * | to, | ||
| int | tolen | ||
| ) |
Definition at line 117 of file testTransactionFSM.cxx.
References fakeTxFifo, len, and resip::TestSupport::makeMessage().
Referenced by main(), and resip::UdpTransport::processTxOne().
{
fakeTxFifo.add(TestSupport::makeMessage(Data((const char *)msg, (int)len), true));
return len;
}

Definition at line 104 of file testTransactionFSM.cxx.
| int clientFd |
Definition at line 107 of file testTransactionFSM.cxx.
Referenced by main().
Definition at line 105 of file testTransactionFSM.cxx.
Referenced by processTimeouts().
| struct sockaddr_in clientSa |
Definition at line 106 of file testTransactionFSM.cxx.
Referenced by main().
| int errorCount = 0 |
Definition at line 109 of file testTransactionFSM.cxx.
Referenced by main(), and processTimeouts().
Definition at line 108 of file testTransactionFSM.cxx.
Referenced by processTimeouts(), and sendto().
| char* ProgramName = 0 |
Definition at line 100 of file testTransactionFSM.cxx.
Referenced by exitusage(), and main().
| char* TestSpecBuf = 0 |
Definition at line 101 of file testTransactionFSM.cxx.
Referenced by main().
Definition at line 102 of file testTransactionFSM.cxx.
Referenced by main(), processClause(), processDelays(), processExpect(), and processInject().
Definition at line 103 of file testTransactionFSM.cxx.
Referenced by main(), processExpect(), and processTimeouts().
1.7.5.1