diff --git a/daemon/call.c b/daemon/call.c index 79e39e769..66ad7c393 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -60,8 +60,7 @@ struct iterator_helper { struct xmlrpc_helper { enum xmlrpc_format fmt; GStringChunk *c; - char *url; - GSList *tags; + GSList *tags_urls; }; struct streamhandler_io { @@ -1130,18 +1129,22 @@ void xmlrpc_kill_calls(void *p) { int i = 0; int status; str *tag; + const char *url; - while (xh->tags) { - tag = xh->tags->data; + while (xh->tags_urls && xh->tags_urls->next) { + tag = xh->tags_urls->data; + url = xh->tags_urls->next->data; - ilog(LOG_INFO, "Forking child to close call with tag "STR_FORMAT" via XMLRPC", STR_FMT(tag)); + ilog(LOG_INFO, "Forking child to close call with tag "STR_FORMAT" via XMLRPC call to %s", + STR_FMT(tag), url); pid = fork(); if (pid) { retry: pid = waitpid(pid, &status, 0); if ((pid > 0 && WIFEXITED(status) && WEXITSTATUS(status) == 0) || i >= 3) { - xh->tags = g_slist_delete_link(xh->tags, xh->tags); + xh->tags_urls = g_slist_delete_link(xh->tags_urls, xh->tags_urls); + xh->tags_urls = g_slist_delete_link(xh->tags_urls, xh->tags_urls); i = 0; } else { @@ -1181,11 +1184,11 @@ retry: r = NULL; switch (xh->fmt) { case XF_SEMS: - xmlrpc_client_call2f(&e, c, xh->url, "di", &r, "(ssss)", + xmlrpc_client_call2f(&e, c, url, "di", &r, "(ssss)", "sbc", "postControlCmd", tag->s, "teardown"); break; case XF_CALLID: - xmlrpc_client_call2f(&e, c, xh->url, "teardown", &r, "(s)", tag->s); + xmlrpc_client_call2f(&e, c, url, "teardown", &r, "(s)", tag->s); break; } @@ -1195,7 +1198,8 @@ retry: goto fault; xmlrpc_client_destroy(c); - xh->tags = g_slist_delete_link(xh->tags, xh->tags); + xh->tags_urls = g_slist_delete_link(xh->tags_urls, xh->tags_urls); + xh->tags_urls = g_slist_delete_link(xh->tags_urls, xh->tags_urls); xmlrpc_env_clean(&e); _exit(0); @@ -1213,8 +1217,9 @@ void kill_calls_timer(GSList *list, struct callmaster *m) { struct call *ca; GSList *csl; struct call_monologue *cm; - const char *url; + const char *url, *url_prefix, *url_suffix; struct xmlrpc_helper *xh = NULL; + char addr[64], url_buf[128]; if (!list) return; @@ -1224,8 +1229,15 @@ void kill_calls_timer(GSList *list, struct callmaster *m) { if (url) { xh = g_slice_alloc(sizeof(*xh)); xh->c = g_string_chunk_new(64); - xh->url = g_string_chunk_insert(xh->c, url); - xh->tags = NULL; + url_prefix = NULL; + url_suffix = strstr(url, "%%"); + if (url_suffix) { + url_prefix = g_string_chunk_insert_len(xh->c, url, url_suffix - url); + url_suffix = g_string_chunk_insert(xh->c, url_suffix + 2); + } + else + url_suffix = g_string_chunk_insert(xh->c, url); + xh->tags_urls = NULL; xh->fmt = m->conf.fmt; } @@ -1237,17 +1249,27 @@ void kill_calls_timer(GSList *list, struct callmaster *m) { rwlock_lock_r(&ca->master_lock); + if (url_prefix) { + smart_ntop_p(addr, &ca->created_from_addr.sin6_addr, sizeof(addr)); + snprintf(url_buf, sizeof(url_buf), "%s%s%s", + url_prefix, addr, url_suffix); + } + else + snprintf(url_buf, sizeof(url_buf), "%s", url_suffix); + switch (m->conf.fmt) { case XF_SEMS: for (csl = ca->monologues; csl; csl = csl->next) { cm = csl->data; if (cm->tag.s && cm->tag.len) { - xh->tags = g_slist_prepend(xh->tags, str_chunk_insert(xh->c, &cm->tag)); + xh->tags_urls = g_slist_prepend(xh->tags_urls, g_string_chunk_insert(xh->c, url_buf)); + xh->tags_urls = g_slist_prepend(xh->tags_urls, str_chunk_insert(xh->c, &cm->tag)); } } break; case XF_CALLID: - xh->tags = g_slist_prepend(xh->tags, str_chunk_insert(xh->c, &ca->callid)); + xh->tags_urls = g_slist_prepend(xh->tags_urls, g_string_chunk_insert(xh->c, url_buf)); + xh->tags_urls = g_slist_prepend(xh->tags_urls, str_chunk_insert(xh->c, &ca->callid)); break; } diff --git a/daemon/call.h b/daemon/call.h index 3328ed9b4..bcf741fd9 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -360,6 +360,7 @@ struct call { time_t ml_deleted; unsigned char tos; char *created_from; + struct sockaddr_in6 created_from_addr; }; struct local_interface { diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 73584180b..67ce881f5 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -134,7 +134,9 @@ fail: return -1; } -static str *call_update_lookup_udp(char **out, struct callmaster *m, enum call_opmode opmode, const char* addr) { +static str *call_update_lookup_udp(char **out, struct callmaster *m, enum call_opmode opmode, const char* addr, + const struct sockaddr_in6 *sin) +{ struct call *c; struct call_monologue *monologue; GQueue q = G_QUEUE_INIT; @@ -155,8 +157,9 @@ static str *call_update_lookup_udp(char **out, struct callmaster *m, enum call_o return str_sprintf("%s 0 0.0.0.0\n", out[RE_UDP_COOKIE]); } - if (addr) { + if (!c->created_from && addr) { c->created_from = call_strdup(c, addr); + c->created_from_addr = *sin; } monologue = call_get_mono_dialogue(c, &fromtag, &totag); @@ -207,11 +210,11 @@ out: return ret; } -str *call_update_udp(char **out, struct callmaster *m, const char* addr) { - return call_update_lookup_udp(out, m, OP_OFFER, addr); +str *call_update_udp(char **out, struct callmaster *m, const char* addr, const struct sockaddr_in6 *sin) { + return call_update_lookup_udp(out, m, OP_OFFER, addr, sin); } str *call_lookup_udp(char **out, struct callmaster *m) { - return call_update_lookup_udp(out, m, OP_ANSWER, NULL); + return call_update_lookup_udp(out, m, OP_ANSWER, NULL, NULL); } @@ -592,7 +595,8 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu } static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster *m, - bencode_item_t *output, enum call_opmode opmode, const char* addr) + bencode_item_t *output, enum call_opmode opmode, const char* addr, + const struct sockaddr_in6 *sin) { str sdp, fromtag, totag = STR_NULL, callid; char *errstr; @@ -631,8 +635,9 @@ static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster if (!call) goto out; - if (addr) { + if (!call->created_from && addr) { call->created_from = call_strdup(call, addr); + call->created_from_addr = *sin; } /* At least the random ICE strings are contained within the call struct, so we * need to hold a ref until we're done sending the reply */ @@ -680,12 +685,14 @@ out: return errstr; } -const char *call_offer_ng(bencode_item_t *input, struct callmaster *m, bencode_item_t *output, const char* addr) { - return call_offer_answer_ng(input, m, output, OP_OFFER, addr); +const char *call_offer_ng(bencode_item_t *input, struct callmaster *m, bencode_item_t *output, const char* addr, + const struct sockaddr_in6 *sin) +{ + return call_offer_answer_ng(input, m, output, OP_OFFER, addr, sin); } const char *call_answer_ng(bencode_item_t *input, struct callmaster *m, bencode_item_t *output) { - return call_offer_answer_ng(input, m, output, OP_ANSWER, NULL); + return call_offer_answer_ng(input, m, output, OP_ANSWER, NULL, NULL); } const char *call_delete_ng(bencode_item_t *input, struct callmaster *m, bencode_item_t *output) { diff --git a/daemon/call_interfaces.h b/daemon/call_interfaces.h index 209707f66..5c1e68601 100644 --- a/daemon/call_interfaces.h +++ b/daemon/call_interfaces.h @@ -13,6 +13,7 @@ struct call; struct call_stats; struct callmaster; struct control_stream; +struct sockaddr_in6; extern int trust_address_def; @@ -24,12 +25,13 @@ str *call_lookup_tcp(char **, struct callmaster *); void call_delete_tcp(char **, struct callmaster *); void calls_status_tcp(struct callmaster *, struct control_stream *); -str *call_update_udp(char **, struct callmaster *, const char*); +str *call_update_udp(char **, struct callmaster *, const char*, const struct sockaddr_in6 *); str *call_lookup_udp(char **, struct callmaster *); str *call_delete_udp(char **, struct callmaster *); str *call_query_udp(char **, struct callmaster *); -const char *call_offer_ng(bencode_item_t *, struct callmaster *, bencode_item_t *, const char*); +const char *call_offer_ng(bencode_item_t *, struct callmaster *, bencode_item_t *, const char*, + const struct sockaddr_in6 *); const char *call_answer_ng(bencode_item_t *, struct callmaster *, bencode_item_t *); const char *call_delete_ng(bencode_item_t *, struct callmaster *, bencode_item_t *); const char *call_query_ng(bencode_item_t *, struct callmaster *, bencode_item_t *); diff --git a/daemon/control_ng.c b/daemon/control_ng.c index afe5a91df..d568520b0 100644 --- a/daemon/control_ng.c +++ b/daemon/control_ng.c @@ -111,7 +111,7 @@ static void control_ng_incoming(struct obj *obj, str *buf, struct sockaddr_in6 * if (!str_cmp(&cmd, "ping")) bencode_dictionary_add_string(resp, "result", "pong"); else if (!str_cmp(&cmd, "offer")) - errstr = call_offer_ng(dict, c->callmaster, resp, addr); + errstr = call_offer_ng(dict, c->callmaster, resp, addr, sin); else if (!str_cmp(&cmd, "answer")) errstr = call_answer_ng(dict, c->callmaster, resp); else if (!str_cmp(&cmd, "delete")) diff --git a/daemon/control_udp.c b/daemon/control_udp.c index bab804142..1e4f3b214 100644 --- a/daemon/control_udp.c +++ b/daemon/control_udp.c @@ -83,7 +83,7 @@ static void control_udp_incoming(struct obj *obj, str *buf, struct sockaddr_in6 } if (chrtoupper(out[RE_UDP_UL_CMD][0]) == 'U') - reply = call_update_udp(out, u->callmaster, addr); + reply = call_update_udp(out, u->callmaster, addr, sin); else if (chrtoupper(out[RE_UDP_UL_CMD][0]) == 'L') reply = call_lookup_udp(out, u->callmaster); else if (chrtoupper(out[RE_UDP_DQ_CMD][0]) == 'D') diff --git a/tests/simulator-ng.pl b/tests/simulator-ng.pl index 9c4572323..5d34cc30b 100755 --- a/tests/simulator-ng.pl +++ b/tests/simulator-ng.pl @@ -46,9 +46,9 @@ setrlimit(RLIMIT_NOFILE, 8000, 8000); $PROTOS and $PROTOS = [split(/\s*[,;:]+\s*/, $PROTOS)]; $PROTOS && @$PROTOS == 1 and $$PROTOS[1] = $$PROTOS[0]; -$DEST and $DEST = [split(/:/, $DEST)]; -$$DEST[0] or $$DEST[0] = '127.0.0.1'; -$$DEST[1] or $$DEST[1] = 2223; +$DEST and $DEST = [$DEST =~ /^(?:([a-z.-]+)(?::(\d+))?|([\d.]+)(?::(\d+))?|([\da-f:]+)|\[([\da-f:]+)\]:(\d+))$/si]; +my $dest_host = $$DEST[0] || $$DEST[2] || $$DEST[4] || $$DEST[5] || 'localhost'; +my $dest_port = $$DEST[1] || $$DEST[3] || $$DEST[6] || 2223; $SUITES and $SUITES = [split(/\s*[,;:]+\s*/, $SUITES)]; my @chrs = ('a' .. 'z', 'A' .. 'Z', '0' .. '9'); @@ -78,8 +78,14 @@ sub msg { return $r ? bdecode($r, 1) : undef; } -socket($fd, AF_INET, SOCK_DGRAM, 0) or die $!; -connect($fd, sockaddr_in($$DEST[1], inet_aton($$DEST[0]))) or die $!; +my @dests = getaddrinfo($dest_host, $dest_port, AF_UNSPEC, SOCK_DGRAM); +while (@dests >= 5) { + my ($fam, $type, $prot, $addr, $canon, @dests) = @dests; + socket($fd, $fam, $type, $prot) or undef($fd), next; + connect($fd, $addr) or undef($fd), next; + last; +} +$fd or die($!); msg({command => 'ping'})->{result} eq 'pong' or die;