Coverage Report

Created: 2025-12-08 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/janus-gateway/src/utils.c
Line
Count
Source
1
/*! \file    utils.c
2
 * \author   Lorenzo Miniero <lorenzo@meetecho.com>
3
 * \copyright GNU General Public License v3
4
 * \brief    Utilities and helpers
5
 * \details  Implementations of a few methods that may be of use here
6
 * and there in the code.
7
 *
8
 * \ingroup core
9
 * \ref core
10
 */
11
12
#include <stdlib.h>
13
#include <string.h>
14
#include <sys/stat.h>
15
#include <errno.h>
16
#include <fcntl.h>
17
#include <sys/file.h>
18
#include <sys/types.h>
19
#include <unistd.h>
20
#include <arpa/inet.h>
21
#include <inttypes.h>
22
23
#include <zlib.h>
24
#include <openssl/rand.h>
25
26
#include "utils.h"
27
#include "rtp.h"
28
#include "debug.h"
29
#include "mutex.h"
30
31
#if __MACH__
32
#include "mach_gettime.h"
33
#endif
34
35
3.75k
gint64 janus_get_monotonic_time_internal(void) {
36
3.75k
  struct timespec ts;
37
3.75k
  clock_gettime (CLOCK_MONOTONIC, &ts);
38
3.75k
  return (ts.tv_sec*G_GINT64_CONSTANT(1000000)) + (ts.tv_nsec/G_GINT64_CONSTANT(1000));
39
3.75k
}
40
41
static gint64 janus_started = 0;
42
0
void janus_mark_started(void) {
43
0
  if(janus_started == 0)
44
0
    janus_started = janus_get_monotonic_time_internal();
45
0
}
46
47
3.75k
gint64 janus_get_monotonic_time(void) {
48
3.75k
  return janus_get_monotonic_time_internal() - janus_started;
49
3.75k
}
50
51
0
gint64 janus_get_real_time(void) {
52
0
  struct timespec ts;
53
0
  clock_gettime (CLOCK_REALTIME, &ts);
54
0
  return (ts.tv_sec*G_GINT64_CONSTANT(1000000)) + (ts.tv_nsec/G_GINT64_CONSTANT(1000));
55
0
}
56
57
0
gboolean janus_is_true(const char *value) {
58
0
  return value && (!strcasecmp(value, "yes") || !strcasecmp(value, "true") || !strcasecmp(value, "1"));
59
0
}
60
61
0
gboolean janus_strcmp_const_time(const void *str1, const void *str2) {
62
0
  if(str1 == NULL || str2 == NULL)
63
0
    return FALSE;
64
0
  const unsigned char *string1 = (const unsigned char *)str1;
65
0
  const unsigned char *string2 = (const unsigned char *)str2;
66
0
  size_t maxlen = strlen((char *)string1);
67
0
  if(strlen((char *)string2) > maxlen)
68
0
    maxlen = strlen((char *)string2);
69
0
  unsigned char *buf1 = g_malloc0(maxlen+1);
70
0
  memcpy(buf1, string1, strlen(str1));
71
0
  unsigned char *buf2 = g_malloc0(maxlen+1);
72
0
  memcpy(buf2, string2, strlen(str2));
73
0
  unsigned char result = 0;
74
0
  size_t i = 0;
75
0
  for (i = 0; i < maxlen; i++) {
76
0
    result |= buf1[i] ^ buf2[i];
77
0
  }
78
0
  g_free(buf1);
79
0
  buf1 = NULL;
80
0
  g_free(buf2);
81
0
  buf2 = NULL;
82
0
  return result == 0;
83
0
}
84
85
0
guint32 janus_random_uint32(void) {
86
0
  guint32 ret = 0;
87
0
  if(RAND_bytes((void *)&ret, sizeof(ret)) != 1) {
88
0
    JANUS_LOG(LOG_WARN, "Safe RAND_bytes() failed, falling back to unsafe PRNG\n");
89
0
    return g_random_int();
90
0
  }
91
0
  return ret;
92
0
}
93
94
0
guint64 janus_random_uint64_full(void) {
95
0
  guint64 ret = 0;
96
0
  if(RAND_bytes((void *)&ret, sizeof(ret)) != 1) {
97
0
    JANUS_LOG(LOG_WARN, "Safe RAND_bytes() failed, falling back to unsafe PRNG\n");
98
0
    return ((guint64)g_random_int() << 32) | g_random_int();
99
0
  }
100
0
  return ret;
101
0
}
102
103
0
guint64 janus_random_uint64(void) {
104
0
  return janus_random_uint64_full() & 0x1FFFFFFFFFFFFF;
105
0
}
106
107
0
char *janus_random_uuid(void) {
108
0
#if GLIB_CHECK_VERSION(2, 52, 0)
109
0
  return g_uuid_string_random();
110
#else
111
  /* g_uuid_string_random is only available from glib 2.52, so if it's
112
   * not available we have to do it manually: the following code is
113
   * heavily based on https://github.com/rxi/uuid4 (MIT license) */
114
  const char *template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
115
  const char *samples = "0123456789abcdef";
116
  union { unsigned char b[16]; uint64_t word[2]; } rnd;
117
  rnd.word[0] = janus_random_uint64_full();
118
  rnd.word[1] = janus_random_uint64_full();
119
  /* Generate the string */
120
  char uuid[37], *dst = uuid;
121
  const char *p = template;
122
  int i = 0, n = 0;
123
  while(*p) {
124
    n = rnd.b[i >> 1];
125
    n = (i & 1) ? (n >> 4) : (n & 0xf);
126
    switch (*p) {
127
      case 'x':
128
        *dst = samples[n];
129
        i++;
130
        break;
131
      case 'y':
132
        *dst = samples[(n & 0x3) + 8];
133
        i++;
134
        break;
135
      default:
136
        *dst = *p;
137
    }
138
    p++;
139
    dst++;
140
  }
141
  uuid[36] = '\0';
142
  return g_strdup(uuid);
143
#endif
144
0
}
145
146
0
guint64 *janus_uint64_dup(guint64 num) {
147
0
  guint64 *numdup = g_malloc(sizeof(guint64));
148
0
  *numdup = num;
149
0
  return numdup;
150
0
}
151
152
0
guint64 janus_uint64_hash(guint64 num) {
153
0
  num = (num ^ (num >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
154
0
  num = (num ^ (num >> 27)) * UINT64_C(0x94d049bb133111eb);
155
0
  num = num ^ (num >> 31);
156
0
  return num;
157
0
}
158
159
0
int janus_string_to_uint8(const char *str, uint8_t *num) {
160
0
  if(str == NULL || num == NULL)
161
0
    return -EINVAL;
162
0
  long int val = strtol(str, 0, 10);
163
0
  if(val < 0 || val > UINT8_MAX)
164
0
    return -ERANGE;
165
0
  *num = val;
166
0
  return 0;
167
0
}
168
169
0
int janus_string_to_uint16(const char *str, uint16_t *num) {
170
0
  if(str == NULL || num == NULL)
171
0
    return -EINVAL;
172
0
  long int val = strtol(str, 0, 10);
173
0
  if(val < 0 || val > UINT16_MAX)
174
0
    return -ERANGE;
175
0
  *num = val;
176
0
  return 0;
177
0
}
178
179
0
int janus_string_to_uint32(const char *str, uint32_t *num) {
180
0
  if(str == NULL || num == NULL)
181
0
    return -EINVAL;
182
0
  long long int val = strtoll(str, 0, 10);
183
0
  if(val < 0 || val > UINT32_MAX)
184
0
    return -ERANGE;
185
0
  *num = val;
186
0
  return 0;
187
0
}
188
189
0
void janus_flags_reset(janus_flags *flags) {
190
0
  if(flags != NULL)
191
0
    g_atomic_pointer_set(flags, 0);
192
0
}
193
194
0
void janus_flags_set(janus_flags *flags, gsize flag) {
195
0
  if(flags != NULL) {
196
0
    g_atomic_pointer_or(flags, flag);
197
0
  }
198
0
}
199
200
0
void janus_flags_clear(janus_flags *flags, gsize flag) {
201
0
  if(flags != NULL) {
202
0
    g_atomic_pointer_and(flags, ~(flag));
203
0
  }
204
0
}
205
206
0
gboolean janus_flags_is_set(janus_flags *flags, gsize flag) {
207
0
  if(flags != NULL) {
208
0
    gsize bit = ((gsize) g_atomic_pointer_get(flags)) & flag;
209
0
    return (bit != 0);
210
0
  }
211
0
  return FALSE;
212
0
}
213
214
/* Easy way to replace multiple occurrences of a string with another */
215
char *janus_string_replace(char *message, const char *old_string, const char *new_string)
216
0
{
217
0
  if(!message || !old_string || !new_string)
218
0
    return NULL;
219
220
0
  if(!strstr(message, old_string)) { /* Nothing to be done (old_string is not there) */
221
0
    return message;
222
0
  }
223
0
  if(!strcmp(old_string, new_string)) { /* Nothing to be done (old_string=new_string) */
224
0
    return message;
225
0
  }
226
0
  if(strlen(old_string) == strlen(new_string)) { /* Just overwrite */
227
0
    char *outgoing = message;
228
0
    char *pos = strstr(outgoing, old_string), *tmp = NULL;
229
0
    while(pos) {
230
0
      memcpy(pos, new_string, strlen(new_string));
231
0
      pos += strlen(old_string);
232
0
      tmp = strstr(pos, old_string);
233
0
      pos = tmp;
234
0
    }
235
0
    return outgoing;
236
0
  } else { /* We need to resize */
237
0
    char *outgoing = g_strdup(message);
238
0
    g_free(message);
239
0
    if(outgoing == NULL) {
240
0
      return NULL;
241
0
    }
242
0
    int diff = strlen(new_string) - strlen(old_string);
243
    /* Count occurrences */
244
0
    int counter = 0;
245
0
    char *pos = strstr(outgoing, old_string), *tmp = NULL;
246
0
    while(pos) {
247
0
      counter++;
248
0
      pos += strlen(old_string);
249
0
      tmp = strstr(pos, old_string);
250
0
      pos = tmp;
251
0
    }
252
0
    uint16_t old_stringlen = strlen(outgoing)+1, new_stringlen = old_stringlen + diff*counter;
253
0
    if(diff > 0) { /* Resize now */
254
0
      tmp = g_realloc(outgoing, new_stringlen);
255
0
      outgoing = tmp;
256
0
    }
257
    /* Replace string */
258
0
    pos = strstr(outgoing, old_string);
259
0
    while(pos) {
260
0
      if(diff > 0) { /* Move to the right (new_string is larger than old_string) */
261
0
        uint16_t len = strlen(pos)+1;
262
0
        memmove(pos + diff, pos, len);
263
0
        memcpy(pos, new_string, strlen(new_string));
264
0
        pos += strlen(new_string);
265
0
        tmp = strstr(pos, old_string);
266
0
      } else { /* Move to the left (new_string is smaller than old_string) */
267
0
        uint16_t len = strlen(pos - diff)+1;
268
0
        memmove(pos, pos - diff, len);
269
0
        memcpy(pos, new_string, strlen(new_string));
270
0
        pos += strlen(old_string);
271
0
        tmp = strstr(pos, old_string);
272
0
      }
273
0
      pos = tmp;
274
0
    }
275
0
    if(diff < 0) { /* We skipped the resize previously (shrinking memory) */
276
0
      tmp = g_realloc(outgoing, new_stringlen);
277
0
      outgoing = tmp;
278
0
    }
279
0
    outgoing[strlen(outgoing)] = '\0';
280
0
    return outgoing;
281
0
  }
282
0
}
283
284
0
size_t janus_strlcat(char *dest, const char *src, size_t dest_size) {
285
0
  size_t ret = g_strlcat(dest, src, dest_size);
286
0
  if(ret >= dest_size)
287
0
    JANUS_LOG(LOG_ERR, "Truncation occurred, %lu >= %lu\n", ret, dest_size);
288
0
  return ret;
289
0
}
290
291
1.57M
int janus_strlcat_fast(char *dest, const char *src, size_t dest_size, size_t *offset) {
292
1.57M
  if(dest == NULL || src == NULL || offset == NULL) {
293
0
    JANUS_LOG(LOG_ERR, "Invalid arguments\n");
294
0
    return -1;
295
0
  }
296
1.57M
  if(*offset >= dest_size) {
297
3.30k
    JANUS_LOG(LOG_ERR, "Offset is beyond the buffer size\n");
298
3.30k
    return -2;
299
3.30k
  }
300
1.56M
  char *p = memccpy(dest + *offset, src, 0, dest_size - *offset);
301
1.56M
  if(p == NULL) {
302
203
    JANUS_LOG(LOG_ERR, "Truncation occurred, %lu >= %lu\n",
303
203
      *offset + strlen(src), dest_size);
304
203
    *offset = dest_size;
305
203
    *(dest + dest_size -1) = '\0';
306
203
    return -3;
307
203
  }
308
1.56M
  *offset = (p - dest - 1);
309
1.56M
  return 0;
310
1.56M
}
311
312
0
int janus_mkdir(const char *dir, mode_t mode) {
313
0
  char tmp[256];
314
0
  char *p = NULL;
315
0
  size_t len;
316
317
0
  int res = 0;
318
0
  g_snprintf(tmp, sizeof(tmp), "%s", dir);
319
0
  len = strlen(tmp);
320
0
  if(tmp[len - 1] == '/')
321
0
    tmp[len - 1] = 0;
322
0
  for(p = tmp + 1; *p; p++) {
323
0
    if(*p == '/') {
324
0
      *p = 0;
325
0
      res = mkdir(tmp, mode);
326
0
      if(res != 0 && errno != EEXIST) {
327
0
        JANUS_LOG(LOG_ERR, "Error creating folder %s\n", tmp);
328
0
        return res;
329
0
      }
330
0
      *p = '/';
331
0
    }
332
0
  }
333
0
  res = mkdir(tmp, mode);
334
0
  if(res != 0 && errno != EEXIST)
335
0
    return res;
336
0
  return 0;
337
0
}
338
339
0
gchar *janus_make_absolute_path(const gchar *base_dir, const gchar *path) {
340
0
  if(!path)
341
0
    return NULL;
342
0
  if(g_path_is_absolute(path))
343
0
    return g_strdup(path);
344
0
  if(!base_dir)
345
0
    return NULL;
346
0
  return g_build_filename(base_dir, path, NULL);
347
0
}
348
349
0
int janus_get_codec_pt(const char *sdp, const char *codec) {
350
0
  if(!sdp || !codec)
351
0
    return -1;
352
0
  int video = 0;
353
0
  const char *format = NULL, *format2 = NULL;
354
0
  if(!strcasecmp(codec, "opus")) {
355
0
    video = 0;
356
0
    format = "opus/48000/2";
357
0
    format2 = "OPUS/48000/2";
358
0
  } else if(!strcasecmp(codec, "pcmu")) {
359
    /* We know the payload type is 0: we just need to make sure it's there */
360
0
    video = 0;
361
0
    format = "pcmu/8000";
362
0
    format2 = "PCMU/8000";
363
0
  } else if(!strcasecmp(codec, "pcma")) {
364
    /* We know the payload type is 8: we just need to make sure it's there */
365
0
    video = 0;
366
0
    format = "pcma/8000";
367
0
    format2 = "PCMA/8000";
368
0
  } else if(!strcasecmp(codec, "g722")) {
369
    /* We know the payload type is 9: we just need to make sure it's there */
370
0
    video = 0;
371
0
    format = "g722/8000";
372
0
    format2 = "G722/8000";
373
0
  } else if(!strcasecmp(codec, "isac16")) {
374
0
    video = 0;
375
0
    format = "isac/16000";
376
0
    format2 = "ISAC/16000";
377
0
  } else if(!strcasecmp(codec, "isac32")) {
378
0
    video = 0;
379
0
    format = "isac/32000";
380
0
    format2 = "ISAC/32000";
381
0
  } else if(!strcasecmp(codec, "l16-48")) {
382
0
    video = 0;
383
0
    format = "l16/48000";
384
0
    format2 = "L16/48000";
385
0
  } else if(!strcasecmp(codec, "l16")) {
386
0
    video = 0;
387
0
    format = "l16/16000";
388
0
    format2 = "L16/16000";
389
0
  } else if(!strcasecmp(codec, "vp8")) {
390
0
    video = 1;
391
0
    format = "vp8/90000";
392
0
    format2 = "VP8/90000";
393
0
  } else if(!strcasecmp(codec, "vp9")) {
394
0
    video = 1;
395
0
    format = "vp9/90000";
396
0
    format2 = "VP9/90000";
397
0
  } else if(!strcasecmp(codec, "h264")) {
398
0
    video = 1;
399
0
    format = "h264/90000";
400
0
    format2 = "H264/90000";
401
0
  } else if(!strcasecmp(codec, "av1")) {
402
0
    video = 1;
403
0
    format = "av1/90000";
404
0
    format2 = "AV1/90000";
405
0
  } else if(!strcasecmp(codec, "h265")) {
406
0
    video = 1;
407
0
    format = "h265/90000";
408
0
    format2 = "H265/90000";
409
0
  } else {
410
0
    JANUS_LOG(LOG_ERR, "Unsupported codec '%s'\n", codec);
411
0
    return -1;
412
0
  }
413
  /* First of all, let's check if the codec is there */
414
0
  if(!video) {
415
0
    if(!strstr(sdp, "m=audio") || (!strstr(sdp, format) && !strstr(sdp, format2)))
416
0
      return -2;
417
0
  } else {
418
0
    if(!strstr(sdp, "m=video") || (!strstr(sdp, format) && !strstr(sdp, format2)))
419
0
      return -2;
420
0
  }
421
0
  char rtpmap[50], rtpmap2[50];
422
0
  g_snprintf(rtpmap, 50, "a=rtpmap:%%d %s", format);
423
0
  g_snprintf(rtpmap2, 50, "a=rtpmap:%%d %s", format2);
424
  /* Look for the mapping */
425
0
  const char *line = strstr(sdp, video ? "m=video" : "m=audio");
426
0
  while(line) {
427
0
    char *next = strchr(line, '\n');
428
0
    if(next) {
429
0
      *next = '\0';
430
0
      if(strstr(line, "a=rtpmap") && strstr(line, format)) {
431
        /* Gotcha! */
432
0
        int pt = 0;
433
0
#pragma GCC diagnostic push
434
0
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
435
0
        if(sscanf(line, rtpmap, &pt) == 1) {
436
0
          *next = '\n';
437
0
          return pt;
438
0
        }
439
0
      } else if(strstr(line, "a=rtpmap") && strstr(line, format2)) {
440
        /* Gotcha! */
441
0
        int pt = 0;
442
0
        if(sscanf(line, rtpmap2, &pt) == 1) {
443
0
#pragma GCC diagnostic pop
444
0
          *next = '\n';
445
0
          return pt;
446
0
        }
447
0
      }
448
0
      *next = '\n';
449
0
    }
450
0
    line = next ? (next+1) : NULL;
451
0
  }
452
0
  return -3;
453
0
}
454
455
0
const char *janus_get_codec_from_pt(const char *sdp, int pt) {
456
0
  if(!sdp || pt < 0)
457
0
    return NULL;
458
0
  if(pt == 0)
459
0
    return "pcmu";
460
0
  if(pt == 8)
461
0
    return "pcma";
462
0
  if(pt == 9)
463
0
    return "g722";
464
  /* Look for the mapping */
465
0
  char rtpmap[50];
466
0
  g_snprintf(rtpmap, 50, "a=rtpmap:%d ", pt);
467
0
  const char *line = strstr(sdp, "m=");
468
0
  while(line) {
469
0
    char *next = strchr(line, '\n');
470
0
    if(next) {
471
0
      *next = '\0';
472
0
      if(strstr(line, rtpmap)) {
473
        /* Gotcha! */
474
0
        char name[100];
475
0
        if(sscanf(line, "a=rtpmap:%d %99s", &pt, name) == 2) {
476
0
          *next = '\n';
477
0
          if(strstr(name, "vp8") || strstr(name, "VP8"))
478
0
            return "vp8";
479
0
          if(strstr(name, "vp9") || strstr(name, "VP9"))
480
0
            return "vp9";
481
0
          if(strstr(name, "h264") || strstr(name, "H264"))
482
0
            return "h264";
483
0
          if(strstr(name, "av1") || strstr(name, "AV1"))
484
0
            return "av1";
485
0
          if(strstr(name, "h265") || strstr(name, "H265"))
486
0
            return "h265";
487
0
          if(strstr(name, "opus") || strstr(name, "OPUS"))
488
0
            return "opus";
489
0
          if(strstr(name, "pcmu") || strstr(name, "PCMU"))
490
0
            return "pcmu";
491
0
          if(strstr(name, "pcma") || strstr(name, "PCMA"))
492
0
            return "pcma";
493
0
          if(strstr(name, "g722") || strstr(name, "G722"))
494
0
            return "g722";
495
0
          if(strstr(name, "isac/16") || strstr(name, "ISAC/16"))
496
0
            return "isac16";
497
0
          if(strstr(name, "isac/32") || strstr(name, "ISAC/32"))
498
0
            return "isac32";
499
0
          if(strstr(name, "l16/48") || strstr(name, "L16/48"))
500
0
            return "l16-48";
501
0
          if(strstr(name, "l16/16") || strstr(name, "L16/16"))
502
0
            return "l16";
503
0
          if(strstr(name, "red"))
504
0
            return NULL;
505
0
          JANUS_LOG(LOG_ERR, "Unsupported codec '%s'\n", name);
506
0
          return NULL;
507
0
        }
508
0
      }
509
0
      *next = '\n';
510
0
    }
511
0
    line = next ? (next+1) : NULL;
512
0
  }
513
0
  return NULL;
514
0
}
515
516
/* PID file management */
517
static char *pidfile = NULL;
518
static int pidfd = -1;
519
static FILE *pidf = NULL;
520
0
int janus_pidfile_create(const char *file) {
521
0
  if(file == NULL)
522
0
    return 0;
523
0
  pidfile = g_strdup(file);
524
  /* Try creating a PID file (or opening an existing one) */
525
0
  pidfd = open(pidfile, O_RDWR|O_CREAT|O_TRUNC, 0644);
526
0
  if(pidfd < 0) {
527
0
    JANUS_LOG(LOG_FATAL, "Error opening/creating PID file %s, does Janus have enough permissions?\n", pidfile);
528
0
    return -1;
529
0
  }
530
0
  pidf = fdopen(pidfd, "r+");
531
0
  if(pidf == NULL) {
532
0
    JANUS_LOG(LOG_FATAL, "Error opening/creating PID file %s, does Janus have enough permissions?\n", pidfile);
533
0
    close(pidfd);
534
0
    return -1;
535
0
  }
536
  /* Try locking the PID file */
537
0
  int pid = 0;
538
0
  if(flock(pidfd, LOCK_EX|LOCK_NB) < 0) {
539
0
    if(fscanf(pidf, "%d", &pid) == 1) {
540
0
      JANUS_LOG(LOG_FATAL, "Error locking PID file (lock held by PID %d?)\n", pid);
541
0
    } else {
542
0
      JANUS_LOG(LOG_FATAL, "Error locking PID file (lock held by unknown PID?)\n");
543
0
    }
544
0
    fclose(pidf);
545
0
    return -1;
546
0
  }
547
  /* Write the PID */
548
0
  pid = getpid();
549
0
  if(fprintf(pidf, "%d\n", pid) < 0) {
550
0
    JANUS_LOG(LOG_FATAL, "Error writing PID in file, error %d (%s)\n", errno, g_strerror(errno));
551
0
    fclose(pidf);
552
0
    return -1;
553
0
  }
554
0
  fflush(pidf);
555
  /* We're done */
556
0
  return 0;
557
0
}
558
559
0
int janus_pidfile_remove(void) {
560
0
  if(pidfile == NULL || pidfd < 0 || pidf == NULL)
561
0
    return 0;
562
  /* Unlock the PID file and remove it */
563
0
  if(flock(pidfd, LOCK_UN) < 0) {
564
0
    JANUS_LOG(LOG_FATAL, "Error unlocking PID file\n");
565
0
    fclose(pidf);
566
0
    close(pidfd);
567
0
    return -1;
568
0
  }
569
0
  fclose(pidf);
570
0
  unlink(pidfile);
571
0
  g_free(pidfile);
572
0
  return 0;
573
0
}
574
575
/* Protected folders management */
576
static GList *protected_folders = NULL;
577
static janus_mutex pf_mutex = JANUS_MUTEX_INITIALIZER;
578
579
0
void janus_protected_folder_add(const char *folder) {
580
0
  if(folder == NULL)
581
0
    return;
582
0
  janus_mutex_lock(&pf_mutex);
583
0
  protected_folders = g_list_append(protected_folders, g_strdup(folder));
584
0
  janus_mutex_unlock(&pf_mutex);
585
0
}
586
587
0
gboolean janus_is_folder_protected(const char *path) {
588
  /* We need a valid pathname (can't start with a space, we don't trim) */
589
0
  if(path == NULL || *path == ' ')
590
0
    return TRUE;
591
  /* Resolve the pathname to its real path first */
592
0
  char resolved[PATH_MAX+1];
593
0
  resolved[0] = '\0';
594
0
  if(realpath(path, resolved) == NULL && errno != ENOENT) {
595
0
    JANUS_LOG(LOG_ERR, "Error resolving path '%s'... %d (%s)\n",
596
0
      path, errno, g_strerror(errno));
597
0
    return TRUE;
598
0
  }
599
  /* Traverse the list of protected folders to see if any match */
600
0
  janus_mutex_lock(&pf_mutex);
601
0
  if(protected_folders == NULL) {
602
    /* No protected folder in the list */
603
0
    janus_mutex_unlock(&pf_mutex);
604
0
    return FALSE;
605
0
  }
606
0
  gboolean protected = FALSE;
607
0
  GList *temp = protected_folders;
608
0
  while(temp) {
609
0
    char *folder = (char *)temp->data;
610
0
    if(folder && (strstr(resolved, folder) == resolved)) {
611
0
      protected = TRUE;
612
0
      break;
613
0
    }
614
0
    temp = temp->next;
615
0
  }
616
0
  janus_mutex_unlock(&pf_mutex);
617
0
  return protected;
618
0
}
619
620
0
void janus_protected_folders_clear(void) {
621
0
  janus_mutex_lock(&pf_mutex);
622
0
  g_list_free_full(protected_folders, (GDestroyNotify)g_free);
623
0
  janus_mutex_unlock(&pf_mutex);
624
0
}
625
626
627
0
void janus_get_json_type_name(int jtype, unsigned int flags, char *type_name) {
628
  /* Longest possible combination is "a non-empty boolean" plus one for null char */
629
0
  gsize req_size = 20;
630
  /* Don't allow for both "positive" and "non-empty" because that needlessly increases the size. */
631
0
  if((flags & JANUS_JSON_PARAM_POSITIVE) != 0) {
632
0
    g_strlcpy(type_name, "a positive ", req_size);
633
0
  }
634
0
  else if((flags & JANUS_JSON_PARAM_NONEMPTY) != 0) {
635
0
    g_strlcpy(type_name, "a non-empty ", req_size);
636
0
  }
637
0
  else if(jtype == JSON_INTEGER || jtype == JSON_ARRAY || jtype == JSON_OBJECT) {
638
0
    g_strlcpy(type_name, "an ", req_size);
639
0
  }
640
0
  else {
641
0
    g_strlcpy(type_name, "a ", req_size);
642
0
  }
643
0
  switch(jtype) {
644
0
    case JSON_TRUE:
645
0
      janus_strlcat(type_name, "boolean", req_size);
646
0
      break;
647
0
    case JSON_INTEGER:
648
0
      janus_strlcat(type_name, "integer", req_size);
649
0
      break;
650
0
    case JSON_REAL:
651
0
      janus_strlcat(type_name, "real", req_size);
652
0
      break;
653
0
    case JSON_STRING:
654
0
      janus_strlcat(type_name, "string", req_size);
655
0
      break;
656
0
    case JSON_ARRAY:
657
0
      janus_strlcat(type_name, "array", req_size);
658
0
      break;
659
0
    case JSON_OBJECT:
660
0
      janus_strlcat(type_name, "object", req_size);
661
0
      break;
662
0
    default:
663
0
      break;
664
0
  }
665
0
}
666
667
0
gboolean janus_json_is_valid(json_t *val, json_type jtype, unsigned int flags) {
668
0
  gboolean is_valid = (json_typeof(val) == jtype || (jtype == JSON_TRUE && json_typeof(val) == JSON_FALSE));
669
0
  if(!is_valid)
670
0
    return FALSE;
671
0
  if((flags & JANUS_JSON_PARAM_POSITIVE) != 0) {
672
0
    switch(jtype) {
673
0
      case JSON_INTEGER:
674
0
        is_valid = (json_integer_value(val) >= 0);
675
0
        break;
676
0
      case JSON_REAL:
677
0
        is_valid = (json_real_value(val) >= 0);
678
0
        break;
679
0
      default:
680
0
        break;
681
0
    }
682
0
  }
683
0
  else if((flags & JANUS_JSON_PARAM_NONEMPTY) != 0) {
684
0
    switch(jtype) {
685
0
      case JSON_STRING:
686
0
        is_valid = (strlen(json_string_value(val)) > 0);
687
0
        break;
688
0
      case JSON_ARRAY:
689
0
        is_valid = (json_array_size(val) > 0);
690
0
        break;
691
0
      default:
692
0
        break;
693
0
    }
694
0
  }
695
0
  return is_valid;
696
0
}
697
698
/* The following code is more related to codec specific helpers */
699
#if defined(__ppc__) || defined(__ppc64__)
700
  # define swap2(d)  \
701
  ((d&0x000000ff)<<8) |  \
702
  ((d&0x0000ff00)>>8)
703
#else
704
4
  # define swap2(d) d
705
#endif
706
707
617
gboolean janus_vp8_is_keyframe(const char *buffer, int len) {
708
617
  if(!buffer || len < 16)
709
378
    return FALSE;
710
  /* Parse VP8 header now */
711
239
  uint8_t vp8pd = *buffer;
712
239
  uint8_t xbit = (vp8pd & 0x80);
713
239
  uint8_t sbit = (vp8pd & 0x10);
714
239
  if(xbit) {
715
98
    JANUS_LOG(LOG_HUGE, "  -- X bit is set!\n");
716
    /* Read the Extended control bits octet */
717
98
    buffer++;
718
98
    vp8pd = *buffer;
719
98
    uint8_t ibit = (vp8pd & 0x80);
720
98
    uint8_t lbit = (vp8pd & 0x40);
721
98
    uint8_t tbit = (vp8pd & 0x20);
722
98
    uint8_t kbit = (vp8pd & 0x10);
723
98
    if(ibit) {
724
67
      JANUS_LOG(LOG_HUGE, "  -- I bit is set!\n");
725
      /* Read the PictureID octet */
726
67
      buffer++;
727
67
      vp8pd = *buffer;
728
67
      uint16_t picid = vp8pd, wholepicid = picid;
729
67
      uint8_t mbit = (vp8pd & 0x80);
730
67
      if(mbit) {
731
49
        JANUS_LOG(LOG_HUGE, "  -- M bit is set!\n");
732
49
        memcpy(&picid, buffer, sizeof(uint16_t));
733
49
        wholepicid = ntohs(picid);
734
49
        picid = (wholepicid & 0x7FFF);
735
49
        buffer++;
736
49
      }
737
67
      JANUS_LOG(LOG_HUGE, "  -- -- PictureID: %"SCNu16"\n", picid);
738
67
    }
739
98
    if(lbit) {
740
48
      JANUS_LOG(LOG_HUGE, "  -- L bit is set!\n");
741
      /* Read the TL0PICIDX octet */
742
48
      buffer++;
743
48
      vp8pd = *buffer;
744
48
    }
745
98
    if(tbit || kbit) {
746
61
      JANUS_LOG(LOG_HUGE, "  -- T/K bit is set!\n");
747
      /* Read the TID/KEYIDX octet */
748
61
      buffer++;
749
61
      vp8pd = *buffer;
750
61
    }
751
98
  }
752
239
  buffer++; /* Now we're in the payload */
753
239
  if(sbit) {
754
178
    JANUS_LOG(LOG_HUGE, "  -- S bit is set!\n");
755
178
    unsigned long int vp8ph = 0;
756
178
    memcpy(&vp8ph, buffer, 4);
757
178
    vp8ph = ntohl(vp8ph);
758
178
    uint8_t pbit = ((vp8ph & 0x01000000) >> 24);
759
178
    if(!pbit) {
760
109
      JANUS_LOG(LOG_HUGE, "  -- P bit is NOT set!\n");
761
      /* It is a key frame! Get resolution for debugging */
762
109
      unsigned char *c = (unsigned char *)buffer+3;
763
      /* vet via sync code */
764
109
      if(c[0]!=0x9d||c[1]!=0x01||c[2]!=0x2a) {
765
108
        JANUS_LOG(LOG_HUGE, "First 3-bytes after header not what they're supposed to be?\n");
766
108
      } else {
767
1
        unsigned short val3, val5;
768
1
        memcpy(&val3,c+3,sizeof(short));
769
1
        int vp8w = swap2(val3)&0x3fff;
770
1
        int vp8ws = swap2(val3)>>14;
771
1
        memcpy(&val5,c+5,sizeof(short));
772
1
        int vp8h = swap2(val5)&0x3fff;
773
1
        int vp8hs = swap2(val5)>>14;
774
1
        JANUS_LOG(LOG_HUGE, "Got a VP8 key frame: %dx%d (scale=%dx%d)\n", vp8w, vp8h, vp8ws, vp8hs);
775
1
        return TRUE;
776
1
      }
777
109
    }
778
178
  }
779
  /* If we got here it's not a key frame */
780
238
  return FALSE;
781
239
}
782
783
617
gboolean janus_vp9_is_keyframe(const char *buffer, int len) {
784
617
  if(!buffer || len < 16)
785
378
    return FALSE;
786
  /* Parse VP9 header now */
787
239
  uint8_t vp9pd = *buffer;
788
239
  uint8_t ibit = (vp9pd & 0x80);
789
239
  uint8_t pbit = (vp9pd & 0x40);
790
239
  uint8_t lbit = (vp9pd & 0x20);
791
239
  uint8_t fbit = (vp9pd & 0x10);
792
239
  uint8_t vbit = (vp9pd & 0x02);
793
239
  buffer++;
794
239
  len--;
795
239
  if(ibit) {
796
    /* Read the PictureID octet */
797
98
    vp9pd = *buffer;
798
98
    uint16_t picid = vp9pd, wholepicid = picid;
799
98
    uint8_t mbit = (vp9pd & 0x80);
800
98
    if(!mbit) {
801
31
      buffer++;
802
31
      len--;
803
67
    } else {
804
67
      memcpy(&picid, buffer, sizeof(uint16_t));
805
67
      wholepicid = ntohs(picid);
806
67
      picid = (wholepicid & 0x7FFF);
807
67
      buffer += 2;
808
67
      len -= 2;
809
67
    }
810
98
  }
811
239
  if(lbit) {
812
134
    buffer++;
813
134
    len--;
814
134
    if(!fbit) {
815
      /* Non-flexible mode, skip TL0PICIDX */
816
10
      buffer++;
817
10
      len--;
818
10
    }
819
134
  }
820
239
  if(fbit && pbit) {
821
    /* Skip reference indices */
822
79
    uint8_t nbit = 1;
823
1.18k
    while(nbit) {
824
1.11k
      vp9pd = *buffer;
825
1.11k
      nbit = (vp9pd & 0x01);
826
1.11k
      buffer++;
827
1.11k
      len--;
828
1.11k
      if(len == 0)  /* Make sure we don't overflow */
829
5
        return FALSE;
830
1.11k
    }
831
79
  }
832
234
  if(vbit) {
833
    /* Parse and skip SS */
834
153
    vp9pd = *buffer;
835
153
    uint n_s = (vp9pd & 0xE0) >> 5;
836
153
    n_s++;
837
153
    uint8_t ybit = (vp9pd & 0x10);
838
153
    if(ybit) {
839
      /* Iterate on all spatial layers and get resolution */
840
101
      buffer++;
841
101
      len--;
842
101
      if(len == 0)  /* Make sure we don't overflow */
843
3
        return FALSE;
844
98
      uint i=0;
845
159
      for(i=0; i<n_s && len>=4; i++,len-=4) {
846
        /* Width */
847
147
        uint16_t w;
848
147
        memcpy(&w, buffer, sizeof(uint16_t));
849
147
        int vp9w = ntohs(w);
850
147
        buffer += 2;
851
        /* Height */
852
147
        uint16_t h;
853
147
        memcpy(&h, buffer, sizeof(uint16_t));
854
147
        int vp9h = ntohs(h);
855
147
        buffer += 2;
856
147
        if(vp9w || vp9h) {
857
86
          JANUS_LOG(LOG_HUGE, "Got a VP9 key frame: %dx%d\n", vp9w, vp9h);
858
86
          return TRUE;
859
86
        }
860
147
      }
861
98
    }
862
153
  }
863
  /* If we got here it's not a key frame */
864
145
  return FALSE;
865
234
}
866
867
617
static gboolean janus_h264_contains_nal(const char *buffer, int len, int val) {
868
617
  if(!buffer || len < 6)
869
234
    return FALSE;
870
  /* Parse H264 header now */
871
383
  uint8_t fragment = *buffer & 0x1F;
872
383
  uint8_t nal = *(buffer+1) & 0x1F;
873
383
  if(fragment == val || ((fragment == 28 || fragment == 29) && nal == val && (*(buffer+1) & 0x80))) {
874
10
    JANUS_LOG(LOG_HUGE, "Got an H264 NAL %d\n", val);
875
10
    return TRUE;
876
373
  } else if(fragment == 24) {
877
    /* May we find it in this STAP-A? */
878
60
    buffer++;
879
60
    len--;
880
60
    uint16_t psize = 0;
881
    /* We're reading 3 bytes */
882
446
    while(len > 2) {
883
387
      memcpy(&psize, buffer, 2);
884
387
      psize = ntohs(psize);
885
387
      buffer += 2;
886
387
      len -= 2;
887
387
      int nal = *buffer & 0x1F;
888
387
      if(nal == val) {
889
1
        JANUS_LOG(LOG_HUGE, "Got an H264 NAL %d\n", val);
890
1
        return TRUE;
891
1
      }
892
386
      buffer += psize;
893
386
      len -= psize;
894
386
    }
895
60
  }
896
  /* If we got here we didn't find it */
897
372
  return FALSE;
898
383
}
899
900
617
gboolean janus_h264_is_keyframe(const char *buffer, int len) {
901
617
  return janus_h264_contains_nal(buffer, len, 7);
902
617
}
903
904
0
gboolean janus_h264_is_i_frame(const char *buffer, int len) {
905
0
  return janus_h264_contains_nal(buffer, len, 5);
906
0
}
907
908
0
gboolean janus_h264_is_b_frame(const char *buffer, int len) {
909
0
  return janus_h264_contains_nal(buffer, len, 1);
910
0
}
911
912
0
gboolean janus_av1_is_keyframe(const char *buffer, int len) {
913
0
  if(!buffer || len < 3)
914
0
    return FALSE;
915
  /* Read the aggregation header */
916
0
  uint8_t aggrh = *buffer;
917
0
  uint8_t zbit = (aggrh & 0x80) >> 7;
918
0
  uint8_t nbit = (aggrh & 0x08) >> 3;
919
  /* FIXME Ugly hack: we consider a packet with Z=0 and N=1 a keyframe */
920
0
  return (!zbit && nbit);
921
0
}
922
923
0
gboolean janus_h265_is_keyframe(const char *buffer, int len) {
924
0
  if(!buffer || len < 2)
925
0
    return FALSE;
926
  /* Parse the NAL unit */
927
0
  uint16_t unit = 0;
928
0
  memcpy(&unit, buffer, sizeof(uint16_t));
929
0
  unit = ntohs(unit);
930
0
  uint8_t type = (unit & 0x7E00) >> 9;
931
0
  if(type == 32 || type == 33 || type == 34 || type == 16 || type == 17 || type == 18 || type == 19 || type == 20 || type == 21) {
932
    /* FIXME We return TRUE for more than just VPS and SPS, as
933
     * suggested in https://github.com/meetecho/janus-gateway/issues/2323 */
934
0
    return TRUE;
935
0
  }
936
0
  return FALSE;
937
0
}
938
939
0
gboolean janus_is_keyframe(int codec, const char *buffer, int len) {
940
0
  switch(codec) {
941
0
    case JANUS_VIDEOCODEC_VP8:
942
0
      return janus_vp8_is_keyframe(buffer, len);
943
0
    case JANUS_VIDEOCODEC_VP9:
944
0
      return janus_vp9_is_keyframe(buffer, len);
945
0
    case JANUS_VIDEOCODEC_H264:
946
0
      return janus_h264_is_keyframe(buffer, len);
947
0
    case JANUS_VIDEOCODEC_AV1:
948
0
      return janus_av1_is_keyframe(buffer, len);
949
0
    case JANUS_VIDEOCODEC_H265:
950
0
      return janus_h265_is_keyframe(buffer, len);
951
0
    default:
952
0
      break;
953
0
  }
954
0
  return FALSE;
955
0
}
956
957
int janus_vp8_parse_descriptor(char *buffer, int len,
958
1.23k
    gboolean *m, uint16_t *picid, uint8_t *tl0picidx, uint8_t *tid, uint8_t *y, uint8_t *keyidx) {
959
1.23k
  if(!buffer || len < 6)
960
468
    return -1;
961
766
  if(picid)
962
766
    *picid = 0;
963
766
  if(tl0picidx)
964
766
    *tl0picidx = 0;
965
766
  if(tid)
966
766
    *tid = 0;
967
766
  if(y)
968
766
    *y = 0;
969
766
  if(keyidx)
970
766
    *keyidx = 0;
971
766
  uint8_t vp8pd = *buffer;
972
766
  uint8_t xbit = (vp8pd & 0x80);
973
  /* Read the Extended control bits octet */
974
766
  if(xbit) {
975
346
    buffer++;
976
346
    vp8pd = *buffer;
977
346
    uint8_t ibit = (vp8pd & 0x80);
978
346
    uint8_t lbit = (vp8pd & 0x40);
979
346
    uint8_t tbit = (vp8pd & 0x20);
980
346
    uint8_t kbit = (vp8pd & 0x10);
981
346
    if(ibit) {
982
      /* Read the PictureID octet */
983
214
      buffer++;
984
214
      vp8pd = *buffer;
985
214
      uint16_t partpicid = vp8pd, wholepicid = partpicid;
986
214
      uint8_t mbit = (vp8pd & 0x80);
987
214
      if(mbit) {
988
146
        memcpy(&partpicid, buffer, sizeof(uint16_t));
989
146
        wholepicid = ntohs(partpicid);
990
146
        partpicid = (wholepicid & 0x7FFF);
991
146
        buffer++;
992
146
      }
993
214
      if(m)
994
214
        *m = (mbit ? TRUE : FALSE);
995
214
      if(picid)
996
214
        *picid = partpicid;
997
214
    }
998
346
    if(lbit) {
999
      /* Read the TL0PICIDX octet */
1000
170
      buffer++;
1001
170
      vp8pd = *buffer;
1002
170
      if(tl0picidx)
1003
170
        *tl0picidx = vp8pd;
1004
170
    }
1005
346
    if(tbit || kbit) {
1006
      /* Read the TID/Y/KEYIDX octet */
1007
204
      buffer++;
1008
204
      vp8pd = *buffer;
1009
204
      if(tid)
1010
204
        *tid = (vp8pd & 0xC0) >> 6;
1011
204
      if(y)
1012
204
        *y = (vp8pd & 0x20) >> 5;
1013
204
      if(keyidx)
1014
204
        *keyidx = (vp8pd & 0x1F) >> 4;
1015
204
    }
1016
346
  }
1017
766
  return 0;
1018
1.23k
}
1019
1020
383
static int janus_vp8_replace_descriptor(char *buffer, int len, gboolean m, uint16_t picid, uint8_t tl0picidx) {
1021
383
  if(!buffer || len < 6)
1022
0
    return -1;
1023
383
  uint8_t vp8pd = *buffer;
1024
383
  uint8_t xbit = (vp8pd & 0x80);
1025
  /* Read the Extended control bits octet */
1026
383
  if(xbit) {
1027
173
    buffer++;
1028
173
    vp8pd = *buffer;
1029
173
    uint8_t ibit = (vp8pd & 0x80);
1030
173
    uint8_t lbit = (vp8pd & 0x40);
1031
173
    uint8_t tbit = (vp8pd & 0x20);
1032
173
    uint8_t kbit = (vp8pd & 0x10);
1033
173
    if(ibit) {
1034
      /* Overwrite the PictureID octet */
1035
107
      buffer++;
1036
107
      vp8pd = *buffer;
1037
107
      uint8_t mbit = (vp8pd & 0x80);
1038
107
      if(!mbit || !m) {
1039
34
        *buffer = picid;
1040
73
      } else {
1041
73
        uint16_t wholepicid = htons(picid);
1042
73
        memcpy(buffer, &wholepicid, 2);
1043
73
        *buffer |= 0x80;
1044
73
        buffer++;
1045
73
      }
1046
107
    }
1047
173
    if(lbit) {
1048
      /* Overwrite the TL0PICIDX octet */
1049
85
      buffer++;
1050
85
      *buffer = tl0picidx;
1051
85
    }
1052
173
    if(tbit || kbit) {
1053
      /* Should we overwrite the TID/Y/KEYIDX octet? */
1054
102
      buffer++;
1055
102
    }
1056
173
  }
1057
383
  return 0;
1058
383
}
1059
1060
0
void janus_vp8_simulcast_context_reset(janus_vp8_simulcast_context *context) {
1061
0
  if(context == NULL)
1062
0
    return;
1063
  /* Reset the context values */
1064
0
  context->last_picid = 0;
1065
0
  context->base_picid = 0;
1066
0
  context->base_picid_prev = 0;
1067
0
  context->last_tlzi = 0;
1068
0
  context->base_tlzi = 0;
1069
0
  context->base_tlzi_prev = 0;
1070
0
}
1071
1072
617
void janus_vp8_simulcast_descriptor_update(char *buffer, int len, janus_vp8_simulcast_context *context, gboolean switched) {
1073
617
  if(!buffer || len < 0)
1074
0
    return;
1075
617
  gboolean m = FALSE;
1076
617
  uint16_t picid = 0;
1077
617
  uint8_t tlzi = 0;
1078
617
  uint8_t tid = 0;
1079
617
  uint8_t ybit = 0;
1080
617
  uint8_t keyidx = 0;
1081
  /* Parse the identifiers in the VP8 payload descriptor */
1082
617
  if(janus_vp8_parse_descriptor(buffer, len, &m, &picid, &tlzi, &tid, &ybit, &keyidx) < 0)
1083
234
    return;
1084
383
  if(switched) {
1085
383
    context->base_picid_prev = context->last_picid;
1086
383
    context->base_picid = picid;
1087
383
    context->base_tlzi_prev = context->last_tlzi;
1088
383
    context->base_tlzi = tlzi;
1089
383
  }
1090
383
  context->last_picid = (picid-context->base_picid)+context->base_picid_prev+1;
1091
383
  if(!m && context->last_picid > 127) {
1092
0
    context->last_picid -= 128;
1093
0
    if(context->last_picid > 127)
1094
0
      context->last_picid = 0;
1095
383
  } else if(m && context->last_picid > 32767) {
1096
0
    context->last_picid -= 32768;
1097
0
  }
1098
383
  context->last_tlzi = (tlzi-context->base_tlzi)+context->base_tlzi_prev+1;
1099
  /* Overwrite the values in the VP8 payload descriptors with the ones we have */
1100
383
  janus_vp8_replace_descriptor(buffer, len, m, context->last_picid, context->last_tlzi);
1101
383
}
1102
1103
/* Helper method to parse a VP9 RTP video frame and get some SVC-related info:
1104
 * notice that this only works with VP9, right now, on an experimental basis */
1105
617
int janus_vp9_parse_svc(char *buffer, int len, gboolean *found, janus_vp9_svc_info *info) {
1106
617
  if(!buffer || len < 8)
1107
311
    return -1;
1108
  /* VP9 depay: */
1109
    /* https://tools.ietf.org/html/draft-ietf-payload-vp9-04 */
1110
  /* Read the first octet (VP9 Payload Descriptor) */
1111
306
  uint8_t vp9pd = *buffer;
1112
306
  uint8_t ibit = (vp9pd & 0x80) >> 7;
1113
306
  uint8_t pbit = (vp9pd & 0x40) >> 6;
1114
306
  uint8_t lbit = (vp9pd & 0x20) >> 5;
1115
306
  uint8_t fbit = (vp9pd & 0x10) >> 4;
1116
306
  uint8_t bbit = (vp9pd & 0x08) >> 3;
1117
306
  uint8_t ebit = (vp9pd & 0x04) >> 2;
1118
306
  uint8_t vbit = (vp9pd & 0x02) >> 1;
1119
306
  if(!lbit) {
1120
    /* No Layer indices present, no need to go on */
1121
115
    if(found)
1122
115
      *found = FALSE;
1123
115
    return 0;
1124
115
  }
1125
  /* Move to the next octet and see what's there */
1126
191
  buffer++;
1127
191
  len--;
1128
191
  if(ibit) {
1129
    /* Read the PictureID octet */
1130
83
    vp9pd = *buffer;
1131
83
    uint16_t picid = vp9pd, wholepicid = picid;
1132
83
    uint8_t mbit = (vp9pd & 0x80);
1133
83
    if(!mbit) {
1134
34
      buffer++;
1135
34
      len--;
1136
49
    } else {
1137
49
      memcpy(&picid, buffer, sizeof(uint16_t));
1138
49
      wholepicid = ntohs(picid);
1139
49
      picid = (wholepicid & 0x7FFF);
1140
49
      buffer += 2;
1141
49
      len -= 2;
1142
49
    }
1143
83
  }
1144
191
  if(lbit) {
1145
    /* Read the octet and parse the layer indices now */
1146
191
    vp9pd = *buffer;
1147
191
    int tlid = (vp9pd & 0xE0) >> 5;
1148
191
    uint8_t ubit = (vp9pd & 0x10) >> 4;
1149
191
    int slid = (vp9pd & 0x0E) >> 1;
1150
191
    uint8_t dbit = (vp9pd & 0x01);
1151
191
    JANUS_LOG(LOG_HUGE, "%s Mode, Layer indices: Temporal: %d (u=%u), Spatial: %d (d=%u)\n",
1152
191
      fbit ? "Flexible" : "Non-flexible", tlid, ubit, slid, dbit);
1153
191
    if(info) {
1154
191
      info->temporal_layer = tlid;
1155
191
      info->spatial_layer = slid;
1156
191
      info->fbit = fbit;
1157
191
      info->pbit = pbit;
1158
191
      info->dbit = dbit;
1159
191
      info->ubit = ubit;
1160
191
      info->bbit = bbit;
1161
191
      info->ebit = ebit;
1162
191
    }
1163
191
    if(found)
1164
191
      *found = TRUE;
1165
    /* Go on, just to get to the SS, if available (which we currently ignore anyway) */
1166
191
    buffer++;
1167
191
    len--;
1168
191
    if(!fbit) {
1169
      /* Non-flexible mode, skip TL0PICIDX */
1170
20
      buffer++;
1171
20
      len--;
1172
20
    }
1173
191
  }
1174
191
  if(fbit && pbit) {
1175
    /* Skip reference indices */
1176
86
    uint8_t nbit = 1;
1177
928
    while(nbit) {
1178
849
      vp9pd = *buffer;
1179
849
      nbit = (vp9pd & 0x01);
1180
849
      buffer++;
1181
849
      len--;
1182
849
      if(len == 0)  /* Make sure we don't overflow */
1183
7
        return -1;
1184
849
    }
1185
86
  }
1186
184
  if(vbit) {
1187
    /* Parse and skip SS */
1188
147
    vp9pd = *buffer;
1189
147
    int n_s = (vp9pd & 0xE0) >> 5;
1190
147
    n_s++;
1191
147
    JANUS_LOG(LOG_HUGE, "There are %d spatial layers\n", n_s);
1192
147
    uint8_t ybit = (vp9pd & 0x10);
1193
147
    uint8_t gbit = (vp9pd & 0x08);
1194
147
    if(ybit) {
1195
      /* Iterate on all spatial layers and get resolution */
1196
69
      buffer++;
1197
69
      len--;
1198
69
      if(len == 0)  /* Make sure we don't overflow */
1199
5
        return -1;
1200
64
      int i=0;
1201
255
      for(i=0; i<n_s; i++) {
1202
        /* Been there, done that: skip skip skip */
1203
218
        buffer += 4;
1204
218
        len -= 4;
1205
218
        if(len <= 0)  /* Make sure we don't overflow */
1206
27
          return -1;
1207
218
      }
1208
64
    }
1209
115
    if(gbit) {
1210
84
      if(!ybit) {
1211
63
        buffer++;
1212
63
        len--;
1213
63
        if(len == 0)  /* Make sure we don't overflow */
1214
1
          return -1;
1215
63
      }
1216
83
      uint8_t n_g = *buffer;
1217
83
      JANUS_LOG(LOG_HUGE, "There are %u frames in a GOF\n", n_g);
1218
83
      buffer++;
1219
83
      len--;
1220
83
      if(len == 0)  /* Make sure we don't overflow */
1221
2
        return -1;
1222
81
      if(n_g > 0) {
1223
77
        int i=0;
1224
3.95k
        for(i=0; i<n_g; i++) {
1225
          /* Read the R bits */
1226
3.93k
          vp9pd = *buffer;
1227
3.93k
          int r = (vp9pd & 0x0C) >> 2;
1228
3.93k
          if(r > 0) {
1229
            /* Skip reference indices */
1230
2.13k
            buffer += r;
1231
2.13k
            len -= r;
1232
2.13k
            if(len <= 0)  /* Make sure we don't overflow */
1233
21
              return -1;
1234
2.13k
          }
1235
3.91k
          buffer++;
1236
3.91k
          len--;
1237
3.91k
          if(len == 0)  /* Make sure we don't overflow */
1238
37
            return -1;
1239
3.91k
        }
1240
77
      }
1241
81
    }
1242
115
  }
1243
91
  return 0;
1244
184
}
1245
1246
/* RED parsing and building utilities */
1247
0
GList *janus_red_parse_blocks(char *buffer, int len) {
1248
0
  if(buffer == NULL || len < 0)
1249
0
    return NULL;
1250
  /* TODO This whole method should be fuzzed */
1251
0
  char *payload = buffer;
1252
0
  int plen = len;
1253
  /* Find out how many generations are in the RED packet */
1254
0
  int gens = 0;
1255
0
  uint32_t red_block;
1256
0
  uint8_t follow = 0, block_pt = 0;
1257
0
  uint16_t ts_offset = 0, block_len = 0;
1258
0
  GList *blocks = NULL;
1259
0
  janus_red_block *rb = NULL;
1260
  /* Parse the header */
1261
0
  while(payload != NULL && plen > 0) {
1262
    /* Go through the header for the different generations */
1263
0
    gens++;
1264
0
    follow = ((*payload) & 0x80) >> 7;
1265
0
    block_pt = (*payload) & 0x7F;
1266
0
    if(follow && plen > 3) {
1267
      /* Read the rest of the header */
1268
0
      memcpy(&red_block, payload, sizeof(red_block));
1269
0
      red_block = ntohl(red_block);
1270
0
      ts_offset = (red_block & 0x00FFFC00) >> 10;
1271
0
      block_len = (red_block & 0x000003FF);
1272
0
      JANUS_LOG(LOG_HUGE, "  [%d] f=%u, pt=%u, tsoff=%"SCNu16", blen=%"SCNu16"\n",
1273
0
        gens, follow, block_pt, ts_offset, block_len);
1274
0
      rb = g_malloc0(sizeof(janus_red_block));
1275
0
      rb->pt = block_pt;
1276
0
      rb->ts_offset = ts_offset;
1277
0
      rb->length = block_len;
1278
0
      blocks = g_list_append(blocks, rb);
1279
0
      payload += 4;
1280
0
      plen -= 4;
1281
0
    } else {
1282
      /* Header parsed */
1283
0
      payload++;
1284
0
      plen--;
1285
0
      JANUS_LOG(LOG_HUGE, "  [%d] f=%u, pt=%u, tsoff=0, blen=TBD.\n",
1286
0
        gens, follow, block_pt);
1287
0
      break;
1288
0
    }
1289
0
  }
1290
  /* Go through the blocks, iterating on the lengths to get a pointer to the data */
1291
0
  if(blocks != NULL) {
1292
0
    gens = 0;
1293
0
    uint16_t length = 0;
1294
0
    GList *temp = blocks;
1295
0
    while(temp != NULL) {
1296
0
      gens++;
1297
0
      rb = (janus_red_block *)temp->data;
1298
0
      length = rb->length;
1299
0
      if(length > plen) {
1300
0
        JANUS_LOG(LOG_WARN, "  >> [%d] Broken red payload:\n", gens);
1301
0
        g_list_free_full(blocks, (GDestroyNotify)g_free);
1302
0
        return NULL;
1303
0
      }
1304
0
      if(length > 0) {
1305
        /* Redundant data, take note of where the block is */
1306
0
        JANUS_LOG(LOG_HUGE, "  >> [%d] plen=%"SCNu16"\n", gens, length);
1307
0
        rb->data = (uint8_t *)payload;
1308
0
        payload += length;
1309
0
        plen -= length;
1310
0
      }
1311
0
      temp = temp->next;
1312
0
    }
1313
0
  }
1314
0
  if(plen > 0) {
1315
    /* The last block is the primary data, add it to the list */
1316
0
    gens++;
1317
0
    JANUS_LOG(LOG_HUGE, "  >> [%d] plen=%d\n", gens, plen);
1318
0
    rb = g_malloc0(sizeof(janus_red_block));
1319
0
    rb->pt = block_pt;
1320
0
    rb->length = plen;
1321
0
    rb->data = (uint8_t *)payload;
1322
0
    blocks = g_list_append(blocks, rb);
1323
0
  }
1324
1325
0
  return blocks;
1326
0
}
1327
0
int janus_red_pack_blocks(char *buffer, int len, GList *blocks) {
1328
0
  if(buffer == NULL || len < 0)
1329
0
    return 1;
1330
0
  int required = 0, written = 0;
1331
0
  janus_red_block *rb = NULL;
1332
  /* Write all headers to the buffer */
1333
0
  uint32_t red_block = 0;
1334
0
  uint8_t *payload = (uint8_t *)buffer;
1335
0
  GList *temp = blocks;
1336
0
  while(temp != NULL) {
1337
0
    rb = (janus_red_block *)temp->data;
1338
0
    required += (temp->next ? 4 : 1);
1339
0
    required += rb->length;
1340
0
    if(len < required) {
1341
0
      JANUS_LOG(LOG_ERR, "RED buffer too small (%d bytes, at least %d needed)\n", len, required);
1342
0
      return -2;
1343
0
    }
1344
0
    if(temp->next != NULL) {
1345
      /* There's going to be a follow-up, write 4 bytes (F=1 and info) */
1346
0
      red_block =
1347
0
        0x80000000 +              /* F=1 */
1348
0
        (0x7F000000 & (rb->pt << 24)) +     /* Payload type */
1349
0
        (0x00FFFC00 & (rb->ts_offset << 10)) +  /* Timestamp offset */
1350
0
        (0x000003FF & rb->length);        /* Data length */
1351
0
      red_block = htonl(red_block);
1352
0
      memcpy(payload + written, &red_block, sizeof(red_block));
1353
0
      written += 4;
1354
0
    } else {
1355
      /* Primary data, 1 byte (F=0 and payload type) */
1356
0
      uint8_t pt = rb->pt;
1357
0
      *(payload + written) = pt;
1358
0
      written++;
1359
0
    }
1360
0
    temp = temp->next;
1361
0
  }
1362
  /* Now write all data to the buffer too */
1363
0
  temp = blocks;
1364
0
  while(temp != NULL) {
1365
0
    rb = (janus_red_block *)temp->data;
1366
    /* Write the data itself */
1367
0
    memcpy(payload + written, rb->data, rb->length);
1368
0
    written += rb->length;
1369
0
    temp = temp->next;
1370
0
  }
1371
0
  return written;
1372
0
}
1373
0
int janus_red_replace_block_pt(char *buffer, int len, int pt) {
1374
0
  if(buffer == NULL || len < 0 || pt < 0 || pt > 127)
1375
0
    return -1;
1376
  /* TODO This whole method should be fuzzed */
1377
0
  char *payload = buffer;
1378
0
  int plen = len;
1379
0
  uint8_t follow = 0;
1380
  /* Parse the header */
1381
0
  while(payload != NULL && plen > 0) {
1382
    /* Go through the block headers */
1383
0
    follow = ((*payload) & 0x80) >> 7;
1384
0
    *payload = (0x80 & (follow << 7)) + (0x7F & pt);
1385
0
    if(follow && plen > 3) {
1386
      /* Move to the next block header */
1387
0
      payload += 4;
1388
0
      plen -= 4;
1389
0
    } else {
1390
      /* We're done */
1391
0
      break;
1392
0
    }
1393
0
  }
1394
0
  return 0;
1395
0
}
1396
1397
/* Bit manipulation (mostly for TWCC) */
1398
0
inline guint32 janus_push_bits(guint32 word, size_t num, guint32 val) {
1399
0
  if(num == 0)
1400
0
    return word;
1401
0
  return (word << num) | (val & (0xFFFFFFFF>>(32-num)));
1402
0
}
1403
1404
0
inline void janus_set1(guint8 *data,size_t i,guint8 val) {
1405
0
  data[i] = val;
1406
0
}
1407
1408
0
inline void janus_set2(guint8 *data,size_t i,guint32 val) {
1409
0
  data[i+1] = (guint8)(val);
1410
0
  data[i]   = (guint8)(val>>8);
1411
0
}
1412
1413
0
inline void janus_set3(guint8 *data,size_t i,guint32 val) {
1414
0
  data[i+2] = (guint8)(val);
1415
0
  data[i+1] = (guint8)(val>>8);
1416
0
  data[i]   = (guint8)(val>>16);
1417
0
}
1418
1419
0
inline void janus_set4(guint8 *data,size_t i,guint32 val) {
1420
0
  data[i+3] = (guint8)(val);
1421
0
  data[i+2] = (guint8)(val>>8);
1422
0
  data[i+1] = (guint8)(val>>16);
1423
0
  data[i]   = (guint8)(val>>24);
1424
0
}
1425
1426
0
uint8_t janus_bitstream_getbit(uint8_t *base, uint32_t offset) {
1427
0
  return ((*(base + (offset >> 0x3))) >> (0x7 - (offset & 0x7))) & 0x1;
1428
0
}
1429
1430
0
uint32_t janus_bitstream_getbits(uint8_t *base, uint8_t num, uint32_t *offset) {
1431
0
  uint32_t res = 0;
1432
0
  int32_t i = 0;
1433
0
  for(i=num-1; i>=0; i--) {
1434
0
    res |= janus_bitstream_getbit(base, (*offset)++) << i;
1435
0
  }
1436
0
  return res;
1437
0
}
1438
1439
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1440
size_t janus_gzip_compress(int compression, char *text, size_t tlen, char *compressed, size_t zlen) {
1441
  if(text == NULL || tlen < 1 || compressed == NULL || zlen < 1)
1442
    return 0;
1443
  if(compression < 0 || compression > 9) {
1444
    JANUS_LOG(LOG_WARN, "Invalid compression factor %d, falling back to default compression...\n", compression);
1445
    compression = Z_DEFAULT_COMPRESSION;
1446
  }
1447
1448
  /* Initialize the deflater, and clarify we need gzip */
1449
  z_stream zs = { 0 };
1450
  zs.zalloc = Z_NULL;
1451
  zs.zfree = Z_NULL;
1452
  zs.opaque = Z_NULL;
1453
  zs.next_in = (Bytef *)text;
1454
  zs.avail_in = (uInt)tlen;
1455
  zs.next_out = (Bytef *)compressed;
1456
  zs.avail_out = (uInt)zlen;
1457
  int res = deflateInit2(&zs, compression, Z_DEFLATED, 15 | 16, 8, Z_DEFAULT_STRATEGY);
1458
  if(res != Z_OK) {
1459
    JANUS_LOG(LOG_ERR, "deflateInit error: %d\n", res);
1460
    return 0;
1461
  }
1462
  /* Deflate the string */
1463
  res = deflate(&zs, Z_FINISH);
1464
  if(res != Z_STREAM_END) {
1465
    JANUS_LOG(LOG_ERR, "deflate error: %d\n", res);
1466
    return 0;
1467
  }
1468
  res = deflateEnd(&zs);
1469
  if(res != Z_OK) {
1470
    JANUS_LOG(LOG_ERR, "deflateEnd error: %d\n", res);
1471
    return 0;
1472
  }
1473
1474
  /* Done, return the size of the compressed data */
1475
  return zs.total_out;
1476
}
1477
#endif