123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- --- a/pcap_wire.cc
- +++ b/pcap_wire.cc
- @@ -18,6 +18,7 @@
-
- #include <sys/time.h>
- #include <sys/select.h>
- +#include <sys/poll.h>
-
- /* 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<PCapWire*>(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<u_char*>(this)));
- + int count = pcap_dispatch(pcap, 1, PCapHandler,
- + reinterpret_cast<u_char*>(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!
|