#include <realtimescheduler.h>
Inheritance diagram for RealtimeScheduler:
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. | |
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 |
PacketBuffer * | packetBuffer |
size_t | buffersize |
int | app_fd |
cModule * | appModule |
cMessage * | appNotificationMsg |
PacketBuffer * | appPacketBuffer |
size_t | appBuffersize |
int | additional_fd |
timeval | baseTime |
Classes | |
class | PacketBufferEntry |
typedef std::list<PacketBufferEntry> RealtimeScheduler::PacketBuffer |
RealtimeScheduler::RealtimeScheduler | ( | ) |
Constructor.
00033 : cScheduler() 00034 { 00035 netw_fd = -1; 00036 app_fd = -1; 00037 additional_fd = -1; 00038 }
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) |
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.
targetTime | stop waiting after this time is up |
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::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 |
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.
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 |
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 | ( | ) |
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] |