No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tsiproxy.c 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /* tsiproxy - mpeg transport stream proxy */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <string.h>
  6. #include <pthread.h>
  7. #include <errno.h>
  8. #include <signal.h>
  9. #include <regex.h>
  10. #include <arpa/inet.h>
  11. #include <netinet/in.h>
  12. #include <sys/types.h>
  13. #include <sys/socket.h>
  14. #include "libfuncs/libfuncs.h"
  15. #include "data.h"
  16. #include "conf.h"
  17. #include "request.h"
  18. char *server_sig = SERVER_SIGNATURE;
  19. char *server_ver = VERSION_ID;
  20. int keep_running = 1;
  21. int rcvsig = 0;
  22. int clean_on_exit = 0;
  23. CONFIG *config;
  24. regex_t request_get;
  25. regex_t http_response;
  26. STATS allstats;
  27. LIST *netconf = NULL;
  28. LIST *clients = NULL;
  29. LIST *chanconf = NULL;
  30. LIST *restreamer = NULL;
  31. char TS_NULL_FRAME[FRAME_PACKET_SIZE];
  32. static int usage_shown = 0;
  33. static void show_usage(void) {
  34. if (usage_shown)
  35. return;
  36. puts("Identification:");
  37. puts("");
  38. puts(" -i ident Streamer identification. Must be formated as PROVIDER/STREAMER");
  39. puts(" -c <channels_file> Channel definitions file");
  40. puts(" -n <networks_file> Network definitions file");
  41. puts("");
  42. puts("Server settings:");
  43. puts("");
  44. puts(" -b addr Local IP address to bind (Default: 0.0.0.0)");
  45. puts(" -p port Port to listen (Default: 8080)");
  46. puts(" -d pidfile Run in daemon mode and write PID file");
  47. puts("");
  48. puts("Stream settings:");
  49. puts("");
  50. puts(" -B Disable stream burst for new clients (usefull for master servers)");
  51. puts("");
  52. usage_shown = 1;
  53. }
  54. static void config_parse(CONFIG *conf, int argc, char **argv) {
  55. int j;
  56. conf->channels_file = "config.channels";
  57. conf->networks_file = "config.networks";
  58. while ((j = getopt(argc, argv, "TRBhXmvb:c:C:d:i:l:L:n:p:s:x:V:H:P:F")) != -1) {
  59. switch (j) {
  60. case 'b':
  61. conf->bind_to = optarg;
  62. break;
  63. case 'c':
  64. conf->channels_file = optarg;
  65. break;
  66. case 'd':
  67. conf->pidfile = optarg;
  68. break;
  69. case 'i':
  70. conf->ident = optarg;
  71. conf->logident = strdup(conf->ident);
  72. char *c = conf->logident;
  73. while (*c) {
  74. if (*c=='/')
  75. *c='-';
  76. c++;
  77. }
  78. break;
  79. case 'n':
  80. conf->networks_file = optarg;
  81. break;
  82. case 'T':
  83. conf->ts_sync = 1;
  84. break;
  85. case 'B':
  86. conf->disable_burst = 1;
  87. break;
  88. case 'p':
  89. conf->server_port = atoi(optarg);
  90. break;
  91. case 'F':
  92. clean_on_exit = 1;
  93. break;
  94. case 'h':
  95. show_usage();
  96. exit(1);
  97. break;
  98. }
  99. }
  100. int is_error = 0;
  101. if (!conf->ident) {
  102. show_usage();
  103. fprintf(stderr, "ERROR: Server ident is not set. Use '-i provider/streamer'\n");
  104. is_error++;
  105. }
  106. if (!conf->channels_file) {
  107. show_usage();
  108. fprintf(stderr, "ERROR: Channel definitions file is not set, use '-c channels_file'\n");
  109. is_error++;
  110. }
  111. if (!conf->networks_file) {
  112. show_usage();
  113. fprintf(stderr, "ERROR: Network definitions file is not set, use '-n networks_file'\n");
  114. is_error++;
  115. }
  116. if (is_error)
  117. exit(3);
  118. }
  119. static void init_channels(void) {
  120. /* Init channels */
  121. fputs("Reading channels map:\t\t",stderr);
  122. int j = load_channels(config);
  123. if (j != -1) {
  124. fprintf(stderr,"[OK] %i channels read\n", j);
  125. } else {
  126. fprintf(stderr,"[ERR] Can't read channels.\n");
  127. exit(1);
  128. }
  129. }
  130. static void init_networks(void) {
  131. /* Init networks */
  132. fputs("Reading networks ACL:\t\t",stderr);
  133. int j = load_networks(config);
  134. if (j != -1) {
  135. fprintf(stderr,"[OK] %i networks read\n", j);
  136. } else {
  137. fprintf(stderr,"[ERR] Can't read networks.\n");
  138. exit(1);
  139. }
  140. }
  141. static void handle_signal(int sig) {
  142. if (!keep_running)
  143. return;
  144. rcvsig = sig;
  145. keep_running = 0;
  146. shutdown_fd(&config->server_socket);
  147. }
  148. int main(int argc, char **argv) {
  149. set_http_response_server_ident(server_sig, server_ver);
  150. printf("%s %s Git: %s\n", server_sig, server_ver, BUILD_ID);
  151. printf("%s\n\n", COPYRIGHT);
  152. restreamer = list_new("restreamer");
  153. clients = list_new("clients");
  154. memset(&allstats, 0, sizeof(allstats));
  155. allstats.start_ts = time(NULL);
  156. uname(&allstats.utsdata);
  157. memset(&TS_NULL_FRAME, 0xff, FRAME_PACKET_SIZE);
  158. int i;
  159. for (i=0; i<FRAME_PACKET_SIZE; i=i+188) {
  160. TS_NULL_FRAME[i+0] = 0x47;
  161. TS_NULL_FRAME[i+1] = 0x1f;
  162. TS_NULL_FRAME[i+2] = 0xff;
  163. TS_NULL_FRAME[i+3] = 0x00;
  164. }
  165. regcomp(&request_get, "^GET /([^ ]*) HTTP/1.*$", REG_EXTENDED);
  166. regcomp(&http_response, "^HTTP/1.[0-1] (([0-9]{3}) .*)", REG_EXTENDED);
  167. config = config_alloc();
  168. config_parse(config, argc, argv);
  169. init_channels();
  170. init_networks();
  171. init_server_socket(config->bind_to, config->server_port, &config->server_name, &config->server_socket);
  172. daemonize(config->pidfile);
  173. /* Must be called after daemonize! */
  174. log_init(config->logident, 0, config->pidfile == NULL, NULL, 0);
  175. /* Catch some signals */
  176. signal(SIGCHLD, SIG_IGN);
  177. signal(SIGPIPE, SIG_IGN);
  178. signal(SIGHUP, SIG_IGN);
  179. signal(SIGINT, handle_signal);
  180. signal(SIGTERM, handle_signal);
  181. LOGf("START: %s %s (%s)\n" , server_sig, server_ver, config->ident);
  182. while(keep_running) {
  183. struct sockaddr_in client;
  184. unsigned int clientlen = sizeof(client);
  185. int clientsock;
  186. clientsock = accept(config->server_socket, (struct sockaddr *) &client, &clientlen);
  187. if (clientsock < 0) {
  188. if (config->server_socket > -1 && errno != EINVAL) // The server_socket is closed on exit, so do not report errors
  189. LOGf("ERROR: Failed to accept client fd: %i err: %s\n", clientsock, strerror(errno));
  190. if (errno==EMFILE || errno==ENFILE) /* No more FDs */
  191. break;
  192. } else {
  193. request_info *req;
  194. pthread_t req_thread;
  195. req = malloc(sizeof(request_info));
  196. if (!req) {
  197. log_perror("Can't allocate request_info", errno);
  198. continue;
  199. }
  200. req->clientsock = clientsock;
  201. req->client = client;
  202. if (pthread_create(&req_thread, NULL, (void *)&process_request, (void *)req)) {
  203. log_perror("Error creating request processing thread.", errno);
  204. exit(1);
  205. }
  206. pthread_detach(req_thread);
  207. }
  208. }
  209. restreamer_stop_all(restreamer);
  210. LOGf("SHUTDOWN: Signal %i | %s %s (%s)\n", rcvsig, server_sig, server_ver, config->ident);
  211. if (clean_on_exit) {
  212. regfree(&http_response);
  213. regfree(&request_get);
  214. list_free(&restreamer, (void (*)(void *))free_restreamer, NULL);
  215. list_free(&clients, (void (*)(void *))stop_client_shutdown, NULL);
  216. list_free(&netconf, (void (*)(void *))free, NULL);
  217. list_free(&chanconf, (void (*)(void *))free_channel, NULL);
  218. }
  219. log_close();
  220. config_free(&config);
  221. exit(0);
  222. }