|
|
|
@ -34,12 +34,20 @@ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef DELETE_DELAY |
|
|
|
#define DELETE_DELAY 30 |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef int (*rewrite_func)(str *, struct packet_stream *); |
|
|
|
|
|
|
|
/* also serves as array index for callstream->peers[] */ |
|
|
|
struct iterator_helper { |
|
|
|
GSList *del; |
|
|
|
GSList *del_timeout; |
|
|
|
GSList *del_scheduled; |
|
|
|
struct stream_fd *ports[0x10000]; |
|
|
|
}; |
|
|
|
struct xmlrpc_helper { |
|
|
|
@ -287,6 +295,7 @@ static const struct mediaproxy_srtp __mps_null = { |
|
|
|
static void unkernelize(struct packet_stream *); |
|
|
|
static void __stream_unkernelize(struct packet_stream *ps); |
|
|
|
static void stream_unkernelize(struct packet_stream *ps); |
|
|
|
static void __monologue_destroy(struct call_monologue *monologue); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -871,6 +880,53 @@ done: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* called with call->master_lock held in R */ |
|
|
|
static int call_timer_delete_monologues(struct call *c) { |
|
|
|
GSList *i; |
|
|
|
struct call_monologue *ml; |
|
|
|
int ret = 0; |
|
|
|
time_t min_deleted = 0; |
|
|
|
|
|
|
|
/* we need a write lock here */ |
|
|
|
rwlock_unlock_r(&c->master_lock); |
|
|
|
rwlock_lock_w(&c->master_lock); |
|
|
|
|
|
|
|
for (i = c->monologues; i; i = i->next) { |
|
|
|
ml = i->data; |
|
|
|
|
|
|
|
if (!ml->deleted) |
|
|
|
continue; |
|
|
|
if (ml->deleted > poller_now) { |
|
|
|
if (!min_deleted || ml->deleted < min_deleted) |
|
|
|
min_deleted = ml->deleted; |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
__monologue_destroy(ml); |
|
|
|
ml->deleted = 0; |
|
|
|
|
|
|
|
if (!g_hash_table_size(c->tags)) { |
|
|
|
ilog(LOG_INFO, "Call branch '"STR_FORMAT"' deleted, no more branches remaining", |
|
|
|
STR_FMT(&ml->tag)); |
|
|
|
ret = 1; /* destroy call */ |
|
|
|
goto out; |
|
|
|
} |
|
|
|
|
|
|
|
ilog(LOG_INFO, "Call branch "STR_FORMAT" deleted", |
|
|
|
STR_FMT(&ml->tag)); |
|
|
|
} |
|
|
|
|
|
|
|
out: |
|
|
|
c->ml_deleted = min_deleted; |
|
|
|
|
|
|
|
rwlock_unlock_w(&c->master_lock); |
|
|
|
rwlock_lock_r(&c->master_lock); |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* called with callmaster->hashlock held */ |
|
|
|
static void call_timer_iterator(void *key, void *val, void *ptr) { |
|
|
|
struct call *c = val; |
|
|
|
@ -883,6 +939,16 @@ static void call_timer_iterator(void *key, void *val, void *ptr) { |
|
|
|
struct stream_fd *sfd; |
|
|
|
|
|
|
|
rwlock_lock_r(&c->master_lock); |
|
|
|
log_info_call(c); |
|
|
|
|
|
|
|
if (c->deleted && poller_now >= c->deleted |
|
|
|
&& c->last_signal <= c->deleted) |
|
|
|
goto delete; |
|
|
|
|
|
|
|
if (c->ml_deleted && poller_now >= c->ml_deleted) { |
|
|
|
if (call_timer_delete_monologues(c)) |
|
|
|
goto delete; |
|
|
|
} |
|
|
|
|
|
|
|
if (!c->streams) |
|
|
|
goto drop; |
|
|
|
@ -925,17 +991,19 @@ next: |
|
|
|
if (good) |
|
|
|
goto out; |
|
|
|
|
|
|
|
log_info_call(c); |
|
|
|
ilog(LOG_INFO, "Closing call branch due to timeout"); |
|
|
|
log_info_clear(); |
|
|
|
ilog(LOG_INFO, "Closing call due to timeout"); |
|
|
|
|
|
|
|
drop: |
|
|
|
rwlock_unlock_r(&c->master_lock); |
|
|
|
hlp->del = g_slist_prepend(hlp->del, obj_get(c)); |
|
|
|
return; |
|
|
|
hlp->del_timeout = g_slist_prepend(hlp->del_timeout, obj_get(c)); |
|
|
|
goto out; |
|
|
|
|
|
|
|
delete: |
|
|
|
hlp->del_scheduled = g_slist_prepend(hlp->del_scheduled, obj_get(c)); |
|
|
|
goto out; |
|
|
|
|
|
|
|
out: |
|
|
|
rwlock_unlock_r(&c->master_lock); |
|
|
|
log_info_clear(); |
|
|
|
} |
|
|
|
|
|
|
|
void xmlrpc_kill_calls(void *p) { |
|
|
|
@ -1033,11 +1101,10 @@ void kill_calls_timer(GSList *list, struct callmaster *m) { |
|
|
|
struct xmlrpc_helper *xh = NULL; |
|
|
|
|
|
|
|
if (!list) |
|
|
|
return; /* shouldn't happen */ |
|
|
|
return; |
|
|
|
|
|
|
|
ca = list->data; |
|
|
|
m = ca->callmaster; /* same callmaster for all of them */ |
|
|
|
url = m->conf.b2b_url; |
|
|
|
/* if m is NULL, it's the scheduled deletions, otherwise it's the timeouts */ |
|
|
|
url = m ? m->conf.b2b_url : NULL; |
|
|
|
if (url) { |
|
|
|
xh = g_slice_alloc(sizeof(*xh)); |
|
|
|
xh->c = g_string_chunk_new(64); |
|
|
|
@ -1187,10 +1254,8 @@ next: |
|
|
|
if (hlp.ports[j]) |
|
|
|
obj_put(hlp.ports[j]); |
|
|
|
|
|
|
|
if (!hlp.del) |
|
|
|
return; |
|
|
|
|
|
|
|
kill_calls_timer(hlp.del, m); |
|
|
|
kill_calls_timer(hlp.del_scheduled, NULL); |
|
|
|
kill_calls_timer(hlp.del_timeout, m); |
|
|
|
} |
|
|
|
#undef DS |
|
|
|
|
|
|
|
@ -1903,6 +1968,7 @@ int monologue_offer_answer(struct call_monologue *monologue, GQueue *streams, |
|
|
|
struct endpoint_map *em; |
|
|
|
|
|
|
|
monologue->call->last_signal = poller_now; |
|
|
|
monologue->call->deleted = 0; |
|
|
|
|
|
|
|
/* we must have a complete dialogue, even though the to-tag (other_ml->tag) |
|
|
|
* may not be known yet */ |
|
|
|
@ -2421,6 +2487,9 @@ static void __monologue_unkernelize(struct call_monologue *monologue) { |
|
|
|
if (!monologue) |
|
|
|
return; |
|
|
|
|
|
|
|
monologue->deleted = 0; /* not really related, but indicates activity, so cancel |
|
|
|
any pending deletion */ |
|
|
|
|
|
|
|
for (l = monologue->medias.head; l; l = l->next) { |
|
|
|
media = l->data; |
|
|
|
|
|
|
|
@ -2582,16 +2651,17 @@ int call_delete_branch(struct callmaster *m, const str *callid, const str *branc |
|
|
|
} |
|
|
|
*/ |
|
|
|
|
|
|
|
__monologue_destroy(ml); |
|
|
|
if (g_hash_table_size(c->tags)) { |
|
|
|
ilog(LOG_INFO, "Call branch deleted (other branches still active)"); |
|
|
|
goto success_unlock; |
|
|
|
} |
|
|
|
ilog(LOG_INFO, "Scheduling deletion of call branch '"STR_FORMAT"' in %d seconds", |
|
|
|
STR_FMT(&ml->tag), DELETE_DELAY); |
|
|
|
ml->deleted = poller_now + 30; |
|
|
|
if (!c->ml_deleted || c->ml_deleted > ml->deleted) |
|
|
|
c->ml_deleted = ml->deleted; |
|
|
|
goto success_unlock; |
|
|
|
|
|
|
|
del_all: |
|
|
|
ilog(LOG_INFO, "Scheduling deletion of entire call in %d seconds", DELETE_DELAY); |
|
|
|
c->deleted = poller_now + DELETE_DELAY; |
|
|
|
rwlock_unlock_w(&c->master_lock); |
|
|
|
ilog(LOG_INFO, "Deleting full call"); |
|
|
|
call_destroy(c); |
|
|
|
goto success; |
|
|
|
|
|
|
|
success_unlock: |
|
|
|
|