/*-
 * Copyright (c) 1993-1994 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by the University of
 *      California, Berkeley and the Network Research Group at
 *      Lawrence Berkeley Laboratory.
 * 4. Neither the name of the University nor of the Laboratory may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <osfcn.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <ctype.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <sys/stat.h>
#ifdef sgi
#include <getopt.h>
#endif

#include "inet.h"
#include "packet.h"
#include "mcastchan.h"

#ifndef lint
static const char rcsid[] =
    "@(#) $Header: rtp_record.cc,v 1.5 94/12/07 10:28:53 van Exp $ (LBL)";
#endif

static void
usage()
{
	fprintf(stderr, "Usage: rtp_record [-o outfile] [-c cnt] hostspec\n");
	exit(1);
}

Network* net;

void
adios()
{
	delete net;
	exit(0);
}

extern "C" char *optarg;
extern "C" int optind;
extern "C" int opterr;

static int hostspec(const char* dst, n_long& addr, u_short& port,
		    u_short& convid, int& fmt, int& ttl)
{
	char spec[256];
	strcpy(spec, dst);

	int ret = 1;
	char* cp = strchr(spec, '/');
	if (cp)
		*cp = 0;
	if ((addr = LookupHostAddr(spec)) == 0) {
		printf("rtp_record: invalid dest host `%s'\n", spec);
		exit(1);
	}

	if (cp && *++cp != '/') {
		/* have a port number */
		port = atoi(cp);
		if (port <= 0) {
			printf("invalid port `%s'\n", cp);
			exit(1);
		}
		ret = 0;
		cp = strchr(cp, '/');
	}

	if (cp && isdigit(cp[1])) {
		/* have a conversation id */
		convid = atoi(++cp);
		cp = strchr(cp, '/');
	}

	if (cp && *++cp) {
		ttl = atoi(cp);
		if (ttl <= 0 || ttl > 255) {
			printf("invalid ttl `%s'\n", cp);
			exit(1);
		}
	}

	return (ret);
}

#define MTU (10*1024)

void
dumpit(int in, int out, int sflag)
{
	char buffer[MTU];
	int cc = read(in, buffer + 4, MTU - 4);
	if (cc < 0) {
		perror("read");
		exit(1);
	}
	*(short*)buffer = htons(cc);
	buffer[2] = sflag;
	buffer[3] = 0;
	if (write(out, buffer, cc + 4) < 0) {
		perror("write");
		exit(1);
	}
}

int
main(int argc, const char** argv)
{
	const char* outfile = 0;
#ifdef __svr4__
	signal(SIGINT, (void (*)(int))adios);
	signal(SIGHUP, (void (*)(int))adios);
	signal(SIGTERM, (void (*)(int))adios);
#else
#ifdef sgi
#ifndef IRIX5
	signal(SIGINT, (int (*)(int ...))adios);
	signal(SIGHUP, (int (*)(int ...))adios);
	signal(SIGTERM, (int (*)(int ...))adios);
#else
	signal(SIGINT, (void (*)(int ...))adios);
	signal(SIGHUP, (void (*)(int ...))adios);
	signal(SIGTERM, (void (*)(int ...))adios);
#endif
#elif defined(__osf__)
	signal(SIGINT, (void (*)(int))adios);
	signal(SIGHUP, (void (*)(int))adios);
	signal(SIGTERM, (void (*)(int))adios);
#else
	signal(SIGHUP, adios);
	signal(SIGINT, adios);
	signal(SIGTERM, adios);
#endif
#endif

	opterr = 0;

	const char* optstr = "c:o:";

	int ctrlsock = 1;
	u_short port = 0;
	u_int cnt = 0;
	int op;
	while ((op = getopt(argc, (char**)argv, (char*)optstr)) != -1) {
		switch (op) {

		default:
			usage();

		case 'c':
			cnt = atoi(optarg);
			break;

		case 'o':
			outfile = optarg;
			break;
		}
	}
	int out;
	if (outfile == 0)
		out = 1;
	else {
		out = open(outfile, O_WRONLY|O_TRUNC|O_CREAT, 0644);
		if (out < 0) {
			perror(outfile);
			exit(1);
		}
	}
	const char* dst = 0;
	if (optind < argc && argc > 1) {
		dst = argv[optind];
		if (argc - optind > 1) {
			printf("rtp_record: extra arguments (starting with `%s')\n",
			       argv[optind + 1]);
			exit(1);
		}
	} else
		usage();

	n_long addr;
	int dummy;
	u_short confid = 0;
	int ttl = 0;/*XXX*/
	hostspec(dst, addr, port, confid, dummy, ttl);
	port = htons(port);
	net = new mcastChannel(addr, port, ttl, ctrlsock);

	int ds = net->rchannel();
	int ss = net->rctrl();

	fd_set fds;
	FD_ZERO(&fds);
	FD_SET(ds, &fds);
	FD_SET(ss, &fds);
	int nfd = ((ds > ss) ? ds : ss) + 1;

#define MAGIC "RTPCLIP 1.0"
	(void)write(out, MAGIC, sizeof(MAGIC));

	for (;;) {
		if (cnt != 0 && --cnt <= 0)
			return (0);

		fd_set s = fds;
		int n = select(nfd, &s, 0, 0, 0);
		if (n < 0) {
			perror("select");
			exit(1);
		}
		if (FD_ISSET(ds, &s))
			dumpit(ds, out, 0);
		if (ds != ss && FD_ISSET(ss, &s)) {
			dumpit(ss, out, 0x80);
		}
	}
}
