From b4a66530d3c5ffe59feda36427422e6110a4279c Mon Sep 17 00:00:00 2001 From: Michael Prokop Date: Tue, 23 Feb 2016 16:35:17 +0100 Subject: [PATCH 01/13] MT#17699 Fix m-a build error + Bump Standards-Version for ngcp-rtpengine-kernel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Noticed during lintian reviews + test builds of ngcp-rtpengine-kernel, STR: * Install ngcp-rtpengine-kernel-source + module-assistant * m-a build ngcp-rtpengine-kernel fails with: | tail: cannot open ‘/usr/src/modules/ngcp-rtpengine/../debian/changelog’ for reading: No such file or directory | dpkg-parsechangelog: error: tail of /usr/src/modules/ngcp-rtpengine/../debian/changelog gave error exit status 1 | Building modules, stage 2. | MODPOST 1 modules | tail: cannot open ‘/usr/src/modules/ngcp-rtpengine/../debian/changelog’ for reading: No such file or directory Fix conflicts: | dh_gencontrol -- -v4.3.0.0+0~mr4.3.0.0+0~20160223155548.661+jessie~1.gbp6d1932+3.16.7-ckt20-1+deb8u3 | dpkg-gencontrol: error: source package has two conflicting values - ngcp-rtpengine-kernel and ngcp-rtpengine | dh_gencontrol: dpkg-gencontrol -pngcp-rtpengine-kernel-modules-3.16.0-4-amd64 -ldebian/changelog -Tdebian/ngcp-rtpengine-kernel-modules-3.16.0-4-amd64.substvars -Pdebian/ngcp-rtpengine-kernel-modules-3.16.0-4-amd64 -v4.3.0.0+0~mr4.3.0.0+0~20160223155548.661+jessie~1.gbp6d1932+3.16.7-ckt20-1+deb8u3 returned exit code 255 | debian/rules:58: recipe for target 'binary-modules' failed While at it Bump Standards-Version for ngcp-rtpengine-kernel to 3.9.7 (no further changes) and fix package description. Change-Id: Iaf7326f55cd3919afdb140d8e7acb5d3ff87b7d9 --- debian/control.modules.in | 6 +++--- kernel-module/Makefile | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/debian/control.modules.in b/debian/control.modules.in index d7264a207..a69488ef5 100644 --- a/debian/control.modules.in +++ b/debian/control.modules.in @@ -1,15 +1,15 @@ -Source: ngcp-rtpengine-kernel +Source: ngcp-rtpengine Section: kernel Priority: optional Maintainer: Sipwise Development Team Build-Depends: debhelper (>= 5) -Standards-Version: 3.9.3 +Standards-Version: 3.9.7 Homepage: http://sipwise.com/ Package: ngcp-rtpengine-kernel-modules-_KVERS_ Architecture: any Depends: linux-modules-_KVERS_ | linux-image-_KVERS_ Provides: ngcp-rtpengine-kernel -Description: TODO +Description: IPtables kernel module for the NGCP media proxy This package provides the ngcp-rtpengine module for the Linux kernel version _KVERS_. diff --git a/kernel-module/Makefile b/kernel-module/Makefile index 0df3f0f6d..1c4ccc365 100644 --- a/kernel-module/Makefile +++ b/kernel-module/Makefile @@ -7,7 +7,7 @@ ifneq ($(RTPENGINE_VERSION),) else DPKG_PRSCHNGLG= $(shell which dpkg-parsechangelog 2>/dev/null) ifneq ($(DPKG_PRSCHNGLG),) - EXTRA_CFLAGS += -DRTPENGINE_VERSION="\"$(shell dpkg-parsechangelog -l$(M)/../debian/changelog | awk '/^Version: / {print $$2}')\"" + EXTRA_CFLAGS += -DRTPENGINE_VERSION="\"$(shell dpkg-parsechangelog -l$(M)/debian/changelog | awk '/^Version: / {print $$2}')\"" else EXTRA_CFLAGS += -DRTPENGINE_VERSION="\"undefined\"" endif From a6b4b869835fce3602a3179050f404fdf7333dc6 Mon Sep 17 00:00:00 2001 From: smititelu Date: Wed, 24 Feb 2016 09:15:27 +0100 Subject: [PATCH 02/13] Fix segfault when ps->component=0 --- daemon/call.c | 1 + 1 file changed, 1 insertion(+) diff --git a/daemon/call.c b/daemon/call.c index f4eb3fe71..252b2c633 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -781,6 +781,7 @@ static void __assign_stream_fds(struct call_media *media, GQueue *intf_sfds) { il = l->data; sfd = g_queue_peek_nth(&il->list, ps->component - 1); + if (!sfd) return ; sfd->stream = ps; g_queue_push_tail(&ps->sfds, sfd); From 5e7640b4c4b8fee48f1494436ef7ac1918837b48 Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Wed, 24 Feb 2016 10:41:10 +0100 Subject: [PATCH 03/13] Add/Retrieve ps->component to/from redis Avoid segfault that happened when ps->component=0 (only when redis involved). If redis involved, ps structure is initially 0'ed before restoring. Currently the ps->component is not restored and leads to the above segfault. --- daemon/redis.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/daemon/redis.c b/daemon/redis.c index cb1b674f4..d0ba67c33 100644 --- a/daemon/redis.c +++ b/daemon/redis.c @@ -674,6 +674,8 @@ static int redis_streams(struct call *c, struct redis_list *streams) { atomic64_set_na(&ps->last_packet, time(NULL)); if (redis_hash_get_unsigned((unsigned int *) &ps->ps_flags, rh, "ps_flags")) return -1; + if (redis_hash_get_unsigned((unsigned int *) &ps->component, rh, "component")) + return -1; if (redis_hash_get_endpoint(&ps->endpoint, rh, "endpoint")) return -1; if (redis_hash_get_endpoint(&ps->advertised_endpoint, rh, "advertised_endpoint")) @@ -1318,7 +1320,7 @@ void redis_update(struct call *c, struct redis *r) { redis_pipe(r, "HMSET stream-"PB"-%u media %u sfd %u rtp_sink %u " "rtcp_sink %u rtcp_sibling %u last_packet "UINT64F" " - "ps_flags %u", + "ps_flags %u component %u", STR(&c->callid), ps->unique_id, ps->media->unique_id, ps->selected_sfd ? ps->selected_sfd->unique_id : -1, @@ -1326,7 +1328,8 @@ void redis_update(struct call *c, struct redis *r) { ps->rtcp_sink ? ps->rtcp_sink->unique_id : -1, ps->rtcp_sibling ? ps->rtcp_sibling->unique_id : -1, atomic64_get(&ps->last_packet), - ps->ps_flags); + ps->ps_flags, + ps->component); redis_update_endpoint(r, "stream", &c->callid, ps->unique_id, "endpoint", &ps->endpoint); redis_update_endpoint(r, "stream", &c->callid, ps->unique_id, "advertised_endpoint", &ps->advertised_endpoint); From c4f630ccfa794b91417b4b010e26fee9054f9cbc Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Tue, 1 Mar 2016 09:41:18 -0500 Subject: [PATCH 04/13] fix kernel module build for 4.4+ kernels fixes #224 Change-Id: I8bc3590858ff3819b058a586d17556d5375ddc07 --- kernel-module/xt_RTPENGINE.c | 44 +++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/kernel-module/xt_RTPENGINE.c b/kernel-module/xt_RTPENGINE.c index 7fffaf11f..8e0f47b8d 100644 --- a/kernel-module/xt_RTPENGINE.c +++ b/kernel-module/xt_RTPENGINE.c @@ -1939,7 +1939,9 @@ err: -static int send_proxy_packet4(struct sk_buff *skb, struct re_address *src, struct re_address *dst, unsigned char tos) { +static int send_proxy_packet4(struct sk_buff *skb, struct re_address *src, struct re_address *dst, + unsigned char tos, const struct xt_action_param *par) +{ struct iphdr *ih; struct udphdr *uh; unsigned int datalen; @@ -1977,12 +1979,20 @@ static int send_proxy_packet4(struct sk_buff *skb, struct re_address *src, struc uh->check = CSUM_MANGLED_0; skb->protocol = htons(ETH_P_IP); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) + if (ip_route_me_harder(par->net, skb, RTN_UNSPEC)) +#else if (ip_route_me_harder(skb, RTN_UNSPEC)) +#endif goto drop; skb->ip_summed = CHECKSUM_NONE; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) + ip_local_out(par->net, skb->sk, skb); +#else ip_local_out(skb); +#endif return 0; @@ -1995,7 +2005,9 @@ drop: -static int send_proxy_packet6(struct sk_buff *skb, struct re_address *src, struct re_address *dst, unsigned char tos) { +static int send_proxy_packet6(struct sk_buff *skb, struct re_address *src, struct re_address *dst, + unsigned char tos, const struct xt_action_param *par) +{ struct ipv6hdr *ih; struct udphdr *uh; unsigned int datalen; @@ -2033,12 +2045,20 @@ static int send_proxy_packet6(struct sk_buff *skb, struct re_address *src, struc uh->check = CSUM_MANGLED_0; skb->protocol = htons(ETH_P_IPV6); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) + if (ip6_route_me_harder(par->net, skb)) +#else if (ip6_route_me_harder(skb)) +#endif goto drop; skb->ip_summed = CHECKSUM_NONE; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) + ip6_local_out(par->net, skb->sk, skb); +#else ip6_local_out(skb); +#endif return 0; @@ -2050,18 +2070,19 @@ drop: -static int send_proxy_packet(struct sk_buff *skb, struct re_address *src, struct re_address *dst, unsigned char tos) { +static int send_proxy_packet(struct sk_buff *skb, struct re_address *src, struct re_address *dst, + unsigned char tos, const struct xt_action_param *par) { if (src->family != dst->family) goto drop; switch (src->family) { case AF_INET: - return send_proxy_packet4(skb, src, dst, tos); + return send_proxy_packet4(skb, src, dst, tos, par); break; case AF_INET6: - return send_proxy_packet6(skb, src, dst, tos); + return send_proxy_packet6(skb, src, dst, tos, par); break; default: @@ -2429,7 +2450,7 @@ static inline int rtp_payload_type(const struct rtp_header *hdr, const struct rt #endif static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, struct re_address *src, - struct re_address *dst, u_int8_t in_tos) + struct re_address *dst, u_int8_t in_tos, const struct xt_action_param *par) { struct udphdr *uh; struct rtpengine_target *g; @@ -2543,7 +2564,8 @@ not_rtp: if (g->target.mirror_addr.family) { DBG("sending mirror packet to dst "MIPF"\n", MIPP(g->target.mirror_addr)); skb2 = skb_copy(skb, GFP_ATOMIC); - err = send_proxy_packet(skb2, &g->target.src_addr, &g->target.mirror_addr, g->target.tos); + err = send_proxy_packet(skb2, &g->target.src_addr, &g->target.mirror_addr, g->target.tos, + par); if (err) atomic64_inc(&g->stats.errors); } @@ -2555,7 +2577,7 @@ not_rtp: srtp_authenticate(&g->encrypt, &g->target.encrypt, &rtp, pkt_idx); } - err = send_proxy_packet(skb, &g->target.src_addr, &g->target.dst_addr, g->target.tos); + err = send_proxy_packet(skb, &g->target.src_addr, &g->target.dst_addr, g->target.tos, par); out: @@ -2656,7 +2678,7 @@ static unsigned int rtpengine4(struct sk_buff *oskb, const struct xt_action_para dst.family = AF_INET; dst.u.ipv4 = ih->daddr; - return rtpengine46(skb, t, &src, &dst, (u_int8_t)ih->tos); + return rtpengine46(skb, t, &src, &dst, (u_int8_t)ih->tos, par); skip2: kfree_skb(skb); @@ -2701,7 +2723,7 @@ static unsigned int rtpengine6(struct sk_buff *oskb, const struct xt_action_para dst.family = AF_INET6; memcpy(&dst.u.ipv6, &ih->daddr, sizeof(dst.u.ipv6)); - return rtpengine46(skb, t, &src, &dst, ipv6_get_dsfield(ih)); + return rtpengine46(skb, t, &src, &dst, ipv6_get_dsfield(ih), par); skip2: kfree_skb(skb); @@ -2770,7 +2792,7 @@ static int __init init(void) { printk(KERN_NOTICE "Registering xt_RTPENGINE module - version %s\n", RTPENGINE_VERSION); #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) - printk(KERN_DEBUG "using uid %u, gid %d\n", proc_uid, proc_gid); + DBG("using uid %u, gid %d\n", proc_uid, proc_gid); proc_kuid = KUIDT_INIT(proc_uid); proc_kgid = KGIDT_INIT(proc_gid); #endif From 926d9d3963d11dd1a4e393f65ffa5d7d9473c996 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Tue, 1 Mar 2016 09:09:41 -0500 Subject: [PATCH 05/13] MT#17699 augment module makefile version detection Depending on the build environment, $M might refer to a subdirectory of the main source tree (i.e. debian directory is in $M/../debian) or the main directory of the source tree (debian is at $M/debian). Use a shell test to detect the correct file. Also take git revision into account as additional info, same as the daemon build system does. Change-Id: Ib82ff2f9b1a1b0c94697fd91d5b9e9c9bb8e61f2 --- kernel-module/Makefile | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/kernel-module/Makefile b/kernel-module/Makefile index 1c4ccc365..6900cd607 100644 --- a/kernel-module/Makefile +++ b/kernel-module/Makefile @@ -2,16 +2,27 @@ PWD := $(shell pwd) KSRC ?= /lib/modules/$(shell uname -r)/build KBUILD := $(KSRC) -ifneq ($(RTPENGINE_VERSION),) - EXTRA_CFLAGS += -DRTPENGINE_VERSION="\"$(RTPENGINE_VERSION)\"" -else +ifeq ($(RTPENGINE_VERSION),) DPKG_PRSCHNGLG= $(shell which dpkg-parsechangelog 2>/dev/null) + DEB_CHANGELOG=$(shell test -f $(M)/../debian/changelog && echo $(M)/../debian/changelog || echo $(M)/debian/changelog) ifneq ($(DPKG_PRSCHNGLG),) - EXTRA_CFLAGS += -DRTPENGINE_VERSION="\"$(shell dpkg-parsechangelog -l$(M)/debian/changelog | awk '/^Version: / {print $$2}')\"" - else - EXTRA_CFLAGS += -DRTPENGINE_VERSION="\"undefined\"" + DPKG_PRSCHNGLG=$(shell dpkg-parsechangelog -l$(DEB_CHANGELOG) | awk '/^Version: / {print $$2}') + endif + GIT_BR_COMMIT=$(shell git branch --no-color --no-column -v 2> /dev/null | awk '/^\*/ {OFS="-"; print "git", $$2, $$3}') + + ifneq ($(DPKG_PRSCHNGLG),) + RTPENGINE_VERSION+=$(DPKG_PRSCHNGLG) + endif + ifneq ($(GIT_BR_COMMIT),) + RTPENGINE_VERSION+=$(GIT_BR_COMMIT) + endif + + ifeq ($(RTPENGINE_VERSION),) + RTPENGINE_VERSION+=undefined endif endif +EXTRA_CFLAGS+= -DRTPENGINE_VERSION="\"$(RTPENGINE_VERSION)\"" + EXTRA_CFLAGS += -D__RE_EXTERNAL obj-m += xt_RTPENGINE.o From 9be68a0c2f243b5d0cc335d1d1801fd3af5aa4c2 Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Tue, 8 Mar 2016 10:24:28 +0100 Subject: [PATCH 06/13] Add FINAL_TIMEOUT parameter The timer that will limit the duration of a call. Add graphite statistics for calls ended this way. --- README.md | 6 ++++++ daemon/call.c | 32 +++++++++++++++++++--------- daemon/call.h | 5 ++++- daemon/cli.c | 2 ++ daemon/graphite.c | 3 +++ daemon/main.c | 7 ++++++ debian/ngcp-rtpengine-daemon.default | 1 + debian/ngcp-rtpengine-daemon.init | 1 + 8 files changed, 46 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 55d3d7866..47c33e202 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 after the call is deleted. Useful for limiting the lifetime of a call. + 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 252b2c633..c4e7c4f58 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; @@ -193,6 +194,18 @@ static void call_timer_iterator(void *key, void *val, void *ptr) { cm = c->callmaster; + 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) goto delete; @@ -232,10 +245,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 +267,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"); @@ -2123,6 +2130,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 28f5c26e0..e11106d7c 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 { @@ -236,6 +237,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; @@ -422,6 +424,7 @@ struct callmaster_config { 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/cli.c b/daemon/cli.c index ad831ffe8..31cf1cff3 100644 --- a/daemon/cli.c +++ b/daemon/cli.c @@ -39,6 +39,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)); diff --git a/daemon/graphite.c b/daemon/graphite.c index 66bf28add..d3d1fcff7 100644 --- a/daemon/graphite.c +++ b/daemon/graphite.c @@ -87,6 +87,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); @@ -143,6 +144,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..236f48e95 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -66,6 +66,7 @@ static int table = -1; static int no_fallback; static int timeout; static int silent_timeout; +static 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)"); @@ -536,6 +542,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" From ef39aa35f17adee5651f6fb97ed4eaf0495c5c0e Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Tue, 15 Mar 2016 15:25:30 +0100 Subject: [PATCH 07/13] Add rtpengine-ctl list/set timeout Setters/getter of the TIMEOUT, SILENT_TIMEOUT and FINAL_TIMEOUT. Updated rtpengine-ctl help with the new commands. --- README.md | 4 +- daemon/cli.c | 129 +++++++++++++++++++++++++++++++++++++++++++- daemon/main.c | 6 +-- utils/rtpengine-ctl | 8 ++- 4 files changed, 138 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 47c33e202..bf6812a18 100644 --- a/README.md +++ b/README.md @@ -295,8 +295,8 @@ The options are described in more detail below. * -a, --final-timeout - The number of seconds after the call is deleted. Useful for limiting the lifetime of a call. - By default this timeout is disabled. + 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 diff --git a/daemon/cli.c b/daemon/cli.c index 31cf1cff3..1b5d34dfa 100644 --- a/daemon/cli.c +++ b/daemon/cli.c @@ -138,6 +138,20 @@ 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; + + /* 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); + + 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; @@ -255,7 +269,7 @@ static void cli_incoming_set_maxopenfiles(char* buffer, int len, struct callmast // 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; @@ -292,7 +306,7 @@ static void cli_incoming_set_maxsessions(char* buffer, int len, struct callmaste int disabled = -1; str maxsessions; - if (len<=1) { + if (len <= 1) { printlen = snprintf(replybuffer,(outbufend-replybuffer), "%s\n", "More parameters required."); ADJUSTLEN(printlen,outbufend,replybuffer); return; @@ -324,6 +338,105 @@ 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) { + 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 */ + m->conf.timeout = timeout_num; + printlen = snprintf (replybuffer,(outbufend-replybuffer), "Success setting timeout to %u\n", timeout_num); + ADJUSTLEN(printlen,outbufend,replybuffer); + } +} + +static void cli_incoming_set_silent_timeout(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend) { + int printlen = 0; + unsigned int silent_timeout_num; + str silent_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 + silent_timeout.s = buffer; + silent_timeout.len = len; + silent_timeout_num = strtol(silent_timeout.s, &endptr, 10); + + if ((errno == ERANGE && (silent_timeout_num == LONG_MAX || silent_timeout_num == LONG_MIN)) || (errno != 0 && silent_timeout_num == 0)) { + printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting silent_timeout to %.*s; errno=%d\n", silent_timeout.len, silent_timeout.s, errno); + ADJUSTLEN(printlen,outbufend,replybuffer); + return; + } else if (endptr == silent_timeout.s) { + printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting silent_timeout to %.*s; no digists found\n", silent_timeout.len, silent_timeout.s); + ADJUSTLEN(printlen,outbufend,replybuffer); + return; + } else { + /* don't lock anything while writing the value - only this command modifies its value */ + m->conf.silent_timeout = silent_timeout_num; + printlen = snprintf (replybuffer,(outbufend-replybuffer), "Success setting silent_timeout to %u\n", silent_timeout_num); + ADJUSTLEN(printlen,outbufend,replybuffer); + } +} + +static void cli_incoming_set_final_timeout(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend) { + int printlen = 0; + unsigned int final_timeout_num; + str final_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 + final_timeout.s = buffer; + final_timeout.len = len; + final_timeout_num = strtol(final_timeout.s, &endptr, 10); + + if ((errno == ERANGE && (final_timeout_num == LONG_MAX || final_timeout_num == LONG_MIN)) || (errno != 0 && final_timeout_num == 0)) { + printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting final_timeout to %.*s; errno=%d\n", final_timeout.len, final_timeout.s, errno); + ADJUSTLEN(printlen,outbufend,replybuffer); + return; + } else if (endptr == final_timeout.s) { + printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting final_timeout to %.*s; no digists found\n", final_timeout.len, final_timeout.s); + ADJUSTLEN(printlen,outbufend,replybuffer); + return; + } else { + /* don't lock anything while writing the value - only this command modifies its value */ + m->conf.final_timeout = final_timeout_num; + printlen = snprintf (replybuffer,(outbufend-replybuffer), "Success setting final_timeout to %u\n", final_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; @@ -337,6 +450,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."); @@ -374,6 +488,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); @@ -385,6 +501,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."); @@ -397,6 +516,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); + } else if (len>=strlen(SET_SILENT_TIMEOUT) && strncmp(buffer,SET_SILENT_TIMEOUT,strlen(SET_SILENT_TIMEOUT)) == 0) { + cli_incoming_set_silent_timeout(buffer+strlen(SET_SILENT_TIMEOUT), len-strlen(SET_SILENT_TIMEOUT), m, replybuffer, outbufend); + } else if (len>=strlen(SET_FINAL_TIMEOUT) && strncmp(buffer,SET_FINAL_TIMEOUT,strlen(SET_FINAL_TIMEOUT)) == 0) { + cli_incoming_set_final_timeout(buffer+strlen(SET_FINAL_TIMEOUT), len-strlen(SET_FINAL_TIMEOUT), m, replybuffer, outbufend); } else { printlen = snprintf(replybuffer, outbufend-replybuffer, "%s:%s\n", "Unknown 'set' command", buffer); ADJUSTLEN(printlen,outbufend,replybuffer); diff --git a/daemon/main.c b/daemon/main.c index 236f48e95..267133fba 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -64,9 +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 int final_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; 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"; From 4343ff02cb8802eb3c9d6ba883072de4e857281d Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Tue, 15 Mar 2016 15:38:15 +0100 Subject: [PATCH 08/13] Update rtpengine-cli set maxopenfiles --- daemon/cli.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/daemon/cli.c b/daemon/cli.c index 1b5d34dfa..e5e9fa26a 100644 --- a/daemon/cli.c +++ b/daemon/cli.c @@ -265,6 +265,7 @@ 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); @@ -278,23 +279,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); } } From 05302c265f7787890728abf367fb09218cb31218 Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Tue, 15 Mar 2016 15:56:30 +0100 Subject: [PATCH 09/13] Update rtpengine-cli set maxsessions --- daemon/cli.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/daemon/cli.c b/daemon/cli.c index e5e9fa26a..3bc6749b4 100644 --- a/daemon/cli.c +++ b/daemon/cli.c @@ -307,9 +307,9 @@ 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) { printlen = snprintf(replybuffer,(outbufend-replybuffer), "%s\n", "More parameters required."); @@ -320,11 +320,16 @@ 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); From 57aa56616d65493cc38c11bedf8e1f5f7869364a Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Mon, 14 Mar 2016 14:06:02 +0100 Subject: [PATCH 10/13] Add offer/answer/delete processing statistics Add graphite offer/answer/delete min/max/avg statistics. Print new graphite statistics in rtpengine-cli list totals. --- daemon/aux.h | 5 ++++ daemon/call.h | 8 ++++++ daemon/cli.c | 33 +++++++++++++++++++++++ daemon/control_ng.c | 66 +++++++++++++++++++++++++++++++++++++++++++++ daemon/graphite.c | 61 ++++++++++++++++++++++++++++++++++++++++- 5 files changed, 172 insertions(+), 1 deletion(-) diff --git a/daemon/aux.h b/daemon/aux.h index afbae0deb..ac4710947 100644 --- a/daemon/aux.h +++ b/daemon/aux.h @@ -567,6 +567,11 @@ INLINE void timeval_multiply(struct timeval *result, const struct timeval *a, co timeval_from_us(result, timeval_us(a) * multiplier); } INLINE void timeval_divide(struct timeval *result, const struct timeval *a, const long divisor) { + if (divisor == 0) { + result->tv_sec = 0; + result->tv_usec = 0; + return ; + } timeval_from_us(result, timeval_us(a) / divisor); } INLINE void timeval_add(struct timeval *result, const struct timeval *a, const struct timeval *b) { diff --git a/daemon/call.h b/daemon/call.h index 28f5c26e0..c66f09676 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -231,6 +231,12 @@ struct stats { u_int8_t in_tos_tclass; /* XXX shouldn't be here - not stats */ }; +struct request_time { + mutex_t lock; + u_int64_t count; + struct timeval time_min, time_max, time_avg; +}; + struct totalstats { time_t started; atomic64 total_timeout_sess; @@ -254,6 +260,8 @@ struct totalstats { mutex_t total_calls_duration_lock; /* for these two below */ struct timeval total_calls_duration_interval; + + struct request_time offer, answer, delete; }; struct stream_params { diff --git a/daemon/cli.c b/daemon/cli.c index ad831ffe8..e01e7aafd 100644 --- a/daemon/cli.c +++ b/daemon/cli.c @@ -21,6 +21,7 @@ static void cli_incoming_list_totals(char* buffer, int len, struct callmaster* m int printlen=0; struct timeval avg, calls_dur_iv; u_int64_t num_sessions, min_sess_iv, max_sess_iv; + struct request_time offer, answer, delete; mutex_lock(&m->totalstats.total_average_lock); avg = m->totalstats.total_average_call_dur; @@ -60,6 +61,23 @@ static void cli_incoming_list_totals(char* buffer, int len, struct callmaster* m max_sess_iv = m->totalstats_lastinterval.managed_sess_max; mutex_unlock(&m->totalstats_lastinterval_lock); + mutex_lock(&m->totalstats_interval.offer.lock); + offer = m->totalstats_interval.offer; + mutex_unlock(&m->totalstats_interval.offer.lock); + + mutex_lock(&m->totalstats_interval.answer.lock); + answer = m->totalstats_interval.answer; + mutex_unlock(&m->totalstats_interval.answer.lock); + + mutex_lock(&m->totalstats_interval.delete.lock); + delete = m->totalstats_interval.delete; + mutex_unlock(&m->totalstats_interval.delete.lock); + + // compute average offer/answer/delete time + timeval_divide(&offer.time_avg, &offer.time_avg, offer.count); + timeval_divide(&answer.time_avg, &answer.time_avg, answer.count); + timeval_divide(&delete.time_avg, &delete.time_avg, delete.count); + printlen = snprintf(replybuffer,(outbufend-replybuffer), "\nGraphite interval statistics (last reported values to graphite):\n"); ADJUSTLEN(printlen,outbufend,replybuffer); printlen = snprintf(replybuffer,(outbufend-replybuffer), " Total calls duration :%ld.%06ld\n\n",calls_dur_iv.tv_sec,calls_dur_iv.tv_usec); @@ -68,6 +86,21 @@ static void cli_incoming_list_totals(char* buffer, int len, struct callmaster* m ADJUSTLEN(printlen,outbufend,replybuffer); printlen = snprintf(replybuffer,(outbufend-replybuffer), " Max managed sessions :"UINT64F"\n", max_sess_iv); ADJUSTLEN(printlen,outbufend,replybuffer); + printlen = snprintf(replybuffer,(outbufend-replybuffer), " Min/Max/Avg offer processing delay :%llu.%06llu/%llu.%06llu/%llu.%06llu sec\n", + (unsigned long long)offer.time_min.tv_sec,(unsigned long long)offer.time_min.tv_usec, + (unsigned long long)offer.time_max.tv_sec,(unsigned long long)offer.time_max.tv_usec, + (unsigned long long)offer.time_avg.tv_sec,(unsigned long long)offer.time_avg.tv_usec); + ADJUSTLEN(printlen,outbufend,replybuffer); + printlen = snprintf(replybuffer,(outbufend-replybuffer), " Min/Max/Avg answer processing delay :%llu.%06llu/%llu.%06llu/%llu.%06llu sec\n", + (unsigned long long)answer.time_min.tv_sec,(unsigned long long)answer.time_min.tv_usec, + (unsigned long long)answer.time_max.tv_sec,(unsigned long long)answer.time_max.tv_usec, + (unsigned long long)answer.time_avg.tv_sec,(unsigned long long)answer.time_avg.tv_usec); + ADJUSTLEN(printlen,outbufend,replybuffer); + printlen = snprintf(replybuffer,(outbufend-replybuffer), " Min/Max/Avg delete processing delay :%llu.%06llu/%llu.%06llu/%llu.%06llu sec\n", + (unsigned long long)delete.time_min.tv_sec,(unsigned long long)delete.time_min.tv_usec, + (unsigned long long)delete.time_max.tv_sec,(unsigned long long)delete.time_max.tv_usec, + (unsigned long long)delete.time_avg.tv_sec,(unsigned long long)delete.time_avg.tv_usec); + ADJUSTLEN(printlen,outbufend,replybuffer); printlen = snprintf(replybuffer,(outbufend-replybuffer), "\n\n"); ADJUSTLEN(printlen,outbufend,replybuffer); diff --git a/daemon/control_ng.c b/daemon/control_ng.c index 1f9735a47..31d924c11 100644 --- a/daemon/control_ng.c +++ b/daemon/control_ng.c @@ -13,6 +13,30 @@ #include "call_interfaces.h" #include "socket.h" +static void timeval_update_request_time(struct request_time *request, const struct timeval *offer_diff) { + // lock offers + mutex_lock(&request->lock); + + // update min value + if (timeval_us(&request->time_min) == 0 || + timeval_cmp(&request->time_min, offer_diff) > 0) { + timeval_from_us(&request->time_min, timeval_us(offer_diff)); + } + + // update max value + if (timeval_us(&request->time_max) == 0 || + timeval_cmp(&request->time_max, offer_diff) < 0) { + timeval_from_us(&request->time_max, timeval_us(offer_diff)); + } + + // update avg value + timeval_add(&request->time_avg, &request->time_avg, offer_diff); + request->count++; + + // unlock offers + mutex_unlock(&request->lock); +} + static void pretty_print(bencode_item_t *el, GString *s) { bencode_item_t *chld; @@ -86,6 +110,9 @@ static void control_ng_incoming(struct obj *obj, str *buf, const endpoint_t *sin struct iovec iov[3]; unsigned int iovlen; GString *log_str; + struct timeval offer_start, offer_stop; + struct timeval answer_start, answer_stop; + struct timeval delete_start, delete_stop; struct control_ng_stats* cur = get_control_ng_stats(c,&sin->address); @@ -143,16 +170,46 @@ static void control_ng_incoming(struct obj *obj, str *buf, const endpoint_t *sin g_atomic_int_inc(&cur->ping); } else if (!str_cmp(&cmd, "offer")) { + // start offer timer + gettimeofday(&offer_start, NULL); + errstr = call_offer_ng(dict, c->callmaster, resp, addr, sin); g_atomic_int_inc(&cur->offer); + + // stop offer timer + gettimeofday(&offer_stop, NULL); + + // print offer duration + timeval_from_us(&offer_stop, timeval_diff(&offer_stop, &offer_start)); + ilog(LOG_INFO, "offer time = %llu.%06llu sec", (unsigned long long)offer_stop.tv_sec, (unsigned long long)offer_stop.tv_usec); } else if (!str_cmp(&cmd, "answer")) { + // start answer timer + gettimeofday(&answer_start, NULL); + errstr = call_answer_ng(dict, c->callmaster, resp); g_atomic_int_inc(&cur->answer); + + // stop answer timer + gettimeofday(&answer_stop, NULL); + + // print answer duration + timeval_from_us(&answer_stop, timeval_diff(&answer_stop, &answer_start)); + ilog(LOG_INFO, "answer time = %llu.%06llu sec", (unsigned long long)answer_stop.tv_sec, (unsigned long long)answer_stop.tv_usec); } else if (!str_cmp(&cmd, "delete")) { + // start delete timer + gettimeofday(&delete_start, NULL); + errstr = call_delete_ng(dict, c->callmaster, resp); g_atomic_int_inc(&cur->delete); + + // stop delete timer + gettimeofday(&delete_stop, NULL); + + // print delete duration + timeval_from_us(&delete_stop, timeval_diff(&delete_stop, &delete_start)); + ilog(LOG_INFO, "delete time = %llu.%06llu sec", (unsigned long long)delete_stop.tv_sec, (unsigned long long)delete_stop.tv_usec); } else if (!str_cmp(&cmd, "query")) { errstr = call_query_ng(dict, c->callmaster, resp); @@ -168,6 +225,15 @@ static void control_ng_incoming(struct obj *obj, str *buf, const endpoint_t *sin if (errstr) goto err_send; + // update interval statistics + if (!str_cmp(&cmd, "offer")) { + timeval_update_request_time(&c->callmaster->totalstats_interval.offer, &offer_stop); + } else if (!str_cmp(&cmd, "answer")) { + timeval_update_request_time(&c->callmaster->totalstats_interval.answer, &answer_stop); + } else if (!str_cmp(&cmd, "delete")) { + timeval_update_request_time(&c->callmaster->totalstats_interval.delete, &delete_stop); + } + goto send_resp; err_send: diff --git a/daemon/graphite.c b/daemon/graphite.c index 66bf28add..74407fbba 100644 --- a/daemon/graphite.c +++ b/daemon/graphite.c @@ -37,6 +37,23 @@ void set_prefix(char* prefix) { graphite_prefix = prefix; } +static struct request_time timeval_clear_request_time(struct request_time *request) { + struct request_time ret; + + mutex_lock(&request->lock); + ret = *request; + request->time_min.tv_sec = 0; + request->time_min.tv_usec = 0; + request->time_max.tv_sec = 0; + request->time_max.tv_usec = 0; + request->time_avg.tv_sec = 0; + request->time_avg.tv_usec = 0; + request->count = 0; + mutex_unlock(&request->lock); + + return ret; +} + int connect_to_graphite_server(const endpoint_t *graphite_ep) { int rc; @@ -105,10 +122,13 @@ int send_graphite_data(struct callmaster *cm, struct totalstats *sent_data) { ts->total_calls_duration_interval = cm->totalstats_interval.total_calls_duration_interval; cm->totalstats_interval.total_calls_duration_interval.tv_sec = 0; cm->totalstats_interval.total_calls_duration_interval.tv_usec = 0; - //ZERO(cm->totalstats_interval.total_calls_duration_interval); mutex_unlock(&cm->totalstats_interval.total_calls_duration_lock); + ts->offer = timeval_clear_request_time(&cm->totalstats_interval.offer); + ts->answer = timeval_clear_request_time(&cm->totalstats_interval.answer); + ts->delete = timeval_clear_request_time(&cm->totalstats_interval.delete); + rwlock_lock_r(&cm->hashlock); mutex_lock(&cm->totalstats_interval.managed_sess_lock); ts->managed_sess_max = cm->totalstats_interval.managed_sess_max; @@ -118,6 +138,32 @@ int send_graphite_data(struct callmaster *cm, struct totalstats *sent_data) { mutex_unlock(&cm->totalstats_interval.managed_sess_lock); rwlock_unlock_r(&cm->hashlock); + // compute average offer/answer/delete time + timeval_divide(&ts->offer.time_avg, &ts->offer.time_avg, ts->offer.count); + timeval_divide(&ts->answer.time_avg, &ts->answer.time_avg, ts->answer.count); + timeval_divide(&ts->delete.time_avg, &ts->delete.time_avg, ts->delete.count); + + if (graphite_prefix!=NULL) { rc = sprintf(ptr,"%s",graphite_prefix); ptr += rc; } + rc = sprintf(ptr,"offer_time_min %llu.%06llu %llu\n",(unsigned long long)ts->offer.time_min.tv_sec,(unsigned long long)ts->offer.time_min.tv_usec,(unsigned long long)g_now.tv_sec); ptr += rc; + if (graphite_prefix!=NULL) { rc = sprintf(ptr,"%s",graphite_prefix); ptr += rc; } + rc = sprintf(ptr,"offer_time_max %llu.%06llu %llu\n",(unsigned long long)ts->offer.time_max.tv_sec,(unsigned long long)ts->offer.time_max.tv_usec,(unsigned long long)g_now.tv_sec); ptr += rc; + if (graphite_prefix!=NULL) { rc = sprintf(ptr,"%s",graphite_prefix); ptr += rc; } + rc = sprintf(ptr,"offer_time_avg %llu.%06llu %llu\n",(unsigned long long)ts->offer.time_avg.tv_sec,(unsigned long long)ts->offer.time_avg.tv_usec,(unsigned long long)g_now.tv_sec); ptr += rc; + + if (graphite_prefix!=NULL) { rc = sprintf(ptr,"%s",graphite_prefix); ptr += rc; } + rc = sprintf(ptr,"answer_time_min %llu.%06llu %llu\n",(unsigned long long)ts->answer.time_min.tv_sec,(unsigned long long)ts->answer.time_min.tv_usec,(unsigned long long)g_now.tv_sec); ptr += rc; + if (graphite_prefix!=NULL) { rc = sprintf(ptr,"%s",graphite_prefix); ptr += rc; } + rc = sprintf(ptr,"answer_time_max %llu.%06llu %llu\n",(unsigned long long)ts->answer.time_max.tv_sec,(unsigned long long)ts->answer.time_max.tv_usec,(unsigned long long)g_now.tv_sec); ptr += rc; + if (graphite_prefix!=NULL) { rc = sprintf(ptr,"%s",graphite_prefix); ptr += rc; } + rc = sprintf(ptr,"answer_time_avg %llu.%06llu %llu\n",(unsigned long long)ts->answer.time_avg.tv_sec,(unsigned long long)ts->answer.time_avg.tv_usec,(unsigned long long)g_now.tv_sec); ptr += rc; + + if (graphite_prefix!=NULL) { rc = sprintf(ptr,"%s",graphite_prefix); ptr += rc; } + rc = sprintf(ptr,"delete_time_min %llu.%06llu %llu\n",(unsigned long long)ts->delete.time_min.tv_sec,(unsigned long long)ts->delete.time_min.tv_usec,(unsigned long long)g_now.tv_sec); ptr += rc; + if (graphite_prefix!=NULL) { rc = sprintf(ptr,"%s",graphite_prefix); ptr += rc; } + rc = sprintf(ptr,"delete_time_max %llu.%06llu %llu\n",(unsigned long long)ts->delete.time_max.tv_sec,(unsigned long long)ts->delete.time_max.tv_usec,(unsigned long long)g_now.tv_sec); ptr += rc; + if (graphite_prefix!=NULL) { rc = sprintf(ptr,"%s",graphite_prefix); ptr += rc; } + rc = sprintf(ptr,"delete_time_avg %llu.%06llu %llu\n",(unsigned long long)ts->delete.time_avg.tv_sec,(unsigned long long)ts->delete.time_avg.tv_usec,(unsigned long long)g_now.tv_sec); ptr += rc; + if (graphite_prefix!=NULL) { rc = sprintf(ptr,"%s",graphite_prefix); ptr += rc; } rc = sprintf(ptr, "call_dur %llu.%06llu %llu\n",(unsigned long long)ts->total_calls_duration_interval.tv_sec,(unsigned long long)ts->total_calls_duration_interval.tv_usec,(unsigned long long)g_now.tv_sec); ptr += rc; if (graphite_prefix!=NULL) { rc = sprintf(ptr,"%s",graphite_prefix); ptr += rc; } @@ -154,6 +200,19 @@ int send_graphite_data(struct callmaster *cm, struct totalstats *sent_data) { (unsigned long long ) ts->total_calls_duration_interval.tv_usec, (unsigned long long ) g_now.tv_sec); + ilog(LOG_DEBUG, "Min/Max/Avg offer processing delay: %llu.%06llu/%llu.%06llu/%llu.%06llu sec", + (unsigned long long)ts->offer.time_min.tv_sec,(unsigned long long)ts->offer.time_min.tv_usec, + (unsigned long long)ts->offer.time_max.tv_sec,(unsigned long long)ts->offer.time_max.tv_usec, + (unsigned long long)ts->offer.time_avg.tv_sec,(unsigned long long)ts->offer.time_avg.tv_usec); + ilog(LOG_DEBUG, "Min/Max/Avg answer processing delay: %llu.%06llu/%llu.%06llu/%llu.%06llu sec", + (unsigned long long)ts->answer.time_min.tv_sec,(unsigned long long)ts->answer.time_min.tv_usec, + (unsigned long long)ts->answer.time_max.tv_sec,(unsigned long long)ts->answer.time_max.tv_usec, + (unsigned long long)ts->answer.time_avg.tv_sec,(unsigned long long)ts->answer.time_avg.tv_usec); + ilog(LOG_DEBUG, "Min/Max/Avg delete processing delay: %llu.%06llu/%llu.%06llu/%llu.%06llu sec", + (unsigned long long)ts->delete.time_min.tv_sec,(unsigned long long)ts->delete.time_min.tv_usec, + (unsigned long long)ts->delete.time_max.tv_sec,(unsigned long long)ts->delete.time_max.tv_usec, + (unsigned long long)ts->delete.time_avg.tv_sec,(unsigned long long)ts->delete.time_avg.tv_usec); + rc = write(graphite_sock.fd, data_to_send, ptr - data_to_send); if (rc<0) { ilog(LOG_ERROR,"Could not write to graphite socket. Disconnecting graphite server."); From 3f4cfffdbb9ca0a97ac0d527031ecc4ef8f0a4c0 Mon Sep 17 00:00:00 2001 From: Pawel Kuzak Date: Mon, 21 Mar 2016 12:49:24 +0100 Subject: [PATCH 11/13] Fixed inconsistency in rtpengine-ctl list totals --- daemon/cli.c | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/daemon/cli.c b/daemon/cli.c index e01e7aafd..f07d34423 100644 --- a/daemon/cli.c +++ b/daemon/cli.c @@ -21,7 +21,7 @@ static void cli_incoming_list_totals(char* buffer, int len, struct callmaster* m int printlen=0; struct timeval avg, calls_dur_iv; u_int64_t num_sessions, min_sess_iv, max_sess_iv; - struct request_time offer, answer, delete; + struct request_time offer_iv, answer_iv, delete_iv; mutex_lock(&m->totalstats.total_average_lock); avg = m->totalstats.total_average_call_dur; @@ -59,24 +59,15 @@ static void cli_incoming_list_totals(char* buffer, int len, struct callmaster* m calls_dur_iv = m->totalstats_lastinterval.total_calls_duration_interval; min_sess_iv = m->totalstats_lastinterval.managed_sess_min; max_sess_iv = m->totalstats_lastinterval.managed_sess_max; - mutex_unlock(&m->totalstats_lastinterval_lock); - - mutex_lock(&m->totalstats_interval.offer.lock); - offer = m->totalstats_interval.offer; - mutex_unlock(&m->totalstats_interval.offer.lock); - - mutex_lock(&m->totalstats_interval.answer.lock); - answer = m->totalstats_interval.answer; - mutex_unlock(&m->totalstats_interval.answer.lock); - - mutex_lock(&m->totalstats_interval.delete.lock); - delete = m->totalstats_interval.delete; - mutex_unlock(&m->totalstats_interval.delete.lock); + offer_iv = m->totalstats_lastinterval.offer; + answer_iv = m->totalstats_lastinterval.answer; + delete_iv = m->totalstats_lastinterval.delete; + mutex_unlock(&m->totalstats_lastinterval_lock); // compute average offer/answer/delete time - timeval_divide(&offer.time_avg, &offer.time_avg, offer.count); - timeval_divide(&answer.time_avg, &answer.time_avg, answer.count); - timeval_divide(&delete.time_avg, &delete.time_avg, delete.count); + timeval_divide(&offer_iv.time_avg, &offer_iv.time_avg, offer_iv.count); + timeval_divide(&answer_iv.time_avg, &answer_iv.time_avg, answer_iv.count); + timeval_divide(&delete_iv.time_avg, &delete_iv.time_avg, delete_iv.count); printlen = snprintf(replybuffer,(outbufend-replybuffer), "\nGraphite interval statistics (last reported values to graphite):\n"); ADJUSTLEN(printlen,outbufend,replybuffer); @@ -87,19 +78,19 @@ static void cli_incoming_list_totals(char* buffer, int len, struct callmaster* m printlen = snprintf(replybuffer,(outbufend-replybuffer), " Max managed sessions :"UINT64F"\n", max_sess_iv); ADJUSTLEN(printlen,outbufend,replybuffer); printlen = snprintf(replybuffer,(outbufend-replybuffer), " Min/Max/Avg offer processing delay :%llu.%06llu/%llu.%06llu/%llu.%06llu sec\n", - (unsigned long long)offer.time_min.tv_sec,(unsigned long long)offer.time_min.tv_usec, - (unsigned long long)offer.time_max.tv_sec,(unsigned long long)offer.time_max.tv_usec, - (unsigned long long)offer.time_avg.tv_sec,(unsigned long long)offer.time_avg.tv_usec); + (unsigned long long)offer_iv.time_min.tv_sec,(unsigned long long)offer_iv.time_min.tv_usec, + (unsigned long long)offer_iv.time_max.tv_sec,(unsigned long long)offer_iv.time_max.tv_usec, + (unsigned long long)offer_iv.time_avg.tv_sec,(unsigned long long)offer_iv.time_avg.tv_usec); ADJUSTLEN(printlen,outbufend,replybuffer); printlen = snprintf(replybuffer,(outbufend-replybuffer), " Min/Max/Avg answer processing delay :%llu.%06llu/%llu.%06llu/%llu.%06llu sec\n", - (unsigned long long)answer.time_min.tv_sec,(unsigned long long)answer.time_min.tv_usec, - (unsigned long long)answer.time_max.tv_sec,(unsigned long long)answer.time_max.tv_usec, - (unsigned long long)answer.time_avg.tv_sec,(unsigned long long)answer.time_avg.tv_usec); + (unsigned long long)answer_iv.time_min.tv_sec,(unsigned long long)answer_iv.time_min.tv_usec, + (unsigned long long)answer_iv.time_max.tv_sec,(unsigned long long)answer_iv.time_max.tv_usec, + (unsigned long long)answer_iv.time_avg.tv_sec,(unsigned long long)answer_iv.time_avg.tv_usec); ADJUSTLEN(printlen,outbufend,replybuffer); printlen = snprintf(replybuffer,(outbufend-replybuffer), " Min/Max/Avg delete processing delay :%llu.%06llu/%llu.%06llu/%llu.%06llu sec\n", - (unsigned long long)delete.time_min.tv_sec,(unsigned long long)delete.time_min.tv_usec, - (unsigned long long)delete.time_max.tv_sec,(unsigned long long)delete.time_max.tv_usec, - (unsigned long long)delete.time_avg.tv_sec,(unsigned long long)delete.time_avg.tv_usec); + (unsigned long long)delete_iv.time_min.tv_sec,(unsigned long long)delete_iv.time_min.tv_usec, + (unsigned long long)delete_iv.time_max.tv_sec,(unsigned long long)delete_iv.time_max.tv_usec, + (unsigned long long)delete_iv.time_avg.tv_sec,(unsigned long long)delete_iv.time_avg.tv_usec); ADJUSTLEN(printlen,outbufend,replybuffer); printlen = snprintf(replybuffer,(outbufend-replybuffer), "\n\n"); From a43996fe4a00bb8b944655d0421dfd41bbf6641c Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Mon, 7 Mar 2016 15:25:50 +0100 Subject: [PATCH 12/13] Add 'unidirectional' attribute In order to kernelize unidirectional streams. --- README.md | 4 ++++ daemon/call.c | 4 ++-- daemon/call.h | 3 +++ daemon/call_interfaces.c | 2 ++ daemon/call_interfaces.h | 1 + daemon/media_socket.c | 5 +++++ daemon/sdp.c | 1 + 7 files changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 55d3d7866..94e66c3ef 100644 --- a/README.md +++ b/README.md @@ -711,6 +711,10 @@ Optionally included keys are: Corresponds to the *rtpproxy* `a` flag. Advertises an RTP endpoint which uses asymmetric RTP, which disables learning of endpoint addresses (see below). + - `unidirectional` + + When this flag is present, kernelize also one-way rtp media. + - `strict source` Normally, *rtpengine* attempts to learn the correct endpoint address for every stream during diff --git a/daemon/call.c b/daemon/call.c index 252b2c633..a712634f1 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -1553,8 +1553,8 @@ int monologue_offer_answer(struct call_monologue *other_ml, GQueue *streams, if (sp->rtp_endpoint.port) { /* copy parameters advertised by the sender of this message */ bf_copy_same(&other_media->media_flags, &sp->sp_flags, - SHARED_FLAG_RTCP_MUX | SHARED_FLAG_ASYMMETRIC | SHARED_FLAG_ICE - | SHARED_FLAG_TRICKLE_ICE | SHARED_FLAG_ICE_LITE); + SHARED_FLAG_RTCP_MUX | SHARED_FLAG_ASYMMETRIC | SHARED_FLAG_UNIDIRECTIONAL | + SHARED_FLAG_ICE | SHARED_FLAG_TRICKLE_ICE | SHARED_FLAG_ICE_LITE); crypto_params_copy(&other_media->sdes_in.params, &sp->crypto, 1); other_media->sdes_in.tag = sp->sdes_tag; diff --git a/daemon/call.h b/daemon/call.h index 28f5c26e0..79a461650 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -124,6 +124,7 @@ enum call_stream_state { #define SHARED_FLAG_MEDIA_HANDOVER 0x00000200 #define SHARED_FLAG_TRICKLE_ICE 0x00000400 #define SHARED_FLAG_ICE_LITE 0x00000800 +#define SHARED_FLAG_UNIDIRECTIONAL 0x00001000 /* struct stream_params */ #define SP_FLAG_NO_RTCP 0x00010000 @@ -132,6 +133,7 @@ enum call_stream_state { #define SP_FLAG_SEND SHARED_FLAG_SEND #define SP_FLAG_RECV SHARED_FLAG_RECV #define SP_FLAG_ASYMMETRIC SHARED_FLAG_ASYMMETRIC +#define SP_FLAG_UNIDIRECTIONAL SHARED_FLAG_UNIDIRECTIONAL #define SP_FLAG_SETUP_ACTIVE SHARED_FLAG_SETUP_ACTIVE #define SP_FLAG_SETUP_PASSIVE SHARED_FLAG_SETUP_PASSIVE #define SP_FLAG_ICE SHARED_FLAG_ICE @@ -159,6 +161,7 @@ enum call_stream_state { /* struct call_media */ #define MEDIA_FLAG_INITIALIZED 0x00010000 #define MEDIA_FLAG_ASYMMETRIC SHARED_FLAG_ASYMMETRIC +#define MEDIA_FLAG_UNIDIRECTIONAL SHARED_FLAG_UNIDIRECTIONAL #define MEDIA_FLAG_SEND SHARED_FLAG_SEND #define MEDIA_FLAG_RECV SHARED_FLAG_RECV #define MEDIA_FLAG_RTCP_MUX SHARED_FLAG_RTCP_MUX diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index c7b4fd5ec..224649c13 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -541,6 +541,8 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu out->trust_address = 0; else if (!bencode_strcmp(it, "asymmetric")) out->asymmetric = 1; + else if (!bencode_strcmp(it, "unidirectional")) + out->unidirectional = 1; else if (!bencode_strcmp(it, "strict-source")) out->strict_source = 1; else if (!bencode_strcmp(it, "media-handover")) diff --git a/daemon/call_interfaces.h b/daemon/call_interfaces.h index 23ee7bea8..214861ec0 100644 --- a/daemon/call_interfaces.h +++ b/daemon/call_interfaces.h @@ -31,6 +31,7 @@ struct sdp_ng_flags { sockfamily_t *address_family; int tos; int asymmetric:1, + unidirectional:1, trust_address:1, port_latching:1, replace_origin:1, diff --git a/daemon/media_socket.c b/daemon/media_socket.c index b9e1e7328..4d719171b 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -1204,6 +1204,11 @@ loop_ok: if (MEDIA_ISSET(media, ASYMMETRIC)) PS_SET(stream, CONFIRMED); + /* confirm sink for unidirectional streams in order to kernelize */ + if (MEDIA_ISSET(media, UNIDIRECTIONAL)) { + PS_SET(sink, CONFIRMED); + } + /* if we have already updated the endpoint in the past ... */ if (PS_ISSET(stream, CONFIRMED)) { /* see if we need to compare the source address with the known endpoint */ diff --git a/daemon/sdp.c b/daemon/sdp.c index 454fac211..4b03276fe 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -1188,6 +1188,7 @@ int sdp_streams(const GQueue *sessions, GQueue *streams, struct sdp_ng_flags *fl memcpy(sp->direction, flags->direction, sizeof(sp->direction)); sp->desired_family = flags->address_family; bf_set_clear(&sp->sp_flags, SP_FLAG_ASYMMETRIC, flags->asymmetric); + bf_set_clear(&sp->sp_flags, SP_FLAG_UNIDIRECTIONAL, flags->unidirectional); bf_set_clear(&sp->sp_flags, SP_FLAG_STRICT_SOURCE, flags->strict_source); bf_set_clear(&sp->sp_flags, SP_FLAG_MEDIA_HANDOVER, flags->media_handover); From bac271b39825817346f0975558b585de1974627a Mon Sep 17 00:00:00 2001 From: smititelu Date: Thu, 17 Mar 2016 16:13:57 +0100 Subject: [PATCH 13/13] Add callmaster config lock --- daemon/call.c | 2 + daemon/call.h | 4 ++ daemon/call_interfaces.c | 7 ++++ daemon/cli.c | 88 +++++++--------------------------------- daemon/main.c | 1 + 5 files changed, 29 insertions(+), 73 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index c4e7c4f58..b76126ee3 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -193,6 +193,7 @@ 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"); @@ -281,6 +282,7 @@ delete: goto out; out: + rwlock_unlock_r(&cm->conf.config_lock); rwlock_unlock_r(&c->master_lock); log_info_clear(); } diff --git a/daemon/call.h b/daemon/call.h index e11106d7c..7e1f29d9a 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -421,10 +421,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 c7b4fd5ec..0a1b82cd1 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: @@ -741,6 +743,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) { @@ -748,10 +751,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 3bc6749b4..4d46c2540 100644 --- a/daemon/cli.c +++ b/daemon/cli.c @@ -141,6 +141,8 @@ static void cli_incoming_list_maxopenfiles(char* buffer, int len, struct callmas 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); @@ -149,6 +151,8 @@ static void cli_incoming_list_timeout(char* buffer, int len, struct callmaster* 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 ; } @@ -334,13 +338,15 @@ static void cli_incoming_set_maxsessions(char* buffer, int len, struct callmaste 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); } @@ -348,7 +354,7 @@ 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) { +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; @@ -375,78 +381,14 @@ static void cli_incoming_set_timeout(char* buffer, int len, struct callmaster* m return; } else { /* don't lock anything while writing the value - only this command modifies its value */ - m->conf.timeout = timeout_num; + 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_set_silent_timeout(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend) { - int printlen = 0; - unsigned int silent_timeout_num; - str silent_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 - silent_timeout.s = buffer; - silent_timeout.len = len; - silent_timeout_num = strtol(silent_timeout.s, &endptr, 10); - - if ((errno == ERANGE && (silent_timeout_num == LONG_MAX || silent_timeout_num == LONG_MIN)) || (errno != 0 && silent_timeout_num == 0)) { - printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting silent_timeout to %.*s; errno=%d\n", silent_timeout.len, silent_timeout.s, errno); - ADJUSTLEN(printlen,outbufend,replybuffer); - return; - } else if (endptr == silent_timeout.s) { - printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting silent_timeout to %.*s; no digists found\n", silent_timeout.len, silent_timeout.s); - ADJUSTLEN(printlen,outbufend,replybuffer); - return; - } else { - /* don't lock anything while writing the value - only this command modifies its value */ - m->conf.silent_timeout = silent_timeout_num; - printlen = snprintf (replybuffer,(outbufend-replybuffer), "Success setting silent_timeout to %u\n", silent_timeout_num); - ADJUSTLEN(printlen,outbufend,replybuffer); - } -} - -static void cli_incoming_set_final_timeout(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend) { - int printlen = 0; - unsigned int final_timeout_num; - str final_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 - final_timeout.s = buffer; - final_timeout.len = len; - final_timeout_num = strtol(final_timeout.s, &endptr, 10); - - if ((errno == ERANGE && (final_timeout_num == LONG_MAX || final_timeout_num == LONG_MIN)) || (errno != 0 && final_timeout_num == 0)) { - printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting final_timeout to %.*s; errno=%d\n", final_timeout.len, final_timeout.s, errno); - ADJUSTLEN(printlen,outbufend,replybuffer); - return; - } else if (endptr == final_timeout.s) { - printlen = snprintf (replybuffer,(outbufend-replybuffer), "Fail setting final_timeout to %.*s; no digists found\n", final_timeout.len, final_timeout.s); - ADJUSTLEN(printlen,outbufend,replybuffer); - return; - } else { - /* don't lock anything while writing the value - only this command modifies its value */ - m->conf.final_timeout = final_timeout_num; - printlen = snprintf (replybuffer,(outbufend-replybuffer), "Success setting final_timeout to %u\n", final_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; @@ -527,11 +469,11 @@ static void cli_incoming_set(char* buffer, int len, struct callmaster* m, char* } 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); + 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_silent_timeout(buffer+strlen(SET_SILENT_TIMEOUT), len-strlen(SET_SILENT_TIMEOUT), m, replybuffer, outbufend); + 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_final_timeout(buffer+strlen(SET_FINAL_TIMEOUT), len-strlen(SET_FINAL_TIMEOUT), m, replybuffer, outbufend); + 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/main.c b/daemon/main.c index 267133fba..4b1b56f50 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -534,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) {