/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 | } |