/* * fping: fast-ping, file-ping, favorite-ping, funky-ping * * Ping a list of target hosts in a round robin fashion. * A better ping overall. * * fping website: http://www.fping.org * * Current maintainer of fping: David Schweikert * Please send suggestions and patches to: david@schweikert.ch * * * Original author: Roland Schemers * IPv6 Support: Jeroen Massar * Improved main loop: David Schweikert * Debian Merge, TOS settings: Tobi Oetiker * Bugfixes, byte order & senseful seq.-numbers: Stephan Fuhrmann (stephan.fuhrmann AT 1und1.de) * * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by Stanford University. The name of the University may not be used * to endorse or promote products derived from this software without * specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * seqmap.c: implementation of a mapping between sequence number and (host, ping_nr) * we can't just use ping_nr*host_count + host_nr, because it can * overflow the 16 bit of the icmp header field. See also: * https://github.com/schweikert/fping/issues/48 */ #include "seqmap.h" #include "options.h" #include "limits.h" #include #include /* description of the data structure used: * * - we assume that no more than SEQMAP_MAXSEQ (65535) pings are sent in * the timeout interval (SEQMAP_TIMEOUT_IN_S) * - we store the values in an array with SEQMAP_MAXSEQ elements * - current sequence number % SEQMAP_MAXSEQ gives the current index * - when entering a value, we check that the current entry is expired */ static SEQMAP_VALUE *seqmap_map = NULL; static unsigned int seqmap_next_id = 0; static SEQMAP_VALUE *seqmap_free_list; #define SEQMAP_TIMEOUT_IN_S 10 #define SEQMAP_UNASSIGNED_HOST_NR UINT_MAX void seqmap_init() { unsigned int i; seqmap_map = calloc(SEQMAP_MAXSEQ, sizeof(SEQMAP_VALUE)); if(seqmap_map == NULL) { perror("malloc error (can't allocate seqmap_map)"); } } unsigned int seqmap_add(unsigned int host_nr, unsigned int ping_count, struct timeval *now) { unsigned int current_id; SEQMAP_VALUE *next_value; if(!seqmap_map) { fprintf(stderr, "fping internal error: seqmap not initialized.\n"); exit(4); } /* check if expired (note that unused seqmap values will have fields set to * 0, so will be seen as expired */ next_value = &seqmap_map[seqmap_next_id]; if(next_value->ping_ts.tv_sec != 0 && (now->tv_sec - next_value->ping_ts.tv_sec) < SEQMAP_TIMEOUT_IN_S) { fprintf(stderr, "fping error: not enough sequence numbers available! (expire_timeout=%d, host_nr=%d, ping_count=%d, seqmap_next_id=%d)\n", SEQMAP_TIMEOUT_IN_S, host_nr, ping_count, seqmap_next_id); exit(4); } /* store the value */ next_value->host_nr = host_nr; next_value->ping_count = ping_count; next_value->ping_ts.tv_sec = now->tv_sec; next_value->ping_ts.tv_usec = now->tv_usec; /* increase next id */ current_id = seqmap_next_id; seqmap_next_id = (seqmap_next_id + 1) % SEQMAP_MAXSEQ; return current_id; } SEQMAP_VALUE *seqmap_fetch(unsigned int id, struct timeval *now) { SEQMAP_VALUE *value; if(id > SEQMAP_MAXSEQ) { return NULL; } value = &seqmap_map[id]; /* verify that value is not expired */ if(now->tv_sec - value->ping_ts.tv_sec >= SEQMAP_TIMEOUT_IN_S) { return NULL; } return value; }