#include <realtimescheduler.h>
1 simsec == 1 sec) It must be subclassed; its subclasses must handle network traffic from/to the simulation
Public Types | |
typedef std::list < PacketBufferEntry > | PacketBuffer |
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. | |
void | sendNotificationMsg (cMessage *msg, cModule *mod) |
send notification msg to module | |
virtual ssize_t | sendBytes (const char *buf, size_t numBytes, sockaddr *addr=0, socklen_t addrlen=0, bool isApp=false, int fd=-1) |
Send data to network. | |
void | closeAppSocket (int fd) |
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 | |
fd_set | all_fds |
int | maxfd |
int | netw_fd |
cModule * | module |
cMessage * | notificationMsg |
PacketBuffer * | packetBuffer |
size_t | buffersize |
cModule * | appModule |
cMessage * | appNotificationMsg |
PacketBuffer * | appPacketBuffer |
size_t | appBuffersize |
int | appConnectionLimit |
int | additional_fd |
timeval | baseTime |
Classes | |
class | PacketBufferEntry |
typedef std::list<PacketBufferEntry> RealtimeScheduler::PacketBuffer |
RealtimeScheduler::RealtimeScheduler | ( | ) |
Constructor.
00033 : cScheduler() 00034 { 00035 FD_ZERO(&all_fds); 00036 maxfd = -1; 00037 netw_fd = -1; 00038 additional_fd = -1; 00039 }
virtual int RealtimeScheduler::initializeNetwork | ( | ) | [protected, pure virtual] |
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.
bool RealtimeScheduler::receiveWithTimeout | ( | long | usec | ) | [protected, virtual] |
Waits for incoming data on the tun device.
usec | Timeout after which to quit waiting (in µsec) |
00098 { 00099 bool newEvent = false; 00100 // prepare sets for select() 00101 fd_set readFD; 00102 readFD = all_fds; 00103 00104 timeval timeout; 00105 timeout.tv_sec = 0; 00106 timeout.tv_usec = usec; 00107 00108 if (select(FD_SETSIZE, &readFD, NULL, NULL, &timeout) > 0) { 00109 // Read on all sockets with data 00110 for( int fd = 0; fd <= maxfd; fd++) { 00111 if( FD_ISSET(fd, &readFD)) { 00112 // Incoming data on netw_fd 00113 if( fd == netw_fd ) { 00114 char* buf = new char[buffersize]; 00115 int nBytes; 00116 00117 // FIXME: Ugly. But we want to support IPv4 and IPv6 here, so we 00118 // reserve enough space for the "bigger" address. 00119 sockaddr* from = (sockaddr*) new sockaddr_in6; 00120 socklen_t addrlen = sizeof(sockaddr_in6); 00121 00122 // FIXME: Ugly... 00123 getsockname(netw_fd, from, &addrlen); 00124 if ( from->sa_family != SOCK_DGRAM ) { 00125 delete from; 00126 from = 0; 00127 addrlen = 0; 00128 nBytes = read(netw_fd, buf, buffersize); 00129 } else { 00130 addrlen = sizeof(sockaddr_in6); 00131 nBytes = recvfrom(netw_fd, buf, buffersize, 0, from, &addrlen); 00132 } 00133 00134 if (nBytes < 0) { 00135 ev << "[RealtimeScheduler::receiveWithTimeout()]\n" 00136 << " Error reading from network: " << strerror(errno) 00137 << endl; 00138 opp_error("Read from network device returned an error"); 00139 } else if (nBytes == 0) { 00140 opp_error("network device closed..."); 00141 } else { 00142 // write data to buffer 00143 ev << "[RealtimeScheduler::receiveWithTimeout()]\n" 00144 << " Received " << nBytes << " bytes" 00145 << endl; 00146 packetBuffer->push_back(PacketBufferEntry(buf, nBytes, from, addrlen)); 00147 // schedule notificationMsg for the interface module 00148 sendNotificationMsg(notificationMsg, module); 00149 newEvent = true; 00150 } 00151 } else if ( fd == additional_fd ) { 00152 // Data on additional FD 00153 additionalFD(); 00154 newEvent = true; 00155 } else { 00156 // Data on app FD 00157 char* buf = new char[appBuffersize]; 00158 int nBytes = read(fd, buf, appBuffersize); 00159 if (nBytes < 0) { 00160 opp_error("Read from network device returned an error (App)"); 00161 } else if (nBytes == 0) { 00162 // Application closed Socket 00163 ev << "[RealtimeScheduler::receiveWithTimeout()]\n" 00164 << " Application closed socket" 00165 << endl; 00166 00167 closeAppSocket(fd); 00168 newEvent = true; 00169 } else { 00170 // write data to buffer 00171 ev << "[RealtimeScheduler::receiveWithTimeout()]\n" 00172 << " Received " << nBytes << " bytes" 00173 << endl; 00174 appPacketBuffer->push_back(PacketBufferEntry(buf, nBytes, PacketBufferEntry::DATA, fd)); 00175 // schedule notificationMsg for the interface module 00176 sendNotificationMsg(appNotificationMsg, appModule); 00177 newEvent = true; 00178 } 00179 } 00180 } 00181 } 00182 } 00183 return newEvent; 00184 }
int RealtimeScheduler::receiveUntil | ( | const timeval & | targetTime | ) | [protected, virtual] |
Tries to read data until the given time is up.
targetTime | stop waiting after this time is up |
00187 { 00188 // if there's more than 200ms to wait, wait in 100ms chunks 00189 // in order to keep UI responsiveness by invoking ev.idle() 00190 timeval curTime; 00191 gettimeofday(&curTime, NULL); 00192 while (targetTime.tv_sec-curTime.tv_sec >=2 || 00193 timeval_diff_usec(targetTime, curTime) >= 200000) { 00194 if (receiveWithTimeout(100000)) { // 100ms 00195 if (ev.idle()) return -1; 00196 return 1; 00197 } 00198 if (ev.idle()) return -1; 00199 gettimeofday(&curTime, NULL); 00200 } 00201 00202 // difference is now at most 100ms, do it at once 00203 long usec = timeval_diff_usec(targetTime, curTime); 00204 if (usec>0) 00205 if (receiveWithTimeout(usec)) { 00206 if (ev.idle()) return -1; 00207 return 1; 00208 } 00209 if (ev.idle()) return -1; 00210 return 0; 00211 }
void RealtimeScheduler::startRun | ( | ) | [virtual] |
Called at the beginning of a simulation run.
00045 { 00046 if (initsocketlibonce()!=0) 00047 throw new cRuntimeError("RealtimeScheduler: Cannot initialize socket library"); 00048 00049 gettimeofday(&baseTime, NULL); 00050 00051 appModule = NULL; 00052 appNotificationMsg = NULL; 00053 module = NULL; 00054 notificationMsg = NULL; 00055 00056 appConnectionLimit = ev.config()->getAsInt("ExternalApp", "connectionLimit"); 00057 00058 if (initializeNetwork()) { 00059 opp_error("realtimeScheduler error: initializeNetwork failed\n"); 00060 } 00061 }
void RealtimeScheduler::executionResumed | ( | ) | [virtual] |
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.
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 |
00073 { 00074 if (!mod || !notifMsg || !buffer) 00075 throw new cRuntimeError("RealtimeScheduler: setInterfaceModule(): arguments must be non-NULL"); 00076 00077 if (!isApp) { 00078 if (module) 00079 throw new cRuntimeError("RealtimeScheduler: setInterfaceModule() already called"); 00080 00081 module = mod; 00082 notificationMsg = notifMsg; 00083 packetBuffer = buffer; 00084 buffersize = mtu; 00085 } else { 00086 if (appModule) 00087 throw new cRuntimeError("RealtimeScheduler: setInterfaceModule() already called"); 00088 00089 appModule = mod; 00090 std::cout << "RealtimeScheduler::setInferfaceModule: " << appModule->fullPath() << std::endl; 00091 appNotificationMsg = notifMsg; 00092 appPacketBuffer = buffer; 00093 appBuffersize = mtu; 00094 } 00095 }
cMessage * RealtimeScheduler::getNextEvent | ( | ) | [virtual] |
Scheduler function -- it comes from cScheduler interface.
00214 { 00215 // assert that we've been configured 00216 if (!module) 00217 throw new cRuntimeError("RealtimeScheduler: setInterfaceModule() not called: it must be called from a module's initialize() function"); 00218 // FIXME: reimplement sanity check 00219 // if (app_fd >= 0 && !appModule) 00220 // throw new cRuntimeError("RealtimeScheduler: setInterfaceModule() not called from application: it must be called from a module's initialize() function"); 00221 00222 // calculate target time 00223 timeval targetTime; 00224 cMessage *msg = sim->msgQueue.peekFirst(); 00225 if (!msg) { 00226 // if there are no events, wait until something comes from outside 00227 // TBD: obey simtimelimit, cpu-time-limit 00228 targetTime.tv_sec = LONG_MAX; 00229 targetTime.tv_usec = 0; 00230 } else { 00231 // use time of next event 00232 simtime_t eventSimtime = msg->arrivalTime(); 00233 targetTime = timeval_add(baseTime, eventSimtime); 00234 } 00235 00236 // if needed, wait until that time arrives 00237 timeval curTime; 00238 gettimeofday(&curTime, NULL); 00239 if (timeval_greater(targetTime, curTime)) { 00240 int status = receiveUntil(targetTime); 00241 if (status == -1) { 00242 printf("WARNING: receiveUntil returned -1 (user interrupt)\n"); 00243 return NULL; // interrupted by user 00244 } else if (status == 1) { 00245 msg = sim->msgQueue.peekFirst(); // received something 00246 } 00247 } else { 00248 // printf("WARNING: Lagging behind realtime!\n"); 00249 // we're behind -- customized versions of this class may 00250 // alert if we're too much behind, whatever that means 00251 } 00252 // ok, return the message 00253 return msg; 00254 }
void RealtimeScheduler::sendNotificationMsg | ( | cMessage * | msg, | |
cModule * | mod | |||
) |
send notification msg to module
msg | The notification Message | |
mod | The destination |
00266 { 00267 if( msg->isScheduled() ) return; // Notification already scheduled 00268 timeval curTime; 00269 gettimeofday(&curTime, NULL); 00270 curTime = timeval_substract(curTime, baseTime); 00271 simtime_t t = curTime.tv_sec + curTime.tv_usec*1e-6; 00272 00273 msg->setSentFrom(mod, -1, simulation.simTime()); 00274 msg->setArrival(mod,-1,t); 00275 simulation.msgQueue.insert(msg); 00276 }
ssize_t RealtimeScheduler::sendBytes | ( | const char * | buf, | |
size_t | numBytes, | |||
sockaddr * | addr = 0 , |
|||
socklen_t | addrlen = 0 , |
|||
bool | isApp = false , |
|||
int | fd = -1 | |||
) | [virtual] |
Send data to network.
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 | |
fd | If connected to more than one external app, set to the corresponding FD. If left to default and multiple apps are connected, the data will be send to one arbitrarily chosen app. |
00284 { 00285 if (!buf) { 00286 ev << "[RealtimeScheduler::sendBytes()]\n" 00287 << " Error sending packet: buf = NULL" 00288 << endl; 00289 return -1; 00290 } 00291 if (!isApp) { 00292 if( numBytes > buffersize ) { 00293 ev << "[RealtimeScheduler::sendBytes()]\n" 00294 << " Trying to send oversized packet: size " << numBytes << " mtu " << buffersize 00295 << endl; 00296 opp_error("Can't send packet: too large"); //FIXME: Throw exception instead 00297 } 00298 00299 if ( netw_fd < 0 ) { 00300 ev << "[RealtimeScheduler::sendBytes()]\n" 00301 << " Can't send packet to network: no tun socket" 00302 << endl; 00303 return 0; 00304 } 00305 int nBytes; 00306 if (addr) { 00307 nBytes = sendto(netw_fd, buf, numBytes, 0, addr, addrlen); 00308 } else { 00309 nBytes = write(netw_fd, buf, numBytes); 00310 } 00311 if (nBytes < 0) { 00312 ev << "[RealtimeScheduler::sendBytes()]\n" 00313 << " Error sending data to network: " << strerror(errno) << "\n" 00314 << " FD = " << netw_fd << ", numBytes = " << numBytes << ", addrlen = " << addrlen 00315 << endl; 00316 } 00317 return nBytes; 00318 00319 } else { 00320 if( numBytes > appBuffersize ) { 00321 ev << "[RealtimeScheduler::sendBytes()]\n" 00322 << " Trying to send oversized packet: size " << numBytes << "\n" 00323 << " mtu " << appBuffersize 00324 << endl; 00325 opp_error("Can't send packet: too large"); //FIXME: Throw exception instead 00326 } 00327 // If no fd is given, select a "random" one 00328 if ( fd < 0 ) { 00329 for ( fd = 0; fd <= maxfd; fd++ ) { 00330 if( fd == netw_fd ) continue; 00331 if( fd == additional_fd ) continue; 00332 if( FD_ISSET(fd, &all_fds)) break; 00333 } 00334 if ( fd > maxfd ) throw new cException("Can't send packet to Application: no socket"); 00335 } 00336 return write(fd, buf, numBytes); 00337 } 00338 // TBD check for errors 00339 }
void RealtimeScheduler::closeAppSocket | ( | int | fd | ) |
Close the application TCP socket.
00257 { 00258 close(fd); 00259 FD_CLR(fd, &all_fds); 00260 00261 appPacketBuffer->push_back(PacketBufferEntry(0, 0, PacketBufferEntry::FD_CLOSE, fd)); 00262 sendNotificationMsg(appNotificationMsg, appModule); 00263 }
fd_set RealtimeScheduler::all_fds [protected] |
int RealtimeScheduler::maxfd [protected] |
int RealtimeScheduler::netw_fd [protected] |
cModule* RealtimeScheduler::module [protected] |
cMessage* RealtimeScheduler::notificationMsg [protected] |
PacketBuffer* RealtimeScheduler::packetBuffer [protected] |
size_t RealtimeScheduler::buffersize [protected] |
cModule* RealtimeScheduler::appModule [protected] |
cMessage* RealtimeScheduler::appNotificationMsg [protected] |
PacketBuffer* RealtimeScheduler::appPacketBuffer [protected] |
size_t RealtimeScheduler::appBuffersize [protected] |
int RealtimeScheduler::appConnectionLimit [protected] |
int RealtimeScheduler::additional_fd [protected] |
timeval RealtimeScheduler::baseTime [protected] |