|
@@ -31,6 +31,9 @@
|
31
|
31
|
#include <netdb.h> // for uint32_t
|
32
|
32
|
|
33
|
33
|
#include "libfuncs/libfuncs.h"
|
|
34
|
+#include "config.h"
|
|
35
|
+
|
|
36
|
+#include "web_server.h"
|
34
|
37
|
|
35
|
38
|
#define DNS_RESOLVER_TIMEOUT 5000
|
36
|
39
|
|
|
@@ -68,42 +71,7 @@ char *server_sig = "tomcast";
|
68
|
71
|
char *server_ver = "1.15";
|
69
|
72
|
char *copyright = "Copyright (C) 2010-2013 Unix Solutions Ltd.";
|
70
|
73
|
|
71
|
|
-typedef enum { udp_sock, tcp_sock } channel_source;
|
72
|
|
-
|
73
|
|
-typedef struct {
|
74
|
|
- channel_source sproto;
|
75
|
|
- char *proto;
|
76
|
|
- char *host;
|
77
|
|
- char *path;
|
78
|
|
- unsigned int port;
|
79
|
|
-} CHANSRC;
|
80
|
|
-
|
81
|
|
-#define MAX_CHANNEL_SOURCES 8
|
82
|
|
-
|
83
|
|
-typedef struct {
|
84
|
|
- char *name;
|
85
|
|
- char *source; /* Full source url */
|
86
|
|
- char *sources[MAX_CHANNEL_SOURCES];
|
87
|
|
- uint8_t num_src;
|
88
|
|
- uint8_t curr_src;
|
89
|
|
- char *dest_host;
|
90
|
|
- int dest_port;
|
91
|
|
-} CHANNEL;
|
92
|
|
-
|
93
|
|
-typedef struct {
|
94
|
|
- char *name;
|
95
|
|
- CHANNEL *channel;
|
96
|
|
- int sock; /* Server socket */
|
97
|
|
- struct sockaddr_in src_sockname;
|
98
|
|
- int clientsock; /* The udp socket */
|
99
|
|
- struct sockaddr_in dst_sockname;
|
100
|
|
- int reconnect:1, /* Set to 1 to force proxy reconnect */
|
101
|
|
- connected:1, /* It's set to 1 when proxy is connected and serving clients */
|
102
|
|
- dienow:1, /* Stop serving clients and exit now */
|
103
|
|
- freechannel:1; /* Free channel data on object free (this is used in chanconf) */
|
104
|
|
- int cookie; /* Used in chanconf to determine if the restreamer is alrady checked */
|
105
|
|
- pthread_t thread;
|
106
|
|
-} RESTREAMER;
|
|
74
|
+static struct config config;
|
107
|
75
|
|
108
|
76
|
channel_source get_sproto(char *url) {
|
109
|
77
|
return strncmp(url, "http", 4)==0 ? tcp_sock : udp_sock;
|
|
@@ -249,6 +217,11 @@ int connect_multicast(struct sockaddr_in send_to) {
|
249
|
217
|
return sendsock;
|
250
|
218
|
}
|
251
|
219
|
|
|
220
|
+void proxy_set_status(RESTREAMER *r, const char *proxy_status) {
|
|
221
|
+ pthread_rwlock_wrlock(&r->lock);
|
|
222
|
+ snprintf(r->status, sizeof(r->status), "%s", proxy_status);
|
|
223
|
+ pthread_rwlock_unlock(&r->lock);
|
|
224
|
+}
|
252
|
225
|
|
253
|
226
|
void connect_destination(RESTREAMER *r) {
|
254
|
227
|
CHANNEL *c = r->channel;
|
|
@@ -275,6 +248,7 @@ RESTREAMER * new_restreamer(const char *name, CHANNEL *channel) {
|
275
|
248
|
r->channel = channel;
|
276
|
249
|
r->clientsock = -1;
|
277
|
250
|
r->dst_sockname = sockname;
|
|
251
|
+ pthread_rwlock_init(&r->lock, NULL);
|
278
|
252
|
connect_destination(r);
|
279
|
253
|
return r;
|
280
|
254
|
}
|
|
@@ -288,27 +262,10 @@ void free_restreamer(RESTREAMER *r) {
|
288
|
262
|
FREE(r);
|
289
|
263
|
}
|
290
|
264
|
|
291
|
|
-
|
292
|
|
-
|
293
|
|
-
|
294
|
|
-char *pidfile = NULL;
|
295
|
|
-char *ident = NULL;
|
296
|
|
-char *logident = NULL;
|
297
|
|
-char *loghost = NULL;
|
298
|
|
-int logport = 514;
|
299
|
|
-
|
300
|
|
-char *channels_file = NULL;
|
301
|
|
-int syslog_active = 0;
|
302
|
|
-
|
303
|
265
|
char TS_NULL_FRAME[FRAME_PACKET_SIZE];
|
304
|
266
|
|
305
|
267
|
regex_t http_response;
|
306
|
268
|
|
307
|
|
-LIST *chanconf = NULL;
|
308
|
|
-LIST *restreamer = NULL;
|
309
|
|
-
|
310
|
|
-static pthread_mutex_t channels_lock = PTHREAD_MUTEX_INITIALIZER;
|
311
|
|
-
|
312
|
269
|
void proxy_log(RESTREAMER *r, char *msg, char *info) {
|
313
|
270
|
LOGf("%s: %sChan: %s Src: %s Dst: udp://%s:%d SrcIP: %s SrcFD: %i DstFD: %i\n",
|
314
|
271
|
msg,
|
|
@@ -323,17 +280,17 @@ void proxy_log(RESTREAMER *r, char *msg, char *info) {
|
323
|
280
|
);
|
324
|
281
|
}
|
325
|
282
|
|
326
|
|
-int load_channels_config() {
|
|
283
|
+int load_channels_config(struct config *cfg) {
|
327
|
284
|
regex_t re;
|
328
|
285
|
regmatch_t res[5];
|
329
|
286
|
char line[1024];
|
330
|
287
|
int fd;
|
331
|
288
|
int num_channels = 0;
|
332
|
289
|
|
333
|
|
- if (pthread_mutex_trylock(&channels_lock) != 0)
|
|
290
|
+ if (pthread_mutex_trylock(&cfg->channels_lock) != 0)
|
334
|
291
|
return -1;
|
335
|
292
|
|
336
|
|
- fd = open(channels_file, O_RDONLY);
|
|
293
|
+ fd = open(cfg->channels_file, O_RDONLY);
|
337
|
294
|
|
338
|
295
|
if (fd != -1) {
|
339
|
296
|
struct timeval tv;
|
|
@@ -385,18 +342,18 @@ report_error:
|
385
|
342
|
regfree(&re);
|
386
|
343
|
shutdown_fd(&fd);
|
387
|
344
|
/* Save current chanconf */
|
388
|
|
- old_chanconf = chanconf;
|
|
345
|
+ old_chanconf = cfg->chanconf;
|
389
|
346
|
/* Switch chanconf */
|
390
|
|
- chanconf = new_chanconf;
|
|
347
|
+ cfg->chanconf = new_chanconf;
|
391
|
348
|
/* Rewrite restreamer channels */
|
392
|
349
|
LNODE *lc, *lr, *lctmp, *lrtmp;
|
393
|
350
|
CHANNEL *chan;
|
394
|
|
- list_lock(restreamer); // Unlocked after second list_for_each(restreamer)
|
|
351
|
+ list_lock(cfg->restreamer); // Unlocked after second list_for_each(restreamer)
|
395
|
352
|
|
396
|
|
- list_lock(chanconf);
|
397
|
|
- list_for_each(chanconf, lc, lctmp) {
|
|
353
|
+ list_lock(cfg->chanconf);
|
|
354
|
+ list_for_each(cfg->chanconf, lc, lctmp) {
|
398
|
355
|
chan = lc->data;
|
399
|
|
- list_for_each(restreamer, lr, lrtmp) {
|
|
356
|
+ list_for_each(cfg->restreamer, lr, lrtmp) {
|
400
|
357
|
if (strcmp(chan->name, ((RESTREAMER *)lr->data)->name)==0) {
|
401
|
358
|
RESTREAMER *restr = lr->data;
|
402
|
359
|
/* Mark the restreamer as valid */
|
|
@@ -425,10 +382,10 @@ report_error:
|
425
|
382
|
}
|
426
|
383
|
}
|
427
|
384
|
}
|
428
|
|
- list_unlock(chanconf);
|
|
385
|
+ list_unlock(cfg->chanconf);
|
429
|
386
|
|
430
|
387
|
/* Kill restreamers that serve channels that no longer exist */
|
431
|
|
- list_for_each(restreamer, lr, lrtmp) {
|
|
388
|
+ list_for_each(cfg->restreamer, lr, lrtmp) {
|
432
|
389
|
RESTREAMER *r = lr->data;
|
433
|
390
|
/* This restreamer should no longer serve clients */
|
434
|
391
|
if (r->cookie != cookie) {
|
|
@@ -439,14 +396,14 @@ report_error:
|
439
|
396
|
r->dienow = 1;
|
440
|
397
|
}
|
441
|
398
|
}
|
442
|
|
- list_unlock(restreamer);
|
|
399
|
+ list_unlock(cfg->restreamer);
|
443
|
400
|
|
444
|
401
|
/* Free old_chanconf */
|
445
|
402
|
list_free(&old_chanconf, free_channel_p, NULL);
|
446
|
403
|
} else {
|
447
|
404
|
num_channels = -1;
|
448
|
405
|
}
|
449
|
|
- pthread_mutex_unlock(&channels_lock);
|
|
406
|
+ pthread_mutex_unlock(&cfg->channels_lock);
|
450
|
407
|
if (num_channels == -1)
|
451
|
408
|
LOGf("CONF : Error loading channels!\n");
|
452
|
409
|
else
|
|
@@ -457,7 +414,7 @@ report_error:
|
457
|
414
|
void proxy_close(RESTREAMER *r) {
|
458
|
415
|
proxy_log(r, "STOP ","");
|
459
|
416
|
// If there are no clients left, no "Timeout" messages will be logged
|
460
|
|
- list_del_entry(restreamer, r);
|
|
417
|
+ list_del_entry(config.restreamer, r);
|
461
|
418
|
free_restreamer(r);
|
462
|
419
|
}
|
463
|
420
|
|
|
@@ -501,10 +458,14 @@ int connect_source(RESTREAMER *r, int retries, int readbuflen, int *http_code) {
|
501
|
458
|
int active = 1;
|
502
|
459
|
int dret = async_resolve_host(src->host, src->port, &(r->src_sockname), DNS_RESOLVER_TIMEOUT, &active);
|
503
|
460
|
if (dret != 0) {
|
504
|
|
- if (dret == 1)
|
|
461
|
+ if (dret == 1) {
|
505
|
462
|
proxy_log(r, "ERR ","Can't resolve src host");
|
506
|
|
- if (dret == 2)
|
|
463
|
+ proxy_set_status(r, "ERROR: Can not resolve source host");
|
|
464
|
+ }
|
|
465
|
+ if (dret == 2) {
|
507
|
466
|
proxy_log(r, "ERR ","Timeout resolving src host");
|
|
467
|
+ proxy_set_status(r, "ERROR: Dns resolve timeout");
|
|
468
|
+ }
|
508
|
469
|
DO_RECONNECT;
|
509
|
470
|
}
|
510
|
471
|
|
|
@@ -519,11 +480,12 @@ int connect_source(RESTREAMER *r, int retries, int readbuflen, int *http_code) {
|
519
|
480
|
proxy_log(r, "NEW ","");
|
520
|
481
|
if (do_connect(r->sock, (struct sockaddr *)&(r->src_sockname), sizeof(r->src_sockname), PROXY_CONNECT_TIMEOUT) < 0) {
|
521
|
482
|
LOGf("ERR : Error connecting to %s srv_fd: %i err: %s\n", r->channel->source, r->sock, strerror(errno));
|
|
483
|
+ proxy_set_status(r, "ERROR: Can not connect to source");
|
522
|
484
|
DO_RECONNECT;
|
523
|
485
|
}
|
524
|
486
|
|
525
|
487
|
snprintf(buf,sizeof(buf)-1, "GET /%s HTTP/1.0\r\nHost: %s:%u\r\nX-Smart-Client: yes\r\nUser-Agent: %s %s (%s)\r\n\r\n",
|
526
|
|
- src->path, src->host, src->port, server_sig, server_ver, ident);
|
|
488
|
+ src->path, src->host, src->port, server_sig, server_ver, config.ident);
|
527
|
489
|
buf[sizeof(buf)-1] = 0;
|
528
|
490
|
fdwrite(r->sock, buf, strlen(buf));
|
529
|
491
|
|
|
@@ -556,14 +518,17 @@ int connect_source(RESTREAMER *r, int retries, int readbuflen, int *http_code) {
|
556
|
518
|
}
|
557
|
519
|
if (*http_code == 0) { // No valid HTTP response, retry
|
558
|
520
|
LOGf("DEBUG: Server returned not valid HTTP code | srv_fd: %i\n", r->sock);
|
|
521
|
+ proxy_set_status(r, "ERROR: Source returned invalid HTTP code");
|
559
|
522
|
DO_RECONNECT;
|
560
|
523
|
}
|
561
|
524
|
if (*http_code == 504) { // No signal, exit
|
562
|
525
|
LOGf("ERR : Get no-signal for %s from %s on srv_fd: %i\n", r->channel->name, r->channel->source, r->sock);
|
|
526
|
+ proxy_set_status(r, "ERROR: Source returned no-signal");
|
563
|
527
|
FATAL_ERROR;
|
564
|
528
|
}
|
565
|
529
|
if (*http_code > 300) { // Unhandled or error codes, exit
|
566
|
530
|
LOGf("ERR : Get code %i for %s from %s on srv_fd: %i exiting.\n", *http_code, r->channel->name, r->channel->source, r->sock);
|
|
531
|
+ proxy_set_status(r, "ERROR: Source returned unhandled error code");
|
567
|
532
|
FATAL_ERROR;
|
568
|
533
|
}
|
569
|
534
|
// connected ok, continue
|
|
@@ -604,6 +569,7 @@ int connect_source(RESTREAMER *r, int retries, int readbuflen, int *http_code) {
|
604
|
569
|
if (setsockopt(r->sock, SOL_SOCKET, SO_RCVBUF, (const char *)&readbuflen, sizeof(readbuflen)) < 0)
|
605
|
570
|
log_perror("play(): setsockopt(SO_RCVBUF)", errno);
|
606
|
571
|
|
|
572
|
+ proxy_set_status(r, "Connected");
|
607
|
573
|
r->connected = 1;
|
608
|
574
|
|
609
|
575
|
free_chansrc(src);
|
|
@@ -613,10 +579,12 @@ int connect_source(RESTREAMER *r, int retries, int readbuflen, int *http_code) {
|
613
|
579
|
int check_restreamer_state(RESTREAMER *r) {
|
614
|
580
|
if (r->dienow) {
|
615
|
581
|
// LOGf("PROXY: Forced disconnect on srv_fd: %i | Channel: %s Source: %s\n", r->sock, r->channel->name, r->channel->source);
|
|
582
|
+ proxy_set_status(r, "Dying");
|
616
|
583
|
return 2;
|
617
|
584
|
}
|
618
|
585
|
if (r->reconnect) {
|
619
|
586
|
LOGf("PROXY: Forced reconnect on srv_fd: %i | Channel: %s Source: %s\n", r->sock, r->channel->name, r->channel->source);
|
|
587
|
+ proxy_set_status(r, "Forced reconnect");
|
620
|
588
|
return 1;
|
621
|
589
|
}
|
622
|
590
|
return 0;
|
|
@@ -640,7 +608,7 @@ int check_restreamer_state(RESTREAMER *r) {
|
640
|
608
|
0 = synced ok
|
641
|
609
|
1 = not synced, reconnect
|
642
|
610
|
*/
|
643
|
|
-int mpeg_sync(int proxysock, char *channel, channel_source source_proto) {
|
|
611
|
+int mpeg_sync(RESTREAMER *r, int proxysock, char *channel, channel_source source_proto) {
|
644
|
612
|
time_t sync_start = time(NULL);
|
645
|
613
|
unsigned int sync_packets = 0;
|
646
|
614
|
unsigned int read_bytes = 0;
|
|
@@ -656,6 +624,7 @@ int mpeg_sync(int proxysock, char *channel, channel_source source_proto) {
|
656
|
624
|
resync:
|
657
|
625
|
if (fdread_ex(proxysock, syncframe, 1, _timeout, _retries, 1) != 1) {
|
658
|
626
|
LOGf("DEBUG: mpeg_sync fdread() timeout | Channel: %s\n", channel);
|
|
627
|
+ proxy_set_status(r, "ERROR: fdread() timeout while syncing mpeg");
|
659
|
628
|
return 1; // reconnect
|
660
|
629
|
}
|
661
|
630
|
// LOGf("DEBUG: Read 0x%02x Offset %u Sync: %u\n", (uint8_t)syncframe[0], read_bytes, sync_packets);
|
|
@@ -664,6 +633,7 @@ resync:
|
664
|
633
|
ssize_t rdsz = fdread_ex(proxysock, syncframe, 188-1, _timeout, _retries, 1);
|
665
|
634
|
if (rdsz != 188-1) {
|
666
|
635
|
LOGf("DEBUG: mpeg_sync fdread() timeout | Channel: %s\n", channel);
|
|
636
|
+ proxy_set_status(r, "ERROR: fdread() timeout while syncing mpeg");
|
667
|
637
|
return 1; // reconnect
|
668
|
638
|
}
|
669
|
639
|
read_bytes += 188-1;
|
|
@@ -675,14 +645,21 @@ resync:
|
675
|
645
|
}
|
676
|
646
|
if (read_bytes > FRAME_PACKET_SIZE) { // Can't sync in 1316 bytes
|
677
|
647
|
LOGf("DEBUG: Can't sync after %d bytes | Channel: %s\n", FRAME_PACKET_SIZE, channel);
|
|
648
|
+ proxy_set_status(r, "ERROR: Can not sync mpeg");
|
678
|
649
|
return 1; // reconnect
|
679
|
650
|
}
|
680
|
651
|
if (sync_start+2 <= time(NULL)) { // Do not sync in two seconds
|
681
|
652
|
LOGf("DEBUG: Timeout while syncing (read %u bytes) | Channel: %s\n", read_bytes, channel);
|
|
653
|
+ proxy_set_status(r, "ERROR: Timeout while syncing mpeg");
|
682
|
654
|
return 1; // reconnect
|
683
|
655
|
}
|
684
|
656
|
} while (1);
|
|
657
|
+ pthread_rwlock_wrlock(&r->lock);
|
|
658
|
+ r->conn_ts = time(NULL);
|
|
659
|
+ r->read_bytes = read_bytes;
|
|
660
|
+ pthread_rwlock_unlock(&r->lock);
|
685
|
661
|
LOGf("SYNC : TS synced after %u bytes | Channel: %s\n", read_bytes-FRAME_PACKET_SIZE, channel);
|
|
662
|
+ proxy_set_status(r, "Working");
|
686
|
663
|
return 0;
|
687
|
664
|
}
|
688
|
665
|
|
|
@@ -807,13 +784,16 @@ void * proxy_ts_stream(void *self) {
|
807
|
784
|
|
808
|
785
|
int http_code = 0;
|
809
|
786
|
while (1) {
|
|
787
|
+ r->conn_ts = 0;
|
|
788
|
+ r->read_bytes = 0;
|
|
789
|
+
|
810
|
790
|
int result = connect_source(self, 1, FRAME_PACKET_SIZE * 1000, &http_code);
|
811
|
791
|
if (result > 0)
|
812
|
792
|
goto RECONNECT;
|
813
|
793
|
|
814
|
794
|
channel_source sproto = get_sproto(r->channel->source);
|
815
|
795
|
|
816
|
|
- int mpgsync = mpeg_sync(r->sock, r->channel->name, sproto);
|
|
796
|
+ int mpgsync = mpeg_sync(r, r->sock, r->channel->name, sproto);
|
817
|
797
|
if (mpgsync == 1) // Timeout
|
818
|
798
|
goto RECONNECT;
|
819
|
799
|
|
|
@@ -836,6 +816,7 @@ void * proxy_ts_stream(void *self) {
|
836
|
816
|
LOGf("PROXY: zero read on srv_fd: %i | Channel: %s Source: %s\n", r->sock, r->channel->name, r->channel->source);
|
837
|
817
|
if (--max_zero_reads == 0) {
|
838
|
818
|
LOGf("PROXY: %d zero reads on srv_fd: %i | Channel: %s Source: %s\n", MAX_ZERO_READS, r->sock, r->channel->name, r->channel->source);
|
|
819
|
+ proxy_set_status(r, "ERROR: Too many zero reads");
|
839
|
820
|
break;
|
840
|
821
|
}
|
841
|
822
|
continue;
|
|
@@ -848,6 +829,9 @@ void * proxy_ts_stream(void *self) {
|
848
|
829
|
//LOGf("DEBUG: Short read (%d) on retreamer srv_fd: %i | Channel: %s\n", readen, sock, chan->name);
|
849
|
830
|
memcpy(buf+readen, TS_NULL_FRAME+readen, FRAME_PACKET_SIZE - readen);
|
850
|
831
|
}
|
|
832
|
+ pthread_rwlock_wrlock(&r->lock);
|
|
833
|
+ r->read_bytes += readen;
|
|
834
|
+ pthread_rwlock_unlock(&r->lock);
|
851
|
835
|
|
852
|
836
|
if (send_reset) {
|
853
|
837
|
send_reset = 0;
|
|
@@ -860,8 +844,13 @@ void * proxy_ts_stream(void *self) {
|
860
|
844
|
}
|
861
|
845
|
}
|
862
|
846
|
LOGf("DEBUG: fdread timeout restreamer srv_fd: %i | Channel: %s\n", r->sock, r->channel->name);
|
|
847
|
+ proxy_set_status(r, "ERROR: Read timeout");
|
863
|
848
|
RECONNECT:
|
|
849
|
+ pthread_rwlock_wrlock(&r->lock);
|
|
850
|
+ r->conn_ts = 0;
|
|
851
|
+ pthread_rwlock_unlock(&r->lock);
|
864
|
852
|
LOGf("DEBUG: reconnect srv_fd: %i | Channel: %s\n", r->sock, r->channel->name);
|
|
853
|
+ proxy_set_status(r, "Reconnecting");
|
865
|
854
|
shutdown_fd(&(r->sock));
|
866
|
855
|
next_channel_source(r->channel);
|
867
|
856
|
continue;
|
|
@@ -893,13 +882,16 @@ void show_usage(int ident_only) {
|
893
|
882
|
puts("\t-l host\t\tSyslog host (default: disabled)");
|
894
|
883
|
puts("\t-L port\t\tSyslog port (default: 514)");
|
895
|
884
|
puts("\t-R\t\tSend reset packets when changing sources.");
|
|
885
|
+ puts("Server settings:");
|
|
886
|
+ puts("\t-b addr\t\tLocal IP address to bind. (default: 0.0.0.0)");
|
|
887
|
+ puts("\t-p port\t\tPort to listen. (default: 0)");
|
896
|
888
|
puts("");
|
897
|
889
|
}
|
898
|
890
|
|
899
|
|
-void set_ident(char *new_ident) {
|
900
|
|
- ident = new_ident;
|
901
|
|
- logident = strdup(ident);
|
902
|
|
- char *c = logident;
|
|
891
|
+void set_ident(char *new_ident, struct config *cfg) {
|
|
892
|
+ cfg->ident = new_ident;
|
|
893
|
+ cfg->logident = strdup(new_ident);
|
|
894
|
+ char *c = cfg->logident;
|
903
|
895
|
while (*c) {
|
904
|
896
|
if (*c=='/')
|
905
|
897
|
*c='-';
|
|
@@ -907,18 +899,26 @@ void set_ident(char *new_ident) {
|
907
|
899
|
}
|
908
|
900
|
}
|
909
|
901
|
|
910
|
|
-void parse_options(int argc, char **argv) {
|
|
902
|
+void parse_options(int argc, char **argv, struct config *cfg) {
|
911
|
903
|
int j, ttl;
|
912
|
|
- while ((j = getopt(argc, argv, "i:c:d:t:o:l:L:RHh")) != -1) {
|
|
904
|
+ cfg->server_socket = -1;
|
|
905
|
+ pthread_mutex_init(&cfg->channels_lock, NULL);
|
|
906
|
+ while ((j = getopt(argc, argv, "i:b:p:c:d:t:o:l:L:RHh")) != -1) {
|
913
|
907
|
switch (j) {
|
|
908
|
+ case 'b':
|
|
909
|
+ cfg->server_addr = optarg;
|
|
910
|
+ break;
|
|
911
|
+ case 'p':
|
|
912
|
+ cfg->server_port = atoi(optarg);
|
|
913
|
+ break;
|
914
|
914
|
case 'i':
|
915
|
|
- set_ident(optarg);
|
|
915
|
+ set_ident(optarg, cfg);
|
916
|
916
|
break;
|
917
|
917
|
case 'c':
|
918
|
|
- channels_file = optarg;
|
|
918
|
+ cfg->channels_file = optarg;
|
919
|
919
|
break;
|
920
|
920
|
case 'd':
|
921
|
|
- pidfile = optarg;
|
|
921
|
+ cfg->pidfile = optarg;
|
922
|
922
|
break;
|
923
|
923
|
case 'o':
|
924
|
924
|
if (inet_aton(optarg, &output_intf) == 0) {
|
|
@@ -931,11 +931,11 @@ void parse_options(int argc, char **argv) {
|
931
|
931
|
multicast_ttl = (ttl && ttl < 127) ? ttl : 1;
|
932
|
932
|
break;
|
933
|
933
|
case 'l':
|
934
|
|
- loghost = optarg;
|
935
|
|
- syslog_active = 1;
|
|
934
|
+ cfg->loghost = optarg;
|
|
935
|
+ cfg->syslog_active = 1;
|
936
|
936
|
break;
|
937
|
937
|
case 'L':
|
938
|
|
- logport = atoi(optarg);
|
|
938
|
+ cfg->logport = atoi(optarg);
|
939
|
939
|
break;
|
940
|
940
|
case 'R':
|
941
|
941
|
send_reset_opt = 1;
|
|
@@ -948,38 +948,44 @@ void parse_options(int argc, char **argv) {
|
948
|
948
|
}
|
949
|
949
|
}
|
950
|
950
|
|
951
|
|
- if (!channels_file) {
|
|
951
|
+ if (!cfg->channels_file) {
|
952
|
952
|
show_usage(0);
|
953
|
953
|
fprintf(stderr, "ERROR: No channels file is set (use -c option).\n");
|
954
|
954
|
exit(1);
|
955
|
955
|
}
|
956
|
956
|
|
957
|
|
- if (!ident) {
|
958
|
|
- set_ident("unixsol/tomcast");
|
|
957
|
+ if (!cfg->ident) {
|
|
958
|
+ set_ident("unixsol/tomcast", cfg);
|
959
|
959
|
}
|
960
|
960
|
|
961
|
961
|
printf("Configuration:\n");
|
962
|
|
- printf("\tServer ident : %s\n", ident);
|
963
|
|
- printf("\tChannels file : %s\n", channels_file);
|
|
962
|
+ printf("\tServer ident : %s\n", cfg->ident);
|
|
963
|
+ printf("\tChannels file : %s\n", cfg->channels_file);
|
964
|
964
|
printf("\tOutput iface addr : %s\n", inet_ntoa(output_intf));
|
965
|
965
|
printf("\tMulticast ttl : %d\n", multicast_ttl);
|
966
|
|
- if (syslog_active) {
|
967
|
|
- printf("\tSyslog host : %s\n", loghost);
|
968
|
|
- printf("\tSyslog port : %d\n", logport);
|
|
966
|
+ if (cfg->syslog_active) {
|
|
967
|
+ printf("\tSyslog host : %s\n", cfg->loghost);
|
|
968
|
+ printf("\tSyslog port : %d\n", cfg->logport);
|
969
|
969
|
} else {
|
970
|
970
|
printf("\tSyslog disabled.\n");
|
971
|
971
|
}
|
972
|
972
|
if (send_reset_opt)
|
973
|
973
|
printf("\tSend reset packets.\n");
|
974
|
|
- if (pidfile) {
|
975
|
|
- printf("\tDaemonize : %s\n", pidfile);
|
|
974
|
+ if (cfg->pidfile) {
|
|
975
|
+ printf("\tDaemonize : %s\n", cfg->pidfile);
|
976
|
976
|
} else {
|
977
|
977
|
printf("\tDo not daemonize.\n");
|
978
|
978
|
}
|
|
979
|
+ if (cfg->server_port) {
|
|
980
|
+ init_server_socket(cfg->server_addr, cfg->server_port, &cfg->server, &cfg->server_socket);
|
|
981
|
+ printf("\tStarting web srv : http://%s:%d/status (sock: %d)\n", cfg->server_addr, cfg->server_port, cfg->server_socket);
|
|
982
|
+ } else {
|
|
983
|
+ printf("\tNo web server\n");
|
|
984
|
+ }
|
979
|
985
|
}
|
980
|
986
|
|
981
|
|
-void init_vars() {
|
982
|
|
- restreamer = list_new("restreamer");
|
|
987
|
+void init_vars(struct config *cfg) {
|
|
988
|
+ cfg->restreamer = list_new("restreamer");
|
983
|
989
|
regcomp(&http_response, "^HTTP/1.[0-1] (([0-9]{3}) .*)", REG_EXTENDED);
|
984
|
990
|
memset(&TS_NULL_FRAME, 0xff, FRAME_PACKET_SIZE);
|
985
|
991
|
int i;
|
|
@@ -991,29 +997,29 @@ void init_vars() {
|
991
|
997
|
}
|
992
|
998
|
}
|
993
|
999
|
|
994
|
|
-void spawn_proxy_threads() {
|
|
1000
|
+void spawn_proxy_threads(struct config *cfg) {
|
995
|
1001
|
LNODE *lc, *lctmp;
|
996
|
1002
|
LNODE *lr, *lrtmp;
|
997
|
1003
|
int spawned = 0;
|
998
|
|
- list_for_each(chanconf, lc, lctmp) {
|
|
1004
|
+ list_for_each(cfg->chanconf, lc, lctmp) {
|
999
|
1005
|
CHANNEL *c = lc->data;
|
1000
|
1006
|
int restreamer_active = 0;
|
1001
|
|
- list_lock(restreamer);
|
1002
|
|
- list_for_each(restreamer, lr, lrtmp) {
|
|
1007
|
+ list_lock(cfg->restreamer);
|
|
1008
|
+ list_for_each(cfg->restreamer, lr, lrtmp) {
|
1003
|
1009
|
RESTREAMER *r = lr->data;
|
1004
|
1010
|
if (strcmp(r->name, c->name)==0) {
|
1005
|
1011
|
restreamer_active = 1;
|
1006
|
1012
|
break;
|
1007
|
1013
|
}
|
1008
|
1014
|
}
|
1009
|
|
- list_unlock(restreamer);
|
|
1015
|
+ list_unlock(cfg->restreamer);
|
1010
|
1016
|
if (!restreamer_active) {
|
1011
|
1017
|
RESTREAMER *nr = new_restreamer(c->name, c);
|
1012
|
1018
|
if (nr->clientsock < 0) {
|
1013
|
1019
|
LOGf("Error creating proxy socket for %s\n", c->name);
|
1014
|
1020
|
free_restreamer(nr);
|
1015
|
1021
|
} else {
|
1016
|
|
- list_add(restreamer, nr);
|
|
1022
|
+ list_add(cfg->restreamer, nr);
|
1017
|
1023
|
if (pthread_create(&nr->thread, NULL, &proxy_ts_stream, nr) == 0) {
|
1018
|
1024
|
spawned++;
|
1019
|
1025
|
pthread_detach(nr->thread);
|
|
@@ -1026,44 +1032,51 @@ void spawn_proxy_threads() {
|
1026
|
1032
|
LOGf("INFO : %d proxy threads spawned\n", spawned);
|
1027
|
1033
|
}
|
1028
|
1034
|
|
1029
|
|
-void kill_proxy_threads() {
|
|
1035
|
+void kill_proxy_threads(struct config *cfg) {
|
1030
|
1036
|
LNODE *l, *tmp;
|
1031
|
1037
|
int killed = 0;
|
1032
|
|
- list_lock(restreamer);
|
1033
|
|
- list_for_each(restreamer, l, tmp) {
|
|
1038
|
+ list_lock(cfg->restreamer);
|
|
1039
|
+ list_for_each(cfg->restreamer, l, tmp) {
|
1034
|
1040
|
RESTREAMER *r = l->data;
|
1035
|
1041
|
r->dienow = 1;
|
1036
|
1042
|
killed++;
|
1037
|
1043
|
}
|
1038
|
|
- list_unlock(restreamer);
|
|
1044
|
+ list_unlock(cfg->restreamer);
|
1039
|
1045
|
LOGf("INFO : %d proxy threads killed\n", killed);
|
1040
|
1046
|
}
|
1041
|
1047
|
|
|
1048
|
+int keep_going = 1;
|
|
1049
|
+
|
1042
|
1050
|
void signal_quit(int sig) {
|
1043
|
|
- kill_proxy_threads();
|
|
1051
|
+ keep_going = 0;
|
|
1052
|
+ kill_proxy_threads(&config);
|
1044
|
1053
|
usleep(500000);
|
1045
|
|
- LOGf("KILL : Signal %i | %s %s (%s)\n", sig, server_sig, server_ver, ident);
|
|
1054
|
+ LOGf("KILL : Signal %i | %s %s (%s)\n", sig, server_sig, server_ver, config.ident);
|
1046
|
1055
|
usleep(100000);
|
1047
|
1056
|
log_close();
|
1048
|
|
- if (pidfile && strlen(pidfile))
|
1049
|
|
- unlink(pidfile);
|
|
1057
|
+ if (config.pidfile && strlen(config.pidfile))
|
|
1058
|
+ unlink(config.pidfile);
|
1050
|
1059
|
signal(sig, SIG_DFL);
|
1051
|
1060
|
raise(sig);
|
1052
|
1061
|
}
|
1053
|
1062
|
|
|
1063
|
+struct config *get_config(void) {
|
|
1064
|
+ return &config;
|
|
1065
|
+}
|
|
1066
|
+
|
1054
|
1067
|
void do_reconnect() {
|
1055
|
1068
|
LNODE *l, *tmp;
|
1056
|
|
- list_lock(restreamer);
|
1057
|
|
- list_for_each(restreamer, l, tmp) {
|
|
1069
|
+ list_lock(config.restreamer);
|
|
1070
|
+ list_for_each(config.restreamer, l, tmp) {
|
1058
|
1071
|
RESTREAMER *r = l->data;
|
1059
|
1072
|
r->reconnect = 1;
|
1060
|
1073
|
}
|
1061
|
|
- list_unlock(restreamer);
|
|
1074
|
+ list_unlock(config.restreamer);
|
1062
|
1075
|
}
|
1063
|
1076
|
|
1064
|
1077
|
void do_reconf() {
|
1065
|
|
- load_channels_config();
|
1066
|
|
- spawn_proxy_threads();
|
|
1078
|
+ load_channels_config(&config);
|
|
1079
|
+ spawn_proxy_threads(&config);
|
1067
|
1080
|
}
|
1068
|
1081
|
|
1069
|
1082
|
void init_signals() {
|
|
@@ -1077,13 +1090,13 @@ void init_signals() {
|
1077
|
1090
|
signal(SIGTERM, signal_quit);
|
1078
|
1091
|
}
|
1079
|
1092
|
|
1080
|
|
-void do_daemonize() {
|
1081
|
|
- if (!pidfile)
|
|
1093
|
+void do_daemonize(struct config *cfg) {
|
|
1094
|
+ if (!cfg->pidfile)
|
1082
|
1095
|
return;
|
1083
|
1096
|
fprintf(stderr, "Daemonizing.\n");
|
1084
|
1097
|
pid_t pid = fork();
|
1085
|
1098
|
if (pid > 0) {
|
1086
|
|
- FILE *F = fopen(pidfile,"w");
|
|
1099
|
+ FILE *F = fopen(cfg->pidfile,"w");
|
1087
|
1100
|
if (F) {
|
1088
|
1101
|
fprintf(F,"%i\n",pid);
|
1089
|
1102
|
fclose(F);
|
|
@@ -1098,25 +1111,26 @@ void do_daemonize() {
|
1098
|
1111
|
}
|
1099
|
1112
|
|
1100
|
1113
|
/* Must be called after daemonize! */
|
1101
|
|
-void init_logger() {
|
1102
|
|
- if (syslog_active)
|
1103
|
|
- fprintf(stderr, "Logging to %s:%d\n", loghost, logport);
|
1104
|
|
- log_init(logident, syslog_active, pidfile == NULL, loghost, logport);
|
|
1114
|
+void init_logger(struct config *cfg) {
|
|
1115
|
+ if (cfg->syslog_active)
|
|
1116
|
+ fprintf(stderr, "Logging to %s:%d\n", cfg->loghost, cfg->logport);
|
|
1117
|
+ log_init(cfg->logident, cfg->syslog_active, cfg->pidfile == NULL, cfg->loghost, cfg->logport);
|
1105
|
1118
|
}
|
1106
|
1119
|
|
1107
|
1120
|
int main(int argc, char **argv) {
|
1108
|
1121
|
set_http_response_server_ident(server_sig, server_ver);
|
1109
|
1122
|
show_usage(1); // Show copyright and version
|
1110
|
|
- init_vars();
|
1111
|
|
- parse_options(argc, argv);
|
1112
|
|
- do_daemonize();
|
1113
|
|
- init_logger();
|
|
1123
|
+ init_vars(&config);
|
|
1124
|
+ parse_options(argc, argv, &config);
|
|
1125
|
+ do_daemonize(&config);
|
|
1126
|
+ init_logger(&config);
|
1114
|
1127
|
init_signals();
|
1115
|
1128
|
|
1116
|
|
- LOGf("INIT : %s %s (%s)\n" , server_sig, server_ver, ident);
|
|
1129
|
+ LOGf("INIT : %s %s (%s)\n" , server_sig, server_ver, config.ident);
|
1117
|
1130
|
|
1118
|
|
- load_channels_config();
|
1119
|
|
- spawn_proxy_threads();
|
|
1131
|
+ load_channels_config(&config);
|
|
1132
|
+ spawn_proxy_threads(&config);
|
|
1133
|
+ web_server_start(&config);
|
1120
|
1134
|
|
1121
|
1135
|
do {
|
1122
|
1136
|
sleep(60);
|