cTunOutScheduler Class Reference

#include <ctunoutscheduler.h>

List of all members.


Detailed Description

This class implements a event scheduler for omnet It makes the simulation run in realtime (i.e.

1 simsec == 1 sec) It is capable of reading/sending data to linux' tun-device Preparing or interpreting the data is done by other classes, however


Public Types

typedef std::list< char * > PacketBuffer

Public Member Functions

 cTunOutScheduler ()
 Constructor.
virtual ~cTunOutScheduler ()
 Destructor.
virtual void startRun ()
 Called at the beginning of a simulation run.
virtual void endRun ()
 Called at the end of a simulation run.
virtual void executionResumed ()
 Recalculates "base time" from current wall clock time.
virtual void setInterfaceModule (cModule *module, cMessage *notificationMsg, PacketBuffer *buffer, int mtu)
 To be called from the module which wishes to receive data from the tun device.
virtual cMessage * getNextEvent ()
 Scheduler function -- it comes from cScheduler interface.
virtual void sendBytes (const char *buf, size_t numBytes)
 Send data to tun device.

Protected Member Functions

virtual void tun_alloc ()
 Allocates the tun device.
virtual bool receiveWithTimeout (long usec)
 Waits for incoming data on the tun device.
virtual int receiveUntil (const timeval &targetTime)
 Tries to read data until the given time is up.

Protected Attributes

int tun_fd
size_t buffersize
char * dev
cModule * module
cMessage * notificationMsg
PacketBufferpacketBuffer
timeval baseTime


Member Typedef Documentation

typedef std::list<char*> cTunOutScheduler::PacketBuffer


Constructor & Destructor Documentation

cTunOutScheduler::cTunOutScheduler (  ) 

Constructor.

00013                                    : cScheduler()
00014 {
00015     tun_fd = -1;
00016 }

cTunOutScheduler::~cTunOutScheduler (  )  [virtual]

Destructor.

00019 {
00020     delete dev;
00021 }


Member Function Documentation

void cTunOutScheduler::endRun (  )  [virtual]

Called at the end of a simulation run.

00074 {}

void cTunOutScheduler::executionResumed (  )  [virtual]

Recalculates "base time" from current wall clock time.

00077 {
00078     gettimeofday(&baseTime, NULL);
00079     baseTime = timeval_substract(baseTime, sim->simTime());
00080 }

cMessage * cTunOutScheduler::getNextEvent (  )  [virtual]

Scheduler function -- it comes from cScheduler interface.

00158 {
00159     // assert that we've been configured
00160     if (!module)
00161         throw new cRuntimeError("cTunOutScheduler: setInterfaceModule() not called: it must be called from a module's initialize() function");
00162 
00163     // calculate target time
00164     timeval targetTime;
00165     cMessage *msg = sim->msgQueue.peekFirst();
00166     if (!msg) {
00167         // if there are no events, wait until something comes from outside
00168         // TBD: obey simtimelimit, cpu-time-limit
00169         targetTime.tv_sec = LONG_MAX;
00170         targetTime.tv_usec = 0;
00171     } else {
00172         // use time of next event
00173         simtime_t eventSimtime = msg->arrivalTime();
00174         targetTime = timeval_add(baseTime, eventSimtime);
00175     }
00176 
00177     // if needed, wait until that time arrives
00178     timeval curTime;
00179     gettimeofday(&curTime, NULL);
00180     if (timeval_greater(targetTime, curTime)) {
00181         int status = receiveUntil(targetTime);
00182         if (status == -1)
00183             return NULL; // interrupted by user
00184         if (status == 1)
00185             msg = sim->msgQueue.peekFirst(); // received something
00186     } else {
00187         // we're behind -- customized versions of this class may
00188         // alert if we're too much behind, whatever that means
00189     }
00190 
00191     // ok, return the message
00192     return msg;
00193 }

int cTunOutScheduler::receiveUntil ( const timeval &  targetTime  )  [protected, virtual]

Tries to read data until the given time is up.

Parameters:
targetTime stop waiting after this time is up
Returns:
1 if data is read, -1 if there is an error, 0 if no data is read
00135 {
00136     // if there's more than 200ms to wait, wait in 100ms chunks
00137     // in order to keep UI responsiveness by invoking ev.idle()
00138     timeval curTime;
00139     gettimeofday(&curTime, NULL);
00140     while (targetTime.tv_sec-curTime.tv_sec >=2 ||
00141             timeval_diff_usec(targetTime, curTime) >= 200000) {
00142         if (receiveWithTimeout(100000)) // 100ms
00143             return 1;
00144         if (ev.idle())
00145             return -1;
00146         gettimeofday(&curTime, NULL);
00147     }
00148 
00149     // difference is now at most 100ms, do it at once
00150     long usec = timeval_diff_usec(targetTime, curTime);
00151     if (usec>0)
00152         if (receiveWithTimeout(usec))
00153             return 1;
00154     return 0;
00155 }

bool cTunOutScheduler::receiveWithTimeout ( long  usec  )  [protected, virtual]

Waits for incoming data on the tun device.

Parameters:
usec Timeout after which to quit waiting (in µsec)
Returns:
true if data was read, false otherwise
00096 {
00097     // prepare sets for select()
00098     fd_set readFD;
00099     FD_ZERO(&readFD);
00100 
00101     FD_SET(tun_fd, &readFD);
00102 
00103     timeval timeout;
00104     timeout.tv_sec = 0;
00105     timeout.tv_usec = usec;
00106 
00107     if (select(FD_SETSIZE, &readFD, NULL, NULL, &timeout) > 0) {
00108         // Incoming data
00109         char* buf = new char[buffersize];
00110         int nBytes = read(tun_fd, buf, buffersize);
00111         if (nBytes < 0) {
00112             opp_error("Read from TUN device returned an error");
00113         } else if (nBytes == 0) {
00114             opp_error("TUN device closed...");
00115         } else {
00116             // write data to buffer
00117             ev << "cTunOutScheduler: received " << nBytes << " bytes\n";
00118             packetBuffer->push_back(buf);
00119 
00120             // schedule notificationMsg for the interface module
00121             timeval curTime;
00122             gettimeofday(&curTime, NULL);
00123             curTime = timeval_substract(curTime, baseTime);
00124             simtime_t t = curTime.tv_sec + curTime.tv_usec*1e-6;
00125             // TBD assert that it's somehow not smaller than previous event's time
00126             notificationMsg->setArrival(module,-1,t);
00127             simulation.msgQueue.insert(notificationMsg);
00128             return true;
00129         }
00130     }
00131     return false;
00132 }

void cTunOutScheduler::sendBytes ( const char *  buf,
size_t  numBytes 
) [virtual]

Send data to tun device.

Parameters:
buf A pointer to the data to be send
numBytes the length of the data
00196 {
00197     if (!buf) {
00198         ev << "Error sending packet: buf = NULL!\n";
00199         return;
00200     }
00201     if( numBytes > buffersize ) {
00202         ev << "trying to send oversizd packet: size " << numBytes << " mtu " << buffersize << "\n";
00203         opp_error("Can't send packet: too large"); //FIXME: Throw exception instead
00204     }
00205     write(tun_fd, buf, numBytes);
00206     // TBD check for errors
00207 }

void cTunOutScheduler::setInterfaceModule ( cModule *  module,
cMessage *  notificationMsg,
PacketBuffer buffer,
int  mtu 
) [virtual]

To be called from the module which wishes to receive data from the tun device.

The method must be called from the module's initialize() function.

Parameters:
module Pointer to the module that whishes to receive the data
notificationMsg A pointer to a message that will be sheduled if there is data to read
buffer A pointer to the buffer the data will be written into
mtu Max allowed packet size
00083 {
00084     if (module)
00085         throw new cRuntimeError("cTunOutScheduler: setInterfaceModule() already called");
00086     if (!mod || !notifMsg || !buffer)
00087         throw new cRuntimeError("cTunOutScheduler: setInterfaceModule(): arguments must be non-NULL");
00088 
00089     module = mod;
00090     notificationMsg = notifMsg;
00091     packetBuffer = buffer;
00092     buffersize = mtu;
00093 }

void cTunOutScheduler::startRun (  )  [virtual]

Called at the beginning of a simulation run.

00024 {
00025     if (initsocketlibonce()!=0)
00026         throw new cRuntimeError("cTunOutScheduler: Cannot initialize socket library");
00027 
00028     gettimeofday(&baseTime, NULL);
00029 
00030     module = NULL;
00031     notificationMsg = NULL;
00032 
00033     dev = new char[IFNAMSIZ];
00034     strcpy(dev, "tun%d");
00035     tun_alloc();
00036 }

void cTunOutScheduler::tun_alloc (  )  [protected, virtual]

Allocates the tun device.

00039 {
00040     // see /usr/src/linux/Documentation/network/tuntap.txt
00041     struct ifreq ifr;
00042     int err;
00043 
00044     if (tun_fd > 0)
00045         opp_error("Already bound to TUN device!");
00046     if( (tun_fd = open("/dev/net/tun", O_RDWR)) < 0 ) {
00047         opp_error("Error opening tun device");
00048     } else {
00049         ev << "cTunOutScheduler: Successfully opened TUN device.\n";
00050     }
00051 
00052     memset(&ifr, 0, sizeof(ifr));
00053 
00054     /* Flags: IFF_TUN   - TUN device (no Ethernet headers)
00055      *        IFF_TAP   - TAP device  
00056      * 
00057      *        IFF_NO_PI - Do not provide packet information  
00058      */
00059     ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
00060     if( *dev ) {
00061         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
00062     }
00063 
00064     if((err = ioctl(tun_fd, TUNSETIFF, (void *) &ifr)) < 0 ) {
00065         close(tun_fd);
00066         opp_error("Error ioctl tun device");
00067     } else {
00068         strncpy(dev, ifr.ifr_name, IFNAMSIZ);
00069         ev << "cTunOutScheduler: Bound to device " << dev << "\n";
00070     }
00071 }


Member Data Documentation

timeval cTunOutScheduler::baseTime [protected]

size_t cTunOutScheduler::buffersize [protected]

char* cTunOutScheduler::dev [protected]

cModule* cTunOutScheduler::module [protected]

cMessage* cTunOutScheduler::notificationMsg [protected]

PacketBuffer* cTunOutScheduler::packetBuffer [protected]

int cTunOutScheduler::tun_fd [protected]


The documentation for this class was generated from the following files:
Generated on Fri Dec 15 17:50:30 2006 for ITM OverSim by  doxygen 1.4.7