Statistics
| Branch: | Revision:

janus-gateway / utils.c @ 887df302

History | View | Annotate | Download (15.4 KB)

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 <arpa/inet.h>
17
#include <sys/file.h>
18
#include <sys/types.h>
19
#include <sys/socket.h>
20
#include <unistd.h>
21

    
22
#include "utils.h"
23
#include "debug.h"
24

    
25
#if __MACH__
26
#include "mach_gettime.h"
27
#endif
28

    
29
gint64 janus_get_monotonic_time(void) {
30
        struct timespec ts;
31
        clock_gettime (CLOCK_MONOTONIC, &ts);
32
        return (ts.tv_sec*G_GINT64_CONSTANT(1000000)) + (ts.tv_nsec/G_GINT64_CONSTANT(1000));
33
}
34

    
35
gint64 janus_get_real_time(void) {
36
        struct timespec ts;
37
        clock_gettime (CLOCK_REALTIME, &ts);
38
        return (ts.tv_sec*G_GINT64_CONSTANT(1000000)) + (ts.tv_nsec/G_GINT64_CONSTANT(1000));
39
}
40

    
41
gboolean janus_is_true(const char *value) {
42
        return value && (!strcasecmp(value, "yes") || !strcasecmp(value, "true") || !strcasecmp(value, "1"));
43
}
44

    
45
gboolean janus_strcmp_const_time(const void *str1, const void *str2) {
46
        if(str1 == NULL || str2 == NULL)
47
                return FALSE;
48
        const unsigned char *string1 = (const unsigned char *)str1;
49
        const unsigned char *string2 = (const unsigned char *)str2;
50
        size_t maxlen = strlen((char *)string1);
51
        if(strlen((char *)string2) > maxlen)
52
                maxlen = strlen((char *)string2);
53
        unsigned char *buf1 = g_malloc0(maxlen+1);
54
        memset(buf1, 0, maxlen);
55
        memcpy(buf1, string1, strlen(str1));
56
        unsigned char *buf2 = g_malloc0(maxlen+1);
57
        memset(buf2, 0, maxlen);
58
        memcpy(buf2, string2, strlen(str2));
59
        unsigned char result = 0;
60
        size_t i = 0;
61
        for (i = 0; i < maxlen; i++) {
62
                result |= buf1[i] ^ buf2[i];
63
        }
64
        g_free(buf1);
65
        buf1 = NULL;
66
        g_free(buf2);
67
        buf2 = NULL;
68
        return result == 0;
69
}
70

    
71
void janus_flags_reset(janus_flags *flags) {
72
        if(flags != NULL)
73
                *flags = 0;
74
}
75

    
76
void janus_flags_set(janus_flags *flags, uint32_t flag) {
77
        if(flags != NULL) {
78
                *flags |= flag;
79
        }
80
}
81

    
82
void janus_flags_clear(janus_flags *flags, uint32_t flag) {
83
        if(flags != NULL) {
84
                *flags &= ~(flag);
85
        }
86
}
87

    
88
gboolean janus_flags_is_set(janus_flags *flags, uint32_t flag) {
89
        if(flags != NULL) {
90
                uint32_t bit = *flags & flag;
91
                return (bit != 0);
92
        }
93
        return FALSE;
94
}
95

    
96
/* Easy way to replace multiple occurrences of a string with another */
97
char *janus_string_replace(char *message, const char *old_string, const char *new_string)
98
{
99
        if(!message || !old_string || !new_string)
100
                return NULL;
101

    
102
        if(!strstr(message, old_string)) {        /* Nothing to be done (old_string is not there) */
103
                return message;
104
        }
105
        if(!strcmp(old_string, new_string)) {        /* Nothing to be done (old_string=new_string) */
106
                return message;
107
        }
108
        if(strlen(old_string) == strlen(new_string)) {        /* Just overwrite */
109
                char *outgoing = message;
110
                char *pos = strstr(outgoing, old_string), *tmp = NULL;
111
                int i = 0;
112
                while(pos) {
113
                        i++;
114
                        memcpy(pos, new_string, strlen(new_string));
115
                        pos += strlen(old_string);
116
                        tmp = strstr(pos, old_string);
117
                        pos = tmp;
118
                }
119
                return outgoing;
120
        } else {        /* We need to resize */
121
                char *outgoing = g_strdup(message);
122
                g_free(message);
123
                if(outgoing == NULL) {
124
                        return NULL;
125
                }
126
                int diff = strlen(new_string) - strlen(old_string);
127
                /* Count occurrences */
128
                int counter = 0;
129
                char *pos = strstr(outgoing, old_string), *tmp = NULL;
130
                while(pos) {
131
                        counter++;
132
                        pos += strlen(old_string);
133
                        tmp = strstr(pos, old_string);
134
                        pos = tmp;
135
                }
136
                uint16_t old_stringlen = strlen(outgoing)+1, new_stringlen = old_stringlen + diff*counter;
137
                if(diff > 0) {        /* Resize now */
138
                        tmp = g_realloc(outgoing, new_stringlen);
139
                        if(!tmp) {
140
                                g_free(outgoing);
141
                                return NULL;
142
                        }
143
                        outgoing = tmp;
144
                }
145
                /* Replace string */
146
                pos = strstr(outgoing, old_string);
147
                while(pos) {
148
                        if(diff > 0) {        /* Move to the right (new_string is larger than old_string) */
149
                                uint16_t len = strlen(pos)+1;
150
                                memmove(pos + diff, pos, len);
151
                                memcpy(pos, new_string, strlen(new_string));
152
                                pos += strlen(new_string);
153
                                tmp = strstr(pos, old_string);
154
                        } else {        /* Move to the left (new_string is smaller than old_string) */
155
                                uint16_t len = strlen(pos - diff)+1;
156
                                memmove(pos, pos - diff, len);
157
                                memcpy(pos, new_string, strlen(new_string));
158
                                pos += strlen(old_string);
159
                                tmp = strstr(pos, old_string);
160
                        }
161
                        pos = tmp;
162
                }
163
                if(diff < 0) {        /* We skipped the resize previously (shrinking memory) */
164
                        tmp = g_realloc(outgoing, new_stringlen);
165
                        if(!tmp) {
166
                                g_free(outgoing);
167
                                return NULL;
168
                        }
169
                        outgoing = tmp;
170
                }
171
                outgoing[strlen(outgoing)] = '\0';
172
                return outgoing;
173
        }
174
}
175

    
176
int janus_mkdir(const char *dir, mode_t mode) {
177
        char tmp[256];
178
        char *p = NULL;
179
        size_t len;
180

    
181
        int res = 0;
182
        g_snprintf(tmp, sizeof(tmp), "%s", dir);
183
        len = strlen(tmp);
184
        if(tmp[len - 1] == '/')
185
                tmp[len - 1] = 0;
186
        for(p = tmp + 1; *p; p++) {
187
                if(*p == '/') {
188
                        *p = 0;
189
                        res = mkdir(tmp, mode);
190
                        if(res != 0 && errno != EEXIST) {
191
                                JANUS_LOG(LOG_ERR, "Error creating folder %s\n", tmp);
192
                                return res;
193
                        }
194
                        *p = '/';
195
                }
196
        }
197
        res = mkdir(tmp, mode);
198
        if(res != 0 && errno != EEXIST)
199
                return res;
200
        return 0;
201
}
202

    
203
int janus_get_opus_pt(const char *sdp) {
204
        if(!sdp)
205
                return -1;
206
        if(!strstr(sdp, "m=audio") || (!strstr(sdp, "opus/48000") && !strstr(sdp, "OPUS/48000")))
207
                return -2;
208
        const char *line = strstr(sdp, "m=audio");
209
        while(line) {
210
                char *next = strchr(line, '\n');
211
                if(next) {
212
                        *next = '\0';
213
                        if(strstr(line, "a=rtpmap") && strstr(line, "opus/48000")) {
214
                                /* Gotcha! */
215
                                int pt = 0;
216
                                if(sscanf(line, "a=rtpmap:%d opus/48000/2", &pt) == 1) {
217
                                        *next = '\n';
218
                                        return pt;
219
                                }
220
                        } else if(strstr(line, "a=rtpmap") && strstr(line, "OPUS/48000")) {
221
                                /* Gotcha! */
222
                                int pt = 0;
223
                                if(sscanf(line, "a=rtpmap:%d OPUS/48000/2", &pt) == 1) {
224
                                        *next = '\n';
225
                                        return pt;
226
                                }
227
                        }
228
                        *next = '\n';
229
                }
230
                line = next ? (next+1) : NULL;
231
        }
232
        return -3;
233
}
234

    
235
int janus_get_isac32_pt(const char *sdp) {
236
        if(!sdp)
237
                return -1;
238
        if(!strstr(sdp, "m=audio") || (!strstr(sdp, "isac/32000") && !strstr(sdp, "ISAC/32000")))
239
                return -2;
240
        const char *line = strstr(sdp, "m=audio");
241
        while(line) {
242
                char *next = strchr(line, '\n');
243
                if(next) {
244
                        *next = '\0';
245
                        if(strstr(line, "a=rtpmap") && strstr(line, "isac/32000")) {
246
                                /* Gotcha! */
247
                                int pt = 0;
248
                                if(sscanf(line, "a=rtpmap:%d isac/32000", &pt) == 1) {
249
                                        *next = '\n';
250
                                        return pt;
251
                                }
252
                        } else if(strstr(line, "a=rtpmap") && strstr(line, "ISAC/32000")) {
253
                                /* Gotcha! */
254
                                int pt = 0;
255
                                if(sscanf(line, "a=rtpmap:%d ISAC/32000", &pt) == 1) {
256
                                        *next = '\n';
257
                                        return pt;
258
                                }
259
                        }
260
                        *next = '\n';
261
                }
262
                line = next ? (next+1) : NULL;
263
        }
264
        return -3;
265
}
266

    
267
int janus_get_isac16_pt(const char *sdp) {
268
        if(!sdp)
269
                return -1;
270
        if(!strstr(sdp, "m=audio") || (!strstr(sdp, "isac/16000") && !strstr(sdp, "ISAC/16000")))
271
                return -2;
272
        const char *line = strstr(sdp, "m=audio");
273
        while(line) {
274
                char *next = strchr(line, '\n');
275
                if(next) {
276
                        *next = '\0';
277
                        if(strstr(line, "a=rtpmap") && strstr(line, "isac/16000")) {
278
                                /* Gotcha! */
279
                                int pt = 0;
280
                                if(sscanf(line, "a=rtpmap:%d isac/16000", &pt) == 1) {
281
                                        *next = '\n';
282
                                        return pt;
283
                                }
284
                        } else if(strstr(line, "a=rtpmap") && strstr(line, "ISAC/16000")) {
285
                                /* Gotcha! */
286
                                int pt = 0;
287
                                if(sscanf(line, "a=rtpmap:%d ISAC/16000", &pt) == 1) {
288
                                        *next = '\n';
289
                                        return pt;
290
                                }
291
                        }
292
                        *next = '\n';
293
                }
294
                line = next ? (next+1) : NULL;
295
        }
296
        return -3;
297
}
298

    
299
int janus_get_pcmu_pt(const char *sdp) {
300
        if(!sdp)
301
                return -1;
302
        if(!strstr(sdp, "m=audio") || (!strstr(sdp, "pcmu/8000") && !strstr(sdp, "PCMU/8000")))
303
                return -2;
304
        const char *line = strstr(sdp, "m=audio");
305
        while(line) {
306
                char *next = strchr(line, '\n');
307
                if(next) {
308
                        *next = '\0';
309
                        if(strstr(line, "a=rtpmap") && strstr(line, "pcmu/8000")) {
310
                                /* Gotcha! */
311
                                int pt = 0;
312
                                if(sscanf(line, "a=rtpmap:%d pcmu/8000", &pt) == 1) {
313
                                        *next = '\n';
314
                                        return pt;
315
                                }
316
                        } else if(strstr(line, "a=rtpmap") && strstr(line, "PCMU/8000")) {
317
                                /* Gotcha! */
318
                                int pt = 0;
319
                                if(sscanf(line, "a=rtpmap:%d PCMU/8000", &pt) == 1) {
320
                                        *next = '\n';
321
                                        return pt;
322
                                }
323
                        }
324
                        *next = '\n';
325
                }
326
                line = next ? (next+1) : NULL;
327
        }
328
        return -3;
329
}
330

    
331
int janus_get_pcma_pt(const char *sdp) {
332
        if(!sdp)
333
                return -1;
334
        if(!strstr(sdp, "m=audio") || (!strstr(sdp, "pcma/8000") && !strstr(sdp, "PCMA/8000")))
335
                return -2;
336
        const char *line = strstr(sdp, "m=audio");
337
        while(line) {
338
                char *next = strchr(line, '\n');
339
                if(next) {
340
                        *next = '\0';
341
                        if(strstr(line, "a=rtpmap") && strstr(line, "pcma/8000")) {
342
                                /* Gotcha! */
343
                                int pt = 0;
344
                                if(sscanf(line, "a=rtpmap:%d pcma/8000", &pt) == 1) {
345
                                        *next = '\n';
346
                                        return pt;
347
                                }
348
                        } else if(strstr(line, "a=rtpmap") && strstr(line, "PCMA/8000")) {
349
                                /* Gotcha! */
350
                                int pt = 0;
351
                                if(sscanf(line, "a=rtpmap:%d PCMA/8000", &pt) == 1) {
352
                                        *next = '\n';
353
                                        return pt;
354
                                }
355
                        }
356
                        *next = '\n';
357
                }
358
                line = next ? (next+1) : NULL;
359
        }
360
        return -3;
361
}
362

    
363
int janus_get_vp8_pt(const char *sdp) {
364
        if(!sdp)
365
                return -1;
366
        if(!strstr(sdp, "m=video") || (!strstr(sdp, "VP8/90000") && !strstr(sdp, "vp8/90000")))
367
                return -2;
368
        const char *line = strstr(sdp, "m=video");
369
        while(line) {
370
                char *next = strchr(line, '\n');
371
                if(next) {
372
                        *next = '\0';
373
                        if(strstr(line, "a=rtpmap") && strstr(line, "VP8/90000")) {
374
                                /* Gotcha! */
375
                                int pt = 0;
376
                                if(sscanf(line, "a=rtpmap:%d VP8/90000", &pt) == 1) {
377
                                        *next = '\n';
378
                                        return pt;
379
                                }
380
                        } else if(strstr(line, "a=rtpmap") && strstr(line, "vp8/90000")) {
381
                                /* Gotcha! */
382
                                int pt = 0;
383
                                if(sscanf(line, "a=rtpmap:%d vp8/90000", &pt) == 1) {
384
                                        *next = '\n';
385
                                        return pt;
386
                                }
387
                        }
388
                        *next = '\n';
389
                }
390
                line = next ? (next+1) : NULL;
391
        }
392
        return -3;
393
}
394

    
395
int janus_get_vp9_pt(const char *sdp) {
396
        if(!sdp)
397
                return -1;
398
        if(!strstr(sdp, "m=video") || (!strstr(sdp, "VP9/90000") && !strstr(sdp, "vp9/90000")))
399
                return -2;
400
        const char *line = strstr(sdp, "m=video");
401
        while(line) {
402
                char *next = strchr(line, '\n');
403
                if(next) {
404
                        *next = '\0';
405
                        if(strstr(line, "a=rtpmap") && strstr(line, "VP9/90000")) {
406
                                /* Gotcha! */
407
                                int pt = 0;
408
                                if(sscanf(line, "a=rtpmap:%d VP9/90000", &pt) == 1) {
409
                                        *next = '\n';
410
                                        return pt;
411
                                }
412
                        } else if(strstr(line, "a=rtpmap") && strstr(line, "vp9/90000")) {
413
                                /* Gotcha! */
414
                                int pt = 0;
415
                                if(sscanf(line, "a=rtpmap:%d vp9/90000", &pt) == 1) {
416
                                        *next = '\n';
417
                                        return pt;
418
                                }
419
                        }
420
                        *next = '\n';
421
                }
422
                line = next ? (next+1) : NULL;
423
        }
424
        return -3;
425
}
426

    
427
int janus_get_h264_pt(const char *sdp) {
428
        if(!sdp)
429
                return -1;
430
        if(!strstr(sdp, "m=video") || (!strstr(sdp, "h264/90000") && !strstr(sdp, "H264/90000")))
431
                return -2;
432
        const char *line = strstr(sdp, "m=video");
433
        while(line) {
434
                char *next = strchr(line, '\n');
435
                if(next) {
436
                        *next = '\0';
437
                        if(strstr(line, "a=rtpmap") && strstr(line, "H264/90000")) {
438
                                /* Gotcha! */
439
                                int pt = 0;
440
                                if(sscanf(line, "a=rtpmap:%d H264/90000", &pt) == 1) {
441
                                        *next = '\n';
442
                                        return pt;
443
                                }
444
                        } else if(strstr(line, "a=rtpmap") && strstr(line, "h264/90000")) {
445
                                /* Gotcha! */
446
                                int pt = 0;
447
                                if(sscanf(line, "a=rtpmap:%d h264/90000", &pt) == 1) {
448
                                        *next = '\n';
449
                                        return pt;
450
                                }
451
                        }
452
                        *next = '\n';
453
                }
454
                line = next ? (next+1) : NULL;
455
        }
456
        return -3;
457
}
458

    
459
gboolean janus_is_ip_valid(const char *ip, int *family) {
460
        if(ip == NULL)
461
                return FALSE;
462

    
463
        struct sockaddr_in addr4;
464
        struct sockaddr_in6 addr6;
465

    
466
        if(inet_pton(AF_INET, ip, &addr4) > 0) {
467
                if(family != NULL)
468
                        *family = AF_INET;
469
                return TRUE;
470
        } else if(inet_pton(AF_INET6, ip, &addr6) > 0) {
471
                if(family != NULL)
472
                        *family = AF_INET6;
473
                return TRUE;
474
        } else {
475
                return FALSE;
476
        }
477
}
478

    
479
char *janus_address_to_ip(struct sockaddr *address) {
480
        if(address == NULL)
481
                return NULL;
482
        char addr_buf[INET6_ADDRSTRLEN];
483
        const char *addr = NULL;
484
        struct sockaddr_in *sin = NULL;
485
        struct sockaddr_in6 *sin6 = NULL;
486

    
487
        switch(address->sa_family) {
488
                case AF_INET:
489
                        sin = (struct sockaddr_in *)address;
490
                        addr = inet_ntop(AF_INET, &sin->sin_addr, addr_buf, INET_ADDRSTRLEN);
491
                        break;
492
                case AF_INET6:
493
                        sin6 = (struct sockaddr_in6 *)address;
494
                        addr = inet_ntop(AF_INET6, &sin6->sin6_addr, addr_buf, INET6_ADDRSTRLEN);
495
                        break;
496
                default:
497
                        /* Unknown family */
498
                        break;
499
        }
500
        return addr ? g_strdup(addr) : NULL;
501
}
502

    
503
/* PID file management */
504
static char *pidfile = NULL;
505
static int pidfd = -1;
506
static FILE *pidf = NULL;
507
int janus_pidfile_create(const char *file) {
508
        if(file == NULL)
509
                return 0;
510
        pidfile = g_strdup(file);
511
        /* Try creating a PID file (or opening an existing one) */
512
        pidfd = open(pidfile, O_RDWR|O_CREAT, 0644);
513
        if(pidfd < 0) {
514
                JANUS_LOG(LOG_FATAL, "Error opening/creating PID file %s, does Janus have enough permissions?\n", pidfile);
515
                return -1;
516
        }
517
        pidf = fdopen(pidfd, "r+");
518
        if(pidf == NULL) {
519
                JANUS_LOG(LOG_FATAL, "Error opening/creating PID file %s, does Janus have enough permissions?\n", pidfile);
520
                close(pidfd);
521
                return -1;
522
        }
523
        /* Try locking the PID file */
524
        int pid = 0;
525
        if(flock(pidfd, LOCK_EX|LOCK_NB) < 0) {
526
                if(fscanf(pidf, "%d", &pid) == 1) {
527
                        JANUS_LOG(LOG_FATAL, "Error locking PID file (lock held by PID %d?)\n", pid);
528
                } else {
529
                        JANUS_LOG(LOG_FATAL, "Error locking PID file (lock held by unknown PID?)\n");
530
                }
531
                fclose(pidf);
532
                return -1;
533
        }
534
        /* Write the PID */
535
        pid = getpid();
536
        if(fprintf(pidf, "%d\n", pid) < 0) {
537
                JANUS_LOG(LOG_FATAL, "Error writing PID in file, error %d (%s)\n", errno, strerror(errno));
538
                fclose(pidf);
539
                return -1;
540
        }
541
        fflush(pidf);
542
        /* We're done */
543
        return 0;
544
}
545

    
546
int janus_pidfile_remove(void) {
547
        if(pidfile == NULL || pidfd < 0 || pidf == NULL)
548
                return 0;
549
        /* Unlock the PID file and remove it */
550
        if(flock(pidfd, LOCK_UN) < 0) {
551
                JANUS_LOG(LOG_FATAL, "Error unlocking PID file\n");
552
                fclose(pidf);
553
                close(pidfd);
554
                return -1;
555
        }
556
        fclose(pidf);
557
        unlink(pidfile);
558
        g_free(pidfile);
559
        return 0;
560
}
561

    
562
void janus_get_json_type_name(int jtype, unsigned int flags, char *type_name) {
563
        /* Longest possible combination is "a non-empty boolean" plus one for null char */
564
        gsize req_size = 20;
565
        /* Don't allow for both "positive" and "non-empty" because that needlessly increases the size. */
566
        if((flags & JANUS_JSON_PARAM_POSITIVE) != 0) {
567
                g_strlcpy(type_name, "a positive ", req_size);
568
        }
569
        else if((flags & JANUS_JSON_PARAM_NONEMPTY) != 0) {
570
                g_strlcpy(type_name, "a non-empty ", req_size);
571
        }
572
        else if(jtype == JSON_INTEGER || jtype == JSON_ARRAY || jtype == JSON_OBJECT) {
573
                g_strlcpy(type_name, "an ", req_size);
574
        }
575
        else {
576
                g_strlcpy(type_name, "a ", req_size);
577
        }
578
        switch(jtype) {
579
                case JSON_TRUE:
580
                        g_strlcat(type_name, "boolean", req_size);
581
                        break;
582
                case JSON_INTEGER:
583
                        g_strlcat(type_name, "integer", req_size);
584
                        break;
585
                case JSON_REAL:
586
                        g_strlcat(type_name, "real", req_size);
587
                        break;
588
                case JSON_STRING:
589
                        g_strlcat(type_name, "string", req_size);
590
                        break;
591
                case JSON_ARRAY:
592
                        g_strlcat(type_name, "array", req_size);
593
                        break;
594
                case JSON_OBJECT:
595
                        g_strlcat(type_name, "object", req_size);
596
                        break;
597
                default:
598
                        break;
599
        }
600
}
601

    
602
gboolean janus_json_is_valid(json_t *val, json_type jtype, unsigned int flags) {
603
        gboolean is_valid = (json_typeof(val) == jtype || (jtype == JSON_TRUE && json_typeof(val) == JSON_FALSE));
604
        if(!is_valid)
605
                return FALSE;
606
        if((flags & JANUS_JSON_PARAM_POSITIVE) != 0) {
607
                switch(jtype) {
608
                        case JSON_INTEGER:
609
                                is_valid = (json_integer_value(val) >= 0);
610
                                break;
611
                        case JSON_REAL:
612
                                is_valid = (json_real_value(val) >= 0);
613
                                break;
614
                        default:
615
                                break;
616
                }
617
        }
618
        else if((flags & JANUS_JSON_PARAM_NONEMPTY) != 0) {
619
                switch(jtype) {
620
                        case JSON_STRING:
621
                                is_valid = (json_string_length(val) > 0);
622
                                break;
623
                        case JSON_ARRAY:
624
                                is_valid = (json_array_size(val) > 0);
625
                                break;
626
                        default:
627
                                break;
628
                }
629
        }
630
        return is_valid;
631
}