--- a/pcap_wire.cc +++ b/pcap_wire.cc @@ -18,6 +18,7 @@ #include #include +#include /* Ways of finding the hardware MAC on this machine... */ /* This is the Linux only fallback. */ @@ -130,20 +131,18 @@ namespace NSLU2Upgrade { * non-static (real) Handler. */ void Handler(const struct pcap_pkthdr *packet_header, const u_char *packet) { - /* This should only be called once... */ - if (captured) - throw std::logic_error("Handler called twice"); - /* Verify the protocol and originating address of the packet, then * return this packet. */ + if (captured) + return; if (packet_header->caplen > 14 && (broadcast || std::memcmp(packet+6, header, 6) == 0)) { - /* Record the address and copy the data */ - std::memcpy(source, packet+6, 6); const size_t len(packet_header->caplen - 14); if (len > captureSize) - throw std::logic_error("packet too long"); + return; + /* Record the address and copy the data */ + std::memcpy(source, packet+6, 6); std::memcpy(captureBuffer, packet+14, len); captureSize = len; captured = true; @@ -156,7 +155,7 @@ namespace NSLU2Upgrade { * packet and the buffer should be big enough. */ if (packet_header->caplen < packet_header->len) - throw std::logic_error("truncated packet"); + return; /*IGNORE EVIL: known evil cast */ reinterpret_cast(user)->Handler(packet_header, packet); @@ -173,56 +172,24 @@ namespace NSLU2Upgrade { virtual void Receive(void *buffer, size_t &size, unsigned long timeout) { /* Now try to read packets until the timeout has been consumed. */ - struct timeval tvStart; - if (timeout > 0 && gettimeofday(&tvStart, 0) != 0) - throw OSError(errno, "gettimeofday(base)"); + int time_count; captureBuffer = buffer; captureSize = size; captured = false; + time_count = timeout / 2000; /* 2 ms intervals */ + time_count++; do { /*IGNORE EVIL: known evil cast */ - int count(pcap_dispatch(pcap, 1, PCapHandler, - reinterpret_cast(this))); + int count = pcap_dispatch(pcap, 1, PCapHandler, + reinterpret_cast(this)); - if (count > 0) { - /* Were any packets handled? */ - if (captured) { - size = captureSize; - return; - } - /* else try again. */ - } else if (count == 0) { - /* Nothing to handle - do the timeout, do this - * by waiting a bit then trying again, the trick - * to this is to work out how long to wait each - * time, for the moment a 10ms delay is used. - */ - if (timeout == 0) - break; - - struct timeval tvNow; - if (gettimeofday(&tvNow, 0) != 0) - throw OSError(errno, "gettimeofday(now)"); - - unsigned long t(tvNow.tv_sec - tvStart.tv_sec); - t *= 1000000; - t += tvNow.tv_usec; - t -= tvStart.tv_usec; - if (t > timeout) - break; - - tvNow.tv_sec = 0; - tvNow.tv_usec = timeout-t; - if (tvNow.tv_usec > 10000) - tvNow.tv_usec = 10000; - - /* Delay, may be interrupted - this should - * be portable to the BSDs (since the - * technique originates in BSD.) - */ - (void)select(0, 0, 0, 0, &tvNow); - } else { + /* Were any packets handled? */ + if (captured) { + size = captureSize; + return; + } + if (count < 0) { /* Error condition. */ if (count == -1) { if (errno != EINTR) @@ -232,7 +199,8 @@ namespace NSLU2Upgrade { } else throw std::logic_error("pcap unexpected result"); } - } while (timeout != 0); + time_count--; + } while (time_count > 0); /* Here on timeout. */ size = 0; @@ -288,6 +256,7 @@ NSLU2Upgrade::Wire *NSLU2Upgrade::Wire:: const unsigned char *mac, const unsigned char *address, int uid) { /* This is used to store the error passed to throw. */ static char PCapErrbuf[PCAP_ERRBUF_SIZE]; + struct bpf_program fp; /* Check the device name. If not given use 'DEFAULT_ETHERNET_IF'. */ if (device == NULL) @@ -301,20 +270,12 @@ NSLU2Upgrade::Wire *NSLU2Upgrade::Wire:: * for other ethernet MACs. (Because the code above does not * check that the destination matches the device in use). */ - pcap = pcap_open_live(device, 1540, false/*promiscuous*/, 1/*ms*/, PCapErrbuf); + pcap = pcap_open_live(device, 1540, false/*promiscuous*/, 2/*ms*/, PCapErrbuf); if (pcap == NULL) throw WireError(errno, PCapErrbuf); } - /* Always do a non-blocking read, because the 'timeout' above - * doesn't work on Linux (return is immediate) and on OSX (and - * maybe other BSDs) the interface tends to hang waiting for - * the timeout to expire even after receiving a single packet. - */ - if (pcap_setnonblock(pcap, true, PCapErrbuf)) - throw WireError(errno, PCapErrbuf); - try { /* The MAC of the transmitting device is needed - without * this the return packet won't go to the right place!