Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various changes of RTP timeout handling to handle timeouts on single streams #1403

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 31 additions & 5 deletions daemon/call.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ void call_make_own_foreign(struct call *c, bool foreign) {
static void call_timer_iterator(struct call *c, struct iterator_helper *hlp) {
GList *it;
unsigned int check;
bool good = false;
bool good = false; // gets true if any stream has active media
bool failed = false; // gets true if any stream has a timeout event
struct packet_stream *ps;
struct stream_fd *sfd;
int tmp_t_reason = UNKNOWN;
Expand Down Expand Up @@ -176,6 +177,12 @@ static void call_timer_iterator(struct call *c, struct iterator_helper *hlp) {
goto out;
}

if (c->timeout_mode == TIMEOUT_OFF)
goto out;

if (c->timeout_activated > rtpe_now.tv_sec)
goto out;

if (c->deleted && rtpe_now.tv_sec >= c->deleted
&& c->last_signal <= c->deleted)
goto delete;
Expand Down Expand Up @@ -206,6 +213,16 @@ static void call_timer_iterator(struct call *c, struct iterator_helper *hlp) {

/* valid stream */

// ignore RTCP Streams
if (PS_ISSET(ps, RTCP))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be more appropriate to use if (!PS_ISSET(ps, RTP)) here? (Streams can be both RTP and RTCP in case of RTCP-mux)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this sounds better. I hadn't RTCP-mux in mind, because it's not used in our case.

goto next;

// ignore Streams which are already marked fot deletion
if (ps->media->monologue->mark_deleted) {
ilog(LOG_DEBUG, "Ignoring deleted monologue");
goto next;
}

css = call_stream_state_machine(ps);

if (css == CSS_ICE)
Expand All @@ -216,12 +233,12 @@ static void call_timer_iterator(struct call *c, struct iterator_helper *hlp) {
g_hash_table_insert(hlp->addr_sfd, &sfd->socket.local, obj_get(sfd));

no_sfd:
if (good)
if (failed && c->timeout_mode == TIMEOUT_ANY)
goto next;

check = rtpe_config.timeout;
tmp_t_reason = TIMEOUT;
if (!MEDIA_ISSET(ps->media, RECV) || !sfd) {
if (!MEDIA_ISSET(ps->media, RECV) || !sfd || !MEDIA_ISSET(ps->media, SEND)) {
check = rtpe_config.silent_timeout;
tmp_t_reason = SILENT_TIMEOUT;
}
Expand All @@ -230,8 +247,14 @@ static void call_timer_iterator(struct call *c, struct iterator_helper *hlp) {
tmp_t_reason = OFFER_TIMEOUT;
}

if (rtpe_now.tv_sec - atomic64_get(timestamp) < check)
if (rtpe_now.tv_sec - atomic64_get(timestamp) < check) {
ps->missed_packet_counter = 0;
good = true;
} else {
ps->missed_packet_counter++;
if (ps->missed_packet_counter > 2)
failed = true;
}

next:
;
Expand All @@ -243,7 +266,7 @@ static void call_timer_iterator(struct call *c, struct iterator_helper *hlp) {
hlp->transcoded_media++;
}

if (good || IS_FOREIGN_CALL(c)) {
if (!failed || (good && (c->timeout_mode == TIMEOUT_ALL)) || IS_FOREIGN_CALL(c)) {
goto out;
}

Expand Down Expand Up @@ -3418,6 +3441,8 @@ static struct call *call_create(const str *callid) {
c->created = rtpe_now;
c->dtls_cert = dtls_cert();
c->tos = rtpe_config.default_tos;
c->timeout_mode = rtpe_config.timeout_mode;
c->timeout_activated = rtpe_now.tv_sec;
if (rtpe_config.cpu_affinity)
c->cpu_affinity = call_socket_cpu_affinity++ % rtpe_config.cpu_affinity;
else
Expand Down Expand Up @@ -4022,6 +4047,7 @@ int call_delete_branch(const str *callid, const str *branch,
"(via-branch '" STR_FORMAT_M "') in %d seconds",
STR_FMT_M(&ml->tag), STR_FMT0_M(branch), delete_delay);
ml->deleted = rtpe_now.tv_sec + delete_delay;
ml->mark_deleted = 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not 100% sure, but could ml->deleted != 0 be used as a test for this instead of adding a new flag?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as i remember i first tried it this way but there was an issue with it but i currently don't know what it was.
I need to make some tests and see, if i can reproduce the issues i had.

if (!c->ml_deleted || c->ml_deleted > ml->deleted)
c->ml_deleted = ml->deleted;
}
Expand Down
41 changes: 41 additions & 0 deletions daemon/call_interfaces.c
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,26 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu
}
}

out->timeout_mode = TIMEOUT_DEFAULT;
if (bencode_dictionary_get_str(input, "timeout", &s)) {
switch (__csh_lookup(&s)) {
case CSH_LOOKUP("off"):
out->timeout_mode=TIMEOUT_OFF;
break;
case CSH_LOOKUP("multi"):
case CSH_LOOKUP("all"):
out->timeout_mode=TIMEOUT_ALL;
break;
case CSH_LOOKUP("any"):
case CSH_LOOKUP("single"):
out->timeout_mode=TIMEOUT_ANY;
break;
default:
ilog(LOG_WARN, "Unknown 'timeout' flag encountered: '"STR_FORMAT"'",
STR_FMT(&s));
}
}

call_ng_flags_list(out, input, "rtcp-mux", call_ng_flags_rtcp_mux, NULL);
call_ng_flags_list(out, input, "RTCP-mux", call_ng_flags_rtcp_mux, NULL);
call_ng_flags_list(out, input, "SDES", ng_sdes_option, NULL);
Expand Down Expand Up @@ -1503,6 +1523,27 @@ static const char *call_offer_answer_ng(struct ng_buffer *ngbuf, bencode_item_t
call->drop_traffic = 0;
}

switch (flags.timeout_mode) {
case TIMEOUT_DEFAULT:
// NO CHANGE
break;
case TIMEOUT_OFF:
ilog(LOG_INFO, "Disable RTP timeout monitoring");
call->timeout_mode = TIMEOUT_OFF;
call->timeout_activated = 0;
break;
case TIMEOUT_ANY:
ilog(LOG_INFO, "Activating RTP any timeout monitoring");
call->timeout_mode = TIMEOUT_ANY;
call->timeout_activated = rtpe_now.tv_sec + rtpe_config.timeout;
break;
case TIMEOUT_ALL:
ilog(LOG_INFO, "Activating RTP all timeout monitoring");
call->timeout_mode = TIMEOUT_ALL;
call->timeout_activated = rtpe_now.tv_sec + rtpe_config.timeout;
break;
}

int do_dequeue = 1;

ret = monologue_offer_answer(dialogue, &streams, &flags);
Expand Down
15 changes: 15 additions & 0 deletions daemon/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ static void options(int *argc, char ***argv) {
AUTO_CLEANUP_GBUF(dtmf_udp_ep);
AUTO_CLEANUP_GBUF(endpoint_learning);
AUTO_CLEANUP_GBUF(dtls_sig);
AUTO_CLEANUP_GBUF(timeout_mode);
double silence_detect = 0;
AUTO_CLEANUP_GVBUF(cn_payload);
AUTO_CLEANUP_GVBUF(dtx_cn_params);
Expand Down Expand Up @@ -460,6 +461,7 @@ static void options(int *argc, char ***argv) {
{ "silent-timeout",'s',0,G_OPTION_ARG_INT, &rtpe_config.silent_timeout,"RTP timeout for muted", "SECS" },
{ "final-timeout",'a',0,G_OPTION_ARG_INT, &rtpe_config.final_timeout, "Call timeout", "SECS" },
{ "offer-timeout",0,0, G_OPTION_ARG_INT, &rtpe_config.offer_timeout, "Timeout for incomplete one-sided calls", "SECS" },
{ "timeout-mode", 0, 0, G_OPTION_ARG_STRING, &timeout_mode, "Timeout Mode", "off|any|all" },
{ "port-min", 'm', 0, G_OPTION_ARG_INT, &rtpe_config.port_min, "Lowest port to use for RTP", "INT" },
{ "port-max", 'M', 0, G_OPTION_ARG_INT, &rtpe_config.port_max, "Highest port to use for RTP", "INT" },
{ "redis", 'r', 0, G_OPTION_ARG_STRING, &redisps, "Connect to Redis database", "[PW@]IP:PORT/INT" },
Expand Down Expand Up @@ -684,6 +686,19 @@ static void options(int *argc, char ***argv) {
if (rtpe_config.final_timeout <= 0)
rtpe_config.final_timeout = 0;

int to_config = TIMEOUT_ALL;
if (timeout_mode) {
if (!strcasecmp(timeout_mode, "all"))
to_config = TIMEOUT_ALL;
else if (!strcasecmp(timeout_mode, "any"))
to_config = TIMEOUT_ANY;
else if (!strcasecmp(timeout_mode, "off"))
to_config = TIMEOUT_OFF;
else
die("Invalid --timeout-mode option ('%s')", timeout_mode);
}
rtpe_config.timeout_mode = to_config;

if (redisps)
if (redis_ep_parse(&rtpe_config.redis_ep, &rtpe_config.redis_db, &rtpe_config.redis_auth, "RTPENGINE_REDIS_AUTH_PW", redisps))
die("Invalid Redis endpoint [IP:PORT/INT] '%s' (--redis)", redisps);
Expand Down
6 changes: 6 additions & 0 deletions include/call.h
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,8 @@ struct packet_stream {

/* in_lock must be held for SETTING these: */
volatile unsigned int ps_flags;

unsigned int missed_packet_counter;
};

/* protected by call->master_lock, except the RO elements */
Expand Down Expand Up @@ -441,6 +443,7 @@ struct call_monologue {
unsigned int silence_media:1;
unsigned int rec_forwarding:1;
unsigned int inject_dtmf:1;
unsigned int mark_deleted:1;
};

struct call_iterator_list {
Expand Down Expand Up @@ -546,6 +549,9 @@ struct call {
unsigned int foreign_media:1; // for calls taken over, tracks whether we have media
unsigned int disable_jb:1;
unsigned int debug:1;

int timeout_mode;
time_t timeout_activated;
};


Expand Down
6 changes: 6 additions & 0 deletions include/call_interfaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ struct sdp_ng_flags {
MEO_BKW,
MEO_BOTH,
} media_echo:3;
enum {
TIMEOUT_DEFAULT = 0,
TIMEOUT_OFF,
TIMEOUT_ALL,
TIMEOUT_ANY
} timeout_mode:2;
unsigned int asymmetric:1,
protocol_accept:1,
no_redis_update:1,
Expand Down
1 change: 1 addition & 0 deletions include/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ struct rtpengine_config {
int silent_timeout;
int final_timeout;
int offer_timeout;
int timeout_mode;
int delete_delay;
GQueue redis_subscribed_keyspaces;
int redis_expires_secs;
Expand Down