util: fix potential buffer overflow
[dvblast.git] / dvblast.c
bloba1ce8bd75a8d8227c546252089e0cf54509cbae6
1 /*****************************************************************************
2 * dvblast.c
3 *****************************************************************************
4 * Copyright (C) 2004, 2008-2011, 2015 VideoLAN
6 * Authors: Christophe Massiot <massiot@via.ecp.fr>
7 * Andy Gatward <a.j.gatward@reading.ac.uk>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <stdint.h>
28 #include <inttypes.h>
29 #include <stdbool.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <pthread.h>
33 #include <netdb.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <signal.h>
38 #include <getopt.h>
39 #include <errno.h>
41 #include <ev.h>
43 #include "dvblast.h"
45 #ifdef HAVE_ICONV
46 #include <iconv.h>
47 #endif
49 #include <bitstream/dvb/si.h>
50 #include <bitstream/ietf/rtp.h>
52 #include "mrtg-cnt.h"
54 /*****************************************************************************
55 * Local declarations
56 *****************************************************************************/
57 struct ev_loop *event_loop;
58 output_t **pp_outputs = NULL;
59 int i_nb_outputs = 0;
60 output_t output_dup;
61 bool b_passthrough = false;
62 static const char *psz_conf_file = NULL;
63 char *psz_srv_socket = NULL;
64 static int i_priority = -1;
65 int i_adapter = 0;
66 int i_fenum = 0;
67 int i_canum = 0;
68 char *psz_delsys = NULL;
69 int i_frequency = 0;
70 char *psz_lnb_type = "universal";
71 int dvb_plp_id = 0;
72 int i_inversion = -1;
73 int i_srate = 27500000;
74 int i_fec = 999;
75 int i_rolloff = 35;
76 int i_satnum = 0;
77 int i_uncommitted = 0;
78 int i_voltage = 13;
79 int b_tone = 0;
80 int i_bandwidth = 8;
81 char *psz_modulation = NULL;
82 int i_pilot = -1;
83 int i_mis = 0;
84 char *psz_mis_pls_mode = "ROOT";
85 int i_mis_pls_mode = 0;
86 int i_mis_pls_code = 0;
87 int i_mis_is_id = 0;
88 int i_fec_lp = 999;
89 int i_guard = -1;
90 int i_transmission = -1;
91 int i_hierarchy = -1;
92 mtime_t i_frontend_timeout_duration = DEFAULT_FRONTEND_TIMEOUT;
93 mtime_t i_quit_timeout_duration = 0;
94 int b_budget_mode = 0;
95 int b_any_type = 0;
96 int b_select_pmts = 0;
97 int b_random_tsid = 0;
98 char *psz_udp_src = NULL;
99 int i_asi_adapter = 0;
100 const char *psz_native_charset = "UTF-8//IGNORE";
101 print_type_t i_print_type = PRINT_TEXT;
102 bool b_print_enabled = false;
103 FILE *print_fh;
104 mtime_t i_print_period = 0;
105 mtime_t i_es_timeout = 0;
107 int i_verbose = DEFAULT_VERBOSITY;
108 int i_syslog = 0;
109 char *psz_syslog_ident = NULL;
111 bool b_enable_emm = false;
112 bool b_enable_ecm = false;
114 uint8_t pi_ssrc_global[4] = { 0, 0, 0, 0 };
115 static bool b_udp_global = false;
116 static bool b_dvb_global = false;
117 static bool b_epg_global = false;
118 static mtime_t i_latency_global = DEFAULT_OUTPUT_LATENCY;
119 static mtime_t i_retention_global = DEFAULT_MAX_RETENTION;
120 static int i_ttl_global = 64;
122 static const char *psz_dvb_charset = "UTF-8//IGNORE";
123 static iconv_t conf_iconv = (iconv_t)-1;
124 static uint16_t i_network_id = 0xffff;
125 static dvb_string_t network_name;
126 static dvb_string_t provider_name;
128 /* TPS Input log filename */
129 char * psz_mrtg_file = NULL;
131 /* PID mapping */
132 bool b_do_remap = false;
133 uint16_t pi_newpids[ N_MAP_PIDS ]; /* pmt, audio, video, spu */
135 void (*pf_Open)( void ) = NULL;
136 void (*pf_Reset)( void ) = NULL;
137 int (*pf_SetFilter)( uint16_t i_pid ) = NULL;
138 void (*pf_UnsetFilter)( int i_fd, uint16_t i_pid ) = NULL;
140 /*****************************************************************************
141 * Configuration files
142 *****************************************************************************/
143 void config_Init( output_config_t *p_config )
145 memset( p_config, 0, sizeof(output_config_t) );
147 p_config->psz_displayname = NULL;
148 p_config->i_network_id = i_network_id;
149 dvb_string_init(&p_config->network_name);
150 dvb_string_init(&p_config->service_name);
151 dvb_string_init(&p_config->provider_name);
152 p_config->psz_srcaddr = NULL;
154 p_config->i_family = AF_UNSPEC;
155 p_config->connect_addr.ss_family = AF_UNSPEC;
156 p_config->bind_addr.ss_family = AF_UNSPEC;
157 p_config->i_if_index_v6 = -1;
158 p_config->i_srcport = 0;
160 p_config->pi_pids = NULL;
161 p_config->b_passthrough = false;
162 p_config->b_do_remap = false;
163 unsigned int i;
164 for ( i = 0; i < N_MAP_PIDS; i++ ) {
165 p_config->pi_confpids[i] = UNUSED_PID;
169 void config_Free( output_config_t *p_config )
171 free( p_config->psz_displayname );
172 dvb_string_clean( &p_config->network_name );
173 dvb_string_clean( &p_config->service_name );
174 dvb_string_clean( &p_config->provider_name );
175 free( p_config->pi_pids );
176 free( p_config->psz_srcaddr );
179 static void config_Defaults( output_config_t *p_config )
181 config_Init( p_config );
183 p_config->i_config = (b_udp_global ? OUTPUT_UDP : 0) |
184 (b_dvb_global ? OUTPUT_DVB : 0) |
185 (b_epg_global ? OUTPUT_EPG : 0);
186 p_config->i_max_retention = i_retention_global;
187 p_config->i_output_latency = i_latency_global;
188 p_config->i_tsid = -1;
189 p_config->i_ttl = i_ttl_global;
190 memcpy( p_config->pi_ssrc, pi_ssrc_global, 4 * sizeof(uint8_t) );
191 dvb_string_copy(&p_config->network_name, &network_name);
192 dvb_string_copy(&p_config->provider_name, &provider_name);
195 char *config_stropt( const char *psz_string )
197 char *ret, *tmp;
198 if ( !psz_string || strlen( psz_string ) == 0 )
199 return NULL;
200 ret = tmp = strdup( psz_string );
201 while (*tmp) {
202 if (*tmp == '_')
203 *tmp = ' ';
204 if (*tmp == '/') {
205 *tmp = '\0';
206 break;
208 tmp++;
210 return ret;
213 static uint8_t *config_striconv( const char *psz_string,
214 const char *psz_charset, size_t *pi_length )
216 char *psz_input = config_stropt(psz_string);
217 *pi_length = strlen(psz_input);
219 /* do not convert ASCII strings */
220 const char *c = psz_string;
221 while (*c)
222 if (!isascii(*c++))
223 break;
224 if (!*c)
225 return (uint8_t *)psz_input;
227 if ( !strcasecmp( psz_native_charset, psz_charset ) )
228 return (uint8_t *)psz_input;
230 #ifdef HAVE_ICONV
231 if ( conf_iconv == (iconv_t)-1 )
233 conf_iconv = iconv_open( psz_charset, psz_native_charset );
234 if ( conf_iconv == (iconv_t)-1 )
235 return (uint8_t *)psz_input;
238 char *psz_tmp = psz_input;
239 size_t i_input = *pi_length;
240 size_t i_output = i_input * 6;
241 size_t i_available = i_output;
242 char *p_output = malloc( i_output );
243 char *p = p_output;
244 if ( iconv( conf_iconv, &psz_tmp, &i_input, &p, &i_available ) == -1 )
246 free( p_output );
248 return (uint8_t *)psz_input;
251 free(psz_input);
252 *pi_length = i_output - i_available;
253 return (uint8_t *)p_output;
254 #else
255 msg_Warn( NULL,
256 "unable to convert from %s to %s (iconv is not available)",
257 psz_native_charset, psz_charset );
258 return (uint8_t *)psz_input;
259 #endif
262 static void config_strdvb( dvb_string_t *p_dvb_string, const char *psz_string,
263 const char *psz_charset )
265 if (psz_string == NULL)
267 dvb_string_init(p_dvb_string);
268 return;
270 dvb_string_clean(p_dvb_string);
272 size_t i_iconv;
273 uint8_t *p_iconv = config_striconv(psz_string, psz_charset, &i_iconv);
274 p_dvb_string->p = dvb_string_set(p_iconv, i_iconv, psz_charset,
275 &p_dvb_string->i);
276 free(p_iconv);
279 static bool config_ParseHost( output_config_t *p_config, char *psz_string )
281 struct addrinfo *p_ai;
282 int i_mtu;
284 p_config->psz_displayname = strdup( psz_string );
286 p_ai = ParseNodeService( psz_string, &psz_string, DEFAULT_PORT );
287 if ( p_ai == NULL ) return false;
288 memcpy( &p_config->connect_addr, p_ai->ai_addr, p_ai->ai_addrlen );
289 freeaddrinfo( p_ai );
291 p_config->i_family = p_config->connect_addr.ss_family;
292 if ( p_config->i_family == AF_UNSPEC ) return false;
294 if ( psz_string == NULL || !*psz_string ) goto end;
296 if ( *psz_string == '@' )
298 psz_string++;
299 p_ai = ParseNodeService( psz_string, &psz_string, 0 );
300 if ( p_ai == NULL || p_ai->ai_family != p_config->i_family )
301 msg_Warn( NULL, "invalid bind address" );
302 else
303 memcpy( &p_config->bind_addr, p_ai->ai_addr, p_ai->ai_addrlen );
304 freeaddrinfo( p_ai );
307 const char *psz_charset = psz_dvb_charset;
308 const char *psz_network_name = NULL;
309 const char *psz_service_name = NULL;
310 const char *psz_provider_name = NULL;
312 while ( (psz_string = strchr( psz_string, '/' )) != NULL )
314 *psz_string++ = '\0';
316 #define IS_OPTION( option ) (!strncasecmp( psz_string, option, strlen(option) ))
317 #define ARG_OPTION( option ) (psz_string + strlen(option))
319 if ( IS_OPTION("udp") )
320 p_config->i_config |= OUTPUT_UDP;
321 else if ( IS_OPTION("dvb") )
322 p_config->i_config |= OUTPUT_DVB;
323 else if ( IS_OPTION("epg") )
324 p_config->i_config |= OUTPUT_EPG;
325 else if ( IS_OPTION("tsid=") )
326 p_config->i_tsid = strtol( ARG_OPTION("tsid="), NULL, 0 );
327 else if ( IS_OPTION("retention=") )
328 p_config->i_max_retention = strtoll( ARG_OPTION("retention="),
329 NULL, 0 ) * 1000;
330 else if ( IS_OPTION("latency=") )
331 p_config->i_output_latency = strtoll( ARG_OPTION("latency="),
332 NULL, 0 ) * 1000;
333 else if ( IS_OPTION("ttl=") )
334 p_config->i_ttl = strtol( ARG_OPTION("ttl="), NULL, 0 );
335 else if ( IS_OPTION("tos=") )
336 p_config->i_tos = strtol( ARG_OPTION("tos="), NULL, 0 );
337 else if ( IS_OPTION("mtu=") )
338 p_config->i_mtu = strtol( ARG_OPTION("mtu="), NULL, 0 );
339 else if ( IS_OPTION("ifindex=") )
340 p_config->i_if_index_v6 = strtol( ARG_OPTION("ifindex="), NULL, 0 );
341 else if ( IS_OPTION("networkid=") )
342 p_config->i_network_id = strtol( ARG_OPTION("networkid="), NULL, 0 );
343 else if ( IS_OPTION("onid=") )
344 p_config->i_onid = strtol( ARG_OPTION("onid="), NULL, 0 );
345 else if ( IS_OPTION("charset=") )
346 psz_charset = ARG_OPTION("charset=");
347 else if ( IS_OPTION("networkname=") )
348 psz_network_name = ARG_OPTION("networkname=");
349 else if ( IS_OPTION("srvname=") )
350 psz_service_name = ARG_OPTION("srvname=");
351 else if ( IS_OPTION("srvprovider=") )
352 psz_provider_name = ARG_OPTION("srvprovider=");
353 else if ( IS_OPTION("srcaddr=") )
355 if ( p_config->i_family != AF_INET ) {
356 msg_Err( NULL, "RAW sockets currently implemented for ipv4 only");
357 return false;
359 free( p_config->psz_srcaddr );
360 p_config->psz_srcaddr = config_stropt( ARG_OPTION("srcaddr=") );
361 p_config->i_config |= OUTPUT_RAW;
363 else if ( IS_OPTION("srcport=") )
364 p_config->i_srcport = strtol( ARG_OPTION("srcport="), NULL, 0 );
365 else if ( IS_OPTION("ssrc=") )
367 in_addr_t i_addr = inet_addr( ARG_OPTION("ssrc=") );
368 memcpy( p_config->pi_ssrc, &i_addr, 4 * sizeof(uint8_t) );
370 else if ( IS_OPTION("pidmap=") )
372 char *str1;
373 char *saveptr = NULL;
374 char *tok = NULL;
375 int i, i_newpid;
376 for (i = 0, str1 = config_stropt( (ARG_OPTION("pidmap="))); i < N_MAP_PIDS; i++, str1 = NULL)
378 tok = strtok_r(str1, ",", &saveptr);
379 if ( !tok )
380 break;
381 i_newpid = strtoul(tok, NULL, 0);
382 p_config->pi_confpids[i] = i_newpid;
384 p_config->b_do_remap = true;
386 else if ( IS_OPTION("newsid=") )
387 p_config->i_new_sid = strtol( ARG_OPTION("newsid="), NULL, 0 );
388 else
389 msg_Warn( NULL, "unrecognized option %s", psz_string );
391 #undef IS_OPTION
392 #undef ARG_OPTION
395 if (psz_network_name != NULL)
396 config_strdvb( &p_config->network_name, psz_network_name, psz_charset );
397 if (psz_service_name != NULL)
398 config_strdvb( &p_config->service_name, psz_service_name, psz_charset );
399 if (psz_provider_name != NULL)
400 config_strdvb( &p_config->provider_name, psz_provider_name,
401 psz_charset );
403 end:
404 i_mtu = p_config->i_family == AF_INET6 ? DEFAULT_IPV6_MTU :
405 DEFAULT_IPV4_MTU;
407 if ( !p_config->i_mtu )
408 p_config->i_mtu = i_mtu;
409 else if ( p_config->i_mtu < TS_SIZE + RTP_HEADER_SIZE )
411 msg_Warn( NULL, "invalid MTU %d, setting %d", p_config->i_mtu, i_mtu );
412 p_config->i_mtu = i_mtu;
415 return true;
418 static void config_Print( output_config_t *p_config )
420 if ( p_config->b_passthrough )
422 msg_Dbg( NULL, "conf: %s config=0x%"PRIx64" sid=*",
423 p_config->psz_displayname, p_config->i_config);
424 return;
427 const char *psz_base = "conf: %s config=0x%"PRIx64" sid=%hu pids[%d]=";
428 size_t i_len = strlen(psz_base) + 6 * p_config->i_nb_pids + 1;
429 char psz_format[i_len];
430 int i, j = strlen(psz_base);
432 strcpy( psz_format, psz_base );
433 for ( i = 0; i < p_config->i_nb_pids; i++ )
434 j += sprintf( psz_format + j, "%u,", p_config->pi_pids[i] );
435 psz_format[j - 1] = '\0';
437 msg_Dbg( NULL, psz_format, p_config->psz_displayname, p_config->i_config,
438 p_config->i_sid, p_config->i_nb_pids );
441 void config_ReadFile(void)
443 FILE *p_file;
444 char psz_line[2048];
445 int i;
447 if ( psz_conf_file == NULL )
449 msg_Err( NULL, "no config file" );
450 return;
453 if ( (p_file = fopen( psz_conf_file, "r" )) == NULL )
455 msg_Err( NULL, "can't fopen config file %s", psz_conf_file );
456 return;
459 while ( fgets( psz_line, sizeof(psz_line), p_file ) != NULL )
461 output_config_t config;
462 output_t *p_output;
463 char *psz_token, *psz_parser;
465 psz_parser = strchr( psz_line, '#' );
466 if ( psz_parser != NULL )
467 *psz_parser-- = '\0';
468 while ( psz_parser >= psz_line && isblank( *psz_parser ) )
469 *psz_parser-- = '\0';
470 if ( psz_line[0] == '\0' )
471 continue;
473 config_Defaults( &config );
475 psz_token = strtok_r( psz_line, "\t\n ", &psz_parser );
476 if ( psz_token == NULL || !config_ParseHost( &config, psz_token ))
478 config_Free( &config );
479 continue;
482 psz_token = strtok_r( NULL, "\t\n ", &psz_parser );
483 if ( psz_token == NULL )
485 config_Free( &config );
486 continue;
488 if( atoi( psz_token ) == 1 )
489 config.i_config |= OUTPUT_WATCH;
490 else
491 config.i_config &= ~OUTPUT_WATCH;
493 psz_token = strtok_r( NULL, "\t\n ", &psz_parser );
494 if ( psz_token == NULL )
496 config_Free( &config );
497 continue;
500 if ( psz_token[0] == '*' )
502 config.b_passthrough = true;
504 else
506 config.i_sid = strtol(psz_token, NULL, 0);
508 psz_token = strtok_r( NULL, "\t\n ", &psz_parser );
509 if ( psz_token != NULL )
511 psz_parser = NULL;
512 for ( ; ; )
514 psz_token = strtok_r( psz_token, ",", &psz_parser );
515 if ( psz_token == NULL )
516 break;
517 config.pi_pids = realloc( config.pi_pids,
518 (config.i_nb_pids + 1) * sizeof(uint16_t) );
519 config.pi_pids[config.i_nb_pids++] = strtol(psz_token, NULL, 0);
520 psz_token = NULL;
525 config_Print( &config );
527 p_output = output_Find( &config );
529 if ( p_output == NULL )
530 p_output = output_Create( &config );
532 if ( p_output != NULL )
534 free( p_output->config.psz_displayname );
535 p_output->config.psz_displayname = strdup( config.psz_displayname );
537 config.i_config |= OUTPUT_VALID | OUTPUT_STILL_PRESENT;
538 output_Change( p_output, &config );
539 demux_Change( p_output, &config );
542 config_Free( &config );
545 fclose( p_file );
547 for ( i = 0; i < i_nb_outputs; i++ )
549 output_t *p_output = pp_outputs[i];
550 output_config_t config;
552 config_Init( &config );
554 if ( (p_output->config.i_config & OUTPUT_VALID) &&
555 !(p_output->config.i_config & OUTPUT_STILL_PRESENT) )
557 msg_Dbg( NULL, "closing %s", p_output->config.psz_displayname );
558 demux_Change( p_output, &config );
559 output_Close( p_output );
562 p_output->config.i_config &= ~OUTPUT_STILL_PRESENT;
563 config_Free( &config );
567 /*****************************************************************************
568 * Signal Handler
569 *****************************************************************************/
570 static void signal_watcher_init(struct ev_signal *w, struct ev_loop *loop,
571 void (*cb)(struct ev_loop*, struct ev_signal*, int),
572 int signum)
574 ev_signal_init(w, cb, signum);
575 ev_signal_start(loop, w);
576 ev_unref(loop);
579 static void sighandler(struct ev_loop *loop, struct ev_signal *w, int revents)
581 switch (w->signum)
583 case SIGINT:
584 case SIGTERM:
585 default:
586 msg_Info( NULL, "Shutdown was requested." );
587 ev_break(loop, EVBREAK_ALL);
588 break;
590 case SIGHUP:
591 msg_Info( NULL, "Configuration reload was requested." );
592 config_ReadFile();
593 break;
597 /*****************************************************************************
598 * Quit timeout
599 *****************************************************************************/
600 static void quit_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
602 ev_break(loop, EVBREAK_ALL);
605 /*****************************************************************************
606 * Version
607 *****************************************************************************/
608 static void DisplayVersion()
610 msg_Raw( NULL, "DVBlast %s (%s)", VERSION, VERSION_EXTRA );
613 /*****************************************************************************
614 * Entry point
615 *****************************************************************************/
616 void usage()
618 DisplayVersion();
619 msg_Raw( NULL, "Usage: dvblast [-q] [-c <config file>] [-r <remote socket>] [-t <ttl>] [-o <SSRC IP>] "
620 "[-i <RT priority>] "
621 #ifdef HAVE_ASI_SUPPORT
622 "[-A <ASI adapter>]"
623 #endif
624 #ifdef HAVE_DVB_SUPPORT
625 "[-a <adapter>] [-n <frontend number>] [-S <diseqc>] [-k <uncommitted port>]"
626 "[-f <frequency>]"
627 "[-s <symbol rate>] [-v <0|13|18>] [-p] [-b <bandwidth>] [-I <inversion>] "
628 "[-F <fec inner>] [-m <modulation] [-R <rolloff>] [-P <pilot>] [-K <fec lp>] "
629 "[-G <guard interval>] [-H <hierarchy>] [-X <transmission>] [-O <lock timeout>] "
630 #endif
631 "[-D [<src host>[:<src port>]@]<src mcast>[:<port>][/<opts>]*] "
632 "[-u] [-w] [-U] [-L <latency>] [-E <retention>] [-d <dest IP>[<:port>][/<opts>]*] [-3] "
633 "[-z] [-C [-e] [-M <network name>] [-N <network ID>]] [-T] [-j <system charset>] "
634 "[-W] [-Y] [-l] [-g <logger ident>] [-Z <mrtg file>] [-V] [-h] [-B <provider_name>] "
635 "[-1 <mis_id>] [-2 <size>] [-5 <DVBS|DVBS2|DVBC_ANNEX_A|DVBC_ANNEX_B|DVBT|DVBT2|ATSC|ISDBT>] -y <ca_dev_number> "
636 "[-J <DVB charset>] [-Q <quit timeout>] [-0 pid_mapping] [-x <text|xml>]"
637 "[-6 <print period>] [-7 <ES timeout>]" );
639 msg_Raw( NULL, "Input:" );
640 #ifdef HAVE_ASI_SUPPORT
641 msg_Raw( NULL, " -A --asi-adapter read packets from an ASI adapter (0-n)" );
642 #endif
643 #ifdef HAVE_DVB_SUPPORT
644 msg_Raw( NULL, " -a --adapter read packets from a Linux-DVB adapter (typically 0-n)" );
645 msg_Raw( NULL, " -b --bandwidth frontend bandwidth" );
646 #endif
647 msg_Raw( NULL, " -D --rtp-input read packets from a multicast address instead of a DVB card" );
648 #ifdef HAVE_DVB_SUPPORT
649 msg_Raw( NULL, " -5 --delsys delivery system" );
650 msg_Raw( NULL, " DVBS|DVBS2|DVBC_ANNEX_A|DVBT|DVBT2|ATSC|ISDBT|DVBC_ANNEX_B(ATSC-C/QAMB) (default guessed)");
651 msg_Raw( NULL, " -f --frequency frontend frequency" );
652 msg_Raw( NULL, " -8 --lnb-type <type> Set LNB type')" );
653 msg_Raw( NULL, " universal old-sky (default: universal)");
654 msg_Raw( NULL, " -9 --dvb-plp-id <number> Switch PLP of the DVB-T2 transmission (default: 0)" );
655 msg_Raw( NULL, " -F --fec-inner Forward Error Correction (FEC Inner)");
656 msg_Raw( NULL, " DVB-S2 0|12|23|34|35|56|78|89|910|999 (default auto: 999)");
657 msg_Raw( NULL, " -I --inversion Inversion (-1 auto, 0 off, 1 on)" );
658 msg_Raw( NULL, " -m --modulation Modulation type" );
659 msg_Raw( NULL, " DVB-C qpsk|qam_16|qam_32|qam_64|qam_128|qam_256 (default qam_auto)" );
660 msg_Raw( NULL, " DVB-T qam_16|qam_32|qam_64|qam_128|qam_256 (default qam_auto)" );
661 msg_Raw( NULL, " DVB-S2 qpsk|psk_8|apsk_16|apsk_32 (default legacy DVB-S)" );
662 msg_Raw( NULL, " -n --frontend-number <frontend number>" );
663 msg_Raw( NULL, " -p --force-pulse force 22kHz pulses for high-band selection (DVB-S)" );
664 msg_Raw( NULL, " -P --pilot DVB-S2 Pilot (-1 auto, 0 off, 1 on)" );
665 msg_Raw( NULL, " -R --rolloff DVB-S2 Rolloff value" );
666 msg_Raw( NULL, " DVB-S2 35=0.35|25=0.25|20=0.20|0=AUTO (default: 35)" );
667 msg_Raw( NULL, " -1 --multistream-id Set stream ID (0-2147483648, default: 0)." );
668 msg_Raw( NULL, " --multistream-id-pls-mode Set multistream PLS mode (ROOT, GOLD, COMBO, default: ROOT)" );
669 msg_Raw( NULL, " --multistream-id-pls-code Set multistream PLS code (0-262143, default: 0)" );
670 msg_Raw( NULL, " --multistream-id-is-id Set multistream IS id (0-255, default: 0)" );
671 msg_Raw( NULL, " -K --fec-lp DVB-T low priority FEC (default auto)" );
672 msg_Raw( NULL, " -G --guard DVB-T guard interval" );
673 msg_Raw( NULL, " DVB-T 32 (1/32)|16 (1/16)|8 (1/8)|4 (1/4)|-1 (auto, default)" );
674 msg_Raw( NULL, " -H --hierarchy DVB-T hierarchy (0, 1, 2, 4 or -1 auto, default)" );
675 msg_Raw( NULL, " -X --transmission DVB-T transmission (2, 4, 8 or -1 auto, default)" );
676 msg_Raw( NULL, " -s --symbol-rate" );
677 msg_Raw( NULL, " -S --diseqc satellite number for diseqc (0: no diseqc, 1-4, A or B)" );
678 msg_Raw( NULL, " -k --uncommitted port number for uncommitted DiSEqC switch (0: no uncommitted DiSEqC switch, 1-16)" );
679 msg_Raw( NULL, " -u --budget-mode turn on budget mode (no hardware PID filtering)" );
680 msg_Raw( NULL, " -v --voltage voltage to apply to the LNB (QPSK)" );
681 msg_Raw( NULL, " -w --select-pmts set a PID filter on all PMTs (auto on, when config file is used)" );
682 msg_Raw( NULL, " -O --lock-timeout timeout for the lock operation (in ms)" );
683 msg_Raw( NULL, " -y --ca-number <ca_device_number>" );
684 msg_Raw( NULL, " -2 --dvr-buf-size <size> set the size of the DVR TS buffer in bytes (default: %d)", i_dvr_buffer_size);
685 #endif
687 msg_Raw( NULL, "Output:" );
688 msg_Raw( NULL, " -c --config-file <config file>" );
689 msg_Raw( NULL, " -C --dvb-compliance pass through or build the mandatory DVB tables" );
690 msg_Raw( NULL, " -d --duplicate duplicate all received packets to a given destination" );
691 msg_Raw( NULL, " -3 --passthrough duplicate all received packets to stdout" );
692 msg_Raw( NULL, " -W --emm-passthrough pass through EMM data (CA system data)" );
693 msg_Raw( NULL, " -Y --ecm-passthrough pass through ECM data (CA program data)" );
694 msg_Raw( NULL, " -e --epg-passthrough pass through DVB EIT schedule tables" );
695 msg_Raw( NULL, " -E --retention maximum retention allowed between input and output (default: 40 ms)" );
696 msg_Raw( NULL, " -L --latency maximum latency allowed between input and output (default: 100 ms)" );
697 msg_Raw( NULL, " -M --network-name DVB network name to declare in the NIT" );
698 msg_Raw( NULL, " -N --network-id DVB network ID to declare in the NIT" );
699 msg_Raw( NULL, " -B --provider-name Service provider name to declare in the SDT" );
700 msg_Raw( NULL, " -o --rtp-output <SSRC IP>" );
701 msg_Raw( NULL, " -t --ttl <ttl> TTL of the output stream" );
702 msg_Raw( NULL, " -T --unique-ts-id generate random unique TS ID for each output" );
703 msg_Raw( NULL, " -U --udp use raw UDP rather than RTP (required by some IPTV set top boxes)" );
704 msg_Raw( NULL, " -z --any-type pass through all ESs from the PMT, of any type" );
705 msg_Raw( NULL, " -0 --pidmap <pmt_pid,audio_pid,video_pid,spu_pid>");
707 msg_Raw( NULL, "Misc:" );
708 msg_Raw( NULL, " -h --help display this full help" );
709 msg_Raw( NULL, " -i --priority <RT priority>" );
710 msg_Raw( NULL, " -j --system-charset character set used for printing messages (default UTF-8//IGNORE)" );
711 msg_Raw( NULL, " -J --dvb-charset character set used in output DVB tables (default UTF-8//IGNORE)" );
712 msg_Raw( NULL, " -l --logger use syslog for logging messages instead of stderr" );
713 msg_Raw( NULL, " -g --logger-ident program name that will be used in syslog messages" );
714 msg_Raw( NULL, " -x --print print interesting events on stdout in a given format" );
715 msg_Raw( NULL, " -q --quiet be quiet (less verbosity, repeat or use number for even quieter)" );
716 msg_Raw( NULL, " -Q --quit-timeout when locked, quit after this delay (in ms), or after the first lock timeout" );
717 msg_Raw( NULL, " -6 --print-period periodicity at which we print bitrate and errors (in ms)" );
718 msg_Raw( NULL, " -7 --es-timeout time of inactivy before which a PID is reported down (in ms)" );
719 msg_Raw( NULL, " -r --remote-socket <remote socket>" );
720 msg_Raw( NULL, " -Z --mrtg-file <file> Log input packets and errors into mrtg-file" );
721 msg_Raw( NULL, " -V --version only display the version" );
722 exit(1);
725 int main( int i_argc, char **pp_argv )
727 const char *psz_network_name = "DVBlast - videolan.org";
728 const char *psz_provider_name = NULL;
729 char *psz_dup_config = NULL;
730 struct sched_param param;
731 int i_error;
732 int c;
733 int b_enable_syslog = 0;
734 struct ev_signal sigint_watcher, sigterm_watcher, sighup_watcher;
735 struct ev_timer quit_watcher;
737 print_fh = stdout;
739 if ( i_argc == 1 )
740 usage();
743 * The only short options left are: 4
744 * Use them wisely.
746 static const struct option long_options[] =
748 { "config-file", required_argument, NULL, 'c' },
749 { "remote-socket", required_argument, NULL, 'r' },
750 { "ttl", required_argument, NULL, 't' },
751 { "rtp-output", required_argument, NULL, 'o' },
752 { "priority", required_argument, NULL, 'i' },
753 { "adapter", required_argument, NULL, 'a' },
754 { "frontend-number", required_argument, NULL, 'n' },
755 { "delsys", required_argument, NULL, '5' },
756 { "dvb-plp-id", required_argument, NULL, '9' },
757 { "frequency", required_argument, NULL, 'f' },
758 { "lnb-type", required_argument, NULL, '8' },
759 { "fec-inner", required_argument, NULL, 'F' },
760 { "rolloff", required_argument, NULL, 'R' },
761 { "symbol-rate", required_argument, NULL, 's' },
762 { "diseqc", required_argument, NULL, 'S' },
763 { "uncommitted", required_argument, NULL, 'k' },
764 { "voltage", required_argument, NULL, 'v' },
765 { "force-pulse", no_argument, NULL, 'p' },
766 { "bandwidth", required_argument, NULL, 'b' },
767 { "inversion", required_argument, NULL, 'I' },
768 { "modulation", required_argument, NULL, 'm' },
769 { "pilot", required_argument, NULL, 'P' },
770 { "multistream-id", required_argument, NULL, '1' },
771 { "multistream-id-pls-mode", required_argument, NULL, 0x100001 },
772 { "multistream-id-pls-code", required_argument, NULL, 0x100002 },
773 { "multistream-id-is-id" , required_argument, NULL, 0x100003 },
774 { "fec-lp", required_argument, NULL, 'K' },
775 { "guard", required_argument, NULL, 'G' },
776 { "hierarchy", required_argument, NULL, 'H' },
777 { "transmission", required_argument, NULL, 'X' },
778 { "lock-timeout", required_argument, NULL, 'O' },
779 { "budget-mode", no_argument, NULL, 'u' },
780 { "select-pmts", no_argument, NULL, 'w' },
781 { "udp", no_argument, NULL, 'U' },
782 { "unique-ts-id", no_argument, NULL, 'T' },
783 { "latency", required_argument, NULL, 'L' },
784 { "retention", required_argument, NULL, 'E' },
785 { "duplicate", required_argument, NULL, 'd' },
786 { "passthrough", no_argument, NULL, '3' },
787 { "rtp-input", required_argument, NULL, 'D' },
788 { "asi-adapter", required_argument, NULL, 'A' },
789 { "any-type", no_argument, NULL, 'z' },
790 { "dvb-compliance", no_argument, NULL, 'C' },
791 { "emm-passthrough", no_argument, NULL, 'W' },
792 { "ecm-passthrough", no_argument, NULL, 'Y' },
793 { "epg-passthrough", no_argument, NULL, 'e' },
794 { "network-name", no_argument, NULL, 'M' },
795 { "network-id", no_argument, NULL, 'N' },
796 { "system-charset", required_argument, NULL, 'j' },
797 { "dvb-charset", required_argument, NULL, 'J' },
798 { "provider-name", required_argument, NULL, 'B' },
799 { "logger", no_argument, NULL, 'l' },
800 { "logger-ident", required_argument, NULL, 'g' },
801 { "print", required_argument, NULL, 'x' },
802 { "quit-timeout", required_argument, NULL, 'Q' },
803 { "print-period", required_argument, NULL, '6' },
804 { "es-timeout", required_argument, NULL, '7' },
805 { "quiet", no_argument, NULL, 'q' },
806 { "help", no_argument, NULL, 'h' },
807 { "version", no_argument, NULL, 'V' },
808 { "mrtg-file", required_argument, NULL, 'Z' },
809 { "ca-number", required_argument, NULL, 'y' },
810 { "pidmap", required_argument, NULL, '0' },
811 { "dvr-buf-size", required_argument, NULL, '2' },
812 { 0, 0, 0, 0 }
815 while ( (c = getopt_long(i_argc, pp_argv, "q::c:r:t:o:i:a:n:5:f:F:R:s:S:k:v:pb:I:m:P:K:G:H:X:O:uwUTL:E:d:3D:A:lg:zCWYeM:N:j:J:B:x:Q:6:7:hVZ:y:0:1:2:9:", long_options, NULL)) != -1 )
817 switch ( c )
819 case 'q':
820 if ( optarg )
822 if ( *optarg == 'q' ) /* e.g. -qqq */
824 i_verbose--;
825 while ( *optarg == 'q' )
827 i_verbose--;
828 optarg++;
831 else
833 i_verbose -= atoi( optarg ); /* e.g. -q2 */
836 else
838 i_verbose--; /* -q */
840 break;
842 case 'c':
843 psz_conf_file = optarg;
845 * When configuration file is used it is reasonable to assume that
846 * services may be added/removed. If b_select_pmts is not set dvblast
847 * is unable to start streaming newly added services in the config.
849 b_select_pmts = 1;
850 break;
852 case 'r':
853 psz_srv_socket = optarg;
854 break;
856 case 't':
857 i_ttl_global = strtol( optarg, NULL, 0 );
858 break;
860 case 'o':
862 struct in_addr maddr;
863 if ( !inet_aton( optarg, &maddr ) )
864 usage();
865 memcpy( pi_ssrc_global, &maddr.s_addr, 4 * sizeof(uint8_t) );
866 break;
869 case 'i':
870 i_priority = strtol( optarg, NULL, 0 );
871 break;
873 case 'a':
874 i_adapter = strtol( optarg, NULL, 0 );
875 break;
877 case 'n':
878 i_fenum = strtol( optarg, NULL, 0 );
879 break;
881 case 'y':
882 i_canum = strtol( optarg, NULL, 0 );
883 break;
885 case '5':
886 psz_delsys = optarg;
887 break;
888 case '9':
889 dvb_plp_id = strtol( optarg, NULL, 0 );
890 break;
891 case 'f':
892 if (optarg && optarg[0] != '-')
893 i_frequency = strtol( optarg, NULL, 0 );
894 if ( pf_Open != NULL )
895 usage();
896 #ifdef HAVE_DVB_SUPPORT
897 pf_Open = dvb_Open;
898 pf_Reset = dvb_Reset;
899 pf_SetFilter = dvb_SetFilter;
900 pf_UnsetFilter = dvb_UnsetFilter;
901 #else
902 msg_Err( NULL, "DVBlast is compiled without DVB support.");
903 exit(1);
904 #endif
905 break;
907 case '8':
908 psz_lnb_type = optarg;
909 break;
911 case 'F':
912 i_fec = strtol( optarg, NULL, 0 );
913 break;
915 case 'R':
916 i_rolloff = strtol( optarg, NULL, 0 );
917 break;
919 case 's':
920 i_srate = strtol( optarg, NULL, 0 );
921 break;
923 case 'S':
924 i_satnum = strtol( optarg, NULL, 16 );
925 break;
927 case 'k':
928 i_uncommitted = strtol( optarg, NULL, 10 );
929 break;
931 case 'v':
932 i_voltage = strtol( optarg, NULL, 0 );
933 break;
935 case 'p':
936 b_tone = 1;
937 break;
939 case 'b':
940 i_bandwidth = strtol( optarg, NULL, 0 );
941 break;
943 case 'I':
944 i_inversion = strtol( optarg, NULL, 0 );
945 break;
947 case 'm':
948 psz_modulation = optarg;
949 break;
951 case 'P':
952 i_pilot = strtol( optarg, NULL, 0 );
953 break;
955 case '1':
956 i_mis = strtol( optarg, NULL, 0 );
957 break;
959 case 0x100001: // --multistream-id-pls-mode
960 psz_mis_pls_mode = optarg;
961 if ( streq( psz_mis_pls_mode, "ROOT" ) ) {
962 i_mis_pls_mode = 0;
963 } else if ( streq( psz_mis_pls_mode, "GOLD" ) ) {
964 i_mis_pls_mode = 1;
965 } else if ( streq( psz_mis_pls_mode, "COMBO" ) ) {
966 i_mis_pls_mode = 2;
967 } else {
968 msg_Err(NULL, "Invalid --multistream-id-pls-mode '%s', valid options are: ROOT GOLD COMBO", optarg);
969 exit(1);
971 break;
973 case 0x100002: // --multistream-id-pls-code
974 i_mis_pls_code = strtol( optarg, NULL, 0 );
975 if ( i_mis_pls_code < 0 || i_mis_pls_code > 262143 ) {
976 msg_Err(NULL, "ERROR: Invalid --multistream-id-pls-code '%s', valid options are: 0-262143", optarg);
977 exit(1);
979 break;
981 case 0x100003: // --multistream-id-is-id
982 i_mis_is_id = strtol( optarg, NULL, 0 );
983 if ( i_mis_is_id < 0 || i_mis_is_id > 255 ) {
984 msg_Err(NULL, "ERROR: Invalid --multistream-id-is-id '%s', valid options are: 0-255", optarg);
985 exit(1);
987 break;
989 case 'K':
990 i_fec_lp = strtol( optarg, NULL, 0 );
991 break;
993 case 'G':
994 i_guard = strtol( optarg, NULL, 0 );
995 break;
997 case 'X':
998 i_transmission = strtol( optarg, NULL, 0 );
999 break;
1001 case 'O':
1002 i_frontend_timeout_duration = strtoll( optarg, NULL, 0 ) * 1000;
1003 break;
1005 case 'H':
1006 i_hierarchy = strtol( optarg, NULL, 0 );
1007 break;
1009 case 'u':
1010 b_budget_mode = 1;
1011 break;
1013 case 'w':
1014 b_select_pmts = !b_select_pmts;
1015 break;
1017 case 'U':
1018 b_udp_global = true;
1019 break;
1021 case 'L':
1022 i_latency_global = strtoll( optarg, NULL, 0 ) * 1000;
1023 break;
1025 case 'E':
1026 i_retention_global = strtoll( optarg, NULL, 0 ) * 1000;
1027 break;
1029 case 'd':
1030 psz_dup_config = optarg;
1031 break;
1033 case '3':
1034 b_passthrough = true;
1035 print_fh = stderr;
1036 break;
1038 case 'D':
1039 psz_udp_src = optarg;
1040 if ( pf_Open != NULL )
1041 usage();
1042 pf_Open = udp_Open;
1043 pf_Reset = udp_Reset;
1044 pf_SetFilter = udp_SetFilter;
1045 pf_UnsetFilter = udp_UnsetFilter;
1046 break;
1048 case 'A':
1049 #ifdef HAVE_ASI_SUPPORT
1050 if ( pf_Open != NULL )
1051 usage();
1052 if ( strncmp(optarg, "deltacast:", 10) == 0)
1054 #ifdef HAVE_ASI_DELTACAST_SUPPORT
1055 i_asi_adapter = strtol( optarg+10, NULL, 0 );
1056 pf_Open = asi_deltacast_Open;
1057 pf_Reset = asi_deltacast_Reset;
1058 pf_SetFilter = asi_deltacast_SetFilter;
1059 pf_UnsetFilter = asi_deltacast_UnsetFilter;
1060 #else
1061 msg_Err( NULL, "DVBlast is compiled without Deltacast ASI support.");
1062 exit(1);
1063 #endif
1065 else
1067 i_asi_adapter = strtol( optarg, NULL, 0 );
1068 pf_Open = asi_Open;
1069 pf_Reset = asi_Reset;
1070 pf_SetFilter = asi_SetFilter;
1071 pf_UnsetFilter = asi_UnsetFilter;
1073 #else
1074 msg_Err( NULL, "DVBlast is compiled without ASI support.");
1075 exit(1);
1076 #endif
1077 break;
1079 case 'z':
1080 b_any_type = 1;
1081 break;
1083 case 'C':
1084 b_dvb_global = true;
1085 break;
1087 case 'W':
1088 b_enable_emm = true;
1089 break;
1091 case 'Y':
1092 b_enable_ecm = true;
1093 break;
1095 case 'e':
1096 b_epg_global = true;
1097 break;
1099 case 'M':
1100 psz_network_name = optarg;
1101 break;
1103 case 'N':
1104 i_network_id = strtoul( optarg, NULL, 0 );
1105 break;
1107 case 'T':
1108 b_random_tsid = 1;
1109 break;
1111 case 'j':
1112 psz_native_charset = optarg;
1113 break;
1115 case 'J':
1116 psz_dvb_charset = optarg;
1117 break;
1119 case 'B':
1120 psz_provider_name = optarg;
1121 break;
1123 case 'l':
1124 b_enable_syslog = 1;
1125 break;
1127 case 'g':
1128 psz_syslog_ident = optarg;
1129 break;
1131 case 'x':
1132 b_print_enabled = true;
1133 if ( !strcmp(optarg, "text") )
1134 i_print_type = PRINT_TEXT;
1135 else if ( !strcmp(optarg, "xml") )
1136 i_print_type = PRINT_XML;
1137 else
1139 b_print_enabled = false;
1140 msg_Warn( NULL, "unrecognized print type %s", optarg );
1142 break;
1144 case 'Q':
1145 i_quit_timeout_duration = strtoll( optarg, NULL, 0 ) * 1000;
1146 break;
1148 case '6':
1149 i_print_period = strtoll( optarg, NULL, 0 ) * 1000;
1150 break;
1152 case '7':
1153 i_es_timeout = strtoll( optarg, NULL, 0 ) * 1000;
1154 break;
1156 case 'V':
1157 DisplayVersion();
1158 exit(0);
1159 break;
1161 case 'Z':
1162 psz_mrtg_file = optarg;
1163 break;
1165 case '0': {
1166 /* We expect a comma separated list of numbers.
1167 Put them into the pi_newpids array as they appear */
1168 char *str1;
1169 char *saveptr = NULL;
1170 char *tok = NULL;
1171 int i, i_newpid;
1172 for (i = 0, str1 = optarg; i < N_MAP_PIDS; i++, str1 = NULL)
1174 tok = strtok_r(str1, ",", &saveptr);
1175 if ( !tok )
1176 break;
1177 i_newpid = strtoul(tok, NULL, 0);
1178 if ( !i_newpid ) {
1179 msg_Err( NULL, "Invalid pidmap string" );
1180 usage();
1182 pi_newpids[i] = i_newpid;
1184 b_do_remap = true;
1185 break;
1187 #ifdef HAVE_DVB_SUPPORT
1188 case '2':
1189 i_dvr_buffer_size = strtol( optarg, NULL, 0 );
1190 if (!i_dvr_buffer_size)
1191 usage(); // it exits
1192 /* roundup to packet size */
1193 i_dvr_buffer_size += TS_SIZE - 1;
1194 i_dvr_buffer_size /= TS_SIZE;
1195 i_dvr_buffer_size *= TS_SIZE;
1196 break;
1197 #endif
1198 case 'h':
1199 default:
1200 usage();
1203 if ( optind < i_argc || pf_Open == NULL )
1204 usage();
1206 if ( b_enable_syslog )
1207 msg_Connect( psz_syslog_ident ? psz_syslog_ident : pp_argv[0] );
1209 if ( b_print_enabled )
1211 /* Make std* line-buffered */
1212 setvbuf(print_fh, NULL, _IOLBF, 0);
1215 if ( i_verbose )
1216 DisplayVersion();
1218 msg_Warn( NULL, "restarting" );
1220 switch (i_print_type)
1222 case PRINT_XML:
1223 fprintf(print_fh, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
1224 fprintf(print_fh, "<TS>\n");
1225 break;
1226 default:
1227 break;
1230 if ( b_udp_global )
1232 msg_Warn( NULL, "raw UDP output is deprecated. Please consider using RTP." );
1233 msg_Warn( NULL, "for DVB-IP compliance you should use RTP." );
1236 if ( b_epg_global && !b_dvb_global )
1238 msg_Dbg( NULL, "turning on DVB compliance, required by EPG information" );
1239 b_dvb_global = true;
1242 if ((event_loop = ev_default_loop(0)) == NULL)
1244 msg_Err( NULL, "unable to initialize libev" );
1245 exit(EXIT_FAILURE);
1248 memset( &output_dup, 0, sizeof(output_dup) );
1249 if ( psz_dup_config != NULL )
1251 output_config_t config;
1253 config_Defaults( &config );
1254 if ( !config_ParseHost( &config, psz_dup_config ) )
1255 msg_Err( NULL, "Invalid target address for -d switch" );
1256 else
1258 output_Init( &output_dup, &config );
1259 output_Change( &output_dup, &config );
1262 config_Free( &config );
1265 config_strdvb( &network_name, psz_network_name, psz_dvb_charset );
1266 config_strdvb( &provider_name, psz_provider_name, psz_dvb_charset );
1268 /* Set signal handlers */
1269 signal_watcher_init(&sigint_watcher, event_loop, sighandler, SIGINT);
1270 signal_watcher_init(&sigterm_watcher, event_loop, sighandler, SIGTERM);
1271 signal_watcher_init(&sighup_watcher, event_loop, sighandler, SIGHUP);
1273 srand( time(NULL) * getpid() );
1275 if ( i_mis_pls_mode || i_mis_pls_code || i_mis_is_id )
1277 i_mis = calc_multistream_id( i_mis_pls_mode, i_mis_pls_code, i_mis_is_id );
1278 msg_Info( NULL, "Calculating multistream-id using pls-mode: %s (%d) pls-code: %d is-id: %d. Resulting multistream-id: %d (0x%x)",
1279 psz_mis_pls_mode, i_mis_pls_mode, i_mis_pls_code, i_mis_is_id, i_mis, i_mis );
1281 else if ( i_mis )
1283 i_mis_pls_mode = (i_mis >> 26) & 0x03;
1284 i_mis_pls_code = (i_mis >> 8) & 0x3ffff;
1285 i_mis_is_id = i_mis & 0xff;
1286 psz_mis_pls_mode =
1287 i_mis_pls_mode == 0 ? "ROOT" :
1288 i_mis_pls_mode == 1 ? "GOLD" :
1289 i_mis_pls_mode == 2 ? "COMBO" : "UNKNOWN";
1291 msg_Info( NULL, "Calculated multistream pls-mode: %s (%d) pls-code: %d is-id: %d from multistream-id: %d (0x%x)",
1292 psz_mis_pls_mode, i_mis_pls_mode, i_mis_pls_code, i_mis_is_id, i_mis, i_mis );
1295 demux_Open();
1297 // init the mrtg logfile
1298 mrtgInit(psz_mrtg_file);
1300 if ( i_priority > 0 )
1302 memset( &param, 0, sizeof(struct sched_param) );
1303 param.sched_priority = i_priority;
1304 if ( (i_error = pthread_setschedparam( pthread_self(), SCHED_RR,
1305 &param )) )
1307 msg_Warn( NULL, "couldn't set thread priority: %s",
1308 strerror(i_error) );
1312 config_ReadFile();
1314 if ( psz_srv_socket != NULL )
1315 comm_Open();
1317 if ( i_quit_timeout_duration )
1319 ev_timer_init(&quit_watcher, quit_cb,
1320 i_quit_timeout_duration / 1000000., 0);
1321 ev_timer_start(event_loop, &quit_watcher);
1324 outputs_Init();
1326 ev_run(event_loop, 0);
1328 mrtgClose();
1329 outputs_Close( i_nb_outputs );
1330 demux_Close();
1331 dvb_string_clean( &network_name );
1332 dvb_string_clean( &provider_name );
1333 if ( conf_iconv != (iconv_t)-1 )
1334 iconv_close( conf_iconv );
1336 switch (i_print_type)
1338 case PRINT_XML:
1339 fprintf(print_fh, "</TS>\n");
1340 break;
1341 default:
1342 break;
1345 if ( b_enable_syslog )
1346 msg_Disconnect();
1348 comm_Close();
1349 block_Vacuum();
1350 ev_loop_destroy(event_loop);
1352 return EXIT_SUCCESS;