PageRenderTime 64ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

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