123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- /* tsiproxy - mpeg transport stream proxy */
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <pthread.h>
- #include <errno.h>
- #include <signal.h>
- #include <regex.h>
- #include <arpa/inet.h>
- #include <netinet/in.h>
- #include <sys/types.h>
- #include <sys/socket.h>
-
- #include "libfuncs/libfuncs.h"
-
- #include "data.h"
- #include "conf.h"
- #include "request.h"
-
- char *server_sig = SERVER_SIGNATURE;
- char *server_ver = VERSION_ID;
-
- int keep_running = 1;
- int rcvsig = 0;
- int clean_on_exit = 0;
-
- CONFIG *config;
-
- regex_t request_get;
- regex_t http_response;
-
- STATS allstats;
-
- LIST *netconf = NULL;
- LIST *clients = NULL;
- LIST *chanconf = NULL;
- LIST *restreamer = NULL;
-
- char TS_NULL_FRAME[FRAME_PACKET_SIZE];
-
- static int usage_shown = 0;
-
- static void show_usage(void) {
- if (usage_shown)
- return;
- puts("Identification:");
- puts("");
- puts(" -i ident Streamer identification. Must be formated as PROVIDER/STREAMER");
- puts(" -c <channels_file> Channel definitions file");
- puts(" -n <networks_file> Network definitions file");
- puts("");
- puts("Server settings:");
- puts("");
- puts(" -b addr Local IP address to bind (Default: 0.0.0.0)");
- puts(" -p port Port to listen (Default: 8080)");
- puts(" -d pidfile Run in daemon mode and write PID file");
- puts("");
- puts("Stream settings:");
- puts("");
- puts(" -B Disable stream burst for new clients (usefull for master servers)");
- puts("");
- usage_shown = 1;
- }
-
- static void config_parse(CONFIG *conf, int argc, char **argv) {
- int j;
- conf->channels_file = "config.channels";
- conf->networks_file = "config.networks";
- while ((j = getopt(argc, argv, "TRBhXmvb:c:C:d:i:l:L:n:p:s:x:V:H:P:F")) != -1) {
- switch (j) {
- case 'b':
- conf->bind_to = optarg;
- break;
- case 'c':
- conf->channels_file = optarg;
- break;
- case 'd':
- conf->pidfile = optarg;
- break;
- case 'i':
- conf->ident = optarg;
- conf->logident = strdup(conf->ident);
- char *c = conf->logident;
- while (*c) {
- if (*c=='/')
- *c='-';
- c++;
- }
- break;
- case 'n':
- conf->networks_file = optarg;
- break;
- case 'T':
- conf->ts_sync = 1;
- break;
- case 'B':
- conf->disable_burst = 1;
- break;
- case 'p':
- conf->server_port = atoi(optarg);
- break;
- case 'F':
- clean_on_exit = 1;
- break;
- case 'h':
- show_usage();
- exit(1);
- break;
- }
- }
- int is_error = 0;
- if (!conf->ident) {
- show_usage();
- fprintf(stderr, "ERROR: Server ident is not set. Use '-i provider/streamer'\n");
- is_error++;
- }
- if (!conf->channels_file) {
- show_usage();
- fprintf(stderr, "ERROR: Channel definitions file is not set, use '-c channels_file'\n");
- is_error++;
- }
- if (!conf->networks_file) {
- show_usage();
- fprintf(stderr, "ERROR: Network definitions file is not set, use '-n networks_file'\n");
- is_error++;
- }
- if (is_error)
- exit(3);
- }
-
- static void init_channels(void) {
- /* Init channels */
- fputs("Reading channels map:\t\t",stderr);
- int j = load_channels(config);
- if (j != -1) {
- fprintf(stderr,"[OK] %i channels read\n", j);
- } else {
- fprintf(stderr,"[ERR] Can't read channels.\n");
- exit(1);
- }
- }
-
- static void init_networks(void) {
- /* Init networks */
- fputs("Reading networks ACL:\t\t",stderr);
- int j = load_networks(config);
- if (j != -1) {
- fprintf(stderr,"[OK] %i networks read\n", j);
- } else {
- fprintf(stderr,"[ERR] Can't read networks.\n");
- exit(1);
- }
- }
-
- static void handle_signal(int sig) {
- if (!keep_running)
- return;
- rcvsig = sig;
- keep_running = 0;
- shutdown_fd(&config->server_socket);
- }
-
- int main(int argc, char **argv) {
- set_http_response_server_ident(server_sig, server_ver);
-
- printf("%s %s Git: %s\n", server_sig, server_ver, BUILD_ID);
- printf("%s\n\n", COPYRIGHT);
-
- restreamer = list_new("restreamer");
- clients = list_new("clients");
-
- memset(&allstats, 0, sizeof(allstats));
- allstats.start_ts = time(NULL);
- uname(&allstats.utsdata);
-
- memset(&TS_NULL_FRAME, 0xff, FRAME_PACKET_SIZE);
- int i;
- for (i=0; i<FRAME_PACKET_SIZE; i=i+188) {
- TS_NULL_FRAME[i+0] = 0x47;
- TS_NULL_FRAME[i+1] = 0x1f;
- TS_NULL_FRAME[i+2] = 0xff;
- TS_NULL_FRAME[i+3] = 0x00;
- }
-
- regcomp(&request_get, "^GET /([^ ]*) HTTP/1.*$", REG_EXTENDED);
- regcomp(&http_response, "^HTTP/1.[0-1] (([0-9]{3}) .*)", REG_EXTENDED);
-
- config = config_alloc();
- config_parse(config, argc, argv);
-
- init_channels();
- init_networks();
- init_server_socket(config->bind_to, config->server_port, &config->server_name, &config->server_socket);
- daemonize(config->pidfile);
-
- /* Must be called after daemonize! */
- log_init(config->logident, 0, config->pidfile == NULL, NULL, 0);
-
- /* Catch some signals */
- signal(SIGCHLD, SIG_IGN);
- signal(SIGPIPE, SIG_IGN);
- signal(SIGHUP, SIG_IGN);
- signal(SIGINT, handle_signal);
- signal(SIGTERM, handle_signal);
-
- LOGf("START: %s %s (%s)\n" , server_sig, server_ver, config->ident);
-
- while(keep_running) {
- struct sockaddr_in client;
- unsigned int clientlen = sizeof(client);
- int clientsock;
- clientsock = accept(config->server_socket, (struct sockaddr *) &client, &clientlen);
- if (clientsock < 0) {
- if (config->server_socket > -1 && errno != EINVAL) // The server_socket is closed on exit, so do not report errors
- LOGf("ERROR: Failed to accept client fd: %i err: %s\n", clientsock, strerror(errno));
- if (errno==EMFILE || errno==ENFILE) /* No more FDs */
- break;
- } else {
- request_info *req;
- pthread_t req_thread;
- req = malloc(sizeof(request_info));
- if (!req) {
- log_perror("Can't allocate request_info", errno);
- continue;
- }
- req->clientsock = clientsock;
- req->client = client;
- if (pthread_create(&req_thread, NULL, (void *)&process_request, (void *)req)) {
- log_perror("Error creating request processing thread.", errno);
- exit(1);
- }
- pthread_detach(req_thread);
- }
- }
-
- restreamer_stop_all(restreamer);
-
- LOGf("SHUTDOWN: Signal %i | %s %s (%s)\n", rcvsig, server_sig, server_ver, config->ident);
-
- if (clean_on_exit) {
- regfree(&http_response);
- regfree(&request_get);
- list_free(&restreamer, (void (*)(void *))free_restreamer, NULL);
- list_free(&clients, (void (*)(void *))stop_client_shutdown, NULL);
- list_free(&netconf, (void (*)(void *))free, NULL);
- list_free(&chanconf, (void (*)(void *))free_channel, NULL);
- }
-
- log_close();
-
- config_free(&config);
-
- exit(0);
- }
|