INET Framework for OMNeT++/OMNEST
cSocketRTScheduler Class Reference

#include <cSocketRTScheduler.h>

List of all members.

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

Constructor & Destructor Documentation

cSocketRTScheduler::cSocketRTScheduler ( )

Constructor.

                                       : cScheduler()
{
    fd = INVALID_SOCKET;
}
cSocketRTScheduler::~cSocketRTScheduler ( ) [virtual]

Destructor.

{
}

Member Function Documentation

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]

Recalculates "base time" from current wall clock time.

{
    gettimeofday(&baseTime, NULL);
    baseTime = timeval_substract(baseTime, sim->getSimTime().dbl());
}
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
}

Member Data Documentation


The documentation for this class was generated from the following files: