diff --git a/daemon/call.c b/daemon/call.c index 502add63f..de0706d3d 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -44,6 +44,11 @@ static __thread const str *log_info; +/* also serves as array index for callstream->peers[] */ +enum opmode { + OP_OFFER = 0, + OP_ANSWER = 1, +}; struct iterator_helper { GSList *del; struct streamrelay *ports[0x10000]; @@ -1169,7 +1174,7 @@ static void callstream_free(void *ptr) { } /* called with call->lock held */ -static int call_streams(struct call *c, GQueue *s, const str *tag, int opmode) { +static int call_streams(struct call *c, GQueue *s, const str *tag, enum opmode opmode) { GQueue *q; GList *i, *l; struct stream_input *t; @@ -1500,14 +1505,19 @@ int call_stream_address(GString *o, struct peer *p, enum stream_address_format f -static str *streams_print(GQueue *s, unsigned int num, unsigned int off, const char *prefix, enum stream_address_format format) { +static str *streams_print(GQueue *s, int rawnum, enum opmode opmode, const char *prefix, enum stream_address_format format) { GString *o; - int i; + int i, num, off; GList *l; struct callstream *t; struct streamrelay *x; int af; + num = abs(rawnum); + off = opmode; /* 0 or 1 */ + if (num < 0) + off ^= 1; /* 1 or 0 */ + o = g_string_new_str(); if (prefix) g_string_append_printf(o, "%s ", prefix); @@ -1599,6 +1609,36 @@ restart: return c; } +/* returns call with lock held, or NULL if not found */ +static struct call *call_get(const str *callid, const str *viabranch, struct callmaster *m) { + struct call *ret; + + rwlock_lock_r(&m->hashlock); + ret = g_hash_table_lookup(m->callhash, callid); + if (!ret) { + rwlock_unlock_r(&m->hashlock); + return NULL; + } + + mutex_lock(&ret->lock); + obj_hold(ret); + rwlock_unlock_r(&m->hashlock); + + if (viabranch && viabranch->s && viabranch->len) { + if (!g_hash_table_lookup(ret->branches, viabranch)) + g_hash_table_insert(ret->branches, call_str_dup(ret, viabranch), (void *) 0x1); + } + + return ret; +} + +/* returns call with lock held, or possibly NULL iff opmode == OP_ANSWER */ +static struct call *call_get_opmode(const str *callid, const str *viabranch, struct callmaster *m, enum opmode opmode) { + if (opmode == OP_OFFER) + return call_get_or_create(callid, viabranch, m); + return call_get(callid, viabranch, m); +} + static int addr_parse_udp(struct stream_input *st, char **out) { u_int32_t ip4; const char *cp; @@ -1662,10 +1702,10 @@ str *call_update_udp(char **out, struct callmaster *m) { goto fail; g_queue_push_tail(&q, &st); - num = call_streams(c, &q, &fromtag, 0); + num = call_streams(c, &q, &fromtag, OP_OFFER); g_queue_clear(&q); - ret = streams_print(c->callstreams, 1, (num >= 0) ? 0 : 1, out[RE_UDP_COOKIE], SAF_UDP); + ret = streams_print(c->callstreams, num, OP_OFFER, out[RE_UDP_COOKIE], SAF_UDP); mutex_unlock(&c->lock); if (redis_update) @@ -1720,10 +1760,10 @@ str *call_lookup_udp(char **out, struct callmaster *m) { g_queue_push_tail(&q, &st); str_init(&totag, out[RE_UDP_UL_TOTAG]); - num = call_streams(c, &q, &totag, 1); + num = call_streams(c, &q, &totag, OP_ANSWER); g_queue_clear(&q); - ret = streams_print(c->callstreams, 1, (num >= 0) ? 1 : 0, out[RE_UDP_COOKIE], SAF_UDP); + ret = streams_print(c->callstreams, num, OP_ANSWER, out[RE_UDP_COOKIE], SAF_UDP); mutex_unlock(&c->lock); if (redis_update) @@ -1743,72 +1783,47 @@ fail: return ret; } -str *call_request(char **out, struct callmaster *m) { +static str *call_request_lookup(char **out, struct callmaster *m, enum opmode opmode, const char *tagstr) { struct call *c; GQueue s = G_QUEUE_INIT; int num; - str *ret, callid, tag; + str *ret = NULL, callid, tag; GHashTable *infohash; str_init(&callid, out[RE_TCP_RL_CALLID]); infohash = g_hash_table_new(g_str_hash, g_str_equal); - c = call_get_or_create(&callid, NULL, m); + c = call_get_opmode(&callid, NULL, m, opmode); + if (!c) { + mylog(LOG_WARNING, LOG_PREFIX_C "Got LOOKUP for unknown call-id", STR_FMT(&callid)); + goto out; + } info_parse(out[RE_TCP_RL_INFO], infohash, m); streams_parse(out[RE_TCP_RL_STREAMS], m, &s); - str_init(&tag, g_hash_table_lookup(infohash, "fromtag")); - num = call_streams(c, &s, &tag, 0); + str_init(&tag, g_hash_table_lookup(infohash, tagstr)); + num = call_streams(c, &s, &tag, opmode); - ret = streams_print(c->callstreams, abs(num), (num >= 0) ? 0 : 1, NULL, SAF_TCP); + ret = streams_print(c->callstreams, num, opmode, NULL, SAF_TCP); mutex_unlock(&c->lock); streams_free(&s); - g_hash_table_destroy(infohash); if (redis_update) redis_update(c, m->conf.redis); mylog(LOG_INFO, LOG_PREFIX_CI "Returning to SIP proxy: %.*s", LOG_PARAMS_CI(c), STR_FMT(ret)); obj_put(c); + +out: + g_hash_table_destroy(infohash); return ret; } +str *call_request(char **out, struct callmaster *m) { + return call_request_lookup(out, m, OP_OFFER, "fromtag"); +} str *call_lookup(char **out, struct callmaster *m) { - struct call *c; - GQueue s = G_QUEUE_INIT; - int num; - str *ret, callid, tag; - GHashTable *infohash; - - str_init(&callid, out[RE_TCP_RL_CALLID]); - rwlock_lock_r(&m->hashlock); - c = g_hash_table_lookup(m->callhash, &callid); - if (!c) { - rwlock_unlock_r(&m->hashlock); - mylog(LOG_WARNING, LOG_PREFIX_C "Got LOOKUP for unknown call-id", STR_FMT(&callid)); - return NULL; - } - obj_hold(c); - mutex_lock(&c->lock); - rwlock_unlock_r(&m->hashlock); - - infohash = g_hash_table_new(g_str_hash, g_str_equal); - info_parse(out[RE_TCP_RL_INFO], infohash, m); - streams_parse(out[RE_TCP_RL_STREAMS], m, &s); - str_init(&tag, g_hash_table_lookup(infohash, "totag")); - num = call_streams(c, &s, &tag, 1); - ret = streams_print(c->callstreams, abs(num), (num >= 0) ? 1 : 0, NULL, SAF_TCP); - mutex_unlock(&c->lock); - - streams_free(&s); - g_hash_table_destroy(infohash); - - if (redis_update) - redis_update(c, m->conf.redis); - - mylog(LOG_INFO, LOG_PREFIX_CI "Returning to SIP proxy: %.*s", LOG_PARAMS_CI(c), STR_FMT(ret)); - obj_put(c); - return ret; + return call_request_lookup(out, m, OP_ANSWER, "totag"); } str *call_delete_udp(char **out, struct callmaster *m) { @@ -2150,7 +2165,7 @@ const char *call_offer(bencode_item_t *input, struct callmaster *m, bencode_item call = call_get_or_create(&callid, &viabranch, m); log_info = &viabranch; - num = call_streams(call, &streams, &fromtag, 0); + num = call_streams(call, &streams, &fromtag, OP_OFFER); sdp_new = sdp_replace(&sdp, &parsed, call, abs(num), (num >= 0) ? 0 : 1); mutex_unlock(&call->lock);