#include "global.h"
#ifdef TCPGATE
#include "commands.h"
#include "mbuf.h"
#include "netuser.h"
#include "bldsaddr.h"
#include "stats.h"
static void tcpgateserv(int s,void *ds,void *p);
static void gate_output(int s1,void *s2,void *p);
extern unsigned short getnextport (void);


#define Gatetdisc (60*10)	/* default to 10 minutes timeout */


#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: tcpgate.c,v 1.18 1997/05/24 12:45:59 root Exp $";
#endif


struct dest {
  int port;
  int socket;
  char *name;
  struct dest *next;
};

static struct dest *dests;


int
tcpgate0 (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
{
struct dest *dp, *dp2;
int port;

	port = atoip(argv[1]);
	dp = dests;
	if (dp->port == port)	{
		dests = dp->next;
	} else	{
		for ( ; dp && dp->next->port != port; dp = dp->next) ;
		if (!dp || !dp->next)	{
			tprintf ("The tcpgate server is not active on port %d - nothing to stop!\n", port);
			return 0;
		}
		dp2 = dp->next;
		dp->next = dp2->next;
		dp = dp2;
	}

	close_s (dp->socket);
	if (dp->name)
		free (dp->name);
	free(dp);
	tprintf ("The tcpgate server removed from port %d\n", port);
	return 0;
}



int tcpgate1(int argc, char *argv[], void *p OPTIONAL)
{
char buf[80];
int port;
char *name;
struct dest *dp;

	port = atoip(argv[1]);
#if 0
	if (argc < 3)
		sprintf(name = buf, "loopback:%d", port);
	else
#endif
		name = argv[2];
	for (dp = dests; dp && dp->port != port; dp = dp->next) ;
	if (!dp) {
		dp = (struct dest *) mallocw(sizeof(struct dest));
		dp->port = port;
		dp->name = 0;
		dp->next = dests;
		dests = dp;
	}
	if (dp->name) free(dp->name);
	dp->name = strdup(name);
	dp->socket = -1;

	sprintf (buf, "TCPGATE %d listener", port);
	return (installserver (argc, argv, &dp->socket, buf, port,
		INADDR_ANY, "TCPGATE server", tcpgateserv, 512, dp));
}



static void
tcpgateserv (int s, void *ds, void *p OPTIONAL)
{
struct dest *dp = (struct dest *)ds;
struct mbuf *bp;
int addrlen;
struct sockaddr *addr = 0;
int rmtsock;
struct proc *rxproc;
struct sockaddr_in lsocket;
#if 0
register struct usock *up;
#endif
int datalen;

	(void) sockowner(s,Curproc);	/* We own it now */
	/* Secede from the parent's sockets, and use the network socket that
	 * was passed to us for both input and output. The reference
	 * count on this socket will still be 1; this allows the domboxbye()
	 * command to work by closing that socket with a single call.
	 * If we return, the socket will be closed automatically.
	 */
	close_s(Curproc->output);
	close_s(Curproc->input);
	Curproc->output = Curproc->input = s;

	log(s, "open TCPGATE server on port %d", dp->port);
	lsocket.sin_family = AF_INET;
	lsocket.sin_addr.s_addr = INADDR_ANY;
	lsocket.sin_port = getnextport();

	addr = build_sockaddr(dp->name, &addrlen);
	if (!addr || (rmtsock = socket(addr->sa_family, SOCK_STREAM, 0)) <= 0 ||
		bind(rmtsock,(char *)&lsocket,sizeof(lsocket)) < 0 ||
		connect(rmtsock, (char *)addr, addrlen))
			return;

#ifdef STATS_USE
	STATS_adduse (1);
	MiscUsers++;
#endif
	/* Fork off the transmit process */
	rxproc = newproc("tcpgate_out",1024,gate_output,s,(void *)rmtsock,&rxproc,0);

	/* Process input on the connection */
	while (1)	{		/*lint !e716 !e774 */
		if((datalen = socklen(s,0)) > 0)	{
			if (recv_mbuf(s,&bp,0,NULLCHAR,0) == -1)
				break;
			if (send_mbuf(rmtsock,bp,0,NULLCHAR,0) == -1)
				break;
		} else if(datalen < 0)
			break;
/*		if((up = itop(s)) == NULLUSOCK)
			break;
		if(up->cb.p == NULLCHAR)
			break;
		if (up->cb.local->peer->cb.local->peer == NULLUSOCK)
			break;
		if (up->cb.tcb->user == -1)
			break;
		if (up->cb.local->flags == LOC_SHUTDOWN)
			break;		*/
		if (rxproc == NULLPROC)
			break;
		if (!datalen)
			kpause (200);
	}
	killproc(rxproc);
#ifdef STATS_USE
	MiscUsers--;
#endif
	log(s, "closed TCPGATE server on port %d", dp->port);
	close_s(s);
	close_s(rmtsock);
	s = -1;
}



static void
gate_output (int s1, void *s2, void *rx)
{
struct mbuf *bp;
int sock2;
struct proc **rxproc;

	sock2 = (int)s2;
	rxproc = (struct proc **)rx;

	for ( ; ; )	{
		kalarm (Gatetdisc * 1000L);
		if (recv_mbuf(sock2,&bp,0,NULLCHAR,0) == -1)
			break;
		kalarm (0);
		if(send_mbuf(s1,bp,0,NULLCHAR,0) == -1)
			break;
	}
	*rxproc = NULLPROC;
}

#endif /* TCPGATE */
