|
|
|
|
@ -505,7 +505,15 @@ static void print_rtcp_sr(GString *log, const pjmedia_rtcp_sr* sr, GString *json
|
|
|
|
|
ntohl(sr->sender_pcount));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void print_rtcp_rr(GString *log, const pjmedia_rtcp_rr* rr, pjmedia_rtcp_common *common, GString *json) {
|
|
|
|
|
static void print_rtcp_rr_list_start(pjmedia_rtcp_common *common, GString *json) {
|
|
|
|
|
if (json)
|
|
|
|
|
g_string_append_printf(json, "\"ssrc\":%u,\"type\":%u,\"report_count\":%u,\"report_blocks\":[",
|
|
|
|
|
ntohl(common->ssrc),
|
|
|
|
|
common->pt,
|
|
|
|
|
common->count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void print_rtcp_rr(GString *log, const pjmedia_rtcp_rr* rr, GString *json) {
|
|
|
|
|
/* Get packet loss */
|
|
|
|
|
u_int32_t packet_loss=0;
|
|
|
|
|
packet_loss = (rr->total_lost_2 << 16) +
|
|
|
|
|
@ -523,11 +531,9 @@ void print_rtcp_rr(GString *log, const pjmedia_rtcp_rr* rr, pjmedia_rtcp_common
|
|
|
|
|
ntohl(rr->dlsr));
|
|
|
|
|
|
|
|
|
|
if (json)
|
|
|
|
|
g_string_append_printf(json, "\"ssrc\":%u,\"type\":%u, \"report_blocks\":[{\"source_ssrc\":%u,"
|
|
|
|
|
g_string_append_printf(json, "{\"source_ssrc\":%u,"
|
|
|
|
|
"\"highest_seq_no\":%u,\"fraction_lost\":%u,\"ia_jitter\":%u,"
|
|
|
|
|
"\"packets_lost\":%u,\"lsr\":%u,\"dlsr\":%u}],\"report_count\":1,",
|
|
|
|
|
ntohl(rr->ssrc),
|
|
|
|
|
common->pt,
|
|
|
|
|
"\"packets_lost\":%u,\"lsr\":%u,\"dlsr\":%u},",
|
|
|
|
|
ntohl(rr->ssrc),
|
|
|
|
|
ntohl(rr->last_seq),
|
|
|
|
|
rr->fract_lost,
|
|
|
|
|
@ -537,18 +543,29 @@ void print_rtcp_rr(GString *log, const pjmedia_rtcp_rr* rr, pjmedia_rtcp_common
|
|
|
|
|
ntohl(rr->dlsr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void parse_and_log_rtcp_report(struct stream_fd *sfd, const str *s, const endpoint_t *src) {
|
|
|
|
|
static void str_sanitize(GString *s) {
|
|
|
|
|
while (s->len > 0 && (s->str[s->len - 1] == ' ' || s->str[s->len - 1] == ','))
|
|
|
|
|
g_string_truncate(s, s->len - 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void print_rtcp_rr_list_end(pjmedia_rtcp_common *common, GString *json) {
|
|
|
|
|
if (json) {
|
|
|
|
|
str_sanitize(json);
|
|
|
|
|
g_string_append_printf(json, "],");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void parse_and_log_rtcp_report(struct stream_fd *sfd, const str *ori_s, const endpoint_t *src) {
|
|
|
|
|
|
|
|
|
|
GString *log;
|
|
|
|
|
pjmedia_rtcp_common *common = (pjmedia_rtcp_common*) s->s;
|
|
|
|
|
str iter_s, comp_s;
|
|
|
|
|
pjmedia_rtcp_common *common;
|
|
|
|
|
const pjmedia_rtcp_rr *rr = NULL;
|
|
|
|
|
const pjmedia_rtcp_sr *sr = NULL;
|
|
|
|
|
GString *json;
|
|
|
|
|
struct call *c = sfd->call;
|
|
|
|
|
struct callmaster *cm = c->callmaster;
|
|
|
|
|
|
|
|
|
|
if (s->len < sizeof(*common))
|
|
|
|
|
return;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
log = _log_facility_rtcp ? g_string_new(NULL) : NULL;
|
|
|
|
|
json = cm->homer ? g_string_new("{ ") : NULL;
|
|
|
|
|
@ -560,44 +577,65 @@ void parse_and_log_rtcp_report(struct stream_fd *sfd, const str *s, const endpoi
|
|
|
|
|
if (log)
|
|
|
|
|
g_string_append_printf(log, "["STR_FORMAT"] ", STR_FMT(&sfd->stream->call->callid));
|
|
|
|
|
|
|
|
|
|
print_rtcp_common(log, common);
|
|
|
|
|
iter_s = *ori_s;
|
|
|
|
|
|
|
|
|
|
/* Parse RTCP */
|
|
|
|
|
if (common->pt == RTCP_PT_SR) {
|
|
|
|
|
if (s->len < (sizeof(*common) + sizeof(*sr)))
|
|
|
|
|
goto out;
|
|
|
|
|
while (iter_s.len) {
|
|
|
|
|
// procedure throughout here: first assign, then str_shift with check for
|
|
|
|
|
// return value (does the length sanity check), then access values.
|
|
|
|
|
// we use iter_s to iterate compound packets and comp_s to access component
|
|
|
|
|
// data.
|
|
|
|
|
|
|
|
|
|
sr = (pjmedia_rtcp_sr*) ((s->s) + sizeof(pjmedia_rtcp_common));
|
|
|
|
|
common = (pjmedia_rtcp_common*) iter_s.s;
|
|
|
|
|
comp_s = iter_s;
|
|
|
|
|
|
|
|
|
|
print_rtcp_sr(log, sr, json);
|
|
|
|
|
if (str_shift(&comp_s, sizeof(*common))) // puts comp_s just past the common header
|
|
|
|
|
break;
|
|
|
|
|
if (str_shift(&iter_s, (ntohs(common->length) + 1) << 2)) // puts iter_s on the next compound packet
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (common->count > 0 && s->len >= (sizeof(pjmedia_rtcp_sr_pkt))) {
|
|
|
|
|
rr = (pjmedia_rtcp_rr*)((s->s) + (sizeof(pjmedia_rtcp_common)
|
|
|
|
|
+ sizeof(pjmedia_rtcp_sr)));
|
|
|
|
|
print_rtcp_rr(log, rr, common, json);
|
|
|
|
|
}
|
|
|
|
|
} else if (common->pt == RTCP_PT_RR && common->count > 0) {
|
|
|
|
|
if (s->len < (sizeof(*common) + sizeof(*rr)))
|
|
|
|
|
goto out;
|
|
|
|
|
print_rtcp_common(log, common);
|
|
|
|
|
|
|
|
|
|
/* Parse RTCP */
|
|
|
|
|
switch (common->pt) {
|
|
|
|
|
case RTCP_PT_SR:
|
|
|
|
|
sr = (pjmedia_rtcp_sr*) ((comp_s.s));
|
|
|
|
|
if (str_shift(&comp_s, sizeof(*sr)))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
print_rtcp_sr(log, sr, json);
|
|
|
|
|
// fall through to RTCP_PT_RR
|
|
|
|
|
|
|
|
|
|
case RTCP_PT_RR:
|
|
|
|
|
print_rtcp_rr_list_start(common, json);
|
|
|
|
|
|
|
|
|
|
rr = (pjmedia_rtcp_rr*)((s->s) + sizeof(pjmedia_rtcp_common));
|
|
|
|
|
print_rtcp_rr(log, rr, common, json);
|
|
|
|
|
for (i = 0; i < common->count; i++) {
|
|
|
|
|
rr = (pjmedia_rtcp_rr*)((comp_s.s));
|
|
|
|
|
if (str_shift(&comp_s, sizeof(*rr)))
|
|
|
|
|
break;
|
|
|
|
|
print_rtcp_rr(log, rr, json);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (common->pt == RTCP_PT_XR) {
|
|
|
|
|
pjmedia_rtcp_xr_rx_rtcp_xr(log, s);
|
|
|
|
|
print_rtcp_rr_list_end(common, json);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RTCP_PT_XR:
|
|
|
|
|
pjmedia_rtcp_xr_rx_rtcp_xr(log, common, &comp_s);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// XXX parse/support additional RTCP types
|
|
|
|
|
|
|
|
|
|
if (log)
|
|
|
|
|
if (log) {
|
|
|
|
|
str_sanitize(log);
|
|
|
|
|
rtcplog(log->str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (json) {
|
|
|
|
|
str_sanitize(json);
|
|
|
|
|
g_string_append(json, " }");
|
|
|
|
|
homer_send(cm->homer, json, &c->callid, src, &sfd->socket.local);
|
|
|
|
|
json = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
if (json)
|
|
|
|
|
g_string_free(json, TRUE);
|
|
|
|
|
if (log)
|
|
|
|
|
|