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(&param, 0, sizeof(struct sched_param));
1375     param.sched_priority = prio;
1376     if ((rv = pthread_setschedparam(pthread_self(), SCHED_RR, &param)))
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