gurba-0.40/
gurba-0.40/bin/
gurba-0.40/lib/
gurba-0.40/lib/cmds/guild/fighter/
gurba-0.40/lib/cmds/monster/
gurba-0.40/lib/cmds/race/catfolk/
gurba-0.40/lib/cmds/race/dwarf/
gurba-0.40/lib/cmds/verb/
gurba-0.40/lib/daemons/data/
gurba-0.40/lib/data/boards/
gurba-0.40/lib/data/messages/
gurba-0.40/lib/data/players/
gurba-0.40/lib/design/
gurba-0.40/lib/domains/gurba/
gurba-0.40/lib/domains/gurba/guilds/fighter/
gurba-0.40/lib/domains/gurba/monsters/
gurba-0.40/lib/domains/gurba/objects/armor/
gurba-0.40/lib/domains/gurba/objects/clothing/
gurba-0.40/lib/domains/gurba/objects/weapons/
gurba-0.40/lib/domains/gurba/vendors/
gurba-0.40/lib/kernel/cmds/admin/
gurba-0.40/lib/kernel/daemons/
gurba-0.40/lib/kernel/include/
gurba-0.40/lib/kernel/lib/
gurba-0.40/lib/kernel/net/
gurba-0.40/lib/kernel/sys/
gurba-0.40/lib/logs/
gurba-0.40/lib/pub/
gurba-0.40/lib/std/modules/languages/
gurba-0.40/lib/std/races/
gurba-0.40/lib/std/races/monsters/
gurba-0.40/lib/wiz/fudge/
gurba-0.40/lib/wiz/spud/
gurba-0.40/src/host/beos/
gurba-0.40/src/host/pc/res/
gurba-0.40/src/kfun/
gurba-0.40/src/lpc/
gurba-0.40/src/parser/
gurba-0.40/tmp/
# define INCLUDE_FILE_IO
# include "dgd.h"
# include <sys/time.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <netdb.h>
# include <errno.h>
# include "str.h"
# include "array.h"
# include "object.h"
# include "comm.net.h"

# define EXT_SIZE 16384   /* size requested when extending a buffer */

struct _connection_ {
    int fd;				/* file descriptor */
    struct sockaddr_in sin;		/* peer's address */
    struct _connection_ *next;		/* next in list */
    int extended;                       /* output buffer has been extended */
    char host[16];			/* ascii ip number of peer */
    char hostlen;			/* length of host string */
};

static connection *connections;		/* connections array */
static connection *flist;		/* list of free connections */
static fd_set rfds;			/* read file descriptor bitmap */
static fd_set wfds;			/* write file descriptor bitmap */
static fd_set readfds;			/* fds selected for reading */
static fd_set writefds;			/* fds selected for writing */
static fd_set xxxfds;
static fd_set ufds;                     /* identical to rfds, minus those that
                                           are blocked */
static int maxfd;			/* largest fd opened yet */

/*
 * NAME:	conn->init()
 * DESCRIPTION:	initialize connections
 */
void conn_init(maxusers)
int maxusers;
{
    register int n;
    register connection *conn;

    connections = ALLOC(connection, maxusers);
    for (n = maxusers, conn = connections; n > 0; --n, conn++) {
	conn->fd = -1;
	conn->next = flist;
	flist = conn;
    }

    FD_ZERO(&rfds);
    FD_ZERO(&wfds);
    FD_ZERO(&ufds);
}

/*
 * NAME:	conn->finish()
 * DESCRIPTION:	terminate connections
 */
void conn_finish()
{
}

/*
 * NAME:	conn->new()
 * DESCRIPTION:	initialize a new connection struct
 */
static connection *conn_new(fd, sin)
int fd;
struct sockaddr_in *sin;
{
    register connection *conn;

    conn = flist;
    flist = conn->next;
    conn->fd = fd;
    memcpy(&conn->sin, sin, sizeof(conn->sin));
    strcpy(conn->host, inet_ntoa(sin->sin_addr));
    conn->hostlen = strlen(conn->host);
    if (fd >= 0) {
	FD_SET(fd, &xxxfds);
	if (fd > maxfd) {
	    maxfd = fd;
	}
    }
    return conn;
}

/*
 * NAME:	conn->extend()
 * DESCRIPTION:	enlarge a socket's output buffer
 */
static void conn_extend(conn)
connection *conn;
{
    int bufsize;
    int sz = sizeof(bufsize);

    conn->extended = 1;
    if (getsockopt(conn->fd, SOL_SOCKET, SO_SNDBUF, (void *)&bufsize, &sz) >= 0
	&& sz == sizeof(bufsize) && bufsize < EXT_SIZE) {
	bufsize = EXT_SIZE;
	setsockopt(conn->fd, SOL_SOCKET, SO_SNDBUF,
		   (void *)&bufsize, sizeof(bufsize));
    }
}


/*
 * NAME:	conn->listen()
 * DESCRIPTION:	bind a connection to a local port
 */
connection *conn_listen(port, protocol)
int port, protocol;
{
    int fd;
    static struct sockaddr_in sin;
    int size;
    int on = 1;

    if (port < 0) {
	/* Request automatic port assignment */
	port = 0;
    }

    /* No free connections:  see the comment about nusers in comm_receive. */
    if (flist == (connection *) NULL) {
	return (connection *) NULL;
    }

    if (protocol == PRC_UDP) {
	fd = socket(PF_INET, SOCK_DGRAM, 0);
    } else {
	fd = socket(PF_INET, SOCK_STREAM, 0);
    }
    if (fd < 0) {
	return (connection *)NULL;
    }
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, 
		   sizeof(on)) < 0) {
        close(fd);
	return (connection *)NULL;
    }

    sin.sin_family = AF_INET;
    sin.sin_port = htons(port);
    sin.sin_addr.s_addr = INADDR_ANY;  /* htonl? */
    if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
	close(fd);
	return (connection *)NULL;
    }

    size = sizeof(sin);
    if (getsockname(fd, (struct sockaddr *)&sin, &size) < 0) {
	close(fd);
	return (connection *)NULL;
    }

    if (protocol != PRC_UDP && listen(fd, 64) < 0) {
	close(fd);
	return (connection *)NULL;
    }

    if (fcntl(fd, F_SETFL, FNDELAY) < 0) {
	close(fd);
	return (connection *)NULL;
    }

    FD_SET(fd, &rfds);
    FD_SET(fd, &ufds);
    return conn_new(fd, &sin);
}

/*
 * NAME:	conn->accept()
 * DESCRIPTION:	accept a connection
 */
connection *conn_accept(conn)
connection *conn;
{
    int fd;
    struct sockaddr_in sin;
    int len, on;
    
    if (!FD_ISSET(conn->fd, &readfds)) {
	return (connection *) NULL;
    }

    len = sizeof(sin);
    fd = accept(conn->fd, (struct sockaddr *) &sin, &len);
    if (fd < 0) {
	return (connection *) NULL;
    }

    on = 1;
    setsockopt(conn->fd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on));

    FD_SET(fd, &rfds);
    FD_SET(fd, &ufds);
    return conn_new(fd, &sin);
}

/*
 * NAME:	conn->connect()
 * DESCRIPTION:	initiate a tcp connection
 */
connection *conn_connect(host, port, protocol)
char *host;
int port, protocol;
{
    int fd;
    static struct sockaddr_in sin;

    if (protocol != PRC_TCP) {
        return (connection *) NULL;
    }

    /* No free connections:  see the comment about nusers in comm_receive(). */
    if (flist == (connection *) NULL) {
	return (connection *) NULL;
    }

    sin.sin_family = AF_INET;
    sin.sin_port = htons(port);
    sin.sin_addr.s_addr = inet_addr(host);

    fd = socket(PF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
	return conn_new(-1, &sin);
    }

    if (fcntl(fd, F_SETFL, FNDELAY) < 0) {
	close(fd);
	return conn_new(-1, &sin);
    }

    if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0 &&
	!(errno == EINPROGRESS || errno == EAGAIN)) {
	close(fd);
	return conn_new(-1, &sin);
    }

    FD_SET(fd, &wfds);
    return conn_new(fd, &sin);
}

/*
 * NAME:	conn->connected()
 * DESCRIPTION:	mark a connecting socket as active
 */
int conn_connected(conn)
register connection *conn;
{
    struct sockaddr sa;
    int salen = sizeof(sa);

    if (conn->fd == -1)
	return -1;

    if (!FD_ISSET(conn->fd, &writefds))
	return 0;

    /* Use getpeername() solely to check for errors. */
    if (getpeername(conn->fd, &sa, &salen) < 0) {
	FD_CLR(conn->fd, &wfds);
	return -1;
    }

    FD_CLR(conn->fd, &wfds);
    FD_SET(conn->fd, &rfds);
    FD_SET(conn->fd, &ufds);
    return 1;
}
    
/*
 * NAME:	conn->writable()
 * DESCRIPTION:	check if a connection has been selected for writing
 */
int conn_writable(conn)
register connection *conn;
{
    return conn->fd >= 0 && FD_ISSET(conn->fd, &writefds);
}

/*
 * NAME:	conn->del()
 * DESCRIPTION:	delete a connection
 */
void conn_del(conn)
register connection *conn;
{
    if (conn->fd >= 0) {
	close(conn->fd);
	FD_CLR(conn->fd, &rfds);
        FD_CLR(conn->fd, &ufds);
	FD_CLR(conn->fd, &wfds);
	FD_CLR(conn->fd, &readfds);
	FD_CLR(conn->fd, &writefds);
	conn->fd = -1;
    }
    conn->next = flist;
    flist = conn;
}

/*
 * NAME:	conn->wait()
 * DESCRIPTION:	mark a connection as waiting for writability
 */
void conn_wait(conn, wait)
register connection *conn;
register int wait;
{
    if (conn->fd < 0) {
	return;
    }

    if (wait) {
	FD_SET(conn->fd, &wfds);
    } else {
	FD_CLR(conn->fd, &wfds);
    }
}

/*
 * NAME:        conn->block()
 * DESCRIPTION: temporarily unselect (block) a connection with respect to
 *              incoming data
 */
void conn_block(conn, flag)
register connection *conn;
register int flag;
{
    if (conn->fd < 0) {
        return;
    }

    if (flag) {
        FD_CLR(conn->fd, &ufds);
        FD_CLR(conn->fd, &readfds);
    } else {
        FD_SET(conn->fd, &ufds);
    }
}

/*
 * NAME:	conn->select()
 * DESCRIPTION:	wait for input from connections
 */
int conn_select(wait)
int wait;
{
    struct timeval timeout;
    int retval;

    /*
     * First, check readability and writability for binary sockets with pending
     * data only.
     */
    memcpy(&readfds, &ufds, sizeof(fd_set));
    memcpy(&writefds, &wfds, sizeof(fd_set));
    timeout.tv_sec = (int) wait;
    timeout.tv_usec = 0;
    retval = select(maxfd + 1, &readfds, &writefds, (fd_set *) NULL, &timeout);
    if (retval < 0) {
        FD_ZERO(&readfds);
    }

    /*
     * Now check writability for all sockets in a polling call.
     */
    memcpy(&xxxfds, &rfds, sizeof(fd_set));
    timeout.tv_sec = 0;
    timeout.tv_usec = 0;
    select(maxfd + 1, (fd_set *) NULL, &xxxfds, (fd_set *) NULL, &timeout);
    return retval;
}

/*
 * NAME:	conn->recvfrom()
 * DESCRIPTION: read a datagram
 */
int conn_recvfrom(conn, buf, size)
connection *conn;
char *buf;
int size;
{
    struct sockaddr_in sin;
    int len = sizeof(sin);
    
    if (conn->fd < 0) {
	return -1;
    }
    if (!FD_ISSET(conn->fd, &readfds)) {
	return 0;
    }
    size = recvfrom(conn->fd, buf, size, 0, (struct sockaddr *)&sin, &len);
    memcpy(&(conn->sin), &sin, len);
    strcpy(conn->host, inet_ntoa(sin.sin_addr));
    conn->hostlen = strlen(conn->host);
    return size;  /* Size may legitimately be 0 */
}

/*
 * NAME:	conn->read()
 * DESCRIPTION:	read from a connection
 */
int conn_read(conn, buf, size)
connection *conn;
char *buf;
int size;
{
    if (conn->fd < 0) {
	return -1;
    }
    if (!FD_ISSET(conn->fd, &readfds) || size == 0) {
	return 0;
    }
    size = read(conn->fd, buf, size);
    return (size == 0) ? -1 : size;
}

/*
 * NAME:	conn->sendto()
 * DESCRIPTION: send a datagram
 */
void conn_sendto(conn, data, size, host, port)
connection *conn;
char *data, *host;
int   size,  port;
{
    static struct sockaddr_in sin;
    if (conn->fd >= 0) {
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = inet_addr(host);
	sin.sin_port = htons(port);
	if (sendto(conn->fd, data, size, 0, (struct sockaddr *)&sin,
		   sizeof(sin)) < 0
	    && errno == EMSGSIZE && !conn->extended) {
	    conn_extend(conn);
	    sendto(conn->fd, data, size, 0, (struct sockaddr *)&sin,
		   sizeof(sin));
	}
    }
}

/*
 * NAME:	conn->write()
 * DESCRIPTION:	write to a connection; return the number of bytes written
 */
int conn_write(conn, buf, size)
connection *conn;
char *buf;
register int size;
{
    int len;

    if (conn->fd < 0) {
	return -1;
    } else if (!FD_ISSET(conn->fd, &xxxfds)) {
	return 0;
    } else {
	len = write(conn->fd, buf, size);
	if (len < 0) {
	    FD_CLR(conn->fd, &xxxfds);
	    if (errno == EWOULDBLOCK) {
		return 0;
	    } else {
		close(conn->fd);
		FD_CLR(conn->fd, &rfds);
                FD_CLR(conn->fd, &ufds);
		FD_CLR(conn->fd, &wfds);
		FD_CLR(conn->fd, &readfds);
		FD_CLR(conn->fd, &writefds);
		conn->fd = -1;
		return -1;
	    }
	}
	if (len < size && !conn->extended) {
	    conn_extend(conn);
	}
	return len;
    }
}

/*
 * NAME:	conn->ipnum()
 * DESCRIPTION:	return the ip number of a connection
 */
string *conn_ipnum(conn)
connection *conn;
{
    return str_new(conn->host, conn->hostlen);
}

/*
 * NAME:	conn->port()
 * DESCRIPTION:	return the port number of a connection
 */
Int conn_port(conn)
connection *conn;
{
    return ntohs(conn->sin.sin_port);
}