From 2e07b6730fd476f861f97d96ad4bb17b4c597234 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 9 Apr 2014 15:06:56 +0200 Subject: [PATCH] Continuing quality reporting - use a buffer with belle_sip_snprintf instead of ms_strdup_printf (multiple new allocations) --- coreapi/quality_reporting.c | 224 ++++++++++++++++++++++-------------- 1 file changed, 140 insertions(+), 84 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 03f9bb65f..cee2d8a4a 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -25,22 +25,68 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "private.h" #include "sal/sal.h" +#include + #define PRINT2(x, f) printf(#x ": " #f "\n", x) #define PRINT(x) PRINT2(x, "%s") // since printf family functions are LOCALE dependent, float separator may differ // depending on the user's locale (LC_NUMERIC env var). static char * float_to_one_decimal_string(float f) { - int floor_part = (int)f; - int one_decimal_part = (int) (10.f * (f - floor_part)); + float rounded_f = floorf(f * 10 + .5f) / 10; + + int floor_part = (int) rounded_f; + int one_decimal_part = floorf (10 * (rounded_f - floor_part) + .5f); return ms_strdup_printf(_("%d.%d"), floor_part, one_decimal_part); } -struct _reporting_metrics_st { +static void append_to_buffer_valist(char **buff, size_t *buff_size, size_t *offset, const char *fmt, va_list args) { + belle_sip_error_code ret; + size_t prevoffset = *offset; + +#ifndef WIN32 + va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/ + va_copy(cap,args); + ret = belle_sip_snprintf_valist(*buff, *buff_size, offset, fmt, cap); + va_end(cap); +#else + ret = belle_sip_snprintf_valist(*buff, *buff_size, offset, fmt, args); +#endif + + // if we are out of memory, we add some size to buffer + if (ret == BELLE_SIP_BUFFER_OVERFLOW) { + ms_warning("Buffer was too small to contain the whole report - doubling its size from %lu to %lu", *buff_size, 2 * *buff_size); + *buff_size += 2048; + *buff = (char *) ms_realloc(*buff, *buff_size); + + *offset = prevoffset; + // recall myself since we did not write all things into the buffer but + // only part of it + append_to_buffer_valist(buff, buff_size, offset, fmt, args); + } +} + +static void append_to_buffer(char **buff, size_t *buff_size, size_t *offset, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + append_to_buffer_valist(buff, buff_size, offset, fmt, args); + va_end(args); +} + + +struct _reporting_addr_st { + char * ip; + int port; + uint32_t ssrc; +}; + +struct _reporting_content_metrics_st { + // timestamps - mandatory time_t ts_start; time_t ts_stop; + // session description - optional int sd_pt; char * sd_pd; int sd_sr; @@ -52,31 +98,37 @@ struct _reporting_metrics_st { int sd_plc; char * sd_ssup; + // jitter buffet - optional int jb_jba; int jb_jbr; int jb_jbn; int jb_jbm; int jb_jbx; + // packet loss - optional float pl_nlr; float pl_jdr; + // burst gap loss - optional int bgl_bld; int bgl_bd; float bgl_gld; int bgl_gd; int bgl_gmin; + // delay - optional int d_rtd; int d_esd; int d_sowd; int d_iaj; int d_maj; + // signal - optional int s_sl; int s_nl; int s_rerl; + // quality estimates - optional int qe_rlq; int qe_rcq; int qe_extri; @@ -85,43 +137,66 @@ struct _reporting_metrics_st { char * qe_qoeestalg; }; -static char * add_metrics(char * dest, struct _reporting_metrics_st rm) { - char * tmp = dest; +struct _reporting_session_report_st { + struct { + char * call_id; + char * local_id; + char * remote_id; + char * orig_id; + struct _reporting_addr_st local_addr; + struct _reporting_addr_st remote_addr; + char * local_group; + char * remote_group; - dest = ms_strdup_printf(_("%sTimestamps:START=%s STOP=%s\r\n"), tmp, + char * local_mac_addr; // optional + char * remote_mac_addr; // optional + } info; + + struct _reporting_content_metrics_st local_metrics; + struct _reporting_content_metrics_st remote_metrics; // optional + + char * dialog_id; // optional +}; + +struct _reporting_session_report_st get_stats(LinphoneCall * call) { + struct _reporting_session_report_st stats = {{0}}; + stats.info.local_addr.ssrc = rtp_session_get_send_ssrc(call->audiostream->ms.session); + stats.info.remote_addr.ssrc = rtp_session_get_recv_ssrc(call->audiostream->ms.session); + stats.info.call_id = call->log->call_id; + if (call->dir == LinphoneCallIncoming) { + stats.info.remote_id = linphone_address_as_string(call->log->from); + stats.info.local_id = linphone_address_as_string(call->log->to); + stats.info.orig_id = stats.info.remote_id; + } else { + stats.info.remote_id = linphone_address_as_string(call->log->to); + stats.info.local_id = linphone_address_as_string(call->log->from); + stats.info.orig_id = stats.info.local_id; + } + stats.local_metrics.ts_start = call->log->start_date_time; + stats.local_metrics.ts_stop = call->log->start_date_time + linphone_call_get_duration(call); + + return stats; +} + + +static void add_metrics(char ** buffer, size_t * size, size_t * offset, struct _reporting_content_metrics_st rm) { + append_to_buffer(buffer, size, offset, "Timestamps:START=%s STOP=%s\r\n", linphone_timestamp_to_rfc3339_string(rm.ts_start), linphone_timestamp_to_rfc3339_string(rm.ts_stop)); - ms_free(tmp); - tmp = dest; - dest = ms_strdup_printf(_("%sSessionDesc:PT=%d PD=%s SR=%d FD=%d FO=%d FPP=%d PPS=%d FMTP=%s PLC=%d SSUP=%s\r\n"), - tmp, rm.sd_pt, rm.sd_pd, rm.sd_sr, rm.sd_fd, rm.sd_fo, rm.sd_fpp, rm.sd_pps, rm.sd_fmtp, rm.sd_plc, rm.sd_ssup); - ms_free(tmp); - tmp = dest; - dest = ms_strdup_printf(_("%sJitterBuffer:JBA=%d JBR=%d JBN=%d JBM=%d JBX=%d\r\n"), - tmp, rm.jb_jba, rm.jb_jbr, rm.jb_jbn, rm.jb_jbm, rm.jb_jbx); - ms_free(tmp); - tmp = dest; - dest = ms_strdup_printf(_("%sPacketLoss:NLR=%s JDR=%s\r\n"), - tmp, float_to_one_decimal_string(rm.pl_nlr), float_to_one_decimal_string(rm.pl_jdr)); - ms_free(tmp); - tmp = dest; - dest = ms_strdup_printf(_("%sBurstGapLoss:BLD=%d BD=%d GLD=%s GD=%d GMIN=%d\r\n"), - tmp, rm.bgl_bld, rm.bgl_bd, float_to_one_decimal_string(rm.bgl_gld), rm.bgl_gd, rm.bgl_gmin); - ms_free(tmp); - tmp = dest; - dest = ms_strdup_printf(_("%sDelay:RTD=%d ESD=%d SOWD=%d IAJ=%d MAJ=%d\r\n"), - tmp, rm.d_rtd, rm.d_esd, rm.d_sowd, rm.d_iaj, rm.d_maj); - ms_free(tmp); - tmp = dest; - dest = ms_strdup_printf(_("%sSignal:SL=%d NL=%d RERL=%d\r\n"), - tmp, rm.s_sl, rm.s_nl, rm.s_rerl); - ms_free(tmp); - tmp = dest; - dest = ms_strdup_printf(_("%sQualityEst:RLQ=%d RCQ=%d EXTRI=%d MOSLQ=%s MOSCQ=%s QoEEstAlg=%s\r\n"), - tmp, rm.qe_rlq, rm.qe_rcq, rm.qe_extri, float_to_one_decimal_string(rm.qe_moslq), float_to_one_decimal_string(rm.qe_moscq), rm.qe_qoeestalg); - ms_free(tmp); - - return dest; + append_to_buffer(buffer, size, offset, "SessionDesc:PT=%d PD=%s SR=%d FD=%d FO=%d FPP=%d PPS=%d FMTP=%s PLC=%d SSUP=%s\r\n", + rm.sd_pt, rm.sd_pd, rm.sd_sr, rm.sd_fd, rm.sd_fo, rm.sd_fpp, rm.sd_pps, rm.sd_fmtp, rm.sd_plc, rm.sd_ssup); + append_to_buffer(buffer, size, offset, "JitterBuffer:JBA=%d JBR=%d JBN=%d JBM=%d JBX=%d\r\n", + rm.jb_jba, rm.jb_jbr, rm.jb_jbn, rm.jb_jbm, rm.jb_jbx); + append_to_buffer(buffer, size, offset, "PacketLoss:NLR=%s JDR=%s\r\n", + float_to_one_decimal_string(rm.pl_nlr), float_to_one_decimal_string(rm.pl_jdr)); + append_to_buffer(buffer, size, offset, "BurstGapLoss:BLD=%d BD=%d GLD=%s GD=%d GMIN=%d\r\n", + rm.bgl_bld, rm.bgl_bd, float_to_one_decimal_string(rm.bgl_gld), rm.bgl_gd, rm.bgl_gmin); + append_to_buffer(buffer, size, offset, "Delay:RTD=%d ESD=%d SOWD=%d IAJ=%d MAJ=%d\r\n", + rm.d_rtd, rm.d_esd, rm.d_sowd, rm.d_iaj, rm.d_maj); + append_to_buffer(buffer, size, offset, "Signal:SL=%d NL=%d RERL=%d\r\n", + rm.s_sl, rm.s_nl, rm.s_rerl); + append_to_buffer(buffer, size, offset, "QualityEst:RLQ=%d RCQ=%d EXTRI=%d MOSLQ=%s MOSCQ=%s QoEEstAlg=%s\r\n", + rm.qe_rlq, rm.qe_rcq, rm.qe_extri, float_to_one_decimal_string(rm.qe_moslq), float_to_one_decimal_string(rm.qe_moscq), rm.qe_qoeestalg); } void linphone_quality_reporting_submit(LinphoneCall* call) { @@ -131,62 +206,43 @@ void linphone_quality_reporting_submit(LinphoneCall* call) { // to: collector@sip.linphone.com // executed AFTER BYE's "OK" response has been received // expires value? - // un envoi à faire par stream ? (ssrc différent pour chaque stream) - // memory leaks - // belle_sip_snprintf - //ex RERL 404 code différent potentiellement avec info manquante + // one send by stream (different ssrc) + // memory leaks strings - append_to_buffer + // ex RERL 404 code différent potentiellement avec info manquante // 3611 pour savoir les valeurs pour les champs non disponibles LinphoneContent content = {0}; LinphoneAddress *addr; int expires = 3600; - const char *local_ip = "TODO";//stream dependentcall->localdesc->addr; //or call->localip ? - const char *remote_ip = "TODO"; - int local_port = 0; //TODO - int remote_port = 0;//linphone_address_get_port(linphone_call_get_remote_address(call)); - uint32_t local_ssrc = rtp_session_get_send_ssrc(call->audiostream->ms.session); - uint32_t remote_ssrc = rtp_session_get_recv_ssrc(call->audiostream->ms.session); - struct _reporting_metrics_st local_metrics = {0}; - struct _reporting_metrics_st remote_metrics = {0}; - - const char *remote_identity; - const char *local_identity; - const char *orig_identity; - if (call->dir == LinphoneCallIncoming) { - remote_identity = linphone_address_as_string(call->log->from); - local_identity = linphone_address_as_string(call->log->to); - orig_identity = remote_identity; - } else { - remote_identity = linphone_address_as_string(call->log->to); - local_identity = linphone_address_as_string(call->log->from); - orig_identity = local_identity; - } - - ms_message("Submitting PUBLISH packet for call between %s and %s", local_identity, remote_identity); - + struct _reporting_session_report_st stats = get_stats(call); + size_t offset = 0; + size_t size = 2048; + char * buffer = (char *) malloc(sizeof(char) * size); content.type = ms_strdup("application"); content.subtype = ms_strdup("vq-rtcpxr"); - content.data = ms_strdup_printf(_("VQSessionReport: CallTerm\r\n")); - content.data = ms_strdup_printf(_("%sCallID: %s\r\n"), content.data, call->log->call_id); - content.data = ms_strdup_printf(_("%sLocalID: %s\r\n"), content.data, local_identity); - content.data = ms_strdup_printf(_("%sRemoteID: %s\r\n"), content.data, remote_identity); - content.data = ms_strdup_printf(_("%sOrigID: %s\r\n"), content.data, orig_identity); - // content.data = ms_strdup_printf(_("%sLocalGroup: %s\r\n"), content.data, "TO_DO"); - // content.data = ms_strdup_printf(_("%sRemoteGroup: %s\r\n"), content.data, "TO_DO"); - content.data = ms_strdup_printf(_("%sLocalAddr: IP=%s PORT=%d SSRC=%d\r\n"), content.data, local_ip, local_port, local_ssrc); - // content.data = ms_strdup_printf(_("%sLocalMAC: %s\r\n"), content.data, "TO_DO"); - content.data = ms_strdup_printf(_("%sRemoteAddr: IP=%s PORT=%d SSRC=%d\r\n"), content.data, remote_ip, remote_port, remote_ssrc); - // content.data = ms_strdup_printf(_("%sRemoteMAC: %s\r\n"), content.data, "TO_DO"); + append_to_buffer(&buffer, &size, &offset, "VQSessionReport: CallTerm\r\n"); + append_to_buffer(&buffer, &size, &offset, "CallID: %s\r\n", stats.info.call_id); + append_to_buffer(&buffer, &size, &offset, "LocalID: %s\r\n", stats.info.local_id); + append_to_buffer(&buffer, &size, &offset, "RemoteID: %s\r\n", stats.info.remote_id); + append_to_buffer(&buffer, &size, &offset, "OrigID: %s\r\n", stats.info.orig_id); + + append_to_buffer(&buffer, &size, &offset, "LocalGroup: %s\r\n", stats.info.local_group); + append_to_buffer(&buffer, &size, &offset, "RemoteGroup: %s\r\n", stats.info.remote_group); + append_to_buffer(&buffer, &size, &offset, "LocalAddr: IP=%s PORT=%d SSRC=%d\r\n", stats.info.local_addr.ip, stats.info.local_addr.port, stats.info.local_addr.ssrc); + append_to_buffer(&buffer, &size, &offset, "LocalMAC: %s\r\n", stats.info.local_mac_addr); + append_to_buffer(&buffer, &size, &offset, "RemoteAddr: IP=%s PORT=%d SSRC=%d\r\n", stats.info.remote_addr.ip, stats.info.remote_addr.port, stats.info.remote_addr.ssrc); + append_to_buffer(&buffer, &size, &offset, "RemoteMAC: %s\r\n", stats.info.remote_mac_addr); - content.data = ms_strdup_printf(_("%sLocalMetrics:\r\n"), content.data); - local_metrics.ts_start = call->log->start_date_time; - local_metrics.ts_stop = call->log->start_date_time + call->log->duration; - content.data = add_metrics((char*)content.data, local_metrics); + append_to_buffer(&buffer, &size, &offset, "LocalMetrics:\r\n"); + add_metrics(&buffer, &size, &offset, stats.local_metrics); - content.data = ms_strdup_printf(_("%sRemoteMetrics:\r\n"), content.data); - remote_metrics.bgl_gld = 42.34f; - content.data = add_metrics((char*)content.data, remote_metrics); - content.data = ms_strdup_printf(_("%sDialogID: %s\r\n"), content.data, "TO_DO"); + append_to_buffer(&buffer, &size, &offset, "RemoteMetrics:\r\n"); + add_metrics(&buffer, &size, &offset, stats.remote_metrics); + if (stats.dialog_id != NULL) { + append_to_buffer(&buffer, &size, &offset, "DialogID: %s\r\n", stats.dialog_id); + } + + content.data = buffer; // for debug purpose only PRINT(content.data);