diff options
Diffstat (limited to 'mcast/netcv2dvbip/main.c')
-rw-r--r-- | mcast/netcv2dvbip/main.c | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/mcast/netcv2dvbip/main.c b/mcast/netcv2dvbip/main.c new file mode 100644 index 0000000..3b31406 --- /dev/null +++ b/mcast/netcv2dvbip/main.c @@ -0,0 +1,400 @@ +#include "dvbipstream.h" +#include "iface.h" + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> + +#ifndef WIN32 +#include <signal.h> +#include <unistd.h> +#include <sys/types.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#ifndef APPLE +#define _LINUX_IN_H +#include <linux/mroute.h> +#endif +#else +#include <direct.h> +#ifdef __MINGW32__ +#include <getopt.h> +#endif +#endif + +#include "streamer.h" + +#define PORT_MAX 6 + +#ifndef WIN32 +// Local function Prototypes +static void signalHandler(int); + +// Global vars... +static int sighandled = 0; +#define GOT_SIGINT 0x01 +#define GOT_SIGHUP 0x02 +#define GOT_SIGTERM 0x04 +#endif + +channel_t *channels=NULL; +int channel_num=0; +int channel_max_num=0; +int channel_use_eit = 0; +int channel_use_sdt = 0; +int portnum = 12345; +int table = 0; +int quiet = 0; + +/*-------------------------------------------------------------------------*/ +channel_t * read_channel_list(char *filename, char *dirname) +{ + FILE *cf; + FILE *pf; + char buf[512]; + + cf=fopen(filename,"r"); + if (!cf) { + printf("Can't read %s: %s\n",filename,strerror(errno)); + return NULL; + } + + if (dirname) { +#ifdef WIN32 + if (((dirname[0]>='A'&&dirname[0]<='Z') || + (dirname[0]>='a'&&dirname[0]<='z')) && dirname[1]==':') { + if (_chdrive((dirname[0]&0xdf)-'A'+1)) { + printf("Can't access %s: %s\n", dirname, + strerror(errno)); + fclose(cf); + return NULL; + } + } +#endif + if (chdir(dirname)) { + printf("Can't access %s: %s\n", dirname, + strerror(errno)); + fclose(cf); + return NULL; + } + } + + pf =fopen("channels.m3u", "w"); + if (!pf) { + printf("Can't create %s: %s\n", "channels.m3u", + strerror(errno)); + fclose(cf); + return NULL; + } + fprintf(pf, "#EXTM3U\n"); + + while(fgets(buf,sizeof(buf),cf)) { + if (channel_num==channel_max_num) { + channel_max_num+=200; + channels=(channel_t*)realloc(channels, + channel_max_num*sizeof(channel_t)); + if (!channels) { + printf("out of memory\n"); + fclose(pf); + fclose(cf); + return NULL; + } + } + if (ParseLine(buf,&channels[channel_num])) { + int ip1 = (channel_num+1)/256; + int ip2 = (channel_num) - (ip1*256) + 1; + if (!quiet) + printf("%i: udp://@239.255.%i.%i:%i - %s \n", + channel_num+1, ip1, ip2, portnum, + channels[channel_num].name); + fprintf(pf, "#EXTINF: %i,%s\n", channel_num+1, + channels[channel_num].name); + fprintf(pf, "udp://@239.255.%i.%i:%i\n", ip1,ip2, + portnum); + if (channel_use_eit) + { + channels[channel_num].NumEitpids = 1; + channels[channel_num].eitpids[0] = 0x12; + } + if (channel_use_sdt) + { + channels[channel_num].NumSdtpids = 1; + channels[channel_num].sdtpids[0] = 0x11; + } + channel_num++; + } + } + printf("Read %i channels, M3U playlist file \"channels.m3u\" " + "generated.\n",channel_num); + fclose(pf); + fclose(cf); + return channels; +} +/*-------------------------------------------------------------------------*/ +int get_channel_num(void) +{ + return channel_num; +} +/*-------------------------------------------------------------------------*/ +int get_channel_name(int n, char *str, int maxlen) +{ +#ifndef WIN32 + snprintf(str,maxlen,"%04i_%s.ts",n+1,channels[n].name); +#else + sprintf(str,"%04i_%s.ts",n+1,channels[n].name); +#endif + while(*str) { + char c=*str; + if (c=='/' || c=='\\' || c==':' || c=='?' || c=='*' || + !isprint(c)) + *str='_'; + str++; + } + return 0; +} +/*-------------------------------------------------------------------------*/ +channel_t *get_channel_data(int n) +{ + return &channels[n]; +} + + +extern cmdline_t cmd; + +void usage (void) +{ + printf("Usage: netcv2dvbip " + "[-b <multicast interface>] " + "[-p <port>] " + "[-i <netceiver interface>] " + "[-c <channels.conf>] " + "[-e activate EIT PID (EPG)] " + "[-s activate SDT PID (may be required for EPG)] " +#ifdef MRT_TABLE + "[-t <routing table number> (requires " + "CONFIG_IP_MROUTE_MULTIPLE_TABLES)] " +#endif + "[-q be more quiet on the screen] " + "[-o <output directory>]\n"); + exit(1); +} + +/*-------------------------------------------------------------------------*/ +int main(int argc, char *argv[]) +{ + char c; + char *dirname = NULL; + char channels[_POSIX_PATH_MAX]; + strcpy(channels, "channels.conf"); + char bindiface[IFNAMSIZ]; + iface_t iflist[MAXIF]; + +#ifndef WIN32 + uid_t uid; + struct sigaction sa; + + uid = getuid(); + if(uid != 0) + { + printf("You must be root! Current uid: %d.\n",uid); + return(1); + } + + sa.sa_handler = signalHandler; + sa.sa_flags = 0; /* Interrupt system calls */ + sigemptyset(&sa.sa_mask); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + +#else + bool IsAdmin = false; + IsUserAdmin(&IsAdmin); + if( IsAdmin == false) + { + printf("You must have administrative privileges!\n"); + return(1); + } +#endif + + memset(bindiface, 0, sizeof(bindiface)); + + while(1) + { + int ret = getopt(argc,argv, "i:hc:b:p:esqo:" +#ifdef MRT_TABLE + "t:" +#endif + ); + if (ret==-1) + break; + + c=(char)ret; + + switch (c) { + case 'i': + strncpy(cmd.iface, optarg, IFNAMSIZ-1); + cmd.iface[IFNAMSIZ-1]=0; + break; + case 'c': + strncpy(channels, optarg, _POSIX_PATH_MAX-1); + channels[_POSIX_PATH_MAX-1]=0; + break; + case 'b': + strncpy(bindiface, optarg, IFNAMSIZ-1); + bindiface[IFNAMSIZ-1] = 0; + break; + case 'p': + portnum = atoi(optarg); + break; +#ifdef MRT_TABLE + case 't': + table = atoi(optarg); + break; +#endif + case 'h': + usage(); + return(0); + case 'e': + channel_use_eit = 1; + break; + case 's': + channel_use_sdt = 1; + break; + case 'q': + quiet = 1; + break; + case 'o': + dirname = optarg; + break; + } + } + + memset( iflist, 0, sizeof(iflist)); + int num_ifaces=discover_interfaces( (iface_t*) &iflist ); + if ( !num_ifaces ) + exit(-1); + + int ifindex = 0; + if ( strlen(bindiface) > 0 ) + { + int found = false; + while ( ifindex < num_ifaces ) + { + if (!strncmp(iflist[ifindex].name, bindiface, IFNAMSIZ)) + { + found = true; + break; + } + ifindex++; + } + if (!found) + { + printf("Cannot find interface %s. Exiting...\n", + bindiface); + exit(-1); + } + + } + + printf("Starting netcv2dvbip. Streams will be sent to port: %d\n", + portnum); + + if (!read_channel_list(channels, dirname)) + exit(-1); + + mcli_startup(); + +#ifdef WIN32 + if ( !IsVistaOrHigher() ) + { + printf("Windows version does not support MLDv2, enabling " + "internal MLDv2 reporter.\n"); + mld_client_init(cmd.iface); + } +#endif + + printf("\n"); + +#ifdef WIN32 + WSADATA ws; + WSAStartup(MAKEWORD (2, 2),&ws); +#endif + + cStreamer streamer; + + struct sockaddr_in listenaddr; + listenaddr.sin_addr.s_addr = iflist[ifindex].ipaddr; + printf("Listening on interface %s (%s)\n\n\n", iflist[ifindex].name, + inet_ntoa(listenaddr.sin_addr)); + + streamer.SetBindIf(iflist[ifindex]); + streamer.SetStreamPort(portnum); + streamer.SetTable(table); + streamer.SetNumGroups(get_channel_num()); + + streamer.Run(); + +#ifdef WIN32 + printf("\nPlease press enter to stop.\n\n\n"); + getchar(); + printf("Stopping...please wait...\n"); +#else + while (1) + { + // Process signaling... + if (sighandled) { + if (sighandled & GOT_SIGINT) { + sighandled &= ~GOT_SIGINT; + printf("\nGot SIGINT signal. Exiting.\n"); + break; + } + if (sighandled & GOT_SIGTERM) { + sighandled &= ~GOT_SIGTERM; + printf("Got SIGTERM signal. Exiting.\n"); + break; + } + } + usleep(10000); + } +#endif + + streamer.Stop(); +#ifdef WIN32 + if ( !IsVistaOrHigher() ) + { + mld_client_exit(); + } +#endif + printf("netcv2dvbip stopped.\n"); + +#ifdef WIN32 + WSACleanup(); +#endif + return 0; +} +/*-------------------------------------------------------------------------*/ +#ifndef WIN32 +/* + * Signal handler. Take note of the fact that the signal arrived + * so that the main loop can take care of it. + */ +static void signalHandler(int sig) { + switch (sig) { + case SIGINT: + sighandled |= GOT_SIGINT; + break; + case SIGTERM: + sighandled |= GOT_SIGTERM; + break; + /* XXX: Not in use. + case SIGHUP: + sighandled |= GOT_SIGHUP; + break; + */ + } +} +#endif |