Source to Quake/mplpc.c


Enter a symbol's name here to quickly find it.

/*
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;
}