
/*
 *  DNETLIB.C
 *
 *	DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved
 *
 *  Library Interface for DNET.
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <errno.h>
#ifdef O_CREAT
#include <sys/file.h>
#endif

extern char *getenv();

typedef unsigned short uword;
typedef unsigned long ulong;
typedef unsigned char ubyte;
typedef struct sockaddr SOCKADDR;

typedef struct {
	int s;
	uword port;
} CHANN;

#define NAMELEN sizeof(".PORT.XXXXX")
#define NAMEPAT "%s.PORT.%ld"

CHANN *
DListen(port)
uword port;
{
    CHANN *chan;
    int s;
    SOCKADDR *sa = (SOCKADDR *)malloc(sizeof(SOCKADDR)+256);
    char *dirstr = getenv("DNETDIR") ? getenv("DNETDIR") : "";

    sprintf(sa->sa_data, NAMEPAT, dirstr, port);
    sa->sa_family = AF_UNIX;
    unlink(sa->sa_data);

    s = socket(PF_UNIX, SOCK_STREAM, 0);
    fcntl(s, F_SETOWN, getpid());
    if (bind(s, sa, sizeof(*sa)-sizeof(sa->sa_data)+strlen(sa->sa_data)) < 0) {
	close(s);
	free(sa);
	return(NULL);
    }
    if (listen(s, 5) < 0) {
        close(s);
        unlink(sa->sa_data);
	free(sa);
        return(NULL);
    }
    chan = (CHANN *)malloc(sizeof(CHANN));
    chan->s = s;
    chan->port = port;
    free(sa);
    return(chan);
}


DUnListen(chan)
CHANN *chan;
{
    char buf[32];

    close(chan->s);
    sprintf(buf, NAMEPAT, chan->port);
    unlink(buf);
    free(chan);
}

DAccept(chan)
CHANN *chan;
{
    SOCKADDR sa;
    int addrlen = sizeof(sa);
    int fd;

    fd = accept(chan->s, &sa, &addrlen);
    return(fd);
}

DOpen(host, port, txpri, rxpri)
char *host;
uword port;
char txpri, rxpri;
{
    int s;
    char rc;
    short xb[3];
    SOCKADDR *sa = (SOCKADDR *)malloc(sizeof(SOCKADDR)+256);
    char *dirstr = getenv("DNETDIR") ? getenv("DNETDIR") : "";

    if (rxpri < -127)
	rxpri = -127;
    if (rxpri > 126)
	rxpri = 126;
    if (txpri < -127)
	txpri = -127;
    if (txpri > 126)
	txpri = 126;

    if (host == NULL)
	host = (getenv("DNETHOST")) ? getenv("DNETHOST"):"";

    sa->sa_family = AF_INET;
    sprintf(sa->sa_data, "%s%s%s", dirstr, "DNET.", host);

    s = socket(PF_UNIX, SOCK_STREAM, 0);
    fcntl(s, F_SETOWN, getpid());
    if (connect(s, sa, sizeof(*sa)-sizeof(sa->sa_data)+
    strlen(sa->sa_data))<0) {
        close(s);
        free(sa);
        return(-1);
    }
    free(sa);
    xb[0] = port;
    ((char *)&xb[1])[0] = txpri;
    ((char *)&xb[1])[1] = rxpri;
    write(s, xb, 4);
    if (read(s, &rc, 1) == 1 && rc == 0)
        return(s);
    close(s);
    return(-1);
}

DEof(fd)
{
    char dummy;

    shutdown(fd, 1);
    write(fd, &dummy, 0);
}

gwrite(fd, buf, bytes)
char *buf;
{
    int n;
    int orig = bytes;
    extern int errno;
    while (bytes) {
	n = write(fd, buf, bytes);
	if (n > 0) {
	    bytes -= n;
	    buf += n;
	    continue;
	}
	if (n < 0) {
	    if (errno == EINTR)
		continue;
	    if (errno == EWOULDBLOCK) {
		int wm = 1 << fd;
		int em = 1 << fd;
		if (select(fd+1, NULL, &wm, &em, NULL) < 0)
		    continue;
		if (wm)
		    continue;
	    }
	    return(orig - bytes);
	}
    }
    return(orig);
}

gread(fd, buf, bytes)
char *buf;
{
    int n;
    int orig = bytes;
    extern int errno;
    while (bytes) {
	n = read(fd, buf, bytes);
	if (n > 0) {
	    bytes -= n;
	    buf += n;
	    break;
	}
	if (n < 0) {
	    if (errno == EINTR)
		continue;
	    if (errno == EWOULDBLOCK) {
		int rm = 1 << fd;
		int em = 1 << fd;
		if (select(fd+1, &rm, NULL, &em, NULL) < 0)
		    continue;
		if (rm)
		    continue;
	    }
	    return(orig - bytes);
	}
	if (n == 0)
	    break;
    }
    return(orig - bytes);
}

ggread(fd, buf, bytes)
char *buf;
{
    int n;
    int ttl = 0;
    while (bytes) {
	n = gread(fd, buf, bytes);
	if (n > 0) {
	    bytes -= n;
	    buf += n;
	    ttl += n;
	    continue;
	}
	return(-1);
    }
    return(ttl);
}

/*
 *	Convert to and from 68000 longword format.  Of course, it really
 *	doesn't matter what format you use, just as long as it is defined.
 */

ntohl68(n)
ulong n;
{
    return(
	(((ubyte *)&n)[0] << 24)|
	(((ubyte *)&n)[1] << 16)|
	(((ubyte *)&n)[2] << 8)|
	(((ubyte *)&n)[3])
    );
}

htonl68(n)
ulong n;
{
    ulong v;
    ((ubyte *)&v)[0] = n >> 24;
    ((ubyte *)&v)[1] = n >> 16;
    ((ubyte *)&v)[2] = n >> 8;
    ((ubyte *)&v)[3] = n;
    return(v);
}

