#include <ctunoutscheduler.h>
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 |
PacketBuffer * | packetBuffer |
timeval | baseTime |
typedef std::list<char*> cTunOutScheduler::PacketBuffer |
cTunOutScheduler::cTunOutScheduler | ( | ) |
cTunOutScheduler::~cTunOutScheduler | ( | ) | [virtual] |
void cTunOutScheduler::executionResumed | ( | ) | [virtual] |
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.
targetTime | stop waiting after this time is up |
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.
usec | Timeout after which to quit waiting (in µsec) |
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.
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.
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 }
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] |