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