From 9886de4654aad53e3fc2eb0a79a6971a8f61f271 Mon Sep 17 00:00:00 2001 From: Frederic-Philippe Metz Date: Thu, 4 Dec 2014 05:29:55 -0500 Subject: [PATCH 01/16] cdrpatch.dpatch: Generiert CDRs. Diese werden in eine konfigurierbare Log Facility geschrieben. Author: Frederic-Philippe Metz --- README.md | 5 +++ daemon/call.c | 47 ++++++++++++++++++++++++++++ daemon/log.c | 8 +++++ daemon/log.h | 6 ++-- daemon/main.c | 9 ++++++ debian/ngcp-rtpengine-daemon.default | 1 + debian/ngcp-rtpengine-daemon.init | 1 + el/rtpengine.init | 5 +++ el/rtpengine.sysconfig | 1 + 9 files changed, 79 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ff651726e..f6732b940 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,7 @@ option and which are reproduced below: -b, --b2b-url=STRING XMLRPC URL of B2B UA -L, --log-level=INT Mask log priorities above this level --log-facility=daemon|local0|... Syslog facility to use for logging + --log-facility-cdr=local0|... Syslog facility to use for logging CDRs -E, --log-stderr Log on stderr instead of syslog -x, --xmlrpc-format=INT XMLRPC timeout request format to use. 0: SEMS DI, 1: call-id only --num-threads=INT Number of worker threads to create @@ -309,6 +310,10 @@ The options are described in more detail below. The syslog facilty to use when sending log messages to the syslog daemon. Defaults to `daemon`. +* --log-facilty-cdr=daemon|local0|...|local7|... + + Same as --log-facility with the difference that only CDRs are written to this log facility. + * -E, --log-stderr Log to stderr instead of syslog. Only useful in combination with `--foreground`. diff --git a/daemon/call.c b/daemon/call.c index c806b5eb6..e44e83d7e 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -831,6 +831,7 @@ forward: if (ret == -1) { ret = -errno; + ilog(LOG_DEBUG,"Error when sending message. Error:%s\n",strerror(errno)); stream->stats.errors++; mutex_lock(&cm->statspslock); cm->statsps.errors++; @@ -2311,6 +2312,10 @@ void call_destroy(struct call *c) { struct call_media *md; GList *k, *o; char buf[64]; + static const int CDRBUFLENGTH = 4096*2; + char cdrbuffer[CDRBUFLENGTH]; memset(&cdrbuffer,0,CDRBUFLENGTH); + char* cdrbufcur = cdrbuffer; + int cdrlinecnt = 0; rwlock_lock_w(&m->hashlock); ret = g_hash_table_remove(m->callhash, &c->callid); @@ -2328,8 +2333,26 @@ void call_destroy(struct call *c) { ilog(LOG_INFO, "Final packet stats:"); + /* CDRs and statistics */ + cdrbufcur += sprintf(cdrbufcur,"ci=%s, ",c->callid.s); for (l = c->monologues; l; l = l->next) { ml = l->data; + if (_log_facility_cdr) { + cdrbufcur += sprintf(cdrbufcur, "ml%i_start_time=%u, " + "ml%i_end_time=%u, " + "ml%i_duration=%u, " + "ml%i_termination=%s, " + "ml%i_local_tag=%s, " + "ml%i_remote_tag=%s, ", + + cdrlinecnt, (unsigned int)ml->created, + cdrlinecnt, (unsigned int)poller_now, + cdrlinecnt, (unsigned int)poller_now-(unsigned int)ml->created, + cdrlinecnt, "TOBEDONE", + cdrlinecnt, ml->tag.s, + cdrlinecnt, ml->active_dialogue ? ml->active_dialogue->tag.s : "(none)"); + } + ilog(LOG_INFO, "--- Tag '"STR_FORMAT"', created " "%u:%02u ago, in dialogue with '"STR_FORMAT"'", STR_FMT(&ml->tag), @@ -2348,6 +2371,24 @@ void call_destroy(struct call *c) { continue; smart_ntop_p(buf, &ps->endpoint.ip46, sizeof(buf)); + + if (_log_facility_cdr) { + const char* protocol = (!PS_ISSET(ps, RTP) && PS_ISSET(ps, RTCP)) ? "rtcp" : "rtp"; + cdrbufcur += sprintf(cdrbufcur, + "ml%i_midx%u_%s_endpoint_ip=%s, " + "ml%i_midx%u_%s_endpoint_port=%u, " + "ml%i_midx%u_%s_local_relay_port=%u, " + "ml%i_midx%u_%s_relayed_packets=%llu, " + "ml%i_midx%u_%s_relayed_bytes=%llu, " + "ml%i_midx%u_%s_relayed_errors=%llu, ", + cdrlinecnt, md->index, protocol, buf, + cdrlinecnt, md->index, protocol, ps->endpoint.port, + cdrlinecnt, md->index, protocol, (unsigned int) (ps->sfd ? ps->sfd->fd.localport : 0), + cdrlinecnt, md->index, protocol, (unsigned long long) ps->stats.packets, + cdrlinecnt, md->index, protocol, (unsigned long long) ps->stats.bytes, + cdrlinecnt, md->index, protocol, (unsigned long long) ps->stats.errors); + } + ilog(LOG_INFO, "------ Media #%u, port %5u <> %15s:%-5hu%s, " "%llu p, %llu b, %llu e", md->index, @@ -2359,8 +2400,14 @@ void call_destroy(struct call *c) { (unsigned long long) ps->stats.errors); } } + if (_log_facility_cdr) + ++cdrlinecnt; } + if (_log_facility_cdr) + /* log it */ + cdrlog(cdrbuffer); + for (l = c->streams; l; l = l->next) { ps = l->data; diff --git a/daemon/log.c b/daemon/log.c index 94d9f6421..a46b5a9bb 100644 --- a/daemon/log.c +++ b/daemon/log.c @@ -57,6 +57,7 @@ static const char* const prio_str[] = { gboolean _log_stderr = 0; int _log_facility = LOG_DAEMON; +int _log_facility_cdr = 0; static GHashTable *__log_limiter; @@ -167,6 +168,13 @@ out: free(msg); } +void cdrlog(const char* cdrbuffer) { + int previous; + int mask = LOG_MASK (LOG_INFO); + previous = setlogmask(mask); + syslog(LOG_INFO | _log_facility_cdr, "%s", cdrbuffer); + setlogmask(previous); +} void log_init() { mutex_init(&__log_limiter_lock); diff --git a/daemon/log.h b/daemon/log.h index d837a4b60..9d09eba14 100644 --- a/daemon/log.h +++ b/daemon/log.h @@ -22,6 +22,7 @@ struct log_info { extern gboolean _log_stderr; extern int _log_facility; +extern int _log_facility_cdr; typedef struct _fac_code { @@ -46,14 +47,11 @@ extern unsigned int max_log_line_length; void log_init(void); void ilog(int prio, const char *fmt, ...)__attribute__ ((format (printf, 2, 3))); - +void cdrlog(const char* cdrbuffer); #include "obj.h" - - - INLINE void log_info_clear() { switch (log_info.e) { case LOG_INFO_NONE: diff --git a/daemon/main.c b/daemon/main.c index 16f4786ee..bc35434f2 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -311,6 +311,7 @@ static void options(int *argc, char ***argv) { char *listenngs = NULL; char *redisps = NULL; char *log_facility_s = NULL; + char *log_facility_cdr_s = NULL; int version = 0; int sip_source = 0; @@ -334,6 +335,7 @@ static void options(int *argc, char ***argv) { { "b2b-url", 'b', 0, G_OPTION_ARG_STRING, &b2b_url, "XMLRPC URL of B2B UA" , "STRING" }, { "log-level", 'L', 0, G_OPTION_ARG_INT, (void *)&log_level,"Mask log priorities above this level","INT" }, { "log-facility",0, 0, G_OPTION_ARG_STRING, &log_facility_s, "Syslog facility to use for logging", "daemon|local0|...|local7"}, + { "log-facility-cdr",0, 0, G_OPTION_ARG_STRING, &log_facility_cdr_s, "Syslog facility to use for logging CDRs", "daemon|local0|...|local7"}, { "log-stderr", 'E', 0, G_OPTION_ARG_NONE, &_log_stderr, "Log on stderr instead of syslog", NULL }, { "xmlrpc-format",'x', 0, G_OPTION_ARG_INT, &xmlrpc_fmt, "XMLRPC timeout request format to use. 0: SEMS DI, 1: call-id only", "INT" }, { "num-threads", 0, 0, G_OPTION_ARG_INT, &num_threads, "Number of worker threads to create", "INT" }, @@ -407,6 +409,13 @@ static void options(int *argc, char ***argv) { } } + if (log_facility_cdr_s) { + if (!parse_log_facility(log_facility_cdr_s, &_log_facility_cdr)) { + print_available_log_facilities(); + die ("Invalid log facility for CDR '%s' (--log-facility-cdr)\n", log_facility_cdr_s); + } + } + if (_log_stderr) { write_log = log_to_stderr; max_log_line_length = 0; diff --git a/debian/ngcp-rtpengine-daemon.default b/debian/ngcp-rtpengine-daemon.default index 74c8a44c1..9cf8cab7b 100644 --- a/debian/ngcp-rtpengine-daemon.default +++ b/debian/ngcp-rtpengine-daemon.default @@ -19,4 +19,5 @@ TABLE=0 # B2B_URL=http://127.0.0.1:8090/ # LOG_LEVEL=6 # LOG_FACILITY=daemon +# LOG_FACILITY_CDR=daemon # NUM_THREADS=5 diff --git a/debian/ngcp-rtpengine-daemon.init b/debian/ngcp-rtpengine-daemon.init index d68cf0d4a..82637eb55 100755 --- a/debian/ngcp-rtpengine-daemon.init +++ b/debian/ngcp-rtpengine-daemon.init @@ -68,6 +68,7 @@ fi OPTIONS="$OPTIONS --table=$TABLE" [ -z "$LOG_LEVEL" ] || OPTIONS="$OPTIONS --log-level=$LOG_LEVEL" [ -z "$LOG_FACILITY" ] || OPTIONS="$OPTIONS --log-facility=$LOG_FACILITY" +[ -z "$LOG_FACILITY_CDR" ] || OPTIONS="$OPTIONS --log-facility-cdr=$LOG_FACILITY_CDR" [ -z "$NUM_THREADS" ] || OPTIONS="$OPTIONS --num-threads=$NUM_THREADS" if test "$FORK" = "no" ; then OPTIONS="$OPTIONS --foreground" diff --git a/el/rtpengine.init b/el/rtpengine.init index 876b2ea64..5c0c97d4b 100644 --- a/el/rtpengine.init +++ b/el/rtpengine.init @@ -146,6 +146,11 @@ build_opts() { then OPTS+=" --num-threads=$NUM_THREADS" fi + + if [[ -n "$LOG_FACILITY_CDR" ]] + then + OPTS+=" --log-facility-cdr=$LOG_FACILITY_CDR" + fi } start() { diff --git a/el/rtpengine.sysconfig b/el/rtpengine.sysconfig index 70e93370a..2baa2997e 100644 --- a/el/rtpengine.sysconfig +++ b/el/rtpengine.sysconfig @@ -34,6 +34,7 @@ LISTEN_UDP=127.0.0.1:2222 # IP address and port combination for UDP # #LOG_LEVEL=6 # Log level to use #LOG_FACILITY=daemon # Syslog facility to use +#LOG_FACILITY_CDR=daemon # Syslog facility to write CDRs #NUM_THREADS=5 # How many worker threads to launch # The following items are for use with NGCP From 947b35e889bda7bf6d33a90f3c09b06306fe6152 Mon Sep 17 00:00:00 2001 From: Frederic-Philippe Metz Date: Thu, 4 Dec 2014 05:30:46 -0500 Subject: [PATCH 02/16] fixed_callduration_and_added_termination_reason_20141125: callduration fix + dier termination reason, warum/wie der call beendet wurde. Author: Frederic-Philippe Metz --- daemon/call.c | 46 ++++++++++++++++++++++++++++++++++++++++------ daemon/call.h | 10 +++++++++- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index e44e83d7e..77deea2d3 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -122,7 +122,15 @@ const struct transport_protocol transport_protocols[] = { }; const int num_transport_protocols = G_N_ELEMENTS(transport_protocols); +const char * get_term_reason_text(char *buf, enum termination_reason t) { + if (t==TIMEOUT) { buf = "TIMEOUT"; return buf; } + if (t==REGULAR) { buf = "REGULAR"; return buf; } + if (t==FORCED) { buf = "FORCED"; return buf; } + if (t==SILENT_TIMEOUT) { buf = "SILENT_TIMEOUT"; return buf; } + buf = "UNKNOWN"; + return buf; +} static void determine_handler(struct packet_stream *in, const struct packet_stream *out); @@ -981,6 +989,7 @@ static int call_timer_delete_monologues(struct call *c) { } __monologue_destroy(ml); + ml->deleted = 0; if (!g_hash_table_size(c->tags)) { @@ -1015,6 +1024,9 @@ 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; + struct call_monologue *ml; + GSList *i; rwlock_lock_r(&c->master_lock); log_info_call(c); @@ -1056,8 +1068,11 @@ no_sfd: goto next; check = cm->conf.timeout; - if (!MEDIA_ISSET(ps->media, RECV) || !sfd) + tmp_t_reason = 1; + if (!MEDIA_ISSET(ps->media, RECV) || !sfd) { check = cm->conf.silent_timeout; + tmp_t_reason = 2; + } if (poller_now - ps->last_packet < check) good = 1; @@ -1069,6 +1084,18 @@ next: if (good) goto out; + for (i = c->monologues; i; i = i->next) { + ml = i->data; + ml->terminated = time(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; + } + } + ilog(LOG_INFO, "Closing call due to timeout"); drop: @@ -2313,6 +2340,7 @@ void call_destroy(struct call *c) { GList *k, *o; char buf[64]; static const int CDRBUFLENGTH = 4096*2; + char reasonbuf[16]; memset(&reasonbuf,0,16); char cdrbuffer[CDRBUFLENGTH]; memset(&cdrbuffer,0,CDRBUFLENGTH); char* cdrbufcur = cdrbuffer; int cdrlinecnt = 0; @@ -2344,11 +2372,10 @@ void call_destroy(struct call *c) { "ml%i_termination=%s, " "ml%i_local_tag=%s, " "ml%i_remote_tag=%s, ", - cdrlinecnt, (unsigned int)ml->created, - cdrlinecnt, (unsigned int)poller_now, - cdrlinecnt, (unsigned int)poller_now-(unsigned int)ml->created, - cdrlinecnt, "TOBEDONE", + cdrlinecnt, (unsigned int)ml->terminated, + cdrlinecnt, (unsigned int)ml->terminated-(unsigned int)ml->created, + cdrlinecnt, get_term_reason_text(reasonbuf,ml->term_reason), cdrlinecnt, ml->tag.s, cdrlinecnt, ml->active_dialogue ? ml->active_dialogue->tag.s : "(none)"); } @@ -2804,6 +2831,7 @@ int call_delete_branch(struct callmaster *m, const str *callid, const str *branc struct call_monologue *ml; int ret; const str *match_tag; + GSList *i; c = call_get(callid, m); if (!c) { @@ -2811,6 +2839,12 @@ int call_delete_branch(struct callmaster *m, const str *callid, const str *branc goto err; } + for (i = c->monologues; i; i = i->next) { + ml = i->data; + ml->terminated = time(NULL); + ml->term_reason = REGULAR; + } + if (!fromtag || !fromtag->s || !fromtag->len) goto del_all; @@ -2843,7 +2877,7 @@ int call_delete_branch(struct callmaster *m, const str *callid, const str *branc ilog(LOG_INFO, "Scheduling deletion of call branch '"STR_FORMAT"' in %d seconds", STR_FMT(&ml->tag), DELETE_DELAY); - ml->deleted = poller_now + 30; + ml->deleted = poller_now + DELETE_DELAY; if (!c->ml_deleted || c->ml_deleted > ml->deleted) c->ml_deleted = ml->deleted; goto success_unlock; diff --git a/daemon/call.h b/daemon/call.h index 2a37b8331..f0b8ea5af 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -12,7 +12,13 @@ #include "compat.h" - +enum termination_reason { + UNKNOWN=0, + REGULAR=1, + FORCED=2, + TIMEOUT=3, + SILENT_TIMEOUT=4 +}; enum stream_address_format { SAF_TCP, @@ -299,6 +305,8 @@ struct call_monologue { str tag; time_t created; /* RO */ time_t deleted; + time_t terminated; + enum termination_reason term_reason; GHashTable *other_tags; struct call_monologue *active_dialogue; From ee655bdcc63eca3ccb32d18cb76d33920ed17bf7 Mon Sep 17 00:00:00 2001 From: Frederic-Philippe Metz Date: Thu, 4 Dec 2014 05:31:22 -0500 Subject: [PATCH 03/16] added_milliseconds_precision_for_CDR.patch: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Im Telco Umfeld ist hier millisekunden-Auflösung gefordert. Nur UDP control zunächst. Author: Frederic-Philippe Metz --- daemon/call.c | 31 +++++++++++++++++++++++-------- daemon/call.h | 4 +++- daemon/call_interfaces.c | 2 ++ 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index 77deea2d3..acfc0b313 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include "poller.h" #include "aux.h" @@ -1086,7 +1088,8 @@ next: for (i = c->monologues; i; i = i->next) { ml = i->data; - ml->terminated = time(NULL); + memset(&ml->terminated,0,sizeof(struct timeval)); + gettimeofday(&(ml->terminated),NULL); if (tmp_t_reason==1) { ml->term_reason = TIMEOUT; } else if (tmp_t_reason==2) { @@ -2327,6 +2330,14 @@ static void unkernelize(struct packet_stream *p) { PS_CLEAR(p, KERNELIZED); } +void timeval_subtract (struct timeval *result, const struct timeval *a, const struct timeval *b) { + long microseconds=0; + + 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; +} + /* called lock-free, but must hold a reference to the call */ void call_destroy(struct call *c) { struct callmaster *m = c->callmaster; @@ -2339,6 +2350,7 @@ void call_destroy(struct call *c) { struct call_media *md; GList *k, *o; char buf[64]; + struct timeval tim_result; static const int CDRBUFLENGTH = 4096*2; char reasonbuf[16]; memset(&reasonbuf,0,16); char cdrbuffer[CDRBUFLENGTH]; memset(&cdrbuffer,0,CDRBUFLENGTH); @@ -2366,15 +2378,17 @@ void call_destroy(struct call *c) { for (l = c->monologues; l; l = l->next) { ml = l->data; if (_log_facility_cdr) { - cdrbufcur += sprintf(cdrbufcur, "ml%i_start_time=%u, " - "ml%i_end_time=%u, " - "ml%i_duration=%u, " + memset(&tim_result,0,sizeof(struct timeval)); + timeval_subtract(&tim_result,&ml->terminated,&ml->started); + cdrbufcur += sprintf(cdrbufcur, "ml%i_start_time=%ld.%06lu, " + "ml%i_end_time=%ld.%06ld, " + "ml%i_duration=%ld.%06ld, " "ml%i_termination=%s, " "ml%i_local_tag=%s, " "ml%i_remote_tag=%s, ", - cdrlinecnt, (unsigned int)ml->created, - cdrlinecnt, (unsigned int)ml->terminated, - cdrlinecnt, (unsigned int)ml->terminated-(unsigned int)ml->created, + 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, get_term_reason_text(reasonbuf,ml->term_reason), cdrlinecnt, ml->tag.s, cdrlinecnt, ml->active_dialogue ? ml->active_dialogue->tag.s : "(none)"); @@ -2841,7 +2855,8 @@ int call_delete_branch(struct callmaster *m, const str *callid, const str *branc for (i = c->monologues; i; i = i->next) { ml = i->data; - ml->terminated = time(NULL); + memset(&ml->terminated,0,sizeof(struct timeval)); + gettimeofday(&(ml->terminated), NULL); ml->term_reason = REGULAR; } diff --git a/daemon/call.h b/daemon/call.h index f0b8ea5af..2a162c2ce 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include "compat.h" @@ -305,7 +306,8 @@ struct call_monologue { str tag; time_t created; /* RO */ time_t deleted; - time_t terminated; + struct timeval started; /* for CDR */ + struct timeval terminated; /* for CDR */ enum termination_reason term_reason; GHashTable *other_tags; struct call_monologue *active_dialogue; diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index efd16f88a..253eabcd0 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -174,6 +174,8 @@ static str *call_update_lookup_udp(char **out, struct callmaster *m, enum call_o redis_update(c, m->conf.redis); + gettimeofday(&(monologue->started), NULL); + ilog(LOG_INFO, "Returning to SIP proxy: "STR_FORMAT"", STR_FMT(ret)); goto out; From 131c9e8110fc451e43141c3cc9564f6c91cdcdf3 Mon Sep 17 00:00:00 2001 From: Frederic-Philippe Metz Date: Thu, 4 Dec 2014 05:55:55 -0500 Subject: [PATCH 04/16] cli Ein Commandline interface, wo man von der console and der rtpengine bestimme Dinge abfragen kann. Author: Frederic-Philippe Metz --- README.md | 5 + daemon/Makefile | 2 +- daemon/call.c | 2 +- daemon/call.h | 1 + daemon/cli.c | 308 +++++++++++++++++++++++++++ daemon/cli.h | 18 ++ daemon/main.c | 18 ++ debian/ngcp-rtpengine-daemon.default | 1 + debian/ngcp-rtpengine-daemon.init | 1 + debian/ngcp-rtpengine-daemon.install | 1 + el/rtpengine.init | 5 + el/rtpengine.sysconfig | 1 + utils/rtpengine-ctl | 69 ++++++ 13 files changed, 430 insertions(+), 2 deletions(-) create mode 100644 daemon/cli.c create mode 100644 daemon/cli.h create mode 100755 utils/rtpengine-ctl diff --git a/README.md b/README.md index f6732b940..fca851581 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,7 @@ option and which are reproduced below: -F, --no-fallback Only start when kernel module is available -i, --interface=[NAME/]IP[!IP] Local interface for RTP -l, --listen-tcp=[IP:]PORT TCP port to listen on + -c, --listen-cli=[IP46:]PORT TCP port to listen on, CLI (command line interface) -u, --listen-udp=[IP46:]PORT UDP port to listen on -n, --listen-ng=[IP46:]PORT UDP port to listen on, NG protocol -T, --tos=INT TOS value to set on streams @@ -267,6 +268,10 @@ The options are described in more detail below. It is recommended to specify not only a local port number, but also 127.0.0.1 as interface to bind to. +* -c, --listen-cli + + TCP ip and port to listen for the CLI (command line interface). + * -t, --tos Takes an integer as argument and if given, specifies the TOS value that should be set in outgoing diff --git a/daemon/Makefile b/daemon/Makefile index 68ef67135..bed33cdc0 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -61,7 +61,7 @@ endif SRCS= main.c kernel.c poller.c aux.c control_tcp.c streambuf.c call.c control_udp.c redis.c \ bencode.c cookie_cache.c udp_listener.c control_ng.c sdp.c str.c stun.c rtcp.c \ - crypto.c rtp.c call_interfaces.c dtls.c log.c + crypto.c rtp.c call_interfaces.c dtls.c log.c cli.c OBJS= $(SRCS:.c=.o) diff --git a/daemon/call.c b/daemon/call.c index acfc0b313..9724c742d 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -2645,7 +2645,7 @@ restart: } /* returns call with master_lock held in W, or NULL if not found */ -static struct call *call_get(const str *callid, struct callmaster *m) { +struct call *call_get(const str *callid, struct callmaster *m) { struct call *ret; rwlock_lock_r(&m->hashlock); diff --git a/daemon/call.h b/daemon/call.h index 2a162c2ce..c8ca767bf 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -420,6 +420,7 @@ struct packet_stream *__packet_stream_new(struct call *call); struct call *call_get_or_create(const str *callid, struct callmaster *m); struct call *call_get_opmode(const str *callid, struct callmaster *m, enum call_opmode opmode); struct call_monologue *call_get_mono_dialogue(struct call *call, const str *fromtag, const str *totag); +struct call *call_get(const str *callid, struct callmaster *m); int monologue_offer_answer(struct call_monologue *monologue, GQueue *streams, const struct sdp_ng_flags *flags); int call_delete_branch(struct callmaster *m, const str *callid, const str *branch, const str *fromtag, const str *totag, bencode_item_t *output); diff --git a/daemon/cli.c b/daemon/cli.c new file mode 100644 index 000000000..b26e918e3 --- /dev/null +++ b/daemon/cli.c @@ -0,0 +1,308 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "poller.h" +#include "aux.h" +#include "log.h" +#include "call.h" +#include "cli.h" + + +static const char* TRUNCATED = " ... Output truncated. Increase Output Buffer ...\n"; + +#define truncate_output(x) do { x -= strlen(TRUNCATED)+1; x += sprintf(x,"%s",TRUNCATED); } while (0); + +#define ADJUSTLEN(printlen,outbuflen,replybuffer) do { if (printlen>=(outbufend-replybuffer)) \ + truncate_output(replybuffer); \ + replybuffer += (printlen>=outbufend-replybuffer)?outbufend-replybuffer:printlen; } while (0); + +static void cli_incoming_list_callid(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend) { + str callid; + struct call* c=0; + struct call_monologue *ml; + struct call_media *md; + struct packet_stream *ps; + GSList *l; + GList *k, *o; + char buf[64]; + int printlen=0; + + if (len<=1) { + printlen = snprintf(replybuffer,(outbufend-replybuffer), "%s\n", "More parameters required."); + ADJUSTLEN(printlen,outbufend,replybuffer); + return; + } + ++buffer; --len; // one space + str_init_len(&callid,buffer,len); + + c = call_get(&callid, m); + + if (!c) { + printlen = snprintf(replybuffer,(outbufend-replybuffer), "\nCall Id not found (%s).\n\n",callid.s); + ADJUSTLEN(printlen,outbufend,replybuffer); + return; + } + + printlen = snprintf (replybuffer,(outbufend-replybuffer), "\ncallid: %30s | deletionmark:%4s | created:%12i\n\n", c->callid.s , c->ml_deleted?"yes":"no", (int)c->created); + ADJUSTLEN(printlen,outbufend,replybuffer); + + for (l = c->monologues; l; l = l->next) { + ml = l->data; + + printlen = snprintf(replybuffer,(outbufend-replybuffer), "--- Tag '"STR_FORMAT"', callduration " + "%u:%02u , in dialogue with '"STR_FORMAT"'\n", + STR_FMT(&ml->tag), + (unsigned int) (poller_now - ml->created) / 60, + (unsigned int) (poller_now - ml->created) % 60, + ml->active_dialogue ? ml->active_dialogue->tag.len : 6, + ml->active_dialogue ? ml->active_dialogue->tag.s : "(none)"); + ADJUSTLEN(printlen,outbufend,replybuffer); + + 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, FALLBACK_RTCP)) + continue; + + smart_ntop_p(buf, &ps->endpoint.ip46, sizeof(buf)); + + printlen = snprintf(replybuffer,(outbufend-replybuffer), "------ Media #%u, port %5u <> %15s:%-5hu%s, " + "%llu p, %llu b, %llu e\n", + md->index, + (unsigned int) (ps->sfd ? ps->sfd->fd.localport : 0), + buf, ps->endpoint.port, + (!PS_ISSET(ps, RTP) && PS_ISSET(ps, RTCP)) ? " (RTCP)" : "", + (unsigned long long) ps->stats.packets, + (unsigned long long) ps->stats.bytes, + (unsigned long long) ps->stats.errors); + ADJUSTLEN(printlen,outbufend,replybuffer); + } + } + } + printlen = snprintf(replybuffer,(outbufend-replybuffer), "\n"); + ADJUSTLEN(printlen,outbufend,replybuffer); + + rwlock_unlock_w(&c->master_lock); // because of call_get(..) +} + +static void cli_incoming_list(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend) { + GHashTableIter iter; + gpointer key, value; + str *ptrkey; + struct call *call; + int printlen=0; + + static const char* LIST_NUMSESSIONS = "numsessions"; + static const char* LIST_SESSIONS = "sessions"; + static const char* LIST_SESSION = "session"; + + if (len<=1) { + printlen = snprintf(replybuffer, outbufend-replybuffer, "%s\n", "More parameters required."); + ADJUSTLEN(printlen,outbufend,replybuffer); + return; + } + ++buffer; --len; // one space + + if (len>=strlen(LIST_NUMSESSIONS) && strncmp(buffer,LIST_NUMSESSIONS,strlen(LIST_NUMSESSIONS)) == 0) { + rwlock_lock_r(&m->hashlock); + printlen = snprintf(replybuffer, outbufend-replybuffer, "Current Sessions on rtpengine:%i\n", g_hash_table_size(m->callhash)); + ADJUSTLEN(printlen,outbufend,replybuffer); + rwlock_unlock_r(&m->hashlock); + } else if (len>=strlen(LIST_SESSIONS) && strncmp(buffer,LIST_SESSIONS,strlen(LIST_SESSIONS)) == 0) { + rwlock_lock_r(&m->hashlock); + if (g_hash_table_size(m->callhash)==0) { + printlen = snprintf(replybuffer, outbufend-replybuffer, "No sessions on this media relay.\n"); + ADJUSTLEN(printlen,outbufend,replybuffer); + rwlock_unlock_r(&m->hashlock); + return; + } + g_hash_table_iter_init (&iter, m->callhash); + while (g_hash_table_iter_next (&iter, &key, &value)) { + ptrkey = (str*)key; + call = (struct call*)value; + printlen = snprintf(replybuffer, outbufend-replybuffer, "callid: %30s | deletionmark:%4s | created:%12i\n", ptrkey->s, call->ml_deleted?"yes":"no", (int)call->created); + ADJUSTLEN(printlen,outbufend,replybuffer); + } + 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 { + printlen = snprintf(replybuffer, outbufend-replybuffer, "%s:%s\n", "Unknown 'list' command", buffer); + ADJUSTLEN(printlen,outbufend,replybuffer); + } +} + +static void cli_incoming_terminate(char* buffer, int len, struct callmaster* m, char* replybuffer, const char* outbufend) { + str termparam; + struct call* c=0; + int printlen=0; + GHashTableIter iter; + gpointer key, value; + + if (len<=1) { + printlen = snprintf(replybuffer, outbufend-replybuffer, "%s\n", "More parameters required."); + ADJUSTLEN(printlen,outbufend,replybuffer); + return; + } + ++buffer; --len; // one space + str_init_len(&termparam,buffer,len); + + // --- terminate all calls + if (!str_memcmp(&termparam,"all")) { + while (g_hash_table_size(m->callhash)) { + g_hash_table_iter_init (&iter, m->callhash); + g_hash_table_iter_next (&iter, &key, &value); + c = (struct call*)value; + if (!c) continue; + call_destroy(c); + } + ilog(LOG_INFO,"All calls terminated by operator."); + printlen = snprintf(replybuffer, outbufend-replybuffer, "%s\n", "All calls terminated by operator."); + ADJUSTLEN(printlen,outbufend,replybuffer); + return; + } + + // --- terminate a dedicated call id + c = call_get(&termparam, m); + + if (!c) { + printlen = snprintf(replybuffer, outbufend-replybuffer, "\nCall Id not found (%s).\n\n",termparam.s); + ADJUSTLEN(printlen,outbufend,replybuffer); + return; + } + call_destroy(c); + + printlen = snprintf(replybuffer, outbufend-replybuffer, "\nCall Id (%s) successfully terminated by operator.\n\n",termparam.s); + ADJUSTLEN(printlen,outbufend,replybuffer); + ilog(LOG_WARN, "Call Id (%s) successfully terminated by operator.",termparam.s); + + rwlock_unlock_w(&c->master_lock); +} + +static void cli_incoming(int fd, void *p, uintptr_t u) { + int nfd; + struct sockaddr_in sin; + struct cli *cli = (void *) p; + socklen_t sinl; + static const int BUFLENGTH = 4096*1024; + char replybuffer[BUFLENGTH]; memset(&replybuffer,0,BUFLENGTH); + char* outbuf = replybuffer; + const char* outbufend = replybuffer+BUFLENGTH; + static const int MAXINPUT = 1024; + char inbuf[MAXINPUT]; memset(&inbuf,0,MAXINPUT); + int inlen = 0, readbytes = 0; + int rc=0; + + mutex_lock(&cli->lock); +next: + sinl = sizeof(sin); + nfd = accept(fd, (struct sockaddr *) &sin, &sinl); + if (nfd == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + sprintf(replybuffer, "Could currently not accept CLI commands. Reason:%s\n", strerror(errno)); + goto cleanup; + } + ilog(LOG_INFO, "Accept error:%s\n", strerror(errno)); + goto next; + } + + ilog(LOG_INFO, "New cli connection from " DF, DP(sin)); + + do { + readbytes = read(nfd, inbuf+inlen, MAXINPUT); + if (readbytes == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + ilog(LOG_INFO, "Could currently not read CLI commands. Reason:%s\n", strerror(errno)); + goto cleanup; + } + ilog(LOG_INFO, "Could currently not read CLI commands. Reason:%s\n", strerror(errno)); + } + inlen += readbytes; + } while (readbytes > 0); + + ilog(LOG_INFO, "Got CLI command:%s\n",inbuf); + + static const char* LIST = "list"; + static const char* TERMINATE = "terminate"; + + if (inlen>=strlen(LIST) && strncmp(inbuf,LIST,strlen(LIST)) == 0) { + cli_incoming_list(inbuf+strlen(LIST), inlen-strlen(LIST), cli->callmaster, outbuf, outbufend); + + } else if (inlen>=strlen(TERMINATE) && strncmp(inbuf,TERMINATE,strlen(TERMINATE)) == 0) { + cli_incoming_terminate(inbuf+strlen(TERMINATE), inlen-strlen(TERMINATE), cli->callmaster, outbuf, outbufend); + } else { + sprintf(replybuffer, "%s:%s\n", "Unknown or incomplete command:", inbuf); + } + + do { + rc += write( nfd, (char *)&replybuffer, strlen(replybuffer) ); + } while (rc < strlen(replybuffer)); + +cleanup: + close(nfd); + mutex_unlock(&cli->lock); +} + +static void control_closed(int fd, void *p, uintptr_t u) { + abort(); +} + +struct cli *cli_new(struct poller *p, u_int32_t ip, u_int16_t port, struct callmaster *m) { + struct cli *c; + int fd; + struct sockaddr_in sin; + struct poller_item i; + + if (!p || !m) + return NULL; + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) + return NULL; + + nonblock(fd); + reuseaddr(fd); + + ZERO(sin); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = ip; + sin.sin_port = htons(port); + if (bind(fd, (struct sockaddr *) &sin, sizeof(sin))) + goto fail; + + if (listen(fd, 5)) + goto fail; + + c = obj_alloc0("cli_udp", sizeof(*c), NULL); + c->fd = fd; + c->poller = p; + c->callmaster = m; + mutex_init(&c->lock); + + ZERO(i); + i.fd = fd; + i.closed = control_closed; + i.readable = cli_incoming; + i.obj = &c->obj; + if (poller_add_item(p, &i)) + goto fail2; + + obj_put(c); + return c; + +fail2: + obj_put(c); +fail: + close(fd); + return NULL; +} diff --git a/daemon/cli.h b/daemon/cli.h new file mode 100644 index 000000000..af562107a --- /dev/null +++ b/daemon/cli.h @@ -0,0 +1,18 @@ +#ifndef CLI_UDP_H_ +#define CLI_UDP_H_ + +#include + +struct cli { + struct obj obj; + + struct callmaster *callmaster; + int fd; + struct poller *poller; + mutex_t lock; + +}; + +struct cli *cli_new(struct poller *p, u_int32_t ip, u_int16_t port, struct callmaster *m); + +#endif /* CLI_UDP_H_ */ diff --git a/daemon/main.c b/daemon/main.c index bc35434f2..006502743 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -25,6 +25,7 @@ #include "sdp.h" #include "dtls.h" #include "call_interfaces.h" +#include "cli.h" @@ -91,6 +92,8 @@ static struct in6_addr udp_listenp; static u_int16_t udp_listenport; static struct in6_addr ng_listenp; static u_int16_t ng_listenport; +static u_int32_t cli_listenp; +static u_int16_t cli_listenport; static int tos; static int table = -1; static int no_fallback; @@ -309,6 +312,7 @@ static void options(int *argc, char ***argv) { char *listenps = NULL; char *listenudps = NULL; char *listenngs = NULL; + char *listencli = NULL; char *redisps = NULL; char *log_facility_s = NULL; char *log_facility_cdr_s = NULL; @@ -323,6 +327,7 @@ static void options(int *argc, char ***argv) { { "listen-tcp", 'l', 0, G_OPTION_ARG_STRING, &listenps, "TCP port to listen on", "[IP:]PORT" }, { "listen-udp", 'u', 0, G_OPTION_ARG_STRING, &listenudps, "UDP port to listen on", "[IP46:]PORT" }, { "listen-ng", 'n', 0, G_OPTION_ARG_STRING, &listenngs, "UDP port to listen on, NG protocol", "[IP46:]PORT" }, + { "listen-cli", 'c', 0, G_OPTION_ARG_STRING, &listencli, "UDP port to listen on, CLI", "[IP46:]PORT" }, { "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" }, @@ -380,6 +385,10 @@ static void options(int *argc, char ***argv) { die("Invalid IP or port (--listen-ng)"); } + if (listencli) {if (parse_ip_port(&cli_listenp, &cli_listenport, listencli)) + die("Invalid IP or port (--listen-cli)"); + } + if (tos < 0 || tos > 255) die("Invalid TOS value"); @@ -557,6 +566,7 @@ void create_everything(struct main_context *ctx) { struct control_tcp *ct; struct control_udp *cu; struct control_ng *cn; + struct cli *cl; int kfd = -1; void *dlh; const char **strp; @@ -625,6 +635,14 @@ no_kernel: die("Failed to open UDP control connection port"); } + cl = NULL; + if (cli_listenport) { + callmaster_exclude_port(ctx->m, cli_listenport); + cl = cli_new(ctx->p, cli_listenp, cli_listenport, ctx->m); + if (!cl) + die("Failed to open UDP CLI connection port"); + } + if (redis_ip) { dlh = dlopen(MP_PLUGIN_DIR "/rtpengine-redis.so", RTLD_NOW | RTLD_GLOBAL); if (!dlh && !g_file_test(MP_PLUGIN_DIR "/rtpengine-redis.so", G_FILE_TEST_IS_REGULAR) diff --git a/debian/ngcp-rtpengine-daemon.default b/debian/ngcp-rtpengine-daemon.default index 9cf8cab7b..713d3fe51 100644 --- a/debian/ngcp-rtpengine-daemon.default +++ b/debian/ngcp-rtpengine-daemon.default @@ -2,6 +2,7 @@ RUN_RTPENGINE=no LISTEN_TCP=25060 LISTEN_UDP=12222 LISTEN_NG=22222 +LISTEN_CLI=9900 # INTERFACES="123.234.345.456" # INTERFACES="internal/12.23.34.45 external/23.34.45.54" # INTERFACES="12.23.34.45!23.34.45.56" diff --git a/debian/ngcp-rtpengine-daemon.init b/debian/ngcp-rtpengine-daemon.init index 82637eb55..4caa2fec8 100755 --- a/debian/ngcp-rtpengine-daemon.init +++ b/debian/ngcp-rtpengine-daemon.init @@ -55,6 +55,7 @@ fi [ -z "$LISTEN_TCP" ] || OPTIONS="$OPTIONS --listen-tcp=$LISTEN_TCP" [ -z "$LISTEN_UDP" ] || OPTIONS="$OPTIONS --listen-udp=$LISTEN_UDP" [ -z "$LISTEN_NG" ] || OPTIONS="$OPTIONS --listen-ng=$LISTEN_NG" +[ -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 "$PIDFILE" ] || OPTIONS="$OPTIONS --pidfile=$PIDFILE" diff --git a/debian/ngcp-rtpengine-daemon.install b/debian/ngcp-rtpengine-daemon.install index 11a8ccb4d..2ef4d0978 100644 --- a/debian/ngcp-rtpengine-daemon.install +++ b/debian/ngcp-rtpengine-daemon.install @@ -1 +1,2 @@ daemon/rtpengine /usr/sbin/ +utils/rtpengine-ctl /usr/sbin/ diff --git a/el/rtpengine.init b/el/rtpengine.init index 5c0c97d4b..529d2b6f7 100644 --- a/el/rtpengine.init +++ b/el/rtpengine.init @@ -92,6 +92,11 @@ build_opts() { OPTS+=" --listen-ng=$LISTEN_NG" fi + if [[ -n "$LISTEN_CLI" ]] + then + OPTS+=" --listen-cli=$LISTEN_CLI" + fi + if [[ -n "$TOS" ]] then OPTS+=" --tos=$TOS" diff --git a/el/rtpengine.sysconfig b/el/rtpengine.sysconfig index 2baa2997e..3048c0cbe 100644 --- a/el/rtpengine.sysconfig +++ b/el/rtpengine.sysconfig @@ -20,6 +20,7 @@ LISTEN_UDP=127.0.0.1:2222 # IP address and port combination for UDP # control #LISTEN_NG=127.0.0.1:2223 # IP address and port combination for NG (UDP) # control +#LISTEN_CLI=127.0.0.1:9900 # #TOS=184 # (o) TOS value to use in outgoing packets #TIMEOUT=60 # (o) Number of seconds after which a media stream is diff --git a/utils/rtpengine-ctl b/utils/rtpengine-ctl new file mode 100755 index 000000000..80a876ebb --- /dev/null +++ b/utils/rtpengine-ctl @@ -0,0 +1,69 @@ +#!/bin/bash +# + +host=127.0.0.1 +port=9900 +error_rc=255 + +prgname=${0##*/} +prgdir=${0%$prgname} + +showusage() { + echo "" + echo " rectl [ -ip -port ] " + echo "" + echo " Supported commands are:" + echo "" + echo " list [ numsessions | sessions | session ]" + echo " numsessions : prints the number of sessions" + echo " sessions : print one-liner session information" + echo " session : print detail about one session" + echo "" + echo " terminate [ all | ]" + echo " all : terminates all current sessions" + echo " : session is immediately terminated" + echo "" + echo "" + echo " Return Value:" + echo " 0 on success with ouput from server side, other values for failure." + echo "" + exit 0 +} + +if [ $# -eq 0 ]; then showusage; fi + + +command -v nc 2>&1 >/dev/null +if [ $? -ne 0 ]; then + echo "Error: rectl requires netcat to be installed." + exit 0 +fi + +while [ $# -gt 0 ]; do + case $1 in + "-?"|"-help"|"-h") + showusage + ;; + "-ip") + shift + if [ $# -gt 0 ]; then + host=$1 + else + echo "Missing parameter for option '-ip'" >&2 + fi + ;; + "-port") + shift + if [ $# -gt 0 ]; then + port=$1 + else + echo "Missing parameter for option '-port'" >&2 + fi + ;; + *) + varargs="$varargs $1" + esac + shift +done + +echo -n ${varargs} | nc ${host} ${port} From cccb0bfe75fe2e1e3e04fba822c51403a9795e58 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Thu, 4 Dec 2014 06:02:32 -0500 Subject: [PATCH 05/16] add Recommends: netcat-openbsd | netcat for CLI patch --- debian/control | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control b/debian/control index 6d5c8123e..9a21efdd1 100644 --- a/debian/control +++ b/debian/control @@ -22,6 +22,7 @@ Depends: ${misc:Depends}, ${shlibs:Depends} Conflicts: ngcp-mediaproxy-ng-daemon Replaces: ngcp-mediaproxy-ng-daemon +Recommends: netcat-openbsd | netcat Description: Proxy for RTP and media streams used in NGCP, userspace part. This daemon handles the first stages of proxying media streams and talks to the kernel part of the proxy for eventual high-performance packet forwarding. From a871cd75076bb40011aef25c270c719403793d64 Mon Sep 17 00:00:00 2001 From: Frederic-Philippe Metz Date: Thu, 4 Dec 2014 06:17:57 -0500 Subject: [PATCH 06/16] added_address_of_invoking_proxy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hinzufügen der Adresse des SIP-Proxy, der die session erstellt hat (sowohl für command line interface als auch CDR) Nur UDP control zunächst. Author: Frederic-Philippe Metz --- daemon/call.c | 1 + daemon/call.h | 1 + daemon/call_interfaces.c | 13 +++++++++---- daemon/call_interfaces.h | 2 +- daemon/cli.c | 4 ++-- daemon/control_udp.c | 2 +- 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index 9724c742d..26f6ce743 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -2375,6 +2375,7 @@ void call_destroy(struct call *c) { /* CDRs and statistics */ cdrbufcur += sprintf(cdrbufcur,"ci=%s, ",c->callid.s); + cdrbufcur += sprintf(cdrbufcur,"created_from=%s", c->created_from); for (l = c->monologues; l; l = l->next) { ml = l->data; if (_log_facility_cdr) { diff --git a/daemon/call.h b/daemon/call.h index c8ca767bf..92cbd0ad8 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -338,6 +338,7 @@ struct call { time_t deleted; time_t ml_deleted; unsigned char tos; + char created_from[64]; }; struct local_interface { diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 253eabcd0..a26c15cad 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -134,7 +134,7 @@ fail: return -1; } -static str *call_update_lookup_udp(char **out, struct callmaster *m, enum call_opmode opmode) { +static str *call_update_lookup_udp(char **out, struct callmaster *m, enum call_opmode opmode, const char* addr) { struct call *c; struct call_monologue *monologue; GQueue q = G_QUEUE_INIT; @@ -154,6 +154,11 @@ static str *call_update_lookup_udp(char **out, struct callmaster *m, enum call_o STR_FMT(&callid)); return str_sprintf("%s 0 0.0.0.0\n", out[RE_UDP_COOKIE]); } + + if (addr) { + memcpy(c->created_from, addr, strlen(addr)); + } + monologue = call_get_mono_dialogue(c, &fromtag, &totag); if (!monologue) goto ml_fail; @@ -196,11 +201,11 @@ out: return ret; } -str *call_update_udp(char **out, struct callmaster *m) { - return call_update_lookup_udp(out, m, OP_OFFER); +str *call_update_udp(char **out, struct callmaster *m, const char* addr) { + return call_update_lookup_udp(out, m, OP_OFFER, addr); } str *call_lookup_udp(char **out, struct callmaster *m) { - return call_update_lookup_udp(out, m, OP_ANSWER); + return call_update_lookup_udp(out, m, OP_ANSWER, NULL); } diff --git a/daemon/call_interfaces.h b/daemon/call_interfaces.h index b6df0dab2..f7444ac68 100644 --- a/daemon/call_interfaces.h +++ b/daemon/call_interfaces.h @@ -24,7 +24,7 @@ str *call_lookup_tcp(char **, struct callmaster *); void call_delete_tcp(char **, struct callmaster *); void calls_status_tcp(struct callmaster *, struct control_stream *); -str *call_update_udp(char **, struct callmaster *); +str *call_update_udp(char **, struct callmaster *, const char*); str *call_lookup_udp(char **, struct callmaster *); str *call_delete_udp(char **, struct callmaster *); str *call_query_udp(char **, struct callmaster *); diff --git a/daemon/cli.c b/daemon/cli.c index b26e918e3..c25ca4906 100644 --- a/daemon/cli.c +++ b/daemon/cli.c @@ -50,7 +50,7 @@ static void cli_incoming_list_callid(char* buffer, int len, struct callmaster* m return; } - printlen = snprintf (replybuffer,(outbufend-replybuffer), "\ncallid: %30s | deletionmark:%4s | created:%12i\n\n", c->callid.s , c->ml_deleted?"yes":"no", (int)c->created); + printlen = snprintf (replybuffer,(outbufend-replybuffer), "\ncallid: %30s | deletionmark:%4s | created:%12i | proxy:%s\n\n", c->callid.s , c->ml_deleted?"yes":"no", (int)c->created, c->created_from); ADJUSTLEN(printlen,outbufend,replybuffer); for (l = c->monologues; l; l = l->next) { @@ -130,7 +130,7 @@ static void cli_incoming_list(char* buffer, int len, struct callmaster* m, char* while (g_hash_table_iter_next (&iter, &key, &value)) { ptrkey = (str*)key; call = (struct call*)value; - printlen = snprintf(replybuffer, outbufend-replybuffer, "callid: %30s | deletionmark:%4s | created:%12i\n", ptrkey->s, call->ml_deleted?"yes":"no", (int)call->created); + printlen = snprintf(replybuffer, outbufend-replybuffer, "callid: %30s | deletionmark:%4s | created:%12i | proxy:%s\n", ptrkey->s, call->ml_deleted?"yes":"no", (int)call->created, call->created_from); ADJUSTLEN(printlen,outbufend,replybuffer); } rwlock_unlock_r(&m->hashlock); diff --git a/daemon/control_udp.c b/daemon/control_udp.c index b00e9d439..bab804142 100644 --- a/daemon/control_udp.c +++ b/daemon/control_udp.c @@ -83,7 +83,7 @@ static void control_udp_incoming(struct obj *obj, str *buf, struct sockaddr_in6 } if (chrtoupper(out[RE_UDP_UL_CMD][0]) == 'U') - reply = call_update_udp(out, u->callmaster); + reply = call_update_udp(out, u->callmaster, addr); else if (chrtoupper(out[RE_UDP_UL_CMD][0]) == 'L') reply = call_lookup_udp(out, u->callmaster); else if (chrtoupper(out[RE_UDP_DQ_CMD][0]) == 'D') From 43bcbcc4db053f60ce784543dd77f44d935ad91b Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Thu, 4 Dec 2014 06:20:32 -0500 Subject: [PATCH 07/16] change created_from to an allocated string buffer --- daemon/call.h | 2 +- daemon/call_interfaces.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/daemon/call.h b/daemon/call.h index 92cbd0ad8..31345b56d 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -338,7 +338,7 @@ struct call { time_t deleted; time_t ml_deleted; unsigned char tos; - char created_from[64]; + char *created_from; }; struct local_interface { diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index a26c15cad..33e6298d7 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -156,7 +156,7 @@ static str *call_update_lookup_udp(char **out, struct callmaster *m, enum call_o } if (addr) { - memcpy(c->created_from, addr, strlen(addr)); + c->created_from = call_strdup(c, addr); } monologue = call_get_mono_dialogue(c, &fromtag, &totag); From 53421588117d74682759805a687ec39935a2d4ac Mon Sep 17 00:00:00 2001 From: Frederic-Philippe Metz Date: Thu, 4 Dec 2014 06:26:00 -0500 Subject: [PATCH 08/16] added_information_of_from_to_tag: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Die from/to information wird irgendwann generell in den tag geschrieben. die info, ob der tag ein from_tag oder to_tag ist, wurde hinzugefügt. Author: Frederic-Philippe Metz --- daemon/call.c | 12 +++++++++++- daemon/call.h | 10 +++++++++- daemon/call_interfaces.c | 6 ++++++ daemon/cli.c | 5 +++-- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index 26f6ce743..64ba52512 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -134,6 +134,13 @@ const char * get_term_reason_text(char *buf, enum termination_reason t) { return buf; } +const char * get_tag_type_text(char *buf, enum tag_type t) { + if (t==FROM_TAG) { buf = "FROM_TAG"; return buf; } + if (t==TO_TAG) { buf = "TO_TAG"; return buf; } + + buf = "UNKNOWN"; + return buf; +} static void determine_handler(struct packet_stream *in, const struct packet_stream *out); @@ -2353,6 +2360,7 @@ void call_destroy(struct call *c) { struct timeval tim_result; 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; @@ -2375,7 +2383,7 @@ void call_destroy(struct call *c) { /* CDRs and statistics */ cdrbufcur += sprintf(cdrbufcur,"ci=%s, ",c->callid.s); - cdrbufcur += sprintf(cdrbufcur,"created_from=%s", c->created_from); + cdrbufcur += sprintf(cdrbufcur,"created_from=%s, ", c->created_from); for (l = c->monologues; l; l = l->next) { ml = l->data; if (_log_facility_cdr) { @@ -2386,12 +2394,14 @@ void call_destroy(struct call *c) { "ml%i_duration=%ld.%06ld, " "ml%i_termination=%s, " "ml%i_local_tag=%s, " + "ml%i_local_tag_type=%s, " "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, get_term_reason_text(reasonbuf,ml->term_reason), cdrlinecnt, ml->tag.s, + cdrlinecnt, get_tag_type_text(tagtypebuf,ml->tagtype), cdrlinecnt, ml->active_dialogue ? ml->active_dialogue->tag.s : "(none)"); } diff --git a/daemon/call.h b/daemon/call.h index 31345b56d..9b5ea27da 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -21,6 +21,12 @@ enum termination_reason { SILENT_TIMEOUT=4 }; +enum tag_type { + UNKNOWN_TAG=0, + FROM_TAG=1, + TO_TAG=2 +}; + enum stream_address_format { SAF_TCP, SAF_UDP, @@ -303,7 +309,8 @@ struct call_media { struct call_monologue { struct call *call; /* RO */ - str tag; + str tag; + enum tag_type tagtype; time_t created; /* RO */ time_t deleted; struct timeval started; /* for CDR */ @@ -502,5 +509,6 @@ INLINE struct packet_stream *packet_stream_sink(struct packet_stream *ps) { return ret; } +const char * get_tag_type_text(char *buf, enum tag_type t); #endif diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 33e6298d7..d4854aaa7 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -163,6 +163,12 @@ static str *call_update_lookup_udp(char **out, struct callmaster *m, enum call_o if (!monologue) goto ml_fail; + if (!totag.s || totag.len==0) { + monologue->tagtype = FROM_TAG; + } else { + monologue->tagtype = TO_TAG; + } + if (addr_parse_udp(&sp, out)) goto addr_fail; diff --git a/daemon/cli.c b/daemon/cli.c index c25ca4906..f59bacfef 100644 --- a/daemon/cli.c +++ b/daemon/cli.c @@ -33,6 +33,7 @@ static void cli_incoming_list_callid(char* buffer, int len, struct callmaster* m GList *k, *o; char buf[64]; int printlen=0; + char tagtypebuf[16]; memset(&tagtypebuf,0,16); if (len<=1) { printlen = snprintf(replybuffer,(outbufend-replybuffer), "%s\n", "More parameters required."); @@ -56,9 +57,9 @@ static void cli_incoming_list_callid(char* buffer, int len, struct callmaster* m for (l = c->monologues; l; l = l->next) { ml = l->data; - printlen = snprintf(replybuffer,(outbufend-replybuffer), "--- Tag '"STR_FORMAT"', callduration " + printlen = snprintf(replybuffer,(outbufend-replybuffer), "--- Tag '"STR_FORMAT"' type: %s, callduration " "%u:%02u , in dialogue with '"STR_FORMAT"'\n", - STR_FMT(&ml->tag), + STR_FMT(&ml->tag), get_tag_type_text(tagtypebuf,ml->tagtype), (unsigned int) (poller_now - ml->created) / 60, (unsigned int) (poller_now - ml->created) % 60, ml->active_dialogue ? ml->active_dialogue->tag.len : 6, From d623710bc4fdd392c9bbe539565183e07d515f07 Mon Sep 17 00:00:00 2001 From: Frederic-Philippe Metz Date: Thu, 4 Dec 2014 06:44:37 -0500 Subject: [PATCH 09/16] adaptions_for_ng_protocol: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dieser patch beinhaltet die Anpassungen für das NG protocol. Author: Frederic-Philippe Metz --- daemon/call_interfaces.c | 19 +++++++++++++++---- daemon/call_interfaces.h | 2 +- daemon/control_ng.c | 2 +- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index d4854aaa7..5e6e8f82d 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -592,7 +592,7 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu } static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster *m, - bencode_item_t *output, enum call_opmode opmode) + bencode_item_t *output, enum call_opmode opmode, const char* addr) { str sdp, fromtag, totag = STR_NULL, callid; char *errstr; @@ -631,6 +631,9 @@ static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster if (!call) goto out; + if (addr) { + memcpy(call->created_from, addr, strlen(addr)); + } /* At least the random ICE strings are contained within the call struct, so we * need to hold a ref until we're done sending the reply */ call_bencode_hold_ref(call, output); @@ -643,6 +646,12 @@ static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster goto out; } + if (!totag.s || totag.len==0) { + monologue->tagtype = FROM_TAG; + } else { + monologue->tagtype = TO_TAG; + } + chopper = sdp_chopper_new(&sdp); bencode_buffer_destroy_add(output->buffer, (free_func_t) sdp_chopper_destroy, chopper); ret = monologue_offer_answer(monologue, &streams, &flags); @@ -653,6 +662,8 @@ static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster redis_update(call, m->conf.redis); obj_put(call); + gettimeofday(&(monologue->started), NULL); + errstr = "Error rewriting SDP"; if (ret) goto out; @@ -669,12 +680,12 @@ out: return errstr; } -const char *call_offer_ng(bencode_item_t *input, struct callmaster *m, bencode_item_t *output) { - return call_offer_answer_ng(input, m, output, OP_OFFER); +const char *call_offer_ng(bencode_item_t *input, struct callmaster *m, bencode_item_t *output, const char* addr) { + return call_offer_answer_ng(input, m, output, OP_OFFER, addr); } const char *call_answer_ng(bencode_item_t *input, struct callmaster *m, bencode_item_t *output) { - return call_offer_answer_ng(input, m, output, OP_ANSWER); + return call_offer_answer_ng(input, m, output, OP_ANSWER, NULL); } const char *call_delete_ng(bencode_item_t *input, struct callmaster *m, bencode_item_t *output) { diff --git a/daemon/call_interfaces.h b/daemon/call_interfaces.h index f7444ac68..209707f66 100644 --- a/daemon/call_interfaces.h +++ b/daemon/call_interfaces.h @@ -29,7 +29,7 @@ str *call_lookup_udp(char **, struct callmaster *); str *call_delete_udp(char **, struct callmaster *); str *call_query_udp(char **, struct callmaster *); -const char *call_offer_ng(bencode_item_t *, struct callmaster *, bencode_item_t *); +const char *call_offer_ng(bencode_item_t *, struct callmaster *, bencode_item_t *, const char*); const char *call_answer_ng(bencode_item_t *, struct callmaster *, bencode_item_t *); const char *call_delete_ng(bencode_item_t *, struct callmaster *, bencode_item_t *); const char *call_query_ng(bencode_item_t *, struct callmaster *, bencode_item_t *); diff --git a/daemon/control_ng.c b/daemon/control_ng.c index 9b800ae2d..afe5a91df 100644 --- a/daemon/control_ng.c +++ b/daemon/control_ng.c @@ -111,7 +111,7 @@ static void control_ng_incoming(struct obj *obj, str *buf, struct sockaddr_in6 * if (!str_cmp(&cmd, "ping")) bencode_dictionary_add_string(resp, "result", "pong"); else if (!str_cmp(&cmd, "offer")) - errstr = call_offer_ng(dict, c->callmaster, resp); + errstr = call_offer_ng(dict, c->callmaster, resp, addr); else if (!str_cmp(&cmd, "answer")) errstr = call_answer_ng(dict, c->callmaster, resp); else if (!str_cmp(&cmd, "delete")) From 0e531ebdf273e9827a2dfbb70b6b8a090695d0d5 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Thu, 4 Dec 2014 06:45:26 -0500 Subject: [PATCH 10/16] change created_from to an allocated string buffer --- daemon/call_interfaces.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 5e6e8f82d..73584180b 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -632,7 +632,7 @@ static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster goto out; if (addr) { - memcpy(call->created_from, addr, strlen(addr)); + call->created_from = call_strdup(call, addr); } /* At least the random ICE strings are contained within the call struct, so we * need to hold a ref until we're done sending the reply */ From 59329ddd04831017f25926e4f172b6fba7a5b8b2 Mon Sep 17 00:00:00 2001 From: Frederic-Philippe Metz Date: Fri, 5 Dec 2014 03:16:39 -0500 Subject: [PATCH 11/16] VOIPTEST_220_delete delay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Im Moment wurden die sessions ja nach 30 sekunden hardcoded abgeräumt. Dieser patch macht das konfigurabel. ersetzt den letzten patch "added_delete_delay_for_memory_cleanup.patch". Author: Frederic-Philippe Metz --- README.md | 5 +++++ daemon/call.c | 15 +++++++-------- daemon/call.h | 1 + daemon/main.c | 5 ++++- debian/ngcp-rtpengine-daemon.default | 1 + debian/ngcp-rtpengine-daemon.init | 1 + el/rtpengine.init | 5 +++++ el/rtpengine.sysconfig | 1 + 8 files changed, 25 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index fca851581..7931add40 100644 --- a/README.md +++ b/README.md @@ -181,6 +181,7 @@ option and which are reproduced below: -E, --log-stderr Log on stderr instead of syslog -x, --xmlrpc-format=INT XMLRPC timeout request format to use. 0: SEMS DI, 1: call-id only --num-threads=INT Number of worker threads to create + -d, --delete-delay Delay for deleting a session from memory. --sip-source Use SIP source address by default --dtls-passive Always prefer DTLS passive role @@ -345,6 +346,10 @@ The options are described in more detail below. Enabled the `DTLS=passive` flag for all calls unconditionally. +* -d, --delete-delay + + Delete the call from memory after the specified delay from memory. + * -r, --redis, -R, --redis-db, -b, --b2b-url NGCP-specific options diff --git a/daemon/call.c b/daemon/call.c index 64ba52512..d80d64c5e 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -36,10 +36,6 @@ -#ifndef DELETE_DELAY -#define DELETE_DELAY 30 -#endif - #ifndef PORT_RANDOM_MIN #define PORT_RANDOM_MIN 6 #define PORT_RANDOM_MAX 20 @@ -1093,6 +1089,9 @@ next: if (good) goto out; + if (c->ml_deleted) + goto out; + for (i = c->monologues; i; i = i->next) { ml = i->data; memset(&ml->terminated,0,sizeof(struct timeval)); @@ -2902,15 +2901,15 @@ int call_delete_branch(struct callmaster *m, const str *callid, const str *branc */ ilog(LOG_INFO, "Scheduling deletion of call branch '"STR_FORMAT"' in %d seconds", - STR_FMT(&ml->tag), DELETE_DELAY); - ml->deleted = poller_now + DELETE_DELAY; + STR_FMT(&ml->tag), m->conf.delete_delay); + ml->deleted = poller_now + m->conf.delete_delay; if (!c->ml_deleted || c->ml_deleted > ml->deleted) c->ml_deleted = ml->deleted; goto success_unlock; del_all: - ilog(LOG_INFO, "Scheduling deletion of entire call in %d seconds", DELETE_DELAY); - c->deleted = poller_now + DELETE_DELAY; + ilog(LOG_INFO, "Scheduling deletion of entire call in %d seconds", m->conf.delete_delay); + c->deleted = poller_now + m->conf.delete_delay; rwlock_unlock_w(&c->master_lock); goto success; diff --git a/daemon/call.h b/daemon/call.h index 9b5ea27da..fefc7f033 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -370,6 +370,7 @@ struct callmaster_config { int port_max; unsigned int timeout; unsigned int silent_timeout; + unsigned int delete_delay; struct redis *redis; char *b2b_url; unsigned char default_tos; diff --git a/daemon/main.c b/daemon/main.c index 006502743..d972c1604 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -107,6 +107,7 @@ static int redis_db = -1; static char *b2b_url; static enum xmlrpc_format xmlrpc_fmt = XF_SEMS; static int num_threads; +static int delete_delay = 30; static void sighandler(gpointer x) { @@ -340,10 +341,11 @@ static void options(int *argc, char ***argv) { { "b2b-url", 'b', 0, G_OPTION_ARG_STRING, &b2b_url, "XMLRPC URL of B2B UA" , "STRING" }, { "log-level", 'L', 0, G_OPTION_ARG_INT, (void *)&log_level,"Mask log priorities above this level","INT" }, { "log-facility",0, 0, G_OPTION_ARG_STRING, &log_facility_s, "Syslog facility to use for logging", "daemon|local0|...|local7"}, - { "log-facility-cdr",0, 0, G_OPTION_ARG_STRING, &log_facility_cdr_s, "Syslog facility to use for logging CDRs", "daemon|local0|...|local7"}, + { "log-facility-cdr",0, 0, G_OPTION_ARG_STRING, &log_facility_cdr_s, "Syslog facility to use for logging CDRs", "daemon|local0|...|local7"}, { "log-stderr", 'E', 0, G_OPTION_ARG_NONE, &_log_stderr, "Log on stderr instead of syslog", NULL }, { "xmlrpc-format",'x', 0, G_OPTION_ARG_INT, &xmlrpc_fmt, "XMLRPC timeout request format to use. 0: SEMS DI, 1: call-id only", "INT" }, { "num-threads", 0, 0, G_OPTION_ARG_INT, &num_threads, "Number of worker threads to create", "INT" }, + { "delete-delay", 'd', 0, G_OPTION_ARG_INT, &delete_delay, "Delay for deleting a session from memory.", "INT" }, { "sip-source", 0, 0, G_OPTION_ARG_NONE, &sip_source, "Use SIP source address by default", NULL }, { "dtls-passive", 0, 0, G_OPTION_ARG_NONE, &dtls_passive_def,"Always prefer DTLS passive role", NULL }, { NULL, } @@ -608,6 +610,7 @@ no_kernel: mc.port_max = port_max; mc.timeout = timeout; mc.silent_timeout = silent_timeout; + mc.delete_delay = delete_delay; mc.default_tos = tos; mc.b2b_url = b2b_url; mc.fmt = xmlrpc_fmt; diff --git a/debian/ngcp-rtpengine-daemon.default b/debian/ngcp-rtpengine-daemon.default index 713d3fe51..20b659cb5 100644 --- a/debian/ngcp-rtpengine-daemon.default +++ b/debian/ngcp-rtpengine-daemon.default @@ -22,3 +22,4 @@ TABLE=0 # LOG_FACILITY=daemon # LOG_FACILITY_CDR=daemon # NUM_THREADS=5 +# DELETE_DELAY=30 \ No newline at end of file diff --git a/debian/ngcp-rtpengine-daemon.init b/debian/ngcp-rtpengine-daemon.init index 4caa2fec8..651e17f6e 100755 --- a/debian/ngcp-rtpengine-daemon.init +++ b/debian/ngcp-rtpengine-daemon.init @@ -71,6 +71,7 @@ OPTIONS="$OPTIONS --table=$TABLE" [ -z "$LOG_FACILITY" ] || OPTIONS="$OPTIONS --log-facility=$LOG_FACILITY" [ -z "$LOG_FACILITY_CDR" ] || OPTIONS="$OPTIONS --log-facility-cdr=$LOG_FACILITY_CDR" [ -z "$NUM_THREADS" ] || OPTIONS="$OPTIONS --num-threads=$NUM_THREADS" +[ -z "$DELETE_DELAY" ] || OPTIONS="$OPTIONS --delete-delay=$DELETE_DELAY" if test "$FORK" = "no" ; then OPTIONS="$OPTIONS --foreground" fi diff --git a/el/rtpengine.init b/el/rtpengine.init index 529d2b6f7..d02e5e8ef 100644 --- a/el/rtpengine.init +++ b/el/rtpengine.init @@ -152,6 +152,11 @@ build_opts() { OPTS+=" --num-threads=$NUM_THREADS" fi + if [[ -n "$DELETE_DELAY" ]] + then + OPTS+=" --delete-delay=$DELETE_DELAY" + fi + if [[ -n "$LOG_FACILITY_CDR" ]] then OPTS+=" --log-facility-cdr=$LOG_FACILITY_CDR" diff --git a/el/rtpengine.sysconfig b/el/rtpengine.sysconfig index 3048c0cbe..430fd9c5e 100644 --- a/el/rtpengine.sysconfig +++ b/el/rtpengine.sysconfig @@ -37,6 +37,7 @@ LISTEN_UDP=127.0.0.1:2222 # IP address and port combination for UDP #LOG_FACILITY=daemon # Syslog facility to use #LOG_FACILITY_CDR=daemon # Syslog facility to write CDRs #NUM_THREADS=5 # How many worker threads to launch +#DELETE_DELAY=30 # Delay to delete session from memory # The following items are for use with NGCP #REDIS=127.0.0.1:6379 From 4882d917ba905af6bd33ced7792ce5c7bf961d5e Mon Sep 17 00:00:00 2001 From: Frederic-Philippe Metz Date: Fri, 5 Dec 2014 03:21:16 -0500 Subject: [PATCH 12/16] 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" From b5665816e69a83242f1269e064c896773ed0ac64 Mon Sep 17 00:00:00 2001 From: Frederic-Philippe Metz Date: Fri, 5 Dec 2014 03:22:56 -0500 Subject: [PATCH 13/16] VOIPTEST-231_session_duration_rectl_milliseconds.patch Millisekunden bei rectl list session der calldauer. --- daemon/call.h | 5 ++++- daemon/cli.c | 19 +++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/daemon/call.h b/daemon/call.h index 8a2b5f68d..3328ed9b4 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -461,7 +461,10 @@ struct interface_address *get_interface_from_address(struct local_interface *lif const struct transport_protocol *transport_protocol(const str *s); - +void timeval_subtract (struct timeval *result, const struct timeval *a, const struct timeval *b); +void timeval_multiply(struct timeval *result, const struct timeval *a, const long multiplier); +void timeval_devide(struct timeval *result, const struct timeval *a, const long devisor); +void timeval_add(struct timeval *result, const struct timeval *a, const struct timeval *b); INLINE void *call_malloc(struct call *c, size_t l) { diff --git a/daemon/cli.c b/daemon/cli.c index 0c10c66ef..162d6274d 100644 --- a/daemon/cli.c +++ b/daemon/cli.c @@ -62,6 +62,8 @@ static void cli_incoming_list_callid(char* buffer, int len, struct callmaster* m char buf[64]; int printlen=0; char tagtypebuf[16]; memset(&tagtypebuf,0,16); + struct timeval tim_result_duration; memset(&tim_result_duration,0,sizeof(struct timeval)); + struct timeval now; memset(&now,0,sizeof(struct timeval)); if (len<=1) { printlen = snprintf(replybuffer,(outbufend-replybuffer), "%s\n", "More parameters required."); @@ -83,13 +85,18 @@ static void cli_incoming_list_callid(char* buffer, int len, struct callmaster* m ADJUSTLEN(printlen,outbufend,replybuffer); for (l = c->monologues; l; l = l->next) { - ml = l->data; - - printlen = snprintf(replybuffer,(outbufend-replybuffer), "--- Tag '"STR_FORMAT"' type: %s, callduration " - "%u:%02u , in dialogue with '"STR_FORMAT"'\n", + ml = l->data; + if (!ml->terminated.tv_sec) { + gettimeofday(&now, NULL); + } else { + now = ml->terminated; + } + timeval_subtract(&tim_result_duration,&now,&ml->started); + printlen = snprintf(replybuffer,(outbufend-replybuffer), "--- Tag '"STR_FORMAT"' type: %s, callduration " + "%ld.%06ld , in dialogue with '"STR_FORMAT"'\n", STR_FMT(&ml->tag), get_tag_type_text(tagtypebuf,ml->tagtype), - (unsigned int) (poller_now - ml->created) / 60, - (unsigned int) (poller_now - ml->created) % 60, + tim_result_duration.tv_sec, + tim_result_duration.tv_usec, ml->active_dialogue ? ml->active_dialogue->tag.len : 6, ml->active_dialogue ? ml->active_dialogue->tag.s : "(none)"); ADJUSTLEN(printlen,outbufend,replybuffer); From a8e55822d23c14443aa478e79e995a1dd6585ff4 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 19 Dec 2014 11:07:41 -0500 Subject: [PATCH 14/16] rtpengine-ctl: use $0 as name in help output --- utils/rtpengine-ctl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/rtpengine-ctl b/utils/rtpengine-ctl index 413b92fea..e69deb12c 100755 --- a/utils/rtpengine-ctl +++ b/utils/rtpengine-ctl @@ -10,7 +10,7 @@ prgdir=${0%$prgname} showusage() { echo "" - echo " rectl [ -ip -port ] " + echo " $0 [ -ip -port ] " echo "" echo " Supported commands are:" echo "" @@ -36,7 +36,7 @@ if [ $# -eq 0 ]; then showusage; fi command -v nc 2>&1 >/dev/null if [ $? -ne 0 ]; then - echo "Error: rectl requires netcat to be installed." + echo "Error: $0 requires netcat to be installed." exit 0 fi From d79bcfe7e4f9f76a797fe491da499d8e0501ab19 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Mon, 22 Dec 2014 10:59:33 -0500 Subject: [PATCH 15/16] remove extraneous linefeed --- daemon/call.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/call.c b/daemon/call.c index bf4eb0ce6..6270dbd9d 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -844,7 +844,7 @@ forward: if (ret == -1) { ret = -errno; - ilog(LOG_DEBUG,"Error when sending message. Error:%s\n",strerror(errno)); + ilog(LOG_DEBUG,"Error when sending message. Error: %s",strerror(errno)); stream->stats.errors++; mutex_lock(&cm->statspslock); cm->statsps.errors++; From a4168bee143dc62b4f21b2f166d083ed23d4167c Mon Sep 17 00:00:00 2001 From: Frederic-Philippe Metz Date: Tue, 23 Dec 2014 09:24:00 -0500 Subject: [PATCH 16/16] RTPENGINE-12_Fixed_Segmentation_fault_if_only_offer_received.patch --- daemon/call.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index 6270dbd9d..307b9bfe9 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -2500,19 +2500,21 @@ void call_destroy(struct call *c) { } 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 (ml->active_dialogue) { + // --- 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 (found) { break; } } if (ps && ps2 && ps->stats.packets!=0 && ps2->stats.packets==0)