diff --git a/oggfwd.c b/oggfwd.c new file mode 100644 index 0000000..5333e47 --- /dev/null +++ b/oggfwd.c @@ -0,0 +1,400 @@ +/* vi:si:noexpandtab:sw=4:sts=4:ts=4 +*/ +/* + * oggfwd -- Forward an Ogg stream from stdin to an Icecast server + * A useful demonstration of the libshout API + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * This program is provided "as-is", with no explicit or implied warranties of + * any kind. + * + * Copyright (C) 2003-2006, J , + * rafael2k , + * Moritz Grimm + * Copyright (C) 2015, Philipp Schafft + */ +/* thanx to rhatto and others at submidialogia :-P */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef NO_UNISTD_H +# include +#endif /* no-NO_UNISTD_H */ + +#include + +extern char *__progname; +extern char *optarg; +extern int optind; +extern int errno; + +volatile sig_atomic_t print_total = 0; +volatile sig_atomic_t quit = 0; + +#define METABUFSIZE 4096 +char *metafilename; +shout_t *shout; + +#define BUFFERSIZE 4096 + +#if defined(__dead) +__dead void +#else +void +#endif /* __dead */ +usage(void) +{ + printf("usage: %s " + "[-hp] " +#ifdef SHOUT_TLS + "[-T {disabled|auto|auto_no_plain|rfc2818|rfc2817}] " +#endif + "[-m metadata file] " + "[-d description] " + "[-g genre] " + "[-n name] " + "[-u URL]\n" + " address port password mountpoint\n", + __progname); + exit(1); +} + + +void +load_metadata() +{ + int i, fh, r; + char buf[METABUFSIZE], *key, *val; + enum {state_comment, state_key, state_value, state_unknown} state; + + bzero(buf, METABUFSIZE); + + if (!metafilename) { + fprintf(stderr, "Please use the -m argument to set the meta file name!\n"); + return; + } + + fh = open(metafilename, O_RDONLY); + + if (-1==fh) { + fprintf(stderr, "Error while opening meta file \"%s\": %s\n", metafilename, strerror(errno)); + return; + } + + r = read(fh, &buf, METABUFSIZE); + if (-1==r) { + fprintf(stderr, "Error while reading meta file \"%s\": %s\n", metafilename, strerror(errno)); + close(fh); + return; + } + + state = state_unknown; + key = val = NULL; + i = 0; + + while (i= MAXPATHLEN) { + fprintf(stderr, "%s: Argument for parameter -%c too long\n", + __progname, optname); + exit(1); + } + + if ((*param = malloc(siz)) == NULL) { + fprintf(stderr, "%s: %s\n", __progname, strerror(errno)); + exit(1); + } + + snprintf(*param, siz, "%s", opt); +} + +#ifdef SHOUT_TLS +void +set_tls_mode(int *tls_mode, char *opt, char optname) +{ + if (0==strcasecmp("DISABLED", opt)) { + *tls_mode = SHOUT_TLS_DISABLED; + } else if (0==strcasecmp("AUTO", opt)) { + *tls_mode = SHOUT_TLS_AUTO; + } else if (0==strcasecmp("AUTO_NO_PLAIN", opt)) { + *tls_mode = SHOUT_TLS_AUTO_NO_PLAIN; + } else if (0==strcasecmp("RFC2818", opt)) { + *tls_mode = SHOUT_TLS_RFC2818; + } else if (0==strcasecmp("RFC2817", opt)) { + *tls_mode = SHOUT_TLS_RFC2817; + } else { + fprintf(stderr, "%s: Invalid value for -%c.\n", + __progname, optname); + usage(); + exit(1); + } +} +#endif + +int +main(int argc, char **argv) +{ + unsigned char buff[BUFFERSIZE]; + int ret, ch; + unsigned int pFlag; + char *description, *genre, *name, *url; + size_t bytes_read = 0; + unsigned short port; + unsigned long long total; +#ifdef SHOUT_TLS + int tls_mode = SHOUT_TLS_AUTO; +#endif + + pFlag = 0; + description = genre = name = url = metafilename = NULL; + while ((ch = getopt(argc, argv, "d:g:hn:m:pu:T:")) != -1) { + switch (ch) { + case 'd': + set_argument_string(&description, optarg, 'D'); + break; + case 'g': + set_argument_string(&genre, optarg, 'g'); + break; + case 'n': + set_argument_string(&name, optarg, 'n'); + break; + case 'm': + set_argument_string(&metafilename, optarg, 'm'); + break; + case 'p': + pFlag = 1; + break; + case 'u': + set_argument_string(&url, optarg, 'u'); + break; + case 'T': +#ifdef SHOUT_TLS + set_tls_mode(&tls_mode, optarg, 'T'); + break; +#endif + case 'h': + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc != 4) { + fprintf(stderr, "%s: Wrong number of arguments\n", __progname); + usage(); + } + + if ((shout = shout_new()) == NULL) { + fprintf(stderr, "%s: Could not allocate shout_t\n", + __progname); + return (1); + } + + shout_set_format(shout, SHOUT_FORMAT_OGG); + +#ifdef SHOUT_TLS + if (shout_set_tls(shout, tls_mode) != SHOUTERR_SUCCESS) { + fprintf(stderr, "%s: Error setting TLS mode: %s\n", __progname, + shout_get_error(shout)); + return (1); + } +#endif + + if (shout_set_host(shout, argv[0]) != SHOUTERR_SUCCESS) { + fprintf(stderr, "%s: Error setting hostname: %s\n", __progname, + shout_get_error(shout)); + return (1); + } + + if (sscanf(argv[1], "%hu", &port) != 1) { + fprintf(stderr, "Invalid port `%s'\n", argv[1]); + usage(); + } + if (shout_set_port(shout, port) != SHOUTERR_SUCCESS) { + fprintf(stderr, "%s: Error setting port: %s\n", __progname, + shout_get_error(shout)); + return (1); + } + + if (shout_set_password(shout, argv[2]) != SHOUTERR_SUCCESS) { + fprintf(stderr, "%s: Error setting password: %s\n", __progname, + shout_get_error(shout)); + return (1); + } + + if (shout_set_mount(shout, argv[3]) != SHOUTERR_SUCCESS) { + fprintf(stderr, "%s: Error setting mount: %s\n", __progname, + shout_get_error(shout)); + return (1); + } + + shout_set_public(shout, pFlag); + + if (metafilename) + load_metadata(); + + if (description) + shout_set_description(shout, description); + + if (genre) + shout_set_genre(shout, genre); + + if (name) + shout_set_name(shout, name); + + if (url) + shout_set_url(shout, url); + + signal(SIGUSR1, sig_handler); + + //wait for data before opening connection to server + bytes_read = fread(buff, 1, sizeof(buff), stdin); + + if (shout_open(shout) == SHOUTERR_SUCCESS) { + printf("%s: Connected to server\n", __progname); + total = 0; + + signal(SIGHUP, sig_handler); + signal(SIGTERM, sig_handler); + signal(SIGINT, sig_handler); + + while (quit == 0) { + total += bytes_read; + + if (bytes_read > 0) { + ret = shout_send(shout, buff, bytes_read); + if (ret != SHOUTERR_SUCCESS) { + printf("%s: Send error: %s\n", + __progname, + shout_get_error(shout)); + quit = 1; + } + } else + quit = 1; + + if (quit) { + printf("%s: Quitting ...\n", __progname); + print_total = 1; + } + + if (print_total) { + printf("%s: Total bytes read: %llu\n", + __progname, total); + print_total = 0; + } + + shout_sync(shout); + + bytes_read = fread(buff, 1, sizeof(buff), stdin); + if (bytes_read != sizeof(buff) && feof(stdin)) { + quit = 1; + } + } + } else { + fprintf(stderr, "%s: Error connecting: %s\n", __progname, + shout_get_error(shout)); + return (1); + } + + shout_close(shout); + + return (0); +}