|
INET Framework for OMNeT++/OMNEST
|
00001 // 00002 // Copyright (C) 2005-2009 Andras Varga, 00003 // Christian Dankbar, 00004 // Irene Ruengeler, 00005 // Michael Tuexen 00006 // 00007 // This program is free software; you can redistribute it and/or 00008 // modify it under the terms of the GNU General Public License 00009 // as published by the Free Software Foundation; either version 2 00010 // of the License, or (at your option) any later version. 00011 // 00012 // This program is distributed in the hope that it will be useful, 00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 // GNU General Public License for more details. 00016 // 00017 // You should have received a copy of the GNU General Public License 00018 // along with this program; if not, see <http://www.gnu.org/licenses/>. 00019 // 00020 00021 // This file is based on the cSocketRTScheduler.cc of OMNeT++ written by 00022 // Andras Varga. 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 /* capture all data packets with up to pcap_snaplen bytes */ 00037 #define PCAP_TIMEOUT 10 /* Timeout in ms */ 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 // Enabling sending makes no sense when we can't receive... 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 /* get pcap handle */ 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 /* compile this command into a filter program */ 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 /* apply the compiled filter to the packet capture device */ 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 // skip ethernet frames not encapsulating an IP packet. 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 // put the IP packet from wire into data[] array of ExtFrame 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 // signalize new incoming packet to the interface via cMessage 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 // TBD assert that it's somehow not smaller than previous event's time 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 // wait until targetTime or a bit longer, wait in PCAP_TIMEOUT chunks 00273 // in order to keep UI responsiveness by invoking ev.idle() 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 // calculate target time 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; // interrupted by user 00310 if (status == 1) 00311 msg = sim->msgQueue.peekFirst(); // received something 00312 } 00313 else 00314 { 00315 // we're behind -- customized versions of this class may 00316 // alert if we're too much behind, whatever that means 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); //note: no ssize_t on MSVC 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 }