driverd.c 5.17 KB
/**************************************************************************
 *									  *
 *		 Copyright (C) 1994, Silicon Graphics, Inc.		  *
 *									  *
 *  These coded instructions, statements, and computer programs  contain  *
 *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
 *  are protected by Federal copyright law.  They  may  not be disclosed  *
 *  to  third  parties  or copied or duplicated in any form, in whole or  *
 *  in part, without the prior written consent of Silicon Graphics, Inc.  *
 *									  *
 **************************************************************************/

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

#include <sys/socket.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>


#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#ifdef __sgi__
#include <bstring.h>
#endif
#include <string.h>
#include <ctype.h>

/* cannot include rpc/pmap_clnt.h XXX hal what is this for? */
extern u_short pmap_getport(struct sockaddr_in *, u_long,u_long,u_int);
#ifdef __linux__
#define setoserror(x)	(errno=x)
#define oserror()	(errno)
#endif

#include "driverd.h"
#include "sys/u64gio.h"

int MakeDriverDConnection (
    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;
}

int
readn(int fd, void *buf, int nbytes)
{
    unsigned char *bp;
    int n, ret;
    
    ret = nbytes;
    while (nbytes) {
	n = read(fd, buf, nbytes);
	if (n < 0) {
printf("readn failure fd %d, n is %d\n", fd, n);
perror("XXX");
	    return n;
	}
	buf = (void *)((int)buf + n);
	nbytes -= n;
    }
    return ret;
}

/*
 * Fake open code (user code side)
 * Translate open into a socket connection to driverd
 */
emopen(char *file)
{
    int family;
    
    return (MakeDriverDConnection(NULL, 0, 10, &family));
}

/*
 * Fake ioctl code (user code side)
 * Translate ioctl into data packet to send over the socket connection
 * to driverd
 */
 
int
emioctl(int fd, int request, long arg)
{
    IoctlRequest req;
    int data;
    

    req.dd_header = DRIVERD_IOCTL_REQUEST;
    req.request = request;
    write(fd, &req, sizeof(req));
    
    switch (request) {
    case U64_RESET:
	fprintf(stderr, "Reset not implemented\n");
	break;
	
    case U64_WRITE:
    case U64_SAFE_WRITE:
	write(fd, (void *)arg, sizeof(u64_write_arg_t));
	write(fd, ((struct u64_write_arg *)arg)->buffer,
		((struct u64_write_arg *)arg)->nbytes);
		
	read(fd, &data, sizeof(data));	    /* response */
	break;
	
    case U64_READ:
	write(fd, (void *)arg, sizeof(u64_read_arg_t));
	
	read(fd, &data, sizeof(data));	    /* response is count*/

	/* now read data */
	return (readn(fd, ((struct u64_read_arg *)arg)->buffer, data));
	break;

    case U64_LISTEN:
	data = arg;
	write(fd, &data, sizeof(data));
    }
}