diff --git a/README.md b/README.md index 94e66c3ef..d06929d84 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,7 @@ option and which are reproduced below: -T, --tos=INT TOS value to set on streams -o, --timeout=SECS RTP timeout -s, --silent-timeout=SECS RTP timeout for muted + -a, --final-timeout=SECS Call timeout -p, --pidfile=FILE Write PID to file -f, --foreground Don't fork to background -m, --port-min=INT Lowest port to use for RTP @@ -292,6 +293,11 @@ The options are described in more detail below. Ditto as the `--timeout` option, but applies to muted or inactive media streams. Defaults to 3600 (one hour). +* -a, --final-timeout + + The number of seconds since call creation, after call is deleted. Useful for limiting the lifetime of a call. + This feature can be disabled by setting the parameter to 0. By default this timeout is disabled. + * -p, --pidfile Specifies a path and file name to write the daemon's PID number to. diff --git a/daemon/call.c b/daemon/call.c index a712634f1..2c897bd10 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -108,6 +108,7 @@ static const char * const __term_reason_texts[] = { [REGULAR] = "REGULAR", [FORCED] = "FORCED", [SILENT_TIMEOUT] = "SILENT_TIMEOUT", + [FINAL_TIMEOUT] = "FINAL_TIMEOUT", }; static const char * const __tag_type_texts[] = { [FROM_TAG] = "FROM_TAG", @@ -183,7 +184,7 @@ static void call_timer_iterator(void *key, void *val, void *ptr) { int good = 0; struct packet_stream *ps; struct stream_fd *sfd; - int tmp_t_reason=0; + int tmp_t_reason = UNKNOWN; struct call_monologue *ml; enum call_stream_state css; atomic64 *timestamp; @@ -192,6 +193,19 @@ static void call_timer_iterator(void *key, void *val, void *ptr) { log_info_call(c); cm = c->callmaster; + rwlock_lock_r(&cm->conf.config_lock); + + if (cm->conf.final_timeout && poller_now >= (c->created + cm->conf.final_timeout)) { + ilog(LOG_INFO, "Closing call due to final timeout"); + tmp_t_reason = FINAL_TIMEOUT; + for (it = c->monologues.head; it; it = it->next) { + ml = it->data; + gettimeofday(&(ml->terminated),NULL); + ml->term_reason = tmp_t_reason; + } + + goto delete; + } if (c->deleted && poller_now >= c->deleted && c->last_signal <= c->deleted) @@ -232,10 +246,10 @@ no_sfd: goto next; check = cm->conf.timeout; - tmp_t_reason = 1; + tmp_t_reason = TIMEOUT; if (!MEDIA_ISSET(ps->media, RECV) || !sfd || !PS_ISSET(ps, FILLED)) { check = cm->conf.silent_timeout; - tmp_t_reason = 2; + tmp_t_reason = SILENT_TIMEOUT; } if (poller_now - atomic64_get(timestamp) < check) @@ -254,13 +268,7 @@ next: for (it = c->monologues.head; it; it = it->next) { ml = it->data; gettimeofday(&(ml->terminated),NULL); - if (tmp_t_reason==1) { - ml->term_reason = TIMEOUT; - } else if (tmp_t_reason==2) { - ml->term_reason = SILENT_TIMEOUT; - } else { - ml->term_reason = UNKNOWN; - } + ml->term_reason = tmp_t_reason; } ilog(LOG_INFO, "Closing call due to timeout"); @@ -274,6 +282,7 @@ delete: goto out; out: + rwlock_unlock_r(&cm->conf.config_lock); rwlock_unlock_r(&c->master_lock); log_info_clear(); } @@ -2123,6 +2132,11 @@ void call_destroy(struct call *c) { timeval_totalstats_average_add(&m->totalstats_interval, &tim_result_duration); timeval_totalstats_interval_call_duration_add(&m->totalstats_interval, &ml->started, &g_now, &m->latest_graphite_interval_start); + + if (ml->term_reason==FINAL_TIMEOUT) { + atomic64_inc(&m->totalstats.total_final_timeout_sess); + atomic64_inc(&m->totalstats_interval.total_final_timeout_sess); + } } diff --git a/daemon/call.h b/daemon/call.h index 1b9d1b656..64cf0b8e8 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -35,7 +35,8 @@ enum termination_reason { REGULAR=1, FORCED=2, TIMEOUT=3, - SILENT_TIMEOUT=4 + SILENT_TIMEOUT=4, + FINAL_TIMEOUT=5 }; enum tag_type { @@ -245,6 +246,7 @@ struct totalstats { atomic64 total_timeout_sess; atomic64 total_rejected_sess; atomic64 total_silent_timeout_sess; + atomic64 total_final_timeout_sess; atomic64 total_regular_term_sess; atomic64 total_forced_term_sess; atomic64 total_relayed_packets; @@ -430,9 +432,14 @@ struct call { struct callmaster_config { int kernelfd; int kernelid; + + /* everything below protected by config_lock */ + rwlock_t config_lock; int max_sessions; unsigned int timeout; unsigned int silent_timeout; + unsigned int final_timeout; + unsigned int delete_delay; struct redis *redis; struct redis *redis_write; diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 224649c13..fef37168d 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -388,10 +388,12 @@ str *call_query_udp(char **out, struct callmaster *m) { rwlock_unlock_w(&c->master_lock); + rwlock_lock_r(&m->conf.config_lock); ret = str_sprintf("%s %lld "UINT64F" "UINT64F" "UINT64F" "UINT64F"\n", out[RE_UDP_COOKIE], (long long int) m->conf.silent_timeout - (poller_now - stats.last_packet), atomic64_get_na(&stats.totals[0].packets), atomic64_get_na(&stats.totals[1].packets), atomic64_get_na(&stats.totals[2].packets), atomic64_get_na(&stats.totals[3].packets)); + rwlock_unlock_r(&m->conf.config_lock); goto out; err: @@ -743,6 +745,7 @@ out: const char *call_offer_ng(bencode_item_t *input, struct callmaster *m, bencode_item_t *output, const char* addr, const endpoint_t *sin) { + rwlock_lock_r(&m->conf.config_lock); if (m->conf.max_sessions>=0) { rwlock_lock_r(&m->hashlock); if (g_hash_table_size(m->callhash) >= m->conf.max_sessions) { @@ -750,10 +753,14 @@ const char *call_offer_ng(bencode_item_t *input, struct callmaster *m, bencode_i atomic64_inc(&m->totalstats.total_rejected_sess); atomic64_inc(&m->totalstats_interval.total_rejected_sess); ilog(LOG_ERROR, "Parallel session limit reached (%i)",m->conf.max_sessions); + + rwlock_unlock_r(&m->conf.config_lock); return "Parallel session limit reached"; } rwlock_unlock_r(&m->hashlock); } + + rwlock_unlock_r(&m->conf.config_lock); return call_offer_answer_ng(input, m, output, OP_OFFER, addr, sin); } diff --git a/daemon/cli.c b/daemon/cli.c index f07d34423..68bfe9967 100644 --- a/daemon/cli.c +++ b/daemon/cli.c @@ -40,6 +40,8 @@ static void cli_incoming_list_totals(char* buffer, int len, struct callmaster* m ADJUSTLEN(printlen,outbufend,replybuffer); printlen = snprintf(replybuffer,(outbufend-replybuffer), " Total timed-out sessions via SILENT_TIMEOUT :"UINT64F"\n",atomic64_get(&m->totalstats.total_silent_timeout_sess)); ADJUSTLEN(printlen,outbufend,replybuffer); + printlen = snprintf(replybuffer,(outbufend-replybuffer), " Total timed-out sessions via FINAL_TIMEOUT :"UINT64F"\n",atomic64_get(&m->totalstats.total_final_timeout_sess)); + ADJUSTLEN(printlen,outbufend,replybuffer); printlen = snprintf(replybuffer,(outbufend-replybuffer), " Total regular terminated sessions :"UINT64F"\n",atomic64_get(&m->totalstats.total_regular_term_sess)); ADJUSTLEN(printlen,outbufend,replybuffer); printlen = snprintf(replybuffer,(outbufend-replybuffer), " Total forced terminated sessions :"UINT64F"\n",atomic64_get(&m->totalstats.total_forced_term_sess)); @@ -160,6 +162,24 @@ static void cli_incoming_list_maxopenfiles(char* buffer, int len, struct callmas return ; } +static void cli_incoming_list_timeout(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend) { + int printlen=0; + + rwlock_lock_r(&m->conf.config_lock); + + /* don't lock anything while reading the value */ + printlen = snprintf(replybuffer,(outbufend-replybuffer), "TIMEOUT=%u\n", m->conf.timeout); + ADJUSTLEN(printlen,outbufend,replybuffer); + printlen = snprintf(replybuffer,(outbufend-replybuffer), "SILENT_TIMEOUT=%u\n", m->conf.silent_timeout); + ADJUSTLEN(printlen,outbufend,replybuffer); + printlen = snprintf(replybuffer,(outbufend-replybuffer), "FINAL_TIMEOUT=%u\n", m->conf.final_timeout); + ADJUSTLEN(printlen,outbufend,replybuffer); + + rwlock_unlock_r(&m->conf.config_lock); + + return ; +} + static void cli_incoming_list_callid(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend) { str callid; struct call* c=0; @@ -273,11 +293,12 @@ static void cli_incoming_set_maxopenfiles(char* buffer, int len, struct callmast unsigned int open_files_num; str open_files; pid_t pid; + char *endptr; // limit the minimum number of open files to avoid rtpengine freeze for low open_files_num values unsigned int min_open_files_num = (1 << 16); - if (len<=1) { + if (len <= 1) { printlen = snprintf(replybuffer,(outbufend-replybuffer), "%s\n", "More parameters required."); ADJUSTLEN(printlen,outbufend,replybuffer); return; @@ -286,23 +307,27 @@ static void cli_incoming_set_maxopenfiles(char* buffer, int len, struct callmast ++buffer; --len; // one space open_files.s = buffer; open_files.len = len; - open_files_num = str_to_ui(&open_files, -1); + open_files_num = strtol(open_files.s, &endptr, 10); - if (open_files_num == -1) { - printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting open_files to %.*s; not an unsigned integer\n", open_files.len, open_files.s); + if ((errno == ERANGE && (open_files_num == LONG_MAX || open_files_num == LONG_MIN)) || (errno != 0 && open_files_num == 0)) { + printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting open_files to %.*s; errno=%d\n", open_files.len, open_files.s, errno); + ADJUSTLEN(printlen,outbufend,replybuffer); + return; + } else if (endptr == open_files.s) { + printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting open_files to %.*s; no digists found\n", open_files.len, open_files.s); ADJUSTLEN(printlen,outbufend,replybuffer); return; } else if (open_files_num < min_open_files_num) { - printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting open_files to %.*s; can't set it under %u\n", open_files.len, open_files.s, min_open_files_num); + printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting open_files to %u; can't set it under %u\n", open_files_num, min_open_files_num); ADJUSTLEN(printlen,outbufend,replybuffer); return; } else if (rlim(RLIMIT_NOFILE, open_files_num) == -1){ - printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting open_files to %.*s; errno = %d\n", open_files.len, open_files.s, errno); + printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting open_files to %u; errno = %d\n", open_files_num, errno); ADJUSTLEN(printlen,outbufend,replybuffer); return; } else { pid = getpid(); - printlen = snprintf (replybuffer,(outbufend-replybuffer), "Success setting open_files to %.*s; cat /proc/%u/limits\n", open_files.len, open_files.s, pid); + printlen = snprintf (replybuffer,(outbufend-replybuffer), "Success setting open_files to %u; cat /proc/%u/limits\n", open_files_num, pid); ADJUSTLEN(printlen,outbufend,replybuffer); } } @@ -310,11 +335,11 @@ static void cli_incoming_set_maxopenfiles(char* buffer, int len, struct callmast static void cli_incoming_set_maxsessions(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend) { int printlen = 0; int maxsessions_num; - int err = 0x80000000; int disabled = -1; str maxsessions; + char *endptr; - if (len<=1) { + if (len <= 1) { printlen = snprintf(replybuffer,(outbufend-replybuffer), "%s\n", "More parameters required."); ADJUSTLEN(printlen,outbufend,replybuffer); return; @@ -323,22 +348,29 @@ static void cli_incoming_set_maxsessions(char* buffer, int len, struct callmaste ++buffer; --len; // one space maxsessions.s = buffer; maxsessions.len = len; - maxsessions_num = str_to_i(&maxsessions, err); + maxsessions_num = strtol(maxsessions.s, &endptr, 10); - if (maxsessions_num == err) { - printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting maxsessions to %.*s; not an integer\n", maxsessions.len, maxsessions.s); + if ((errno == ERANGE && (maxsessions_num == LONG_MAX || maxsessions_num == LONG_MIN)) || (errno != 0 && maxsessions_num == 0)) { + printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting maxsessions to %.*s; errno=%d\n", maxsessions.len, maxsessions.s, errno); + ADJUSTLEN(printlen,outbufend,replybuffer); + return; + } else if (endptr == maxsessions.s) { + printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting maxsessions to %.*s; no digists found\n", maxsessions.len, maxsessions.s); ADJUSTLEN(printlen,outbufend,replybuffer); + return; } else if (maxsessions_num < disabled) { printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting maxsessions to %d; either positive or -1 values allowed\n", maxsessions_num); ADJUSTLEN(printlen,outbufend,replybuffer); } else if (maxsessions_num == disabled) { - /* don't lock anything while writing the value - only this command modifies its value */ + rwlock_lock_w(&m->conf.config_lock); m->conf.max_sessions = maxsessions_num; + rwlock_unlock_w(&m->conf.config_lock); printlen = snprintf (replybuffer,(outbufend-replybuffer), "Success setting maxsessions to %d; disable feature\n", maxsessions_num); ADJUSTLEN(printlen,outbufend,replybuffer); } else { - /* don't lock anything while writing the value - only this command modifies its value */ + rwlock_lock_w(&m->conf.config_lock); m->conf.max_sessions = maxsessions_num; + rwlock_unlock_w(&m->conf.config_lock); printlen = snprintf (replybuffer,(outbufend-replybuffer), "Success setting maxsessions to %d\n", maxsessions_num); ADJUSTLEN(printlen,outbufend,replybuffer); } @@ -346,6 +378,41 @@ static void cli_incoming_set_maxsessions(char* buffer, int len, struct callmaste return; } +static void cli_incoming_set_timeout(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend, unsigned int *conf_timeout) { + int printlen = 0; + unsigned int timeout_num; + str timeout; + char *endptr; + + if (len <= 1) { + printlen = snprintf(replybuffer,(outbufend-replybuffer), "%s\n", "More parameters required."); + ADJUSTLEN(printlen,outbufend,replybuffer); + return; + } + + ++buffer; --len; // one space + timeout.s = buffer; + timeout.len = len; + timeout_num = strtol(timeout.s, &endptr, 10); + + if ((errno == ERANGE && (timeout_num == LONG_MAX || timeout_num == LONG_MIN)) || (errno != 0 && timeout_num == 0)) { + printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting timeout to %.*s; errno=%d\n", timeout.len, timeout.s, errno); + ADJUSTLEN(printlen,outbufend,replybuffer); + return; + } else if (endptr == timeout.s) { + printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting timeout to %.*s; no digists found\n", timeout.len, timeout.s); + ADJUSTLEN(printlen,outbufend,replybuffer); + return; + } else { + /* don't lock anything while writing the value - only this command modifies its value */ + rwlock_lock_w(&m->conf.config_lock); + *conf_timeout = timeout_num; + rwlock_unlock_w(&m->conf.config_lock); + printlen = snprintf (replybuffer,(outbufend-replybuffer), "Success setting timeout to %u\n", timeout_num); + ADJUSTLEN(printlen,outbufend,replybuffer); + } +} + static void cli_incoming_list(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend) { GHashTableIter iter; gpointer key, value; @@ -359,6 +426,7 @@ static void cli_incoming_list(char* buffer, int len, struct callmaster* m, char* static const char* LIST_TOTALS = "totals"; static const char* LIST_MAX_OPEN_FILES = "maxopenfiles"; static const char* LIST_MAX_SESSIONS = "maxsessions"; + static const char* LIST_TIMEOUT = "timeout"; if (len<=1) { printlen = snprintf(replybuffer, outbufend-replybuffer, "%s\n", "More parameters required."); @@ -396,6 +464,8 @@ static void cli_incoming_list(char* buffer, int len, struct callmaster* m, char* cli_incoming_list_maxsessions(buffer+strlen(LIST_MAX_SESSIONS), len-strlen(LIST_MAX_SESSIONS), m, replybuffer, outbufend); } else if (len>=strlen(LIST_MAX_OPEN_FILES) && strncmp(buffer,LIST_MAX_OPEN_FILES,strlen(LIST_MAX_OPEN_FILES)) == 0) { cli_incoming_list_maxopenfiles(buffer+strlen(LIST_MAX_OPEN_FILES), len-strlen(LIST_MAX_OPEN_FILES), m, replybuffer, outbufend); + } else if (len>=strlen(LIST_TIMEOUT) && strncmp(buffer,LIST_TIMEOUT,strlen(LIST_TIMEOUT)) == 0) { + cli_incoming_list_timeout(buffer+strlen(LIST_TIMEOUT), len-strlen(LIST_TIMEOUT), m, replybuffer, outbufend); } else { printlen = snprintf(replybuffer, outbufend-replybuffer, "%s:%s\n", "Unknown 'list' command", buffer); ADJUSTLEN(printlen,outbufend,replybuffer); @@ -407,6 +477,9 @@ static void cli_incoming_set(char* buffer, int len, struct callmaster* m, char* static const char* SET_MAX_OPEN_FILES = "maxopenfiles"; static const char* SET_MAX_SESSIONS = "maxsessions"; + static const char* SET_TIMEOUT = "timeout"; + static const char* SET_SILENT_TIMEOUT = "silenttimeout"; + static const char* SET_FINAL_TIMEOUT = "finaltimeout"; if (len<=1) { printlen = snprintf(replybuffer, outbufend-replybuffer, "%s\n", "More parameters required."); @@ -419,6 +492,12 @@ static void cli_incoming_set(char* buffer, int len, struct callmaster* m, char* cli_incoming_set_maxopenfiles(buffer+strlen(SET_MAX_OPEN_FILES), len-strlen(SET_MAX_OPEN_FILES), m, replybuffer, outbufend); } else if (len>=strlen(SET_MAX_SESSIONS) && strncmp(buffer,SET_MAX_SESSIONS,strlen(SET_MAX_SESSIONS)) == 0) { cli_incoming_set_maxsessions(buffer+strlen(SET_MAX_SESSIONS), len-strlen(SET_MAX_SESSIONS), m, replybuffer, outbufend); + } else if (len>=strlen(SET_TIMEOUT) && strncmp(buffer,SET_TIMEOUT,strlen(SET_TIMEOUT)) == 0) { + cli_incoming_set_timeout(buffer+strlen(SET_TIMEOUT), len-strlen(SET_TIMEOUT), m, replybuffer, outbufend, &m->conf.timeout); + } else if (len>=strlen(SET_SILENT_TIMEOUT) && strncmp(buffer,SET_SILENT_TIMEOUT,strlen(SET_SILENT_TIMEOUT)) == 0) { + cli_incoming_set_timeout(buffer+strlen(SET_SILENT_TIMEOUT), len-strlen(SET_SILENT_TIMEOUT), m, replybuffer, outbufend, &m->conf.silent_timeout); + } else if (len>=strlen(SET_FINAL_TIMEOUT) && strncmp(buffer,SET_FINAL_TIMEOUT,strlen(SET_FINAL_TIMEOUT)) == 0) { + cli_incoming_set_timeout(buffer+strlen(SET_FINAL_TIMEOUT), len-strlen(SET_FINAL_TIMEOUT), m, replybuffer, outbufend, &m->conf.final_timeout); } else { printlen = snprintf(replybuffer, outbufend-replybuffer, "%s:%s\n", "Unknown 'set' command", buffer); ADJUSTLEN(printlen,outbufend,replybuffer); diff --git a/daemon/graphite.c b/daemon/graphite.c index 74407fbba..dd798b0ea 100644 --- a/daemon/graphite.c +++ b/daemon/graphite.c @@ -104,6 +104,7 @@ int send_graphite_data(struct callmaster *cm, struct totalstats *sent_data) { atomic64_local_copy_zero_struct(ts, &cm->totalstats_interval, total_timeout_sess); atomic64_local_copy_zero_struct(ts, &cm->totalstats_interval, total_rejected_sess); atomic64_local_copy_zero_struct(ts, &cm->totalstats_interval, total_silent_timeout_sess); + atomic64_local_copy_zero_struct(ts, &cm->totalstats_interval, total_final_timeout_sess); atomic64_local_copy_zero_struct(ts, &cm->totalstats_interval, total_regular_term_sess); atomic64_local_copy_zero_struct(ts, &cm->totalstats_interval, total_forced_term_sess); atomic64_local_copy_zero_struct(ts, &cm->totalstats_interval, total_relayed_packets); @@ -189,6 +190,8 @@ int send_graphite_data(struct callmaster *cm, struct totalstats *sent_data) { if (graphite_prefix!=NULL) { rc = sprintf(ptr,"%s",graphite_prefix); ptr += rc; } rc = sprintf(ptr,"silent_timeout_sess "UINT64F" %llu\n", atomic64_get_na(&ts->total_silent_timeout_sess),(unsigned long long)g_now.tv_sec); ptr += rc; if (graphite_prefix!=NULL) { rc = sprintf(ptr,"%s",graphite_prefix); ptr += rc; } + rc = sprintf(ptr,"final_timeout_sess "UINT64F" %llu\n", atomic64_get_na(&ts->total_final_timeout_sess),(unsigned long long)g_now.tv_sec); ptr += rc; + if (graphite_prefix!=NULL) { rc = sprintf(ptr,"%s",graphite_prefix); ptr += rc; } rc = sprintf(ptr,"timeout_sess "UINT64F" %llu\n", atomic64_get_na(&ts->total_timeout_sess),(unsigned long long)g_now.tv_sec); ptr += rc; if (graphite_prefix!=NULL) { rc = sprintf(ptr,"%s",graphite_prefix); ptr += rc; } rc = sprintf(ptr,"reject_sess "UINT64F" %llu\n", atomic64_get_na(&ts->total_rejected_sess),(unsigned long long)g_now.tv_sec); ptr += rc; diff --git a/daemon/main.c b/daemon/main.c index e16b6a0dc..4b1b56f50 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -64,8 +64,9 @@ endpoint_t redis_write_ep; static int tos; static int table = -1; static int no_fallback; -static int timeout; -static int silent_timeout; +static unsigned int timeout; +static unsigned int silent_timeout; +static unsigned int final_timeout; static int port_min = 30000; static int port_max = 40000; static int max_sessions = -1; @@ -285,6 +286,7 @@ static void options(int *argc, char ***argv) { { "tos", 'T', 0, G_OPTION_ARG_INT, &tos, "Default TOS value to set on streams", "INT" }, { "timeout", 'o', 0, G_OPTION_ARG_INT, &timeout, "RTP timeout", "SECS" }, { "silent-timeout",'s',0,G_OPTION_ARG_INT, &silent_timeout,"RTP timeout for muted", "SECS" }, + { "final-timeout",'a',0,G_OPTION_ARG_INT, &final_timeout, "Call timeout", "SECS" }, { "pidfile", 'p', 0, G_OPTION_ARG_FILENAME, &pidfile, "Write PID to file", "FILE" }, { "foreground", 'f', 0, G_OPTION_ARG_NONE, &foreground, "Don't fork to background", NULL }, { "port-min", 'm', 0, G_OPTION_ARG_INT, &port_min, "Lowest port to use for RTP", "INT" }, @@ -360,9 +362,13 @@ static void options(int *argc, char ***argv) { if (timeout <= 0) timeout = 60; + if (silent_timeout <= 0) silent_timeout = 3600; + if (final_timeout <= 0) + final_timeout = 0; + if (redisps) if (redis_ep_parse(&redis_ep, &redis_db, &redis_auth, "RTPENGINE_REDIS_AUTH_PW", redisps)) die("Invalid Redis endpoint [IP:PORT/INT] (--redis)"); @@ -528,6 +534,7 @@ no_kernel: dtls_timer(ctx->p); ZERO(mc); + rwlock_init(&mc.config_lock); mc.kernelfd = kfd; mc.kernelid = table; if (max_sessions < -1) { @@ -536,6 +543,7 @@ no_kernel: mc.max_sessions = max_sessions; mc.timeout = timeout; mc.silent_timeout = silent_timeout; + mc.final_timeout = final_timeout; mc.delete_delay = delete_delay; mc.default_tos = tos; mc.b2b_url = b2b_url; diff --git a/debian/ngcp-rtpengine-daemon.default b/debian/ngcp-rtpengine-daemon.default index 161088ed8..a296a9c88 100644 --- a/debian/ngcp-rtpengine-daemon.default +++ b/debian/ngcp-rtpengine-daemon.default @@ -8,6 +8,7 @@ LISTEN_CLI=9900 # INTERFACES="12.23.34.45!23.34.45.56" TIMEOUT=60 SILENT_TIMEOUT=3600 +# FINAL_TIMEOUT=10800 PIDFILE=/var/run/ngcp-rtpengine-daemon.pid FORK=yes # TOS=184 diff --git a/debian/ngcp-rtpengine-daemon.init b/debian/ngcp-rtpengine-daemon.init index 5bf1e891f..f9a193d2d 100755 --- a/debian/ngcp-rtpengine-daemon.init +++ b/debian/ngcp-rtpengine-daemon.init @@ -58,6 +58,7 @@ fi [ -z "$LISTEN_CLI" ] || OPTIONS="$OPTIONS --listen-cli=$LISTEN_CLI" [ -z "$TIMEOUT" ] || OPTIONS="$OPTIONS --timeout=$TIMEOUT" [ -z "$SILENT_TIMEOUT" ] || OPTIONS="$OPTIONS --silent-timeout=$SILENT_TIMEOUT" +[ -z "$FINAL_TIMEOUT" ] || OPTIONS="$OPTIONS --final-timeout=$FINAL_TIMEOUT" [ -z "$PIDFILE" ] || OPTIONS="$OPTIONS --pidfile=$PIDFILE" [ -z "$TOS" ] || OPTIONS="$OPTIONS --tos=$TOS" [ -z "$PORT_MIN" ] || OPTIONS="$OPTIONS --port-min=$PORT_MIN" diff --git a/utils/rtpengine-ctl b/utils/rtpengine-ctl index 3959bc3e7..161de4eae 100755 --- a/utils/rtpengine-ctl +++ b/utils/rtpengine-ctl @@ -62,21 +62,25 @@ sub showusage { print "\n"; print " Supported commands are:\n"; print "\n"; - print " list [ numsessions | maxsessions | maxopenfiles | sessions | session | totals ]\n"; + print " list [ numsessions | maxsessions | maxopenfiles | sessions | session | totals | timeout ]\n"; print " numsessions : print the number of sessions\n"; print " maxsessions : print the number of allowed sessions\n"; print " maxopenfiles : print the number of allowed open files\n"; print " sessions : print one-liner session information\n"; print " session : print detail about one session\n"; print " totals : print total statistics\n"; + print " timeout : print timout parameters\n"; print "\n"; print " terminate [ all | ]\n"; print " all : terminates all current sessions\n"; print " : session is immediately terminated\n"; print "\n"; - print " set [ maxopenfiles | maxsessions ]\n"; + print " set [ maxsessions | maxopenfiles | timeout | silent_timeout | final_timeout ]\n"; print " maxsessions : set the max nr of allowed sessions\n"; print " maxopenfiles : set the max nr of allowed open files\n"; + print " timeout : set the --timeout parameter \n"; + print " silenttimeout : set the --silent-timeout parameter \n"; + print " finaltimeout : set the --final-timeout parameter \n"; print "\n"; print "\n"; print " Return Value:\n";