/vm/platforms/win32/plugins/SocketPlugin/sqWin32NewNet.c
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 */