00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "cSocketRTScheduler.h"
00025
00026 #ifndef IPPROTO_SCTP
00027 #define IPPROTO_SCTP 132
00028 #endif
00029
00030 #include <headers/ethernet.h>
00031
00032 #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__) || defined(_WIN64)
00033 #include <ws2tcpip.h>
00034 #endif
00035
00036 #define PCAP_SNAPLEN 65536
00037 #define PCAP_TIMEOUT 10
00038
00039 #ifdef HAVE_PCAP
00040 std::vector<cModule *>cSocketRTScheduler::modules;
00041 std::vector<pcap_t *>cSocketRTScheduler::pds;
00042 std::vector<int32>cSocketRTScheduler::datalinks;
00043 std::vector<int32>cSocketRTScheduler::headerLengths;
00044 #endif
00045 timeval cSocketRTScheduler::baseTime;
00046
00047 Register_Class(cSocketRTScheduler);
00048
00049 inline std::ostream& operator<<(std::ostream& out, const timeval& tv)
00050 {
00051 return out << (uint32)tv.tv_sec << "s" << tv.tv_usec << "us";
00052 }
00053
00054
00055 cSocketRTScheduler::cSocketRTScheduler() : cScheduler()
00056 {
00057 fd = INVALID_SOCKET;
00058 }
00059
00060 cSocketRTScheduler::~cSocketRTScheduler()
00061 {
00062 }
00063
00064 void cSocketRTScheduler::startRun()
00065 {
00066 #ifdef HAVE_PCAP
00067 const int32 on = 1;
00068
00069 #endif
00070 gettimeofday(&baseTime, NULL);
00071 #ifdef HAVE_PCAP
00072
00073 fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
00074 if (fd == INVALID_SOCKET)
00075 throw cRuntimeError("cSocketRTScheduler: Root priviledges needed");
00076 if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0)
00077 throw cRuntimeError("cSocketRTScheduler: couldn't set sockopt for raw socket");
00078 #endif
00079 }
00080
00081
00082 void cSocketRTScheduler::endRun()
00083 {
00084 #ifdef HAVE_PCAP
00085 pcap_stat ps;
00086
00087 #endif
00088 close(fd);
00089 fd = INVALID_SOCKET;
00090 #ifdef HAVE_PCAP
00091
00092 for (uint16 i=0; i<pds.size(); i++)
00093 {
00094 if (pcap_stats(pds.at(i), &ps) < 0)
00095 throw cRuntimeError("cSocketRTScheduler::endRun(): Can not get pcap statistics: %s", pcap_geterr(pds.at(i)));
00096 else
00097 EV << modules.at(i)->getFullPath() << ": Received Packets: " << ps.ps_recv << " Dropped Packets: " << ps.ps_drop << ".\n";
00098 pcap_close(pds.at(i));
00099 }
00100
00101 pds.clear();
00102 modules.clear();
00103 pds.clear();
00104 datalinks.clear();
00105 headerLengths.clear();
00106 #endif
00107 }
00108
00109 void cSocketRTScheduler::executionResumed()
00110 {
00111 gettimeofday(&baseTime, NULL);
00112 baseTime = timeval_substract(baseTime, sim->getSimTime().dbl());
00113 }
00114
00115 void cSocketRTScheduler::setInterfaceModule(cModule *mod, const char *dev, const char *filter)
00116 {
00117 #ifdef HAVE_PCAP
00118 char errbuf[PCAP_ERRBUF_SIZE];
00119 struct bpf_program fcode;
00120 pcap_t * pd;
00121 int32 datalink;
00122 int32 headerLength;
00123
00124 if (!mod || !dev || !filter)
00125 throw cRuntimeError("cSocketRTScheduler::setInterfaceModule(): arguments must be non-NULL");
00126
00127
00128 memset(&errbuf, 0, sizeof(errbuf));
00129 if ((pd = pcap_open_live(dev, PCAP_SNAPLEN, 0, PCAP_TIMEOUT, errbuf)) == NULL)
00130 throw cRuntimeError("cSocketRTScheduler::setInterfaceModule(): Can not open pcap device, error = %s", errbuf);
00131 else if(strlen(errbuf) > 0)
00132 EV << "cSocketRTScheduler::setInterfaceModule: pcap_open_live returned waring: " << errbuf << "\n";
00133
00134
00135 if (pcap_compile(pd, &fcode, (char *)filter, 0, 0) < 0)
00136 throw cRuntimeError("cSocketRTScheduler::setInterfaceModule(): Can not compile filter: %s", pcap_geterr(pd));
00137
00138
00139 if (pcap_setfilter(pd, &fcode) < 0)
00140 throw cRuntimeError("cSocketRTScheduler::setInterfaceModule(): Can not apply compiled filter: %s", pcap_geterr(pd));
00141
00142 if ((datalink = pcap_datalink(pd)) < 0)
00143 throw cRuntimeError("cSocketRTScheduler::setInterfaceModule(): Can not get datalink: %s", pcap_geterr(pd));
00144
00145 #ifndef LINUX
00146 if (pcap_setnonblock(pd, 1, errbuf) < 0)
00147 throw cRuntimeError("cSocketRTScheduler::pcap_setnonblock(): Can not put pcap device into non-blocking mode, error = %s", errbuf);
00148 #endif
00149
00150 switch (datalink) {
00151 case DLT_NULL:
00152 headerLength = 4;
00153 break;
00154 case DLT_EN10MB:
00155 headerLength = 14;
00156 break;
00157 case DLT_SLIP:
00158 headerLength = 24;
00159 break;
00160 case DLT_PPP:
00161 headerLength = 24;
00162 break;
00163 default:
00164 throw cRuntimeError("cSocketRTScheduler::setInterfaceModule(): Unsupported datalink: %d", datalink);
00165 }
00166 modules.push_back(mod);
00167 pds.push_back(pd);
00168 datalinks.push_back(datalink);
00169 headerLengths.push_back(headerLength);
00170
00171 EV << "Opened pcap device " << dev << " with filter " << filter << " and datalink " << datalink << ".\n";
00172 #else
00173 throw cRuntimeError("cSocketRTScheduler::setInterfaceModule(): pcap devices not supported");
00174 #endif
00175 }
00176
00177 #ifdef HAVE_PCAP
00178 static void packet_handler(u_char *user, const struct pcap_pkthdr *hdr, const u_char *bytes)
00179 {
00180 unsigned i;
00181 int32 headerLength;
00182 int32 datalink;
00183 cModule *module;
00184 struct ether_header *ethernet_hdr;
00185
00186 i = *(uint16 *)user;
00187 datalink = cSocketRTScheduler::datalinks.at(i);
00188 headerLength = cSocketRTScheduler::headerLengths.at(i);
00189 module = cSocketRTScheduler::modules.at(i);
00190
00191
00192 if (datalink == DLT_EN10MB)
00193 {
00194 ethernet_hdr = (struct ether_header *)bytes;
00195 if (ntohs(ethernet_hdr->ether_type) != ETHERTYPE_IP)
00196 return;
00197 }
00198
00199
00200 ExtFrame *notificationMsg = new ExtFrame("rtEvent");
00201 notificationMsg->setDataArraySize(hdr->caplen - headerLength);
00202 for (uint16 j=0; j< hdr->caplen - headerLength; j++)
00203 notificationMsg->setData(j, bytes[j + headerLength]);
00204
00205
00206 EV << "Captured " << hdr->caplen - headerLength << " bytes for an IP packet.\n";
00207 timeval curTime;
00208 gettimeofday(&curTime, NULL);
00209 curTime = timeval_substract(curTime, cSocketRTScheduler::baseTime);
00210 simtime_t t = curTime.tv_sec + curTime.tv_usec*1e-6;
00211
00212 notificationMsg->setArrival(module, -1, t);
00213
00214 simulation.msgQueue.insert(notificationMsg);
00215 }
00216 #endif
00217
00218 bool cSocketRTScheduler::receiveWithTimeout()
00219 {
00220 bool found;
00221 struct timeval timeout;
00222 #ifdef HAVE_PCAP
00223 int32 n;
00224 #ifdef LINUX
00225 int32 fd[FD_SETSIZE], maxfd;
00226 fd_set rdfds;
00227 #endif
00228 #endif
00229
00230 found = false;
00231 timeout.tv_sec = 0;
00232 timeout.tv_usec = PCAP_TIMEOUT * 1000;
00233 #ifdef HAVE_PCAP
00234 #ifdef LINUX
00235 FD_ZERO(&rdfds);
00236 maxfd = -1;
00237 for (uint16 i = 0; i < pds.size(); i++)
00238 {
00239 fd[i] = pcap_get_selectable_fd(pds.at(i));
00240 if (fd[i] > maxfd)
00241 maxfd = fd[i];
00242 FD_SET(fd[i], &rdfds);
00243 }
00244 if (select(maxfd + 1, &rdfds, NULL, NULL, &timeout) < 0)
00245 {
00246 return found;
00247 }
00248 #endif
00249 for (uint16 i = 0; i < pds.size(); i++)
00250 {
00251 #ifdef LINUX
00252 if (!(FD_ISSET(fd[i], &rdfds)))
00253 continue;
00254 #endif
00255 if ((n = pcap_dispatch(pds.at(i), 1, packet_handler, (uint8 *)&i)) < 0)
00256 throw cRuntimeError("cSocketRTScheduler::pcap_dispatch(): An error occired: %s", pcap_geterr(pds.at(i)));
00257 if (n > 0)
00258 found = true;
00259 }
00260 #ifndef LINUX
00261 if (!found)
00262 select(0, NULL, NULL, NULL, &timeout);
00263 #endif
00264 #else
00265 select(0, NULL, NULL, NULL, &timeout);
00266 #endif
00267 return found;
00268 }
00269
00270 int32 cSocketRTScheduler::receiveUntil(const timeval& targetTime)
00271 {
00272
00273
00274 timeval curTime;
00275 gettimeofday(&curTime, NULL);
00276 while (timeval_greater(targetTime, curTime))
00277 {
00278 if (receiveWithTimeout())
00279 return 1;
00280 if (ev.idle())
00281 return -1;
00282 gettimeofday(&curTime, NULL);
00283 }
00284 return 0;
00285 }
00286
00287 cMessage *cSocketRTScheduler::getNextEvent()
00288 {
00289 timeval targetTime, curTime, diffTime;
00290
00291
00292 cMessage *msg = sim->msgQueue.peekFirst();
00293 if (!msg)
00294 {
00295 targetTime.tv_sec = LONG_MAX;
00296 targetTime.tv_usec = 0;
00297 }
00298 else
00299 {
00300 simtime_t eventSimtime = msg->getArrivalTime();
00301 targetTime = timeval_add(baseTime, eventSimtime.dbl());
00302 }
00303
00304 gettimeofday(&curTime, NULL);
00305 if (timeval_greater(targetTime, curTime))
00306 {
00307 int32 status = receiveUntil(targetTime);
00308 if (status == -1)
00309 return NULL;
00310 if (status == 1)
00311 msg = sim->msgQueue.peekFirst();
00312 }
00313 else
00314 {
00315
00316
00317 diffTime = timeval_substract(curTime, targetTime);
00318 EV << "We are behind: " << diffTime.tv_sec + diffTime.tv_usec * 1e-6 << " seconds\n";
00319 }
00320 return msg;
00321 }
00322
00323 void cSocketRTScheduler::sendBytes(uint8 *buf, size_t numBytes, struct sockaddr *to, socklen_t addrlen)
00324 {
00325 if (fd == INVALID_SOCKET)
00326 throw cRuntimeError("cSocketRTScheduler::sendBytes(): no raw socket.");
00327
00328 int sent = sendto(fd, (char *)buf, numBytes, 0, to, addrlen);
00329
00330 if (sent == numBytes)
00331 EV << "Sent an IP packet with length of " << sent << " bytes.\n";
00332 else
00333 EV << "Sending of an IP packet FAILED! (sendto returned " << sent << " (" << strerror(errno) << ") instead of " << numBytes << ").\n";
00334 }