/*
 * Copyright 1993,1994 Globetrotter Software, Inc.
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Globetrotter Software not be used
 * in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.  Globetrotter Software makes
 * no representations about the suitability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 *
 * GLOBETROTTER SOFTWARE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO
 * EVENT SHALL GLOBETROTTER SOFTWARE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 * OF THIS SOFTWARE.
 *
 * Author:  Jim McBeath, Globetrotter Software, jimmc@globes.com
 */
/* sock.c - socket routines
 *
 * Jim McBeath, November 18, 1993
 */

#include "htimp.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#ifndef FIONREAD
#include <sys/filio.h>
#endif
#include <netinet/in.h>
#include <errno.h>
#include <netdb.h>
#include <fcntl.h>

#ifdef O_NONBLOCK
#define NONBLOCKFLAG O_NONBLOCK
#else
#define NONBLOCKFLAG FNDELAY
#endif

extern int ImpDebug;

int ImpPort = DEFAULT_IMP_PORT;
int ImpMasterListenConn;
int ImpMasterConn;	/* descriptor for connection to master (in slave) */

ImpSetPort(n)
int n;
{
	ImpPort = n;
}

int	/* returns file descriptor */
ImpMasterListen()
{
	int s;
	int t;
	struct sockaddr_in sockin;
	int one=1;

	s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if (s<0) {
		ImpFatal("+Socket failed in master");
		/* NOTREACHED */
	}
	ImpMasterListenConn = s;
	t = setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
	if (t<0) {
		ImpFatal("+Setsockopt failed in master");
		/* NOTREACHED */
	}
	memset((char *)&sockin,'\0',sizeof(sockin));
	sockin.sin_family = AF_INET;
	sockin.sin_addr.s_addr = htonl(INADDR_ANY);
	sockin.sin_port = htons((unsigned short)ImpPort);
	t = bind(s,(struct sockaddr *)&sockin,sizeof(sockin));
	if (t<0) {
		ImpFatal("+Bind failed in master");
		/* NOTREACHED */
	}
	t = listen(s,2);
	if (t<0) {
		ImpFatal("+Listen failed in master");
		/* NOTREACHED */
	}
	if (ImpDebug)
		fprintf(stderr,"Master is listening\n");
	return s;
}

int
ImpMasterAccept(s)
int s;		/* the listen descriptor */
{
	int d;
	struct sockaddr_in inaddr;
	int inaddrlen = sizeof(inaddr);
	int oflags;
	int t;

	d = accept(s,(struct sockaddr *)&inaddr,&inaddrlen);
	if (d<0) {
		perror("Accept failed in master");
		return -1;
	}
	oflags = fcntl(d, F_GETFL, 0);
	t = fcntl(d, F_SETFL, NONBLOCKFLAG | oflags);
	if (t<0) {
		perror("Can't make client socket non-blocking");
		return -1;
	}
	return d;
}

void
ImpMasterDisconnect(d)
int d;		/* the connection to drop */
{
	close(d);
	shutdown(d,2);	/* no more sends nor receives */
}

ImpConnectToMaster()
{
	int s;
	int t;
	struct hostent *he;
	struct hostent *gethostbyname();
	struct sockaddr_in sockin;

	memset((char *)&sockin,'\0',sizeof(sockin));
	sockin.sin_family = AF_INET;
	sockin.sin_port = htons((unsigned short)ImpPort);
	he = gethostbyname("localhost");
	if (!he) {
		ImpFatal("Can't translate localhost");
		/* NOTREACHED */
	}
	memcpy ((char *)&sockin.sin_addr,(char *)he->h_addr,
		sizeof(sockin.sin_addr));
	s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if (s<0) {
		ImpFatal("+Socket failed");
		/* NOTREACHED */
	}
	t = connect(s,(struct sockaddr *)&sockin,sizeof(sockin));
	if (t<0) {
		if (errno==ECONNREFUSED)
			return 0;	/* connect failed */
		ImpFatal("+Connect failed");
		/* NOTREACHED */
	}
	ImpMasterConn = s;	/* save where we can get it */
	return 1;		/* OK */
}

/* end */
