diff -up net-tools-2.0/netstat.c.dup-tcp net-tools-2.0/netstat.c --- net-tools-2.0/netstat.c.dup-tcp 2012-10-04 11:32:01.437729086 +0200 +++ net-tools-2.0/netstat.c 2012-10-04 11:32:01.441729032 +0200 @@ -502,6 +502,121 @@ static void prg_cache_load(void) " will not be shown, you would have to be root to see it all.)\n")); } +#define TCP_HASH_SIZE 1009 + +static struct tcp_node { + struct tcp_node *next; + char *socket_pair; +} *tcp_node_hash[TCP_HASH_SIZE]; + +static unsigned int tcp_node_compute_string_hash(const char *p) +{ + unsigned int h = *p; + + if (h) + for (p += 1; *p != '\0'; p++) + h = (h << 5) - h + *p; + + return h; +} + +#define TCP_NODE_HASH_STRING(x) \ + (tcp_node_compute_string_hash(x) % TCP_HASH_SIZE) + +static void tcp_node_hash_clear(void) +{ + int i; + struct tcp_node *next_node; + struct tcp_node *tmp_node; + for (i=0; i < TCP_HASH_SIZE; i++) { + if (tcp_node_hash[i]) { + /* free the children of this hash bucket */ + next_node = tcp_node_hash[i]->next; + while (next_node) { + tmp_node = next_node; + next_node = next_node->next; + free(tmp_node->socket_pair); + free(tmp_node); + } + + /* free the bucket itself */ + free(tcp_node_hash[i]->socket_pair); + free(tcp_node_hash[i]); + tcp_node_hash[i] = NULL; + } + } +} + +/* This function takes a socket pair string. If it already exists in + the hash it returns -1, otherwise it returns 0. */ + +static int tcp_node_hash_check_and_append(const char *local_addr, + int local_port, + const char *rem_addr, + int rem_port) +{ + unsigned int hash_val; + struct tcp_node *tmp_node; + int tmp_string_len; + char *tmp_string;; + + /* Size of the string is the size of the two lengths of the address + strings plus enough sizes for the colons and the ports. */ + tmp_string_len = strlen(local_addr) + strlen(rem_addr) + 32; + tmp_string = malloc(tmp_string_len); + if (!tmp_string) + return 0; + + if (snprintf(tmp_string, tmp_string_len - 1, "%s:%d:%s:%d", + local_addr, local_port, rem_addr, rem_port) < 0) { + free(tmp_string); + return 0; + } + + hash_val = TCP_NODE_HASH_STRING(tmp_string); + + /* See if we have to allocate this node */ + if (!tcp_node_hash[hash_val]) { + tcp_node_hash[hash_val] = malloc(sizeof(struct tcp_node)); + if (!tcp_node_hash[hash_val]) { + free(tmp_string); + return 0; + } + + memset(tcp_node_hash[hash_val], 0, sizeof(struct tcp_node)); + + /* Stuff this new value into the hash bucket and return early */ + tcp_node_hash[hash_val]->socket_pair = tmp_string; + return 0; + } + + /* Try to find the value in the hash bucket. */ + tmp_node = tcp_node_hash[hash_val]; + while (tmp_node) { + if (!strcmp(tmp_node->socket_pair, tmp_string)) { + free(tmp_string); + return -1; + } + tmp_node = tmp_node->next; + } + + /* If we got this far it means that it isn't in the hash bucket. + Add it to the front since it's faster that way. */ + tmp_node = tcp_node_hash[hash_val]; + + tcp_node_hash[hash_val] = malloc(sizeof(struct tcp_node)); + if (!tcp_node_hash[hash_val]) { + free(tmp_string); + tcp_node_hash[hash_val] = tmp_node; + return 0; + } + + tcp_node_hash[hash_val]->socket_pair = tmp_string; + tcp_node_hash[hash_val]->next = tmp_node; + + return 0; +} + #if HAVE_AFNETROM static const char *netrom_state[] = { @@ -1018,6 +1133,12 @@ static void tcp_do_one(int lnr, const ch return; } + /* make sure that we haven't seen this socket pair before */ + if (tcp_node_hash_check_and_append(local_addr, local_port, rem_addr, rem_port) < 0) { + /* fprintf(stderr, _("warning, got duplicate tcp line.\n")); */ + return; + } + addr_do_one(local_addr, sizeof(local_addr), 22, ap, &localaddr, local_port, "tcp"); addr_do_one(rem_addr, sizeof(rem_addr), 22, ap, &remaddr, rem_port, "tcp"); @@ -2355,6 +2476,7 @@ int main break; wait_continous(reptimer); prg_cache_clear(); + tcp_node_hash_clear(); } return (i); }