|
INET Framework for OMNeT++/OMNEST
|
#include <cSocketRTScheduler.h>
Public Member Functions | |
| cSocketRTScheduler () | |
| virtual | ~cSocketRTScheduler () |
| virtual void | startRun () |
| virtual void | endRun () |
| virtual void | executionResumed () |
| void | setInterfaceModule (cModule *mod, const char *dev, const char *filter) |
| virtual cMessage * | getNextEvent () |
| void | sendBytes (unsigned char *buf, size_t numBytes, struct sockaddr *from, socklen_t addrlen) |
Static Public Attributes | |
| static timeval | baseTime |
Protected Member Functions | |
| virtual bool | receiveWithTimeout () |
| virtual int | receiveUntil (const timeval &targetTime) |
Protected Attributes | |
| int | fd |
| cSocketRTScheduler::cSocketRTScheduler | ( | ) |
Constructor.
: cScheduler()
{
fd = INVALID_SOCKET;
}
| cSocketRTScheduler::~cSocketRTScheduler | ( | ) | [virtual] |
Destructor.
{
}
| void cSocketRTScheduler::endRun | ( | ) | [virtual] |
Called at the end of a simulation run.
{
#ifdef HAVE_PCAP
pcap_stat ps;
#endif
close(fd);
fd = INVALID_SOCKET;
#ifdef HAVE_PCAP
for (uint16 i=0; i<pds.size(); i++)
{
if (pcap_stats(pds.at(i), &ps) < 0)
throw cRuntimeError("cSocketRTScheduler::endRun(): Can not get pcap statistics: %s", pcap_geterr(pds.at(i)));
else
EV << modules.at(i)->getFullPath() << ": Received Packets: " << ps.ps_recv << " Dropped Packets: " << ps.ps_drop << ".\n";
pcap_close(pds.at(i));
}
pds.clear();
modules.clear();
pds.clear();
datalinks.clear();
headerLengths.clear();
#endif
}
| void cSocketRTScheduler::executionResumed | ( | ) | [virtual] |
| cMessage * cSocketRTScheduler::getNextEvent | ( | ) | [virtual] |
Scheduler function -- it comes from cScheduler interface.
{
timeval targetTime, curTime, diffTime;
// calculate target time
cMessage *msg = sim->msgQueue.peekFirst();
if (!msg)
{
targetTime.tv_sec = LONG_MAX;
targetTime.tv_usec = 0;
}
else
{
simtime_t eventSimtime = msg->getArrivalTime();
targetTime = timeval_add(baseTime, eventSimtime.dbl());
}
gettimeofday(&curTime, NULL);
if (timeval_greater(targetTime, curTime))
{
int32 status = receiveUntil(targetTime);
if (status == -1)
return NULL; // interrupted by user
if (status == 1)
msg = sim->msgQueue.peekFirst(); // received something
}
else
{
// we're behind -- customized versions of this class may
// alert if we're too much behind, whatever that means
diffTime = timeval_substract(curTime, targetTime);
EV << "We are behind: " << diffTime.tv_sec + diffTime.tv_usec * 1e-6 << " seconds\n";
}
return msg;
}
| int32 cSocketRTScheduler::receiveUntil | ( | const timeval & | targetTime | ) | [protected, virtual] |
Referenced by getNextEvent().
{
// wait until targetTime or a bit longer, wait in PCAP_TIMEOUT chunks
// in order to keep UI responsiveness by invoking ev.idle()
timeval curTime;
gettimeofday(&curTime, NULL);
while (timeval_greater(targetTime, curTime))
{
if (receiveWithTimeout())
return 1;
if (ev.idle())
return -1;
gettimeofday(&curTime, NULL);
}
return 0;
}
| bool cSocketRTScheduler::receiveWithTimeout | ( | ) | [protected, virtual] |
Referenced by receiveUntil().
{
bool found;
struct timeval timeout;
#ifdef HAVE_PCAP
int32 n;
#ifdef LINUX
int32 fd[FD_SETSIZE], maxfd;
fd_set rdfds;
#endif
#endif
found = false;
timeout.tv_sec = 0;
timeout.tv_usec = PCAP_TIMEOUT * 1000;
#ifdef HAVE_PCAP
#ifdef LINUX
FD_ZERO(&rdfds);
maxfd = -1;
for (uint16 i = 0; i < pds.size(); i++)
{
fd[i] = pcap_get_selectable_fd(pds.at(i));
if (fd[i] > maxfd)
maxfd = fd[i];
FD_SET(fd[i], &rdfds);
}
if (select(maxfd + 1, &rdfds, NULL, NULL, &timeout) < 0)
{
return found;
}
#endif
for (uint16 i = 0; i < pds.size(); i++)
{
#ifdef LINUX
if (!(FD_ISSET(fd[i], &rdfds)))
continue;
#endif
if ((n = pcap_dispatch(pds.at(i), 1, packet_handler, (uint8 *)&i)) < 0)
throw cRuntimeError("cSocketRTScheduler::pcap_dispatch(): An error occired: %s", pcap_geterr(pds.at(i)));
if (n > 0)
found = true;
}
#ifndef LINUX
if (!found)
select(0, NULL, NULL, NULL, &timeout);
#endif
#else
select(0, NULL, NULL, NULL, &timeout);
#endif
return found;
}
| void cSocketRTScheduler::sendBytes | ( | unsigned char * | buf, |
| size_t | numBytes, | ||
| struct sockaddr * | from, | ||
| socklen_t | addrlen | ||
| ) |
Send on the currently open connection
Referenced by ExtInterface::handleMessage().
{
if (fd == INVALID_SOCKET)
throw cRuntimeError("cSocketRTScheduler::sendBytes(): no raw socket.");
int sent = sendto(fd, (char *)buf, numBytes, 0, to, addrlen); //note: no ssize_t on MSVC
if (sent == numBytes)
EV << "Sent an IP packet with length of " << sent << " bytes.\n";
else
EV << "Sending of an IP packet FAILED! (sendto returned " << sent << " (" << strerror(errno) << ") instead of " << numBytes << ").\n";
}
| void cSocketRTScheduler::setInterfaceModule | ( | cModule * | mod, |
| const char * | dev, | ||
| const char * | filter | ||
| ) |
To be called from the module which wishes to receive data from the socket. The method must be called from the module's initialize() function.
Referenced by ExtInterface::initialize().
{
#ifdef HAVE_PCAP
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program fcode;
pcap_t * pd;
int32 datalink;
int32 headerLength;
if (!mod || !dev || !filter)
throw cRuntimeError("cSocketRTScheduler::setInterfaceModule(): arguments must be non-NULL");
/* get pcap handle */
memset(&errbuf, 0, sizeof(errbuf));
if ((pd = pcap_open_live(dev, PCAP_SNAPLEN, 0, PCAP_TIMEOUT, errbuf)) == NULL)
throw cRuntimeError("cSocketRTScheduler::setInterfaceModule(): Can not open pcap device, error = %s", errbuf);
else if(strlen(errbuf) > 0)
EV << "cSocketRTScheduler::setInterfaceModule: pcap_open_live returned waring: " << errbuf << "\n";
/* compile this command into a filter program */
if (pcap_compile(pd, &fcode, (char *)filter, 0, 0) < 0)
throw cRuntimeError("cSocketRTScheduler::setInterfaceModule(): Can not compile filter: %s", pcap_geterr(pd));
/* apply the compiled filter to the packet capture device */
if (pcap_setfilter(pd, &fcode) < 0)
throw cRuntimeError("cSocketRTScheduler::setInterfaceModule(): Can not apply compiled filter: %s", pcap_geterr(pd));
if ((datalink = pcap_datalink(pd)) < 0)
throw cRuntimeError("cSocketRTScheduler::setInterfaceModule(): Can not get datalink: %s", pcap_geterr(pd));
#ifndef LINUX
if (pcap_setnonblock(pd, 1, errbuf) < 0)
throw cRuntimeError("cSocketRTScheduler::pcap_setnonblock(): Can not put pcap device into non-blocking mode, error = %s", errbuf);
#endif
switch (datalink) {
case DLT_NULL:
headerLength = 4;
break;
case DLT_EN10MB:
headerLength = 14;
break;
case DLT_SLIP:
headerLength = 24;
break;
case DLT_PPP:
headerLength = 24;
break;
default:
throw cRuntimeError("cSocketRTScheduler::setInterfaceModule(): Unsupported datalink: %d", datalink);
}
modules.push_back(mod);
pds.push_back(pd);
datalinks.push_back(datalink);
headerLengths.push_back(headerLength);
EV << "Opened pcap device " << dev << " with filter " << filter << " and datalink " << datalink << ".\n";
#else
throw cRuntimeError("cSocketRTScheduler::setInterfaceModule(): pcap devices not supported");
#endif
}
| void cSocketRTScheduler::startRun | ( | ) | [virtual] |
Called at the beginning of a simulation run.
{
#ifdef HAVE_PCAP
const int32 on = 1;
#endif
gettimeofday(&baseTime, NULL);
#ifdef HAVE_PCAP
// Enabling sending makes no sense when we can't receive...
fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (fd == INVALID_SOCKET)
throw cRuntimeError("cSocketRTScheduler: Root priviledges needed");
if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0)
throw cRuntimeError("cSocketRTScheduler: couldn't set sockopt for raw socket");
#endif
}
timeval cSocketRTScheduler::baseTime [static] |
Referenced by executionResumed(), getNextEvent(), and startRun().
int cSocketRTScheduler::fd [protected] |
Referenced by cSocketRTScheduler(), endRun(), receiveWithTimeout(), sendBytes(), and startRun().