/*
Copyright (C) 1996-1997 Id Software, Inc.

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.

*/
#include <go32.h>
#include "mpdosock.h"

//#include "types.h"
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;

//#include "lpc.h"
typedef struct
{
	short  version;            // version of LPC requested
	short  sizeOfArgs;         // size of arguments
	short  service;            // service # requested
	char   Data[1];            // data
} LPCData;

typedef struct
{
	short version;             // LPC version
	short sizeOfReturn;        // return data size
	short error;               // any error codes
	short noRet;               // number of returns
	char  Data[1];             // data
} LPCReturn;

//#include "services.h"
#define  MAXSOCKETS  20

// services
#define LPC_SOCKBIND        4
#define LPC_SOCKGETHOSTBYNAME   5
#define LPC_SOCKGETHOSTNAME     6
#define LPC_SOCKGETHOSTBYADDR   7
#define LPC_SOCKCLOSE           8
#define LPC_SOCKSOCKET          9
#define LPC_SOCKRECVFROM        10
#define LPC_SOCKSENDTO          11
#define LPC_SOCKIOCTL           12
#define LPC_SOCKGETSOCKNAME     13
#define LPC_SOCKFLUSH           14
#define LPC_SOCKSETOPT          15
#define LPC_SOCKGETLASTERROR    16
#define LPC_SOCKINETADDR        17

// htons, ntohs, htonl, ntohl implemented locally

// errors
#define LPC_UNRECOGNIZED_SERVICE  -1
#define LPC_NOERROR                0

// structures for support
typedef struct
{
	SOCKET s;
	int    namelen;
	char   name[1];
} BindArgs;

typedef struct
{
	SOCKET s;
	long   cmd;
	char   data[1];
} IoctlArgs;

typedef struct
{
	int retVal;
	int namelen;
	char name[1];
} GetSockNameRet;

typedef GetSockNameRet GetHostNameRet;

typedef struct
{
	int   retVal;
	int   h_addr_0;    // that's the only important value
} GetHostByNameRet;

typedef struct
{
	int   len;
	int   type;
	char  addr[1];
} GetHostByAddrArgs;

typedef struct
{
	int   retVal;
	char  h_name[1];  // h_name is the only important value
} GetHostByAddrRet;

typedef struct
{
	SOCKET s;
	int flags;
} RecvFromArgs;

typedef struct
{
	int  retVal;
	int  errCode;
	int  len;   // message len
	struct sockaddr    sockaddr;
	int  sockaddrlen;
	char Data[1];
} RecvFromRet;

typedef struct
{
	SOCKET s;
	int    flags;
	int    len;
	struct sockaddr sockaddr;
	int    sockaddrlen;
	char   Data[1];
} SendToArgs;

typedef struct
{
	int   retVal;
	int   errCode;
} SendToRet;

typedef struct
{
	int     bufflen;
	SOCKET  s;
	int     len;
	int     sockaddrlen;
	struct sockaddr    address;
	char               data[1];
} SocketChannelData;

typedef struct
{
	int af;
	int type;
	int protocol;
} SocketArgs;

typedef struct
{
	SOCKET s;
	int len;
	int flags;
	int addrlen;
	struct sockaddr addr;
	char data[1];
} WinSockData;

typedef struct
{
	SOCKET s;
	int level;
	int optname;
	int optlen;
	char optval[1];
} SetSockOptArgs;

typedef struct
{
	SOCKET   sock[MAXSOCKETS];
} SocketMap;

//#include "rtq.h"
#define RTQ_NODE struct rtq_node

RTQ_NODE
{
	RTQ_NODE *self; // Ring zero address of this node
	RTQ_NODE *left; // Ring zero address of preceding node
	RTQ_NODE *right; // Ring zero address of succeding node
	BYTE       *rtqDatum;  // Ring 3 Datum of Buffer (start of preface)
	BYTE       *rtqInsert; // Ring 3 insertion position
	WORD     rtqLen; // Length of buffer, excluding preface
	WORD     rtqUpCtr;  // Up Counter of bytes used so far
	WORD     rtqQCtr;   // number of nodes attached
	WORD     padding;   // DWORD alignment
};

#define RTQ_PARAM_MOVENODE struct rtq_param_movenode
RTQ_PARAM_MOVENODE
{
	WORD     rtqFromDQ;
	WORD     rtqToDQ;
};

RTQ_NODE *rtq_fetch (RTQ_NODE*, RTQ_NODE*); // To, From

//#include "mplib.h"
// give up time slice
void Yield (void);
void MGenWakeupDll (void);

// post a message to win32 side
void PostWindowsMessage (void);

// get # of items on qNo
int MGenGetQueueCtr (int qNo);

// move first node from qFrom to qTo
RTQ_NODE *MGenMoveTo (int qFrom, int qTo);

// get first node from q
RTQ_NODE *MGenGetNode (int q);

// get master node, returning size of RTQ_NODE for size verification
RTQ_NODE *MGenGetMasterNode (unsigned *size);

// move all nodes from qFrom to qTo
RTQ_NODE *MGenFlushNodes (int qFrom, int qTo);

// count number of nodes in queues designated by bitmask
// lowerOrderBits == 0..31, upperOrderBits == 32-63
int MGenMCount (unsigned lowerOrderBits, unsigned upperOrderBits);

// perform consistency check on chunnel address space
int MGenSanityCheck (void);

#include <stdio.h>
#include <sys/farptr.h>

extern short flat_selector;

#define SOCKET_MAP_QUEUE  41

#define IDLE_QUEUE    44
#define REC_QUEUE     45
#define SEND_QUEUE    46

//  queue sizes
#define FREEQBASE      58
#define FREEQ64        58
#define FREEQ128       59
#define FREEQ256       60
#define FREEQ512       61
#define FREEQ1024      62
#define FREEQ2048      63

#define NFREEQ         6

#define QLIMIT         10

#define PRIVATEQ       50

#define FARPKL(x)  (_farnspeekl((unsigned long) x))
#define FARPKB(x)  (_farnspeekb((unsigned long) x))
#define FARPKS(x)  (_farnspeekw((unsigned long) x))

#define FARPOKL(x, y) (_farnspokel((unsigned long) x, (unsigned long) y))
#define FARPOKB(x, y) (_farnspokeb((unsigned long) x, (unsigned char) y))

int Qsizes[] = { 64, 128, 256, 512, 1024, 2048 };

int SocketError = 0;

SocketMap *SockMap;

#define HOSTENT_ALIAS_LIMIT    5
#define HOSTENT_STRLEN_LIMIT   50
#define HOSTENT_ADDR_LIST_LIMIT   5

struct hostent  HostEnt;

char HostEnt_hname[HOSTENT_STRLEN_LIMIT];
char *HostEnt_h_aliases[HOSTENT_ALIAS_LIMIT];
char HostEnt_names[HOSTENT_ALIAS_LIMIT][HOSTENT_STRLEN_LIMIT];
struct in_addr *HostEnt_addr_list[HOSTENT_ADDR_LIST_LIMIT];
struct in_addr HostEnt_addrs[HOSTENT_ADDR_LIST_LIMIT];

void
fmemcpyto (void *to, const void *from, int length)
{
	movedata (_my_ds(), (unsigned) from, flat_selector, (unsigned) to, length);
}

void
fmemcpyfrom (void *to, const void *from, int length)
{
	movedata (flat_selector, (unsigned) from, _my_ds(), (unsigned) to, length);
}

void
fstrcpyto (char *to, const char *from)
{
	while (*from)
	{
		FARPOKB (to, *from);
		to++;
		from++;
	}
	FARPOKB (to, 0);
}

void
fstrncpyto (char *to, const char *from, int len)
{
	while (*from && len)
	{
		FARPOKB (to, *from);
		to++;
		from++;
		len--;
	}
	FARPOKB (to, 0);
}

void
fstrcpyfrom (char *to, const char *from)
{
	while (FARPKB (from))
	{
		*to = FARPKB (from);
		from++;
		to++;
	}
	*to = 0;
}

void
fstrncpyfrom (char *to, const char *from, int len)
{
	while (FARPKB (from) && len)
	{
		*to =  FARPKB (from);
		from++;
		to++;
		len--;
	}
	*to = 0;
}

void
GetSocketMap (void)
{
	RTQ_NODE *n = MGenGetNode (SOCKET_MAP_QUEUE);
	
	SockMap = (SocketMap *) FARPKL (&n->rtqDatum);
}

void *
GetFreeBufferToQueue (int q, int bufSize)
{
	int i;
	
	for (i = 0; i < NFREEQ; i++)
	{
		if (Qsizes[i] >= bufSize && MGenGetQueueCtr (i + FREEQBASE))
		{
			RTQ_NODE *n = MGenMoveTo (i + FREEQBASE, q);
			if (!n)
				continue;
			FARPOKL (&n->rtqUpCtr, bufSize);
			return (void *) FARPKL (&n->rtqDatum);
		}
	}
	
	return 0;
}

void
FreeBufferFromQueue (int q)
{
	int i;
	RTQ_NODE *n = MGenGetNode (q);
	
	for (i = 0; i < NFREEQ; i++)
	{
		if (Qsizes[i] == FARPKS (&n->rtqLen))
		{
			MGenMoveTo (q, i + FREEQBASE);
			return;
		}
	}
}

void
SetLPCData (LPCData *lpc)
{

	FARPOKL (& (lpc->version), 1);
	FARPOKL (& (lpc->sizeOfArgs), 0);
	FARPOKL (& (lpc->service), 0);
}

int
bind (SOCKET s, const struct sockaddr *name, int namelen)
{
	RTQ_NODE *n = MGenGetNode (IDLE_QUEUE);
	LPCData  *p;
	LPCReturn *r;
	BindArgs  *bargs;
	int       retVal;
	
	_farsetsel (flat_selector);
	SocketError = 0;
	p = (LPCData *) FARPKL (&n->rtqDatum);
	SetLPCData (p);
	FARPOKL (&p->service, LPC_SOCKBIND);
	bargs = (BindArgs *) p->Data;
	FARPOKL (&bargs->s, s);
	FARPOKL (&bargs->namelen, namelen);
	fmemcpyto (bargs->name, name, namelen);
	MGenMoveTo (IDLE_QUEUE, SEND_QUEUE);
	PostWindowsMessage();
	
	while ( (n = MGenGetNode (REC_QUEUE)) == 0)
		Yield();
		
	r = (LPCReturn *) FARPKL (&n->rtqDatum);
	
	if (FARPKS (&r->error) != LPC_NOERROR)
	{
		return -1;
	}
	
	retVal = FARPKL (r->Data);
	
	// get ready for next call
	MGenMoveTo (REC_QUEUE, IDLE_QUEUE);
	
	return retVal;
}

int
closesocket (SOCKET s)
{
	RTQ_NODE *n = MGenGetNode (IDLE_QUEUE);
	LPCData  *p;
	LPCReturn *r;
	int       retVal;
	
	_farsetsel (flat_selector);
	SocketError = 0;
	p = (LPCData *) FARPKL (&n->rtqDatum);
	SetLPCData (p);
	FARPOKL (&p->service, LPC_SOCKCLOSE);
	FARPOKL (p->Data, s);
	
	MGenMoveTo (IDLE_QUEUE, SEND_QUEUE);
	PostWindowsMessage();
	
	while ( (n = MGenGetNode (REC_QUEUE)) == 0)
		Yield();
		
	r = (LPCReturn *) FARPKL (&n->rtqDatum);
	
	if (FARPKS (&r->error) != LPC_NOERROR)
	{
		return -1;
	}
	
	retVal = FARPKL (r->Data);
	
	// get ready for next call
	MGenMoveTo (REC_QUEUE, IDLE_QUEUE);
	
	return retVal;
}

void
ZapHostEnt()
{
	// do nothing
}

void
ReconstructHostEnt (struct hostent *s, void *flattened)
{
	struct hostent   *old = (struct hostent *) flattened;
	int i;
	char **ptr;
	
	
	s->h_name = HostEnt_hname;
	fstrncpyfrom (s->h_name, (char *) FARPKL (&old->h_name), HOSTENT_STRLEN_LIMIT - 1);
	s->h_name[HOSTENT_STRLEN_LIMIT-1] = 0;
	
	s->h_aliases = HostEnt_h_aliases;
	ptr = (char **) FARPKL (&old->h_aliases);
	for (i = 0; i < (HOSTENT_ALIAS_LIMIT - 1) && FARPKL (ptr); i++, ptr++)
	{
		s->h_aliases[i] = HostEnt_names[i];
		// fstrncpyfrom(s->h_aliases[i], (void *) FARPKL(ptr), HOSTENT_STRLEN_LIMIT-1);
		s->h_aliases[i][HOSTENT_STRLEN_LIMIT-1] = 0;
	}
	s->h_aliases[i] = 0;
	
	s->h_addrtype = FARPKS (&old->h_addrtype);
	s->h_length = FARPKS (&old->h_length);
	
	if (FARPKS (&old->h_length) != sizeof (struct in_addr))
	{
		printf ("Error!\n");
		exit (0);
	}
	
	s->h_addr_list = (char **) HostEnt_addr_list;
	ptr = (char **) FARPKL (&old->h_addr_list);
	for (i = 0; i < (HOSTENT_ADDR_LIST_LIMIT - 1) && FARPKL (ptr); i++, ptr++)
	{
		s->h_addr_list[i] = (char *) & (HostEnt_addrs[i]);
		fmemcpyfrom (s->h_addr_list[i], (void *) FARPKL (ptr), s->h_length);
	}
	s->h_addr_list[i] = 0;
}


int
getsockname (SOCKET s, struct sockaddr *name, int *namelen)
{
	RTQ_NODE *n = MGenGetNode (IDLE_QUEUE);
	LPCData  *p;
	LPCReturn *r;
	GetSockNameRet  *ret;
	int       retVal;
	
	SocketError = 0;
	_farsetsel (flat_selector);
	p = (LPCData *) FARPKL (&n->rtqDatum);
	SetLPCData (p);
	FARPOKL (&p->service, LPC_SOCKGETSOCKNAME);
	FARPOKL (p->Data, s);
	
	MGenMoveTo (IDLE_QUEUE, SEND_QUEUE);
	PostWindowsMessage();
	
	while ( (n = MGenGetNode (REC_QUEUE)) == 0)
		Yield();
		
		
	r = (LPCReturn *) FARPKL (&n->rtqDatum);
	
	if (FARPKS (&r->error) != LPC_NOERROR)
	{
		return -1;
	}
	
	ret = (GetSockNameRet *) r->Data;
	retVal = FARPKL (&ret->retVal);
	fmemcpyfrom (name, ret->name, FARPKL (&ret->namelen));
	*namelen = FARPKL (&ret->namelen);
	
	// get ready for next call
	MGenMoveTo (REC_QUEUE, IDLE_QUEUE);
	
	return retVal;
}

int
gethostname (char *name, int namelen)
{
	RTQ_NODE *n;
	LPCData  *p;
	LPCReturn *r;
	GetHostNameRet  *ret;
	int       retVal;
	char  *s;
	
	_farsetsel (flat_selector);
	SocketError = 0;
	n = (RTQ_NODE *) MGenGetNode (IDLE_QUEUE);
	p = (LPCData *) FARPKL (&n->rtqDatum);
	SetLPCData (p);
	FARPOKL (&p->service, LPC_SOCKGETHOSTNAME);
	MGenMoveTo (IDLE_QUEUE, SEND_QUEUE);
	PostWindowsMessage();
	
	while ( (n = (RTQ_NODE *) (MGenGetNode (REC_QUEUE))) == 0)
		Yield();
		
	r = (LPCReturn *) FARPKL (&n->rtqDatum);
	
	if (FARPKS (&r->error) != LPC_NOERROR)
	{
		return -1;
	}
	
	ret = (GetHostNameRet *) r->Data;
	
	retVal = FARPKL (&ret->retVal);
	
	s = ret->name;
	
	fstrncpyfrom (name, s, namelen);
	
#if 0
	len = strlen (ret->name);
	
	if (len > namelen)
		memcpy (name, ret->name, ret->namelen);
	else
		strcpy (name, ret->name);
#endif
		
	// get ready for next call
	MGenMoveTo (REC_QUEUE, IDLE_QUEUE);
	
	return retVal;
}

struct hostent *
gethostbyname (const char *name)
{
	RTQ_NODE *n = MGenGetNode (IDLE_QUEUE);
	LPCData  *p;
	LPCReturn *r;
	struct hostent *retVal;
	
	_farsetsel (flat_selector);
	SocketError = 0;
	p = (LPCData *) FARPKL (&n->rtqDatum);
	SetLPCData (p);
	FARPOKL (&p->service, LPC_SOCKGETHOSTBYNAME);
	fstrcpyto (p->Data, name);
	
	MGenMoveTo (IDLE_QUEUE, SEND_QUEUE);
	PostWindowsMessage();
	
	while ( (n = MGenGetNode (REC_QUEUE)) == 0)
		Yield();
		
	r = (LPCReturn *) FARPKL (&n->rtqDatum);
	retVal = (struct hostent *) r->Data;
	
	if (FARPKL (&retVal->h_name) == 0)
	{
		retVal = 0;
	}
	else
	{
		ZapHostEnt();
		ReconstructHostEnt (&HostEnt, (void *) retVal);
		retVal = &HostEnt;
	}
	
	// get ready for next call
	MGenMoveTo (REC_QUEUE, IDLE_QUEUE);
	
	return retVal;
}

struct hostent *
gethostbyaddr (const char *addr, int len, int type)
{
	RTQ_NODE *n = MGenGetNode (IDLE_QUEUE);
	LPCData  *p;
	LPCReturn *r;
	GetHostByAddrArgs *args;
	struct hostent *retVal;
	
	SocketError = 0;
	_farsetsel (flat_selector);
	p = (LPCData *) FARPKL (&n->rtqDatum);
	SetLPCData (p);
	FARPOKL (&p->service, LPC_SOCKGETHOSTBYADDR);
	args = (GetHostByAddrArgs *) p->Data;
	FARPOKL (&args->len, len);
	FARPOKL (&args->type, type);
	fmemcpyto (args->addr, addr, len);
	
	MGenMoveTo (IDLE_QUEUE, SEND_QUEUE);
	PostWindowsMessage();
	
	while ( (n = MGenGetNode (REC_QUEUE)) == 0)
		Yield();
	r = (LPCReturn *) FARPKL (&n->rtqDatum);
	retVal = (struct hostent *) r->Data;
	
	if (FARPKL (&retVal->h_name) == 0)
	{
		retVal = 0;
	}
	else
	{
		ZapHostEnt();
		
		ReconstructHostEnt (&HostEnt, (void *) retVal);
		retVal = &HostEnt;
	}
	
	// get ready for next call
	MGenMoveTo (REC_QUEUE, IDLE_QUEUE);
	
	return retVal;
}


SOCKET
socket (int af, int type, int protocol)
{
	RTQ_NODE *n = MGenGetNode (IDLE_QUEUE);
	LPCData  *p;
	LPCReturn *r;
	SocketArgs  *args;
	int       retVal;
	
	_farsetsel (flat_selector);
	SocketError = 0;
	p = (LPCData *) FARPKL (&n->rtqDatum);
	SetLPCData (p);
	FARPOKL (&p->service, LPC_SOCKSOCKET);
	args = (SocketArgs *) p->Data;
	FARPOKL (&args->af, af);
	FARPOKL (&args->type, type);
	FARPOKL (&args->protocol, protocol);
	
	MGenMoveTo (IDLE_QUEUE, SEND_QUEUE);
	PostWindowsMessage();
	
	while ( (n = MGenGetNode (REC_QUEUE)) == 0)
		Yield();
		
	r = (LPCReturn *) FARPKL (&n->rtqDatum);
	
	
	if (FARPKS (&r->error) != LPC_NOERROR)
	{
		return -1;
	}
	
	retVal = FARPKL (r->Data);
	
	// get ready for next call
	MGenMoveTo (REC_QUEUE, IDLE_QUEUE);
	
	return retVal;
}

void
sockets_flush (void)
{
	RTQ_NODE *n = MGenGetNode (IDLE_QUEUE);
	LPCData  *p;
	
	SocketError = 0;
	p = (LPCData *) FARPKL (&n->rtqDatum);
	SetLPCData (p);
	FARPOKL (&p->service, LPC_SOCKFLUSH);
	
	MGenMoveTo (IDLE_QUEUE, SEND_QUEUE);
	PostWindowsMessage();
	
	while ( (n = MGenGetNode (REC_QUEUE)) == 0)
		Yield();
		
	MGenMoveTo (REC_QUEUE, IDLE_QUEUE);
}

int
recvfrom (SOCKET s, char *buf, int len, int flags, struct sockaddr *from,
		  int *fromlen)
{
	int i;
	RTQ_NODE *n;
	WinSockData  *data;
	int  bytesRead;
	
	SocketError = 0;
	_farsetsel (flat_selector);
	if (!SockMap)
		GetSocketMap();
		
	for (i = 0; i < MAXSOCKETS; i++)
	{
		if (FARPKL (& (SockMap->sock[i])) == s)
			break;
	}
	
	if (i == MAXSOCKETS)
		return SOCKET_ERROR;
		
	// pick up node
	n = MGenGetNode (i);
	if (n == 0)
	{
		SocketError = WSAEWOULDBLOCK;
		return -1;
	}
	
	data = (WinSockData *) FARPKL (&n->rtqDatum);
	bytesRead = FARPKL (&data->len);
	
	if (from)
	{
		fmemcpyfrom (from, &data->addr, sizeof (struct sockaddr));
	}
	
	if (fromlen)
	{
		*fromlen = FARPKL (&data->addrlen);
	}
	
	fmemcpyfrom (buf, data->data, len > bytesRead ? bytesRead : len);
	
	if ( (flags & MSG_PEEK) == 0)
	{
		FreeBufferFromQueue (i);
	}
	
	return bytesRead;
}

int
sendto (SOCKET s, const char *buf, int len, int flags, const struct sockaddr *to, int tolen)
{
	int i;
	int outQ;
	WinSockData *data;
	
	SocketError = 0;
	_farsetsel (flat_selector);
	if (!SockMap)
		GetSocketMap();
		
	for (i = 0; i < MAXSOCKETS; i++)
	{
		if (FARPKL (&SockMap->sock[i]) == s)
		{
			break;
		}
	}
	
	if (i == MAXSOCKETS)
	{
		SocketError = WSAENOTSOCK;
		return SOCKET_ERROR;
	}
	
	outQ = i + MAXSOCKETS;
	
	if (MGenGetQueueCtr (outQ) >= QLIMIT)
	{
		SocketError = WSAEWOULDBLOCK;
		return SOCKET_ERROR;
	}
	
	data = GetFreeBufferToQueue (PRIVATEQ, len + sizeof (WinSockData));
	
	if (!data)
	{
		SocketError = WSAEWOULDBLOCK;
		return SOCKET_ERROR;
	}
	
	FARPOKL (&data->s, s);
	FARPOKL (&data->len, len);
	if (to)
	{
		fmemcpyto (&data->addr, to, tolen);
		FARPOKL (&data->addrlen, tolen);
	}
	else
	{
		FARPOKL (&data->addrlen, 0);
	}
	
	FARPOKL (&data->flags, flags);
	
	fmemcpyto (data->data, buf, len);
	
	MGenMoveTo (PRIVATEQ, outQ);
	
	return len;
}

int
ioctlsocket (SOCKET s, long cmd, unsigned long *argp)
{
	RTQ_NODE *n = MGenGetNode (IDLE_QUEUE);
	LPCData  *p;
	LPCReturn *r;
	IoctlArgs  *args;
	int       retVal;
	
	SocketError = 0;
	_farsetsel (flat_selector);
	p = (LPCData *) FARPKL (&n->rtqDatum);
	SetLPCData (p);
	FARPOKL (&p->service, LPC_SOCKIOCTL);
	args = (IoctlArgs *) p->Data;
	FARPOKL (&args->s, s);
	FARPOKL (&args->cmd, cmd);
	
	switch (cmd)
	{
		case FIONBIO:
			FARPOKL (args->data, *argp);
			break;
		default:
			return SOCKET_ERROR;
	}
	
	MGenMoveTo (IDLE_QUEUE, SEND_QUEUE);
	PostWindowsMessage();
	
	while ( (n = MGenGetNode (REC_QUEUE)) == 0)
		Yield();
		
	r = (LPCReturn *) FARPKL (&n->rtqDatum);
	
	
	retVal = FARPKL (r->Data);
	
	// get ready for next call
	MGenMoveTo (REC_QUEUE, IDLE_QUEUE);
	
	return retVal;
}

int
setsockopt (SOCKET s, int level, int optname, const char *optval, int optlen)
{
	RTQ_NODE *n = MGenGetNode (IDLE_QUEUE);
	LPCData  *p;
	LPCReturn *r;
	SetSockOptArgs  *args;
	int       retVal;
	
	SocketError = 0;
	_farsetsel (flat_selector);
	p = (LPCData *) FARPKL (&n->rtqDatum);
	SetLPCData (p);
	FARPOKL (&p->service, LPC_SOCKSETOPT);
	args = (SetSockOptArgs *) p->Data;
	FARPOKL (&args->s, s);
	FARPOKL (&args->level, level);
	FARPOKL (&args->optname, optname);
	FARPOKL (&args->optlen, optlen);
	fmemcpyto (args->optval, optval, optlen);
	
	MGenMoveTo (IDLE_QUEUE, SEND_QUEUE);
	PostWindowsMessage();
	
	while ( (n = MGenGetNode (REC_QUEUE)) == 0)
		Yield();
		
	r = (LPCReturn *) FARPKL (&n->rtqDatum);
	
	retVal = FARPKL (r->Data);
	
	// get ready for next call
	MGenMoveTo (REC_QUEUE, IDLE_QUEUE);
	
	return retVal;
}

int
WSAGetLastError (void)
{
	RTQ_NODE *n = MGenGetNode (IDLE_QUEUE);
	LPCData  *p;
	LPCReturn *r;
	int       retVal;
	
	
	_farsetsel (flat_selector);
	if (SocketError)
	{
		int err = SocketError;
		
		SocketError = 0;
		return err;
	}
	
	p = (LPCData *) FARPKL (&n->rtqDatum);
	SetLPCData (p);
	FARPOKL (&p->service, LPC_SOCKGETLASTERROR);
	
	MGenMoveTo (IDLE_QUEUE, SEND_QUEUE);
	PostWindowsMessage();
	
	while ( (n = MGenGetNode (REC_QUEUE)) == 0)
		Yield();
		
	r = (LPCReturn *) FARPKL (&n->rtqDatum);
	
	
	retVal = FARPKL (r->Data);
	
	// get ready for next call
	MGenMoveTo (REC_QUEUE, IDLE_QUEUE);
	
	return retVal;
}

unsigned long inet_addr (const char *cp)
{
	int ret;
	unsigned int ha1, ha2, ha3, ha4;
	unsigned long ipaddr;
	
	ret = sscanf (cp, "%d.%d.%d.%d", &ha1, &ha2, &ha3, &ha4);
	if (ret != 4)
		return -1;
	ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;
	return ipaddr;
#if 0
	RTQ_NODE *n = MGenGetNode (IDLE_QUEUE);
	LPCData  *p;
	LPCReturn *r;
	int       retVal;
	
	SocketError = 0;
	_farsetsel (flat_selector);
	p = (LPCData *) FARPKL (&n->rtqDatum);
	SetLPCData (p);
	FARPOKL (&p->service, LPC_SOCKINETADDR);
	
	fstrcpyto (p->Data, cp);
	
	MGenMoveTo (IDLE_QUEUE, SEND_QUEUE);
	PostWindowsMessage();
	
	while ( (n = MGenGetNode (REC_QUEUE)) == 0)
		Yield();
		
	r = (LPCReturn *) FARPKL (&n->rtqDatum);
	
	if (FARPKS (&r->error) != LPC_NOERROR)
	{
		return -1;
	}
	
	retVal = FARPKL (r->Data);
	
	// get ready for next call
	MGenMoveTo (REC_QUEUE, IDLE_QUEUE);
	
	return retVal;
#endif
}

char *inet_ntoa (struct in_addr in)
{
	static char buf [32];
	
	sprintf (buf, "%u.%u.%u.%u", in.S_un.S_un_b.s_b1, in.S_un.S_un_b.s_b2, in.S_un.S_un_b.s_b3, in.S_un.S_un_b.s_b4);
	return buf;
}
