PageRenderTime 58ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/brlcad/branches/dmtogl/src/other/tcl/win/tclWinSock.c

https://bitbucket.org/vrrm/brl-cad-copy-for-fast-history-browsing-in-git
C | 2605 lines | 1305 code | 322 blank | 978 comment | 294 complexity | 81425ed018c4642916d316a734d01580 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, LGPL-2.1, Apache-2.0, AGPL-3.0, LGPL-3.0, GPL-3.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, 0BSD, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * tclWinSock.c --
  3. *
  4. * This file contains Windows-specific socket related code.
  5. *
  6. * Copyright (c) 1995-1997 Sun Microsystems, Inc.
  7. *
  8. * See the file "license.terms" for information on usage and redistribution of
  9. * this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10. *
  11. * RCS: @(#) $Id$
  12. */
  13. #include "tclWinInt.h"
  14. #ifdef _MSC_VER
  15. # pragma comment (lib, "ws2_32")
  16. #endif
  17. /*
  18. * Support for control over sockets' KEEPALIVE and NODELAY behavior is
  19. * currently disabled.
  20. */
  21. #undef TCL_FEATURE_KEEPALIVE_NAGLE
  22. /*
  23. * Make sure to remove the redirection defines set in tclWinPort.h that is in
  24. * use in other sections of the core, except for us.
  25. */
  26. #undef getservbyname
  27. #undef getsockopt
  28. #undef ntohs
  29. #undef setsockopt
  30. /*
  31. * The following variable is used to tell whether this module has been
  32. * initialized. If 1, initialization of sockets was successful, if -1 then
  33. * socket initialization failed (WSAStartup failed).
  34. */
  35. static int initialized = 0;
  36. TCL_DECLARE_MUTEX(socketMutex)
  37. /*
  38. * The following variable holds the network name of this host.
  39. */
  40. static TclInitProcessGlobalValueProc InitializeHostName;
  41. static ProcessGlobalValue hostName = {
  42. 0, 0, NULL, NULL, InitializeHostName, NULL, NULL
  43. };
  44. /*
  45. * The following defines declare the messages used on socket windows.
  46. */
  47. #define SOCKET_MESSAGE WM_USER+1
  48. #define SOCKET_SELECT WM_USER+2
  49. #define SOCKET_TERMINATE WM_USER+3
  50. #define SELECT TRUE
  51. #define UNSELECT FALSE
  52. /*
  53. * The following structure is used to store the data associated with each
  54. * socket.
  55. */
  56. typedef struct SocketInfo {
  57. Tcl_Channel channel; /* Channel associated with this socket. */
  58. SOCKET socket; /* Windows SOCKET handle. */
  59. int flags; /* Bit field comprised of the flags described
  60. * below. */
  61. int watchEvents; /* OR'ed combination of FD_READ, FD_WRITE,
  62. * FD_CLOSE, FD_ACCEPT and FD_CONNECT that
  63. * indicate which events are interesting. */
  64. int readyEvents; /* OR'ed combination of FD_READ, FD_WRITE,
  65. * FD_CLOSE, FD_ACCEPT and FD_CONNECT that
  66. * indicate which events have occurred. */
  67. int selectEvents; /* OR'ed combination of FD_READ, FD_WRITE,
  68. * FD_CLOSE, FD_ACCEPT and FD_CONNECT that
  69. * indicate which events are currently being
  70. * selected. */
  71. int acceptEventCount; /* Count of the current number of FD_ACCEPTs
  72. * that have arrived and not yet processed. */
  73. Tcl_TcpAcceptProc *acceptProc;
  74. /* Proc to call on accept. */
  75. ClientData acceptProcData; /* The data for the accept proc. */
  76. int lastError; /* Error code from last message. */
  77. struct SocketInfo *nextPtr; /* The next socket on the per-thread socket
  78. * list. */
  79. } SocketInfo;
  80. /*
  81. * The following structure is what is added to the Tcl event queue when a
  82. * socket event occurs.
  83. */
  84. typedef struct SocketEvent {
  85. Tcl_Event header; /* Information that is standard for all
  86. * events. */
  87. SOCKET socket; /* Socket descriptor that is ready. Used to
  88. * find the SocketInfo structure for the file
  89. * (can't point directly to the SocketInfo
  90. * structure because it could go away while
  91. * the event is queued). */
  92. } SocketEvent;
  93. /*
  94. * This defines the minimum buffersize maintained by the kernel.
  95. */
  96. #define TCP_BUFFER_SIZE 4096
  97. /*
  98. * The following macros may be used to set the flags field of a SocketInfo
  99. * structure.
  100. */
  101. #define SOCKET_ASYNC (1<<0) /* The socket is in blocking mode. */
  102. #define SOCKET_EOF (1<<1) /* A zero read happened on the
  103. * socket. */
  104. #define SOCKET_ASYNC_CONNECT (1<<2) /* This socket uses async connect. */
  105. #define SOCKET_PENDING (1<<3) /* A message has been sent for this
  106. * socket */
  107. typedef struct ThreadSpecificData {
  108. HWND hwnd; /* Handle to window for socket messages. */
  109. HANDLE socketThread; /* Thread handling the window */
  110. Tcl_ThreadId threadId; /* Parent thread. */
  111. HANDLE readyEvent; /* Event indicating that a socket event is
  112. * ready. Also used to indicate that the
  113. * socketThread has been initialized and has
  114. * started. */
  115. HANDLE socketListLock; /* Win32 Event to lock the socketList */
  116. SocketInfo *socketList; /* Every open socket in this thread has an
  117. * entry on this list. */
  118. } ThreadSpecificData;
  119. static Tcl_ThreadDataKey dataKey;
  120. static WNDCLASS windowClass;
  121. /*
  122. * Static functions defined in this file.
  123. */
  124. static SocketInfo * CreateSocket(Tcl_Interp *interp, int port,
  125. const char *host, int server, const char *myaddr,
  126. int myport, int async);
  127. static int CreateSocketAddress(LPSOCKADDR_IN sockaddrPtr,
  128. const char *host, int port);
  129. static void InitSockets(void);
  130. static SocketInfo * NewSocketInfo(SOCKET socket);
  131. static void SocketExitHandler(ClientData clientData);
  132. static LRESULT CALLBACK SocketProc(HWND hwnd, UINT message, WPARAM wParam,
  133. LPARAM lParam);
  134. static int SocketsEnabled(void);
  135. static void TcpAccept(SocketInfo *infoPtr);
  136. static int WaitForSocketEvent(SocketInfo *infoPtr, int events,
  137. int *errorCodePtr);
  138. static DWORD WINAPI SocketThread(LPVOID arg);
  139. static void TcpThreadActionProc(ClientData instanceData,
  140. int action);
  141. static Tcl_EventCheckProc SocketCheckProc;
  142. static Tcl_EventProc SocketEventProc;
  143. static Tcl_EventSetupProc SocketSetupProc;
  144. static Tcl_DriverBlockModeProc TcpBlockProc;
  145. static Tcl_DriverCloseProc TcpCloseProc;
  146. static Tcl_DriverSetOptionProc TcpSetOptionProc;
  147. static Tcl_DriverGetOptionProc TcpGetOptionProc;
  148. static Tcl_DriverInputProc TcpInputProc;
  149. static Tcl_DriverOutputProc TcpOutputProc;
  150. static Tcl_DriverWatchProc TcpWatchProc;
  151. static Tcl_DriverGetHandleProc TcpGetHandleProc;
  152. /*
  153. * This structure describes the channel type structure for TCP socket
  154. * based IO.
  155. */
  156. static Tcl_ChannelType tcpChannelType = {
  157. "tcp", /* Type name. */
  158. TCL_CHANNEL_VERSION_5, /* v5 channel */
  159. TcpCloseProc, /* Close proc. */
  160. TcpInputProc, /* Input proc. */
  161. TcpOutputProc, /* Output proc. */
  162. NULL, /* Seek proc. */
  163. TcpSetOptionProc, /* Set option proc. */
  164. TcpGetOptionProc, /* Get option proc. */
  165. TcpWatchProc, /* Set up notifier to watch this channel. */
  166. TcpGetHandleProc, /* Get an OS handle from channel. */
  167. NULL, /* close2proc. */
  168. TcpBlockProc, /* Set socket into (non-)blocking mode. */
  169. NULL, /* flush proc. */
  170. NULL, /* handler proc. */
  171. NULL, /* wide seek proc */
  172. TcpThreadActionProc, /* thread action proc */
  173. NULL, /* truncate */
  174. };
  175. /*
  176. *----------------------------------------------------------------------
  177. *
  178. * InitSockets --
  179. *
  180. * Initialize the socket module. If winsock startup is successful,
  181. * registers the event window for the socket notifier code.
  182. *
  183. * Assumes socketMutex is held.
  184. *
  185. * Results:
  186. * None.
  187. *
  188. * Side effects:
  189. * Initializes winsock, registers a new window class and creates a
  190. * window for use in asynchronous socket notification.
  191. *
  192. *----------------------------------------------------------------------
  193. */
  194. static void
  195. InitSockets(void)
  196. {
  197. DWORD id;
  198. WSADATA wsaData;
  199. DWORD err;
  200. ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
  201. TclThreadDataKeyGet(&dataKey);
  202. if (!initialized) {
  203. initialized = 1;
  204. TclCreateLateExitHandler(SocketExitHandler, (ClientData) NULL);
  205. /*
  206. * Create the async notification window with a new class. We must
  207. * create a new class to avoid a Windows 95 bug that causes us to get
  208. * the wrong message number for socket events if the message window is
  209. * a subclass of a static control.
  210. */
  211. windowClass.style = 0;
  212. windowClass.cbClsExtra = 0;
  213. windowClass.cbWndExtra = 0;
  214. windowClass.hInstance = TclWinGetTclInstance();
  215. windowClass.hbrBackground = NULL;
  216. windowClass.lpszMenuName = NULL;
  217. windowClass.lpszClassName = "TclSocket";
  218. windowClass.lpfnWndProc = SocketProc;
  219. windowClass.hIcon = NULL;
  220. windowClass.hCursor = NULL;
  221. if (!RegisterClassA(&windowClass)) {
  222. TclWinConvertError(GetLastError());
  223. goto initFailure;
  224. }
  225. /*
  226. * Initialize the winsock library and check the interface version
  227. * actually loaded. We only ask for the 1.1 interface and do require
  228. * that it not be less than 1.1.
  229. */
  230. #define WSA_VERSION_MAJOR 1
  231. #define WSA_VERSION_MINOR 1
  232. #define WSA_VERSION_REQD MAKEWORD(WSA_VERSION_MAJOR, WSA_VERSION_MINOR)
  233. err = WSAStartup((WORD)WSA_VERSION_REQD, &wsaData);
  234. if (err != 0) {
  235. TclWinConvertWSAError(err);
  236. goto initFailure;
  237. }
  238. /*
  239. * Note the byte positions are swapped for the comparison, so that
  240. * 0x0002 (2.0, MAKEWORD(2,0)) doesn't look less than 0x0101 (1.1).
  241. * We want the comparison to be 0x0200 < 0x0101.
  242. */
  243. if (MAKEWORD(HIBYTE(wsaData.wVersion), LOBYTE(wsaData.wVersion))
  244. < MAKEWORD(WSA_VERSION_MINOR, WSA_VERSION_MAJOR)) {
  245. TclWinConvertWSAError(WSAVERNOTSUPPORTED);
  246. WSACleanup();
  247. goto initFailure;
  248. }
  249. #undef WSA_VERSION_REQD
  250. #undef WSA_VERSION_MAJOR
  251. #undef WSA_VERSION_MINOR
  252. }
  253. /*
  254. * Check for per-thread initialization.
  255. */
  256. if (tsdPtr == NULL) {
  257. tsdPtr = TCL_TSD_INIT(&dataKey);
  258. tsdPtr->socketList = NULL;
  259. tsdPtr->hwnd = NULL;
  260. tsdPtr->threadId = Tcl_GetCurrentThread();
  261. tsdPtr->readyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  262. if (tsdPtr->readyEvent == NULL) {
  263. goto initFailure;
  264. }
  265. tsdPtr->socketListLock = CreateEvent(NULL, FALSE, TRUE, NULL);
  266. if (tsdPtr->socketListLock == NULL) {
  267. goto initFailure;
  268. }
  269. tsdPtr->socketThread = CreateThread(NULL, 256, SocketThread, tsdPtr,
  270. 0, &id);
  271. if (tsdPtr->socketThread == NULL) {
  272. goto initFailure;
  273. }
  274. SetThreadPriority(tsdPtr->socketThread, THREAD_PRIORITY_HIGHEST);
  275. /*
  276. * Wait for the thread to signal when the window has been created and
  277. * if it is ready to go.
  278. */
  279. WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
  280. if (tsdPtr->hwnd == NULL) {
  281. goto initFailure; /* Trouble creating the window */
  282. }
  283. Tcl_CreateEventSource(SocketSetupProc, SocketCheckProc, NULL);
  284. }
  285. return;
  286. initFailure:
  287. TclpFinalizeSockets();
  288. initialized = -1;
  289. return;
  290. }
  291. /*
  292. *----------------------------------------------------------------------
  293. *
  294. * SocketsEnabled --
  295. *
  296. * Check that the WinSock was successfully initialized.
  297. *
  298. * Results:
  299. * 1 if it is.
  300. *
  301. * Side effects:
  302. * None.
  303. *
  304. *----------------------------------------------------------------------
  305. */
  306. /* ARGSUSED */
  307. static int
  308. SocketsEnabled(void)
  309. {
  310. int enabled;
  311. Tcl_MutexLock(&socketMutex);
  312. enabled = (initialized == 1);
  313. Tcl_MutexUnlock(&socketMutex);
  314. return enabled;
  315. }
  316. /*
  317. *----------------------------------------------------------------------
  318. *
  319. * SocketExitHandler --
  320. *
  321. * Callback invoked during exit clean up to delete the socket
  322. * communication window and to release the WinSock DLL.
  323. *
  324. * Results:
  325. * None.
  326. *
  327. * Side effects:
  328. * None.
  329. *
  330. *----------------------------------------------------------------------
  331. */
  332. /* ARGSUSED */
  333. static void
  334. SocketExitHandler(
  335. ClientData clientData) /* Not used. */
  336. {
  337. Tcl_MutexLock(&socketMutex);
  338. /*
  339. * Make sure the socket event handling window is cleaned-up for, at
  340. * most, this thread.
  341. */
  342. TclpFinalizeSockets();
  343. UnregisterClass("TclSocket", TclWinGetTclInstance());
  344. WSACleanup();
  345. initialized = 0;
  346. Tcl_MutexUnlock(&socketMutex);
  347. }
  348. /*
  349. *----------------------------------------------------------------------
  350. *
  351. * TclpFinalizeSockets --
  352. *
  353. * This function is called from Tcl_FinalizeThread to finalize the
  354. * platform specific socket subsystem. Also, it may be called from within
  355. * this module to cleanup the state if unable to initialize the sockets
  356. * subsystem.
  357. *
  358. * Results:
  359. * None.
  360. *
  361. * Side effects:
  362. * Deletes the event source and destroys the socket thread.
  363. *
  364. *----------------------------------------------------------------------
  365. */
  366. void
  367. TclpFinalizeSockets(void)
  368. {
  369. ThreadSpecificData *tsdPtr;
  370. tsdPtr = (ThreadSpecificData *) TclThreadDataKeyGet(&dataKey);
  371. if (tsdPtr != NULL) {
  372. if (tsdPtr->socketThread != NULL) {
  373. if (tsdPtr->hwnd != NULL) {
  374. PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0);
  375. /*
  376. * Wait for the thread to exit. This ensures that we are
  377. * completely cleaned up before we leave this function.
  378. */
  379. WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
  380. tsdPtr->hwnd = NULL;
  381. }
  382. CloseHandle(tsdPtr->socketThread);
  383. tsdPtr->socketThread = NULL;
  384. }
  385. if (tsdPtr->readyEvent != NULL) {
  386. CloseHandle(tsdPtr->readyEvent);
  387. tsdPtr->readyEvent = NULL;
  388. }
  389. if (tsdPtr->socketListLock != NULL) {
  390. CloseHandle(tsdPtr->socketListLock);
  391. tsdPtr->socketListLock = NULL;
  392. }
  393. Tcl_DeleteEventSource(SocketSetupProc, SocketCheckProc, NULL);
  394. }
  395. }
  396. /*
  397. *----------------------------------------------------------------------
  398. *
  399. * TclpHasSockets --
  400. *
  401. * This function determines whether sockets are available on the current
  402. * system and returns an error in interp if they are not. Note that
  403. * interp may be NULL.
  404. *
  405. * Results:
  406. * Returns TCL_OK if the system supports sockets, or TCL_ERROR with an
  407. * error in interp (if non-NULL).
  408. *
  409. * Side effects:
  410. * If not already prepared, initializes the TSD structure and socket
  411. * message handling thread associated to the calling thread for the
  412. * subsystem of the driver.
  413. *
  414. *----------------------------------------------------------------------
  415. */
  416. int
  417. TclpHasSockets(
  418. Tcl_Interp *interp) /* Where to write an error message if sockets
  419. * are not present, or NULL if no such message
  420. * is to be written. */
  421. {
  422. Tcl_MutexLock(&socketMutex);
  423. InitSockets();
  424. Tcl_MutexUnlock(&socketMutex);
  425. if (SocketsEnabled()) {
  426. return TCL_OK;
  427. }
  428. if (interp != NULL) {
  429. Tcl_AppendResult(interp, "sockets are not available on this system",
  430. NULL);
  431. }
  432. return TCL_ERROR;
  433. }
  434. /*
  435. *----------------------------------------------------------------------
  436. *
  437. * SocketSetupProc --
  438. *
  439. * This function is invoked before Tcl_DoOneEvent blocks waiting for an
  440. * event.
  441. *
  442. * Results:
  443. * None.
  444. *
  445. * Side effects:
  446. * Adjusts the block time if needed.
  447. *
  448. *----------------------------------------------------------------------
  449. */
  450. void
  451. SocketSetupProc(
  452. ClientData data, /* Not used. */
  453. int flags) /* Event flags as passed to Tcl_DoOneEvent. */
  454. {
  455. SocketInfo *infoPtr;
  456. Tcl_Time blockTime = { 0, 0 };
  457. ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
  458. if (!(flags & TCL_FILE_EVENTS)) {
  459. return;
  460. }
  461. /*
  462. * Check to see if there is a ready socket. If so, poll.
  463. */
  464. WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
  465. for (infoPtr = tsdPtr->socketList; infoPtr != NULL;
  466. infoPtr = infoPtr->nextPtr) {
  467. if (infoPtr->readyEvents & infoPtr->watchEvents) {
  468. Tcl_SetMaxBlockTime(&blockTime);
  469. break;
  470. }
  471. }
  472. SetEvent(tsdPtr->socketListLock);
  473. }
  474. /*
  475. *----------------------------------------------------------------------
  476. *
  477. * SocketCheckProc --
  478. *
  479. * This function is called by Tcl_DoOneEvent to check the socket event
  480. * source for events.
  481. *
  482. * Results:
  483. * None.
  484. *
  485. * Side effects:
  486. * May queue an event.
  487. *
  488. *----------------------------------------------------------------------
  489. */
  490. static void
  491. SocketCheckProc(
  492. ClientData data, /* Not used. */
  493. int flags) /* Event flags as passed to Tcl_DoOneEvent. */
  494. {
  495. SocketInfo *infoPtr;
  496. SocketEvent *evPtr;
  497. ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
  498. if (!(flags & TCL_FILE_EVENTS)) {
  499. return;
  500. }
  501. /*
  502. * Queue events for any ready sockets that don't already have events
  503. * queued (caused by persistent states that won't generate WinSock
  504. * events).
  505. */
  506. WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
  507. for (infoPtr = tsdPtr->socketList; infoPtr != NULL;
  508. infoPtr = infoPtr->nextPtr) {
  509. if ((infoPtr->readyEvents & infoPtr->watchEvents)
  510. && !(infoPtr->flags & SOCKET_PENDING)) {
  511. infoPtr->flags |= SOCKET_PENDING;
  512. evPtr = (SocketEvent *) ckalloc(sizeof(SocketEvent));
  513. evPtr->header.proc = SocketEventProc;
  514. evPtr->socket = infoPtr->socket;
  515. Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
  516. }
  517. }
  518. SetEvent(tsdPtr->socketListLock);
  519. }
  520. /*
  521. *----------------------------------------------------------------------
  522. *
  523. * SocketEventProc --
  524. *
  525. * This function is called by Tcl_ServiceEvent when a socket event
  526. * reaches the front of the event queue. This function is responsible for
  527. * notifying the generic channel code.
  528. *
  529. * Results:
  530. * Returns 1 if the event was handled, meaning it should be removed from
  531. * the queue. Returns 0 if the event was not handled, meaning it should
  532. * stay on the queue. The only time the event isn't handled is if the
  533. * TCL_FILE_EVENTS flag bit isn't set.
  534. *
  535. * Side effects:
  536. * Whatever the channel callback functions do.
  537. *
  538. *----------------------------------------------------------------------
  539. */
  540. static int
  541. SocketEventProc(
  542. Tcl_Event *evPtr, /* Event to service. */
  543. int flags) /* Flags that indicate what events to handle,
  544. * such as TCL_FILE_EVENTS. */
  545. {
  546. SocketInfo *infoPtr;
  547. SocketEvent *eventPtr = (SocketEvent *) evPtr;
  548. int mask = 0;
  549. int events;
  550. ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
  551. if (!(flags & TCL_FILE_EVENTS)) {
  552. return 0;
  553. }
  554. /*
  555. * Find the specified socket on the socket list.
  556. */
  557. WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
  558. for (infoPtr = tsdPtr->socketList; infoPtr != NULL;
  559. infoPtr = infoPtr->nextPtr) {
  560. if (infoPtr->socket == eventPtr->socket) {
  561. break;
  562. }
  563. }
  564. SetEvent(tsdPtr->socketListLock);
  565. /*
  566. * Discard events that have gone stale.
  567. */
  568. if (!infoPtr) {
  569. return 1;
  570. }
  571. infoPtr->flags &= ~SOCKET_PENDING;
  572. /*
  573. * Handle connection requests directly.
  574. */
  575. if (infoPtr->readyEvents & FD_ACCEPT) {
  576. TcpAccept(infoPtr);
  577. return 1;
  578. }
  579. /*
  580. * Mask off unwanted events and compute the read/write mask so we can
  581. * notify the channel.
  582. */
  583. events = infoPtr->readyEvents & infoPtr->watchEvents;
  584. if (events & FD_CLOSE) {
  585. /*
  586. * If the socket was closed and the channel is still interested in
  587. * read events, then we need to ensure that we keep polling for this
  588. * event until someone does something with the channel. Note that we
  589. * do this before calling Tcl_NotifyChannel so we don't have to watch
  590. * out for the channel being deleted out from under us. This may cause
  591. * a redundant trip through the event loop, but it's simpler than
  592. * trying to do unwind protection.
  593. */
  594. Tcl_Time blockTime = { 0, 0 };
  595. Tcl_SetMaxBlockTime(&blockTime);
  596. mask |= TCL_READABLE|TCL_WRITABLE;
  597. } else if (events & FD_READ) {
  598. fd_set readFds;
  599. struct timeval timeout;
  600. /*
  601. * We must check to see if data is really available, since someone
  602. * could have consumed the data in the meantime. Turn off async
  603. * notification so select will work correctly. If the socket is still
  604. * readable, notify the channel driver, otherwise reset the async
  605. * select handler and keep waiting.
  606. */
  607. SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  608. (WPARAM) UNSELECT, (LPARAM) infoPtr);
  609. FD_ZERO(&readFds);
  610. FD_SET(infoPtr->socket, &readFds);
  611. timeout.tv_usec = 0;
  612. timeout.tv_sec = 0;
  613. if (select(0, &readFds, NULL, NULL, &timeout) != 0) {
  614. mask |= TCL_READABLE;
  615. } else {
  616. infoPtr->readyEvents &= ~(FD_READ);
  617. SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  618. (WPARAM) SELECT, (LPARAM) infoPtr);
  619. }
  620. }
  621. if (events & (FD_WRITE | FD_CONNECT)) {
  622. mask |= TCL_WRITABLE;
  623. if (events & FD_CONNECT && infoPtr->lastError != NO_ERROR) {
  624. /*
  625. * Connect errors should also fire the readable handler.
  626. */
  627. mask |= TCL_READABLE;
  628. }
  629. }
  630. if (mask) {
  631. Tcl_NotifyChannel(infoPtr->channel, mask);
  632. }
  633. return 1;
  634. }
  635. /*
  636. *----------------------------------------------------------------------
  637. *
  638. * TcpBlockProc --
  639. *
  640. * Sets a socket into blocking or non-blocking mode.
  641. *
  642. * Results:
  643. * 0 if successful, errno if there was an error.
  644. *
  645. * Side effects:
  646. * None.
  647. *
  648. *----------------------------------------------------------------------
  649. */
  650. static int
  651. TcpBlockProc(
  652. ClientData instanceData, /* The socket to block/un-block. */
  653. int mode) /* TCL_MODE_BLOCKING or
  654. * TCL_MODE_NONBLOCKING. */
  655. {
  656. SocketInfo *infoPtr = (SocketInfo *) instanceData;
  657. if (mode == TCL_MODE_NONBLOCKING) {
  658. infoPtr->flags |= SOCKET_ASYNC;
  659. } else {
  660. infoPtr->flags &= ~(SOCKET_ASYNC);
  661. }
  662. return 0;
  663. }
  664. /*
  665. *----------------------------------------------------------------------
  666. *
  667. * TcpCloseProc --
  668. *
  669. * This function is called by the generic IO level to perform channel
  670. * type specific cleanup on a socket based channel when the channel is
  671. * closed.
  672. *
  673. * Results:
  674. * 0 if successful, the value of errno if failed.
  675. *
  676. * Side effects:
  677. * Closes the socket.
  678. *
  679. *----------------------------------------------------------------------
  680. */
  681. /* ARGSUSED */
  682. static int
  683. TcpCloseProc(
  684. ClientData instanceData, /* The socket to close. */
  685. Tcl_Interp *interp) /* Unused. */
  686. {
  687. SocketInfo *infoPtr = (SocketInfo *) instanceData;
  688. /* TIP #218 */
  689. int errorCode = 0;
  690. /* ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); */
  691. /*
  692. * Check that WinSock is initialized; do not call it if not, to prevent
  693. * system crashes. This can happen at exit time if the exit handler for
  694. * WinSock ran before other exit handlers that want to use sockets.
  695. */
  696. if (SocketsEnabled()) {
  697. /*
  698. * Clean up the OS socket handle. The default Windows setting for a
  699. * socket is SO_DONTLINGER, which does a graceful shutdown in the
  700. * background.
  701. */
  702. if (closesocket(infoPtr->socket) == SOCKET_ERROR) {
  703. TclWinConvertWSAError((DWORD) WSAGetLastError());
  704. errorCode = Tcl_GetErrno();
  705. }
  706. }
  707. /*
  708. * TIP #218. Removed the code removing the structure from the global
  709. * socket list. This is now done by the thread action callbacks, and only
  710. * there. This happens before this code is called. We can free without
  711. * fear of damaging the list.
  712. */
  713. ckfree((char *) infoPtr);
  714. return errorCode;
  715. }
  716. /*
  717. *----------------------------------------------------------------------
  718. *
  719. * NewSocketInfo --
  720. *
  721. * This function allocates and initializes a new SocketInfo structure.
  722. *
  723. * Results:
  724. * Returns a newly allocated SocketInfo.
  725. *
  726. * Side effects:
  727. * None, except for allocation of memory.
  728. *
  729. *----------------------------------------------------------------------
  730. */
  731. static SocketInfo *
  732. NewSocketInfo(
  733. SOCKET socket)
  734. {
  735. SocketInfo *infoPtr;
  736. /* ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); */
  737. infoPtr = (SocketInfo *) ckalloc((unsigned) sizeof(SocketInfo));
  738. infoPtr->channel = 0;
  739. infoPtr->socket = socket;
  740. infoPtr->flags = 0;
  741. infoPtr->watchEvents = 0;
  742. infoPtr->readyEvents = 0;
  743. infoPtr->selectEvents = 0;
  744. infoPtr->acceptEventCount = 0;
  745. infoPtr->acceptProc = NULL;
  746. infoPtr->acceptProcData = NULL;
  747. infoPtr->lastError = 0;
  748. /*
  749. * TIP #218. Removed the code inserting the new structure into the global
  750. * list. This is now handled in the thread action callbacks, and only
  751. * there.
  752. */
  753. infoPtr->nextPtr = NULL;
  754. return infoPtr;
  755. }
  756. /*
  757. *----------------------------------------------------------------------
  758. *
  759. * CreateSocket --
  760. *
  761. * This function opens a new socket and initializes the SocketInfo
  762. * structure.
  763. *
  764. * Results:
  765. * Returns a new SocketInfo, or NULL with an error in interp.
  766. *
  767. * Side effects:
  768. * None, except for allocation of memory.
  769. *
  770. *----------------------------------------------------------------------
  771. */
  772. static SocketInfo *
  773. CreateSocket(
  774. Tcl_Interp *interp, /* For error reporting; can be NULL. */
  775. int port, /* Port number to open. */
  776. const char *host, /* Name of host on which to open port. */
  777. int server, /* 1 if socket should be a server socket, else
  778. * 0 for a client socket. */
  779. const char *myaddr, /* Optional client-side address */
  780. int myport, /* Optional client-side port */
  781. int async) /* If nonzero, connect client socket
  782. * asynchronously. */
  783. {
  784. u_long flag = 1; /* Indicates nonblocking mode. */
  785. int asyncConnect = 0; /* Will be 1 if async connect is in
  786. * progress. */
  787. SOCKADDR_IN sockaddr; /* Socket address */
  788. SOCKADDR_IN mysockaddr; /* Socket address for client */
  789. SOCKET sock = INVALID_SOCKET;
  790. SocketInfo *infoPtr; /* The returned value. */
  791. ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
  792. TclThreadDataKeyGet(&dataKey);
  793. /*
  794. * Check that WinSock is initialized; do not call it if not, to prevent
  795. * system crashes. This can happen at exit time if the exit handler for
  796. * WinSock ran before other exit handlers that want to use sockets.
  797. */
  798. if (!SocketsEnabled()) {
  799. return NULL;
  800. }
  801. if (!CreateSocketAddress(&sockaddr, host, port)) {
  802. goto error;
  803. }
  804. if ((myaddr != NULL || myport != 0) &&
  805. !CreateSocketAddress(&mysockaddr, myaddr, myport)) {
  806. goto error;
  807. }
  808. sock = socket(AF_INET, SOCK_STREAM, 0);
  809. if (sock == INVALID_SOCKET) {
  810. goto error;
  811. }
  812. /*
  813. * Win-NT has a misfeature that sockets are inherited in child processes
  814. * by default. Turn off the inherit bit.
  815. */
  816. SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
  817. /*
  818. * Set kernel space buffering
  819. */
  820. TclSockMinimumBuffers((int) sock, TCP_BUFFER_SIZE);
  821. if (server) {
  822. /*
  823. * Bind to the specified port. Note that we must not call setsockopt
  824. * with SO_REUSEADDR because Microsoft allows addresses to be reused
  825. * even if they are still in use.
  826. *
  827. * Bind should not be affected by the socket having already been set
  828. * into nonblocking mode. If there is trouble, this is one place to
  829. * look for bugs.
  830. */
  831. if (bind(sock, (SOCKADDR *) &sockaddr, sizeof(SOCKADDR_IN))
  832. == SOCKET_ERROR) {
  833. goto error;
  834. }
  835. /*
  836. * Set the maximum number of pending connect requests to the max value
  837. * allowed on each platform (Win32 and Win32s may be different, and
  838. * there may be differences between TCP/IP stacks).
  839. */
  840. if (listen(sock, SOMAXCONN) == SOCKET_ERROR) {
  841. goto error;
  842. }
  843. /*
  844. * Add this socket to the global list of sockets.
  845. */
  846. infoPtr = NewSocketInfo(sock);
  847. /*
  848. * Set up the select mask for connection request events.
  849. */
  850. infoPtr->selectEvents = FD_ACCEPT;
  851. infoPtr->watchEvents |= FD_ACCEPT;
  852. } else {
  853. /*
  854. * Try to bind to a local port, if specified.
  855. */
  856. if (myaddr != NULL || myport != 0) {
  857. if (bind(sock, (SOCKADDR *) &mysockaddr, sizeof(SOCKADDR_IN))
  858. == SOCKET_ERROR) {
  859. goto error;
  860. }
  861. }
  862. /*
  863. * Set the socket into nonblocking mode if the connect should be done
  864. * in the background.
  865. */
  866. if (async) {
  867. if (ioctlsocket(sock, (long) FIONBIO, &flag) == SOCKET_ERROR) {
  868. goto error;
  869. }
  870. }
  871. /*
  872. * Attempt to connect to the remote socket.
  873. */
  874. if (connect(sock, (SOCKADDR *) &sockaddr,
  875. sizeof(SOCKADDR_IN)) == SOCKET_ERROR) {
  876. TclWinConvertWSAError((DWORD) WSAGetLastError());
  877. if (Tcl_GetErrno() != EWOULDBLOCK) {
  878. goto error;
  879. }
  880. /*
  881. * The connection is progressing in the background.
  882. */
  883. asyncConnect = 1;
  884. }
  885. /*
  886. * Add this socket to the global list of sockets.
  887. */
  888. infoPtr = NewSocketInfo(sock);
  889. /*
  890. * Set up the select mask for read/write events. If the connect
  891. * attempt has not completed, include connect events.
  892. */
  893. infoPtr->selectEvents = FD_READ | FD_WRITE | FD_CLOSE;
  894. if (asyncConnect) {
  895. infoPtr->flags |= SOCKET_ASYNC_CONNECT;
  896. infoPtr->selectEvents |= FD_CONNECT;
  897. }
  898. }
  899. /*
  900. * Register for interest in events in the select mask. Note that this
  901. * automatically places the socket into non-blocking mode.
  902. */
  903. ioctlsocket(sock, (long) FIONBIO, &flag);
  904. SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT, (LPARAM) infoPtr);
  905. return infoPtr;
  906. error:
  907. TclWinConvertWSAError((DWORD) WSAGetLastError());
  908. if (interp != NULL) {
  909. Tcl_AppendResult(interp, "couldn't open socket: ",
  910. Tcl_PosixError(interp), NULL);
  911. }
  912. if (sock != INVALID_SOCKET) {
  913. closesocket(sock);
  914. }
  915. return NULL;
  916. }
  917. /*
  918. *----------------------------------------------------------------------
  919. *
  920. * CreateSocketAddress --
  921. *
  922. * This function initializes a sockaddr structure for a host and port.
  923. *
  924. * Results:
  925. * 1 if the host was valid, 0 if the host could not be converted to an IP
  926. * address.
  927. *
  928. * Side effects:
  929. * Fills in the *sockaddrPtr structure.
  930. *
  931. *----------------------------------------------------------------------
  932. */
  933. static int
  934. CreateSocketAddress(
  935. LPSOCKADDR_IN sockaddrPtr, /* Socket address */
  936. const char *host, /* Host. NULL implies INADDR_ANY */
  937. int port) /* Port number */
  938. {
  939. struct hostent *hostent; /* Host database entry */
  940. struct in_addr addr; /* For 64/32 bit madness */
  941. /*
  942. * Check that WinSock is initialized; do not call it if not, to prevent
  943. * system crashes. This can happen at exit time if the exit handler for
  944. * WinSock ran before other exit handlers that want to use sockets.
  945. */
  946. if (!SocketsEnabled()) {
  947. Tcl_SetErrno(EFAULT);
  948. return 0;
  949. }
  950. ZeroMemory(sockaddrPtr, sizeof(SOCKADDR_IN));
  951. sockaddrPtr->sin_family = AF_INET;
  952. sockaddrPtr->sin_port = htons((u_short) (port & 0xFFFF));
  953. if (host == NULL) {
  954. addr.s_addr = INADDR_ANY;
  955. } else {
  956. addr.s_addr = inet_addr(host);
  957. if (addr.s_addr == INADDR_NONE) {
  958. hostent = gethostbyname(host);
  959. if (hostent != NULL) {
  960. memcpy(&addr, hostent->h_addr, (size_t) hostent->h_length);
  961. } else {
  962. #ifdef EHOSTUNREACH
  963. Tcl_SetErrno(EHOSTUNREACH);
  964. #else
  965. #ifdef ENXIO
  966. Tcl_SetErrno(ENXIO);
  967. #endif
  968. #endif
  969. return 0; /* Error. */
  970. }
  971. }
  972. }
  973. /*
  974. * NOTE: On 64 bit machines the assignment below is rumored to not do the
  975. * right thing. Please report errors related to this if you observe
  976. * incorrect behavior on 64 bit machines such as DEC Alphas. Should we
  977. * modify this code to do an explicit memcpy?
  978. */
  979. sockaddrPtr->sin_addr.s_addr = addr.s_addr;
  980. return 1; /* Success. */
  981. }
  982. /*
  983. *----------------------------------------------------------------------
  984. *
  985. * WaitForSocketEvent --
  986. *
  987. * Waits until one of the specified events occurs on a socket.
  988. *
  989. * Results:
  990. * Returns 1 on success or 0 on failure, with an error code in
  991. * errorCodePtr.
  992. *
  993. * Side effects:
  994. * Processes socket events off the system queue.
  995. *
  996. *----------------------------------------------------------------------
  997. */
  998. static int
  999. WaitForSocketEvent(
  1000. SocketInfo *infoPtr, /* Information about this socket. */
  1001. int events, /* Events to look for. */
  1002. int *errorCodePtr) /* Where to store errors? */
  1003. {
  1004. int result = 1;
  1005. int oldMode;
  1006. ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
  1007. TclThreadDataKeyGet(&dataKey);
  1008. /*
  1009. * Be sure to disable event servicing so we are truly modal.
  1010. */
  1011. oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
  1012. /*
  1013. * Reset WSAAsyncSelect so we have a fresh set of events pending.
  1014. */
  1015. SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) UNSELECT,
  1016. (LPARAM) infoPtr);
  1017. SendMessage(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) SELECT,
  1018. (LPARAM) infoPtr);
  1019. while (1) {
  1020. if (infoPtr->lastError) {
  1021. *errorCodePtr = infoPtr->lastError;
  1022. result = 0;
  1023. break;
  1024. } else if (infoPtr->readyEvents & events) {
  1025. break;
  1026. } else if (infoPtr->flags & SOCKET_ASYNC) {
  1027. *errorCodePtr = EWOULDBLOCK;
  1028. result = 0;
  1029. break;
  1030. }
  1031. /*
  1032. * Wait until something happens.
  1033. */
  1034. WaitForSingleObject(tsdPtr->readyEvent, INFINITE);
  1035. }
  1036. (void) Tcl_SetServiceMode(oldMode);
  1037. return result;
  1038. }
  1039. /*
  1040. *----------------------------------------------------------------------
  1041. *
  1042. * Tcl_OpenTcpClient --
  1043. *
  1044. * Opens a TCP client socket and creates a channel around it.
  1045. *
  1046. * Results:
  1047. * The channel or NULL if failed. An error message is returned in the
  1048. * interpreter on failure.
  1049. *
  1050. * Side effects:
  1051. * Opens a client socket and creates a new channel.
  1052. *
  1053. *----------------------------------------------------------------------
  1054. */
  1055. Tcl_Channel
  1056. Tcl_OpenTcpClient(
  1057. Tcl_Interp *interp, /* For error reporting; can be NULL. */
  1058. int port, /* Port number to open. */
  1059. const char *host, /* Host on which to open port. */
  1060. const char *myaddr, /* Client-side address */
  1061. int myport, /* Client-side port */
  1062. int async) /* If nonzero, should connect client socket
  1063. * asynchronously. */
  1064. {
  1065. SocketInfo *infoPtr;
  1066. char channelName[16 + TCL_INTEGER_SPACE];
  1067. if (TclpHasSockets(interp) != TCL_OK) {
  1068. return NULL;
  1069. }
  1070. /*
  1071. * Create a new client socket and wrap it in a channel.
  1072. */
  1073. infoPtr = CreateSocket(interp, port, host, 0, myaddr, myport, async);
  1074. if (infoPtr == NULL) {
  1075. return NULL;
  1076. }
  1077. wsprintfA(channelName, "sock%d", infoPtr->socket);
  1078. infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
  1079. (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE));
  1080. if (Tcl_SetChannelOption(interp, infoPtr->channel, "-translation",
  1081. "auto crlf") == TCL_ERROR) {
  1082. Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);
  1083. return (Tcl_Channel) NULL;
  1084. }
  1085. if (Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "")
  1086. == TCL_ERROR) {
  1087. Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);
  1088. return (Tcl_Channel) NULL;
  1089. }
  1090. return infoPtr->channel;
  1091. }
  1092. /*
  1093. *----------------------------------------------------------------------
  1094. *
  1095. * Tcl_MakeTcpClientChannel --
  1096. *
  1097. * Creates a Tcl_Channel from an existing client TCP socket.
  1098. *
  1099. * Results:
  1100. * The Tcl_Channel wrapped around the preexisting TCP socket.
  1101. *
  1102. * Side effects:
  1103. * None.
  1104. *
  1105. * NOTE: Code contributed by Mark Diekhans (markd@grizzly.com)
  1106. *
  1107. *----------------------------------------------------------------------
  1108. */
  1109. Tcl_Channel
  1110. Tcl_MakeTcpClientChannel(
  1111. ClientData sock) /* The socket to wrap up into a channel. */
  1112. {
  1113. SocketInfo *infoPtr;
  1114. char channelName[16 + TCL_INTEGER_SPACE];
  1115. ThreadSpecificData *tsdPtr;
  1116. if (TclpHasSockets(NULL) != TCL_OK) {
  1117. return NULL;
  1118. }
  1119. tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
  1120. /*
  1121. * Set kernel space buffering and non-blocking.
  1122. */
  1123. TclSockMinimumBuffers((int) sock, TCP_BUFFER_SIZE);
  1124. infoPtr = NewSocketInfo((SOCKET) sock);
  1125. /*
  1126. * Start watching for read/write events on the socket.
  1127. */
  1128. infoPtr->selectEvents = FD_READ | FD_CLOSE | FD_WRITE;
  1129. SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  1130. (WPARAM) SELECT, (LPARAM) infoPtr);
  1131. wsprintfA(channelName, "sock%d", infoPtr->socket);
  1132. infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
  1133. (ClientData) infoPtr, (TCL_READABLE | TCL_WRITABLE));
  1134. Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto crlf");
  1135. return infoPtr->channel;
  1136. }
  1137. /*
  1138. *----------------------------------------------------------------------
  1139. *
  1140. * Tcl_OpenTcpServer --
  1141. *
  1142. * Opens a TCP server socket and creates a channel around it.
  1143. *
  1144. * Results:
  1145. * The channel or NULL if failed. An error message is returned in the
  1146. * interpreter on failure.
  1147. *
  1148. * Side effects:
  1149. * Opens a server socket and creates a new channel.
  1150. *
  1151. *----------------------------------------------------------------------
  1152. */
  1153. Tcl_Channel
  1154. Tcl_OpenTcpServer(
  1155. Tcl_Interp *interp, /* For error reporting - may be NULL. */
  1156. int port, /* Port number to open. */
  1157. const char *host, /* Name of local host. */
  1158. Tcl_TcpAcceptProc *acceptProc,
  1159. /* Callback for accepting connections from new
  1160. * clients. */
  1161. ClientData acceptProcData) /* Data for the callback. */
  1162. {
  1163. SocketInfo *infoPtr;
  1164. char channelName[16 + TCL_INTEGER_SPACE];
  1165. if (TclpHasSockets(interp) != TCL_OK) {
  1166. return NULL;
  1167. }
  1168. /*
  1169. * Create a new client socket and wrap it in a channel.
  1170. */
  1171. infoPtr = CreateSocket(interp, port, host, 1, NULL, 0, 0);
  1172. if (infoPtr == NULL) {
  1173. return NULL;
  1174. }
  1175. infoPtr->acceptProc = acceptProc;
  1176. infoPtr->acceptProcData = acceptProcData;
  1177. wsprintfA(channelName, "sock%d", infoPtr->socket);
  1178. infoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
  1179. (ClientData) infoPtr, 0);
  1180. if (Tcl_SetChannelOption(interp, infoPtr->channel, "-eofchar", "")
  1181. == TCL_ERROR) {
  1182. Tcl_Close((Tcl_Interp *) NULL, infoPtr->channel);
  1183. return (Tcl_Channel) NULL;
  1184. }
  1185. return infoPtr->channel;
  1186. }
  1187. /*
  1188. *----------------------------------------------------------------------
  1189. *
  1190. * TcpAccept --
  1191. *
  1192. * Accept a TCP socket connection. This is called by SocketEventProc and
  1193. * it in turns calls the registered accept function.
  1194. *
  1195. * Results:
  1196. * None.
  1197. *
  1198. * Side effects:
  1199. * Invokes the accept proc which may invoke arbitrary Tcl code.
  1200. *
  1201. *----------------------------------------------------------------------
  1202. */
  1203. static void
  1204. TcpAccept(
  1205. SocketInfo *infoPtr) /* Socket to accept. */
  1206. {
  1207. SOCKET newSocket;
  1208. SocketInfo *newInfoPtr;
  1209. SOCKADDR_IN addr;
  1210. int len;
  1211. char channelName[16 + TCL_INTEGER_SPACE];
  1212. ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
  1213. TclThreadDataKeyGet(&dataKey);
  1214. /*
  1215. * Accept the incoming connection request.
  1216. */
  1217. len = sizeof(SOCKADDR_IN);
  1218. newSocket = accept(infoPtr->socket, (SOCKADDR *)&addr,
  1219. &len);
  1220. /*
  1221. * Clear the ready mask so we can detect the next connection request. Note
  1222. * that connection requests are level triggered, so if there is a request
  1223. * already pending, a new event will be generated.
  1224. */
  1225. if (newSocket == INVALID_SOCKET) {
  1226. infoPtr->acceptEventCount = 0;
  1227. infoPtr->readyEvents &= ~(FD_ACCEPT);
  1228. return;
  1229. }
  1230. /*
  1231. * It is possible that more than one FD_ACCEPT has been sent, so an extra
  1232. * count must be kept. Decrement the count, and reset the readyEvent bit
  1233. * if the count is no longer > 0.
  1234. */
  1235. infoPtr->acceptEventCount--;
  1236. if (infoPtr->acceptEventCount <= 0) {
  1237. infoPtr->readyEvents &= ~(FD_ACCEPT);
  1238. }
  1239. /*
  1240. * Win-NT has a misfeature that sockets are inherited in child processes
  1241. * by default. Turn off the inherit bit.
  1242. */
  1243. SetHandleInformation((HANDLE) newSocket, HANDLE_FLAG_INHERIT, 0);
  1244. /*
  1245. * Add this socket to the global list of sockets.
  1246. */
  1247. newInfoPtr = NewSocketInfo(newSocket);
  1248. /*
  1249. * Select on read/write events and create the channel.
  1250. */
  1251. newInfoPtr->selectEvents = (FD_READ | FD_WRITE | FD_CLOSE);
  1252. SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  1253. (WPARAM) SELECT, (LPARAM) newInfoPtr);
  1254. wsprintfA(channelName, "sock%d", newInfoPtr->socket);
  1255. newInfoPtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
  1256. (ClientData) newInfoPtr, (TCL_READABLE | TCL_WRITABLE));
  1257. if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-translation",
  1258. "auto crlf") == TCL_ERROR) {
  1259. Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel);
  1260. return;
  1261. }
  1262. if (Tcl_SetChannelOption(NULL, newInfoPtr->channel, "-eofchar", "")
  1263. == TCL_ERROR) {
  1264. Tcl_Close((Tcl_Interp *) NULL, newInfoPtr->channel);
  1265. return;
  1266. }
  1267. /*
  1268. * Invoke the accept callback function.
  1269. */
  1270. if (infoPtr->acceptProc != NULL) {
  1271. (infoPtr->acceptProc) (infoPtr->acceptProcData, newInfoPtr->channel,
  1272. inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
  1273. }
  1274. }
  1275. /*
  1276. *----------------------------------------------------------------------
  1277. *
  1278. * TcpInputProc --
  1279. *
  1280. * This function is called by the generic IO level to read data from a
  1281. * socket based channel.
  1282. *
  1283. * Results:
  1284. * The number of bytes read or -1 on error.
  1285. *
  1286. * Side effects:
  1287. * Consumes input from the socket.
  1288. *
  1289. *----------------------------------------------------------------------
  1290. */
  1291. static int
  1292. TcpInputProc(
  1293. ClientData instanceData, /* The socket state. */
  1294. char *buf, /* Where to store data. */
  1295. int toRead, /* Maximum number of bytes to read. */
  1296. int *errorCodePtr) /* Where to store error codes. */
  1297. {
  1298. SocketInfo *infoPtr = (SocketInfo *) instanceData;
  1299. int bytesRead;
  1300. DWORD error;
  1301. ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
  1302. TclThreadDataKeyGet(&dataKey);
  1303. *errorCodePtr = 0;
  1304. /*
  1305. * Check that WinSock is initialized; do not call it if not, to prevent
  1306. * system crashes. This can happen at exit time if the exit handler for
  1307. * WinSock ran before other exit handlers that want to use sockets.
  1308. */
  1309. if (!SocketsEnabled()) {
  1310. *errorCodePtr = EFAULT;
  1311. return -1;
  1312. }
  1313. /*
  1314. * First check to see if EOF was already detected, to prevent calling the
  1315. * socket stack after the first time EOF is detected.
  1316. */
  1317. if (infoPtr->flags & SOCKET_EOF) {
  1318. return 0;
  1319. }
  1320. /*
  1321. * Check to see if the socket is connected before trying to read.
  1322. */
  1323. if ((infoPtr->flags & SOCKET_ASYNC_CONNECT)
  1324. && !WaitForSocketEvent(infoPtr, FD_CONNECT, errorCodePtr)) {
  1325. return -1;
  1326. }
  1327. /*
  1328. * No EOF, and it is connected, so try to read more from the socket. Note
  1329. * that we clear the FD_READ bit because read events are level triggered
  1330. * so a new event will be generated if there is still data available to be
  1331. * read. We have to simulate blocking behavior here since we are always
  1332. * using non-blocking sockets.
  1333. */
  1334. while (1) {
  1335. SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  1336. (WPARAM) UNSELECT, (LPARAM) infoPtr);
  1337. bytesRead = recv(infoPtr->socket, buf, toRead, 0);
  1338. infoPtr->readyEvents &= ~(FD_READ);
  1339. /*
  1340. * Check for end-of-file condition or successful read.
  1341. */
  1342. if (bytesRead == 0) {
  1343. infoPtr->flags |= SOCKET_EOF;
  1344. }
  1345. if (bytesRead != SOCKET_ERROR) {
  1346. break;
  1347. }
  1348. /*
  1349. * If an error occurs after the FD_CLOSE has arrived, then ignore the
  1350. * error and report an EOF.
  1351. */
  1352. if (infoPtr->readyEvents & FD_CLOSE) {
  1353. infoPtr->flags |= SOCKET_EOF;
  1354. bytesRead = 0;
  1355. break;
  1356. }
  1357. error = WSAGetLastError();
  1358. /*
  1359. * If an RST comes, then ignore the error and report an EOF just like
  1360. * on unix.
  1361. */
  1362. if (error == WSAECONNRESET) {
  1363. infoPtr->flags |= SOCKET_EOF;
  1364. bytesRead = 0;
  1365. break;
  1366. }
  1367. /*
  1368. * Check for error condition or underflow in non-blocking case.
  1369. */
  1370. if ((infoPtr->flags & SOCKET_ASYNC) || (error != WSAEWOULDBLOCK)) {
  1371. TclWinConvertWSAError(error);
  1372. *errorCodePtr = Tcl_GetErrno();
  1373. bytesRead = -1;
  1374. break;
  1375. }
  1376. /*
  1377. * In the blocking case, wait until the file becomes readable or
  1378. * closed and try again.
  1379. */
  1380. if (!WaitForSocketEvent(infoPtr, FD_READ|FD_CLOSE, errorCodePtr)) {
  1381. bytesRead = -1;
  1382. break;
  1383. }
  1384. }
  1385. SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  1386. (WPARAM) SELECT, (LPARAM) infoPtr);
  1387. return bytesRead;
  1388. }
  1389. /*
  1390. *----------------------------------------------------------------------
  1391. *
  1392. * TcpOutputProc --
  1393. *
  1394. * This function is called by the generic IO level to write data to a
  1395. * socket based channel.
  1396. *
  1397. * Results:
  1398. * The number of bytes written or -1 on failure.
  1399. *
  1400. * Side effects:
  1401. * Produces output on the socket.
  1402. *
  1403. *----------------------------------------------------------------------
  1404. */
  1405. static int
  1406. TcpOutputProc(
  1407. ClientData instanceData, /* The socket state. */
  1408. const char *buf, /* Where to get data. */
  1409. int toWrite, /* Maximum number of bytes to write. */
  1410. int *errorCodePtr) /* Where to store error codes. */
  1411. {
  1412. SocketInfo *infoPtr = (SocketInfo *) instanceData;
  1413. int bytesWritten;
  1414. DWORD error;
  1415. ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
  1416. TclThreadDataKeyGet(&dataKey);
  1417. *errorCodePtr = 0;
  1418. /*
  1419. * Check that WinSock is initialized; do not call it if not, to prevent
  1420. * system crashes. This can happen at exit time if the exit handler for
  1421. * WinSock ran before other exit handlers that want to use sockets.
  1422. */
  1423. if (!SocketsEnabled()) {
  1424. *errorCodePtr = EFAULT;
  1425. return -1;
  1426. }
  1427. /*
  1428. * Check to see if the socket is connected before trying to write.
  1429. */
  1430. if ((infoPtr->flags & SOCKET_ASYNC_CONNECT)
  1431. && !WaitForSocketEvent(infoPtr, FD_CONNECT, errorCodePtr)) {
  1432. return -1;
  1433. }
  1434. while (1) {
  1435. SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  1436. (WPARAM) UNSELECT, (LPARAM) infoPtr);
  1437. bytesWritten = send(infoPtr->socket, buf, toWrite, 0);
  1438. if (bytesWritten != SOCKET_ERROR) {
  1439. /*
  1440. * Since Windows won't generate a new write event until we hit an
  1441. * overflow condition, we need to force the event loop to poll
  1442. * until the condition changes.
  1443. */
  1444. if (infoPtr->watchEvents & FD_WRITE) {
  1445. Tcl_Time blockTime = { 0, 0 };
  1446. Tcl_SetMaxBlockTime(&blockTime);
  1447. }
  1448. break;
  1449. }
  1450. /*
  1451. * Check for error condition or overflow. In the event of overflow, we
  1452. * need to clear the FD_WRITE flag so we can detect the next writable
  1453. * event. Note that Windows only sends a new writable event after a
  1454. * send fails with WSAEWOULDBLOCK.
  1455. */
  1456. error = WSAGetLastError();
  1457. if (error == WSAEWOULDBLOCK) {
  1458. infoPtr->readyEvents &= ~(FD_WRITE);
  1459. if (infoPtr->flags & SOCKET_ASYNC) {
  1460. *errorCodePtr = EWOULDBLOCK;
  1461. bytesWritten = -1;
  1462. break;
  1463. }
  1464. } else {
  1465. TclWinConvertWSAError(error);
  1466. *errorCodePtr = Tcl_GetErrno();
  1467. bytesWritten = -1;
  1468. break;
  1469. }
  1470. /*
  1471. * In the blocking case, wait until the file becomes writable or
  1472. * closed and try again.
  1473. */
  1474. if (!WaitForSocketEvent(infoPtr, FD_WRITE|FD_CLOSE, errorCodePtr)) {
  1475. bytesWritten = -1;
  1476. break;
  1477. }
  1478. }
  1479. SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
  1480. (WPARAM) SELECT, (LPARAM) infoPtr);
  1481. return bytesWritten;
  1482. }
  1483. /*
  1484. *----------------------------------------------------------------------
  1485. *
  1486. * TcpSetOptionProc --
  1487. *
  1488. * Sets Tcp channel specific options.
  1489. *
  1490. * Results:
  1491. * None, unless an error happens.
  1492. *
  1493. * Side effects:
  1494. * Changes attributes of the socket at the system level.
  1495. *
  1496. *----------------------------------------------------------------------
  1497. */
  1498. static int
  1499. TcpSetOptionProc(
  1500. ClientData instanceData, /* Socket state. */
  1501. Tcl_Interp *interp, /* For error reporting - can be NULL. */
  1502. const char *optionName, /* Name of the option to set. */
  1503. const char *value) /* New value for option. */
  1504. {
  1505. SocketInfo *infoPtr;
  1506. SOCKET sock;
  1507. /*
  1508. * Check that WinSock is initialized; do not call it if not, to prevent
  1509. * system crashes. This can happen at exit time if the exit handler for
  1510. * WinSock ran before other exit handlers that want to use sockets.
  1511. */
  1512. if (!SocketsEnabled()) {
  1513. if (interp) {
  1514. Tcl_AppendResult(interp, "winsock is not initialized", NULL);
  1515. }
  1516. return TCL_ERROR;
  1517. }
  1518. infoPtr = (SocketInfo *) instanceData;
  1519. sock = infoPtr->socket;
  1520. #ifdef TCL_FEATURE_KEEPALIVE_NAGLE
  1521. if (!strcasecmp(optionName, "-keepalive")) {
  1522. BOOL val = FALSE;
  1523. int boolVar, rtn;
  1524. if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) {
  1525. return TCL_ERROR;
  1526. }
  1527. if (boolVar) {
  1528. val = TRUE;
  1529. }
  1530. rtn = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
  1531. (const char *) &val, sizeof(BOOL));
  1532. if (rtn != 0) {
  1533. TclWinConvertWSAError(WSAGetLastError());
  1534. if (interp) {
  1535. Tcl_AppendResult(interp, "couldn't set socket option: ",
  1536. Tcl_PosixError(interp), NULL);
  1537. }
  1538. return TCL_ERROR;
  1539. }
  1540. return TCL_OK;
  1541. } else if (!strcasecmp(optionName, "-nagle")) {
  1542. BOOL val = FALSE;
  1543. int boolVar, rtn;
  1544. if (Tcl_GetBoolean(interp, value, &boolVar) != TCL_OK) {
  1545. return TCL_ERROR;
  1546. }
  1547. if (!boolVar) {
  1548. val = TRUE;
  1549. }
  1550. rtn = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
  1551. (const char *) &val, sizeof(BOOL));
  1552. if (rtn != 0) {
  1553. TclWinConvertWSAError(WSAGetLastError());
  1554. if (interp) {
  1555. Tcl_AppendResult(interp, "couldn't set socket option: ",
  1556. Tcl_PosixError(interp), NULL);
  1557. }
  1558. return TCL_ERROR;
  1559. }
  1560. return TCL_OK;
  1561. }
  1562. return Tcl_BadChannelOption(interp, optionName, "keepalive nagle");
  1563. #else
  1564. return Tcl_BadChannelOption(interp, optionName, "");
  1565. #endif /*TCL_FEATURE_KEEPALIVE_NAGLE*/
  1566. }
  1567. /*
  1568. *----------------------------------------------------------------------
  1569. *
  1570. * TcpGetOptionProc --
  1571. *
  1572. * Computes an option value for a TCP socket based channel, or a list of
  1573. * all options and their values.
  1574. *
  1575. * Note: This code is based on code contributed by John Haxby.
  1576. *
  1577. * Results:
  1578. * A standard Tcl result. The value of the specified option or a list of
  1579. * all options and their values is returned in the supplied DString.
  1580. *
  1581. * Side effects:
  1582. * None.
  1583. *
  1584. *----------------------------------------------------------------------
  1585. */
  1586. static int
  1587. TcpGetOptionProc(
  1588. ClientData instanceData, /* Socket state. */
  1589. Tcl_Interp *interp, /* For error reporting - can be NULL */
  1590. const char *optionName, /* Name of the option to retrieve the value
  1591. * for, or NULL to get all options and their
  1592. * values. */
  1593. Tcl_DString *dsPtr) /* Where to store the computed value;
  1594. * initialized by caller. */
  1595. {
  1596. SocketInfo *infoPtr;
  1597. SOCKADDR_IN sockname;
  1598. SOCKADDR_IN peername;
  1599. struct hostent *hostEntPtr;
  1600. SOCKET sock;
  1601. int size = sizeof(SOCKADDR_IN);
  1602. size_t len = 0;
  1603. char buf[TCL_INTEGER_SPACE];
  1604. /*
  1605. * Check that WinSock is initialized; do not call it if not, to prevent
  1606. * system crashes. This can happen at exit time if the exit handler for
  1607. * WinSock ran before other exit handlers that want to use sockets.
  1608. */
  1609. if (!SocketsEnabled()) {
  1610. if (interp) {
  1611. Tcl_AppendResult(interp, "winsock is not initialized", NULL);
  1612. }
  1613. return TCL_ERROR;
  1614. }
  1615. infoPtr = (SocketInfo *) instanceData;
  1616. sock = (int) infoPtr->socket;
  1617. if (optionName != NULL) {
  1618. len = strlen(optionName);
  1619. }
  1620. if ((len > 1) && (optionName[1] == 'e') &&
  1621. (strncmp(optionName, "-error", len) == 0)) {
  1622. int optlen;
  1623. DWORD err;
  1624. int ret;
  1625. optlen = sizeof(int);
  1626. ret = TclWinGetSockOpt((int)sock, SOL_SOCKET, SO_ERROR,
  1627. (char *)&err, &optlen);
  1628. if (ret == SOCKET_ERROR) {
  1629. err = WSAGetLastError();
  1630. }
  1631. if (err) {
  1632. TclWinConvertWSAError(err);
  1633. Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(Tcl_GetErrno()), -1);
  1634. }
  1635. return TCL_O

Large files files are truncated, but you can click here to view the full file