/*
 * Micro-X -- an X server for DOS
 * Copyright (C) 1993 StarNet Communications Corp.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 * StarNet Communications Corp.
 * 550 Lakeside Dr. #3
 * Sunnyvale CA 94086 US
 * http://www.starnet.com
 * x-dos@starnet.com
 */

#include <string.h>	/* for prototypes only */
#include "funcdef.h"
#include "local.h"
#include "../defs.h"

extern int _near errno;
extern char _near shared_buf[4096];
union {
    struct udp_input udp;
    struct udp_output udp_output;
    u_char buffer[1536];
} udp_io;

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

    ioctl(fd, 2, shared_buf, 11);
    if (shared_buf[0] > 0 && shared_buf[0] < 4) {
	errno = EWOULDBLOCK;
	return -1;
    }
    if (shared_buf[0] == 0) {
	errno = shared_buf[7];
	return -1;
    }
    ioctl(fd, 3, "\6\4", 2);
    buf[0] = fd;
    addr->socket = *(u_short *)&shared_buf[1];
    addr->host = *(u_long *)&shared_buf[3];
    return sizeof (struct net_addr) + sizeof (short);
}

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

int _fastcall
bw_eof(buf)
short _far *buf;
{
    if (ioctl(buf[1], 3, "\3", 1) < 0)
	return -1;
    buf[0] = 0;
    return 2;
}

int _fastcall
bw_select(buf)
short _far *buf;
{
    u_long iflags = *(u_long _far *)&buf[2];
    u_long oflags = *(u_long _far *)&buf[4];
    u_long reti = 0, reto = 0;
    u_long mask;
    int nfds = buf[1];
    int i, n = 0, x;

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

int _fastcall
bw_drain(buf)
short _far *buf;
{
    int len;

    len = read(buf[1], shared_buf, sizeof shared_buf);
    if (len <= 0) {
	if (len == 0)
	    errno = TCP_ERR_HANGUP;
	return -1;
    }
    buf[0] = len;
    return 2;
}

int _fastcall
bw_read(buf)
short _far *buf;
{
    int len;

    len = read(buf[1], shared_buf, buf[2]);
    if (len <= 0) {
	if (len == 0)
	    errno = TCP_ERR_HANGUP;
	return -1;
    }
if ((unsigned)len > (unsigned)buf[2]) {
dfputs("read too big: returned ");
printd(len);
dfputs(" asked for ");
printd(buf[2]);
dfputs("\r\n");
}
    buf[0] = len;
    return 2;
}

int _fastcall
bw_sendto(buf)
short _far *buf;
{
    int len;
    int fd = buf[1];
    struct net_addr _far *addr = (struct net_addr _far *)&buf[4];

    udp_io.udp_output.udp_dest = addr->host;
    udp_io.udp_output.udp_dp = addr->socket;
    udp_io.udp_output.udp_odlen = buf[2];
    memcpy((char *)(&udp_io.udp_output + 1), shared_buf,
	    udp_io.udp_output.udp_odlen);
    len = udp_io.udp_output.udp_odlen + sizeof (udp_io.udp_output);
    len = write(fd, &udp_io, len);
    if (len < 0)
	return -1;
    len -= sizeof (udp_io.udp_output);
    buf[0] = len;
    return 2;
}

int _fastcall
bw_recv(buf)
short _far *buf;
{
    int fd = buf[1];
    int i, len;
    struct udph *udp;
    struct net_addr _far *addr = (struct net_addr _far *)&buf[1];

    i = read(fd, &udp_io, sizeof udp_io);
    if (i < 0)
	return -1;
    udp = (struct udph *)&udp_io.buffer[udp_io.udp.udp_ptr];
    len = ntohs(udp_io.udp.ip.tlen);
    addr->host = udp_io.udp.ip.ipsource;
    addr->socket = udp->source;
    len -= sizeof (struct udph);
    if (len > buf[2])
	len = buf[2];
    memcpy(shared_buf, (char *)(udp + 1), len);
    buf[0] = len;
    return sizeof (struct net_addr) + sizeof (short);
}

int _fastcall
bw_write(buf)
short _far *buf;
{
    int len;

    len = write(buf[1], shared_buf, buf[2]);
    if (len < 0)
	return -1;
    buf[0] = len;
    return 2;
}
