main.c 5.96 KB
/*
 * main.c: driver daemon test program (verify we can connect to daemon).
 *
 * Copyright 1995, Silicon Graphics, Inc.
 * All Rights Reserved.
 *
 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
 * the contents of this file may not be disclosed to third parties, copied or
 * duplicated in any form, in whole or in part, without the prior written
 * permission of Silicon Graphics, Inc.
 *
 * RESTRICTED RIGHTS LEGEND:
 * Use, duplication or disclosure by the Government is subject to restrictions
 * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
 * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
 * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
 * rights reserved under the Copyright Laws of the United States.
 *
 * $Revision: 1.1.1.1 $
 */

#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/file.h>
#include <sys/ioctl.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <bstring.h>
#include <string.h>

#include "driverd.h"


static char *
copystring(char * const src, const int len)
{
    char *dst;

    dst = malloc((unsigned int)len + 1);
    if (dst) {
        strncpy (dst, src, (unsigned int)len);
        dst[len] = '\0';
    }

    return dst;
}

static int MakeTCPConnection (
    char *phostname,
    int iserver,
    int retries,
    int *familyp)			/* RETURN */
{
    char hostnamebuf[256];		/* tmp space */
    unsigned long hostinetaddr;		/* result of inet_addr of arpa addr */
    struct sockaddr_in inaddr;		/* IP socket */
    struct sockaddr *addr;		/* generic socket pointer */
    int addrlen;			/* length of addr */
    struct hostent *hp;			/* entry in hosts table */
    int fd;				/* file descriptor to return */

#define INVALID_INETADDR ((unsigned long) -1)

    if (!phostname) {
	hostnamebuf[0] = '\0';
	gethostname(hostnamebuf, sizeof hostnamebuf);
	phostname = hostnamebuf;
    }

    /*
     * if numeric host name then try to parse it as such; do the number
     * first because some systems return garbage instead of INVALID_INETADDR
     */
    if (isascii(phostname[0]) && isdigit(phostname[0])) {
	hostinetaddr = inet_addr (phostname);
    } else {
	hostinetaddr = INVALID_INETADDR;
    }

    /*
     * try numeric
     */
    if (hostinetaddr == INVALID_INETADDR) {
	if ((hp = gethostbyname(phostname)) == NULL) {
	    /* No such host! */
	    return -1;
	}
	if (hp->h_addrtype != AF_INET) {  /* is IP host? */
	    /* Not an Internet host! */
	    return -1;
	}
 
	/* Set up the socket data. */
	inaddr.sin_family = hp->h_addrtype;
	bcopy ((char *)hp->h_addr, (char *)&inaddr.sin_addr, 
	       sizeof(inaddr.sin_addr));
    } else {
	inaddr.sin_addr.s_addr = hostinetaddr;
	inaddr.sin_family = AF_INET;
    }

    addr = (struct sockaddr *) &inaddr;
    addrlen = sizeof (struct sockaddr_in);

    inaddr.sin_port = pmap_getport(&inaddr, DRIVERD_RPC_PORT, 1, IPPROTO_TCP);
    if (inaddr.sin_port == 0) {
	inaddr.sin_port = DRIVERD_TCP_PORT + iserver;
	inaddr.sin_port = htons (inaddr.sin_port);	/* may be funky macro */
    }

    /*
     * Open the network connection.
     */
    do {
	if ((fd = socket ((int) addr->sa_family, SOCK_STREAM, 0)) < 0) {
	    return -1;
	}

	/*
	 * turn off TCP coalescence
	 */
#ifdef TCP_NODELAY
	{
	    int tmp = 1;
	    setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof (int));
	}
#endif

	/*
	 * connect to the socket; if there is no driver daemon server or 
	 * if the backlog has been reached, then ECONNREFUSED will be returned.
	 */
	if (connect (fd, addr, addrlen) < 0) {
	    int olderrno = oserror();
	    (void) close (fd);
	    if (olderrno != ECONNREFUSED || retries <= 0) {
		setoserror(olderrno);
		return -1;
	    }
	    sleep (1);
	} else {
	    break;
	}
    } while (retries-- > 0);

    return fd;
}

main(int argc, char *argv[])
{
    int daemonFd;
    int family;
    int numread, pend;
    int i;
    RegisterSession regSession;
    EventFromGame gameEvent;
    unsigned int data[256];

    fd_set MySocket;

    daemonFd = MakeTCPConnection(NULL, 0, 10, &family);
    fprintf(stderr, "daemonFd = %d\n", daemonFd);

    /*
     * Firstly, register ourselves with the daemon.
     */

    regSession.dd_header = DRIVERD_REGISTER_SESSION;
    regSession.id = ((id_t)getpid());
    regSession.min_event = 0;
    regSession.max_event = 50;
    write(daemonFd, &regSession, sizeof(RegisterSession));

    /*
     * If any command line args are supplied, assume we are taking the role
     * of the "emulator", and periodically write events to the daemon.
     *
     * Otherwise (argc == 1), take the role of a host side client
     * and select on our private fd (to the daemon) & read events passed to
     * us from the emulator/game.
     */
    if (argc == 1) {

	FD_ZERO(&MySocket);
	FD_SET(daemonFd, &MySocket);

	while(1) {

	    numread = select(128, &MySocket, NULL, NULL, NULL);

	    if (ioctl(daemonFd, FIONREAD, (char *) &pend) < 0) {
		fprintf(stderr, 
"dd_test: Unable to check to see how many bytes are pending.\n");
	    } else {
		numread = read(daemonFd, data, pend);

		/*
		 * Select can return, indicating there's data to be read,
		 * but if FIONREAD says there is no data, it's because the
		 * daemon has gone away.  Exit(0) is the only sane alternative.
		 */
		if (numread == 0) {
		    exit(0);
		}
		fprintf(stderr, "received %d bytes from daemon\n", numread);

		for (i = 0; i < (numread >> 2); i++) {
		    fprintf(stderr, "0x%x = %d ", data[i], data[i]);
		}
		fprintf(stderr, "\n");
	    }
	    fflush(stderr);
	}
    } else {
	/*
 	 * Periodically send events & see if we wake up clients.
	 */
	numread = 0;
	gameEvent.dd_header = DRIVERD_EVENT_FROM_GAME;
	while(1) {
	    gameEvent.event = numread;
	    fprintf(stderr, "Sending event %d\n", numread);
	    fflush(stderr);
	    write(daemonFd, &gameEvent, sizeof(EventFromGame));
	    sleep(1);
	    numread += 10;
	    if (numread > 100)
		numread = 0;
        }
    }
}