realtimescheduler.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2006 Institut fuer Telematik, Universitaet Karlsruhe (TH)
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with this program; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 //
00018 
00024 #include "realtimescheduler.h"
00025 
00026 Register_PerRunConfigOption(CFGID_EXTERNALAPP_CONNECTION_LIMIT, "externalapp-connection-limit", CFG_INT, NULL, "TODO some documentation");
00027 Register_PerRunConfigOption(CFGID_EXTERNALAPP_APP_PORT, "externalapp-app-port", CFG_INT, NULL, "TODO some documentation");
00028 
00029 inline std::ostream& operator<<(std::ostream& os, const timeval& tv)
00030 {
00031     return os << (unsigned long)tv.tv_sec << "s" << tv.tv_usec << "us";
00032 }
00033 
00034 RealtimeScheduler::RealtimeScheduler() : cScheduler()
00035 {
00036     FD_ZERO(&all_fds);
00037     maxfd = 0;
00038     netw_fd = INVALID_SOCKET;
00039     additional_fd = INVALID_SOCKET;
00040     apptun_fd = INVALID_SOCKET;
00041 }
00042 
00043 RealtimeScheduler::~RealtimeScheduler()
00044 { }
00045 
00046 void RealtimeScheduler::startRun()
00047 {
00048     if (initsocketlibonce()!=0)
00049         throw cRuntimeError("RealtimeScheduler: Cannot initialize socket library");
00050 
00051     gettimeofday(&baseTime, NULL);
00052 
00053     appModule = NULL;
00054     appNotificationMsg = NULL;
00055     module = NULL;
00056     notificationMsg = NULL;
00057 
00058     appConnectionLimit = ev.getConfig()->getAsInt(CFGID_EXTERNALAPP_CONNECTION_LIMIT, 0);
00059 
00060     if (initializeNetwork()) {
00061         opp_error("realtimeScheduler error: initializeNetwork failed\n");
00062     }
00063 }
00064 
00065 void RealtimeScheduler::endRun()
00066 {}
00067 
00068 void RealtimeScheduler::executionResumed()
00069 {
00070     gettimeofday(&baseTime, NULL);
00071     baseTime = timeval_substract(baseTime, SIMTIME_DBL(simTime()));
00072 }
00073 
00074 void RealtimeScheduler::setInterfaceModule(cModule *mod, cMessage *notifMsg,
00075                                            PacketBuffer* buffer, int mtu,
00076                                            bool isApp)
00077 {
00078     if (!mod || !notifMsg || !buffer) {
00079         throw cRuntimeError("RealtimeScheduler: setInterfaceModule(): "
00080                                 "arguments must be non-NULL");
00081     }
00082 
00083     if (!isApp) {
00084         if (module) {
00085             throw cRuntimeError("RealtimeScheduler: setInterfaceModule() "
00086                                     "already called");
00087         }
00088         module = mod;
00089         notificationMsg = notifMsg;
00090         packetBuffer = buffer;
00091         buffersize = mtu;
00092     } else {
00093         if (appModule) {
00094             throw cRuntimeError("RealtimeScheduler: setInterfaceModule() "
00095                                     "already called");
00096         }
00097         appModule = mod;
00098         appNotificationMsg = notifMsg;
00099         appPacketBuffer = buffer;
00100         appBuffersize = mtu;
00101     }
00102 }
00103 
00104 bool RealtimeScheduler::receiveWithTimeout(long usec)
00105 {
00106     bool newEvent = false;
00107     // prepare sets for select()
00108     fd_set readFD;
00109     readFD = all_fds;
00110 
00111     timeval timeout;
00112     timeout.tv_sec = 0;
00113     timeout.tv_usec = usec;
00114 
00115     if (select(FD_SETSIZE, &readFD, NULL, NULL, &timeout) > 0) {
00116         // Read on all sockets with data
00117         for (SOCKET fd = 0; fd <= maxfd; fd++) {
00118             if (FD_ISSET(fd, &readFD)) {
00119                 // Incoming data on netw_fd
00120                 if (fd == netw_fd) {
00121                     char* buf = new char[buffersize];
00122                     int nBytes;
00123 
00124                     // FIXME: Ugly. But we want to support IPv4 and IPv6 here, so we
00125                     // reserve enough space for the "bigger" address.
00126                     sockaddr* from = (sockaddr*) new sockaddr_in;
00127                     socklen_t addrlen = sizeof(sockaddr_in);
00128 
00129                     // FIXME: Ugly...
00130                     getsockname(netw_fd, from, &addrlen);
00131                     if ( from->sa_family != SOCK_DGRAM ) {
00132                         delete from;
00133                         from = 0;
00134                         addrlen = 0;
00135                         // use read() for TUN device
00136                         nBytes = read(netw_fd, buf, buffersize);
00137                     } else {
00138                         addrlen = sizeof(sockaddr_in);
00139                         nBytes = recvfrom(netw_fd, buf, buffersize, 0, from, &addrlen);
00140                     }
00141 
00142                     if (nBytes < 0) {
00143                         ev << "[RealtimeScheduler::receiveWithTimeout()]\n"
00144                             << "    Error reading from network: " << strerror(sock_errno())
00145                             << endl;
00146                         delete[] buf;
00147                         buf = NULL;
00148                         opp_error("Read from network device returned an error");
00149                     } else if (nBytes == 0) {
00150                         ev << "[RealtimeScheduler::receiveWithTimeout()]\n"
00151                            << "    Received 0 byte long UDP packet!" << endl;
00152                         delete[] buf;
00153                         buf = NULL;
00154                     } else {
00155                         // write data to buffer
00156                         ev << "[RealtimeScheduler::receiveWithTimeout()]\n"
00157                             << "    Received " << nBytes << " bytes"
00158                             << endl;
00159                         packetBuffer->push_back(PacketBufferEntry(buf, nBytes, from, addrlen));
00160                         // schedule notificationMsg for the interface module
00161                         sendNotificationMsg(notificationMsg, module);
00162                         newEvent = true;
00163                     }
00164                 } else if ( fd == apptun_fd ) {
00165                     // Data on application TUN FD
00166                     char* buf = new char[appBuffersize];
00167                     // use read() for TUN device
00168                     int nBytes = read(fd, buf, appBuffersize);
00169 
00170                     if (nBytes < 0) {
00171                         ev << "[RealtimeScheduler::receiveWithTimeout()]\n"
00172                             << "    Error reading from application TUN socket: "
00173                             << strerror(sock_errno())
00174                             << endl;
00175                         delete[] buf;
00176                         buf = NULL;
00177                         opp_error("Read from application TUN socket returned "
00178                                   "an error");
00179                     } else if (nBytes == 0) {
00180                         ev << "[RealtimeScheduler::receiveWithTimeout()]\n"
00181                            << "    Received 0 byte long UDP packet!" << endl;
00182                         delete[] buf;
00183                         buf = NULL;
00184                     } else {
00185                         // write data to buffer
00186                         ev << "[RealtimeScheduler::receiveWithTimeout()]\n"
00187                             << "    Received " << nBytes << " bytes"
00188                             << endl;
00189 
00190                         appPacketBuffer->push_back(PacketBufferEntry(buf,
00191                             nBytes, PacketBufferEntry::PACKET_APPTUN_DATA, fd));
00192 
00193                         // schedule notificationMsg for the interface module
00194                         sendNotificationMsg(appNotificationMsg, appModule);
00195                         newEvent = true;
00196                     }
00197                 } else if ( fd == additional_fd ) {
00198                     // Data on additional FD
00199                     additionalFD();
00200                     newEvent = true;
00201                 } else {
00202                     // Data on app FD
00203                     char* buf = new char[appBuffersize];
00204                     int nBytes = recv(fd, buf, appBuffersize, 0);
00205                     if (nBytes < 0) {
00206                         delete[] buf;
00207                         buf = NULL;
00208                         ev << "[RealtimeScheduler::receiveWithTimeout()]\n"
00209                             << "    Read error from application socket: "
00210                             << strerror(sock_errno()) << endl;
00211                         opp_error("Read from network device returned an error (App)");
00212                     } else if (nBytes == 0) {
00213                         // Application closed Socket
00214                         ev << "[RealtimeScheduler::receiveWithTimeout()]\n"
00215                             << "    Application closed socket"
00216                             << endl;
00217                         delete[] buf;
00218                         buf = NULL;
00219                         closeAppSocket(fd);
00220                         newEvent = true;
00221                     } else {
00222                         // write data to buffer
00223                         ev << "[RealtimeScheduler::receiveWithTimeout()]\n"
00224                             << "    Received " << nBytes << " bytes"
00225                             << endl;
00226                         appPacketBuffer->push_back(PacketBufferEntry(buf, nBytes, PacketBufferEntry::PACKET_DATA, fd));
00227                         // schedule notificationMsg for the interface module
00228                         sendNotificationMsg(appNotificationMsg, appModule);
00229                         newEvent = true;
00230                     }
00231                 }
00232             }
00233         }
00234     }
00235     return newEvent;
00236 }
00237 
00238 int RealtimeScheduler::receiveUntil(const timeval& targetTime)
00239 {
00240     // if there's more than 200ms to wait, wait in 100ms chunks
00241     // in order to keep UI responsiveness by invoking ev.idle()
00242     timeval curTime;
00243     gettimeofday(&curTime, NULL);
00244     while (targetTime.tv_sec-curTime.tv_sec >=2 ||
00245             timeval_diff_usec(targetTime, curTime) >= 200000) {
00246         if (receiveWithTimeout(100000)) { // 100ms
00247             if (ev.idle()) return -1;
00248             return 1;
00249         }
00250         if (ev.idle()) return -1;
00251         gettimeofday(&curTime, NULL);
00252     }
00253 
00254     // difference is now at most 100ms, do it at once
00255     long usec = timeval_diff_usec(targetTime, curTime);
00256     if (usec>0)
00257         if (receiveWithTimeout(usec)) {
00258             if (ev.idle()) return -1;
00259             return 1;
00260         }
00261     if (ev.idle()) return -1;
00262     return 0;
00263 }
00264 
00265 cMessage *RealtimeScheduler::getNextEvent()
00266 {
00267     // assert that we've been configured
00268     if (!module)
00269         throw cRuntimeError("RealtimeScheduler: setInterfaceModule() not called: it must be called from a module's initialize() function");
00270     // FIXME: reimplement sanity check
00271 //    if (app_fd >= 0 && !appModule)
00272 //        throw cRuntimeError("RealtimeScheduler: setInterfaceModule() not called from application: it must be called from a module's initialize() function");
00273 
00274     // calculate target time
00275     timeval targetTime;
00276     cMessage *msg = sim->msgQueue.peekFirst();
00277     if (!msg) {
00278         // if there are no events, wait until something comes from outside
00279         // TBD: obey simtimelimit, cpu-time-limit
00280         targetTime.tv_sec = LONG_MAX;
00281         targetTime.tv_usec = 0;
00282     } else {
00283         // use time of next event
00284         simtime_t eventSimtime = msg->getArrivalTime();
00285         targetTime = timeval_add(baseTime, SIMTIME_DBL(eventSimtime));
00286     }
00287 
00288     // if needed, wait until that time arrives
00289     timeval curTime;
00290     gettimeofday(&curTime, NULL);
00291     if (timeval_greater(targetTime, curTime)) {
00292         int status = receiveUntil(targetTime);
00293         if (status == -1) {
00294             printf("WARNING: receiveUntil returned -1 (user interrupt)\n");
00295             return NULL; // interrupted by user
00296         } else if (status == 1) {
00297             msg = sim->msgQueue.peekFirst(); // received something
00298         }
00299     } else {
00300         //    printf("WARNING: Lagging behind realtime!\n");
00301         // we're behind -- customized versions of this class may
00302         // alert if we're too much behind, whatever that means
00303     }
00304     // ok, return the message
00305     return msg;
00306 }
00307 
00308 void RealtimeScheduler::closeAppSocket(SOCKET fd)
00309 {
00310 #ifdef _WIN32
00311     closesocket(fd);
00312 #else
00313     close(fd);
00314 #endif
00315     FD_CLR(fd, &all_fds);
00316 
00317     appPacketBuffer->push_back(PacketBufferEntry(0, 0, PacketBufferEntry::PACKET_FD_CLOSE, fd));
00318     sendNotificationMsg(appNotificationMsg, appModule);
00319 }
00320 
00321 void RealtimeScheduler::sendNotificationMsg(cMessage* msg, cModule* mod)
00322 {
00323     if (msg->isScheduled()) return; // Notification already scheduled
00324     timeval curTime;
00325     gettimeofday(&curTime, NULL);
00326     curTime = timeval_substract(curTime, baseTime);
00327     simtime_t t = curTime.tv_sec + curTime.tv_usec*1e-6;
00328 
00329     // if t < simTime, clock would go backwards. this would be bad...
00330     // (this could happen as timeval has a lower number of digits that simtime_t)
00331     if (t < simTime()) t = simTime();
00332 
00333     msg->setSentFrom(mod, -1, simTime());
00334     msg->setArrival(mod,-1,t);
00335     simulation.msgQueue.insert(msg);
00336 }
00337 
00338 ssize_t RealtimeScheduler::sendBytes(const char *buf,
00339                                      size_t numBytes,
00340                                      sockaddr* addr,
00341                                      socklen_t addrlen,
00342                                      bool isApp,
00343                                      SOCKET fd)
00344 {
00345     if (!buf) {
00346         ev << "[RealtimeScheduler::sendBytes()]\n"
00347         << "    Error sending packet: buf = NULL"
00348         << endl;
00349         return -1;
00350     }
00351     if (!isApp) {
00352         if( numBytes > buffersize ) {
00353             ev << "[RealtimeScheduler::sendBytes()]\n"
00354             << "    Trying to send oversized packet: size " << numBytes << " mtu " << buffersize
00355             << endl;
00356             opp_error("Can't send packet: too large"); //FIXME: Throw exception instead
00357         }
00358 
00359         if ( netw_fd == INVALID_SOCKET ) {
00360             ev << "[RealtimeScheduler::sendBytes()]\n"
00361             << "    Can't send packet to network: no tun/udp socket"
00362             << endl;
00363             return 0;
00364         }
00365         int nBytes;
00366         if (addr) {
00367             nBytes =  sendto(netw_fd, buf, numBytes, 0, addr, addrlen);
00368         } else {
00369             // TUN
00370             nBytes =  write(netw_fd, buf, numBytes);
00371         }
00372         if (nBytes < 0) {
00373             ev << "[RealtimeScheduler::sendBytes()]\n"
00374             << "    Error sending data to network: " << strerror(sock_errno()) << "\n"
00375             << "    FD = " << netw_fd << ", numBytes = " << numBytes <<  ", addrlen = " << addrlen
00376             << endl;
00377         }
00378         return nBytes;
00379 
00380     } else {
00381         if (numBytes > appBuffersize) {
00382             ev << "[RealtimeScheduler::sendBytes()]\n"
00383             << "    Trying to send oversized packet: size " << numBytes << "\n"
00384             << "    mtu " << appBuffersize
00385             << endl;
00386             opp_error("Can't send packet: too large"); //FIXME: Throw exception instead
00387         }
00388         // If no fd is given, select a "random" one
00389         if (fd == INVALID_SOCKET) {
00390             for (fd = 0; fd <= maxfd; fd++) {
00391                 if (fd == netw_fd) continue;
00392                 if (fd == additional_fd) continue;
00393                 if (FD_ISSET(fd, &all_fds)) break;
00394             }
00395             if (fd > maxfd) {
00396                 throw cRuntimeError("Can't send packet to Application: no socket");
00397             }
00398         }
00399         if (fd == apptun_fd) {
00400             // Application TUN FD
00401             return write(fd, buf, numBytes);
00402         } else {
00403             return send(fd, buf, numBytes, 0);
00404         }
00405     }
00406     // TBD check for errors
00407 }
00408 
Generated on Wed May 26 16:21:15 2010 for OverSim by  doxygen 1.6.3