📄 testtransactionfsm.cxx
字号:
// How this works:
//
// The first argument to this program needs to be a file that has a test in it.
//
// Clauses in this file can be: inject_wire, expect_wire, expect_tu,
// inject_tu, and delay. A keyword needs to be by itself on a line. They
// need to be in this form
//
// inject_wire (or inject_tu)
// {
// ...put a SIP message here that has a CRLF after each line...
// }
//
// expect_wire (or expect_tu)
// {
// status=100 (or method=REGISTER)
// timeout=32
// }
//
// delay
// {
// timeout=48
// }
//
// The inject_* clauses inject the SIP message described at the "wire"
// or the "tu" level. The expect_* clauses indicate that the test
// specification expects to read a certain response (distinguished only
// by its response code) or request (distinguished only by its method
// name). The expect_* clauses don't block but will queue the
// expectation for the duration of the timeout specified. When you
// really want to sit and wait for a message, insert a delay clause.
// This is used as a "barrier" at which you want all the above timeouts
// to happen. You'll want one at the end of your test, for example.
#ifndef __MINGW32__
#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"
using namespace resip;
using namespace std;
#define RESIPROCATE_SUBSYSTEM Subsystem::TEST
#define PORT 5060
// --------------------------------------------------
namespace resip
{
class TestFSM // this class is a friend of the SipStack and can directly access private stuff
{
public:
static void addMessage(SipStack* stack,SipMessage* message)
{
stack->mTransactionController.mStateMacFifo.add(message);
}
};
}
typedef struct {
struct timeval mExpiry;
bool mIsRequest;
bool mIsTransport;
int mResponseCode;
MethodTypes mMethod;
} WaitNode;
// --------------------------------------------------
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;
// --------------------------------------------------
// This is pure evil. We interpose our own version of sendto
// so that this gets called by the UDP transport instead of the libc
// version.
int
sendto(int s, const void *msg, size_t len, int flags,
const struct sockaddr *to, int tolen)
{
fakeTxFifo.add(TestSupport::makeMessage(Data((const char *)msg, (int)len), true));
return len;
}
// --------------------------------------------------
void
exitusage()
{
cerr << "Usage: " << ProgramName << " ";
cerr << "<testfileofsipmessagesandstuff>" << endl;
exit(1);
}
void
processTimeouts(int arg)
{
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);
}
void
processInject()
{
const char* start = TestSpecParseBuf->position();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -