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;
+ }
+}
+
/************************************************************