RealtimeScheduler Class Reference

#include <realtimescheduler.h>

Inheritance diagram for RealtimeScheduler:

TunOutScheduler UdpOutScheduler 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 must be subclassed; its subclasses must handle network traffic from/to the simulation


Public Types

typedef std::list< PacketBufferEntryPacketBuffer

Public Member Functions

 RealtimeScheduler ()
 Constructor.
virtual ~RealtimeScheduler ()
 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, bool isApp=false)
 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 ssize_t sendBytes (const char *buf, size_t numBytes, sockaddr *addr=0, socklen_t addrlen=0, bool isApp=false)
 Send data to network.
void closeAppSocket ()
 Close the application TCP socket.

Protected Member Functions

virtual int initializeNetwork ()=0
 Initialize the network.
virtual void additionalFD ()
 This function is called from main loop if data is accessable from "additional_fd".
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 netw_fd
cModule * module
cMessage * notificationMsg
PacketBufferpacketBuffer
size_t buffersize
int app_fd
cModule * appModule
cMessage * appNotificationMsg
PacketBufferappPacketBuffer
size_t appBuffersize
int additional_fd
timeval baseTime

Classes

class  PacketBufferEntry


Member Typedef Documentation

typedef std::list<PacketBufferEntry> RealtimeScheduler::PacketBuffer


Constructor & Destructor Documentation

RealtimeScheduler::RealtimeScheduler (  ) 

Constructor.

00033                                      : cScheduler()
00034 {
00035     netw_fd = -1;
00036     app_fd = -1;
00037     additional_fd = -1;
00038 }

RealtimeScheduler::~RealtimeScheduler (  )  [virtual]

Destructor.

00040 { }


Member Function Documentation

virtual int RealtimeScheduler::initializeNetwork (  )  [protected, pure virtual]

Initialize the network.

Implemented in TunOutScheduler, and UdpOutScheduler.

virtual void RealtimeScheduler::additionalFD (  )  [inline, protected, virtual]

This function is called from main loop if data is accessable from "additional_fd".

This FD can be set in initializeNetwork by concrete implementations.

Reimplemented in TunOutScheduler, and UdpOutScheduler.

00083 {};

bool RealtimeScheduler::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
00092 {
00093     bool newData = false;
00094     // prepare sets for select()
00095     fd_set readFD;
00096     FD_ZERO(&readFD);
00097 
00098     if ( netw_fd >= 0 ) FD_SET(netw_fd, &readFD);
00099     if ( app_fd >= 0 ) FD_SET(app_fd, &readFD);
00100     if ( additional_fd >= 0 ) FD_SET(additional_fd, &readFD);
00101 
00102     timeval timeout;
00103     timeout.tv_sec = 0;
00104     timeout.tv_usec = usec;
00105 
00106     if (select(FD_SETSIZE, &readFD, NULL, NULL, &timeout) > 0) {
00107         // Incoming data
00108         if ( (netw_fd >= 0 ) && (FD_ISSET(netw_fd, &readFD)) ) {
00109             char* buf = new char[buffersize];
00110             int nBytes;
00111 
00112             // FIXME: Ugly. But we want to support IPv4 and IPv6 here, so we
00113             // reserve enough space for the "bigger" address.
00114             sockaddr* from = (sockaddr*) new sockaddr_in6;
00115             socklen_t addrlen = sizeof(sockaddr_in6);
00116 
00117             // FIXME: Ugly...
00118             getsockname(netw_fd, from, &addrlen);
00119             if ( from->sa_family != SOCK_DGRAM ) {
00120                 delete from;
00121                 from = 0;
00122                 addrlen = 0;
00123                 nBytes = read(netw_fd, buf, buffersize);
00124             } else {
00125                 addrlen = sizeof(sockaddr_in6);
00126                 nBytes = recvfrom(netw_fd, buf, buffersize, 0, from, &addrlen);
00127             }
00128 
00129             if (nBytes < 0) {
00130                 ev << "Error reading from network: " << strerror(errno) << "\n";
00131                 opp_error("Read from network device returned an error");
00132             } else if (nBytes == 0) {
00133                 opp_error("network device closed...");
00134             } else {
00135                 // write data to buffer
00136                 ev << "RealtimeScheduler: received " << nBytes << " bytes\n";
00137                 packetBuffer->push_back(PacketBufferEntry(buf, nBytes, from, addrlen));
00138 
00139                 // schedule notificationMsg for the interface module
00140                 timeval curTime;
00141                 gettimeofday(&curTime, NULL);
00142                 curTime = timeval_substract(curTime, baseTime);
00143                 simtime_t t = curTime.tv_sec + curTime.tv_usec*1e-6;
00144                 // TBD assert that it's somehow not smaller than previous event's time
00145                 notificationMsg->setArrival(module,-1,t);
00146                 simulation.msgQueue.insert(notificationMsg);
00147                 newData = true;
00148             }
00149         }
00150         if ( (app_fd >= 0) && (FD_ISSET(app_fd, &readFD)) ) {
00151             char* buf = new char[appBuffersize];
00152             int nBytes = read(app_fd, buf, appBuffersize);
00153             if (nBytes < 0) {
00154                 opp_error("Read from network device returned an error (App)");
00155             } else if (nBytes == 0) {
00156                 // Application closed Socket
00157                 ev << "Application closed socket\n";
00158                 close(app_fd);
00159                 app_fd = -1;
00160             } else {
00161                 // write data to buffer
00162                 ev << "RealtimeScheduler: received " << nBytes << " bytes\n";
00163                 appPacketBuffer->push_back(PacketBufferEntry(buf, nBytes));
00164 
00165                 // schedule notificationMsg for the interface module
00166                 timeval curTime;
00167                 gettimeofday(&curTime, NULL);
00168                 curTime = timeval_substract(curTime, baseTime);
00169                 simtime_t t = curTime.tv_sec + curTime.tv_usec*1e-6;
00170                 // TBD assert that it's somehow not smaller than previous event's time
00171                 appNotificationMsg->setArrival(appModule,-1,t);
00172                 simulation.msgQueue.insert(appNotificationMsg);
00173                 newData = true;
00174             }
00175         }
00176         if ( (additional_fd >= 0) && (FD_ISSET(additional_fd, &readFD)) ) {
00177             additionalFD();
00178         }
00179     }
00180     return newData;
00181 }

int RealtimeScheduler::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
00184 {
00185     // if there's more than 200ms to wait, wait in 100ms chunks
00186     // in order to keep UI responsiveness by invoking ev.idle()
00187     timeval curTime;
00188     gettimeofday(&curTime, NULL);
00189     while (targetTime.tv_sec-curTime.tv_sec >=2 ||
00190             timeval_diff_usec(targetTime, curTime) >= 200000) {
00191         if (receiveWithTimeout(100000)) { // 100ms
00192             if (ev.idle()) return -1;
00193             return 1;
00194         }
00195         if (ev.idle()) return -1;
00196         gettimeofday(&curTime, NULL);
00197     }
00198 
00199     // difference is now at most 100ms, do it at once
00200     long usec = timeval_diff_usec(targetTime, curTime);
00201     if (usec>0)
00202         if (receiveWithTimeout(usec)) {
00203             if (ev.idle()) return -1;
00204             return 1;
00205         }
00206         if (ev.idle()) return -1;
00207     return 0;
00208 }

void RealtimeScheduler::startRun (  )  [virtual]

Called at the beginning of a simulation run.

00043 {
00044     if (initsocketlibonce()!=0)
00045         throw new cRuntimeError("RealtimeScheduler: Cannot initialize socket library");
00046 
00047     gettimeofday(&baseTime, NULL);
00048 
00049     appModule = NULL;
00050     appNotificationMsg = NULL;
00051     module = NULL;
00052     notificationMsg = NULL;
00053 
00054     if (initializeNetwork()) {
00055         opp_error("realtimeScheduler error: initializeNetwork failed\n");
00056     }
00057 }

void RealtimeScheduler::endRun (  )  [virtual]

Called at the end of a simulation run.

00059 {}

void RealtimeScheduler::executionResumed (  )  [virtual]

Recalculates "base time" from current wall clock time.

00062 {
00063     gettimeofday(&baseTime, NULL);
00064     baseTime = timeval_substract(baseTime, sim->simTime());
00065 }

void RealtimeScheduler::setInterfaceModule ( cModule *  module,
cMessage *  notificationMsg,
PacketBuffer buffer,
int  mtu,
bool  isApp = false 
) [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
isApp set to "true" if called from a realworldApp
00068 {
00069     if (!mod || !notifMsg || !buffer)
00070         throw new cRuntimeError("RealtimeScheduler: setInterfaceModule(): arguments must be non-NULL");
00071 
00072     if (!isApp) {
00073         if (module)
00074             throw new cRuntimeError("RealtimeScheduler: setInterfaceModule() already called");
00075 
00076         module = mod;
00077         notificationMsg = notifMsg;
00078         packetBuffer = buffer;
00079         buffersize = mtu;
00080     } else {
00081         if (appModule)
00082             throw new cRuntimeError("RealtimeScheduler: setInterfaceModule() already called");
00083 
00084         appModule = mod;
00085         appNotificationMsg = notifMsg;
00086         appPacketBuffer = buffer;
00087         appBuffersize = mtu;
00088     }
00089 }

cMessage * RealtimeScheduler::getNextEvent (  )  [virtual]

Scheduler function -- it comes from cScheduler interface.

00211 {
00212     // assert that we've been configured
00213     if (!module)
00214         throw new cRuntimeError("RealtimeScheduler: setInterfaceModule() not called: it must be called from a module's initialize() function");
00215     if (app_fd >= 0 && !appModule)
00216         throw new cRuntimeError("RealtimeScheduler: setInterfaceModule() not called from application: it must be called from a module's initialize() function");
00217 
00218     // calculate target time
00219     timeval targetTime;
00220     cMessage *msg = sim->msgQueue.peekFirst();
00221     if (!msg) {
00222         // if there are no events, wait until something comes from outside
00223         // TBD: obey simtimelimit, cpu-time-limit
00224         targetTime.tv_sec = LONG_MAX;
00225         targetTime.tv_usec = 0;
00226     } else {
00227         // use time of next event
00228         simtime_t eventSimtime = msg->arrivalTime();
00229         targetTime = timeval_add(baseTime, eventSimtime);
00230     }
00231 
00232     // if needed, wait until that time arrives
00233     timeval curTime;
00234     gettimeofday(&curTime, NULL);
00235     if (timeval_greater(targetTime, curTime)) {
00236         int status = receiveUntil(targetTime);
00237         if (status == -1) {
00238             printf("WARNING: receiveUntil returned -1 (user interrupt)\n");
00239             return NULL; // interrupted by user
00240         } else if (status == 1) {
00241             msg = sim->msgQueue.peekFirst(); // received something
00242         }
00243     } else {
00244         //    printf("WARNING: Lagging behind realtime!\n");
00245         // we're behind -- customized versions of this class may
00246         // alert if we're too much behind, whatever that means
00247     }
00248     // ok, return the message
00249     return msg;
00250 }

ssize_t RealtimeScheduler::sendBytes ( const char *  buf,
size_t  numBytes,
sockaddr *  addr = 0,
socklen_t  addrlen = 0,
bool  isApp = false 
) [virtual]

Send data to network.

Parameters:
buf A pointer to the data to be send
numBytes the length of the data
isApp set to "true" if called from a realworldApp
addr If needed, the destination address
addrlen The length of the address
Returns:
The number of bytes written, -1 on error
00263 {
00264     if (!buf) {
00265         ev << "Error sending packet: buf = NULL!\n";
00266         return -1;
00267     }
00268     if (!isApp) {
00269         if( numBytes > buffersize ) {
00270             ev << "trying to send oversizd packet: size " << numBytes << " mtu " << buffersize << "\n";
00271             opp_error("Can't send packet: too large"); //FIXME: Throw exception instead
00272         }
00273         
00274         if ( netw_fd < 0 ) {
00275             ev << "Can't send packet to network: no tun socket!" << endl;
00276             return 0;
00277         }
00278         int nBytes;
00279         if (addr) {
00280             nBytes =  sendto(netw_fd, buf, numBytes, 0, addr, addrlen);
00281         } else {
00282             nBytes =  write(netw_fd, buf, numBytes);
00283         }
00284         if (nBytes < 0) {
00285             ev << "Error sending data to network: " << strerror(errno) << "\n";
00286             ev << "FD = " << netw_fd << ", numBytes = " << numBytes 
00287                 <<  ", addrlen = " << addrlen << "\n";
00288         }
00289         return nBytes;
00290 
00291     } else {
00292         if( numBytes > appBuffersize ) {
00293             ev << "trying to send oversizd packet: size " << numBytes << " mtu " << appBuffersize << "\n";
00294             opp_error("Can't send packet: too large"); //FIXME: Throw exception instead
00295         }
00296         if ( app_fd < 0 ) opp_error ("Can't send packet to Application: no socket");
00297         return write(app_fd, buf, numBytes);
00298     }
00299     // TBD check for errors
00300 }

void RealtimeScheduler::closeAppSocket (  ) 

Close the application TCP socket.

00253 {
00254     close(app_fd);
00255     app_fd = -1;
00256 }


Member Data Documentation

int RealtimeScheduler::netw_fd [protected]

cModule* RealtimeScheduler::module [protected]

cMessage* RealtimeScheduler::notificationMsg [protected]

PacketBuffer* RealtimeScheduler::packetBuffer [protected]

size_t RealtimeScheduler::buffersize [protected]

int RealtimeScheduler::app_fd [protected]

cModule* RealtimeScheduler::appModule [protected]

cMessage* RealtimeScheduler::appNotificationMsg [protected]

PacketBuffer* RealtimeScheduler::appPacketBuffer [protected]

size_t RealtimeScheduler::appBuffersize [protected]

int RealtimeScheduler::additional_fd [protected]

timeval RealtimeScheduler::baseTime [protected]


The documentation for this class was generated from the following files:
Generated on Tue Jul 24 16:51:19 2007 for ITM OverSim by  doxygen 1.5.1