154 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			154 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
--- 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!
 |