Coverage Report

Created: 2026-07-30 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rtpproxy/modules/acct_rtcp_hep/rtcp2json.c
Line
Count
Source
1
/*
2
 * (c) 1998-2018 by Columbia University; all rights reserved
3
 *
4
 * SPDX-License-Identifier: BSD-3-Clause
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. Neither the name of the University nor the names of its contributors
15
 *    may be used to endorse or promote products derived from this software
16
 *    without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 */
30
31
#include <sys/types.h>
32
#include <sys/time.h>
33
#include <sys/socket.h>
34
#include <sys/select.h>
35
#include <netinet/in.h>
36
#include <arpa/inet.h>
37
38
#include <assert.h>
39
#include <errno.h>
40
#include <signal.h>
41
#include <stdlib.h>
42
#include <string.h>
43
#include <stdio.h>
44
#include <unistd.h>
45
46
#include "rtpp_types.h"
47
#include "rtcp.h"
48
#include "rtpp_sbuf.h"
49
#include "rtcp2json.h"
50
51
#if 0
52
typedef uint32_t member_t;
53
54
/*
55
* Show SDES information for one member.
56
*/
57
void member_sdes(FILE *out, member_t m, rtcp_sdes_type_t t, char *b, int len)
58
{
59
  static struct {
60
    rtcp_sdes_type_t t;
61
    const char *name;
62
  } map[] = {
63
    {RTCP_SDES_END,    "end"},
64
    {RTCP_SDES_CNAME,  "CNAME"},
65
    {RTCP_SDES_NAME,   "NAME"},
66
    {RTCP_SDES_EMAIL,  "EMAIL"},
67
    {RTCP_SDES_PHONE,  "PHONE"},
68
    {RTCP_SDES_LOC,    "LOC"},
69
    {RTCP_SDES_TOOL,   "TOOL"},
70
    {RTCP_SDES_NOTE,   "NOTE"},
71
    {RTCP_SDES_PRIV,   "PRIV"},
72
    {11,               "SOURCE"},
73
    {0,0}
74
  };
75
  int i;
76
  char num[10];
77
78
  sprintf(num, "%d", t);
79
  for (i = 0; map[i].name; i++) {
80
    if (map[i].t == t) break;
81
  }
82
  fprintf(out, "%s=\"%*.*s\" ",
83
    map[i].name ? map[i].name : num, len, len, b);
84
} /* member_sdes */
85
86
/*
87
* Parse one SDES chunk (one SRC description). Total length is 'len'.
88
* Return new buffer position or zero if error.
89
*/
90
static char *rtp_read_sdes(FILE *out, char *b, int len)
91
{
92
  rtcp_sdes_item_t *rsp;
93
  uint32_t src = *(uint32_t *)b;
94
  int total_len = 0;
95
96
  len -= 4;  /* subtract SSRC from available bytes */
97
  if (len <= 0) {
98
    return 0;
99
  }
100
  rsp = (rtcp_sdes_item_t *)(b + 4);
101
  for (; rsp->type; rsp = (rtcp_sdes_item_t *)((char *)rsp + rsp->length + 2)) {
102
    member_sdes(out, src, rsp->type, rsp->data, rsp->length);
103
    total_len += rsp->length + 2;
104
  }
105
  if (total_len >= len) {
106
    fprintf(stderr,
107
      "Remaining length of %d bytes for SSRC item too short (has %u bytes)\n",
108
      len, total_len);
109
    return 0;
110
  }
111
  b = (char *)rsp + 1;
112
  /* skip padding */
113
  return b + ((4 - ((int)b & 0x3)) & 0x3);
114
} /* rtp_read_sdes */
115
#endif
116
117
#define RSW_REST(exitcode, sbc, format, args...)         \
118
46.8k
  {                                                      \
119
46.8k
    int rval;                                            \
120
47.6k
    for (;;) {                                           \
121
47.6k
      rval = rtpp_sbuf_write((sbc), (format), ## args);  \
122
47.6k
      if (rval == SBW_OK)                                \
123
47.6k
          break;                                         \
124
47.6k
      if (rval == SBW_ERR)                               \
125
729
          return (exitcode);                             \
126
729
      assert(rval == SBW_SHRT);                          \
127
729
      if (rtpp_sbuf_extend((sbc), (sbc)->alen * 2) != 0) \
128
729
          return (exitcode);                             \
129
729
    }                                                    \
130
46.8k
  }
131
      
132
133
/*
134
* Return length parsed, -1 on error.
135
*/
136
int rtcp2json(struct rtpp_sbuf *out, const void *buf, int len)
137
377
{
138
377
  const rtcp_t *r;         /* RTCP header */
139
377
  int i;
140
#if 0
141
  const char *cp;
142
#endif
143
144
377
  if (len < sizeof(rtcp_common_t)) {
145
2
    return -1;
146
2
  }
147
375
  r = (rtcp_t *)buf;
148
  /* Backwards compatibility: VAT header. */
149
375
  if (r->common.version != RTP_VERSION) {
150
#if 0
151
    fprintf(out, "invalid version %d\n", r->common.version);
152
#endif
153
4
    return -1;
154
4
  }
155
156
#if 0
157
  fprintf(out, "\n");
158
#endif
159
7.22k
  while (len > 0) {
160
6.94k
    if (len < sizeof(rtcp_common_t)) {
161
4
      return -1;
162
4
    }
163
6.94k
    size_t bincr = sizeof(uint32_t) * (ntohs(r->common.length) + 1);
164
165
6.94k
    switch (r->common.pt) {
166
4.01k
    case RTCP_SR:
167
4.01k
      if (len < bincr || bincr < (char *)&(r->r.sr) - (char *)r + sizeof(r->r.sr) + (sizeof(r->r.sr.rr[0]) * (r->common.count - 1)))
168
46
        goto invallen;
169
3.96k
      RSW_REST(-1, out, "{\n \"ssrc\": %lu,\n",
170
4.01k
        (unsigned long)ntohl(r->r.sr.ssrc));
171
3.96k
      RSW_REST(-1, out, " \"sender_information\": {\n  \"ntp_timestamp_sec\": %lu,\n  \"ntp_timestamp_usec\": %lu,\n  \"rtp_timestamp\": %lu,\n  \"packets\": %lu,\n  \"octets\": %lu\n },\n",
172
20.2k
        (unsigned long)ntohl(r->r.sr.ntp_sec),
173
20.2k
        (unsigned long)ntohl(r->r.sr.ntp_frac),
174
20.2k
        (unsigned long)ntohl(r->r.sr.rtp_ts),
175
20.2k
        (unsigned long)ntohl(r->r.sr.psent),
176
20.2k
        (unsigned long)ntohl(r->r.sr.osent));
177
3.96k
      RSW_REST(-1, out, " \"type\": %lu,\n", (unsigned long)r->common.pt);
178
3.96k
      if (r->common.count > 0)
179
3.96k
        RSW_REST(-1, out, " \"report_blocks\": [\n");
180
8.00k
      for (i = 0; i < r->common.count; i++) {
181
4.03k
        if (i > 0)
182
4.03k
          RSW_REST(-1, out, "  ,\n");
183
4.03k
        RSW_REST(-1, out, "  {\n   \"source_ssrc\": %lu,\n   \"fraction_lost\": %lu,\n   \"packets_lost\": %ld,\n   \"highest_seq_no\": %lu,\n   \"ia_jitter\": %lu,\n   \"lsr\": %lu,\n   \"dlsr\": %lu\n  }\n",
184
24.7k
         (unsigned long)ntohl(r->r.sr.rr[i].ssrc),
185
24.7k
         (unsigned long)r->r.sr.rr[i].fraction,
186
24.7k
         (long)RTCP_GET_LOST(&r->r.sr.rr[i]),
187
24.7k
         (unsigned long)ntohl(r->r.sr.rr[i].last_seq),
188
24.7k
         (unsigned long)ntohl(r->r.sr.rr[i].jitter),
189
24.7k
         (unsigned long)ntohl(r->r.sr.rr[i].lsr),
190
24.7k
         (unsigned long)ntohl(r->r.sr.rr[i].dlsr));
191
4.03k
      }
192
3.96k
      if (r->common.count > 0)
193
3.96k
        RSW_REST(-1, out, " ],\n");
194
3.96k
      RSW_REST(-1, out, " \"report_count\": %lu\n", (unsigned long)r->common.count);
195
3.96k
      RSW_REST(-1, out, "}");
196
3.96k
      break;
197
198
2.63k
    case RTCP_RR:
199
2.63k
      if (len < bincr || bincr < (char *)&(r->r.rr) - (char *)r + sizeof(r->r.rr) + (sizeof(r->r.rr.rr[0]) * (r->common.count - 1)))
200
40
        goto invallen;
201
2.59k
      RSW_REST(-1, out, "{\n \"ssrc\": %lu,\n",
202
2.62k
        (unsigned long)ntohl(r->r.rr.ssrc));
203
2.59k
      RSW_REST(-1, out, " \"type\": %lu,\n", (unsigned long)r->common.pt);
204
2.59k
      if (r->common.count > 0)
205
2.59k
        RSW_REST(-1, out, " \"report_blocks\": [\n");
206
4.72k
      for (i = 0; i < r->common.count; i++) {
207
2.13k
        if (i > 0)
208
2.13k
          RSW_REST(-1, out, "  ,\n");
209
2.13k
        RSW_REST(-1, out, "  {\n   \"source_ssrc\": %lu,\n   \"fraction_lost\": %lu,\n   \"packets_lost\": %ld,\n   \"highest_seq_no\": %lu,\n   \"ia_jitter\": %lu,\n   \"lsr\": %lu,\n   \"dlsr\": %lu\n  }\n",
210
13.6k
          (unsigned long)ntohl(r->r.rr.rr[i].ssrc),
211
13.6k
          (unsigned long)r->r.rr.rr[i].fraction,
212
13.6k
          (long)RTCP_GET_LOST(&r->r.rr.rr[i]),
213
13.6k
          (unsigned long)ntohl(r->r.rr.rr[i].last_seq),
214
13.6k
          (unsigned long)ntohl(r->r.rr.rr[i].jitter),
215
13.6k
          (unsigned long)ntohl(r->r.rr.rr[i].lsr),
216
13.6k
          (unsigned long)ntohl(r->r.rr.rr[i].dlsr));
217
2.13k
      }
218
2.59k
      if (r->common.count > 0)
219
2.59k
        RSW_REST(-1, out, " ],\n");
220
2.59k
      RSW_REST(-1, out, " \"report_count\": %lu\n", (unsigned long)r->common.count);
221
2.59k
      RSW_REST(-1, out, "}");
222
2.59k
      break;
223
224
0
    case RTCP_SDES:
225
#if 0
226
      fprintf(out, " (SDES p=%d count=%d len=%d\n",
227
        r->common.p, r->common.count, ntohs(r->common.length));
228
      cp = (const char *)&r->r.sdes;
229
      for (i = 0; i < r->common.count; i++) {
230
        int remaining = (ntohs(r->common.length) << 2) -
231
                        (cp - (const char *)&r->r.sdes);
232
        fprintf(out, "  (src=0x%lx ",
233
          (unsigned long)ntohl(((struct rtcp_sdes *)cp)->src));
234
        if (remaining > 0) {
235
          cp = rtp_read_sdes(out, cp,
236
            (ntohs(r->common.length) << 2) - (cp - (const char *)&r->r.sdes));
237
          if (!cp) return -1;
238
        } else {
239
          fprintf(stderr, "Missing at least %d bytes.\n", -remaining);
240
          return -1;
241
        }
242
        fprintf(out, ")\n");
243
      }
244
      fprintf(out, " )\n");
245
#endif
246
0
      break;
247
248
0
    case RTCP_BYE:
249
#if 0
250
      fprintf(out, " (BYE p=%d count=%d len=%d\n",
251
        r->common.p, r->common.count, ntohs(r->common.length));
252
      for (i = 0; i < r->common.count; i++) {
253
        fprintf(out, "  (ssrc[%d]=0x%0lx ", i,
254
          (unsigned long)ntohl(r->r.bye.src[i]));
255
      }
256
      fprintf(out, ")\n");
257
      if (ntohs(r->common.length) > r->common.count) {
258
        cp = (const char *)&r->r.bye.src[r->common.count];
259
        fprintf(out, "reason=\"%*.*s\"", *cp, *cp, cp+1);
260
      }
261
      fprintf(out, " )\n");
262
#endif
263
0
      break;
264
265
    /* invalid type */
266
294
    default:
267
#if 0
268
      fprintf(out, "(? pt=%d src=0x%lx)\n", r->common.pt,
269
        (unsigned long)ntohl(r->r.sdes.src));
270
#endif
271
294
      break;
272
6.94k
    }
273
6.85k
    len -= bincr;
274
6.85k
    r = (const rtcp_t *)((const char *)r + bincr);
275
6.85k
  }
276
277
281
  return len;
278
279
86
invallen:
280
  /* something wrong with packet format */
281
#if 0
282
  fprintf(out, "Illegal RTCP packet length %d words.\n",
283
   ntohs(r->common.length));
284
#endif
285
86
  return -1;
286
371
}