/* tsiproxy - mpeg transport stream proxy */ #include #include #include #include #include #include #include #include #include #include #include #include #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 Channel definitions file"); puts(" -n 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; ibind_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); }