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"
# define FD_SETSIZE   1024
# include <winsock.h>
# include "str.h"
# include "array.h"
# include "object.h"
# include "comm.net.h"

struct _connection_ {
    SOCKET fd;				/* file descriptor */
    struct sockaddr_in addr;		/* internet address of connection */
    struct _connection_ *next;		/* next in list */
    char host[16];			/* ascii ip number of peer */
    char hostlen;			/* length of host string */
};

static int nusers;			/* # of users */
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. */

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

    /* initialize winsock */
    if (WSAStartup(MAKEWORD(1, 1), &wsadata) != 0) {
	P_message("WSAStartup failed (no winsock?)\n");
	exit(2);
    }
    if (LOBYTE(wsadata.wVersion) != 1 || HIBYTE(wsadata.wVersion) != 1) {
	WSACleanup();
	P_message("Winsock 1.1 not supported\n");
	exit(2);
    }

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

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

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

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

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

    return conn;
}

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

    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 == INVALID_SOCKET) {
	return (connection *)NULL;
    }

    on = 1;
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, 
		   sizeof(on)) != 0) {
        closesocket(fd);
	return (connection *)NULL;
    }

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

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

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

    nonblock = TRUE;
    if (ioctlsocket(fd, FIONBIO, &nonblock) != 0) {
	closesocket(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(connection *conn)
{
    SOCKET 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 == INVALID_SOCKET) {
	return (connection *) NULL;
    }

    on = 1;
    setsockopt(conn->fd, SOL_SOCKET, SO_OOBINLINE, (char *)&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(char *host, int port, int protocol)
{
    SOCKET fd;
    static struct sockaddr_in sin;
    unsigned long nonblock;
    int err;

    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((u_short) port);
    sin.sin_addr.s_addr = inet_addr(host);

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

    nonblock = TRUE;
    if (ioctlsocket(fd, FIONBIO, &nonblock) != 0) {
	closesocket(fd);
	return conn_new(INVALID_SOCKET, &sin);
    }

    if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR) {
	err = WSAGetLastError();
	if (err != WSAEWOULDBLOCK) {
	    closesocket(fd);
	    return conn_new(INVALID_SOCKET, &sin);
	}
    }

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

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

    if (conn->fd == INVALID_SOCKET)
	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(connection *conn)
{
    return conn->fd != INVALID_SOCKET && FD_ISSET(conn->fd, &writefds);
}

/*
 * NAME:	conn->del()
 * DESCRIPTION:	delete a connection
 */
void conn_del(connection *conn)
{
    if (conn->fd != INVALID_SOCKET) {
	closesocket(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 = INVALID_SOCKET;
    }
    conn->next = flist;
    flist = conn;
}

/*
 * NAME:	conn->wait()
 * DESCRIPTION:	mark a connection as waiting for writability
 */
void conn_wait(connection *conn, int wait)
{
    if (conn->fd == INVALID_SOCKET)
	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(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(0, &readfds, &writefds, (fd_set *) NULL, &timeout);
    /*
     * 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(0, (fd_set *) NULL, &xxxfds, (fd_set *) NULL, &timeout);
    return retval;
}

/*
 * NAME:	conn->recvfrom()
 * DESCRIPTION: read a datagram
 */
int conn_recvfrom(connection *conn, char *buf, int size)
{
    struct sockaddr_in sin;
    int len = sizeof(sin);
    
    if (conn->fd == INVALID_SOCKET) {
	return -1;
    }
    if (!FD_ISSET(conn->fd, &readfds)) {
	return 0;
    }
    size = recvfrom(conn->fd, buf, size, 0, (struct sockaddr *)&sin, &len);
    memcpy(&(conn->addr), &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(connection *conn, char *buf, int size)
{
    if (conn->fd == INVALID_SOCKET) {
	return -1;
    }
    if (!FD_ISSET(conn->fd, &readfds) || size == 0) {
	return 0;
    }
    size = recv(conn->fd, buf, size, 0);
    return (size == 0) ? -1 : size;
}

/*
 * NAME:	conn->sendto()
 * DESCRIPTION: send a datagram
 */
void conn_sendto(connection *conn, char *data, int size, char *host, int port)
{
    static struct sockaddr_in sin;
    if (conn->fd != INVALID_SOCKET) {
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = inet_addr(host);
	sin.sin_port = htons((unsigned short) port);
	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(connection *conn, char *buf, int size)
{
    int len;
    int err;

    if (conn->fd == INVALID_SOCKET) {
	return -1;
    } else if (!FD_ISSET(conn->fd, &xxxfds)) {
	return 0;
    } else {
	/* I'm assuming Win32 writes are not interruptible. */
	len = send(conn->fd, buf, size, 0);
	if (len == SOCKET_ERROR) {
	    FD_CLR(conn->fd, &xxxfds);
	    err = WSAGetLastError();
	    if (err == WSAEWOULDBLOCK) {
		return 0;
	    } else {
		closesocket(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 = INVALID_SOCKET;
		return -1;
	    }
	}
	return len;
    }
}

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

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