diff --git a/daemon/aux.h b/daemon/aux.h index fbfa21893..4fe3c1bbe 100644 --- a/daemon/aux.h +++ b/daemon/aux.h @@ -57,6 +57,15 @@ static inline void uuid_str_generate(char *s) { uuid_unparse(uuid, s); } +static inline void swap_ptrs(void *a, void *b) { + void *t, **aa, **bb; + aa = a; + bb = b; + t = *aa; + *aa = *bb; + *bb = t; +} + #endif diff --git a/daemon/control_udp.c b/daemon/control_udp.c index 540285516..947a6ac24 100644 --- a/daemon/control_udp.c +++ b/daemon/control_udp.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "control_udp.h" #include "poller.h" @@ -18,7 +19,9 @@ static pcre *parse_re; static pcre_extra *parse_ree; -static GHashTable *cookies; +static GHashTable *fresh_cookies, *stale_cookies; +static GStringChunk *fresh_chunks, *stale_chunks; +time_t oven_time; @@ -68,27 +71,33 @@ static void control_udp_incoming(int fd, void *p) { pcre_get_substring_list(buf, ovec, ret, &out); - if (!cookies) - cookies = g_hash_table_new_full(g_str_hash, g_str_equal, free, free); + if (!fresh_cookies) { + fresh_cookies = g_hash_table_new(g_str_hash, g_str_equal); + stale_cookies = g_hash_table_new(g_str_hash, g_str_equal); + fresh_chunks = g_string_chunk_new(4 * 1024); + stale_chunks = g_string_chunk_new(4 * 1024); + time(&oven_time); + } + else { + if (u->poller->now - oven_time >= 30) { + g_hash_table_remove_all(stale_cookies); + g_string_chunk_clear(stale_chunks); + swap_ptrs(&stale_cookies, &fresh_cookies); + swap_ptrs(&stale_chunks, &fresh_chunks); + oven_time = u->poller->now; /* baked new cookies! */ + } + } /* XXX better hashing */ - reply = g_hash_table_lookup(cookies, out[1]); + reply = g_hash_table_lookup(fresh_cookies, out[1]); + if (!reply) + reply = g_hash_table_lookup(stale_cookies, out[1]); if (reply) { + mylog(LOG_INFO, "Detected command from udp:" DF " as a duplicate", DP(sin)); sendto(fd, reply, strlen(reply), 0, (struct sockaddr *) &sin, sin_len); goto out; } - ZERO(mh); - mh.msg_name = &sin; - mh.msg_namelen = sizeof(sin); - mh.msg_iov = iov; - mh.msg_iovlen = 2; - - iov[0].iov_base = (void *) out[1]; - iov[0].iov_len = strlen(out[1]); - iov[1].iov_base = " "; - iov[1].iov_len = 1; - if (out[2][0] == 'u' || out[2][0] == 'U') reply = call_update_udp(out, u->callmaster); else if (out[2][0] == 'l' || out[2][0] == 'L') @@ -96,6 +105,17 @@ static void control_udp_incoming(int fd, void *p) { else if (out[9][0] == 'd' || out[9][0] == 'D') reply = call_delete_udp(out, u->callmaster); else if (out[12][0] == 'v' || out[12][0] == 'V') { + ZERO(mh); + mh.msg_name = &sin; + mh.msg_namelen = sizeof(sin); + mh.msg_iov = iov; + mh.msg_iovlen = 2; + + iov[0].iov_base = (void *) out[1]; + iov[0].iov_len = strlen(out[1]); + iov[1].iov_base = " "; + iov[1].iov_len = 1; + if (out[13][0] == 'f' || out[13][0] == 'F') { ret = 0; if (!strcmp(out[14], "20040107")) @@ -118,7 +138,9 @@ static void control_udp_incoming(int fd, void *p) { if (reply) { sendto(fd, reply, strlen(reply), 0, (struct sockaddr *) &sin, sin_len); - g_hash_table_insert(cookies, strdup(out[1]), reply); /* XXX timeout entries */ + g_hash_table_insert(fresh_cookies, g_string_chunk_insert(fresh_chunks, out[1]), + g_string_chunk_insert(fresh_chunks, reply)); + free(reply); } out: