#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <xti.h>
#include <sys/tk_types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include "funcdef.h"
#include "local.h"
#include "../defs.h"
#include "../funcs.h"

extern unsigned long my_address;

struct nfs_func {
	int (_fastcall *proc)(short _far *);
} _near nfs_funcs[] = {
	0,
	nfs_init,
	nfs_shutdown,
	nfs_socket,
	nfs_info,
	nfs_accept,
	nfs_drain,
	nfs_release,
	nfs_eof,
	nfs_read,
	nfs_write,
	nfs_recv,
	nfs_sendto,
	nfs_select,
	0
};

unsigned int near n_funcs = sizeof (nfs_funcs) / sizeof (nfs_funcs[0]);

int
main(argc, argv, envp)
int argc;
char **argv;
char **envp;
{
	return 0;
}

int
rpc_entry(buf, size)
short _far *buf;
int size;
{
    struct nfs_func near *nfp;
    int i;

    nfp = &nfs_funcs[buf[0]];
    if ((unsigned)buf[0] >= n_funcs || !nfp->proc) {
	buf[0] = -1;
	buf[2] = NETERR_BADCALL;
	return 6;
    }
    i = (nfp->proc)(buf);
    if (i < 0) {
	buf[0] = i;
	buf[1] = errno;
	buf[2] = convert_error(t_errno);
	return 6;
    }
    return i;
}

int _fastcall
nfs_info(buf)
short _far *buf;
{
    struct net_info _far *ni = (struct net_info _far *)&buf[1];

    ni->ip_address = my_address;
    ni->ip_broadcast = 0;
    buf[0] = 0;
    return sizeof (struct net_info) + sizeof (short);
}

int _fastcall
nfs_accept(buf)
short _far *buf;
{
    struct t_call *call;
    struct net_addr _far *addr = (struct net_addr _far *)&buf[1];
    int fd = buf[1];

    call = (struct t_call *)t_alloc(fd, T_CALL, T_ADDR|T_OPT);
    if (!call)
	return -1;
    if (t_listen(fd, call) < 0 ||
	t_accept(fd, fd, call) < 0) {
	t_free((char *)call, T_CALL);
	return -1;
    }
    buf[0] = fd;
    addr->host = ((struct sockaddr_in *)call->addr.buf)->sin_addr.s_addr;
    addr->socket = ntohs(((struct sockaddr_in *)call->addr.buf)->sin_port);
    t_free((char *)call, T_CALL);
    return sizeof (struct net_addr) + sizeof (short);
}

int _fastcall
nfs_release(buf)
short _far *buf;
{
    if (t_close(buf[1]) < 0)
	return -1;
    buf[0] = 0;
    return 2;
}

int _fastcall
nfs_eof(buf)
short _far *buf;
{
    if (t_sndrel(buf[1]) < 0)
	return -1;
    buf[0] = 0;
    return 2;
}

/*
 * buf[4] contains oflags, of which each bit indicates that a
 * particular socket can accept outgoing data.  Since there is no
 * way to tell this with PC/NFS without actually trying to send
 * data, we don't set bits in that flag.
 * Unfortunately, oflags also tells us when a connection can be
 * accepted with net_accept so we have to query those.
 */
int _fastcall
nfs_select(buf)
short _far *buf;
{
    u_long iflags = *(u_long _far *)&buf[2];
    u_long oflags = *(u_long _far *)&buf[4];
    u_long reti, reto;
    u_long mask;
    int nfds = buf[1];
    int i, x, n;

    reti = 0;
    reto = 0;
    n = 0;
    for (i = 0, mask = 1; i < nfds; i++, mask <<= 1) {
	if (mask & oflags) {
	    if (t_look(i) != 0) {
		reto |= mask;
		n++;
	    }
	}
	if (mask & iflags) {
	    if ((x = t_look(i)) > 0) {
		reti |= mask;
		n++;
	    } else if (x < 0)
		return -1;
	}
    }
    *(u_long _far *)&buf[2] = reti;
    *(u_long _far *)&buf[4] = reto;
    buf[0] = n;
    return 12;
}

void
_nullcheck()
{
}
