typedef struct host_entry
 {
-     struct host_entry    *prev,*next;        /* doubly linked list */
+     struct host_entry    *prev,*next;        /* double linked list */
+        struct host_entry    *sq_prev;           /* double linked list for the send-queue */
+        struct host_entry    *sq_next;           /* double linked list for the send-queue */
+        struct timeval       sq_send_time;       /* can't send before this time */
+
      int                  i;                  /* index into array */
      char                 *name;              /* name as given by user */
      char                 *host;              /* text description of host */
 HOST_ENTRY **table = NULL;     /* array of pointers to items in the list */
 HOST_ENTRY *cursor;
 
+/* send queue (sq): hosts in this list are ready for a new ping to be sent */
+/* the inter-ping interval must be respected when going through this list */
+/* and sending the pings. However, the per-host interval (-p), doesn't need */
+/* to be considered (the host is not here, if that interval didn't pass */
+HOST_ENTRY *sq_first;
+HOST_ENTRY *sq_last;
+
 char *prog;
 int ident;                                     /* our pid */
 int s;                                         /* socket */
 void u_sleep();
 int recvfrom_wto ();
 void remove_job();
-void send_ping();
+int send_ping();
 void usage();
 int wait_for_reply();
 long timeval_diff();
 void u_sleep( int u_sec );
 int recvfrom_wto ( int s, char *buf, int len, FPING_SOCKADDR *saddr, int timo );
 void remove_job( HOST_ENTRY *h );
-void send_ping( int s, HOST_ENTRY *h );
+int send_ping( int s, HOST_ENTRY *h );
 long timeval_diff( struct timeval *a, struct timeval *b );
+void timeval_add(struct timeval *a, long t_10u);
 void usage( void );
 int wait_for_reply( u_int );
 void print_per_system_stats( void );
 void finish();
 int handle_random_icmp( FPING_ICMPHDR *p, int psize, FPING_SOCKADDR *addr );
 char *sprint_tm( int t );
+void sq_enqueue(HOST_ENTRY  *h);
+HOST_ENTRY *sq_dequeue();
+void sq_remove(HOST_ENTRY *h);
 
 #endif /* _NO_PROTO */
 
        int opton = 1;
 #endif
        u_int lt, ht;
-       int advance;
        struct protoent *proto;
        char *buf;
        uid_t uid;
 #endif /* DEBUG || _DEBUG */
 
        cursor = rrlist;
-       advance = 0;
 
        /* main loop */
 
        while( num_jobs )
        {
+               /* send any pings that need sending */
+               if(sq_first) {
+#if defined( DEBUG ) || defined( _DEBUG )
+                       if( trace_flag ) {
+                               long st = timeval_diff(&sq_first->sq_send_time, ¤t_time);
+                               fprintf(stderr, "next ping in %d ms (%s)\n", st / 100, sq_first->host);
+                       }
+#endif
+
+                       if(sq_first->sq_send_time.tv_sec < current_time.tv_sec ||
+                               (sq_first->sq_send_time.tv_sec == current_time.tv_sec &&
+                                sq_first->sq_send_time.tv_usec < current_time.tv_usec))
+                       {
+                               lt = timeval_diff( ¤t_time, &last_send_time );
+                               if(lt > interval) {
+                                       HOST_ENTRY *h;
+                                       h = sq_dequeue();
+
+                                       if(send_ping(s, h)) {
+                                           /* schedule retry */
+                                           if(!loop_flag && !count_flag && h->waiting < retry + 1) {
+                                                   h->sq_send_time.tv_sec = current_time.tv_sec;
+                                                   h->sq_send_time.tv_usec = current_time.tv_usec;
+                                                   timeval_add(&h->sq_send_time, h->timeout);
+                                                   sq_enqueue(h);
+
+                                                   if(backoff_flag) {
+                                                           h->timeout *= backoff;
+                                                   }
+                                           }
+                                           /* schedule next ping */
+                                           else if(loop_flag ||
+                                             (count_flag && h->num_sent < count))
+                                           {
+                                                   h->sq_send_time.tv_sec = current_time.tv_sec;
+                                                   h->sq_send_time.tv_usec = current_time.tv_usec;
+                                                   timeval_add(&h->sq_send_time, perhost_interval);
+                                                   sq_enqueue(h);
+                                           }
+                                       }
+                               }
+                       }
+               }
+
+               /* receive replies */
                if( num_pingsent ) {
                        if(wait_for_reply(interval)) {
                                while(wait_for_reply(0)); /* process other replies in the queue */
                }
 
                gettimeofday( ¤t_time, &tz );
-               lt = timeval_diff( ¤t_time, &last_send_time );
                ht = timeval_diff( ¤t_time, &cursor->last_send_time );
-                       
+
+               /* print report */
                if( report_interval && ( loop_flag || count_flag ) &&
                        ( timeval_diff ( ¤t_time, &last_report_time )     > report_interval ) )
                {
                if( trace_flag )
                {
                        printf(
-                               "main loop:\n  [%s, wait/run/sent/recv/timeout = %u/%u/%u/%u/%u], jobs/lt/ht = %u/%u/%u\n",
+                               "main loop:\n  [%s, wait/run/sent/recv/timeout = %u/%u/%u/%u/%u], jobs/ht = %u/%u\n",
                                cursor->host, cursor->waiting, cursor->running, cursor->num_sent, 
-                               cursor->num_recv, cursor->timeout, num_jobs, lt, ht );
-
-               }
-#endif
+                               cursor->num_recv, cursor->timeout, num_jobs, ht );
 
-               /* if it's OK to send while counting or looping or starting */
-               if( ( lt > interval ) && ( ht > perhost_interval ) )
-               {
-                       /* send if starting or looping */
-                       if( ( cursor->num_sent == 0 ) || loop_flag )
-                       {
-                               send_ping( s, cursor );
-                       }
-               
-                       /* send if counting and count not exceeded */
-                       if( count_flag )
-                       {
-                               if( cursor->num_sent < count )
-                               {
-                                       send_ping( s, cursor );
-                               }
-                       }
                }
-
-               /* is-it-alive mode, and timeout exceeded while waiting for a reply */
-               /*   and we haven't exceeded our retries                            */
-               if(!count_flag && !loop_flag) {
-                       if( ( lt > interval ) && !cursor->num_recv &&
-                               ( ht > cursor->timeout ) && ( cursor->waiting < retry + 1 ) )
-                       {
-#if defined( DEBUG ) || defined( _DEBUG )
-                               if( trace_flag ) 
-                                       printf( "main loop: timeout for %s\n", cursor->host );
 #endif
-                               num_timeout++;
-
-                               /* try again */
-                               if( backoff_flag )
-                                       cursor->timeout *= backoff;
 
-                               send_ping( s, cursor );
-                       }
-               }
-
-               /* didn't send, can we remove? */
-
-#if defined( DEBUG ) || defined( _DEBUG )
-               if( trace_flag )
-                       printf( "main loop: didn't send to %s\n", cursor->host );
-#endif /* DEBUG || _DEBUG */
-    
-               /* remove all terminated jobs */
+               /* check if timeout reached */
                if(count_flag)
                {
-                       while( cursor && cursor->num_sent >= count &&
-                              (cursor->num_recv >= count || ht > cursor->timeout) )
+                       while(cursor &&
+                                 ht > cursor->timeout &&
+                             cursor->num_sent >= count)
                        {
-                               fprintf(stderr, "removed: %s\n", cursor->host);
+                               num_timeout++;
                                remove_job(cursor);
                                if(cursor) {
                                        ht = timeval_diff( ¤t_time, &cursor->last_send_time );
                }
                else if(!loop_flag)
                {
-                       /* normal mode, and we got one */
-                       if( cursor->num_recv )
+                       while(cursor &&
+                                 ht > cursor->timeout &&
+                                 cursor->waiting >= retry + 1)
                        {
+                               num_timeout++;
                                remove_job( cursor );
-                       }
-                       else
-                       {
-                               /* normal mode, and timeout exceeded while waiting for a reply */
-                               /* and we've run out of retries, so node is unreachable */
-                               while( cursor && ( ht > cursor->timeout ) && ( cursor->waiting >= retry + 1 ) )
-                               {
-                                       num_timeout++;
-                                       remove_job( cursor );
-                                       if(cursor) {
-                                               ht = timeval_diff( ¤t_time, &cursor->last_send_time );
-                                       }
+                               if(cursor) {
+                                       ht = timeval_diff( ¤t_time, &cursor->last_send_time );
                                }
                        }
                }
-               
+
+               /* we use the cursor to go through all running jobs and check for timeouts */
                if(cursor) {
                        cursor = cursor->next;
                }
 ************************************************************/
 
 #ifdef _NO_PROTO
-void send_ping( s, h )
+int send_ping( s, h )
 int s; HOST_ENTRY *h;
 #else
-void send_ping( int s, HOST_ENTRY *h )
+int send_ping( int s, HOST_ENTRY *h )
 #endif /* _NO_PROTO */
 {
        char *buffer;
                
                num_unreachable++;
                remove_job( h ); 
+               free( buffer );
+               return(0);
+       }
 
-       }/* IF */
-       else
-       {
-               /* mark this trial as outstanding */
-               if( !loop_flag )
-                       h->resp_times[h->num_sent] = RESP_WAITING;
+       /* mark this trial as outstanding */
+       if( !loop_flag )
+               h->resp_times[h->num_sent] = RESP_WAITING;
 
 #if defined( DEBUG ) || defined( _DEBUG )
-               if( sent_times_flag )
-                       h->sent_times[h->num_sent] = timeval_diff( &h->last_send_time, &start_time );
+       if( sent_times_flag )
+               h->sent_times[h->num_sent] = timeval_diff( &h->last_send_time, &start_time );
 #endif /* DEBUG || _DEBUG */
 
-               h->num_sent++;
-               h->num_sent_i++;
-               h->waiting++;
-               num_pingsent++;
-               last_send_time = h->last_send_time;
-
-       }/* ELSE */
+       h->num_sent++;
+       h->num_sent_i++;
+       h->waiting++;
+       num_pingsent++;
+       last_send_time = h->last_send_time;
        
        free( buffer );
-
-} /* send_ping() */
+       return(1);
+}
 
 
 /************************************************************
                printf( "\n" );
        
        }/* IF */
+
+       /* remove this job, if we are done */
+       if((count_flag && h->num_recv >= count) ||
+          (!loop_flag && !count_flag && h->num_recv))
+       {
+               remove_job(h);
+       }
        
        fflush( stdout );
        return num_jobs;
        
        }/* ELSE */
 
+       /* send queue */
+       p->sq_send_time.tv_sec  = 0;
+       p->sq_send_time.tv_usec = 0;
+       sq_enqueue(p);
+
        num_hosts++;
 
 } /* add_addr() */
                if( h==cursor )
                        cursor = h->next;
 
-       }/* IF */
+       }
        else
        {
                cursor = NULL;
                rrlist = NULL;
        
-       }/* ELSE */
+       }
+
+       sq_remove(h);
 
 } /* remove_job() */
 
 
 } /* timeval_diff() */
 
+/************************************************************
+
+  Function: timeval_add
+
+*************************************************************/
+void timeval_add(struct timeval *a, long t_10u)
+{
+       t_10u *= 10;
+       a->tv_sec += (t_10u + a->tv_usec) / 1000000;
+       a->tv_usec = (t_10u + a->tv_usec) % 1000000;
+}
+
 /************************************************************
 
   Function: sprint_tm
 
 } /* recvfrom_wto() */
 
+/************************************************************
+
+  Function: sq_enqueue
+
+  Enqueue a host that needs to be pinged, but not before the time
+  written in h->sq_send_time.
+
+  The queue is sorted, so that sq_first always points to the host
+  that should be pinged first.
+
+*************************************************************/
+void sq_enqueue(HOST_ENTRY  *h)
+{
+       HOST_ENTRY *i;
+       HOST_ENTRY *i_next;
+
+       h->sq_next = NULL;
+
+    /* Empty list */
+       if(sq_first == NULL) {
+               h->sq_prev = NULL;
+               sq_first = h;
+           sq_last = h;
+               return;
+       }
+
+
+       /* Insert on head? */
+       if(h->sq_send_time.tv_sec < sq_first->sq_send_time.tv_sec ||
+       (h->sq_send_time.tv_sec == sq_first->sq_send_time.tv_sec &&
+           h->sq_send_time.tv_usec <= sq_first->sq_send_time.tv_usec))
+       {
+               h->sq_prev = NULL;
+               h->sq_next = sq_first;
+               sq_first = h;
+               return;
+       }
+
+       /* Find insertion point */
+       i = sq_first;
+       while(1) {
+               i_next = i->sq_next;
+           if(i_next == NULL || 
+                  h->sq_send_time.tv_sec < i_next->sq_send_time.tv_sec ||
+           (h->sq_send_time.tv_sec == i_next->sq_send_time.tv_sec &&
+               h->sq_send_time.tv_usec < i_next->sq_send_time.tv_usec))
+               {
+                       h->sq_prev = i;
+                       h->sq_next = i_next;
+                       i->sq_next = h;
+                       if(i_next != NULL) {
+                               i_next->sq_prev = h;
+                       }
+                       else {
+                               sq_last = h;
+                       }
+                       return;
+               }
+               i = i_next;
+       }
+}
+
+/************************************************************
+
+  Function: sq_dequeue
+
+*************************************************************/
+HOST_ENTRY *sq_dequeue()
+{
+       HOST_ENTRY *dequeued;
+
+       if(sq_first == NULL) {
+               return NULL;
+       }
+       dequeued = sq_first;
+       sq_remove(dequeued);
+
+       return dequeued;
+}
+
+/************************************************************
+
+  Function: sq_remove
+
+*************************************************************/
+void sq_remove(HOST_ENTRY *h)
+{
+       if(sq_first == h) {
+               sq_first = h->sq_next;
+       }
+       if(sq_last == h) {
+               sq_last = h->sq_prev;
+       }
+       if(h->sq_prev) {
+               h->sq_prev->sq_next = h->sq_next;
+       }
+       if(h->sq_next) {
+               h->sq_next->sq_prev = h->sq_prev;
+       }
+}
+
 
 /************************************************************