PageRenderTime 95ms CodeModel.GetById 3ms app.highlight 79ms RepoModel.GetById 1ms app.codeStats 0ms

/vm/platforms/win32/plugins/SocketPlugin/sqWin32NewNet.c

https://bitbucket.org/rmacnak/nsvm
C | 1986 lines | 1356 code | 229 blank | 401 comment | 299 complexity | 00e3536599da5bfd78c17fdee9b3e996 MD5 | raw file
   1/****************************************************************************
   2*   PROJECT: Squeak port for Win32 (NT / Win95)
   3*   FILE:    sqWin32Net.c
   4*   CONTENT: Networking in Squeak
   5*
   6*   AUTHOR:  Andreas Raab (ar)
   7*   ADDRESS: University of Magdeburg, Germany
   8*   EMAIL:   raab@isg.cs.uni-magdeburg.de
   9*   RCSID:   $Id: sqWin32NewNet.c 1383 2006-03-27 07:25:07Z andreas $
  10*
  11*   NOTES:
  12*	1) TCP & UDP are now fully supported.
  13*	2) State changes are now recorded from separate threads to give
  14*	   maximum responsiveness to Squeak servers.
  15*	3) Sockets are always accept()ed by the OS level thread. I *think*
  16*	   that this is a good idea because it makes loosing connections due
  17*	   to inactivity from Squeak rather unlikely.Though, of course, it
  18*	   requires resources...
  19*
  20*****************************************************************************/
  21#include <windows.h>
  22#include <winsock.h>
  23#include <errno.h> /* For cygwin gcc 3.4 */
  24#include "sq.h"
  25#include "SocketPlugin/SocketPlugin.h"
  26
  27#ifndef NO_NETWORK
  28
  29#ifndef NO_RCSID
  30  static char RCSID[]="$Id: sqWin32NewNet.c 1383 2006-03-27 07:25:07Z andreas $";
  31#endif
  32
  33#if 0
  34
  35#ifdef __MINGW32__
  36/*
  37 * WinSock 2 extension -- manifest constants for WSAIoctl()
  38 */
  39#define IOC_UNIX                      0x00000000
  40#define IOC_WS2                       0x08000000
  41#define IOC_PROTOCOL                  0x10000000
  42#define IOC_VENDOR                    0x18000000
  43
  44#define _WSAIO(x,y)                   (IOC_VOID|(x)|(y))
  45#define _WSAIOR(x,y)                  (IOC_OUT|(x)|(y))
  46#define _WSAIOW(x,y)                  (IOC_IN|(x)|(y))
  47#define _WSAIORW(x,y)                 (IOC_INOUT|(x)|(y))
  48
  49#define SIO_ASSOCIATE_HANDLE          _WSAIOW(IOC_WS2,1)
  50#define SIO_ENABLE_CIRCULAR_QUEUEING  _WSAIO(IOC_WS2,2)
  51#define SIO_FIND_ROUTE                _WSAIOR(IOC_WS2,3)
  52#define SIO_FLUSH                     _WSAIO(IOC_WS2,4)
  53#define SIO_GET_BROADCAST_ADDRESS     _WSAIOR(IOC_WS2,5)
  54#define SIO_GET_EXTENSION_FUNCTION_POINTER  _WSAIORW(IOC_WS2,6)
  55#define SIO_GET_QOS                   _WSAIORW(IOC_WS2,7)
  56#define SIO_GET_GROUP_QOS             _WSAIORW(IOC_WS2,8)
  57#define SIO_MULTIPOINT_LOOPBACK       _WSAIOW(IOC_WS2,9)
  58#define SIO_MULTICAST_SCOPE           _WSAIOW(IOC_WS2,10)
  59#define SIO_SET_QOS                   _WSAIOW(IOC_WS2,11)
  60#define SIO_SET_GROUP_QOS             _WSAIOW(IOC_WS2,12)
  61#define SIO_TRANSLATE_HANDLE          _WSAIORW(IOC_WS2,13)
  62#define SIO_ROUTING_INTERFACE_QUERY   _WSAIORW(IOC_WS2,20)
  63#define SIO_ROUTING_INTERFACE_CHANGE  _WSAIOW(IOC_WS2,21)
  64#define SIO_ADDRESS_LIST_QUERY        _WSAIOR(IOC_WS2,22)
  65#define SIO_ADDRESS_LIST_CHANGE       _WSAIO(IOC_WS2,23)
  66#define SIO_QUERY_TARGET_PNP_HANDLE   _WSAIOR(IOC_WS2,24)
  67#define SIO_ADDRESS_LIST_SORT         _WSAIORW(IOC_WS2,25)
  68
  69
  70int
  71FAR PASCAL
  72WSAIoctl(
  73    SOCKET s,
  74    DWORD dwIoControlCode,
  75    LPVOID lpvInBuffer,
  76    DWORD cbInBuffer,
  77    LPVOID lpvOutBuffer,
  78    DWORD cbOutBuffer,
  79    LPDWORD lpcbBytesReturned,
  80    LPOVERLAPPED lpOverlapped,
  81    void *lpCompletionRoutine
  82    );
  83#endif
  84
  85#endif
  86
  87#ifndef NDEBUG
  88#define DBG(s) debugCheckWatcherThreads(PSP(s))
  89#else
  90#define DBG(s)
  91#endif
  92
  93/*** Socket Type Constants ***/
  94#define TCPSocketType 0
  95#define UDPSocketType 1
  96
  97/*** Resolver Status Constants ***/
  98#define RESOLVER_UNINITIALIZED 0
  99#define RESOLVER_SUCCESS  1
 100#define RESOLVER_BUSY   2
 101#define RESOLVER_ERROR   3
 102
 103/*** TCP Socket Status Constants ***/
 104#define Unconnected    0
 105#define WaitingForConnection 1
 106#define Connected    2
 107#define OtherEndClosed   3
 108#define ThisEndClosed   4
 109
 110/* read/write watcher operations */
 111#define WatchNone 0
 112#define WatchData 1
 113#define WatchConnect 2
 114#define WatchClose 3
 115#define WatchAccept 4
 116#define WatchAcceptSingle 5
 117
 118#define MIN(a,b) ((a) < (b) ? (a) : (b))
 119#define MAX(a,b) ((a) > (b) ? (a) : (b))
 120#define SIGNAL(index) synchronizedSignalSemaphoreWithIndex(index)
 121
 122#ifndef INVALID_SOCKET
 123#define INVALID_SOCKET (-1)
 124#endif
 125#ifndef SOCKET_ERROR
 126#define SOCKET_ERROR (-1)
 127#endif
 128
 129static WSADATA wsaData;
 130
 131static int resolverSemaphoreIndex = 0;
 132static int thisNetSession = 0;
 133static u_long zero = 0;
 134static u_long one = 1;
 135
 136#ifndef MAXHOSTNAMELEN
 137#define MAXHOSTNAMELEN 256
 138#endif
 139static char localHostName[MAXHOSTNAMELEN];
 140static u_long localHostAddress;
 141
 142/* Structure for storing accepted sockets */
 143typedef struct acceptedSocketStruct {
 144  struct acceptedSocketStruct *next;
 145  struct sockaddr_in peer;
 146  SOCKET s;
 147} acceptedSocketStruct;
 148
 149/* Socket structure private to primitive implementation */
 150typedef struct privateSocketStruct {
 151  struct privateSocketStruct *next;
 152  SOCKET s;
 153
 154  int sockType;
 155  int sockState;
 156  int sockError;
 157
 158  int readSema;
 159  int writeSema;
 160  int connSema;
 161
 162  struct sockaddr_in peer;  /* socket address in connect() or send/rcv address for UDP */
 163
 164  HANDLE mutex;             /* The mutex used for synchronized access to this socket */
 165  acceptedSocketStruct *accepted; /* Accepted connections on a socket */
 166
 167
 168  DWORD  readWatcherOp;      /* read operation to watch */
 169  HANDLE hReadWatcherEvent;  /* event for waking up read watcher */
 170  HANDLE hReadThread;
 171
 172  DWORD  writeWatcherOp;     /* write operation to watch */
 173  HANDLE hWriteWatcherEvent; /* event for waking up write watcher */
 174  HANDLE hWriteThread;
 175
 176  volatile DWORD closePending; /* Cleanup counter */
 177
 178  int readSelect;
 179  int writeSelect;
 180} privateSocketStruct;
 181
 182static privateSocketStruct *firstSocket = NULL;
 183/* Additional flags for sockState which will be received by async notification:
 184   SOCK_DATA_WRITABLE      - all pending data has been sent
 185   SOCK_DATA_READABLE      - data is available for this connection
 186   SOCK_SERVER			   - socket has been initialized for accept()
 187   SOCK_BOUND_UDP		   - UDP socket has a local port assigned
 188*/
 189#define SOCK_PUBLIC_MASK   0x0000FFFF
 190#define SOCK_DATA_WRITABLE 0x00010000
 191#define SOCK_DATA_READABLE 0x00020000
 192#define SOCK_BOUND_UDP     0x00040000
 193
 194/********* Private accessors of a Squeak socket pointer *********/
 195#define PSP(s)         ((privateSocketStruct*) ((s)->privateSocketPtr))
 196
 197#define SOCKET(s)      (PSP(s)->s)
 198#define SOCKETSTATE(s) (PSP(s)->sockState)
 199#define SOCKETERROR(s) (PSP(s)->sockError)
 200#define ADDRESS(s)      ((struct sockaddr_in*)(&PSP(s)->peer))
 201
 202extern struct VirtualMachine *interpreterProxy;
 203#define FAIL()         interpreterProxy->primitiveFail()
 204
 205#define LOCKSOCKET(mutex, duration) \
 206  if(WaitForSingleObject(mutex, duration) == WAIT_FAILED)\
 207      printLastError(TEXT("Failed to lock socket"));
 208#define UNLOCKSOCKET(mutex)\
 209  if(ReleaseMutex(mutex) == 0)\
 210    printLastError(TEXT("Failed to unlock socket"));
 211
 212/*****************************************************************************
 213 Helpers
 214 *****************************************************************************/
 215static int socketReadable(SOCKET s)
 216{
 217  struct timeval tv= { 0, 0 };
 218  fd_set fds;
 219
 220  FD_ZERO(&fds);
 221  FD_SET(s, &fds);
 222  return select(1, &fds, NULL, NULL, &tv) == 1;
 223}
 224
 225static int socketWritable(SOCKET s)
 226{
 227  struct timeval tv= { 0, 0 };
 228  fd_set fds;
 229
 230  FD_ZERO(&fds);
 231  FD_SET(s, &fds);
 232  return select(1, NULL, &fds, NULL, &tv) == 1;
 233}
 234
 235static int socketError(SOCKET s)
 236{
 237  struct timeval tv= { 0, 0 };
 238  fd_set fds;
 239
 240  FD_ZERO(&fds);
 241  FD_SET(s, &fds);
 242  return select(1, NULL, NULL, &fds, &tv) == 1;
 243}
 244
 245static int removeFromList(privateSocketStruct *pss) {
 246  /* remove the private pointer from the list */
 247  privateSocketStruct *tmp;
 248  if(pss == firstSocket) firstSocket = pss->next;
 249  else {
 250    tmp = firstSocket;
 251    while(tmp && tmp->next != pss) tmp = tmp->next;
 252    if(tmp) tmp->next = pss->next;
 253  }
 254}
 255
 256/* cleanupSocket:
 257   Clean up the private socket structure and associated elements.
 258   The function is called from the watcher threads when a socket
 259   is being destroyed.
 260*/
 261static void cleanupSocket(privateSocketStruct *pss)
 262{
 263  int remainingThreads;
 264
 265  /* Guard socket state for modification */
 266  LOCKSOCKET(pss->mutex, INFINITE);
 267  remainingThreads = --pss->closePending;
 268  UNLOCKSOCKET(pss->mutex);
 269  if(remainingThreads > 0) {
 270    /* somebody else will do the cleanup */
 271    return;
 272  }
 273  /* I am the last thread. Do the cleanup */
 274  CloseHandle(pss->mutex);
 275  CloseHandle(pss->hReadWatcherEvent);
 276  CloseHandle(pss->hWriteWatcherEvent);
 277  CloseHandle(pss->hReadThread);
 278  CloseHandle(pss->hWriteThread);
 279
 280  /* Cleanup any accepted sockets */
 281  while(pss->accepted) {
 282    acceptedSocketStruct *temp = pss->accepted;
 283    struct linger l;
 284    pss->accepted = temp->next;
 285    l.l_onoff = 1;
 286    l.l_linger = 0;
 287    setsockopt(temp->s, SOL_SOCKET, SO_LINGER, (char*)&l, sizeof(l));
 288    closesocket(temp->s);
 289    temp->s = 0;
 290    GlobalFree(GlobalHandle(temp));
 291  }
 292  /* And again: C allocators thread safe?! */
 293  free(pss);
 294  /* done */
 295}
 296
 297
 298/* inplaceAcceptHandler:
 299   Accept an incoming connection and store the new socket in place
 300   of the old one. NOTE: Called from thread while socket is locked.
 301*/
 302static int inplaceAcceptHandler(privateSocketStruct *pss)
 303{
 304  SOCKET newSocket;
 305  struct linger l;
 306
 307  newSocket = accept(pss->s,0,NULL);
 308  if(newSocket == INVALID_SOCKET) {
 309    pss->sockError = WSAGetLastError();
 310  } else {
 311    /* Destroy the server socket */
 312    l.l_onoff = 1;
 313    l.l_linger = 0;
 314    setsockopt(pss->s, SOL_SOCKET, SO_LINGER, (char*)&l, sizeof(l));
 315    ioctlsocket(newSocket,FIONBIO,&zero);
 316    closesocket(pss->s);
 317    pss->s = 0;
 318    /* Make the socket non-blocking */
 319    ioctlsocket(newSocket,FIONBIO,&one);
 320    /* And install the new socket */
 321    pss->s = newSocket;
 322    pss->sockState = Connected | SOCK_DATA_WRITABLE; /* connected and ready to send */
 323  }
 324  return 1;
 325}
 326
 327/* acceptHandler:
 328   Accept an incoming connection and store the socket in the
 329   list of accepted sockets from the server socket.
 330   NOTE: Called from thread while socket is locked.
 331*/
 332static int acceptHandler(privateSocketStruct *pss)
 333{
 334  SOCKET result;
 335  int addrSize = sizeof(struct sockaddr_in);
 336  struct sockaddr_in addr;
 337  acceptedSocketStruct *accepted = NULL;
 338
 339  /* accept incoming connections */
 340  result = accept(pss->s, (struct sockaddr*) &pss->peer, &addrSize);
 341  if(result != INVALID_SOCKET) {
 342    /* prepare the accept structure */
 343    /* Q: Are the C allocation functions thread safe?! */
 344    accepted = GlobalLock(GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(acceptedSocketStruct)));
 345    if(accepted) {
 346      accepted->s = result;
 347      MoveMemory(&accepted->peer, &addr, addrSize);
 348    }
 349  } else {
 350    pss->sockError = WSAGetLastError();
 351  }
 352  if(accepted != NULL) {
 353    accepted->next = pss->accepted;
 354    pss->accepted = accepted;
 355    pss->sockState = Connected;
 356  }
 357  return 1;
 358}
 359
 360/*****************************************************************************
 361 ****************************************************************************/
 362static void debugPrintSocket(privateSocketStruct *pss) {
 363  printf("### Socket [%x]\n", pss);
 364  printf("\tHandle: %x\n", pss->s);
 365  printf("\tType: %d\n", pss->sockType);
 366  printf("\tState: %x", pss->sockState & SOCK_PUBLIC_MASK);
 367  if(pss->sockState & SOCK_DATA_READABLE)
 368    printf(" [readable]");
 369  if(pss->sockState & SOCK_DATA_WRITABLE)
 370    printf(" [writable]");
 371  if(pss->sockState & SOCK_BOUND_UDP)
 372    printf(" [bound for udp]");
 373  printf("\n");
 374  printf("\tError: %x\n", pss->sockError);
 375  printf("\treadSema: %d\n", pss->readSema);
 376  printf("\twriteSema: %d\n", pss->writeSema);
 377  printf("\tconnSema: %d\n", pss->connSema);
 378  { /* count pending accept()s */
 379    acceptedSocketStruct *tmp = pss->accepted;
 380    int n = 0;
 381    while(tmp) {
 382      tmp = tmp->next;
 383      n++;
 384    }
 385    printf("\tPending accepts: %d\n",n);
 386  }
 387  printf("\tRead Watcher Op: %d\n", pss->readWatcherOp);
 388  printf("\tWrite Watcher Op: %d\n",pss->writeWatcherOp);
 389  printf("\tClose pending: %d\n",pss->closePending);
 390  printf("\tIn read select: %d\n", pss->readSelect);
 391  printf("\tIn write select: %d\n", pss->writeSelect);
 392}
 393
 394int win32DebugPrintSocketState(void) {
 395  privateSocketStruct *pss;
 396
 397  pss = firstSocket;
 398  while(pss) {
 399    debugPrintSocket(pss);
 400    pss = pss->next;
 401  }
 402}
 403
 404static void debugCheckWatcherThreads(privateSocketStruct *pss) {
 405  int state = pss->sockState;
 406  int printReason = 0;
 407
 408  if(pss->readWatcherOp == WatchAccept) {
 409    /* accept() is different; don't bother */
 410    return;
 411  }
 412  if(pss->readWatcherOp == WatchAcceptSingle) {
 413    /* same thing */
 414    return;
 415  }
 416
 417  if( (state & SOCK_PUBLIC_MASK) == Unconnected )
 418    /* means we should not be watching anything */
 419    if(pss->readSelect || pss->writeSelect ||
 420       (pss->readWatcherOp != 0) || (pss->writeWatcherOp != 0)) {
 421      printReason |= 1; /* watching stuff on unconnected socket */
 422    }
 423
 424  if( (state & SOCK_PUBLIC_MASK) == Connected) {
 425    if(pss->readWatcherOp != WatchData)
 426      printReason |= 2; /* watching non-data stuff on connected socket */
 427    if( (state & SOCK_DATA_READABLE) == pss->readSelect)
 428      printReason |= 4; /* watching w/ data or not watching w/o data */
 429    if(pss->writeWatcherOp != WatchData)
 430      printReason |= 8; /* watching non-data stuff */
 431    if( (state & SOCK_DATA_WRITABLE) == pss->writeSelect)
 432      printReason |= 16; /* watching w/ data or not watching w/o data */
 433  }
 434
 435  if( (state & SOCK_PUBLIC_MASK) == WaitingForConnection) {
 436    if(!pss->writeSelect || (pss->writeWatcherOp != WatchConnect))
 437      printReason |= 32; /* not watching for connection */
 438  }
 439  if( (state & SOCK_PUBLIC_MASK) == ThisEndClosed) {
 440    if(!pss->readSelect || (pss->readWatcherOp != WatchClose))
 441      printReason |= 64; /* not watching for close */
 442  }
 443  if(printReason) {
 444    printf("#### WARNING: Watcher threads are running wild on socket\n");
 445    if(printReason & 1)
 446      printf("\t* Watching for stuff while unconnected\n");
 447    if(printReason & 2)
 448      printf("\t* Watching for non-data while no data readable\n");
 449    if(printReason & 4)
 450      printf("\t* Socket read state differs from select() state\n");
 451    if(printReason & 8)
 452      printf("\t* Watching for non-data while no data writable\n");
 453    if(printReason & 16)
 454      printf("\t* Socket write state differs from select() state\n");
 455    if(printReason & 32)
 456      printf("\t* Watching for non-connect while connecting\n");
 457    if(printReason & 64)
 458      printf("\t* Watching for non-close while closing\n");
 459    debugPrintSocket(pss);
 460  }
 461}
 462
 463/*****************************************************************************
 464 *****************************************************************************
 465 State watcher threads:
 466 The following two functions are run from separate threads. They identify
 467 a change in read/write state (e.g., whenever a socket switches from
 468 non-readable to readable or from non-writeable to writeable) set the
 469 appropriate flags and signal the associated semaphore. To avoid possible
 470 problems with resource allocation, the threads are never explicitly
 471 terminated. They have instead an associated timeout value in select()
 472 after which they can terminate themselves if requested.
 473 *****************************************************************************
 474 *****************************************************************************/
 475
 476static DWORD WINAPI readWatcherThread(privateSocketStruct *pss)
 477{
 478  struct timeval tv= { 1000, 0 }; /* Timeout value == 1000 sec */
 479  fd_set fds;
 480  int n, doWait, sema;
 481
 482  while(1) {
 483    doWait = 1;
 484    /* Do we have a task to perform?! */
 485    if(pss->readWatcherOp) {
 486      /* Determine state of the socket */
 487      FD_ZERO(&fds);
 488      FD_SET(pss->s, &fds);
 489      pss->readSelect = 1;
 490      n = select(1, &fds, NULL, NULL, &tv);
 491      pss->readSelect = 0;
 492      /* Note: select will return
 493	 0 - if it timed out (unlikely but possible)
 494	 1 - if the socket is readable
 495	 SOCKET_ERROR - if the socket has been closed
 496      */
 497      if(n == 1) {
 498	/* Guard socket state modification */
 499	LOCKSOCKET(pss->mutex, INFINITE);
 500	/* Change appropriate socket state */
 501	switch(pss->readWatcherOp) {
 502	case WatchData:
 503	  /* Data may be available */
 504	  pss->sockState |= SOCK_DATA_READABLE;
 505	  SIGNAL(pss->readSema);
 506	  doWait = 1; /* until data has been read */
 507	  break;
 508	case WatchClose:
 509	  /* Pending close has succeeded */
 510	  pss->sockState = ThisEndClosed;
 511	  pss->readWatcherOp = 0; /* since a close succeeded */
 512	  pss->s = 0;
 513	  SIGNAL(pss->connSema);
 514	  doWait = 1;
 515	  break;
 516	case WatchAcceptSingle:
 517	  /* Accept a single connection inplace */
 518	  inplaceAcceptHandler(pss);
 519	  pss->readWatcherOp = WatchData; /* check for incoming data */
 520	  pss->writeWatcherOp = WatchData; /* and signal when writable */
 521	  SIGNAL(pss->connSema);
 522	  doWait = 0;
 523	  break;
 524	case WatchAccept:
 525	  /* Connection can be accepted */
 526	  acceptHandler(pss);
 527	  SIGNAL(pss->connSema);
 528	  doWait = 0; /* only wait for more connections */
 529	  break;
 530	}
 531	UNLOCKSOCKET(pss->mutex);
 532      } else {
 533	if(n == SOCKET_ERROR) {
 534	  int err = WSAGetLastError();
 535	  LOCKSOCKET(pss->mutex, INFINITE);
 536	  pss->sockState = OtherEndClosed;
 537	  pss->sockError = err;
 538	  SIGNAL(pss->connSema);
 539	  UNLOCKSOCKET(pss->mutex);
 540	} else {
 541	  /* select() timed out */
 542	  doWait = 0; /* continue waiting in select() */
 543	}
 544      }
 545    }
 546
 547    /* Wait until we have something to do */
 548    if(doWait && !pss->closePending)
 549      WaitForSingleObject(pss->hReadWatcherEvent, INFINITE);
 550
 551    /* Check if we need to close the socket */
 552    if(pss->closePending) {
 553      cleanupSocket(pss);
 554      /* And stop running */
 555      ExitThread(0);
 556    }
 557  }
 558}
 559
 560static DWORD WINAPI writeWatcherThread(privateSocketStruct *pss)
 561{
 562  struct timeval tv= { 1000, 0 }; /* Timeout value == 1000 sec */
 563  fd_set fds, err;
 564  int n, doWait, errSize;
 565
 566  while(1) {
 567    doWait = 1;
 568    if(pss->writeWatcherOp) {
 569      /* Determine state of the socket */
 570      FD_ZERO(&fds);
 571      FD_SET(pss->s, &fds);
 572      FD_ZERO(&err);
 573      FD_SET(pss->s, &err);
 574      pss->writeSelect = 1;
 575      n = select(1, NULL, &fds, &err, &tv);
 576      pss->writeSelect = 0;
 577      /* Note: select will return
 578	 0 - if it timed out (unlikely but possible)
 579	 1 - if the socket is writable or an error occured
 580	 SOCKET_ERROR - if the socket has been closed
 581      */
 582      if(n == 1) {
 583	/* Guard socket state modification */
 584	LOCKSOCKET(pss->mutex, INFINITE);
 585	if(FD_ISSET(pss->s, &err)) {
 586	  /* An error occured */
 587	  if(pss->writeWatcherOp == WatchConnect) {
 588	    /* asynchronous connect failed */
 589	    pss->sockState = Unconnected;
 590	    SIGNAL(pss->connSema);
 591	  } else {
 592	    /* get socket error */
 593	    /* printf("ERROR: %d\n", WSAGetLastError()); */
 594	    errSize = sizeof(pss->sockError);
 595	    getsockopt(pss->s, SOL_SOCKET, SO_ERROR, (char*)&pss->sockError, &errSize);
 596	    SIGNAL(pss->writeSema);
 597	  }
 598	  pss->writeWatcherOp = 0; /* what else can we do */
 599	  doWait = 1; /* until somebody wakes us up */
 600	} else {
 601	  /* Change appropriate socket state */
 602	  switch(pss->writeWatcherOp) {
 603	  case WatchConnect:
 604	    /* Pending connect() has succeeded */
 605	    pss->sockState = Connected | SOCK_DATA_WRITABLE;
 606	    /* Start read watcher for incoming data */
 607	    pss->readWatcherOp = WatchData;
 608	    SetEvent(pss->hReadWatcherEvent);
 609	    SIGNAL(pss->connSema);
 610	    /* And fall through since data can be sent */
 611	    pss->writeWatcherOp = WatchData;
 612	  case WatchData:
 613	    /* Data can be sent */
 614	    pss->sockState |= SOCK_DATA_WRITABLE;
 615	    SIGNAL(pss->writeSema);
 616	    doWait = 1; /* until data has been written */
 617	    break;
 618	  }
 619	}
 620	UNLOCKSOCKET(pss->mutex);
 621      } else {
 622	if(n == SOCKET_ERROR) {
 623	  int err = WSAGetLastError();
 624	  LOCKSOCKET(pss->mutex, INFINITE);
 625	  pss->sockState = OtherEndClosed;
 626	  pss->sockError = err;
 627	  SIGNAL(pss->connSema);
 628	  UNLOCKSOCKET(pss->mutex);
 629	} else {
 630	  /* select() timed out */
 631	  doWait = 0; /* continue waiting in select() */
 632	}
 633      }
 634    }
 635    /* Wait until we have something to do */
 636    if(doWait && !pss->closePending) {
 637      WaitForSingleObject(pss->hWriteWatcherEvent, INFINITE);
 638    }
 639
 640    /* Check if we need to close the socket */
 641    if(pss->closePending) {
 642      cleanupSocket(pss);
 643      /* And stop running */
 644      ExitThread(0);
 645    }
 646  }
 647}
 648
 649/*****************************************************************************
 650 *****************************************************************************
 651 *****************************************************************************/
 652
 653static void abortSocket(privateSocketStruct *pss)
 654{
 655  struct linger l;
 656
 657  LOCKSOCKET(pss->mutex, INFINITE);
 658  l.l_onoff = 1;
 659  l.l_linger = 0;
 660  setsockopt(pss->s, SOL_SOCKET, SO_LINGER, (char*)&l, sizeof(l));
 661  closesocket(pss->s);
 662  pss->s = 0;
 663  pss->sockState = Unconnected;
 664  pss->readWatcherOp = 0;
 665  pss->writeWatcherOp = 0;
 666  UNLOCKSOCKET(pss->mutex);
 667}
 668
 669/* createWatcherThreads: Create the state change watcher threads */
 670static int createWatcherThreads(privateSocketStruct *pss)
 671{
 672  DWORD id;
 673  HANDLE hThread;
 674  SYSTEM_INFO sysInfo;
 675  DWORD pageSize;
 676
 677  /* determine page boundaries */
 678  GetSystemInfo(&sysInfo);
 679  pageSize = sysInfo.dwPageSize;
 680
 681  /* Setup events */
 682  pss->hReadWatcherEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
 683  pss->hWriteWatcherEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
 684
 685  /* Create the read watcher */
 686  hThread =
 687    CreateThread(NULL,			   /* No security descriptor */
 688		 pageSize,                 /* default stack size     */
 689		 (LPTHREAD_START_ROUTINE) readWatcherThread, /* what to do */
 690		 (LPVOID) pss,      /* parameter for thread   */
 691		 CREATE_SUSPENDED,  /* creation parameter -- create suspended so we can check the return value */
 692		 &id);              /* return value for thread id */
 693  pss->hReadThread = hThread;
 694  if(!hThread) {
 695    printLastError(TEXT("CreateThread() failed"));
 696    removeFromList(pss);
 697    pss->closePending = 1;
 698    abortSocket(pss);
 699    cleanupSocket(pss);
 700    return 0;
 701  }
 702  if(!SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST))
 703    printLastError(TEXT("SetThreadPriority() failed"));
 704  if(!ResumeThread(hThread))
 705    printLastError(TEXT("ResumeThread() failed"));
 706
 707  /* Create the write watcher */
 708  hThread =
 709    CreateThread(NULL,			   /* No security descriptor */
 710		 pageSize,                 /* default stack size     */
 711		 (LPTHREAD_START_ROUTINE) writeWatcherThread,/* what to do */
 712		 (LPVOID) pss,      /* parameter for thread   */
 713		 CREATE_SUSPENDED,  /* creation parameter -- create suspended so we can check the return value */
 714		 &id);              /* return value for thread id */
 715  pss->hWriteThread = hThread;
 716  if(!hThread) {
 717    printLastError(TEXT("CreateThread() failed"));
 718    removeFromList(pss);
 719    abortSocket(pss);
 720    pss->closePending = 1;
 721    SetEvent(pss->hReadWatcherEvent);
 722    return 0;
 723  }
 724  if(!SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST))
 725    printLastError(TEXT("SetThreadPriority() failed"));
 726  if(!ResumeThread(hThread))
 727    printLastError(TEXT("ResumeThread() failed"));
 728
 729  return 1;
 730}
 731
 732/*****************************************************************************
 733 *****************************************************************************
 734 *****************************************************************************/
 735
 736/*****************************************************************************
 737  sqNetworkInit: Initialize network with the given DNS semaphore.
 738*****************************************************************************/
 739int sqNetworkInit(int resolverSemaIndex)
 740{
 741  int err;
 742
 743
 744  if (thisNetSession != 0) return 0;  /* noop if network is already initialized */
 745
 746  err = WSAStartup( MAKEWORD(2,0), &wsaData );
 747  if ( err != 0 )
 748    return -1;
 749
 750  /* Confirm that the Windows Sockets DLL supports 1.1 or greater */
 751  if(HIBYTE(wsaData.wVersion < 1) || HIBYTE(wsaData.wVersion) > 2) {
 752    WSACleanup();
 753    return -1;
 754  }
 755
 756  gethostname(localHostName,MAXHOSTNAMELEN);
 757  thisNetSession = GetTickCount();
 758  if (thisNetSession == 0) thisNetSession = 1;  /* don't use 0 */
 759
 760  /* install resolver semaphore */
 761  resolverSemaphoreIndex = resolverSemaIndex;
 762
 763  /* Done. */
 764  return 0;
 765}
 766
 767/*****************************************************************************
 768  sqNetworkShutdown: Clean up networking.
 769*****************************************************************************/
 770void sqNetworkShutdown(void)
 771{
 772  privateSocketStruct *pss;
 773  if (thisNetSession == 0) return;  /* noop if network is already shut down */
 774
 775  /* Clean up pending sockets */
 776  while(firstSocket) {
 777    pss = firstSocket;
 778    /* Abort socket */
 779    abortSocket(pss);
 780    /* Prepare cleanup from threads */
 781    LOCKSOCKET(pss->mutex, INFINITE);
 782    pss->closePending = 2; /* threads are running */
 783    pss->readWatcherOp = 0;
 784    pss->writeWatcherOp = 0;
 785    SetEvent(pss->hReadWatcherEvent);
 786    SetEvent(pss->hWriteWatcherEvent);
 787    firstSocket = pss->next;
 788    UNLOCKSOCKET(pss->mutex);
 789    /* Note: it is important that we guard the SetEvent() above
 790       since the threads are running at higher priority and may
 791       immediately try to clean up once SetEvent() is called.
 792       Locking the socket prevents them until we are finished */
 793  }
 794  thisNetSession = 0;
 795  WSACleanup();
 796}
 797
 798/*** Squeak Generic Socket Functions ***/
 799
 800/*****************************************************************************
 801  SocketValid: Validate a given SocketPtr
 802*****************************************************************************/
 803static int SocketValid(SocketPtr s) {
 804  if ((s != NULL) &&
 805      (s->privateSocketPtr != NULL) &&
 806      (s->sessionID == thisNetSession)) {
 807    return true;
 808  } else {
 809    FAIL();
 810    return false;
 811  }
 812}
 813
 814/*****************************************************************************
 815  sqSocketAbortConnection: Immediately terminate a pending connection
 816*****************************************************************************/
 817void sqSocketAbortConnection(SocketPtr s)
 818{
 819  if (!SocketValid(s)) return;
 820  /* abort the socket connection */
 821  abortSocket(PSP(s));
 822}
 823
 824/*****************************************************************************
 825  sqSocketCloseConnection: gracefully close an open socket
 826*****************************************************************************/
 827void sqSocketCloseConnection(SocketPtr s)
 828{
 829  privateSocketStruct *pss = PSP(s);
 830  int err;
 831
 832  if (!SocketValid(s)) return;
 833  /* Try to gracefully close the socket */
 834  err = closesocket(SOCKET(s));
 835  LOCKSOCKET(pss->mutex, INFINITE);
 836  pss->readWatcherOp = pss->writeWatcherOp = 0;
 837  if(err) {
 838    err = WSAGetLastError();
 839    if(err == WSAEWOULDBLOCK) {
 840      /* Setup the read watcher to see when it closed */
 841      pss->sockState = ThisEndClosed;
 842      pss->readWatcherOp = WatchClose;
 843      pss->writeWatcherOp = 0;
 844      SetEvent(pss->hReadWatcherEvent);
 845    } else {
 846      pss->sockState = Unconnected;
 847      pss->sockError = err;
 848      SIGNAL(pss->connSema);
 849    }
 850  } else {
 851    pss->s = 0;
 852    pss->sockState = Unconnected;
 853    SIGNAL(pss->connSema);
 854  }
 855  /* Cleanup any accepted sockets */
 856  while(pss->accepted) {
 857    acceptedSocketStruct *temp = pss->accepted;
 858    struct linger l;
 859    pss->accepted = temp->next;
 860    l.l_onoff = 1;
 861    l.l_linger = 0;
 862    setsockopt(temp->s, SOL_SOCKET, SO_LINGER, (char*)&l, sizeof(l));
 863    closesocket(temp->s);
 864    temp->s = 0;
 865    GlobalFree(GlobalHandle(temp));
 866  }
 867  UNLOCKSOCKET(pss->mutex);
 868}
 869
 870/*****************************************************************************
 871  sqSocketConnectionStatus: return public status flags of the socket
 872*****************************************************************************/
 873int sqSocketConnectionStatus(SocketPtr s)
 874{
 875  int status;
 876
 877  if (!SocketValid(s)) return -1;
 878  DBG(s);
 879  status = SOCKETSTATE(s) & 0xFFFF;
 880  return status;
 881}
 882
 883/*****************************************************************************
 884  sqSocketConnectToPort:
 885	TCP => open a connection.
 886	UDP => set remote address.
 887*****************************************************************************/
 888void sqSocketConnectToPort(SocketPtr s, int addr, int port)
 889{
 890  int err;
 891  privateSocketStruct *pss = PSP(s);
 892
 893  if (!SocketValid(s)) return;
 894  ZeroMemory(ADDRESS(s),sizeof(struct sockaddr_in));
 895  ADDRESS(s)->sin_family = AF_INET;
 896  ADDRESS(s)->sin_port = htons((short)port);
 897  ADDRESS(s)->sin_addr.s_addr = htonl(addr);
 898
 899  if(UDPSocketType == s->socketType) { /* UDP */
 900    if(!pss->sockState & SOCK_BOUND_UDP) {
 901      /* The socket is locally unbound and we
 902	 must 'magically' assign a local port so
 903	 that client code can also read from the socket */
 904      sqSocketListenOnPort(s,0); /* Note: 0 is a wildcard */
 905    }
 906    return;
 907  }
 908
 909  /* TCP */
 910  err = connect( SOCKET(s), (struct sockaddr*) ADDRESS(s), sizeof(struct sockaddr_in));
 911  if(err) {
 912    err = WSAGetLastError();
 913    if(err != WSAEWOULDBLOCK) {
 914      pss->sockState = Unconnected; /* reset */
 915      pss->sockError = err;
 916      SIGNAL(pss->connSema);
 917    } else {
 918      /* Connection in progress => Start write watcher */
 919      LOCKSOCKET(pss->mutex, INFINITE);
 920      pss->sockState = WaitingForConnection;
 921      pss->writeWatcherOp = WatchConnect;
 922      SetEvent(pss->hWriteWatcherEvent);
 923      UNLOCKSOCKET(pss->mutex);
 924    }
 925  } else {
 926    /* Connection completed synchronously */
 927    LOCKSOCKET(pss->mutex, INFINITE);
 928    pss->sockState = Connected | SOCK_DATA_WRITABLE;
 929    pss->readWatcherOp = WatchData; /* waiting for data */
 930    SetEvent(pss->hReadWatcherEvent);
 931    SIGNAL(pss->connSema);
 932    SIGNAL(pss->writeSema);
 933    UNLOCKSOCKET(pss->mutex);
 934  }
 935}
 936
 937/*****************************************************************************
 938  sqSocketListenOnPort:
 939	TCP => start listening for incoming connections.
 940	UDP => associate the local port number with the socket.
 941*****************************************************************************/
 942void sqSocketListenOnPort(SocketPtr s, int port)
 943{
 944  int result;
 945  struct sockaddr_in addr;
 946  privateSocketStruct *pss = PSP(s);
 947
 948  if (!SocketValid(s)) return;
 949  /* bind the socket */
 950  ZeroMemory(&addr,sizeof(struct sockaddr_in));
 951  addr.sin_family = AF_INET;
 952  addr.sin_port = htons((short)port);
 953  addr.sin_addr.s_addr = localHostAddress;
 954
 955  result = bind( SOCKET(s), (struct sockaddr*) &addr, sizeof(struct sockaddr_in));
 956  if(result == SOCKET_ERROR) {
 957    pss->sockError = WSAGetLastError();
 958    FAIL();
 959    return;
 960  }
 961  if(UDPSocketType == s->socketType) { /* UDP */
 962    SOCKETSTATE(s) = Connected | SOCK_BOUND_UDP | SOCK_DATA_WRITABLE;
 963  } else { /* TCP */
 964    /* show our willingness to accept a single incoming connection */
 965    result = listen(SOCKET(s), 1);
 966    if(result == SOCKET_ERROR) {
 967      FAIL();
 968    } else {
 969      /* Waiting for accept => Start read watcher */
 970      pss->sockState = WaitingForConnection;
 971      pss->readWatcherOp = WatchAcceptSingle;
 972      SetEvent(pss->hReadWatcherEvent);
 973    }
 974  }
 975}
 976
 977/*****************************************************************************
 978  sqSocketBindToPort: allow binding a socket to a specific port and address
 979*****************************************************************************/
 980void sqSocketBindToPort(SocketPtr s, int addr, int port)
 981{
 982  int result;
 983  struct sockaddr_in inaddr;
 984  privateSocketStruct *pss = PSP(s);
 985
 986  if (!SocketValid(s)) return;
 987
 988  /* bind the socket */
 989  ZeroMemory(&inaddr,sizeof(struct sockaddr_in));
 990  inaddr.sin_family = AF_INET;
 991  inaddr.sin_port = htons((short)port);
 992  inaddr.sin_addr.s_addr = htonl(addr);
 993
 994  result = bind( SOCKET(s), (struct sockaddr*) &inaddr, sizeof(struct sockaddr_in));
 995  if(result == SOCKET_ERROR) {
 996    pss->sockError = WSAGetLastError();
 997    FAIL();
 998    return;
 999  }
1000}
1001
1002
1003/*****************************************************************************
1004  sqSocketListenOnPortBacklogSize:
1005	TCP => start listening for incoming connections.
1006	UDP => Just call sqListenOnPort
1007*****************************************************************************/
1008void sqSocketListenOnPortBacklogSize(SocketPtr s, int port, int backlogSize) {
1009  sqSocketListenOnPortBacklogSizeInterface(s, port, backlogSize, 0);
1010}
1011
1012
1013void sqSocketListenOnPortBacklogSizeInterface(SocketPtr s, int port, int backlogSize, int addr)
1014{
1015  int result;
1016  struct sockaddr_in inaddr;
1017  privateSocketStruct *pss = PSP(s);
1018
1019  if (!SocketValid(s)) return;
1020
1021  if(UDPSocketType == s->socketType) {
1022    sqSocketListenOnPort(s, port);
1023    return;
1024  }
1025
1026  /* bind the socket */
1027  ZeroMemory(&inaddr,sizeof(struct sockaddr_in));
1028  inaddr.sin_family = AF_INET;
1029  inaddr.sin_port = htons((short)port);
1030  inaddr.sin_addr.s_addr = htonl(addr);
1031
1032  result = bind( SOCKET(s), (struct sockaddr*) &inaddr, sizeof(struct sockaddr_in));
1033  if(result == SOCKET_ERROR) {
1034    pss->sockError = WSAGetLastError();
1035    FAIL();
1036    return;
1037  }
1038  /* show our willingness to accept a backlogSize incoming connections */
1039  result = listen(SOCKET(s), backlogSize);
1040  if(result != SOCKET_ERROR) {
1041    LOCKSOCKET(pss->mutex, INFINITE);
1042    /* Waiting for accept => Start read watcher */
1043    pss->sockState = WaitingForConnection;
1044    pss->readWatcherOp = WatchAccept;
1045    SetEvent(pss->hReadWatcherEvent);
1046    UNLOCKSOCKET(pss->mutex);
1047  } else {
1048    pss->sockError = WSAGetLastError();
1049    FAIL();
1050  }
1051}
1052
1053/*****************************************************************************
1054  sqSocketDestroy: Release the resources associated with this socket.
1055                   If a connection is open, it is aborted
1056*****************************************************************************/
1057void sqSocketDestroy(SocketPtr s)
1058{
1059  privateSocketStruct *pss;
1060
1061  if (!SocketValid(s)) return;
1062
1063  pss = s->privateSocketPtr;
1064
1065  /* close the socket if it is open */
1066  if(pss->s) {
1067    sqSocketAbortConnection(s);
1068  }
1069
1070  removeFromList(pss);
1071  s->privateSocketPtr = NULL;
1072
1073  /* Prepare cleanup from threads */
1074  LOCKSOCKET(pss->mutex, INFINITE);
1075  pss->closePending = 2; /* threads are running */
1076  pss->readWatcherOp = 0;
1077  pss->writeWatcherOp = 0;
1078  SetEvent(pss->hReadWatcherEvent);
1079  SetEvent(pss->hWriteWatcherEvent);
1080  UNLOCKSOCKET(pss->mutex);
1081  /* Note: it is important that we guard the SetEvent() above
1082     since the threads are running at higher priority and may
1083     immediately try to clean up once SetEvent() is called.
1084     Locking the socket prevents them until we are finished */
1085}
1086
1087/*****************************************************************************
1088  sqSocketReceiveDataAvailable: Return non-zero if data available
1089*****************************************************************************/
1090int sqSocketReceiveDataAvailable(SocketPtr s)
1091{
1092  int sockState;
1093
1094  if(!SocketValid(s)) return 0;
1095  DBG(s);
1096  sockState = SOCKETSTATE(s);
1097  return (sockState & SOCK_DATA_READABLE) /* e.g., do we have data? */
1098    && ((sockState & SOCK_PUBLIC_MASK) == Connected); /* and are we still connected? */
1099}
1100
1101/*****************************************************************************
1102  sqSocketReceiveDataBufCount:
1103  Receive data into the given buffer. Do not exceed bufSize.
1104  Return the number of bytes actually read.
1105*****************************************************************************/
1106sqInt sqSocketReceiveDataBufCount(SocketPtr s, char *buf, sqInt bufSize)
1107{
1108  privateSocketStruct *pss = PSP(s);
1109  int result;
1110  int addrSize;
1111
1112  if (!SocketValid(s)) return -1;
1113  if(bufSize <= 0) return bufSize;
1114
1115  /* read incoming data */
1116  if(UDPSocketType == pss->sockType) { /* UDP */
1117    addrSize = sizeof(pss->peer);
1118    result = recvfrom(pss->s, buf, bufSize, 0,
1119		      (struct sockaddr*) &pss->peer, &addrSize);
1120  } else { /* TCP */
1121    result = recv(pss->s,buf, bufSize, 0);
1122  }
1123
1124/* printf("Data read (%d) WSAGetLastError (%d)\n", result, WSAGetLastError()); */
1125
1126  /* Guard eventual writes to socket state */
1127  LOCKSOCKET(pss->mutex, INFINITE)
1128
1129  /* Check if something went wrong */
1130  if(result <= 0) {
1131      if(result == 0) {
1132	/* UDP doesn't know "other end closed" state */
1133	if(pss->sockType != UDPSocketType)
1134	  pss->sockState = OtherEndClosed;
1135      } else if(result < 0) {
1136	int err = WSAGetLastError();
1137	if(err != WSAEWOULDBLOCK) {
1138	  /* printf("ERROR: %d\n", err); */
1139	  /* NOTE: We consider all other errors to be fatal, e.g.,
1140	     report them as "other end closed". Looking at the
1141	     WSock documentation this ought to be correct. */
1142	  /* UDP doesn't know "other end closed" state */
1143	  if(pss->sockType != UDPSocketType) {
1144	    pss->sockState = OtherEndClosed;
1145	    SIGNAL(pss->connSema);
1146	  }
1147	  pss->sockError = err;
1148	}
1149	result = 0;
1150      }
1151  }
1152
1153  if(!socketReadable(pss->s)) {
1154    /* no more data to read; wake up read watcher */
1155    pss->sockState &= ~SOCK_DATA_READABLE;
1156    pss->readWatcherOp = WatchData;
1157    SetEvent(pss->hReadWatcherEvent);
1158  }
1159
1160  UNLOCKSOCKET(pss->mutex);
1161  return result;
1162}
1163
1164/*****************************************************************************
1165  sqSocketSendDone: Return non-zero if all data has been sent.
1166*****************************************************************************/
1167sqInt sqSocketSendDone(SocketPtr s)
1168{
1169  int sockState;
1170
1171  if (!SocketValid(s)) return 1;
1172  DBG(s);
1173  sockState = SOCKETSTATE(s);
1174  return (sockState & SOCK_DATA_WRITABLE) /* e.g., everything has been written */
1175    && ((sockState & SOCK_PUBLIC_MASK) == Connected); /* and we are still connected */
1176}
1177
1178/*****************************************************************************
1179  sqSocketSendDataBufCount:
1180  Send bufSize bytes from the data pointed to by buf.
1181  Return the number of bytes sent.
1182*****************************************************************************/
1183sqInt sqSocketSendDataBufCount(SocketPtr s, char *buf, sqInt bufSize)
1184{
1185  privateSocketStruct *pss = PSP(s);
1186  int result;
1187  int addrSize;
1188
1189  if (!SocketValid(s)) return -1;
1190  /***NOTE***NOTE***NOTE***NOTE***NOTE***
1191      It's not clear if we should just bail out here
1192      if the buffer size is zero. It's consistent with
1193      what the Unix VM does but I think we should actually
1194      fail here....
1195  **************************************/
1196  if(!bufSize) return 0;
1197
1198  /* send actual data */
1199  if(UDPSocketType == pss->sockType) { /* UDP */
1200    addrSize = sizeof(pss->peer);
1201    result = sendto(pss->s, buf, bufSize, 0,
1202		    (struct sockaddr*) &pss->peer, addrSize);
1203  } else {
1204    result = send(pss->s, buf, bufSize, 0);
1205  }
1206/* printf("Data sent (%d) WSAGetLastError (%d)\n", result, WSAGetLastError()); */
1207
1208  /* Guard eventual writes to socket state */
1209  LOCKSOCKET(pss->mutex, INFINITE)
1210
1211  /* Check if something went wrong */
1212  if(result <= 0) {
1213      if(result == 0) {
1214	/* UDP doesn't know "other end closed" state */
1215	if(pss->sockType != UDPSocketType)
1216	  pss->sockState = OtherEndClosed;
1217      } else {
1218	int err = WSAGetLastError();
1219	if(err != WSAEWOULDBLOCK) {
1220	  /* printf("ERROR: %d\n", err); */
1221	  /* NOTE: We consider all other errors to be fatal, e.g.,
1222	     report them as "other end closed". Looking at the
1223	     WSock documentation this ought to be correct. */
1224	  /* UDP doesn't know "other end closed" state */
1225	  if(pss->sockType != UDPSocketType) {
1226	    pss->sockState = OtherEndClosed;
1227	    SIGNAL(pss->connSema);
1228	  }
1229	  pss->sockError = err;
1230	}
1231	result = 0;
1232      }
1233  }
1234
1235  if(!socketWritable(pss->s)) {
1236    /* can't write more data; wake up write watcher */
1237    pss->sockState &= ~SOCK_DATA_WRITABLE;
1238    pss->writeWatcherOp = WatchData;
1239    SetEvent(pss->hWriteWatcherEvent);
1240  }
1241
1242  UNLOCKSOCKET(pss->mutex);
1243  return result;
1244}
1245
1246/*****************************************************************************
1247  sqSocketError: Return any error on the socket.
1248*****************************************************************************/
1249int sqSocketError(SocketPtr s)
1250{
1251  if(!SocketValid(s)) return -1;
1252  return SOCKETERROR(s);
1253}
1254
1255/*****************************************************************************
1256  sqSocketLocalAddress: Return the address of the socket on this host.
1257*****************************************************************************/
1258int sqSocketLocalAddress(SocketPtr s)
1259{
1260  struct sockaddr_in sin;
1261  int sinSize = sizeof(sin);
1262
1263  if (!SocketValid(s)) return -1;
1264  if(getsockname(SOCKET(s), (struct sockaddr *)&sin, &sinSize)) return 0; /* failed */
1265  if(sin.sin_family != AF_INET) return 0; /* can't handle other than internet addresses */
1266  return ntohl(sin.sin_addr.s_addr);
1267}
1268
1269/*****************************************************************************
1270  sqSocketLocalPort: Return the port of the socket on this host
1271*****************************************************************************/
1272int sqSocketLocalPort(SocketPtr s)
1273{
1274  struct sockaddr_in sin;
1275  int sinSize = sizeof(sin);
1276
1277  if (!SocketValid(s)) return -1;
1278  if(getsockname(SOCKET(s), (struct sockaddr *)&sin, &sinSize)) return 0; /* failed */
1279  if(sin.sin_family != AF_INET) return 0; /* can't handle other than internet addresses */
1280  return ntohs(sin.sin_port);
1281}
1282
1283/*****************************************************************************
1284  sqSocketRemoteAddress: Return the address of the socket on the remote host
1285*****************************************************************************/
1286int sqSocketRemoteAddress(SocketPtr s)
1287{
1288  struct sockaddr_in sin;
1289  int sinSize = sizeof(sin);
1290
1291  if (!SocketValid(s)) return -1;
1292  if(TCPSocketType == s->socketType) { /* TCP */
1293    if(getpeername(SOCKET(s), (struct sockaddr *)&sin, &sinSize)) return 0; /* failed */
1294  } else { /* UDP */
1295    MoveMemory(&sin,&(PSP(s)->peer),sinSize);
1296  }
1297  if(sin.sin_family != AF_INET) return 0; /* can't handle other than internet addresses */
1298  return ntohl(sin.sin_addr.s_addr);
1299}
1300
1301/*****************************************************************************
1302  sqSocketRemotePort: Return the port of the socket on the remote host
1303*****************************************************************************/
1304int sqSocketRemotePort(SocketPtr s)
1305{
1306  struct sockaddr_in sin;
1307  int sinSize = sizeof(sin);
1308
1309  if (!SocketValid(s)) return -1;
1310  if(TCPSocketType == s->socketType) { /* TCP */
1311    if(getpeername(SOCKET(s), (struct sockaddr *)&sin, &sinSize)) return 0; /* failed */
1312  } else { /* UDP */
1313    MoveMemory(&sin,&(PSP(s)->peer),sinSize);
1314  }
1315  if(sin.sin_family != AF_INET) return 0; /* can't handle other than internet addresses */
1316  return ntohs(sin.sin_port);
1317}
1318
1319
1320/*****************************************************************************
1321  sqSocketSetReusable: set the SO_REUSEADDR option for the socket.
1322*****************************************************************************/
1323void sqSocketSetReusable (SocketPtr s)
1324{
1325  size_t bufSize;
1326  unsigned char   buf[4];
1327  int err;
1328
1329  if (!SocketValid(s)) return;
1330  *(int *)buf = 1;
1331  bufSize = 4;
1332  err = setsockopt(SOCKET(s), SOL_SOCKET, SO_REUSEADDR, buf, bufSize);
1333  if(err < 0) interpreterProxy->success(false);
1334}
1335
1336/*****************************************************************************
1337 *****                     New Socket Functions                          *****
1338 *****************************************************************************/
1339/*****************************************************************************
1340  sqSocketCreateNetTypeSocketTypeRecvBytesSendBytesSemaID:
1341  Create a socket for the given netType (which is always internet here)
1342  a given socketType (UDP or TCP) appropriate buffer size (being ignored ;-)
1343  and a semaphore to signal upon changes in the socket state.
1344*****************************************************************************/
1345void sqSocketCreateNetTypeSocketTypeRecvBytesSendBytesSemaID(
1346            SocketPtr s, int netType, int socketType,
1347            int recvBufSize, int sendBufSize, int semaIndex)
1348{
1349  sqSocketCreateNetTypeSocketTypeRecvBytesSendBytesSemaIDReadSemaIDWriteSemaID(s, netType, socketType, recvBufSize, sendBufSize, semaIndex, semaIndex, semaIndex);
1350}
1351
1352void	sqSocketCreateNetTypeSocketTypeRecvBytesSendBytesSemaIDReadSemaIDWriteSemaID(SocketPtr s, int netType, int socketType, int recvBufSize, int sendBufSize, int connSemaIndex, int readSemaIndex, int writeSemaIndex)
1353{
1354
1355  SOCKET newSocket;
1356  privateSocketStruct *pss;
1357
1358  s->sessionID = 0;
1359  /* perform internal initialization */
1360  if(socketType == TCPSocketType)
1361    newSocket = socket(AF_INET,SOCK_STREAM, 0);
1362  else if(socketType == UDPSocketType)
1363    newSocket = socket(AF_INET, SOCK_DGRAM, 0);
1364  else { FAIL(); return; }
1365  if(newSocket == INVALID_SOCKET) {
1366    FAIL();
1367    return;
1368  }
1369  /* Allow the re-use of the current port */
1370  setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR, (char*) &one, sizeof(one));
1371  /* Disable TCP delays */
1372  ioctlsocket(newSocket,FIONBIO,&one);
1373
1374  /* initialize private socket structure */
1375  pss = (privateSocketStruct*) calloc(1,sizeof(privateSocketStruct));
1376  pss->s = newSocket;
1377  pss->sockType = socketType;
1378  pss->connSema = connSemaIndex;
1379  pss->readSema = readSemaIndex;
1380  pss->writeSema = writeSemaIndex;
1381
1382  /* UDP sockets are born "connected" */
1383  if(UDPSocketType == socketType) {
1384    pss->sockState = Connected | SOCK_DATA_WRITABLE;
1385  } else {/* TCP */
1386    pss->sockState = Unconnected;
1387  }
1388  pss->sockError= 0;
1389
1390  /* initial UDP peer := wildcard */
1391  ZeroMemory(&pss->peer, sizeof(pss->peer));
1392  pss->peer.sin_family= AF_INET;
1393  pss->peer.sin_port= htons((short)0);;
1394  pss->peer.sin_addr.s_addr= INADDR_ANY;
1395
1396  /* fill the SQSocket */
1397  s->sessionID = thisNetSession;
1398  s->socketType = socketType;
1399  s->privateSocketPtr = pss;
1400
1401  /* Create a new mutex object for synchronized access */
1402  pss->mutex = CreateMutex(NULL, 0,NULL);
1403  if(!pss->mutex) { FAIL(); return; }
1404
1405  /* Install the socket into the socket list */
1406  pss->next = firstSocket;
1407  firstSocket = pss;
1408
1409  /* Setup the watchers */
1410  if(UDPSocketType == socketType) {
1411    /* Since UDP sockets are always connected */
1412    pss->readWatcherOp = pss->writeWatcherOp = WatchData;
1413  }
1414  if(!createWatcherThreads(pss)) {
1415    /* note: necessary cleanup is done from within createWatcherThreads */
1416    s->privateSocketPtr = NULL; /* declare invalid */
1417    FAIL();
1418  }
1419}
1420
1421
1422/*****************************************************************************
1423  sqSocketAcceptFromRecvBytesSendBytesSemaID:
1424  Create a new socket by accepting an incoming connection from the source socket.
1425*****************************************************************************/
1426
1427void sqSocketAcceptFromRecvBytesSendBytesSemaID(
1428            SocketPtr s, SocketPtr serverSocket,
1429            int recvBufSize, int sendBufSize, int semaIndex)
1430{
1431  sqSocketAcceptFromRecvBytesSendBytesSemaIDReadSemaIDWriteSemaID(s, serverSocket, recvBufSize, sendBufSize, semaIndex, semaIndex, semaIndex);
1432}
1433
1434void sqSocketAcceptFromRecvBytesSendBytesSemaIDReadSemaIDWriteSemaID(SocketPtr s, SocketPtr serverSocket, int recvBufSize, int sendBufSize, int connSemaIndex, int readSemaIndex, int writeSemaIndex)
1435{
1436  acceptedSocketStruct *accepted;
1437  privateSocketStruct *pss;
1438
1439  /* Lock the server socket and retrieve the last accepted connection */
1440  pss = PSP(serverSocket); /* temporarily */
1441
1442  /* Guard modification in server socket state */
1443  LOCKSOCKET(pss->mutex, INFINITE);
1444  accepted = pss->accepted;
1445  if(accepted) {
1446    pss->accepted = accepted->next;
1447    if(!pss->accepted) {
1448      /* No more connections; go back to waiting state and start watcher */
1449      pss->sockState = WaitingForConnection;
1450      pss->readWatcherOp = WatchAccept;
1451      SetEvent(pss->hReadWatcherEvent);
1452    }
1453  }
1454  UNLOCKSOCKET(pss->mutex);
1455
1456  if(!accepted) { /* something was wrong here */
1457    FAIL();
1458    return;
1459  }
1460  if(accepted->s == INVALID_SOCKET) {
1461    FAIL();
1462    return;
1463  }
1464  /* private socket structure */
1465  pss = (privateSocketStruct*) calloc(1,sizeof(privateSocketStruct));
1466  pss->s = accepted->s;
1467  pss->sockType = PSP(serverSocket)->sockType;
1468  pss->connSema = connSemaIndex;
1469  pss->readSema = readSemaIndex;
1470  pss->writeSema = writeSemaIndex;
1471  pss->sockState= Connected | SOCK_DATA_WRITABLE;
1472  pss->sockError= 0;
1473  MoveMemory(&pss->peer, &accepted->peer, sizeof(struct sockaddr_in));
1474
1475  /* fill the SQSocket */
1476  s->sessionID = thisNetSession;
1477  s->socketType = pss->sockType;
1478  s->privateSocketPtr = pss;
1479
1480  /* Make the socket non-blocking */
1481  ioctlsocket(SOCKET(s),FIONBIO,&one);
1482
1483  /* Create a new mutex object for synchronized access */
1484  pss->mutex = CreateMutex(NULL, 0,NULL);
1485  if(!pss->mutex) { FAIL(); return; }
1486
1487  /* Install the socket into the socket list */
1488  pss->next = firstSocket;
1489  firstSocket = pss;
1490
1491  /* Setup the watchers */
1492  pss->readWatcherOp = pss->writeWatcherOp = WatchData;
1493
1494  if(!createWatcherThreads(pss)) {
1495    /* note: necessary cleanup is done from within createWatcherThreads */
1496    s->privateSocketPtr = NULL; /* declare invalid */
1497    FAIL();
1498  }
1499
1500  /* Cleanup */
1501  GlobalFree(GlobalHandle(accepted));
1502}
1503
1504sqInt sqSocketReceiveUDPDataBufCountaddressportmoreFlag(SocketPtr s, char *buf, sqInt bufSize,  sqInt *address,  sqInt *port, sqInt *moreFlag)
1505{
1506  int nRead;
1507  if(UDPSocketType != s->socketType)
1508    return interpreterProxy->primitiveFail();
1509  /* bind UDP socket*/
1510  sqSocketConnectToPort(s, *address, *port);
1511  if(interpreterProxy->failed()) return 0;
1512  /* receive data */
1513  nRead = sqSocketReceiveDataBufCount(s, buf, bufSize);
1514  if(nRead >= 0) {
1515    *address= ntohl(ADDRESS(s)->sin_addr.s_addr);
1516    *port= ntohs(ADDRESS(s)->sin_port);
1517  }
1518  return nRead;
1519}
1520
1521sqInt	sqSockettoHostportSendDataBufCount(SocketPtr s, sqInt address, sqInt port, char *buf, sqInt bufSize)
1522{
1523  if(UDPSocketType != s->socketType)
1524    return interpreterProxy->primitiveFail();
1525  /* bind UDP socket */
1526  sqSocketConnectToPort(s, address, port);
1527  if(interpreterProxy->failed()) return 0;
1528  /* send data */
1529  return sqSocketSendDataBufCount(s, buf, bufSize);
1530}
1531
1532/*** socket options ***/
1533
1534
1535/* NOTE: we only support the portable options here as an incentive for
1536         people to write portable Squeak programs.  If you need
1537         non-portable socket options then go write yourself a plugin
1538         specific to your platform.  This decision is unilateral and
1539         non-negotiable.  - ikp
1540   NOTE: we only support the integer-valued options because the code
1541	 in SocketPlugin doesn't seem able to cope with the others.
1542	 (Personally I think that things like SO_SNDTIMEO et al would
1543	 by far more interesting than the majority of things on this
1544	 list, but there you go...)
1545   NOTE: if your build fails because of a missing option in this list,
1546	 simply DELETE THE OPTION (or comment it out) and then send
1547	 me mail (andreas.raab@gmx.de) to let me know about it.
1548*/
1549
1550typedef struct {
1551  char *name;		/* name as known to Squeak */
1552  int   optLevel;	/* protocol level */
1553  int   optName;	/* name as known to the network layer */
1554  int   optType;        /* type of option */
1555} socketOption;
1556
1557#ifndef SOL_IP
1558# define SOL_IP IPPROTO_IP
1559#endif
1560
1561#ifndef SOL_UDP
1562# define SOL_UDP IPPROTO_UDP
1563#endif
1564
1565#ifndef SOL_TCP
1566# define SOL_TCP IPPROTO_TCP
1567#endif
1568
1569static socketOption socketOptions[]= {
1570  { "SO_DEBUG",			SOL_SOCKET,	SO_DEBUG,          1 },
1571  { "SO_REUSEADDR",		SOL_SOCKET,	SO_REUSEADDR,      1 },
1572  { "SO_DONTROUTE",		SOL_SOCKET,	SO_DONTROUTE,      1 },
1573  { "SO_BROADCAST",		SOL_SOCKET,	SO_BROADCAST,      1 },
1574  { "SO_SNDBUF",		SOL_SOCKET,	SO_SNDBUF,         1 },
1575  { "SO_RCVBUF",		SOL_SOCKET,	SO_RCVBUF,         1 },
1576  { "SO_KEEPALIVE",		SOL_SOCKET,	SO_KEEPALIVE,      1 },
1577  { "SO_OOBINLINE",		SOL_SOCKET,	SO_OOBINLINE,      1 },
1578  { "SO_LINGER",		SOL_SOCKET,	SO_LINGER,         1 },
1579#if defined(IP_MULTICAST_IF)
1580  { "IP_MULTICAST_IF",		SOL_IP,		IP_MULTICAST_IF,   1 },
1581#endif
1582#if defined(IP_MULTICAST_TTL)
1583  { "IP_MULTICAST_TTL",		SOL_IP,		IP_MULTICAST_TTL,  1 },
1584#endif
1585#if defined(IP_MULTICAST_LOOP)
1586  { "IP_MULTICAST_LOOP",	SOL_IP,		IP_MULTICAST_LOOP, 1 },
1587#endif
1588  { "TCP_NODELAY",		SOL_TCP,	TCP_NODELAY,       1 },
1589  { "SO_RCVLOWAT",		SOL_SOCKET,	SO_RCVLOWAT,       1 },
1590  { "SO_SNDLOWAT",		SOL_SOCKET,	SO_SNDLOWAT,       1 },
1591
1592  /* multicast support */
1593#if defined(IP_ADD_MEMBERSHIP)
1594  {"IP_ADD_MEMBERSHIP",         SOL_IP,         IP_ADD_MEMBERSHIP,  100},
1595#endif
1596#if defined(IP_DROP_MEMBERSHIP)
1597  {"IP_DROP_MEMBERSHIP",        SOL_IP,         IP_DROP_MEMBERSHIP, 100},
1598#endif
1599
1600#if 0
1601  /* WSAIoctl() support */
1602  {"SIO_GET_BROADCAST_ADDRESS",	0,	SIO_GET_BROADCAST_ADDRESS, 200},
1603#endif
1604  { (char *)0,			0,		0,                  0 }
1605};
1606
1607
1608static socketOption *findOption(char *name, size_t nameSize) {
1609  socketOption *opt= 0;
1610  char buf[128];
1611  if(nameSize > 127) return NULL;
1612  strncpy(buf, name, nameSize);
1613  buf[nameSize] = 0;
1614  for (opt= socketOptions; opt->name != 0; ++opt)
1615    if (!strcmp(buf, opt->name))
1616      return opt;
1617  return NULL;
1618}
1619
1620
1621/*
1622  set the given option for the socket.
1623*/
1624sqInt sqSocketSetOptionsoptionNameStartoptionNameSizeoptionValueStartoptionValueSizereturnedValue
1625    (SocketPtr s,char *optionName, sqInt optionNameSize,
1626     char *optionValueIndex, sqInt optionValueSize, sqInt *result)
1627{
1628  char optionValue[256];
1629  size_t bufSize;
1630  unsigned char   buf[256];
1631
1632  if (SocketValid(s)) {
1633    socketOption *opt= findOption(optionName, (size_t)optionNameSize);
1634
1635    if (opt == 0) goto barf;
1636    if(optionValueSize >= sizeof(optionValue)) goto barf;
1637
1638    memcpy(optionValue, optionValueIndex, optionValueSize);
1639    optionValue[optionValueSize] = 0;
1640
1641    if(opt->optType == 1) {
1642      /* integer options */
1643      ((int*)buf)[0] = atoi(optionValue);
1644      bufSize = sizeof(int);
1645      /* printf("optionValue: %d (%s)\n", ((int*)buf)[0], optionValue); */
1646    } else if(opt->optType == 100) {
1647      /* multicast options, taking one or two IP addresses, e.g.,
1648         '1.2.3.4|5.6.7.8' specifies multicast group + interface
1649	 '1.2.3.4' specifies only multicast group (interface is INADDR_ANY)
1650      */
1651      if(optionValueSize == 4) {
1652	((int*)buf)[0] = ((int*)optionValue)[0];
1653	((int*)buf)[1] = INADDR_ANY;
1654      } else if(optionValueSize == 8) {
1655	((int*)buf)[0] = ((int*)optionValue)[0];
1656	((int*)buf)[1] = ((int*)optionValue)[1];
1657      } else {
1658	goto barf;
1659      }
1660      bufSize = 8;
1661    } else {
1662      goto barf;
1663    }
1664    {
1665      int err;
1666      err = setsockopt(SOCKET(s), opt->optLevel, opt->optName,buf, bufSize);
1667      /* printf("setsockopt(): %d\n", err); */
1668      if(err < 0) goto barf;
1669    }
1670    /* it isn't clear what we're supposed to return here, since
1671       setsockopt isn't supposed to have any value-result parameters
1672       (go grok that `const' on the buffer argument if you don't
1673       believe me).  the image says "the result of the negotiated
1674       value".  what the fuck is there to negotiate?  either
1675       setsockopt sets the value or it barfs.  and i'm not about to go
1676       calling getsockopt just to see if the value got changed or not
1677       (the image should send getOption: to the Socket if it really
1678       wants to know).  if the following is wrong then I could
1679       probably care (a lot) less...  fix the logic in the image and
1680       then maybe i'll care about fixing the logic in here.  (i know
1681       that isn't very helpful, but it's 05:47 in the morning and i'm
1682       severely grumpy after fixing several very unpleasant bugs that
1683       somebody introduced into this file while i wasn't looking.)  */
1684    *result= 0;
1685    return 0;
1686  }
1687 barf:
1688  interpreterProxy->success(false);
1689  return false;
1690}
1691
1692
1693/* query the socket for the given option.  */
1694sqInt sqSocketGetOptionsoptionNameStartoptionNameSizereturnedValue
1695    (SocketPtr s,char *optionName, sqInt optionNameSize, sqInt *result)
1696{
1697  int optval;
1698  size_t len;
1699  socketOption *opt;
1700  if (!SocketValid(s)) goto barf;
1701  opt= findOption(optionName, (size_t)optionNameSize);
1702  if (opt == 0) {
1703    /* printf("option not found\n"); */
1704    goto barf;
1705  }
1706  if (opt->optType == 1) {
1707    len= sizeof(optval);
1708    if ((getsockopt(SOCKET(s), opt->optLevel, opt->optName,
1709		    (void*)&optval,&len)) < 0)
1710      {
1711	/* printf("getsockopt() returned < 0\n"); */
1712	goto barf;
1713      }
1714    if (len != sizeof(optval)) {
1715      /* printf("len != sizeof(optval)"); */
1716      goto barf;
1717    }
1718    *result= optval;
1719    return 0;
1720  }
1721
1722#if 0
1723  if(opt->optType == 200) {
1724    int sz, err;
1725    struct sockaddr_in addr;
1726    /* WSAIoctl() */
1727    if(opt->optName != SIO_GET_BROADCAST_ADDRESS) goto barf;
1728    err = WSAIoctl(SOCKET(s),
1729		   SIO_GET_BROADCAST_ADDRESS,
1730		   NULL, 0,
1731		   &addr, sizeof(addr),
1732		   &sz,
1733		   NULL, NULL);
1734    if(err) {
1735      printf("WSAIoctl error: %d (WSAGetLastError=%d)\n",
1736	     err, WSAGetLastError());
1737      goto barf;
1738    }
1739    if(sz != sizeof(addr)) {
1740      printf("WSAIoctl returned %d instead of %d\n", sz, sizeof(addr));
1741      goto barf;
1742    }
1743    *result = ntohl(addr.sin_addr.s_addr);
1744    return 0;
1745  }
1746#endif
1747
1748 barf:
1749  interpreterProxy->success(false);
1750  return errno;
1751}
1752
1753/*****************************************************************************
1754 *****                     Resolver Functions                            *****
1755 *****************************************************************************
1756 NOTE: Resolver functions don't need synchronization - there is only one
1757       resolver process running at a time.
1758 *****************************************************************************/
1759
1760static char lastName[MAXHOSTNAMELEN+1];
1761static int lastAddr;
1762
1763static int lastError;
1764static HANDLE asyncLookupHandle = 0;
1765static char hostentBuffer[MAXGETHOSTSTRUCT];
1766
1767static DWORD WINAPI sqGetHostByAddr(int netAddress);
1768static DWORD WINAPI sqGetHostByName(char *hostName);
1769
1770/*****************************************************************************
1771  Convenience functions. We may use them later.
1772*****************************************************************************/
1773static char *
1774nameOf(int netAddress)
1775{ u_long nAddr;
1776  struct hostent *he;
1777
1778  lastError = 0;
1779  nAddr = htonl(netAddress);
1780  he = gethostbyaddr((char*)&nAddr,sizeof(nAddr),AF_INET);
1781  if(he) return he->h_name;
1782  lastError = h_errno;
1783  return "";
1784}
1785
1786static int
1787addressOf(char *hostName)
1788{ struct hostent *he;
1789
1790  lastError = 0;
1791  he = gethostbyname(hostName);
1792  if(he) return ntohl(*(long*)(he->h_addr_list[0]));
1793  lastError = h_errno;
1794  return 0;
1795}
1796
1797/*****************************************************************************
1798  sqResolverAbort: Abort a pending DNS lookup
1799*****************************************************************************/
1800void sqResolverAbort(void)
1801{
1802  if(!asyncLookupHandle) return; /* lookup already finished */
1803  TerminateThread(asyncLookupHandle, 0);
1804  /* forget last name */
1805  lastName[0] = 0;
1806  /* indicate finished operation */
1807  asyncLookupHandle = 0;
1808}
1809
1810/*****************************************************************************
1811  sqResolverAddrLookupResult: Return the result of the last name lookup
1812*****************************************************************************/
1813void sqResolverAddrLookupResult(char *nameForAddress, int nameSize)
1814{
1815  MoveMemory(nameForAddress, lastName, nameSize);
1816}
1817
1818/*****************************************************************************
1819  sqResolverAddrLookupResult: Return sizeof(result) of the last name lookup
1820*****************************************************************************/
1821int sqResolverAddrLookupResultSize(void)
1822{
1823  return strlen(lastName);
1824}
1825
1826/*****************************************************************************
1827  sqResolverError: Return the last error of a DNS lookup
1828*****************************************************************************/
1829int sqResolverError(void)
1830{
1831  return lastError;
1832}
1833
1834/*****************************************************************************
1835  sqResolverLocalAddress: Return the address of the local host
1836*****************************************************************************/
1837int sqResolverLocalAddress(void)
1838{
1839  return addressOf(localHostName);
1840}
1841
1842/*****************************************************************************
1843  sqResolverNameLookupResult: Return the address of the last DNS lookup
1844*****************************************************************************/
1845int sqResolverNameLookupResult(void)
1846{
1847  return lastAddr;
1848}
1849
1850/*****************************************************************************
1851  sqResolverStartAddrLookup: Look up the name to a given address
1852*****************************************************************************/
1853void sqResolverStartAddrLookup(int address)
1854{
1855  DWORD id;
1856  if(asyncLookupHandle) return; /* lookup in progress */
1857  asyncLookupHandle =
1858    CreateThread(NULL,                    /* No security descriptor */
1859                 0,                       /* default stack size     */
1860                 (LPTHREAD_START_ROUTINE) &sqGetHostByAddr, /* what to do */
1861                 (LPVOID) address,        /* parameter for thread   */
1862                 CREATE_SUSPENDED,        /* creation parameter -- create suspended so we can check the return value */
1863                 &id);                    /* return value for thread id */
1864  if(!asyncLookupHandle)
1865    printLastError(TEXT("CreateThread() failed"));
1866  /* lookups run with normal priority */
1867  if(!SetThreadPriority(asyncLookupHandle, THREAD_PRIORITY_NORMAL))
1868    printLastError(TEXT("SetThreadPriority() failed"));
1869  if(!ResumeThread(asyncLookupHandle))
1870    printLastError(TEXT("ResumeThread() failed"));
1871}
1872
1873/*****************************************************************************
1874  sqResolverStartNameLookup: Look up the address to a given host name
1875*****************************************************************************/
1876void sqResolverStartNameLookup(char *hostName, int nameSize)
1877{ int len;
1878  DWORD id;
1879
1880  if(asyncLookupHandle) return; /* lookup in progress */
1881  len = nameSize < MAXHOSTNAMELEN ? nameSize : MAXHOSTNAMELEN;
1882  if((lastError == 0) &&
1883     (strlen(lastName) == len) &&
1884     (strncmp(hostName, lastName, len) == 0)) {
1885	  /* same as last, no point in looking it up */
1886	  SIGNAL(resolverSemaphoreIndex);
1887	  return;
1888  }
1889  MoveMemory(lastName,hostName, len);
1890  lastName[len] = 0;
1891  lastError = 0;
1892  asyncLookupHandle =
1893    CreateThread(NULL,                    /* No security descriptor */
1894                 0,                       /* default stack size     */
1895                 (LPTHREAD_START_ROUTINE) &sqGetHostByName, /* what to do */
1896                 (LPVOID) lastName,       /* parameter for thread   */
1897                 CREATE_SUSPENDED,        /* creation parameter -- create suspended so we can check the return value */
1898                 &id);                    /* return value for thread id */
1899  if(!asyncLookupHandle)
1900    printLastError(TEXT("CreateThread() failed"));
1901  /* lookups run with normal priority */
1902  if(!SetThreadPriority(asyncLookupHandle, THREAD_PRIORITY_NORMAL))
1903    printLastError(TEXT("SetThreadPriority() failed"));
1904  if(!ResumeThread(asyncLookupHandle))
1905    printLastError(TEXT("ResumeThread() failed"));
1906}
1907
1908/*****************************************************************************
1909  sqResolverStatus: Return resolver status
1910*****************************************************************************/
1911int sqResolverStatus(void)
1912{
1913  if(!thisNetSession)
1914    return RESOLVER_UNINITIALIZED; /* not initialized */
1915
1916  if(asyncLookupHandle)
1917    return RESOLVER_BUSY; /* lookup in progress */
1918
1919  if(lastError)
1920    return RESOLVER_ERROR; /* resolver idle but last request failed */
1921
1922  return RESOLVER_SUCCESS; /* ready and idle */
1923}
1924
1925
1926
1927/*****************************************************************************
1928 sqGetHostByAddr: Perform a threaded gethostbyaddr()
1929*****************************************************************************/
1930DWORD WINAPI sqGetHostByAddr(int netAddress)
1931{ struct hostent *he;
1932  u_long nAddr;
1933
1934  nAddr = htonl(netAddress);
1935  he = gethostbyaddr((char*)&nAddr, 4, PF_INET);
1936  if(he)
1937    {
1938      strcpy(lastName,he->h_name);
1939      lastAddr = ntohl(*(long*)(he->h_addr_list[0]));
1940      lastError = 0;
1941    }
1942  else
1943    lastError = WSAGetLastError();
1944  asyncLookupHandle = 0;
1945  SIGNAL(resolverSemaphoreIndex);
1946  ExitThread(0);
1947  return 1;
1948}
1949
1950
1951/*****************************************************************************
1952 sqGetHostByName: Perform a threaded gethostbyname()
1953*****************************************************************************/
1954DWORD WINAPI sqGetHostByName(char *hostName)
1955{ struct hostent *he;
1956
1957  he = gethostbyname(hostName);
1958  if(he)
1959    {
1960      strcpy(lastName,he->h_name);
1961      lastAddr = ntohl(*(long*)(he->h_addr_list[0]));
1962      lastError = 0;
1963    }
1964  else
1965    lastError = WSAGetLastError();
1966  asyncLookupHandle = 0;
1967  SIGNAL(resolverSemaphoreIndex);
1968  ExitThread(0);
1969  return 1;
1970}
1971
1972/***** socket module initializers *****/
1973int socketInit(void)
1974{
1975	thisNetSession = 0;
1976	return 1;
1977}
1978
1979int socketShutdown(void)
1980{
1981	sqNetworkShutdown();
1982	sqResolverAbort();
1983	return 1;
1984}
1985
1986#endif /* NO_NETWORK */