|
|
|
@ -7,6 +7,7 @@ |
|
|
|
#include <glib.h> |
|
|
|
#include <time.h> |
|
|
|
#include <netinet/in.h> |
|
|
|
#include <errno.h> |
|
|
|
|
|
|
|
#include "control_udp.h" |
|
|
|
#include "poller.h" |
|
|
|
@ -15,6 +16,9 @@ |
|
|
|
#include "call.h" |
|
|
|
|
|
|
|
|
|
|
|
static const char *cookie_in_use = "MAGIC"; |
|
|
|
|
|
|
|
|
|
|
|
static void control_udp_closed(int fd, void *p, uintptr_t x) { |
|
|
|
abort(); |
|
|
|
} |
|
|
|
@ -34,8 +38,9 @@ static void control_udp_incoming(int fd, void *p, uintptr_t x) { |
|
|
|
|
|
|
|
sin_len = sizeof(sin); |
|
|
|
len = recvfrom(fd, buf, sizeof(buf) - 1, 0, (struct sockaddr *) &sin, &sin_len); |
|
|
|
if (len <= 0) { |
|
|
|
mylog(LOG_WARNING, "Error reading from UDP socket"); |
|
|
|
if (len < 0) { |
|
|
|
if (errno != EWOULDBLOCK) |
|
|
|
mylog(LOG_WARNING, "Error reading from UDP socket"); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
@ -87,6 +92,7 @@ static void control_udp_incoming(int fd, void *p, uintptr_t x) { |
|
|
|
|
|
|
|
pcre_get_substring_list(buf, ovec, ret, &out); |
|
|
|
|
|
|
|
mutex_lock(&u->lock); |
|
|
|
if (poller_now(u->poller) - u->oven_time >= 30) { |
|
|
|
g_hash_table_remove_all(u->stale_cookies); |
|
|
|
#if GLIB_CHECK_VERSION(2,14,0) |
|
|
|
@ -101,16 +107,26 @@ static void control_udp_incoming(int fd, void *p, uintptr_t x) { |
|
|
|
u->oven_time = poller_now(u->poller); /* baked new cookies! */ |
|
|
|
} |
|
|
|
|
|
|
|
restart: |
|
|
|
/* XXX better hashing */ |
|
|
|
reply = g_hash_table_lookup(u->fresh_cookies, out[RE_UDP_COOKIE]); |
|
|
|
if (!reply) |
|
|
|
reply = g_hash_table_lookup(u->stale_cookies, out[RE_UDP_COOKIE]); |
|
|
|
if (reply) { |
|
|
|
if (reply == cookie_in_use) { |
|
|
|
/* another thread is working on this right now */ |
|
|
|
cond_wait(&u->cond, &u->lock); |
|
|
|
goto restart; |
|
|
|
} |
|
|
|
mutex_unlock(&u->lock); |
|
|
|
mylog(LOG_INFO, "Detected command from udp:%s:%u as a duplicate", addr, ntohs(sin.sin6_port)); |
|
|
|
sendto(fd, reply, strlen(reply), 0, (struct sockaddr *) &sin, sin_len); |
|
|
|
goto out; |
|
|
|
} |
|
|
|
|
|
|
|
g_hash_table_replace(u->fresh_cookies, (void *) out[RE_UDP_COOKIE], (void *) cookie_in_use); |
|
|
|
mutex_unlock(&u->lock); |
|
|
|
|
|
|
|
if (chrtoupper(out[RE_UDP_UL_CMD][0]) == 'U') |
|
|
|
reply = call_update_udp(out, u->callmaster); |
|
|
|
else if (chrtoupper(out[RE_UDP_UL_CMD][0]) == 'L') |
|
|
|
@ -151,8 +167,11 @@ static void control_udp_incoming(int fd, void *p, uintptr_t x) { |
|
|
|
|
|
|
|
if (reply) { |
|
|
|
sendto(fd, reply, strlen(reply), 0, (struct sockaddr *) &sin, sin_len); |
|
|
|
g_hash_table_insert(u->fresh_cookies, g_string_chunk_insert(u->fresh_chunks, out[RE_UDP_COOKIE]), |
|
|
|
mutex_lock(&u->lock); |
|
|
|
g_hash_table_replace(u->fresh_cookies, g_string_chunk_insert(u->fresh_chunks, out[RE_UDP_COOKIE]), |
|
|
|
g_string_chunk_insert(u->fresh_chunks, reply)); |
|
|
|
cond_broadcast(&u->cond); |
|
|
|
mutex_unlock(&u->lock); |
|
|
|
free(reply); |
|
|
|
} |
|
|
|
|
|
|
|
@ -197,6 +216,7 @@ struct control_udp *control_udp_new(struct poller *p, struct in6_addr ip, u_int1 |
|
|
|
c->fresh_chunks = g_string_chunk_new(4 * 1024); |
|
|
|
c->stale_chunks = g_string_chunk_new(4 * 1024); |
|
|
|
c->oven_time = poller_now(p); |
|
|
|
mutex_init(&c->lock); |
|
|
|
c->parse_re = pcre_compile( |
|
|
|
/* cookie cmd flags callid viabranch:5 */ |
|
|
|
"^(\\S+)\\s+(?:([ul])(\\S*)\\s+([^;]+)(?:;(\\S+))?\\s+" \ |
|
|
|
|