/* Copyright distributed.net 1997-1999 - All Rights Reserved
 * For use in distributed.net projects only.
 * Any other distribution or use of this source violates copyright.
 *
 * Written by Cyrus Patel <cyp@fb14.uni-mainz.de>
 *
 * ---------------------------------------------------------------------
 * This module containts the shim layer between Winsock DLL and Windows.
 * While this shim is essential for Watcom 386 flat memory model extensions
 * for win16, is also used by the win32cli client to allow the client to
 * run on systems without winsock.dll/wsock32.dll/ws2_32.dll
 *
 * This module is known to work with 16bit Novell, Microsoft and Trumpet
 * stacks, as well as the 32bit Alpha and x86 Microsoft stacks.
 *
 * Little endian byte format is assumed throughout.
 * ---------------------------------------------------------------------
 * When used with Watcom 386 flat model extensions, the winsock.h header
 * must be #included with the following wrapper:
 *   #include <windows.h> // use default shimming/redefs
 *   #ifdef __WINDOWS_386__
 *     #undef FAR
 *     #define FAR
 *   #endif
 *   #include <winsock.h> // use the 16 bit version
 *   #ifdef __WINDOWS_386__
 *     #undef FAR
 *     #define FAR far
 *     #undef FD_ISSET // macro applies a FAR cast that results in truncation
 *     #define FD_ISSET(fd, set) __WSAFDIsSet(fd, set) //...so discard the cast
 *   #endif
*/
#if (!defined(lint) && defined(__showids__))
const char *w32sock_cpp(void) {
return "@(#)$Id: w32sock.cpp,v 1.11.2.6 1999/12/31 20:28:51 michmarc Exp $"; }
#endif

#include "w32sock.h" // <windows.h> and <winsock.h> as documented above.

#if defined(_M_ALPHA)
  #define WINSOCK_DLL_FILENAME "WS2_32.DLL"
  #undef PASCAL
  #define PASCAL
#elif defined(__WINDOWS_386__)
  #define WINSOCK_DLL_FILENAME "WINSOCK.DLL"
  #undef FAR
  #define FAR
#elif defined(__WIN32__) || defined(WIN32)
  static char *__GetWinsockDLLFilename(void)
  {
    static char * wslib = NULL;
    if (wslib == NULL)
    {
      /* original win95, win95a, win95b, win95 with winsock2 either don't 
         have winsock2, or have a broken winsock2, that under 'some 
         circumstances' incorrectly fails socket() with WSAESOCKTNOSUPPORT 
         (specified socket type is not supported in address family)
      */
      OSVERSIONINFO osver;
      osver.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
      GetVersionEx(&osver);
      if (VER_PLATFORM_WIN32_NT == osver.dwPlatformId)
        osver.dwMajorVersion += 20;
      else if (VER_PLATFORM_WIN32s == osver.dwPlatformId)
      {
        DWORD dwVersion = GetVersion();
        osver.dwMajorVersion = LOBYTE(LOWORD(dwVersion));
        osver.dwMinorVersion = HIBYTE(LOWORD(dwVersion));  
      }
      wslib = "WSOCK32.DLL";
      if (((osver.dwMajorVersion * 100)+osver.dwMinorVersion) > 400) 
      {
        wslib = "WS2_32.DLL";
        if (GetModuleHandle(wslib) == NULL)
        {
          OFSTRUCT ofstruct;
          ofstruct.cBytes = sizeof(ofstruct);
          #ifndef OF_SEARCH
          #define OF_SEARCH 0x0400
          #endif
          if ( OpenFile( wslib, &ofstruct, OF_EXIST|OF_SEARCH) == HFILE_ERROR )
            wslib = "WSOCK32.DLL";
        }
      }
    }
    return wslib;
  }
  #define WINSOCK_DLL_FILENAME __GetWinsockDLLFilename()
#else
  #define WINSOCK_DLL_FILENAME "WINSOCK.DLL"
#endif


/* ==================================================================== */

static struct
{
  int initlevel;
  int internalinit; /* if autoinitialized from WSAStartup */
  int lasterror;
} w32sockstatics = {0,0,0};


//import winsock symbol should always be able to find the lib
//because WSAStartup calls __w32sockinitdeinit which loads the lib
static FARPROC ImportWinsockSymbol(LPCSTR lpszProcName)
{
  if (w32sockstatics.initlevel <= 0)
    return (FARPROC)0;
  HMODULE ws = GetModuleHandle(WINSOCK_DLL_FILENAME /* "WINSOCK" */);
  if (ws)
    return GetProcAddress(ws, lpszProcName);
  return (FARPROC)0;
}

static HINSTANCE __LoadLibrary( LPCSTR lpszLibName )
{
  HINSTANCE hinst = 0;
  HMODULE ws;
  OFSTRUCT ofstruct;
  ofstruct.szPathName[0] = '\0';
  if (( ws = GetModuleHandle(WINSOCK_DLL_FILENAME) ) != ((HMODULE)0))
  {
    unsigned int len = GetModuleFileName(ws, ofstruct.szPathName,
                       sizeof(ofstruct.szPathName));
    if (len >= sizeof(ofstruct.szPathName))
      len = sizeof(ofstruct.szPathName)-1;
    ofstruct.szPathName[len] = '\0';
  }
  else
  {
    ofstruct.cBytes = sizeof(ofstruct);
    #ifndef OF_SEARCH
    #define OF_SEARCH 0x0400
    #endif
    if ( OpenFile( lpszLibName, &ofstruct, OF_EXIST|OF_SEARCH) == HFILE_ERROR )
      ofstruct.szPathName[0] = '\0';
  }
  if (ofstruct.szPathName[0])
  {
    hinst = LoadLibrary( ofstruct.szPathName );
    if (hinst <= ((HINSTANCE)(32)))
      hinst = 0;
  }
  return hinst;
}


static int __w32sockInitDeinit(int init_or_deinit )
{
  static HINSTANCE hinstWinsock = NULL;

  if (init_or_deinit == 0)   /* getstate */
  {
    if (w32sockstatics.initlevel <= 0)
      return 0;
    return (GetModuleHandle(WINSOCK_DLL_FILENAME /*"WINSOCK"*/) != NULL);
  }
  else if (init_or_deinit < 0)   /* deinitialize */
  {
    if ((--w32sockstatics.initlevel)==0)
    {
      if (hinstWinsock)
      {
        FreeLibrary(hinstWinsock);
        hinstWinsock = NULL;
      }
    }
  }
  else if (init_or_deinit > 0)   /* initialize */
  {
    if ((++w32sockstatics.initlevel)==1)
    {
      hinstWinsock = __LoadLibrary(WINSOCK_DLL_FILENAME);
      if ((UINT) hinstWinsock < 32)
      {
        hinstWinsock = NULL;
        --w32sockstatics.initlevel;
        return 0;
      }
    }
  }
  return 1;
}

/* ---------------------------------------- */

u_short PASCAL FAR htons(u_short s)
{ return ((((s)&0xff)<<8) | (((s)>>8)&0xff)); }
u_short PASCAL FAR ntohs(u_short s)
{  return htons(s); }
u_long PASCAL FAR htonl(u_long l)
{ return ((((l)&0xff)<<24) | (((l)>>24)&0xff) | (((l)&0xff00)<<8) | (((l)>>8)&0xff00)); }
u_long PASCAL FAR ntohl(u_long l)
{ return htonl(l); }

/* ---------------------------------------- */

static char *inet_ntoa_r(char *buff, u_long inaddr )
{
  if ( buff )
  {
    unsigned int i;
    char *a = (char *)(&inaddr), *b = buff;

    for ( i=0; i<4; i++ )
    {
      register unsigned int r, c = (((unsigned int)(*a++)) & 255 );
      if ( i )
        *b++ = '.';
      if ( (r = c / 100) != 0 )
        *b++ = (char)( r + '0' );
      r <<= 8;
      if ( (r |= ((c % 100)/10)) != 0)
        *b++ = (char)( (r & 0xff) + '0' );
      *b++ = (char)((c%10) + '0');
    }
    *b++=0;
  }
  return buff;
}


static char *__inet_ultoa( u_long addr )
{
  static char buff[18];
  return inet_ntoa_r( buff, addr );
}

char FAR * PASCAL FAR inet_ntoa( struct in_addr addr )
{ return __inet_ultoa( *((u_long *)(&addr)) ); }

/* ---------------------------------------- */

void PASCAL FAR WSASetLastError(int iError)
{
  if (w32sockstatics.initlevel <= 0)
    return;

  w32sockstatics.lasterror = 0;
  FARPROC __proc = ImportWinsockSymbol( "WSASetLastError" );
  if (__proc)
  {
    #if defined(__WINDOWS_386__)
    _Call16(__proc,"w",iError);
    #else
    (*((void (PASCAL FAR *)(int))(__proc)))(iError);
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return;
}

/* ---------------------------------------- */

int PASCAL FAR WSAGetLastError(void)
{
  if (w32sockstatics.initlevel <= 0)
    return WSANOTINITIALISED;

  if (w32sockstatics.lasterror != 0)
    return w32sockstatics.lasterror;

  FARPROC __proc = ImportWinsockSymbol( "WSAGetLastError" );
  if (__proc)
  {
    #if defined(__WINDOWS_386__)
    return (0xffff & (_Call16(__proc,"")));
    #else
    return (*((int (PASCAL FAR *)(void))(__proc)))();
    #endif
  }
  return WSAEOPNOTSUPP;
}

/* ---------------------------------------- */

int PASCAL FAR gethostname(char FAR * name, int namelen)
{
  w32sockstatics.lasterror = 0;
  FARPROC __gethostname = ImportWinsockSymbol( "gethostname" );
  if (__gethostname)
  {
    #if defined(__WINDOWS_386__)
    int rc = -1; char buf[256];
    DWORD alias = AllocAlias16( (void *)(&buf[0]) );
    if (alias)
    {
      buf[0]=0;
      if ((0xffff & (_Call16(__gethostname,"dw", alias, sizeof(buf) ))) == 0)
        rc = 0;
      FreeAlias16( alias );
    }
    if (rc == 0)
    {
      buf[sizeof(buf)-1]=0;
      for (rc=0;(buf[rc] && rc<(namelen-1));rc++)
       *name++ = buf[rc];
      *name++ = 0;
      rc = 0;
    }
    return rc;
    #else
    return (*((int (PASCAL FAR *)(char FAR *,int))(__gethostname)))(name, namelen);
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return -1;
}

/* ---------------------------------------- */

SOCKET PASCAL FAR socket(int domain, int type, int protocol)
{
  w32sockstatics.lasterror = 0;
  FARPROC __socket = ImportWinsockSymbol( "socket" );
  if (__socket)
  {
    #if defined(__WINDOWS_386__)
    SOCKET ns = (SOCKET)(0xffff & (_Call16(__socket,"www",domain,type,protocol)));
    return ((ns == ((INVALID_SOCKET)&0xffff))?(INVALID_SOCKET):(ns));
    #else
    return (*(SOCKET (PASCAL FAR *)(int,int,int))(__socket))(domain,type,protocol);
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return -1;
}

/* ---------------------------------------- */

int PASCAL FAR shutdown(SOCKET s, int how)
{
  w32sockstatics.lasterror = 0;
  FARPROC __shutdown = ImportWinsockSymbol( "shutdown" );
  if (__shutdown)
  {
    #if defined(__WINDOWS_386__)
    return (((_Call16(__shutdown,"ww",s,how) & 0xffff) == 0)?(0):(-1));
    #else
    return (*((int (PASCAL FAR *)(SOCKET,int))(__shutdown)))(s,how);
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return -1;
}

/* ---------------------------------------- */

int PASCAL FAR closesocket(SOCKET s)
{
  w32sockstatics.lasterror = 0;
  FARPROC __closesocket = ImportWinsockSymbol( "closesocket" );
  if (__closesocket)
  {
    #if defined(__WINDOWS_386__)
    return (((_Call16(__closesocket,"w",s) & 0xffff) == 0)?(0):(-1));
    #else
    return (*((int (PASCAL FAR *)(SOCKET))(__closesocket)))(s);
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return -1;
}

/* ---------------------------------------- */

static int __getpeersockname( const char *procname, SOCKET s,
                              struct sockaddr FAR *name, int FAR * namelen )
{
  w32sockstatics.lasterror = 0;
  FARPROC __proc = ImportWinsockSymbol( procname );
  if (__proc)
  {
    #if defined(__WINDOWS_386__)
    if (name && namelen)
    {
      WORD _namelen = (WORD)(*namelen);
      int rc = (((_Call16(__proc,"wpp",s,name,&_namelen)&0xffff)==0)?(0):(-1));
      *namelen = _namelen;
      return rc;
    }
    #else
      return (*((int (PASCAL FAR *)(SOCKET, struct sockaddr FAR *, int FAR *))
                                   (__proc)))( s, name, namelen );
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return -1;
}

/* ---------------------------------------- */

int PASCAL FAR getpeername(SOCKET s, struct sockaddr FAR *name, int FAR * namelen)
{
  return __getpeersockname( "getpeername", s, name, namelen );
}

/* ---------------------------------------- */

int PASCAL FAR getsockname(SOCKET s, struct sockaddr FAR *name, int FAR * namelen)
{
  return __getpeersockname( "getsockname", s, name, namelen );
}

/* ---------------------------------------- */

SOCKET PASCAL FAR accept(SOCKET s, struct sockaddr FAR *addr,
                          int FAR *addrlen)
{
  w32sockstatics.lasterror = 0;
  FARPROC __accept = ImportWinsockSymbol( "accept" );
  if (__accept)
  {
    #if defined(__WINDOWS_386__)
    if (addr && addrlen)
    {
      WORD _addrlen = (WORD)(*addrlen);
      SOCKET ns = (0xffff & _Call16(__accept, "wpp", s, addr, &_addrlen));
      *addrlen = _addrlen;
      return ((ns == ((INVALID_SOCKET)&0xffff))?(INVALID_SOCKET):(ns));
    }
    return -1;
    #else
    return (*((SOCKET (PASCAL FAR *)(SOCKET, struct sockaddr FAR *, int FAR *))
         (__accept)))( s, addr, addrlen );
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return -1;
}

/* ---------------------------------------- */

static int __bindconnect( const char *procname, SOCKET s,
                          const struct sockaddr FAR *addr, int addrlen )
{
  w32sockstatics.lasterror = 0;
  FARPROC __proc = ImportWinsockSymbol( procname );
  if (__proc)
  {
    #if defined(__WINDOWS_386__)
    return (((_Call16(__proc, "wpw", s, addr, addrlen) & 0xffff)==0)?(0):(-1));
    #else
    return (*((int (PASCAL FAR *)(SOCKET, const struct sockaddr FAR *, int))
                                 (__proc)))( s, addr, addrlen );
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return -1;
}

/* ---------------------------------------- */

int PASCAL FAR bind(SOCKET s, const struct sockaddr FAR *addr, int namelen)
{
  return __bindconnect( "bind", s, addr, namelen );
}

/* ---------------------------------------- */

int PASCAL FAR connect(SOCKET s, const struct sockaddr FAR *name, int namelen)
{
  int rv = __bindconnect( "connect", s, name, namelen );
  if ((rv == SOCKET_ERROR) && (WSAGetLastError() == 0))
    return 0;
  else
    return rv;
}

/* ---------------------------------------- */

int PASCAL FAR getsockopt(SOCKET s, int level, int optname,
                                           char FAR * optval, int FAR *optlen)
{
  w32sockstatics.lasterror = 0;
  FARPROC __proc = ImportWinsockSymbol( "getsockopt" );
  if (__proc)
  {
    #if defined(__WINDOWS_386__)
    short len = (short)(*optlen);
    if ((0xffff & _Call16(__proc, "wwwpp", s, level, optname, optval, &len))==0)
    {
      *optlen = (((int)len) & 0xffff);
      return 0;
    }
    return -1;
    #else
    return (*((int (PASCAL FAR *)(SOCKET, int, int, char FAR *, int FAR *))
                             (__proc)))( s, level, optname, optval, optlen );
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return -1;
}

/* ---------------------------------------- */

int PASCAL FAR setsockopt(SOCKET s, int level, int optname,
                             const char FAR * optval, int optlen)
{
  w32sockstatics.lasterror = 0;
  FARPROC __proc = ImportWinsockSymbol( "setsockopt" );
  if (__proc)
  {
    #if defined(__WINDOWS_386__)
    return (((0xffff & _Call16(__proc, "wwwpw", s, level, 
                      optname, optval, optlen))==0)?(0):(-1));
    #else
    return (*((int (PASCAL FAR *)(SOCKET, int, int, const char FAR *, int ))
                             (__proc)))( s, level, optname, optval, optlen );
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return -1;
}

/* ---------------------------------------- */

int PASCAL FAR listen(SOCKET s, int backlog)
{
  w32sockstatics.lasterror = 0;
  FARPROC __proc = ImportWinsockSymbol( "listen" );
  if (__proc)
  {
    #if defined(__WINDOWS_386__)
    return (((0xffff & _Call16(__proc, "ww", s, backlog ))==0)?(0):(-1));
    #else
    return (*((int (PASCAL FAR *)(SOCKET, int ))(__proc)))( s, backlog );
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return -1;
}

/* ---------------------------------------- */

int PASCAL FAR recvfrom(SOCKET s, char FAR * buf, int len, int flags,
                         struct sockaddr FAR *from, int FAR * fromlen)
{
  w32sockstatics.lasterror = 0;
  FARPROC __proc = ImportWinsockSymbol( "recvfrom" );
  if (__proc)
  {
    #if defined(__WINDOWS_386__)
    WORD _fromlen = (WORD)(*fromlen);
    short rc;
    if (len > 0x7fff)
      len = 0x7fff;
    rc = (short)_Call16(__proc, "wpwwpp", s, buf, len, flags, from, &_fromlen);
    *fromlen = _fromlen;
    return ((rc<0)?(-1):(rc));
    #else
    return (*((int (PASCAL FAR *)(SOCKET, char FAR *, int, int,
                 struct sockaddr FAR *, int FAR * ))(__proc)))
                 ( s, buf, len, flags, from, fromlen );
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return -1;
}

/* ---------------------------------------- */

int PASCAL FAR sendto(SOCKET s, const char FAR * buf, int len, int flags,
                       const struct sockaddr FAR *to, int tolen)
{
  w32sockstatics.lasterror = 0;
  FARPROC __proc = ImportWinsockSymbol( "sendto" );
  if (__proc)
  {
    #if defined(__WINDOWS_386__)
    short rc;
    if (len > 0x7fff)
      len = 0x7fff;
    rc = (short)_Call16(__proc, "wpwwpw", s, buf, len, flags, to, tolen );
    return ((rc<0)?(-1):(rc));
    #else
    return (*((int (PASCAL FAR *)(SOCKET, const char FAR *, int, int,
                 const struct sockaddr FAR *, int ))(__proc)))
                 ( s, buf, len, flags, to, tolen );
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return -1;
}

/* ---------------------------------------- */

#if defined(__WINDOWS_386__)

struct fd_set_short {
  unsigned short fd_count;               /* how many are SET? */
  unsigned short fd_array[1];            /* an array of SOCKETs */
};

static void __map_int_to_short_fdset( fd_set FAR *argfds )
{
  if (argfds)
  {
    struct fd_set_short *shortfds;
    unsigned int i, count;

    shortfds = (struct fd_set_short *)argfds;
    count = (unsigned int)argfds->fd_count;
    shortfds->fd_count = (short)count;
    for (i=0;i<count;i++)
      shortfds->fd_array[i] = (short)argfds->fd_array[i];
  }
  return;
}

static void __map_short_to_int_fdset( fd_set FAR *argfds )
{
  if (argfds)
  {
    struct fd_set_short *shortfds;
    unsigned int i, count;

    shortfds = (struct fd_set_short *)argfds;
    count = (unsigned int)shortfds->fd_count;
    for (i=count;i>0;)
    {
      --i;
      argfds->fd_array[i] =
                (0xffff & ((unsigned int)(shortfds->fd_array[i])));
    }
    argfds->fd_count = count;
  }
  return;
}
#endif

/* ---------------------------------------- */

int PASCAL FAR __WSAFDIsSet(SOCKET s, fd_set FAR *fds)
{
  w32sockstatics.lasterror = 0;
  FARPROC __proc = ImportWinsockSymbol( "__WSAFDIsSet" );
  if (__proc)
  {
    #if defined(__WINDOWS_386__)
    unsigned int i, count = (((unsigned int)(fds->fd_count)) & 0xffff);
    for (i=0;i<count;i++)
    {
      if (fds->fd_array[i] == s)
        return 1;
    }
    return 0;
    #else
    return (*((int (PASCAL FAR *)(SOCKET, fd_set FAR *))(__proc)))( s, fds );
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return 0;
}

/* ---------------------------------------- */

int PASCAL FAR select(int nfds, fd_set FAR *readfds, fd_set FAR *writefds,
               fd_set FAR *exceptfds, const struct timeval FAR *timeout)
{
  w32sockstatics.lasterror = 0;
  FARPROC __proc = ImportWinsockSymbol( "select" );
  if (__proc)
  {
    #if defined(__WINDOWS_386__)
    __map_int_to_short_fdset( readfds );
    __map_int_to_short_fdset( writefds );
    __map_int_to_short_fdset( exceptfds );
    short rc = (short)((0xFFFF) & (_Call16(__proc, "wpppp", nfds,
                      readfds, writefds, exceptfds, timeout )));
    __map_short_to_int_fdset( readfds );
    __map_short_to_int_fdset( writefds );
    __map_short_to_int_fdset( writefds );
    return ((rc<0)?(-1):(rc));
    #else
    return (*((int (PASCAL FAR *)(int, fd_set FAR *, fd_set FAR *,
         fd_set FAR *, const struct timeval FAR * ))(__proc)))
                            ( nfds, readfds, writefds, exceptfds, timeout );
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return -1;
}

/* ---------------------------------------- */

unsigned long PASCAL FAR inet_addr(const char FAR * cp)
{
  w32sockstatics.lasterror = 0;
  FARPROC __inet_addr = ImportWinsockSymbol( "inet_addr" );
  if (__inet_addr)
  {
    #if defined(__WINDOWS_386__)
    return (unsigned long)_Call16(__inet_addr, "p", cp );
    #else
    return (*((int (PASCAL FAR *)(const char FAR *))(__inet_addr)))(cp);
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return -1;
}

/* ---------------------------------------- */

#if defined(__WINDOWS_386__)
struct hostent FAR * PASCAL FAR __parsehostent(int dobyname, DWORD hpp )
{
  static struct
  {
    char hostname[256]; char aliasbuf[256]; char  addrbuf[128];
    char *addrlist[32]; char *aliaslist[8];
    struct hostent hent;
  } ghn[2];

  dobyname = ((dobyname)?(1):(0));
  struct hostent far *hp;
  unsigned int index;

  if (hpp)
  {
    hp = (struct hostent far *)MK_FP32( (void *)hpp );
    if (hp)
    {
      if (hp->h_length <= 0) /* screwed up implementation */
        return (struct hostent FAR *)0;

      ghn[dobyname].hostname[0] = 0;
      ghn[dobyname].aliaslist[0]= (char *)0;
      ghn[dobyname].addrlist[0] = (char *)0;

      ghn[dobyname].hent.h_addrtype = hp->h_addrtype;
      ghn[dobyname].hent.h_length = hp->h_length;
      ghn[dobyname].hent.h_name = &(ghn[dobyname].hostname[0]);
      ghn[dobyname].hent.h_aliases = &(ghn[dobyname].aliaslist[0]);
      ghn[dobyname].hent.h_addr_list = &(ghn[dobyname].addrlist[0]);

      index = 0;
      if (hp->h_addr_list)
      {
        char far *cfp = (char far *)MK_FP32((void *)hp->h_addr_list);
        unsigned int pos = 0;
        unsigned int addrlen = (unsigned int)(ghn[dobyname].hent.h_length);

        index=0;
        while (cfp && ((pos + addrlen) < sizeof(ghn[dobyname].addrbuf)) &&
          index<((sizeof(ghn[dobyname].addrlist)/sizeof(ghn[dobyname].addrlist[0]))-1))
        {
          void *vp;
          char *cp = (char *)&vp;
          unsigned int i;
          for (i=0;i<sizeof(vp);i++)
            *cp++=*cfp++;
          if (!vp)
            break;
          char far *ufp = (char far *)MK_FP32(vp);
          if (!ufp)
            break;
          ghn[dobyname].addrlist[index]=&(ghn[dobyname].addrbuf[pos]);
          for (i=0;i<((unsigned int)(addrlen));i++)
            ghn[dobyname].addrbuf[pos++]=*ufp++;

          index++;
        }
        ghn[dobyname].addrlist[index]=(char *)0;
        ghn[dobyname].hent.h_addr_list = &(ghn[dobyname].addrlist[0]);
      }

      index = 0;
      if (hp->h_aliases)
      {
        char far *cfp = (char far *)MK_FP32((void *)hp->h_aliases);
        unsigned int pos = 0;

        index=0;
        while (cfp && pos<sizeof(ghn[dobyname].aliasbuf) &&
          index<((sizeof(ghn[dobyname].aliaslist)/sizeof(ghn[dobyname].aliaslist[0]))-1))
        {
          void *vp;
          char *cp = (char *)&vp;
          unsigned int i;
          for (i=0;i<sizeof(vp);i++)
            *cp++=*cfp++;
          if (!vp)
            break;
          char far *ufp = (char far *)MK_FP32(vp);
          if (!ufp)
            break;
          ghn[dobyname].aliaslist[index]=&(ghn[dobyname].aliasbuf[pos]);
          while (*ufp && (pos<(sizeof(ghn[dobyname].aliasbuf)-1)))
            ghn[dobyname].aliasbuf[pos++]=*ufp++;
          if (*ufp)
            break;
          index++;
        }
        ghn[dobyname].aliaslist[index]=(char *)0;
        ghn[dobyname].hent.h_aliases = &(ghn[dobyname].aliaslist[0]);
      }

      if (hp->h_name)
      {
        char far *cfp = (char far *)MK_FP32( (void *)hp->h_name );
        unsigned int pos = 0;

        while (*cfp && pos<(sizeof(ghn[dobyname].hostname)-1))
          ghn[dobyname].hostname[pos++] = *cfp++;
        ghn[dobyname].hostname[pos]=0;
        ghn[dobyname].hent.h_name = &(ghn[dobyname].hostname[0]);
      }

      return &(ghn[dobyname].hent);
    }
  }
  return (struct hostent FAR *)0;
}

#endif /* if defined(__WINDOWS_386__) */


/* ---------------------------------------- */

struct hostent FAR * PASCAL FAR gethostbyaddr(const char FAR * name, int len, int type)
{
  w32sockstatics.lasterror = 0;
  FARPROC __gethostbyaddr = ImportWinsockSymbol( "gethostbyaddr" );
  if (__gethostbyaddr)
  {
    #if defined(__WINDOWS_386__)
    return __parsehostent(0, _Call16(__gethostbyaddr,"pww",name,len,type));
    #else
    return (*((struct hostent FAR * (PASCAL FAR *)(const char FAR *,int,int))
                                         (__gethostbyaddr)))(name,len,type);
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return (hostent FAR *)0;
}

/* ---------------------------------------- */

struct hostent FAR * PASCAL FAR gethostbyname(const char FAR * name)
{
  w32sockstatics.lasterror = 0;
  FARPROC __gethostbyname = ImportWinsockSymbol( "gethostbyname" );
  if (__gethostbyname)
  {
    #if defined(__WINDOWS_386__)
    return __parsehostent(1, _Call16(__gethostbyname,"p",name));
    #else
    return (*((struct hostent FAR * (PASCAL FAR *)(const char FAR *))
                                         (__gethostbyname)))(name);
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return (struct hostent FAR * )0;
}

/* ---------------------------------------- */

int PASCAL FAR send(SOCKET s, const char FAR * buf, int len, int flags)
{
  w32sockstatics.lasterror = 0;
  FARPROC __send = ImportWinsockSymbol( "send" );
  if (__send)
  {
    #if defined(__WINDOWS_386__)
    short rc;
    if (len > 0x7fff)
      len = 0x7fff;
    rc = (short)(0xFFFF & (_Call16(__send, "wpww", s, buf, len, flags)));
    return ((rc<0)?(-1):(((int)(rc))&0xFFFF));
    #else
    return (*((int (PASCAL FAR *)(SOCKET, const char FAR *, int, int))(__send)))
                                                         (s, buf, len, flags);
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return -1;
}

/* ---------------------------------------- */

int PASCAL FAR recv (SOCKET s, char FAR * buf, int len, int flags)
{
  w32sockstatics.lasterror = 0;
  FARPROC __recv = ImportWinsockSymbol( "recv" );
  if (__recv)
  {
    #if defined(__WINDOWS_386__)
    short rc;
    if (len > 0x7fff)
      len = 0x7fff;
    rc = (short)(0xFFFF & (_Call16(__recv, "wpww", s, buf, len, flags)));
    return ((rc<0)?(-1):(((int)(rc))&0xFFFF));
    #else
    return (*((int (PASCAL FAR *)(SOCKET, char FAR *, int, int))(__recv)))
                                                         (s, buf, len, flags);
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return -1;
}

/* ---------------------------------------- */

int PASCAL FAR ioctlsocket(SOCKET s, long cmd, u_long FAR *argp)
{
  w32sockstatics.lasterror = 0;
  FARPROC __ioctlsocket = ImportWinsockSymbol( "ioctlsocket" );
  if (__ioctlsocket)
  {
    #if defined(__WINDOWS_386__)
    return (((_Call16(__ioctlsocket, "wdp", s, cmd, argp )&0xFFFF)==0)?(0):(-1));
    #else
    return (*((int (PASCAL FAR *)(SOCKET, long, u_long FAR *))(__ioctlsocket)))
                                                          ( s, cmd, argp);
    #endif
  }
  w32sockstatics.lasterror = WSAEOPNOTSUPP;
  return -1;
}

/* ---------------------------------------- */

int PASCAL FAR WSAStartup(WORD wVerRequired, LPWSADATA lpWSAData)
{
  w32sockstatics.lasterror = WSANOTINITIALISED;
  int ec = WSASYSNOTREADY;

  if (!lpWSAData)
    return WSAEFAULT;

  int didinit = 0;
  if (w32sockstatics.initlevel == 0)
  {
    if (__w32sockInitDeinit( +1 ) == 0)
      return ec;
    w32sockstatics.internalinit = 1;
    didinit = 1;
  }

  FARPROC __WSAStartup = ImportWinsockSymbol( "WSAStartup" );
  if (__WSAStartup)
  {
    #if defined(__WINDOWS_386__)
    lpWSAData->szDescription[0]=0;
    lpWSAData->szSystemStatus[0]=0;
    ec = (_Call16( __WSAStartup, "wp", wVerRequired, lpWSAData )&0xFFFF);
    #else
    ec = (*((int (PASCAL FAR *)(WORD, LPWSADATA))(__WSAStartup)))
                                         (wVerRequired, lpWSAData);
    #endif
    if (ec == 0)
    {
      w32sockstatics.lasterror = 0;
      return 0;
    }
  }

  if (didinit)
  {
    __w32sockInitDeinit( -1 );
    w32sockstatics.internalinit = 0;
  }

  return ec;
}

/* ---------------------------------------- */

int PASCAL FAR WSACleanup(void)
{
  w32sockstatics.lasterror = 0;
  int rc = -1; /* SOCKET_ERROR */

  FARPROC __WSACleanup = ImportWinsockSymbol( "WSACleanup" );
  if (__WSACleanup)
  {
    #if defined(__WINDOWS_386__)
    rc=(((_Call16(__WSACleanup,"") & 0xFFFF) == 0)?(0):(rc));
    #else
    rc=(*((int (PASCAL FAR *)(void))(__WSACleanup)))();
    #endif
  }

  if (w32sockstatics.initlevel == 1 && w32sockstatics.internalinit)
  {
    __w32sockInitDeinit( -1 ); //decrements w32sockstatics.initlevel
    w32sockstatics.internalinit = 0;
  }

  w32sockstatics.lasterror = WSANOTINITIALISED;
  return rc;
}

/* ---------------------------------------- */

int w32sockInitialize(void)
{
  if (__w32sockInitDeinit(+1))
  {
    WSADATA wsadata;
    if ( WSAStartup(0x101, &wsadata ) == 0)
      return 1;
    __w32sockInitDeinit(-1);
  }
  return 0;
}

int w32sockDeinitialize(void)
{
  if (__w32sockInitDeinit(0))
  {
    WSACleanup();
    __w32sockInitDeinit(-1);
    return 1;
  }
  return 0;
}

int w32sockIsAlive(void)
{
  return __w32sockInitDeinit(0);
}

/* ---------------------------------------- */

