--- ntop/globals-core.h 2003-10-03 18:13:08.000000000 -0500
+++ ntop/globals-core.h 2003-10-16 13:10:26.000000000 -0500
@@ -313,6 +313,7 @@
 extern void resetTrafficCounter(TrafficCounter *ctr);
 extern HostTraffic* getFirstHost(u_int actualDeviceId);
 extern HostTraffic* getNextHost(u_int actualDeviceId, HostTraffic *host);
+extern void setInDeviceMap(HostTraffic *el, u_int device);
 extern HostTraffic* findHostByNumIP(struct in_addr hostIpAddress, u_int actualDeviceId);
 extern HostTraffic* findHostBySerial(HostSerial serial, u_int actualDeviceId);
 extern HostTraffic* findHostByMAC(char* macAddr, u_int actualDeviceId);
--- ntop/globals-defines.h 2003-10-03 18:13:08.000000000 -0500
+++ ntop/globals-defines.h 2003-10-16 12:43:19.000000000 -0500
@@ -427,6 +427,10 @@
  */
 /* #define IDLE_PURGE_DEBUG */
 
+/* INDEVICEMAP_DEBUG logs the mapping of host entry usage across devices
+ */
+#define INDEVICEMAP_DEBUG
+
 /* INITWEB_DEBUG logs the initialization of the web server
  */
 /* #define INITWEB_DEBUG */
--- ntop/globals-structtypes.h 2003-10-15 09:14:39.000000000 -0500
+++ ntop/globals-structtypes.h 2003-10-16 10:52:18.000000000 -0500
@@ -533,6 +533,7 @@
   NonIpProtoTrafficInfo *nonIpProtoTrafficInfos; /* Info about further non IP protos */
 
   fd_set           flags;
+  fd_set           inDevices; /* Which devices reference this host? */
   TrafficCounter   pktSent, pktRcvd, pktSentSession, pktRcvdSession,
     pktDuplicatedAckSent, pktDuplicatedAckRcvd;
   TrafficCounter   lastPktSent, lastPktRcvd;
--- ntop/hash.c 2003-10-15 09:14:39.000000000 -0500
+++ ntop/hash.c 2003-10-16 13:58:58.000000000 -0500
@@ -104,13 +104,13 @@
 
     traceEvent(CONST_TRACE_INFO, "hashHost(%s/%s/%d) = %u",
 	       intoa(*hostIpAddress),
-	       etheraddr_string(ether_addr, buf),
+               ether_addr == NULL ? "(null)" : etheraddr_string(ether_addr, buf),
 	       (*useIPAddressForSearching), idx);
   } else {
     char buf[LEN_ETHERNET_ADDRESS_DISPLAY];
 
     traceEvent(CONST_TRACE_INFO, "hashHost(%s/%d) = %u",
-	       etheraddr_string(ether_addr, buf),
+               ether_addr == NULL ? "(null)" : etheraddr_string(ether_addr, buf),
 	       (*useIPAddressForSearching), idx);
   }
 #endif
@@ -206,11 +206,30 @@
   if(host->magic != CONST_MAGIC_NUMBER) {
     traceEvent(CONST_TRACE_WARNING, "Error: bad magic number (expected=%d/real=%d)",
 	       CONST_MAGIC_NUMBER, host->magic);
+    return;
   }
 
-#ifdef DEBUG
-  traceEvent(CONST_TRACE_INFO, "Entering freeHostInfo(%u)", host->hostTrafficBucket);
+#ifdef IDLE_PURGE_DEBUG
+  traceEvent(CONST_TRACE_NOISY, "IDLE_PURGE: Entering freeHostInfo() 0x%08x %u '%c%c%c%c'",
+             host,
+             host->hostTrafficBucket,
+             FD_ISSET( 0, &host->inDevices) ? '1' : '0',
+             FD_ISSET( 1, &host->inDevices) ? '1' : '0',
+             FD_ISSET( 2, &host->inDevices) ? '1' : '0',
+             FD_ISSET( 3, &host->inDevices) ? '1' : '0');
 #endif
+
+  /* Clear the flag... */
+  FD_CLR(actualDeviceId, &(host->inDevices));
+
+  /* Valid for free (we were the ONLY device?) ... */
+  for (i=0; i<MAX_NUM_DEVICES; i++) {
+    if(FD_ISSET(i, &(host->inDevices))) break;
+  }
+  if(i != MAX_NUM_DEVICES) {
+    traceEvent(CONST_TRACE_INFO, "host %u in use on another device, not actually freeing it", host->hostTrafficBucket);
+    return;
+  }
 
   /* ********** */
 
@@ -236,6 +236,11 @@
   traceEvent(CONST_TRACE_INFO, "HOST_FREE_DEBUG: Deleting a hash_hostTraffic entry [%s/%s/%s][idx=%d]",
              host->ethAddressString, host->hostNumIpAddress, host->hostSymIpAddress, host->hostTrafficBucket);
 #endif
+
+  /* BEGIN the free of this host entry.
+   *   First, we decrement magic so we don't think this is valid anymore
+   */
+  host->magic--;
 
   /* Make sure this host is not part of the ipTrafficMatrixHosts list */
   if((myGlobals.device[actualDeviceId].ipTrafficMatrix != NULL)
@@ -330,6 +351,8 @@
   if(host->icmpInfo != NULL) free(host->icmpInfo);
   if(host->trafficDistribution != NULL) free(host->trafficDistribution);
 
+  host->magic = 0; /* Clear magic so we don't think this is valid */
+
   /* ********** */
   /*
     #ifdef HASH_DEBUG
@@ -438,6 +461,10 @@
   struct timeval hiresTimeStart, hiresTimeEnd;
   HostTraffic *el, *prev, *next;
 
+#ifdef IDLE_PURGE_DEBUG
+  traceEvent(CONST_TRACE_NOISY, "IDLE_PURGE(%d): purgeIdleHosts() started", actDevice);
+#endif
+
   if(myGlobals.rFileName != NULL) return;
 
   if(firstRun) {
@@ -457,6 +484,9 @@
   memset(theFlaggedHosts, 0, maxHosts*sizeof(HostTraffic*));
 
   purgeTime = startTime-30 /*PARM_HOST_PURGE_MINIMUM_IDLE <<== */; /* Time used to decide whether a host need to be purged */
+#ifdef IDLE_PURGE_DEBUG
+  traceEvent(CONST_TRACE_NOISY, "IDLE_PURGE(%d): Purge time is %d", actDevice, purgeTime);
+#endif
 
 #ifdef CFG_MULTITHREADED
   accessMutex(&myGlobals.hostsHashMutex, "purgeIdleHosts");
@@ -471,9 +501,16 @@
 #endif
 
 #ifdef HASH_DEBUG
+ #ifdef IDLE_PURGE_DEBUG
+  traceEvent(CONST_TRACE_NOISY, "IDLE_PURGE(%d): Running hashSanityCheck()". actDevice);
+ #endif
   hashSanityCheck();
 #endif
 
+#ifdef IDLE_PURGE_DEBUG
+  traceEvent(CONST_TRACE_NOISY, "IDLE_PURGE(%d): Scanning for idle hosts", actDevice);
+#endif
+
   for(idx=0; idx<myGlobals.device[actDevice].actualHashSize; idx++) {
 #ifdef CFG_MULTITHREADED
     accessMutex(&myGlobals.hostsHashMutex, "scanIdleLoop");
@@ -483,6 +520,15 @@
       prev = NULL;
 
       while(el) {
+
+#ifdef IDLE_PURGE_DEBUG
+       traceEvent(CONST_TRACE_NOISY, "IDLE_PURGE(%d): Testing 0x%08x [%s/%s]",
+                  actDevice,
+                  el,
+                  el->hostNumIpAddress,
+                  el->hostSymIpAddress);
+#endif
+
 	if((el->refCount == 0) 
 	   && (el->lastSeen < purgeTime) 
 	   && (!broadcastHost(el))
@@ -491,6 +537,9 @@
 	       || (!subnetPseudoLocalHost(el)))      /* Purge remote hosts only */
 	   ) {
 	  /* Host selected for deletion */
+#ifdef IDLE_PURGE_DEBUG
+         traceEvent(CONST_TRACE_NOISY, "IDLE_PURGE(%d.%03d): 0x%08x is IDLE, last seen %d, schedule for purge", actDevice, numHosts, el, el->lastSeen);
+#endif
 	  theFlaggedHosts[numHosts++] = el;
 	  next = el->next;
 
@@ -519,15 +568,23 @@
   hashSanityCheck();
 #endif
 
-  traceEvent(CONST_TRACE_NOISY, "IDLE_PURGE: FINISHED selection, %d [out of %d] hosts selected",
-	     numHosts, scannedHosts);
+  traceEvent(CONST_TRACE_NOISY, "IDLE_PURGE(%d): Scanning for idle hosts complete, %d [out of %d] selected",
+	     actDevice, numHosts, scannedHosts);
+
+#ifdef IDLE_PURGE_DEBUG
+  traceEvent(CONST_TRACE_NOISY, "IDLE_PURGE(%d): Freeing selected hosts", actDevice);
+#endif
 
   /* Now free the entries */
   for(idx=0; idx<numHosts; idx++) {
 #ifdef IDLE_PURGE_DEBUG
-    traceEvent(CONST_TRACE_INFO, "IDLE_PURGE_DEBUG: Purging host %d [last seen=%d]... %s",
-	       idx, theFlaggedHosts[idx]->lastSeen, theFlaggedHosts[idx]->hostSymIpAddress);
 #endif
+    if(theFlaggedHosts[idx] != NULL) 
+      traceEvent(CONST_TRACE_INFO, "IDLE_PURGE(%d.%03d): Freeing 0x%08x '%s'/'%s'",
+  	       actDevice, idx,
+               theFlaggedHosts[idx], 
+               theFlaggedHosts[idx]->hostNumIpAddress,
+               theFlaggedHosts[idx]->hostSymIpAddress);
 
     freeHostInfo(theFlaggedHosts[idx], actDevice);
     numFreedBuckets++;
@@ -549,14 +606,14 @@
   hiresDeltaTime=timeval_subtract(hiresTimeEnd, hiresTimeStart);
 
   if(numFreedBuckets > 0)
-    traceEvent(CONST_TRACE_NOISY, "IDLE_PURGE: Device %d [%s]: %d hosts deleted, elapsed time is %.6f seconds (%.6f per host)",
+    traceEvent(CONST_TRACE_NOISY, "IDLE_PURGE(%d) '%s': %d hosts deleted, elapsed time is %.6f seconds (%.6f per host)",
 	       actDevice,
 	       myGlobals.device[actDevice].name,
 	       numFreedBuckets,
 	       hiresDeltaTime,
 	       hiresDeltaTime / numFreedBuckets);
   else
-    traceEvent(CONST_TRACE_NOISY, "IDLE_PURGE: Device %d: no hosts deleted", actDevice);
+    traceEvent(CONST_TRACE_NOISY, "IDLE_PURGE(%d) '%s': No hosts deleted", actDevice, myGlobals.device[actDevice].name);
 }
 
 /* **************************************************** */
@@ -603,8 +660,10 @@
 		 &useIPAddressForSearching,
 		 &el, actualDeviceId);
 
-  if(el != NULL)
+  if(el != NULL) {
+    setInDeviceMap(el, actualDeviceId);
     return(el); /* Found */
+  }
   else if(idx == FLAG_NO_PEER)
     return(NULL);
   else
@@ -748,6 +807,7 @@
     el->magic = CONST_MAGIC_NUMBER;
     el->hostTrafficBucket = idx; /* Set the bucket index */
     el->originalHostTrafficBucket = idx; /* Set the bucket index */
+    setInDeviceMap(el, actualDeviceId);
 
     /* traceEvent(CONST_TRACE_INFO, "new entry added at bucket %d", idx); */
 
@@ -887,6 +947,7 @@
 
 
   if(el != NULL) {
+    setInDeviceMap(el, actualDeviceId);
     el->lastSeen = myGlobals.actTime;
 
     if(setSpoofingFlag)
--- ntop/util.c 2003-10-15 09:14:40.000000000 -0500
+++ ntop/util.c 2003-10-16 13:21:55.000000000 -0500
@@ -98,7 +98,88 @@
 
 /* ************************************ */
 
+    /* Routine for setting inDevice map */
+
+/*
+ * This is a hack - for cleanlyness it should be dependent upon MAX_NUM_DEVICES and done
+ * in a function, but this is used for debugging only and that would be slow.
+ * Really, SHOW_DEVICEUSEMAP s/b in globals-core.h, but keeping hacks together is a good idea.
+
+ * First, let's define it 'right' the full 32 devices:
+
+#define CONST_DEVICEUSEMAP_FORMAT "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c"
+
+#define SHOW_DEVICEUSEMAP(a)      FD_ISSET( 0, &a) ? '1' : '0', \
+                                  FD_ISSET( 1, &a) ? '1' : '0', \
+                                  FD_ISSET( 2, &a) ? '1' : '0', \
+                                  FD_ISSET( 3, &a) ? '1' : '0', \
+                                  FD_ISSET( 4, &a) ? '1' : '0', \
+                                  FD_ISSET( 5, &a) ? '1' : '0', \
+                                  FD_ISSET( 6, &a) ? '1' : '0', \
+                                  FD_ISSET( 7, &a) ? '1' : '0', \
+                                  FD_ISSET( 8, &a) ? '1' : '0', \
+                                  FD_ISSET( 9, &a) ? '1' : '0', \
+                                  FD_ISSET(10, &a) ? '1' : '0', \
+                                  FD_ISSET(11, &a) ? '1' : '0', \
+                                  FD_ISSET(12, &a) ? '1' : '0', \
+                                  FD_ISSET(13, &a) ? '1' : '0', \
+                                  FD_ISSET(14, &a) ? '1' : '0', \
+                                  FD_ISSET(15, &a) ? '1' : '0', \
+                                  FD_ISSET(16, &a) ? '1' : '0', \
+                                  FD_ISSET(17, &a) ? '1' : '0', \
+                                  FD_ISSET(18, &a) ? '1' : '0', \
+                                  FD_ISSET(19, &a) ? '1' : '0', \
+                                  FD_ISSET(20, &a) ? '1' : '0', \
+                                  FD_ISSET(21, &a) ? '1' : '0', \
+                                  FD_ISSET(22, &a) ? '1' : '0', \
+                                  FD_ISSET(23, &a) ? '1' : '0', \
+                                  FD_ISSET(24, &a) ? '1' : '0', \
+                                  FD_ISSET(25, &a) ? '1' : '0', \
+                                  FD_ISSET(26, &a) ? '1' : '0', \
+                                  FD_ISSET(27, &a) ? '1' : '0', \
+                                  FD_ISSET(28, &a) ? '1' : '0', \
+                                  FD_ISSET(29, &a) ? '1' : '0', \
+                                  FD_ISSET(30, &a) ? '1' : '0', \
+                                  FD_ISSET(31, &a) ? '1' : '0', \
+                                  FD_ISSET(32, &a) ? '1' : '0'
+
+ * But, that's way more than we care to see for normal debugging, so let's instead
+ * give a workable definition:
+ */
+
+#define CONST_DEVICEUSEMAP_FORMAT "%c%c%c%c"
+
+#define SHOW_DEVICEUSEMAP(a)      FD_ISSET( 0, &a) ? '1' : '0', \
+                                  FD_ISSET( 1, &a) ? '1' : '0', \
+                                  FD_ISSET( 2, &a) ? '1' : '0', \
+                                  FD_ISSET( 3, &a) ? '1' : '0'
+
+void setInDeviceMap(HostTraffic *el, u_int device) {
+
+#ifdef INDEVICEMAP_DEBUG
+  fd_set oldInDevices;
+
+  memcpy(&oldInDevices, &el->inDevices, sizeof(fd_set));
+#endif
+
+  FD_SET(device, &el->inDevices);
+
+#ifdef INDEVICEMAP_DEBUG
+  if(memcmp((void*)&el->inDevices, (void*)&oldInDevices, sizeof(fd_set)) != 0)
+    traceEvent(CONST_TRACE_NOISY,
+               "INDEVICEMAP_DEBUG: %08x: " CONST_DEVICEUSEMAP_FORMAT " -> " CONST_DEVICEUSEMAP_FORMAT " '%s'/'%s'",
+               el,
+               SHOW_DEVICEUSEMAP(oldInDevices) ,
+               SHOW_DEVICEUSEMAP(el->inDevices),
+               el->ethAddressString, el->hostNumIpAddress);
+#endif
+
+}
+
+/* ************************************ */
+
 HostTraffic* findHostByNumIP(struct in_addr hostIpAddress, u_int actualDeviceId) {
+
   HostTraffic *el;
   short dummyShort=1;
   u_int idx = hashHost(&hostIpAddress, NULL, &dummyShort, &el, actualDeviceId);
@@ -112,6 +195,7 @@
 
   for(; el != NULL; el = el->next) {
     if((el->hostNumIpAddress != NULL) && (el->hostIpAddress.s_addr == hostIpAddress.s_addr))
+      setInDeviceMap(el, actualDeviceId);
       return(el);
   }
 
@@ -127,6 +211,7 @@
 
       for(; el != NULL; el = el->next) {
 	if((el->hostNumIpAddress != NULL) && (el->hostIpAddress.s_addr == hostIpAddress.s_addr))
+          setInDeviceMap(el, actualDeviceId);
 	  return(el);
       }
     }
@@ -170,8 +256,10 @@
     el = myGlobals.device[actualDeviceId].hash_hostTraffic[idx];
 
   for(; el != NULL; el = el->next) {
-    if((el->ethAddress[0] != '\0') && (!strncmp(el->ethAddress, macAddr, LEN_ETHERNET_ADDRESS)))
+    if((el->ethAddress[0] != '\0') && (!strncmp(el->ethAddress, macAddr, LEN_ETHERNET_ADDRESS))) {
+      setInDeviceMap(el, actualDeviceId);
       return(el);
+    }
   }
 
   return(NULL);
@@ -1746,6 +1834,7 @@
 
 void resetHostsVariables(HostTraffic* el) {
   FD_ZERO(&(el->flags));
+  FD_ZERO(&(el->inDevices));
 
   el->totContactedSentPeers = el->totContactedRcvdPeers = 0;
   resetUsageCounter(&el->contactedSentPeers);
