From 4882d917ba905af6bd33ced7792ce5c7bf961d5e Mon Sep 17 00:00:00 2001 From: Frederic-Philippe Metz Date: Fri, 5 Dec 2014 03:21:16 -0500 Subject: [PATCH] RTPENGINE-1_total_statistics_rectl.patch: Neues rectl kommando list totals, mit dem man sich die totalen statistiken ausgeben kann Author: Frederic-Philippe Metz --- daemon/call.c | 114 ++++++++++++++++++++++++++++++++++++++------ daemon/call.h | 15 ++++++ daemon/cli.c | 50 +++++++++++++++++++ daemon/main.c | 3 ++ utils/rtpengine-ctl | 1 + 5 files changed, 169 insertions(+), 14 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index d80d64c5e..bf4eb0ce6 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -438,7 +438,7 @@ void kernelize(struct packet_stream *stream) { PS_SET(stream, KERNELIZED); return; - + no_kernel_warn: ilog(LOG_WARNING, "No support for kernel packet forwarding available"); no_kernel: @@ -1036,6 +1036,8 @@ static void call_timer_iterator(void *key, void *val, void *ptr) { rwlock_lock_r(&c->master_lock); log_info_call(c); + cm = c->callmaster; + if (c->deleted && poller_now >= c->deleted && c->last_signal <= c->deleted) goto delete; @@ -1048,8 +1050,6 @@ static void call_timer_iterator(void *key, void *val, void *ptr) { if (!c->streams) goto drop; - cm = c->callmaster; - for (it = c->streams; it; it = it->next) { ps = it->data; mutex_lock(&ps->in_lock); @@ -2338,16 +2338,36 @@ static void unkernelize(struct packet_stream *p) { void timeval_subtract (struct timeval *result, const struct timeval *a, const struct timeval *b) { long microseconds=0; + microseconds = ((long)a->tv_sec - (long)b->tv_sec) * 1000000 + ((long)a->tv_usec - (long)b->tv_usec); + result->tv_sec = microseconds/(long)1000000; + result->tv_usec = microseconds%(long)1000000; +} - microseconds = (a->tv_sec - b->tv_sec) * 1000000 + ((long)a->tv_usec - (long)b->tv_usec); - result->tv_sec = microseconds/1000000; - result->tv_usec = microseconds%1000000; +void timeval_multiply(struct timeval *result, const struct timeval *a, const long multiplier) { + long microseconds=0; + microseconds = (((long)a->tv_sec * 1000000) + (long)a->tv_usec) * multiplier; + result->tv_sec = microseconds/(long)1000000; + result->tv_usec = microseconds%(long)1000000; +} + +void timeval_devide(struct timeval *result, const struct timeval *a, const long devisor) { + long microseconds=0; + microseconds = (((long)a->tv_sec * 1000000) + (long)a->tv_usec) / devisor; + result->tv_sec = microseconds/(long)1000000; + result->tv_usec = microseconds%(long)1000000; +} + +void timeval_add(struct timeval *result, const struct timeval *a, const struct timeval *b) { + long microseconds=0; + microseconds = ((long)a->tv_sec + (long)b->tv_sec) * (long)1000000 + ((long)a->tv_usec + (long)b->tv_usec); + result->tv_sec = microseconds/(long)1000000; + result->tv_usec = microseconds%(long)1000000; } /* called lock-free, but must hold a reference to the call */ void call_destroy(struct call *c) { struct callmaster *m = c->callmaster; - struct packet_stream *ps; + struct packet_stream *ps=0, *ps2=0; struct stream_fd *sfd; struct poller *p = m->poller; GSList *l; @@ -2356,13 +2376,15 @@ void call_destroy(struct call *c) { struct call_media *md; GList *k, *o; char buf[64]; - struct timeval tim_result; + struct timeval tim_result_duration; static const int CDRBUFLENGTH = 4096*2; char reasonbuf[16]; memset(&reasonbuf,0,16); char tagtypebuf[16]; memset(&tagtypebuf,0,16); - char cdrbuffer[CDRBUFLENGTH]; memset(&cdrbuffer,0,CDRBUFLENGTH); - char* cdrbufcur = cdrbuffer; - int cdrlinecnt = 0; + char cdrbuffer[CDRBUFLENGTH]; memset(&cdrbuffer,0,CDRBUFLENGTH); + char* cdrbufcur = cdrbuffer; + int cdrlinecnt = 0; + int found = 0; + //char tmpstreampairstatus[2]; memset(&tmpstreampairstatus,0,2); rwlock_lock_w(&m->hashlock); ret = g_hash_table_remove(m->callhash, &c->callid); @@ -2386,8 +2408,8 @@ void call_destroy(struct call *c) { for (l = c->monologues; l; l = l->next) { ml = l->data; if (_log_facility_cdr) { - memset(&tim_result,0,sizeof(struct timeval)); - timeval_subtract(&tim_result,&ml->terminated,&ml->started); + memset(&tim_result_duration,0,sizeof(struct timeval)); + timeval_subtract(&tim_result_duration,&ml->terminated,&ml->started); cdrbufcur += sprintf(cdrbufcur, "ml%i_start_time=%ld.%06lu, " "ml%i_end_time=%ld.%06ld, " "ml%i_duration=%ld.%06ld, " @@ -2397,7 +2419,7 @@ void call_destroy(struct call *c) { "ml%i_remote_tag=%s, ", cdrlinecnt, ml->started.tv_sec, ml->started.tv_usec, cdrlinecnt, ml->terminated.tv_sec, ml->terminated.tv_usec, - cdrlinecnt, tim_result.tv_sec, tim_result.tv_usec, + cdrlinecnt, tim_result_duration.tv_sec, tim_result_duration.tv_usec, cdrlinecnt, get_term_reason_text(reasonbuf,ml->term_reason), cdrlinecnt, ml->tag.s, cdrlinecnt, get_tag_type_text(tagtypebuf,ml->tagtype), @@ -2449,12 +2471,76 @@ void call_destroy(struct call *c) { (unsigned long long) ps->stats.packets, (unsigned long long) ps->stats.bytes, (unsigned long long) ps->stats.errors); + m->totalstats.total_relayed_packets += (unsigned long long) ps->stats.packets; + m->totalstats.total_relayed_errors += (unsigned long long) ps->stats.errors; } } if (_log_facility_cdr) ++cdrlinecnt; } + // --- for statistics getting one way stream or no relay at all + m->totalstats.total_nopacket_relayed_sess *= 2; + for (l = c->monologues; l; l = l->next) { + ml = l->data; + + // --- go through partner ml and search the RTP + for (k = ml->medias.head; k; k = k->next) { + md = k->data; + + for (o = md->streams.head; o; o = o->next) { + ps = o->data; + if ((PS_ISSET(ps, RTP) && !PS_ISSET(ps, RTCP))) { + // --- only RTP is interesting + found = 1; + break; + } + } + if (found) { break; } + } + found = 0; + + // --- go through partner ml and search the RTP + for (k = ml->active_dialogue->medias.head; k; k = k->next) { + md = k->data; + + for (o = md->streams.head; o; o = o->next) { + ps2 = o->data; + if ((PS_ISSET(ps2, RTP) && !PS_ISSET(ps2, RTCP))) { + // --- only RTP is interesting + found = 1; + break; + } + } + if (found) { break; } + } + + if (ps && ps2 && ps->stats.packets!=0 && ps2->stats.packets==0) + m->totalstats.total_oneway_stream_sess++; + + if (ps && ps2 && ps->stats.packets==0 && ps2->stats.packets==0) + m->totalstats.total_nopacket_relayed_sess++; + + } + m->totalstats.total_nopacket_relayed_sess /= 2; + + m->totalstats.total_managed_sess += 1; + + ml = c->monologues->data; + if (ml->term_reason==TIMEOUT) { + m->totalstats.total_timeout_sess++; + } else if (ml->term_reason==SILENT_TIMEOUT) { + m->totalstats.total_silent_timeout_sess++; + } else if (ml->term_reason==REGULAR) { + m->totalstats.total_regular_term_sess++; + } else if (ml->term_reason==FORCED) { + m->totalstats.total_forced_term_sess++; + } + + timeval_multiply(&m->totalstats.total_average_call_dur,&m->totalstats.total_average_call_dur,m->totalstats.total_managed_sess-1); + timeval_add(&m->totalstats.total_average_call_dur,&m->totalstats.total_average_call_dur,&tim_result_duration); + timeval_devide(&m->totalstats.total_average_call_dur,&m->totalstats.total_average_call_dur,m->totalstats.total_managed_sess); + if (_log_facility_cdr) /* log it */ cdrlog(cdrbuffer); diff --git a/daemon/call.h b/daemon/call.h index fefc7f033..8a2b5f68d 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -192,6 +192,20 @@ struct stats { u_int64_t errors; }; +struct totalstats { + time_t started; + u_int64_t total_managed_sess; + u_int64_t total_timeout_sess; + u_int64_t total_silent_timeout_sess; + u_int64_t total_regular_term_sess; + u_int64_t total_forced_term_sess; + u_int64_t total_relayed_packets; + u_int64_t total_relayed_errors; + u_int64_t total_nopacket_relayed_sess; + u_int64_t total_oneway_stream_sess; + struct timeval total_average_call_dur; +}; + struct udp_fd { int fd; u_int16_t localport; @@ -395,6 +409,7 @@ struct callmaster { struct stats statsps; /* per second stats, running timer */ mutex_t statslock; struct stats stats; /* copied from statsps once a second */ + struct totalstats totalstats; struct poller *poller; pcre *info_re; diff --git a/daemon/cli.c b/daemon/cli.c index f59bacfef..0c10c66ef 100644 --- a/daemon/cli.c +++ b/daemon/cli.c @@ -23,6 +23,34 @@ static const char* TRUNCATED = " ... Output truncated. Increase Output Buffer truncate_output(replybuffer); \ replybuffer += (printlen>=outbufend-replybuffer)?outbufend-replybuffer:printlen; } while (0); +static void cli_incoming_list_totals(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend) { + int printlen=0; + printlen = snprintf(replybuffer,(outbufend-replybuffer), "\nTotal statistics (does not include current running sessions):\n\n"); + ADJUSTLEN(printlen,outbufend,replybuffer); + printlen = snprintf(replybuffer,(outbufend-replybuffer), " Uptime of rtpengine :%llu seconds\n", (unsigned long long)time(NULL)-m->totalstats.started); + ADJUSTLEN(printlen,outbufend,replybuffer); + printlen = snprintf(replybuffer,(outbufend-replybuffer), " Total managed sessions :%llu\n", (unsigned long long)m->totalstats.total_managed_sess); + ADJUSTLEN(printlen,outbufend,replybuffer); + printlen = snprintf(replybuffer,(outbufend-replybuffer), " Total timed-out sessions via TIMEOUT :%llu\n",(unsigned long long)m->totalstats.total_timeout_sess); + ADJUSTLEN(printlen,outbufend,replybuffer); + printlen = snprintf(replybuffer,(outbufend-replybuffer), " Total timed-out sessions via SILENT_TIMEOUT :%llu\n",(unsigned long long)m->totalstats.total_silent_timeout_sess); + ADJUSTLEN(printlen,outbufend,replybuffer); + printlen = snprintf(replybuffer,(outbufend-replybuffer), " Total regular terminated sessions :%llu\n",(unsigned long long)m->totalstats.total_regular_term_sess); + ADJUSTLEN(printlen,outbufend,replybuffer); + printlen = snprintf(replybuffer,(outbufend-replybuffer), " Total forced terminated sessions :%llu\n",(unsigned long long)m->totalstats.total_forced_term_sess); + ADJUSTLEN(printlen,outbufend,replybuffer); + printlen = snprintf(replybuffer,(outbufend-replybuffer), " Total relayed packets :%llu\n",(unsigned long long)m->totalstats.total_relayed_packets); + ADJUSTLEN(printlen,outbufend,replybuffer); + printlen = snprintf(replybuffer,(outbufend-replybuffer), " Total relayed packet errors :%llu\n",(unsigned long long)m->totalstats.total_relayed_errors); + ADJUSTLEN(printlen,outbufend,replybuffer); + printlen = snprintf(replybuffer,(outbufend-replybuffer), " Total number of streams with no relayed packets :%llu\n", (unsigned long long)m->totalstats.total_nopacket_relayed_sess); + ADJUSTLEN(printlen,outbufend,replybuffer); + printlen = snprintf(replybuffer,(outbufend-replybuffer), " Total number of 1-way streams :%llu\n",(unsigned long long)m->totalstats.total_oneway_stream_sess); + ADJUSTLEN(printlen,outbufend,replybuffer); + printlen = snprintf(replybuffer,(outbufend-replybuffer), " Average call duration :%ld.%06ld\n\n",m->totalstats.total_average_call_dur.tv_sec,m->totalstats.total_average_call_dur.tv_usec); + ADJUSTLEN(printlen,outbufend,replybuffer); +} + static void cli_incoming_list_callid(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend) { str callid; struct call* c=0; @@ -106,6 +134,7 @@ static void cli_incoming_list(char* buffer, int len, struct callmaster* m, char* static const char* LIST_NUMSESSIONS = "numsessions"; static const char* LIST_SESSIONS = "sessions"; static const char* LIST_SESSION = "session"; + static const char* LIST_TOTALS = "totals"; if (len<=1) { printlen = snprintf(replybuffer, outbufend-replybuffer, "%s\n", "More parameters required."); @@ -137,6 +166,8 @@ static void cli_incoming_list(char* buffer, int len, struct callmaster* m, char* rwlock_unlock_r(&m->hashlock); } else if (len>=strlen(LIST_SESSION) && strncmp(buffer,LIST_SESSION,strlen(LIST_SESSION)) == 0) { cli_incoming_list_callid(buffer+strlen(LIST_SESSION), len-strlen(LIST_SESSION), m, replybuffer, outbufend); + } else if (len>=strlen(LIST_TOTALS) && strncmp(buffer,LIST_TOTALS,strlen(LIST_TOTALS)) == 0) { + cli_incoming_list_totals(buffer+strlen(LIST_TOTALS), len-strlen(LIST_TOTALS), m, replybuffer, outbufend); } else { printlen = snprintf(replybuffer, outbufend-replybuffer, "%s:%s\n", "Unknown 'list' command", buffer); ADJUSTLEN(printlen,outbufend,replybuffer); @@ -149,6 +180,8 @@ static void cli_incoming_terminate(char* buffer, int len, struct callmaster* m, int printlen=0; GHashTableIter iter; gpointer key, value; + struct call_monologue *ml; + GSList *i; if (len<=1) { printlen = snprintf(replybuffer, outbufend-replybuffer, "%s\n", "More parameters required."); @@ -165,6 +198,14 @@ static void cli_incoming_terminate(char* buffer, int len, struct callmaster* m, g_hash_table_iter_next (&iter, &key, &value); c = (struct call*)value; if (!c) continue; + if (!c->ml_deleted) { + for (i = c->monologues; i; i = i->next) { + ml = i->data; + memset(&ml->terminated,0,sizeof(struct timeval)); + gettimeofday(&(ml->terminated), NULL); + ml->term_reason = FORCED; + } + } call_destroy(c); } ilog(LOG_INFO,"All calls terminated by operator."); @@ -181,6 +222,15 @@ static void cli_incoming_terminate(char* buffer, int len, struct callmaster* m, ADJUSTLEN(printlen,outbufend,replybuffer); return; } + + if (!c->ml_deleted) { + for (i = c->monologues; i; i = i->next) { + ml = i->data; + memset(&ml->terminated,0,sizeof(struct timeval)); + gettimeofday(&(ml->terminated), NULL); + ml->term_reason = FORCED; + } + } call_destroy(c); printlen = snprintf(replybuffer, outbufend-replybuffer, "\nCall Id (%s) successfully terminated by operator.\n\n",termparam.s); diff --git a/daemon/main.c b/daemon/main.c index d972c1604..0c9dbc26f 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -665,6 +665,9 @@ no_kernel: ctx->m->conf = mc; callmaster_config_init(ctx->m); + ZERO(ctx->m->totalstats); + ctx->m->totalstats.started = time(NULL); + if (!foreground) daemonize(); wpidfile(); diff --git a/utils/rtpengine-ctl b/utils/rtpengine-ctl index 80a876ebb..413b92fea 100755 --- a/utils/rtpengine-ctl +++ b/utils/rtpengine-ctl @@ -18,6 +18,7 @@ showusage() { echo " numsessions : prints the number of sessions" echo " sessions : print one-liner session information" echo " session : print detail about one session" + echo " totals : print total statistics (does not include current sessions)" echo "" echo " terminate [ all | ]" echo " all : terminates all current sessions"