Statistics
| Branch: | Revision:

janus-gateway / utils.c @ c07b32bd

History | View | Annotate | Download (9.06 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_vp8_pt(const char *sdp) {
236
        if(!sdp)
237
                return -1;
238
        if(!strstr(sdp, "m=video") || (!strstr(sdp, "VP8/90000") && !strstr(sdp, "vp8/90000")))
239
                return -2;
240
        const char *line = strstr(sdp, "m=video");
241
        while(line) {
242
                char *next = strchr(line, '\n');
243
                if(next) {
244
                        *next = '\0';
245
                        if(strstr(line, "a=rtpmap") && strstr(line, "VP8/90000")) {
246
                                /* Gotcha! */
247
                                int pt = 0;
248
                                if(sscanf(line, "a=rtpmap:%d VP8/90000", &pt) == 1) {
249
                                        *next = '\n';
250
                                        return pt;
251
                                }
252
                        } else if(strstr(line, "a=rtpmap") && strstr(line, "vp8/90000")) {
253
                                /* Gotcha! */
254
                                int pt = 0;
255
                                if(sscanf(line, "a=rtpmap:%d vp8/90000", &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
gboolean janus_is_ip_valid(const char *ip, int *family) {
268
        if(ip == NULL)
269
                return FALSE;
270

    
271
        struct sockaddr_in addr4;
272
        struct sockaddr_in6 addr6;
273

    
274
        if(inet_pton(AF_INET, ip, &addr4) > 0) {
275
                if(family != NULL)
276
                        *family = AF_INET;
277
                return TRUE;
278
        } else if(inet_pton(AF_INET6, ip, &addr6) > 0) {
279
                if(family != NULL)
280
                        *family = AF_INET6;
281
                return TRUE;
282
        } else {
283
                return FALSE;
284
        }
285
}
286

    
287
char *janus_address_to_ip(struct sockaddr *address) {
288
        if(address == NULL)
289
                return NULL;
290
        char addr_buf[INET6_ADDRSTRLEN];
291
        const char *addr = NULL;
292
        struct sockaddr_in *sin = NULL;
293
        struct sockaddr_in6 *sin6 = NULL;
294

    
295
        switch(address->sa_family) {
296
                case AF_INET:
297
                        sin = (struct sockaddr_in *)address;
298
                        addr = inet_ntop(AF_INET, &sin->sin_addr, addr_buf, INET_ADDRSTRLEN);
299
                        break;
300
                case AF_INET6:
301
                        sin6 = (struct sockaddr_in6 *)address;
302
                        addr = inet_ntop(AF_INET6, &sin6->sin6_addr, addr_buf, INET6_ADDRSTRLEN);
303
                        break;
304
                default:
305
                        /* Unknown family */
306
                        break;
307
        }
308
        return addr ? g_strdup(addr) : NULL;
309
}
310

    
311
/* PID file management */
312
static char *pidfile = NULL;
313
static int pidfd = -1;
314
static FILE *pidf = NULL;
315
int janus_pidfile_create(const char *file) {
316
        if(file == NULL)
317
                return 0;
318
        pidfile = g_strdup(file);
319
        /* Try creating a PID file (or opening an existing one) */
320
        pidfd = open(pidfile, O_RDWR|O_CREAT, 0644);
321
        if(pidfd < 0) {
322
                JANUS_LOG(LOG_FATAL, "Error opening/creating PID file %s, does Janus have enough permissions?\n", pidfile);
323
                return -1;
324
        }
325
        pidf = fdopen(pidfd, "r+");
326
        if(pidf == NULL) {
327
                JANUS_LOG(LOG_FATAL, "Error opening/creating PID file %s, does Janus have enough permissions?\n", pidfile);
328
                close(pidfd);
329
                return -1;
330
        }
331
        /* Try locking the PID file */
332
        int pid = 0;
333
        if(flock(pidfd, LOCK_EX|LOCK_NB) < 0) {
334
                if(fscanf(pidf, "%d", &pid) == 1) {
335
                        JANUS_LOG(LOG_FATAL, "Error locking PID file (lock held by PID %d?)\n", pid);
336
                } else {
337
                        JANUS_LOG(LOG_FATAL, "Error locking PID file (lock held by unknown PID?)\n");
338
                }
339
                fclose(pidf);
340
                return -1;
341
        }
342
        /* Write the PID */
343
        pid = getpid();
344
        if(fprintf(pidf, "%d\n", pid) < 0) {
345
                JANUS_LOG(LOG_FATAL, "Error writing PID in file, error %d (%s)\n", errno, strerror(errno));
346
                fclose(pidf);
347
                return -1;
348
        }
349
        fflush(pidf);
350
        /* We're done */
351
        return 0;
352
}
353

    
354
int janus_pidfile_remove(void) {
355
        if(pidfile == NULL || pidfd < 0 || pidf == NULL)
356
                return 0;
357
        /* Unlock the PID file and remove it */
358
        if(flock(pidfd, LOCK_UN) < 0) {
359
                JANUS_LOG(LOG_FATAL, "Error unlocking PID file\n");
360
                fclose(pidf);
361
                close(pidfd);
362
                return -1;
363
        }
364
        fclose(pidf);
365
        unlink(pidfile);
366
        g_free(pidfile);
367
        return 0;
368
}