1 /*
2 * Copyright (C) 2014-2020 Catalin Toda <catalinii@yahoo.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17 * USA
18 *
19 */
20 #define _GNU_SOURCE
21 #define _FILE_OFFSET_BITS 64
22 #define UTILS_C
23
24 #include "utils.h"
25 #include "dvb.h"
26 #include "minisatip.h"
27 #include "pmt.h"
28 #include "socketworks.h"
29 #include <arpa/inet.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <math.h>
34 #include <net/if.h>
35 #include <netdb.h>
36 #include <netinet/in.h>
37 #include <signal.h>
38 #include <stdarg.h>
39 #include <stdint.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <sys/ioctl.h>
44 #include <sys/mman.h>
45 #include <sys/socket.h>
46 #include <sys/stat.h>
47 #include <sys/time.h>
48 #include <sys/types.h>
49 #include <syslog.h>
50 #include <time.h>
51 #include <unistd.h>
52
53 #if !defined(__mips__) && !defined(NO_BACKTRACE)
54 #include <execinfo.h>
55 #endif
56
57 #define DEFAULT_LOG LOG_UTILS
58
59 #define MAX_DATA 1500 // 16384
60 #define UNUSED_KEY 0
61
62 char pn[256];
63
64 Shttp_client *httpc[MAX_HTTPC];
65
66 SMutex utils_mutex;
67
68 // Hash function from
69 // https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key
hash_func(uint32_t x)70 static inline uint32_t hash_func(uint32_t x) {
71 x = ((x >> 16) ^ x) * 0x45d9f3b;
72 x = ((x >> 16) ^ x) * 0x45d9f3b;
73 x = (x >> 16) ^ x;
74 return x;
75 }
76
get_index_hash(SHashTable * hash,uint32_t key)77 int get_index_hash(SHashTable *hash, uint32_t key) {
78 int pos;
79 int start_pos = hash_func(key) % hash->size;
80
81 pos = start_pos;
82 do {
83 if (HASH_ITEM_ENABLED(hash->items[pos]) && hash->items[pos].key == key)
84 return pos;
85 if (!HASH_ITEM_ENABLED(hash->items[pos]))
86 break;
87 pos = (pos + 1) % hash->size;
88 } while (pos != start_pos);
89
90 return -1;
91 }
92
create_hash_table(SHashTable * hash,int no)93 int create_hash_table(SHashTable *hash, int no) {
94 if (hash->init == 1)
95 return 0;
96 memset(hash, 0, sizeof(SHashTable));
97 hash->init = 1;
98 hash->items = malloc(no * sizeof(SHashItem));
99 if (!hash->items) {
100 LOG_AND_RETURN(1, "Could not allocate Hash Items %d", no);
101 }
102 memset(hash->items, 0, no * sizeof(SHashItem));
103 hash->size = no;
104 mutex_init(&hash->mutex);
105 return 0;
106 }
107
getItem(SHashTable * hash,uint32_t key)108 void *getItem(SHashTable *hash, uint32_t key) {
109 int i, locking = 0;
110 void *result = NULL;
111 if (hash->mutex.state > 0) {
112 locking = 1;
113 mutex_lock(&hash->mutex);
114 }
115
116 i = get_index_hash(hash, key);
117 result = i >= 0 ? hash->items[i].data : NULL;
118 if (locking)
119 mutex_unlock(&hash->mutex);
120 return result;
121 }
122
getItemLen(SHashTable * hash,uint32_t key)123 int getItemLen(SHashTable *hash, uint32_t key) {
124 int i, locking = 0;
125 int result = 0;
126 if (hash->mutex.state > 0) {
127 locking = 1;
128 mutex_lock(&hash->mutex);
129 }
130
131 i = get_index_hash(hash, key);
132 result = i >= 0 ? hash->items[i].len : 0;
133 if (locking)
134 mutex_unlock(&hash->mutex);
135 return result;
136 }
137
getItemSize(SHashTable * hash,uint32_t key)138 int getItemSize(SHashTable *hash, uint32_t key) {
139 int i, locking = 0;
140 int result = 0;
141 if (hash->mutex.state > 0) {
142 locking = 1;
143 mutex_lock(&hash->mutex);
144 }
145
146 i = get_index_hash(hash, key);
147 result = i >= 0 ? hash->items[i].max_size : 0;
148 if (locking)
149 mutex_unlock(&hash->mutex);
150 return result;
151 }
152
153 // copy = 1 - do allocation and copy content
154 // is_alloc = 1 - memory allocated
setItemSize(SHashItem * s,uint32_t max_size,int copy)155 int setItemSize(SHashItem *s, uint32_t max_size, int copy) {
156 if (s->max_size >= max_size && s->is_alloc == copy)
157 return 0;
158 if (s->is_alloc)
159 free1(s->data);
160 s->is_alloc = 0;
161 if (copy) {
162 s->data = malloc1(max_size + 10);
163 if (!s->data)
164 LOG_AND_RETURN(-1, "%s: Could not resize from %d to %d",
165 __FUNCTION__, s->max_size, max_size);
166 s->is_alloc = 1;
167 }
168 s->max_size = max_size;
169
170 return 0;
171 }
172
_setItem(SHashTable * hash,uint32_t key,void * data,int len,int copy)173 int _setItem(SHashTable *hash, uint32_t key, void *data, int len, int copy) {
174 mutex_lock(&hash->mutex);
175 SHashItem *s = NULL;
176 int i = get_index_hash(hash, key);
177 if (i >= 0)
178 s = hash->items + i;
179 if (!s) {
180 // Add new element
181 int start_pos = hash_func(key) % hash->size;
182 int pos;
183 pos = start_pos;
184 do {
185 if (!HASH_ITEM_ENABLED(hash->items[pos])) {
186 s = hash->items + pos;
187 break;
188 }
189 hash->conflicts++;
190 pos = (pos + 1) % hash->size;
191 } while (pos != start_pos);
192 }
193
194 if (!s) {
195 mutex_unlock(&hash->mutex);
196 LOG_AND_RETURN(-1, "%s failed for key %jx", __FUNCTION__, key);
197 }
198
199 if (setItemSize(s, len, copy)) {
200 mutex_unlock(&hash->mutex);
201 return 1;
202 }
203
204 s->key = key;
205 s->len = len;
206 if (copy)
207 memcpy(s->data, data, len);
208 else
209 s->data = data;
210
211 if (hash->resize) {
212 mutex_unlock(&hash->mutex);
213 return 0;
214 }
215 if (++hash->len > hash->size / 2) {
216 int new_size = hash->size * 2;
217 SHashTable ht;
218 ht.init = 0;
219
220 // Do not fail, hash table full will fail before this code.
221 if (create_hash_table(&ht, new_size))
222 LOG_AND_RETURN(0, "Resizing hash_table at %p from %d to %d", hash,
223 hash->size, new_size);
224 hash->resize = 1;
225 ht.resize = 1;
226 copy_hash_table(hash, &ht);
227 free_hash(hash);
228 memcpy(hash, &ht, sizeof(SHashTable));
229 hash->resize = 0;
230 }
231 mutex_unlock(&hash->mutex);
232 return 0;
233 }
234
copy_hash_table(SHashTable * s,SHashTable * d)235 void copy_hash_table(SHashTable *s, SHashTable *d) {
236 int i;
237 for (i = 0; i < s->size; i++)
238 if (HASH_ITEM_ENABLED(s->items[i])) {
239 _setItem(d, s->items[i].key, s->items[i].data, s->items[i].len, 0);
240 int di = get_index_hash(d, s->items[i].key);
241 if (di == -1)
242 continue;
243 memcpy(d->items + di, s->items + i, sizeof(SHashItem));
244 memset(s->items + i, 0, sizeof(SHashItem));
245 }
246 }
247
delItem(SHashTable * hash,uint32_t key)248 int delItem(SHashTable *hash, uint32_t key) {
249 mutex_lock(&hash->mutex);
250
251 int empty = get_index_hash(hash, key);
252 if (empty == -1) {
253 mutex_unlock(&hash->mutex);
254 return 0;
255 }
256 int pos;
257 for (pos = (empty + 1) % hash->size; HASH_ITEM_ENABLED(hash->items[pos]);
258 pos = (pos + 1) % hash->size) {
259 int k = hash_func(hash->items[pos].key) % hash->size;
260 if ((pos > empty && (k <= empty || k > pos)) ||
261 (pos < empty && (k <= empty && k > pos))) {
262 SHashItem it;
263 memcpy(&it, hash->items + empty, sizeof(hash->items[0]));
264 memcpy(hash->items + empty, hash->items + pos,
265 sizeof(hash->items[0]));
266 memcpy(hash->items + pos, &it, sizeof(hash->items[0]));
267 empty = pos;
268 }
269 }
270 SHashItem *s = hash->items + empty;
271 hash->len--;
272 s->len = 0;
273 s->key = UNUSED_KEY;
274 LOGM("Deleted Item Pos %d", empty);
275 mutex_unlock(&hash->mutex);
276 return 0;
277 }
278
delItemP(SHashTable * hash,void * p)279 int delItemP(SHashTable *hash, void *p) {
280 int i;
281 for (i = 0; i < hash->size; i++)
282 if (HASH_ITEM_ENABLED(hash->items[i]) && hash->items[i].data == p)
283 delItem(hash, hash->items[i].key);
284 return 0;
285 }
286
free_hash(SHashTable * hash)287 void free_hash(SHashTable *hash) {
288 int i;
289 if (hash->init != 1)
290 return;
291
292 mutex_lock(&hash->mutex);
293 for (i = 0; i < hash->size; i++)
294 if (hash->items[i].is_alloc) {
295 free(hash->items[i].data);
296 }
297 void *items = hash->items;
298 free(items);
299 hash->items = NULL;
300 hash->size = 0;
301 //mutex_unlock(&hash->mutex);
302 mutex_destroy(&hash->mutex); // unlock and destroy mutex
303 memset(hash, 0, sizeof(SHashTable));
304 return;
305 }
306
split(char ** rv,char * s,int lrv,char sep)307 int split(char **rv, char *s, int lrv, char sep) {
308 int i = 0, j = 0;
309
310 if (!s)
311 return 0;
312 for (i = 0; s[i] && s[i] == sep && s[i] < 32; i++)
313 ;
314
315 rv[j++] = &s[i];
316 // LOG("start %d %d\n",i,j);
317 while (j < lrv - 1) {
318 if (s[i] == 0 || s[i + 1] == 0)
319 break;
320 if (s[i] == sep || s[i] < 33) {
321 s[i] = 0;
322 if (s[i + 1] != sep && s[i + 1] > 32)
323 rv[j++] = &s[i + 1];
324 } else if (s[i] < 14)
325 s[i] = 0;
326 // LOG("i=%d j=%d %d %c \n",i,j,s[i],s[i]);
327 i++;
328 }
329 if (s[i] == sep)
330 s[i] = 0;
331 rv[j] = NULL;
332 return j;
333 }
334
strip(char * s)335 char *strip(char *s) // strip spaces from the front of a string
336 {
337 if (s < (char *)1000)
338 return NULL;
339
340 while (*s && *s == ' ')
341 s++;
342 return s;
343 }
344
map_intd(char * s,char ** v,int dv)345 int map_intd(char *s, char **v, int dv) {
346 int i, n = dv;
347
348 if (s == NULL) {
349 LOG_AND_RETURN(dv, "map_intd: s=>NULL, v=%p, %s %s", v,
350 v ? v[0] : "NULL", v ? v[1] : "NULL");
351 }
352
353 s = strip(s);
354
355 if (!*s)
356 LOG_AND_RETURN(dv, "map_intd: s is empty");
357
358 if (v == NULL) {
359 if (s[0] != '+' && s[0] != '-' && (s[0] < '0' || s[0] > '9'))
360 LOG_AND_RETURN(dv, "map_intd: s not a number: %s, v=%p, %s %s", s,
361 v, v ? v[0] : "NULL", v ? v[1] : "NULL");
362 return atoi(s);
363 }
364 for (i = 0; v[i]; i++)
365 if (!strncasecmp(s, v[i], strlen(v[i])))
366 n = i;
367 return n;
368 }
369
check_strs(char * s,char ** v,int dv)370 int check_strs(char *s, char **v, int dv) {
371 int i, n = dv;
372
373 if (s == NULL) {
374 LOG_AND_RETURN(dv, "check_strs: s=>NULL, v=%p, %s %s", v,
375 v ? v[0] : "NULL", v ? v[1] : "NULL");
376 }
377 if (v == NULL) {
378 LOG_AND_RETURN(dv, "check_strs: v is empty");
379 }
380
381 s = strip(s);
382
383 if (!*s)
384 LOG_AND_RETURN(dv, "check_strs: s is empty");
385
386 for (i = 0; v[i]; i++)
387 if (strncasecmp(s, v[i], strlen(s)) == 0)
388 n = i;
389 return n;
390 }
391
header_parameter(char ** arg,int i)392 char *header_parameter(char **arg,
393 int i) // get the value of a header parameter
394 {
395 int len = strlen(arg[i]);
396 char *result;
397
398 if (arg[i][len - 1] == ':')
399 return arg[i + 1];
400
401 result = strchr(arg[i], ':');
402 if (result)
403 return result + 1;
404
405 if (strcmp(arg[i + 1], ":") == 0)
406 return arg[i + 2];
407 return NULL;
408 }
409
map_float(char * s,int mul)410 int map_float(char *s, int mul) {
411 float f;
412 int r;
413
414 if (s == NULL)
415 LOG_AND_RETURN(0, "map_float: s=>NULL, mul=%d", mul);
416 if (s[0] != '+' && s[0] != '-' && (s[0] < '0' || s[0] > '9'))
417 LOG_AND_RETURN(0, "map_float: s not a number: %s, mul=%d", s, mul);
418
419 f = atof(s);
420 r = (int)(f * mul);
421 // LOG("atof returned %.1f, mul = %d, result=%d",f,mul,r);
422 return r;
423 }
424
map_int(char * s,char ** v)425 int map_int(char *s, char **v) { return map_intd(s, v, 0); }
426
end_of_header(char * buf)427 int end_of_header(char *buf) {
428 return buf[0] == 0x0d && buf[1] == 0x0a && buf[2] == 0x0d && buf[3] == 0x0a;
429 }
430
431 void posix_signal_handler(int sig, siginfo_t *siginfo, ucontext_t *ctx);
set_signal_handler(char * argv0)432 void set_signal_handler(char *argv0) {
433 struct sigaction sig_action = {};
434 sig_action.sa_sigaction =
435 (void (*)(int, siginfo_t *, void *))posix_signal_handler;
436 sigemptyset(&sig_action.sa_mask);
437
438 memset(pn, 0, sizeof(pn));
439 strncpy(pn, argv0, sizeof(pn) - 1);
440
441 sig_action.sa_flags = SA_SIGINFO | SA_ONSTACK;
442
443 #ifndef __mips__
444 if (sigaction(SIGBUS, &sig_action, NULL) != 0) {
445 LOG("Could not set signal SIGBUS");
446 }
447 if (sigaction(SIGSEGV, &sig_action, NULL) != 0) {
448 LOG("Could not set signal SIGSEGV");
449 }
450 if (sigaction(SIGABRT, &sig_action, NULL) != 0) {
451 LOG("Could not set signal SIGABRT");
452 }
453 if (sigaction(SIGFPE, &sig_action, NULL) != 0) {
454 LOG("Could not set signal SIGFPE");
455 }
456 if (sigaction(SIGILL, &sig_action, NULL) != 0) {
457 LOG("Could not set signal SIGILL");
458 }
459 #endif
460 if (sigaction(SIGINT, &sig_action, NULL) != 0) {
461 LOG("Could not set signal SIGINT");
462 }
463
464 if (sigaction(SIGTERM, &sig_action, NULL) != 0) {
465 LOG("Could not set signal SIGTERM");
466 }
467 if (signal(SIGHUP, SIG_IGN) != 0) {
468 LOG("Could not ignore signal SIGHUP");
469 }
470 if (signal(SIGPIPE, SIG_IGN) != 0) {
471 LOG("Could not ignore signal SIGPIPE");
472 }
473 }
474
addr2line(char const * const program_name,void const * const addr)475 int addr2line(char const *const program_name, void const *const addr) {
476 char addr2line_cmd[512] = {0};
477
478 sprintf(addr2line_cmd, "addr2line -f -p -e %.256s %p", program_name, addr);
479 return system(addr2line_cmd);
480 }
481
print_trace(void)482 void print_trace(void) {
483 void *array[10];
484 size_t size;
485 size_t i;
486 #if !defined(NO_BACKTRACE)
487
488 size = backtrace(array, 10);
489
490 printf("Obtained %zu stack frames.\n", size);
491
492 for (i = 0; i < size; i++) {
493 printf("%p : ", array[i]);
494 if (addr2line(pn, array[i]))
495 printf("\n");
496 }
497 #else
498 printf(" No backtrace defined\n");
499 #endif
500 }
501
502 extern int run_loop;
503
posix_signal_handler(int sig,siginfo_t * siginfo,ucontext_t * ctx)504 void posix_signal_handler(int sig, siginfo_t *siginfo, ucontext_t *ctx) {
505 uint64_t sp = 0, ip = 0;
506
507 if (sig == SIGINT || sig == SIGTERM) {
508 run_loop = 0;
509 return;
510 }
511 #ifdef __mips__
512 sp = ctx->uc_mcontext.gregs[29];
513 ip = ctx->uc_mcontext.pc;
514 #endif
515 #ifdef __sh__
516 sp = ctx->uc_mcontext.pr;
517 ip = ctx->uc_mcontext.pc;
518 #endif
519 printf("RECEIVED SIGNAL %d - SP=%lX IP=%lX\n", sig, (long unsigned int)sp,
520 (long unsigned int)ip);
521
522 print_trace();
523 exit(1);
524 }
525
526 int /* Returns 0 on success, -1 on error */
becomeDaemon()527 becomeDaemon() {
528 int maxfd, fd, fdi, fdo, pid;
529 __attribute__((unused)) int rv;
530 struct stat sb;
531 FILE *f;
532 char path[255];
533 char buf[255];
534 char log_file[sizeof(buf)];
535
536 memset(path, 0, sizeof(path));
537 if ((f = fopen(pid_file, "rt"))) {
538 char tmp_buf[10];
539 memset(tmp_buf, 0, sizeof(tmp_buf));
540 fgets(tmp_buf, sizeof(tmp_buf) - 1, f);
541 pid = atoi(tmp_buf);
542 fclose(f);
543 snprintf(buf, sizeof(buf) - 1, "/proc/%d/exe", pid);
544
545 if (0 < readlink(buf, path, sizeof(path) - 1) &&
546 0 == strcmp(pn, path)) {
547 LOG("Found %s running with pid %d, killing....", app_name, pid);
548 kill(pid, SIGINT);
549 usleep(500);
550 }
551 }
552
553 LOG("running %s in background and logging to %s", app_name, opts.log_file);
554
555 switch (fork()) { /* Become background process */
556 case -1:
557 return -1;
558 case 0:
559 break; /* Child falls through... */
560 default:
561 _exit(0); /* while parent terminates */
562 }
563
564 if (setsid() == -1) /* Become leader of new session */
565 return -1;
566
567 switch ((pid = fork())) { /* Ensure we are not session leader */
568 case -1:
569 return -1;
570 case 0:
571 break;
572 default:
573 _exit(0);
574 }
575
576 umask(0); /* Clear file mode creation mask */
577
578 maxfd = sysconf(_SC_OPEN_MAX);
579 if (maxfd == -1) /* Limit is indeterminate... */
580 maxfd = 1024; /* so take a guess */
581
582 for (fd = 0; fd < maxfd; fd++)
583 close(fd);
584
585 close(STDIN_FILENO); /* Reopen standard fd's to /dev/null */
586 // chdir ("/tmp"); /* Change to root
587 // directory */
588
589 fdi = open("/dev/null", O_RDWR);
590 memset(buf, 0, sizeof(buf));
591 snprintf(buf, sizeof(buf) - 1, "%s", opts.log_file);
592 SAFE_STRCPY(log_file, buf);
593 if (fdi != STDIN_FILENO) /* 'fdi' should be 0 */
594 {
595 if (fdi >= 0)
596 close(fdi);
597 return -1;
598 }
599 if (stat(buf, &sb) == -1)
600 fdo = open(log_file, O_RDWR | O_CREAT, 0666);
601 else
602 fdo = open(log_file, O_RDWR | O_APPEND);
603 if (fdo != STDOUT_FILENO) /* 'fd' should be 1 */
604 {
605 if (fdo >= 0)
606 close(fdo);
607 return -1;
608 }
609 if (dup2(STDOUT_FILENO, STDERR_FILENO) != STDERR_FILENO)
610 return -1;
611
612 return 0;
613 }
614
mymalloc(int a,char * f,int l)615 void *mymalloc(int a, char *f, int l) {
616 void *x = malloc(a);
617 if (x)
618 memset(x, 0, a);
619 LOGM("%s:%d allocation_wrapper malloc allocated %d bytes at %p", f, l, a,
620 x);
621 if (!x)
622 LOG0("Failed allocating %d bytes of memory", a)
623 return x;
624 }
625
myrealloc(void * p,int a,char * f,int l)626 void *myrealloc(void *p, int a, char *f, int l) {
627 void *x = realloc(p, a);
628 if (x)
629 memset(x, 0, a);
630 LOGM("%s:%d allocation_wrapper realloc allocated %d bytes from %p -> %p", f,
631 l, a, p, x);
632 if (!x) {
633 LOG0("Failed allocating %d bytes of memory", a)
634 if (!strcmp(f, "socketworks.c"))
635 LOG0("Try to decrease the parameters -b and/or -B")
636 }
637 return x;
638 }
639
myfree(void * x,char * f,int l)640 void myfree(void *x, char *f, int l) {
641 LOGM("%s:%d allocation_wrapper free called with argument %p", f, l, x);
642 free(x);
643 }
644
645 pthread_mutex_t log_mutex;
646
get_current_timestamp(void)647 char *get_current_timestamp(void) {
648 static char date_str[200];
649 time_t date;
650 struct tm *t;
651 char *day[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
652 char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
653 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
654 time(&date);
655 t = gmtime(&date);
656 if (!t)
657 return "Fri, Sat Jan 1 00:00:20 2000 GMT";
658 snprintf(date_str, sizeof(date_str), "%s, %s %d %02d:%02d:%02d %d GMT",
659 day[t->tm_wday], month[t->tm_mon], t->tm_mday, t->tm_hour,
660 t->tm_min, t->tm_sec, t->tm_year + 1900);
661 return date_str;
662 }
663
get_current_timestamp_log(void)664 char *get_current_timestamp_log(void) {
665 static char date_str[200];
666 struct timeval tv;
667 struct tm *t;
668
669 if (gettimeofday(&tv, NULL))
670 return "01/01 00:00:20";
671 t = localtime(&tv.tv_sec);
672 if (!t)
673 return "01/01 00:00:20";
674 snprintf(date_str, sizeof(date_str), "%02d/%02d %02d:%02d:%02d.%03d",
675 t->tm_mday, t->tm_mon + 1, t->tm_hour, t->tm_min, t->tm_sec,
676 (int)(tv.tv_usec / 1000));
677 return date_str;
678 }
679
_log(const char * file,int line,const char * fmt,...)680 void _log(const char *file, int line, const char *fmt, ...) {
681 va_list arg;
682 int len = 0, len1 = 0, both = 0;
683 static int idx, times;
684 char stid[50];
685 static char output[2][2000]; // prints just the first 2000 bytes from
686 // the message
687
688 /* Check if the message should be logged */
689 opts.last_log = (char *)fmt;
690
691 stid[0] = 0;
692 if (!opts.no_threads) {
693 pthread_mutex_lock(&log_mutex);
694 snprintf(stid, sizeof(stid) - 2, " %s", thread_name);
695 stid[sizeof(stid) - 1] = 0;
696 }
697
698 if (!fmt) {
699 printf("NULL format at %s:%d !!!!!", file, line);
700 if (!opts.no_threads)
701 pthread_mutex_unlock(&log_mutex);
702 return;
703 }
704 idx = 1 - idx;
705 if (idx > 1)
706 idx = 1;
707 else if (idx < 0)
708 idx = 0;
709 if (opts.file_line && !opts.slog)
710 len1 = snprintf(output[idx], sizeof(output[0]),
711 "[%s%s] %s:%d: ", get_current_timestamp_log(), stid,
712 file, line);
713 else if (!opts.slog)
714 len1 = snprintf(output[idx], sizeof(output[0]),
715 "[%s%s]: ", get_current_timestamp_log(), stid);
716 else if (opts.file_line) {
717 len1 = 0;
718 output[idx][0] = '\0';
719 }
720 /* Write the error message */
721 len = len1 =
722 len1 < (int)sizeof(output[0]) ? len1 : (int)sizeof(output[0]) - 1;
723 both = 0;
724 va_start(arg, fmt);
725 len += vsnprintf(output[idx] + len, sizeof(output[0]) - len, fmt, arg);
726 va_end(arg);
727
728 if (strcmp(output[idx] + len1, output[1 - idx] + len1) == 0)
729 times++;
730 else {
731 if (times > 0) {
732 both = 1;
733 snprintf(output[1 - idx], sizeof(output[0]),
734 "Message repeated %d times", times);
735 }
736 times = 0;
737 }
738
739 if (both) {
740 if (opts.slog)
741 syslog(LOG_NOTICE, "%s", output[1 - idx]);
742 else
743 puts(output[1 - idx]);
744 both = 0;
745 }
746 if (times == 0) {
747 if (opts.slog)
748 syslog(LOG_NOTICE, "%s", output[idx]);
749 else
750 puts(output[idx]);
751 }
752 fflush(stdout);
753 if (!opts.no_threads)
754 pthread_mutex_unlock(&log_mutex);
755 }
756
endswith(char * src,char * with)757 int endswith(char *src, char *with) {
758 int lw = strlen(with);
759 if (strlen(src) > lw && !strcmp(src + strlen(src) - lw, with))
760 return 1;
761 return 0;
762 }
763
764 #define VAR_LENGTH 20
765 extern _symbols adapters_sym[];
766 extern _symbols minisatip_sym[];
767 extern _symbols stream_sym[];
768 #ifndef DISABLE_DVBAPI
769 extern _symbols dvbapi_sym[];
770 #endif
771 #ifndef DISABLE_SATIPCLIENT
772 extern _symbols satipc_sym[];
773 #endif
774 #ifdef AXE
775 extern _symbols axe_sym[];
776 #endif
777 #ifndef DISABLE_PMT
778 extern _symbols pmt_sym[];
779 #endif
780
781 _symbols *sym[] = {adapters_sym, stream_sym, minisatip_sym,
782 #ifndef DISABLE_DVBAPI
783 dvbapi_sym,
784 #endif
785 #ifndef DISABLE_SATIPCLIENT
786 satipc_sym,
787 #endif
788 #ifndef DISABLE_PMT
789 pmt_sym,
790 #endif
791 #ifdef AXE
792 axe_sym,
793 #endif
794 NULL};
795
snprintf_pointer(char * dest,int max_len,int type,void * p,float multiplier)796 int snprintf_pointer(char *dest, int max_len, int type, void *p,
797 float multiplier) {
798 int nb;
799 switch (type & 0xF) {
800 case VAR_UINT8:
801 nb = snprintf(dest, max_len, "%d",
802 (int)((*(unsigned char *)p) * multiplier));
803 break;
804 case VAR_INT8:
805 nb = snprintf(dest, max_len, "%d", (int)((*(char *)p) * multiplier));
806 break;
807 case VAR_UINT16:
808 nb =
809 snprintf(dest, max_len, "%d", (int)((*(uint16_t *)p) * multiplier));
810 break;
811 case VAR_INT16:
812 nb = snprintf(dest, max_len, "%d", (int)((*(int16_t *)p) * multiplier));
813 break;
814 case VAR_INT:
815 nb = snprintf(dest, max_len, "%d", (int)((*(int *)p) * multiplier));
816 break;
817
818 case VAR_INT64:
819 nb = snprintf(dest, max_len, "%jd",
820 (int64_t)((*(int64_t *)p) * multiplier));
821 break;
822
823 case VAR_STRING:
824 nb = snprintf(dest, max_len, "%s", (char *)p);
825 break;
826
827 case VAR_PSTRING:
828 nb = snprintf(dest, max_len, "%s", (*(char **)p) ? (*(char **)p) : "");
829 break;
830
831 case VAR_FLOAT:
832 nb =
833 snprintf(dest, max_len, "%f", (double)((*(float *)p) * multiplier));
834 break;
835
836 case VAR_HEX:
837 nb = snprintf(dest, max_len, "0x%x", (int)((*(int *)p) * multiplier));
838 break;
839
840 default:
841 nb = 0;
842 break;
843 }
844 if (nb > max_len) /* see man 'snprintf' */
845 nb = max_len;
846 return nb;
847 }
848
escape_json_string(char * dest,int dl,char * src,int sl)849 int escape_json_string(char *dest, int dl, char *src, int sl) {
850 int i, j = 1;
851 if (dl < 2)
852 LOG_AND_RETURN(0, "%s: dl %d < 2 for %s", __FUNCTION__, dl, src);
853
854 dest[0] = '"';
855 for (i = 0; (i < sl) && (j < dl - 1); i++) {
856 unsigned char c = (unsigned char)src[i];
857 if (c >= 32)
858 dest[j++] = src[i];
859 else
860 strlcatf(dest, sl, j, "%%x%02X", c);
861 }
862 dest[j++] = '"';
863 dest[j] = 0;
864 return j;
865 }
866
867 char zero[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
868
get_json_state(char * buf,int len)869 int get_json_state(char *buf, int len) {
870 int ptr = 0, first = 1, i, j, off, string;
871 _symbols *p;
872 char escape[200]; // string variable max len
873
874 memset(escape, 0, sizeof(escape));
875 strlcatf(buf, len, ptr, "{\n");
876 for (i = 0; sym[i] != NULL; i++) {
877 for (j = 0; sym[i][j].name; j++) {
878 p = sym[i] + j;
879 strlcatf(buf, len, ptr, first ? "\"%s\":" : ",\n\"%s\":", p->name);
880 string = 0;
881 switch (p->type) {
882 case VAR_STRING:
883 case VAR_PSTRING:
884 case VAR_HEX:
885 case VAR_AARRAY_STRING:
886 case VAR_AARRAY_PSTRING:
887 string = 1;
888 break;
889 }
890 if (p->type < VAR_ARRAY) {
891 if (string) {
892 int len2 =
893 snprintf_pointer(escape, sizeof(escape) - 1, p->type,
894 p->addr, p->multiplier);
895 ptr +=
896 escape_json_string(buf + ptr, len - ptr, escape, len2);
897 } else
898 ptr += snprintf_pointer(buf + ptr, len - ptr, p->type,
899 p->addr, p->multiplier);
900 } else if ((p->type & 0xF0) == VAR_ARRAY) {
901 strlcatf(buf, len, ptr, "[");
902 for (off = 0; off < p->len; off++) {
903 if (off > 0)
904 strlcatf(buf, len, ptr, ",");
905 if (string) {
906 int len2 = snprintf_pointer(
907 escape, sizeof(escape) - 1, p->type,
908 ((char *)p->addr) + off + p->skip, p->multiplier);
909 ptr += escape_json_string(buf + ptr, len - ptr, escape,
910 len2);
911 } else
912 ptr += snprintf_pointer(
913 buf + ptr, len - ptr, p->type,
914 ((char *)p->addr) + off + p->skip, p->multiplier);
915 }
916 strlcatf(buf, len, ptr, "]");
917 } else if ((sym[i][j].type & 0xF0) == VAR_AARRAY) {
918 strlcatf(buf, len, ptr, "[");
919 for (off = 0; off < p->len; off++) {
920 char **p1 = (char **)p->addr;
921 if (off > 0)
922 strlcatf(buf, len, ptr, ",");
923 if (string) {
924 int len2 = snprintf_pointer(
925 escape, sizeof(escape) - 1, p->type,
926 p1[off] ? p1[off] + p->skip : zero, p->multiplier);
927 ptr += escape_json_string(buf + ptr, len - ptr, escape,
928 len2);
929 } else
930 ptr += snprintf_pointer(
931 buf + ptr, len - ptr, p->type,
932 p1[off] ? p1[off] + p->skip : zero, p->multiplier);
933 }
934 strlcatf(buf, len, ptr, "]");
935 } else if (sym[i][j].type == VAR_FUNCTION_INT) {
936 get_data_int funi = (get_data_int)p->addr;
937 strlcatf(buf, len, ptr, "[");
938 for (off = 0; off < p->len; off++) {
939 int storage = funi(off);
940 if (off > 0)
941 strlcatf(buf, len, ptr, ",");
942 ptr += snprintf_pointer(buf + ptr, len - ptr, p->type,
943 &storage, 1);
944 }
945 strlcatf(buf, len, ptr, "]");
946 } else if (sym[i][j].type == VAR_FUNCTION_INT64) {
947 get_data_int64 fun64 = (get_data_int64)p->addr;
948 strlcatf(buf, len, ptr, "[");
949 for (off = 0; off < p->len; off++) {
950 int64_t storage = fun64(off);
951 if (off > 0)
952 strlcatf(buf, len, ptr, ",");
953 ptr += snprintf_pointer(buf + ptr, len - ptr, p->type,
954 &storage, 1);
955 }
956 strlcatf(buf, len, ptr, "]");
957 } else if (sym[i][j].type == VAR_FUNCTION_STRING) {
958 get_data_string funs = (get_data_string)p->addr;
959 strlcatf(buf, len, ptr, "[");
960 for (off = 0; off < p->len; off++) {
961 memset(escape, 0, sizeof(escape));
962 funs(off, escape, sizeof(escape) - 1);
963 if (off > 0)
964 strlcatf(buf, len, ptr, ",");
965 ptr += escape_json_string(buf + ptr, len - ptr, escape,
966 strlen(escape));
967 }
968 strlcatf(buf, len, ptr, "]");
969 // LOG("func_str -> %s", buf);
970 } else {
971 strlcatf(buf, len, ptr, "\"\"");
972 }
973 first = 0;
974 }
975 }
976 strlcatf(buf, len, ptr, "\n}\n");
977 return ptr;
978 }
979
980 extern SMutex bw_mutex;
981
get_json_bandwidth(char * buf,int len)982 int get_json_bandwidth(char *buf, int len) {
983 int ptr = 0;
984 mutex_init(&bw_mutex);
985 mutex_lock(&bw_mutex);
986 strlcatf(buf, len, ptr, "\
987 {\n\
988 \"bw\":%jd,\n\
989 \"tbw\":%jd,\n\
990 \"reads\":%u,\n\
991 \"writes\":%u,\n\
992 \"fwrites\":%u,\n\
993 \"ns_read\":%jd,\n\
994 \"tt\":%jd\n\
995 }",
996 c_bw, c_tbw, c_reads, c_writes, c_failed_writes, c_ns_read, c_tt);
997 mutex_unlock(&bw_mutex);
998 return ptr;
999 }
1000
get_var_address(char * var,float * multiplier,int * type,void * storage,int ls)1001 void *get_var_address(char *var, float *multiplier, int *type, void *storage,
1002 int ls) {
1003 int i, j, off;
1004 *multiplier = 0;
1005 for (i = 0; sym[i] != NULL; i++)
1006 for (j = 0; sym[i][j].name; j++)
1007 if (!strncmp(sym[i][j].name, var, strlen(sym[i][j].name))) {
1008 *type = sym[i][j].type;
1009 if (sym[i][j].type < VAR_ARRAY) {
1010 *multiplier = sym[i][j].multiplier;
1011 return sym[i][j].addr;
1012 } else if ((sym[i][j].type & 0xF0) == VAR_ARRAY) {
1013 off = map_intd(var + strlen(sym[i][j].name), NULL, 0);
1014 if (off >= 0 && off < sym[i][j].len) {
1015 *multiplier = sym[i][j].multiplier;
1016 return (((char *)sym[i][j].addr) +
1017 off * sym[i][j].skip);
1018 }
1019 } else if ((sym[i][j].type & 0xF0) == VAR_AARRAY) {
1020 off = map_intd(var + strlen(sym[i][j].name), NULL, 0);
1021 if (off >= 0 && off < sym[i][j].len) {
1022 char **p1 = (char **)sym[i][j].addr;
1023 char *p = p1[off];
1024
1025 if (!p) {
1026 p = zero;
1027 } else
1028 p += sym[i][j].skip;
1029 *multiplier = sym[i][j].multiplier;
1030 return p;
1031 }
1032 } else if (sym[i][j].type == VAR_FUNCTION_INT) {
1033 off = map_intd(var + strlen(sym[i][j].name), NULL, 0);
1034 get_data_int funi = (get_data_int)sym[i][j].addr;
1035 *(int *)storage = funi(off);
1036 *multiplier = 1;
1037 return storage;
1038 } else if (sym[i][j].type == VAR_FUNCTION_INT64) {
1039 off = map_intd(var + strlen(sym[i][j].name), NULL, 0);
1040 get_data_int64 fun64 = (get_data_int64)sym[i][j].addr;
1041 *(int64_t *)storage = fun64(off);
1042 *multiplier = 1;
1043 return storage;
1044 } else if (sym[i][j].type == VAR_FUNCTION_STRING) {
1045 off = map_intd(var + strlen(sym[i][j].name), NULL, 0);
1046 get_data_string funs = (get_data_string)sym[i][j].addr;
1047 funs(off, storage, ls);
1048 return storage;
1049 }
1050 }
1051 return NULL;
1052 }
1053
var_eval(char * orig,int len,char * dest,int max_len)1054 int var_eval(char *orig, int len, char *dest, int max_len) {
1055 char var[VAR_LENGTH + 1];
1056 char storage[64 * 5]; // variable max len
1057 float multiplier;
1058 int type = 0;
1059 void *p;
1060 int nb = 0;
1061 memset(var, 0, sizeof(var));
1062 strncpy(var, orig + 1, len - 1);
1063 p = get_var_address(var, &multiplier, &type, storage, sizeof(storage));
1064 if (p)
1065 nb = snprintf_pointer(dest, max_len, type, p, multiplier);
1066 return nb;
1067 }
1068
is_var(char * s)1069 int is_var(char *s) {
1070 int i = 0;
1071 if (*s != '$')
1072 return 0;
1073 while (s[++i] != 0) {
1074 if (s[i] == '$')
1075 return i;
1076 if (i >= VAR_LENGTH)
1077 return 0;
1078 }
1079 return 0;
1080 }
1081
1082 // replace $VAR$ with it's value and write the output to the socket
process_file(void * sock,char * s,int len,char * ctype)1083 void process_file(void *sock, char *s, int len, char *ctype) {
1084 char outp[8300];
1085 int i, io = 0, lv, le, respond = 1;
1086 sockets *so = (sockets *)sock;
1087 __attribute__((unused)) int rv;
1088 LOG("processing_file %p len %d:", s, len);
1089 for (i = 0; i < len; i++) {
1090 lv = 0;
1091 if (s[i] == '$')
1092 lv = is_var(s + i);
1093 if (lv == 0) {
1094 outp[io++] = s[i];
1095 } else {
1096 le = var_eval(s + i, lv, outp + io, sizeof(outp) - io - 10);
1097 io += le;
1098 i += lv;
1099 }
1100 if (io > sizeof(outp) - 100) {
1101 if (respond) {
1102 http_response(
1103 so, 200, ctype, "", 0,
1104 0); // sending back the response without Content-Length
1105 respond = 0;
1106 }
1107 rv = sockets_write(so->id, outp, io);
1108 outp[io] = 0;
1109 // LOG("%s", outp);
1110 io = 0;
1111 }
1112 }
1113 outp[io] = 0;
1114 if (respond)
1115 http_response(so, 200, ctype, outp, 0,
1116 0); // sending back the response with Content-Length
1117 // if output < 8192
1118 else {
1119 strcpy(outp + io, "\r\n\r\n");
1120 rv = sockets_write(so->id, outp, io + 4);
1121 outp[io] = 0;
1122 DEBUGM("%s", outp);
1123 }
1124 }
1125
readfile(char * fn,char * ctype,int * len)1126 char *readfile(char *fn, char *ctype, int *len) {
1127 char ffn[256];
1128 char *mem;
1129 struct stat sb;
1130 int fd, nl = 0;
1131 *len = 0;
1132
1133 if (strstr(fn, ".."))
1134 return 0;
1135 snprintf(ffn, sizeof(ffn), "%s/%s", opts.document_root, fn);
1136 ffn[sizeof(ffn) - 1] = 0;
1137 #ifdef O_LARGEFILE
1138 if ((fd = open(ffn, O_RDONLY | O_LARGEFILE)) < 0)
1139 #else
1140 if ((fd = open(ffn, O_RDONLY)) < 0)
1141 #endif
1142 LOG_AND_RETURN(NULL, "Could not open file %s", ffn);
1143
1144 if ((fstat(fd, &sb) == -1) || !S_ISREG(sb.st_mode)) {
1145 LOG("readfile: %s is not a file", ffn);
1146 close(fd);
1147 return NULL;
1148 }
1149 nl = sb.st_size;
1150 mem = mmap(0, nl, PROT_READ, MAP_SHARED, fd, 0);
1151 if (mem == MAP_FAILED) {
1152 close(fd);
1153 LOG_AND_RETURN(NULL, "mmap failed for file %s", ffn);
1154 }
1155 close(fd);
1156 LOG("opened %s fd %d at %p - %d bytes", ffn, fd, mem, nl);
1157
1158 *len = nl;
1159 if (ctype) {
1160 ctype[0] = 0;
1161 if (endswith(fn, "png"))
1162 strcpy(ctype, "Cache-Control: max-age=3600\r\nContent-type: "
1163 "image/png\r\nConnection: close");
1164 else if (endswith(fn, "jpg") || endswith(fn, "jpeg"))
1165 strcpy(ctype, "Cache-Control: max-age=3600\r\nContent-type: "
1166 "image/jpeg\r\nConnection: close");
1167 else if (endswith(fn, "css"))
1168 strcpy(ctype, "Cache-Control: max-age=3600\r\nContent-type: "
1169 "text/css\r\nConnection: close");
1170 else if (endswith(fn, "js"))
1171 strcpy(ctype, "Cache-Control: max-age=3600\r\nContent-type: "
1172 "text/javascript\r\nConnection: close");
1173 else if (endswith(fn, "htm") || endswith(fn, "html"))
1174 strcpy(ctype, "Cache-Control: max-age=3600\r\nContent-type: "
1175 "text/html\r\nConnection: close");
1176 else if (endswith(fn, "xml"))
1177 strcpy(ctype, "Cache-Control: no-cache\r\nContent-type: text/xml");
1178 else if (endswith(fn, "2.json")) // debug
1179 strcpy(ctype, "Content-type: application/json");
1180 else if (endswith(fn, "json"))
1181 strcpy(ctype, "Cache-Control: no-cache\r\nContent-type: "
1182 "application/json");
1183 else if (endswith(fn, "m3u"))
1184 strcpy(ctype,
1185 "Cache-Control: no-cache\r\nContent-type: video/x-mpegurl");
1186 else
1187 strcpy(ctype, "Cache-Control: no-cache\r\nContent-type: "
1188 "application/octet-stream");
1189 }
1190 return mem;
1191 }
1192
closefile(char * mem,int len)1193 int closefile(char *mem, int len) { return munmap((void *)mem, len); }
1194
1195 #undef DEFAULT_LOG
1196 #define DEFAULT_LOG LOG_LOCK
1197
mutex_init(SMutex * mutex)1198 int mutex_init(SMutex *mutex) {
1199 int rv;
1200 pthread_mutexattr_t attr;
1201
1202 if (opts.no_threads)
1203 return 0;
1204 if (mutex->enabled)
1205 return 1;
1206
1207 pthread_mutexattr_init(&attr);
1208 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1209
1210 if ((rv = pthread_mutex_init(&mutex->mtx, &attr))) {
1211 LOG("mutex init %p failed with error %d %s", mutex, rv, strerror(rv));
1212 return rv;
1213 }
1214
1215 mutex->create_time = getTick();
1216 mutex->enabled = 1;
1217 mutex->state = 0;
1218 LOG("Mutex init OK %p", mutex);
1219 return 0;
1220 }
1221
1222 __thread SMutex *mutexes[100];
1223 __thread int imtx = 0;
1224
mutex_lock1(char * FILE,int line,SMutex * mutex)1225 int mutex_lock1(char *FILE, int line, SMutex *mutex) {
1226 int rv;
1227 int64_t start_lock = 0;
1228 if (opts.no_threads)
1229 return 0;
1230
1231 if (!mutex || !mutex->enabled) {
1232 LOGM("%s:%d Mutex not enabled %p", FILE, line, mutex);
1233 return 1;
1234 }
1235 if (mutex->enabled && mutex->state && tid != mutex->tid) {
1236 LOGM("%s:%d Locking mutex %p already locked at %s:%d tid %lx", FILE,
1237 line, mutex, mutex->file, mutex->line, mutex->tid);
1238 start_lock = getTick();
1239 } else
1240 LOGM("%s:%d Locking mutex %p", FILE, line, mutex);
1241 rv = pthread_mutex_lock(&mutex->mtx);
1242 if (!mutex->enabled && rv == 0) {
1243 pthread_mutex_unlock(&mutex->mtx);
1244 LOG("Mutex %p destroyed meanwhile", mutex);
1245 return 1;
1246 }
1247 if (rv != 0) {
1248 LOG("Mutex Lock %p failed", mutex);
1249 return rv;
1250 }
1251 if (start_lock > 0) {
1252 uint64_t ms = getTick() - start_lock;
1253 char *prev_file = "none";
1254 int prev_line = -1;
1255 if (mutex && mutex->enabled && mutex->file) {
1256 prev_file = mutex->file;
1257 prev_line = mutex->line;
1258 }
1259 LOGL(ms > 1000 ? 1 : DEFAULT_LOG,
1260 "%s:%d Locked %p after %ld ms, previously locked at: %s, line "
1261 "%d",
1262 FILE, line, mutex, ms, prev_file, prev_line);
1263 }
1264 mutex->file = FILE;
1265 mutex->line = line;
1266 mutex->state++;
1267 mutex->tid = tid;
1268 mutex->lock_time = getTick();
1269
1270 mutexes[imtx++] = mutex;
1271 return 0;
1272 }
mutex_unlock1(char * FILE,int line,SMutex * mutex)1273 int mutex_unlock1(char *FILE, int line, SMutex *mutex) {
1274 int rv = -1;
1275 if (opts.no_threads)
1276 return 0;
1277
1278 if (!mutex || mutex->enabled) {
1279 LOGM("%s:%d Unlocking mutex %p", FILE, line, mutex);
1280 if (mutex) {
1281 mutex->state--;
1282 rv = pthread_mutex_unlock(&mutex->mtx);
1283 }
1284 } else
1285 LOG("%s:%d Unlock disabled mutex %p", FILE, line, mutex);
1286
1287 if (rv != 0 && rv != 1 && rv != -1) {
1288 LOGM("mutex_unlock failed at %s:%d: %d %s", FILE, line, rv,
1289 strerror(rv));
1290 }
1291 if (rv == 0 || rv == 1)
1292 rv = 0;
1293
1294 if (rv != -1 && imtx > 0) {
1295 if ((imtx >= 1) && mutexes[imtx - 1] == mutex)
1296 imtx--;
1297 else if ((imtx >= 2) && mutexes[imtx - 2] == mutex) {
1298 mutexes[imtx - 2] = mutexes[imtx - 1];
1299 imtx--;
1300 } else
1301 LOG("mutex_leak: Expected %p got %p", mutex, mutexes[imtx - 1]);
1302 }
1303 return rv;
1304 }
1305
mutex_destroy(SMutex * mutex)1306 int mutex_destroy(SMutex *mutex) {
1307 int rv;
1308 if (opts.no_threads)
1309 return 0;
1310 if (!mutex || !mutex->enabled) {
1311 LOG("destroy disabled mutex %p", mutex);
1312
1313 return 1;
1314 }
1315 mutex->enabled = 0;
1316
1317 if ((imtx >= 1) && mutexes[imtx - 1] == mutex)
1318 imtx--;
1319 else if ((imtx >= 2) && mutexes[imtx - 2] == mutex) {
1320 mutexes[imtx - 2] = mutexes[imtx - 1];
1321 imtx--;
1322 }
1323
1324 if ((rv = pthread_mutex_unlock(&mutex->mtx)) != 1 && rv != 0)
1325 LOG("%s: pthread_mutex_unlock 1 failed for %p with error %d %s",
1326 __FUNCTION__, mutex, rv, strerror(rv));
1327
1328 // coverity[use : FALSE]
1329 if ((rv = pthread_mutex_unlock(&mutex->mtx)) != 1 && rv != 0)
1330 LOG("%s: pthread_mutex_unlock 2 failed for %p with error %d %s",
1331 __FUNCTION__, mutex, rv, strerror(rv));
1332
1333 LOG("Destroying mutex %p", mutex);
1334 return 0;
1335 }
1336
clean_mutexes()1337 void clean_mutexes() {
1338 int i;
1339 if (!imtx)
1340 return;
1341 if (opts.no_threads)
1342 return;
1343 // LOG("mutex_leak: unlock %d mutexes", imtx);
1344 for (i = imtx - 1; i >= 0; i--) {
1345 if (!mutexes[i] || !mutexes[i]->enabled)
1346 continue;
1347 LOG("mutex_leak: %s unlocking mutex %p from %s:%d", __FUNCTION__,
1348 mutexes[i], mutexes[i]->file, mutexes[i]->line);
1349 mutex_unlock(mutexes[i]);
1350 }
1351 imtx = 0;
1352 }
1353 #undef DEFAULT_LOG
1354 #define DEFAULT_LOG LOG_UTILS
1355
get_tid()1356 pthread_t get_tid() { return pthread_self(); }
1357
start_new_thread(char * name)1358 pthread_t start_new_thread(char *name) {
1359 pthread_t tid;
1360 int rv;
1361 if (opts.no_threads)
1362 return get_tid();
1363
1364 if ((rv = pthread_create(&tid, NULL, &select_and_execute, name))) {
1365 LOG("Failed to create thread: %s, error %d %s", name, rv, strerror(rv));
1366 return get_tid();
1367 }
1368 return tid;
1369 }
1370
set_thread_prio(pthread_t tid,int prio)1371 void set_thread_prio(pthread_t tid, int prio) {
1372 int rv;
1373 struct sched_param param;
1374 memset(¶m, 0, sizeof(struct sched_param));
1375 param.sched_priority = prio;
1376 if ((rv = pthread_setschedparam(pthread_self(), SCHED_RR, ¶m)))
1377 LOG("pthread_setschedparam failed with error %d", rv);
1378 return;
1379 }
1380
1381 struct struct_array {
1382 char enabled;
1383 SMutex mutex;
1384 };
1385
1386 // leaves sa[i]->mutex locked
add_new_lock(void ** arr,int count,int size,SMutex * mutex)1387 int add_new_lock(void **arr, int count, int size, SMutex *mutex) {
1388 int i;
1389 struct struct_array **sa = (struct struct_array **)arr;
1390 mutex_init(mutex);
1391 mutex_lock(mutex);
1392 for (i = 0; i < count; i++)
1393 if (!sa[i] || !sa[i]->enabled) {
1394 if (!sa[i]) {
1395 sa[i] = malloc1(size);
1396 if (!sa[i]) {
1397 mutex_unlock(mutex);
1398 LOG("Could not allocate memory for %p index %d", arr, i);
1399 return -1;
1400 }
1401 memset(sa[i], 0, size);
1402 }
1403 mutex_init(&sa[i]->mutex);
1404 // coverity[use : FALSE]
1405 mutex_lock(&sa[i]->mutex);
1406 sa[i]->enabled = 1;
1407 mutex_unlock(mutex);
1408 return i;
1409 }
1410 mutex_unlock(mutex);
1411 return -1;
1412 }
1413
1414 int64_t init_tick;
1415
getTick()1416 int64_t getTick() { // ms
1417 int64_t theTick;
1418 struct timespec ts;
1419 clock_gettime(CLOCK_MONOTONIC, &ts);
1420 theTick = ts.tv_nsec / 1000000;
1421 theTick += ts.tv_sec * 1000;
1422 if (init_tick == 0)
1423 init_tick = theTick;
1424 return theTick - init_tick;
1425 }
1426
getTickUs()1427 int64_t getTickUs() {
1428 int64_t utime;
1429 struct timespec ts;
1430 clock_gettime(CLOCK_MONOTONIC, &ts);
1431 utime = ((int64_t)ts.tv_sec) * 1000000 + ts.tv_nsec / 1000;
1432 return utime;
1433 }
1434
1435 pthread_t join_th[100];
1436 int join_pos = 0;
1437 SMutex join_lock;
1438
add_join_thread(pthread_t t)1439 void add_join_thread(pthread_t t) {
1440 mutex_init(&join_lock);
1441 mutex_lock(&join_lock);
1442 join_th[join_pos++] = t;
1443 LOG("%s: pthread %lx", __FUNCTION__, t);
1444 mutex_unlock(&join_lock);
1445 }
1446
join_thread()1447 void join_thread() {
1448 int i, rv;
1449 if (!join_lock.enabled)
1450 return;
1451 mutex_lock(&join_lock);
1452 // LOG("starting %s", __FUNCTION__);
1453 for (i = 0; i < join_pos; i++) {
1454 LOGM("Joining thread %lx", join_th[i]);
1455 if ((rv = pthread_join(join_th[i], NULL)))
1456 LOG("Join thread failed for %lx with %d %s", join_th[i], rv,
1457 strerror(rv));
1458 }
1459 join_pos = 0;
1460 mutex_unlock(&join_lock);
1461 }
1462
init_utils(char * arg0)1463 int init_utils(char *arg0) {
1464 set_signal_handler(arg0);
1465 return 0;
1466 }
1467
_hexdump(char * desc,void * addr,int len)1468 void _hexdump(char *desc, void *addr, int len) {
1469 int i, pos = 0, bl = (len * 6 < 100) ? 100 : len * 6;
1470 char buff[17];
1471 char buf[bl];
1472 unsigned char *pc = (unsigned char *)addr;
1473
1474 if (len == 0) {
1475 LOG("%s: ZERO LENGTH", desc);
1476 return;
1477 }
1478 if (len < 0) {
1479 LOG("%s: NEGATIVE LENGTH: %i\n", desc, len);
1480 return;
1481 }
1482 memset(buf, 0, bl - 1);
1483 // Process every byte in the data.
1484 for (i = 0; i < len; i++) {
1485 // Multiple of 16 means new line (with line offset).
1486
1487 if ((i % 16) == 0) {
1488 // Just don't print ASCII for the zeroth line.
1489 if (i != 0)
1490 strlcatf(buf, bl, pos, " %s\n", buff);
1491
1492 // Output the offset.
1493 strlcatf(buf, bl, pos, " %04x ", i);
1494 }
1495
1496 // Now the hex code for the specific character.
1497 strlcatf(buf, bl, pos, " %02x", pc[i]);
1498
1499 // And store a printable ASCII character for later.
1500 if ((pc[i] < 0x20) || (pc[i] > 0x7e))
1501 buff[i % 16] = '.';
1502 else
1503 buff[i % 16] = pc[i];
1504 buff[(i % 16) + 1] = '\0';
1505 }
1506
1507 // Pad out last line if not exactly 16 characters.
1508 while ((i % 16) != 0) {
1509 strlcatf(buf, bl, pos, " ");
1510 i++;
1511 }
1512
1513 // And print the final ASCII bit.
1514 strlcatf(buf, bl, pos, " %s\n", buff);
1515 if (!desc)
1516 LOG("\n%s", buf)
1517 else
1518 LOG("%s:\n%s", desc, buf);
1519 }
1520
1521 SMutex httpc_mutex;
1522
http_client_add()1523 int http_client_add() {
1524
1525 Shttp_client *h;
1526 int i = add_new_lock((void **)httpc, MAX_HTTPC, sizeof(Shttp_client),
1527 &httpc_mutex);
1528 if (i == -1) {
1529 LOG_AND_RETURN(-1, "Could not add new http client");
1530 }
1531
1532 h = httpc[i];
1533 h->id = i;
1534 h->opaque = NULL;
1535 memset(h->host, 0, sizeof(h->host));
1536 memset(h->req, 0, sizeof(h->req));
1537 h->port = 0;
1538 mutex_unlock(&h->mutex);
1539 LOG("returning new http client %d", i);
1540
1541 return i;
1542 }
1543
http_client_del(int i)1544 int http_client_del(int i) {
1545 Shttp_client *h;
1546 h = get_httpc(i);
1547 if (!h)
1548 return 0;
1549
1550 if (mutex_lock(&h->mutex))
1551 return 0;
1552 h->enabled = 0;
1553 mutex_destroy(&h->mutex);
1554 LOGM("Stopping http client %d", i);
1555 return 0;
1556 }
1557
http_client_close(sockets * s)1558 int http_client_close(sockets *s) {
1559 Shttp_client *h = get_httpc(s->sid);
1560 if (!h) {
1561 LOG("HTTP Client record not found for sockets id %d, http client "
1562 "id %d",
1563 s->id, s->sid);
1564 return 1;
1565 }
1566 if (h->action)
1567 h->action(NULL, 0, h->opaque, h);
1568
1569 http_client_del(h->id);
1570 return 1;
1571 }
1572
http_client_read(sockets * s)1573 void http_client_read(sockets *s) {
1574 Shttp_client *h = get_httpc(s->sid);
1575 if (!h) {
1576 LOG("HTTP Client record not found for sockets id %d, http client "
1577 "id %d",
1578 s->id, s->sid);
1579 return;
1580 }
1581 if (!s->rlen && h->req[0]) {
1582 char headers[500];
1583 sprintf(headers, "GET %s HTTP/1.0\r\n\r\n", (char *)h->req);
1584 LOGM("%s: sending to %d: %s", __FUNCTION__, s->sock, (char *)h->req);
1585 sockets_write(s->id, headers, strlen(headers));
1586 h->req[0] = 0;
1587 return;
1588 }
1589 if (h->action)
1590 h->action(s->buf, s->rlen, h->opaque, h);
1591 s->rlen = 0;
1592 return;
1593 }
1594
http_client(char * url,char * request,void * callback,void * opaque)1595 int http_client(char *url, char *request, void *callback, void *opaque) {
1596 Shttp_client *h;
1597 int id;
1598 char *req;
1599 char *sep;
1600 int http_client_sock, sock;
1601
1602 if (strncmp("http", url, 4))
1603 LOG_AND_RETURN(0, "Only http support for %s", url);
1604
1605 id = http_client_add();
1606 h = get_httpc(id);
1607 if (!h)
1608 LOG_AND_RETURN(1, "Could not add http client");
1609 strncpy(h->host, url + 7, sizeof(h->host) - 1);
1610 h->port = 80;
1611 sep = strchr(h->host, ':');
1612 if (sep) {
1613 h->port = map_intd(sep + 1, NULL, 80);
1614 }
1615 if (!sep)
1616 sep = strchr(h->host, '/');
1617 if (!sep)
1618 sep = url + strlen(h->host);
1619 sep[0] = 0;
1620
1621 req = strchr(url + 7, '/');
1622 if (!req)
1623 req = "/";
1624
1625 sock = tcp_connect(h->host, h->port, NULL, 0);
1626 if (sock < 0)
1627 LOG_AND_RETURN(1, "%s: connect to %s:%d failed", __FUNCTION__, h->host,
1628 h->port);
1629 http_client_sock = sockets_add(sock, NULL, -1, TYPE_TCP | TYPE_CONNECT,
1630 (socket_action)http_client_read,
1631 (socket_action)http_client_close,
1632 (socket_action)http_client_close);
1633 if (http_client_sock < 0)
1634 LOG_AND_RETURN(1, "%s: sockets_add failed", __FUNCTION__);
1635 h->opaque = opaque;
1636 h->action = callback;
1637 set_sockets_sid(http_client_sock, id);
1638 strncpy(h->req, req, sizeof(h->req) - 1);
1639 sockets_timeout(http_client_sock, 2000); // 2s timeout
1640 LOGM("%s url %s using handle %d s_id %d", __FUNCTION__, url, sock,
1641 http_client_sock);
1642 return 0;
1643 }
1644
1645 static uint32_t crc_tab[256] = {
1646 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
1647 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
1648 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
1649 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
1650 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
1651 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
1652 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
1653 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
1654 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
1655 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
1656 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
1657 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
1658 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
1659 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
1660 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
1661 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
1662 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
1663 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
1664 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
1665 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
1666 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
1667 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
1668 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
1669 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
1670 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
1671 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
1672 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
1673 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
1674 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
1675 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
1676 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
1677 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
1678 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
1679 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
1680 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
1681 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
1682 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
1683 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
1684 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
1685 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
1686 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
1687 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
1688 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
1689
crc_32(const uint8_t * data,int datalen)1690 uint32_t crc_32(const uint8_t *data, int datalen) {
1691 uint32_t crc = 0xFFFFFFFF;
1692 if (datalen < 0)
1693 return crc;
1694 hexdump("crc_32 ", (uint8_t *)data, datalen);
1695 while (datalen--) {
1696 crc = (crc << 8) ^ crc_tab[((crc >> 24) ^ *data++) & 0xff];
1697 }
1698 return crc;
1699 }
1700
_dump_packets(char * message,unsigned char * b,int len,int packet_offset)1701 void _dump_packets(char *message, unsigned char *b, int len,
1702 int packet_offset) {
1703 int i, pid, cc;
1704 uint32_t crc;
1705
1706 for (i = 0; i < len; i += 188) {
1707 crc = crc_32(b + i + 4, 184); // skip header
1708 pid = PID_FROM_TS(b + i);
1709 cc = b[i + 3] & 0xF;
1710 LOG("%s: pid %04d (%04X) CC=%X CRC=%08X%s pos: %d packet %d : "
1711 "[%02X "
1712 "%02X "
1713 "%02X %02X] %02X %02X %02X %02X",
1714 message, pid, pid, cc, crc, (b[i + 3] & 0x80) ? "encrypted" : "",
1715 i + packet_offset, (packet_offset + i) / 188, b[i], b[i + 1],
1716 b[i + 2], b[i + 3], b[i + 4], b[i + 5], b[i + 6], b[i + 7]);
1717 }
1718 }
1719
buffer_to_ts(uint8_t * dest,int dstsize,uint8_t * src,int srclen,char * cc,int pid)1720 int buffer_to_ts(uint8_t *dest, int dstsize, uint8_t *src, int srclen, char *cc,
1721 int pid) {
1722 int pos = 0, left = 0, len = 0;
1723 uint8_t *b;
1724
1725 while ((srclen > 0) && (len < dstsize)) {
1726 if (dstsize - len < 188)
1727 LOG_AND_RETURN(-1,
1728 "Not enough space to copy pid %d, len %d from "
1729 "%d, srclen %d",
1730 pid, len, dstsize, srclen)
1731 b = dest + len;
1732 *cc = ((*cc) + 1) % 16;
1733 b[0] = 0x47;
1734 b[1] = pid >> 8;
1735 if (pos == 0)
1736 b[1] |= 0x40;
1737 b[2] = pid & 0xFF;
1738 b[3] = 0x10 | *cc;
1739 left = srclen > 184 ? 184 : srclen;
1740 memcpy(b + 4, src + pos, left);
1741 pos += left;
1742 srclen -= left;
1743 if (left < 184)
1744 memset(b + left + 4, -1, 184 - left);
1745 if (opts.debug & DEFAULT_LOG) {
1746 LOG("pid %d, left -> %d, len %d, cc %d", pid, left, len, *cc);
1747 hexdump("packet -> ", b, 188);
1748 }
1749 len += 188;
1750 }
1751 return len;
1752 }
1753
1754 /*
1755 void write_buf_to_file(char *file, uint8_t *buf, int len)
1756 {
1757 int x = open(file, O_RDWR);
1758 if (x >= 0)
1759 {
1760 write(x, buf, len);
1761 close(x);
1762 }
1763 else
1764 LOG("Could not write %d bytes to %s: %d", len, file, errno);
1765 }
1766 */
1767