#ifndef	lint
static char sccsid[] = "@(#)server_rpc.c 1.9 88/12/21";
#endif	/*lint*/

#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#include <sys/file.h>
#include <conndefs.h>

#define WIRETAPPORT	9473	/* Arbitrary 'WIRE' port number */
#define MAXHOSTNAME MAXHOSTNAMELEN


extern int debug;
extern char *host;
char myhost[MAXHOSTNAMELEN];
char NewHost[MAXHOSTNAMELEN];

fd_set readmaster;

int news = 0;
int xsocket;
int listener_sock = -1;

tcp_init()
{
    int s;
    char c;
    fd_set readfd;
    int count, len;
    static char handshake[] = "WIRETAP2 V1.0\n";

    len = strlen(handshake);
#ifdef WIRETAP

    if ((s = iconnect(host, WIRETAPPORT)) < 0)
	return -1;

    for (count = 0; count < len;) {

	FD_ZERO(&readfd);
	FD_SET(s, &readfd);
	select(s+1, &readfd, (fd_set *)0, &readfd, NULL);

	if (!read(s, &c, 1)) {
	    close(s);
	    return -1;
	}

	if (c == handshake[count]) {
	    count++;

	} else {
	    count = 0;
	}
    }

    for (count = 0; count < len; count++) {
	while (!write(s, &handshake[count], 1));
    }

    printf("Connected to %s\n", host);

    return(s);
#endif WIRETAP
#ifdef XSERVER

    if (listener_sock < 0)
	if ((listener_sock = open_listener(WIRETAPPORT)) < 0) {
	    perror("open_listener");
	    return -1;
	} 

    if ((s = wait_for_connection(listener_sock)) < 0)
	return -1;

    for (count = 0; count < len; count++) {
	while (!write(s, &handshake[count], 1));
    }

    for (count = 0; count < len;) {

	FD_ZERO(&readfd);
	FD_SET(s, &readfd);
	select(s+1, &readfd, (fd_set *)0, &readfd, NULL);

	if (!read(s, &c, 1)) {
	    close(s);
	    return -1;
	}

	if (c == handshake[count]) {
	    count++;

	} else {
	    count = 0;
	}
    }

    return(s);

#endif XSERVER
}

open_listener(port)
int port;
{
    char   myname[MAXHOSTNAME+1];
    int    s;
    struct sockaddr_in sa;
    struct hostent *hp;
    struct servent *sp;

    bzero(&sa,sizeof(struct sockaddr_in));      /* clear our address */
    gethostname(myname,MAXHOSTNAME);            /* who are we? */
    hp= gethostbyname(myname);                  /* get our address info */
    if (hp == NULL)                             /* we don't exist !? */
        return(-1);
    sa.sin_family= hp->h_addrtype;              /* this is our host address */
    sa.sin_port= htons(port);			/* this is our port number */
    if ((s= socket(AF_INET,SOCK_STREAM,0)) < 0) /* create socket */
        return(-1);
    if (bind(s,&sa,sizeof sa,0) < 0) {
        close(s);
        return(-1);                               /* bind address to socket */
    }
    listen(s, 1);                               /* max # of queued connects */
    return(s);
}

int wait_for_connection(s)
int s;
{
    fd_set readfd;
    int t;

    FD_ZERO(&readfd);
    FD_SET(s, &readfd);

    if (debug)
	printf("Waiting for a connection\n");

    while (1) {
	select(s+1, &readfd, (fd_set *)0, (fd_set *)0, NULL);
	if ((t = get_connection(s)) < 0) {
	    if (errno == EINTR)
		continue;
	    perror("accept");
	    exit(1);
	}
	return(t);
    }
}

int get_connection(s)
int s;                    /* socket created with open_listener() */
{
    struct sockaddr_in isa; /* address of socket */
    int i;                  /* size of address */
    int t;                  /* socket of connection */
    int on = 1;
    struct hostent *hp;

    i = sizeof(isa);                   /* find socket's address */
    getsockname(s,&isa,&i);            /* for accept() */

    if ((t = accept(s,&isa,&i)) < 0)   /* accept connection if there is one */
        return(-1);

    hp = gethostbyaddr((char *) &isa.sin_addr, sizeof(isa.sin_addr), AF_INET);

    sprintf(NewHost, "%s", (hp == NULL) ?
	   (char *)inet_ntoa(isa.sin_addr) : hp->h_name);

    printf("Just got a connection from %s\n", NewHost);

    (void)ioctl(t, FIOCLEX, 0);
    (void)ioctl(t, FIONBIO, &on);

    return(t);
}


xconnect(channel)
char channel;
{
#ifdef WIRETAP
    int fd;
    struct sockaddr_in sin;
    struct hostent *ServerHP;
#ifndef SO_DONTLINGER
    struct linger linger;
#endif SO_DONTLINGER

    bzero((char *)&sin, sizeof(sin));
    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	return -1;

    if (gethostname(myhost, MAXHOSTNAMELEN) != 0) {
	printf("Couldnt get my host name!\n");
	exit (1);
    }
	
    if ((ServerHP = gethostbyname(myhost)) == NULL) {
	printf("Couldnt resolve my host name!\n");
	exit(1);
    }

    (void) setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,  (char *) NULL, 0);
    (void) setsockopt(fd, SOL_SOCKET, SO_USELOOPBACK,(char *) NULL, 0);
#ifdef  SO_DONTLINGER
    (void) setsockopt(fd, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0);
#else   SO_DONTLINGER
    linger.l_onoff = 0;
    linger.l_linger = 0;
    (void) setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&linger, sizeof linger);
#endif  SO_DONTLINGER

    sin.sin_family = AF_INET;
    bcopy((char *)ServerHP->h_addr, (char *)&sin.sin_addr, ServerHP->h_length);
    sin.sin_port = xsocket;

    if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
	switch (errno) {
	case ECONNREFUSED:
	    /* experience says this is because there is no Server
	       to connect to */
	    (void)close(fd);
	    fprintf(stderr, "No Server to Conenct To.\n");
	    return(-1);

        default:
	    (void)close(fd);
	    return (-1);
	}

    if (debug)
	printf("Connect to Server on port %d.\n", fd);

    return(fd);
#endif WIRETAP
}

xdisconnect(channel)
char channel;
{
    close(conn_list[channel].fd);
}

clear_listeners()
{
    FD_ZERO(&readmaster);
}

add_listener(s)
int s;
{
    FD_SET(s, &readmaster);
}

remove_listener(s)
int s;
{
    FD_CLR(s, &readmaster);
}


