Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2321 lines
57 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. socket.c
  5. Abstract:
  6. Contains functions to create, delete and manipulate IPX sockets and SPX
  7. connections
  8. Contents:
  9. CreateSocket
  10. AllocateTemporarySocket
  11. QueueSocket
  12. DequeueSocket
  13. FindSocket
  14. FindActiveSocket
  15. ReopenSocket
  16. KillSocket
  17. KillShortLivedSockets
  18. AllocateConnection
  19. DeallocateConnection
  20. FindConnection
  21. QueueConnection
  22. DequeueConnection
  23. KillConnection
  24. AbortOrTerminateConnection
  25. CheckPendingSpxRequests
  26. (CheckSocketState)
  27. (CheckSelectRead)
  28. (CheckSelectWrite)
  29. (AsyncReadAction)
  30. (AsyncWriteAction)
  31. (CompleteAccept)
  32. (CompleteReceive)
  33. (CompleteConnect)
  34. (CompleteSend)
  35. Author:
  36. Richard L Firth (rfirth) 25-Oct-1993
  37. Environment:
  38. User-mode Win32
  39. Revision History:
  40. 25-Oct-1993 rfirth
  41. Created
  42. --*/
  43. #include "vw.h"
  44. #pragma hdrstop
  45. //
  46. // miscellaneous manifests
  47. //
  48. #define ARBITRARY_CONNECTION_INCREMENT 2
  49. //
  50. // macros
  51. //
  52. #define ALLOCATE_CONNECTION_NUMBER() (ConnectionNumber += ARBITRARY_CONNECTION_INCREMENT)
  53. //
  54. // private data
  55. //
  56. PRIVATE LPSOCKET_INFO SocketList = NULL;
  57. PRIVATE LPCONNECTION_INFO ConnectionList = NULL;
  58. PRIVATE WORD ConnectionNumber = ARBITRARY_CONNECTION_NUMBER;
  59. //
  60. // private functions
  61. //
  62. PRIVATE
  63. BOOL
  64. CheckSocketState(
  65. IN SOCKET Socket,
  66. OUT LPBOOL Readable,
  67. OUT LPBOOL Writeable,
  68. OUT LPBOOL Error
  69. );
  70. PRIVATE
  71. VOID
  72. CheckSelectRead(
  73. IN LPSOCKET_INFO pSocketInfo,
  74. IN LPCONNECTION_INFO pConnectionInfo,
  75. OUT BOOL *CheckRead
  76. );
  77. PRIVATE
  78. VOID
  79. CheckSelectWrite(
  80. IN LPSOCKET_INFO pSocketInfo,
  81. IN LPCONNECTION_INFO pConnectionInfo,
  82. OUT BOOL *CheckWrite
  83. );
  84. PRIVATE
  85. VOID
  86. AsyncReadAction(
  87. IN LPSOCKET_INFO pSocketInfo,
  88. IN LPCONNECTION_INFO pConnectionInfo,
  89. OUT BOOL *ReadPerformed
  90. );
  91. PRIVATE
  92. VOID
  93. AsyncWriteAction(
  94. IN LPSOCKET_INFO pSocketInfo,
  95. IN LPCONNECTION_INFO pConnectionInfo,
  96. OUT BOOL *WritePerformed
  97. );
  98. PRIVATE
  99. VOID
  100. CompleteAccept(
  101. IN LPSOCKET_INFO pSocketInfo,
  102. IN LPCONNECTION_INFO pConnectionInfo
  103. );
  104. PRIVATE
  105. VOID
  106. CompleteReceive(
  107. IN LPSOCKET_INFO pSocketInfo,
  108. IN LPCONNECTION_INFO pConnectionInfo
  109. );
  110. PRIVATE
  111. VOID
  112. CompleteConnect(
  113. IN LPSOCKET_INFO pSocketInfo,
  114. IN LPCONNECTION_INFO pConnectionInfo
  115. );
  116. PRIVATE
  117. VOID
  118. CompleteSend(
  119. IN LPSOCKET_INFO pSocketInfo,
  120. IN LPCONNECTION_INFO pConnectionInfo
  121. );
  122. #if SPX_HACK
  123. PRIVATE VOID ModifyFirstReceive(LPBYTE, LPDWORD, WORD, SOCKET);
  124. #endif
  125. //
  126. // public functions
  127. //
  128. int
  129. CreateSocket(
  130. IN SOCKET_TYPE SocketType,
  131. IN OUT ULPWORD pSocketNumber,
  132. OUT SOCKET* pSocket
  133. )
  134. /*++
  135. Routine Description:
  136. Creates a socket for IPX or SPX (a connection). Once the socket is created
  137. we have to bind it to the IPX/SPX 'socket' - i.e. port. We also need to
  138. change a few things about the standard socket:
  139. * if this is an SPX request then we must set the REUSEADDR socket option
  140. since there may typically be several connect requests over the same
  141. WinSock socket: we need to be able to bind multiple connections to the
  142. same socket number
  143. * all sockets opened by this function are put into non-blocking mode
  144. * all sockets opened by this function will return the packet header in
  145. any received data (IPX_RECVHDR)
  146. The requested socket number can be 0 in which case we bind to a dynamic
  147. socket number. We always return the number of the socket bound to: if not 0
  148. on input, this should always be the same value as that requested in
  149. pSocketNumber
  150. If any WinSock call fails (and the socket was created) then we close the
  151. socket before returning
  152. Arguments:
  153. SocketType - SOCKET_TYPE_IPX or SOCKET_TYPE_SPX
  154. pSocketNumber - input: socket number to bind (can be 0)
  155. output: socket number bound
  156. pSocket - pointer to address of socket identifier to return
  157. Return Value:
  158. int
  159. Success - IPX_SUCCESS/SPX_SUCCESS (0)
  160. Failure - IPX_SOCKET_TABLE_FULL
  161. WinSock cannot create the socket
  162. IPX_SOCKET_ALREADY_OPEN
  163. Assume the request was for an IPX socket: we do not allow
  164. multiple IPX sockets to be bound to the same socket number,
  165. only SPX
  166. --*/
  167. {
  168. SOCKET s;
  169. SOCKADDR_IPX socketAddress;
  170. BOOL true = TRUE;
  171. int rc;
  172. int status = IPX_SOCKET_TABLE_FULL; // default error
  173. s = socket(AF_IPX,
  174. (SocketType == SOCKET_TYPE_SPX) ? SOCK_SEQPACKET : SOCK_DGRAM,
  175. (SocketType == SOCKET_TYPE_SPX) ? NSPROTO_SPX : NSPROTO_IPX
  176. );
  177. if (s != INVALID_SOCKET) {
  178. //
  179. // for stream (SPX) sockets, we need multiple sockets bound to the
  180. // same socket number if we are to have multiple connections on the
  181. // same SPX socket
  182. //
  183. if (SocketType == SOCKET_TYPE_SPX) {
  184. rc = setsockopt(s,
  185. SOL_SOCKET,
  186. SO_REUSEADDR,
  187. (char FAR*)&true,
  188. sizeof(true)
  189. );
  190. if (rc == SOCKET_ERROR) {
  191. IPXDBGPRINT((__FILE__, __LINE__,
  192. FUNCTION_ANY,
  193. IPXDBG_LEVEL_ERROR,
  194. "CreateSocket: setsockopt(SO_REUSEADDR) returns %d\n",
  195. WSAGetLastError()
  196. ));
  197. } else {
  198. rc = setsockopt(s,
  199. SOL_SOCKET,
  200. SO_OOBINLINE,
  201. (char FAR*)&true,
  202. sizeof(true)
  203. );
  204. if (rc == SOCKET_ERROR) {
  205. IPXDBGPRINT((__FILE__, __LINE__,
  206. FUNCTION_ANY,
  207. IPXDBG_LEVEL_ERROR,
  208. "CreateSocket: setsockopt(SO_OOBINLINE) returns %d\n",
  209. WSAGetLastError()
  210. ));
  211. }
  212. }
  213. } else {
  214. //
  215. // allow broadcasts to be transmitted on IPX sockets
  216. //
  217. rc = setsockopt(s,
  218. SOL_SOCKET,
  219. SO_BROADCAST,
  220. (char FAR*)&true,
  221. sizeof(true)
  222. );
  223. }
  224. if (!rc) {
  225. //
  226. // bind the socket to the local socket number (port)
  227. //
  228. ZeroMemory(&socketAddress, sizeof(socketAddress));
  229. socketAddress.sa_family = AF_IPX;
  230. socketAddress.sa_socket = *pSocketNumber;
  231. rc = bind(s, (LPSOCKADDR)&socketAddress, sizeof(socketAddress));
  232. if (rc != SOCKET_ERROR) {
  233. int length = sizeof(socketAddress);
  234. ZeroMemory(&socketAddress, sizeof(socketAddress));
  235. socketAddress.sa_family = AF_IPX;
  236. //
  237. // use getsockname() to find the (big-endian) socket value that
  238. // was actually assigned: should only be different from
  239. // *pSocketNumber if the latter was 0 on input
  240. //
  241. rc = getsockname(s, (LPSOCKADDR)&socketAddress, &length);
  242. if (rc != SOCKET_ERROR) {
  243. u_long arg = !0;
  244. //
  245. // put the socket into non-blocking mode. Neither IPX nor
  246. // SPX sockets are blocking: the app starts an I/O request
  247. // and if it doesn't complete immediately, will be completed
  248. // by AES which periodically polls the outstanding I/O
  249. // requests
  250. //
  251. rc = ioctlsocket(s, FIONBIO, &arg);
  252. if (rc != SOCKET_ERROR) {
  253. //
  254. // return protocol header on receive frames
  255. //
  256. rc = setsockopt(s,
  257. NSPROTO_IPX,
  258. IPX_RECVHDR,
  259. (char FAR*)&true,
  260. sizeof(true)
  261. );
  262. if (rc != SOCKET_ERROR) {
  263. *pSocketNumber = socketAddress.sa_socket;
  264. *pSocket = s;
  265. status = IPX_SUCCESS;
  266. } else {
  267. IPXDBGPRINT((__FILE__, __LINE__,
  268. FUNCTION_ANY,
  269. IPXDBG_LEVEL_ERROR,
  270. "CreateSocket: setsockopt(RECVHDR) returns %d\n",
  271. WSAGetLastError()
  272. ));
  273. }
  274. } else {
  275. IPXDBGPRINT((__FILE__, __LINE__,
  276. FUNCTION_ANY,
  277. IPXDBG_LEVEL_ERROR,
  278. "CreateSocket: ioctlsocket(FIONBIO) returns %d\n",
  279. WSAGetLastError()
  280. ));
  281. }
  282. } else {
  283. IPXDBGPRINT((__FILE__, __LINE__,
  284. FUNCTION_ANY,
  285. IPXDBG_LEVEL_ERROR,
  286. "CreateSocket: getsockname() returns %d\n",
  287. WSAGetLastError()
  288. ));
  289. }
  290. } else {
  291. //
  292. // bind() failed - either an expected error (the requested socket
  293. // is already in use), or (horror) an unexpected error, in which
  294. // case report table full (?)
  295. //
  296. switch (WSAGetLastError()) {
  297. case WSAEADDRINUSE:
  298. ASSERT(*pSocketNumber != 0);
  299. ASSERT(SocketType == SOCKET_TYPE_IPX);
  300. status = IPX_SOCKET_ALREADY_OPEN;
  301. break;
  302. default:
  303. IPXDBGPRINT((__FILE__, __LINE__,
  304. FUNCTION_ANY,
  305. IPXDBG_LEVEL_ERROR,
  306. "CreateSocket: bind() on socket %#x returns %d\n",
  307. s,
  308. WSAGetLastError()
  309. ));
  310. }
  311. }
  312. }
  313. } else {
  314. //
  315. // the socket() call failed - treat as table full
  316. //
  317. IPXDBGPRINT((__FILE__, __LINE__,
  318. FUNCTION_ANY,
  319. IPXDBG_LEVEL_ERROR,
  320. "CreateSocket: socket() returns %d\n",
  321. WSAGetLastError()
  322. ));
  323. }
  324. if (status != IPX_SUCCESS) {
  325. if (s != INVALID_SOCKET) {
  326. closesocket(s);
  327. }
  328. }
  329. return status;
  330. }
  331. LPSOCKET_INFO
  332. AllocateTemporarySocket(
  333. VOID
  334. )
  335. /*++
  336. Routine Description:
  337. Allocates a temporary socket. Creates an IPX socket having a dynamically
  338. allocated socket number
  339. Arguments:
  340. None.
  341. Return Value:
  342. LPSOCKET_INFO
  343. Success - pointer to SOCKET_INFO structure
  344. Failure - NULL
  345. --*/
  346. {
  347. LPSOCKET_INFO pSocketInfo;
  348. int rc;
  349. pSocketInfo = AllocateSocket();
  350. if (pSocketInfo) {
  351. //
  352. // assumption: the SOCKET_INFO structure was zeroed by LocalAlloc(LPTR,..
  353. // hence the SocketNumber fields is 0. This causes CreateSocket to
  354. // generate a dynamic socket number
  355. //
  356. rc = CreateSocket(SOCKET_TYPE_IPX,
  357. &pSocketInfo->SocketNumber,
  358. &pSocketInfo->Socket
  359. );
  360. if (rc == IPX_SUCCESS) {
  361. pSocketInfo->Flags |= SOCKET_FLAG_TEMPORARY;
  362. } else {
  363. DeallocateSocket(pSocketInfo);
  364. pSocketInfo = NULL;
  365. }
  366. }
  367. return pSocketInfo;
  368. }
  369. VOID
  370. QueueSocket(
  371. IN LPSOCKET_INFO pSocketInfo
  372. )
  373. /*++
  374. Routine Description:
  375. Add a SOCKET_INFO structure to the list (LIFO) of (opened) sockets
  376. Arguments:
  377. pSocketInfo - pointer to filled-in SOCKET_INFO structure
  378. Return Value:
  379. None.
  380. --*/
  381. {
  382. RequestMutex();
  383. pSocketInfo->Next = SocketList;
  384. SocketList = pSocketInfo;
  385. ReleaseMutex();
  386. }
  387. LPSOCKET_INFO
  388. DequeueSocket(
  389. IN LPSOCKET_INFO pSocketInfo
  390. )
  391. /*++
  392. Routine Description:
  393. Remove a SOCKET_INFO structure from the list
  394. Arguments:
  395. pSocketInfo - pointer to SOCKET_INFO structure to remove
  396. Return Value:
  397. LPSOCKET_INFO
  398. pSocketInfo - should be this value
  399. NULL - couldn't find pSocketInfo (should not get this!)
  400. --*/
  401. {
  402. LPSOCKET_INFO prev, p;
  403. ASSERT(SocketList);
  404. RequestMutex();
  405. prev = (LPSOCKET_INFO)&SocketList;
  406. p = SocketList;
  407. while (p) {
  408. if (p == pSocketInfo) {
  409. prev->Next = p->Next;
  410. p->Next = NULL;
  411. break;
  412. } else {
  413. prev = p;
  414. p = p->Next;
  415. }
  416. }
  417. if (!p) {
  418. //
  419. // should never reach here
  420. //
  421. IPXDBGPRINT((__FILE__, __LINE__,
  422. FUNCTION_ANY,
  423. IPXDBG_LEVEL_FATAL,
  424. "DequeueSocket: can't find socket structure %08x on queue\n",
  425. pSocketInfo
  426. ));
  427. }
  428. ReleaseMutex();
  429. return p;
  430. }
  431. LPSOCKET_INFO
  432. FindSocket(
  433. IN WORD SocketNumber
  434. )
  435. /*++
  436. Routine Description:
  437. Locate a SOCKET_INFO structure in the list, by (big-endian) socket number
  438. Assumes: 1. There is 1 and only 1 SOCKET_INFO structure that contains
  439. SocketNumber
  440. Arguments:
  441. SocketNumber - big-endian socket number to find
  442. Return Value:
  443. LPSOCKET_INFO
  444. NULL - couldn't find requested socket
  445. !NULL - pointer to discovered SOCKET_INFO structure
  446. --*/
  447. {
  448. LPSOCKET_INFO p;
  449. RequestMutex();
  450. p = SocketList;
  451. while (p) {
  452. if (p->SocketNumber == SocketNumber) {
  453. break;
  454. } else {
  455. p = p->Next;
  456. }
  457. }
  458. ReleaseMutex();
  459. return p;
  460. }
  461. LPSOCKET_INFO
  462. FindActiveSocket(
  463. IN LPSOCKET_INFO pSocketInfo
  464. )
  465. /*++
  466. Routine Description:
  467. Find a SOCKET_INFO structure with pending send or receive. Called as FindFirst,
  468. FindNext - first call made with pSocketInfo == NULL: enters critical section
  469. if an active socket is found, returns pointer
  470. Subsequent calls are made with pSocketInfo pointing to last returned
  471. SOCKET_INFO. This continues the search. When search exhausted, critical
  472. section is released
  473. Arguments:
  474. pSocketInfo - pointer to SOCKET_INFO structure: first time must be NULL
  475. Return Value:
  476. LPSOCKET_INFO - next active SOCKET_INFO structure or NULL
  477. --*/
  478. {
  479. if (!pSocketInfo) {
  480. RequestMutex();
  481. pSocketInfo = SocketList;
  482. } else {
  483. pSocketInfo = pSocketInfo->Next;
  484. }
  485. for (; pSocketInfo; pSocketInfo = pSocketInfo->Next) {
  486. if (pSocketInfo->Flags & (SOCKET_FLAG_SENDING | SOCKET_FLAG_LISTENING)) {
  487. return pSocketInfo;
  488. }
  489. }
  490. ReleaseMutex();
  491. return NULL;
  492. }
  493. int
  494. ReopenSocket(
  495. LPSOCKET_INFO pSocketInfo
  496. )
  497. /*++
  498. Routine Description:
  499. Called expressly to close an IPX socket and reassign the descriptor to SPX.
  500. Note that after this function completes, IPXSendPacket and IPXListenForPacket
  501. cannot be made agains the IPX socket
  502. Arguments:
  503. pSocketInfo - pointer to SOCKET_INFO which currently describes an IPX socket
  504. Return Value:
  505. int - return code from CreateSocket
  506. --*/
  507. {
  508. int rc;
  509. rc = closesocket(pSocketInfo->Socket);
  510. if (rc == SOCKET_ERROR) {
  511. IPXDBGPRINT((__FILE__, __LINE__,
  512. FUNCTION_ANY,
  513. IPXDBG_LEVEL_ERROR,
  514. "ReopenSocket: closesocket() returns %d\n",
  515. WSAGetLastError()
  516. ));
  517. }
  518. //
  519. // mark this socket as connection-based (SPX) socket
  520. //
  521. pSocketInfo->SpxSocket = TRUE;
  522. //
  523. // re-open the socket for SPX use
  524. //
  525. return CreateSocket(SOCKET_TYPE_SPX,
  526. &pSocketInfo->SocketNumber,
  527. &pSocketInfo->Socket
  528. );
  529. }
  530. VOID
  531. KillSocket(
  532. IN LPSOCKET_INFO pSocketInfo
  533. )
  534. /*++
  535. Routine Description:
  536. closes a socket, removes the SOCKET_INFO structure from the list and cancels
  537. any pending send, listen or timed events associated with the socket
  538. Arguments:
  539. pSocketInfo - identifying socket to kill
  540. Return Value:
  541. None.
  542. --*/
  543. {
  544. int rc;
  545. //
  546. // remove the SOCKET_INFO structure from the list of sockets. Cancel
  547. // any pending ECB requests and any IPX timed events that have the
  548. // same socket number
  549. //
  550. DequeueSocket(pSocketInfo);
  551. rc = closesocket(pSocketInfo->Socket);
  552. if (rc == SOCKET_ERROR) {
  553. IPXDBGPRINT((__FILE__, __LINE__,
  554. FUNCTION_ANY,
  555. IPXDBG_LEVEL_ERROR,
  556. "KillSocket: closesocket() returns %d\n",
  557. WSAGetLastError()
  558. ));
  559. }
  560. //
  561. // the socket has been removed from SocketList: no need to grab mutex to
  562. // perform the following
  563. //
  564. CancelTimedEvents(pSocketInfo->SocketNumber, 0, 0);
  565. CancelSocketQueue(&pSocketInfo->ListenQueue);
  566. CancelSocketQueue(&pSocketInfo->HeaderQueue);
  567. CancelSocketQueue(&pSocketInfo->SendQueue);
  568. if (pSocketInfo->SpxSocket) {
  569. LPCONNECTION_INFO pConnectionInfo;
  570. while (pConnectionInfo = pSocketInfo->Connections) {
  571. DequeueConnection(pSocketInfo, pConnectionInfo);
  572. KillConnection(pConnectionInfo);
  573. }
  574. }
  575. DeallocateSocket(pSocketInfo);
  576. }
  577. VOID
  578. KillShortLivedSockets(
  579. IN WORD Owner
  580. )
  581. /*++
  582. Routine Description:
  583. For all those sockets created by a DOS process as SHORT_LIVED, terminate
  584. the sockets, cancelling any outstanding ECBs
  585. Arguments:
  586. Owner - DOS PDB which opened sockets
  587. Return Value:
  588. None.
  589. --*/
  590. {
  591. LPSOCKET_INFO pSocketInfo;
  592. IPXDBGPRINT((__FILE__, __LINE__,
  593. FUNCTION_ANY,
  594. IPXDBG_LEVEL_INFO,
  595. "KillShortLivedSockets(%04x)\n",
  596. Owner
  597. ));
  598. RequestMutex();
  599. //
  600. // kill any non-socket (AES) timed events owned by this DOS process
  601. //
  602. CancelTimedEvents(0, Owner, 0);
  603. //
  604. // kill all sockets owned by this PDB
  605. //
  606. pSocketInfo = SocketList;
  607. while (pSocketInfo) {
  608. LPSOCKET_INFO next;
  609. next = pSocketInfo->Next;
  610. if (!pSocketInfo->LongLived && (pSocketInfo->Owner == Owner)) {
  611. IPXDBGPRINT((__FILE__, __LINE__,
  612. FUNCTION_ANY,
  613. IPXDBG_LEVEL_INFO,
  614. "KillShortLivedSockets: Socket %04x owned by %04x\n",
  615. B2LW(pSocketInfo->SocketNumber),
  616. pSocketInfo->Owner
  617. ));
  618. KillSocket(pSocketInfo);
  619. }
  620. pSocketInfo = next;
  621. }
  622. ReleaseMutex();
  623. }
  624. LPCONNECTION_INFO
  625. AllocateConnection(
  626. LPSOCKET_INFO pSocketInfo
  627. )
  628. /*++
  629. Routine Description:
  630. Allocates a CONNECTION_INFO structure. If successful, links it at the head
  631. of ConnectionList
  632. Arguments:
  633. pSocketInfo - pointer to owner SOCKET_INFO
  634. Return Value:
  635. LPCONNECTION_INFO
  636. Success - !NULL
  637. Failure - NULL
  638. --*/
  639. {
  640. LPCONNECTION_INFO pConnectionInfo;
  641. pConnectionInfo = (LPCONNECTION_INFO)LocalAlloc(LPTR, sizeof(*pConnectionInfo));
  642. if (pConnectionInfo) {
  643. RequestMutex();
  644. pConnectionInfo->ConnectionId = ALLOCATE_CONNECTION_NUMBER();
  645. pConnectionInfo->List = ConnectionList;
  646. ConnectionList = pConnectionInfo;
  647. ReleaseMutex();
  648. #if SPX_HACK
  649. pConnectionInfo->Flags = CF_1ST_RECEIVE;
  650. #endif
  651. }
  652. return pConnectionInfo;
  653. }
  654. VOID
  655. DeallocateConnection(
  656. IN LPCONNECTION_INFO pConnectionInfo
  657. )
  658. /*++
  659. Routine Description:
  660. Undoes the work of AllocateConnection - removes pConnectionInfo from
  661. ConnectionList and deallocates the structure
  662. Arguments:
  663. pConnectionInfo - pointer to CONNECTION_INFO to deallocate
  664. Return Value:
  665. None.
  666. --*/
  667. {
  668. LPCONNECTION_INFO p;
  669. LPCONNECTION_INFO prev = (LPCONNECTION_INFO)&ConnectionList;
  670. RequestMutex();
  671. for (p = ConnectionList; p != pConnectionInfo; ) {
  672. prev = p;
  673. p = p->List;
  674. }
  675. //
  676. // if p is NULL or differs from pConnectionInfo then there's a problem
  677. //
  678. ASSERT(p);
  679. //
  680. // special case if pConnectionInfo is first on list: can't say
  681. // &ConnectionList->List - accesses one pointer beyond ConnectionList
  682. // which is WRONG
  683. //
  684. if (prev == (LPCONNECTION_INFO)&ConnectionList) {
  685. ConnectionList = p->List;
  686. } else {
  687. prev->List = p->List;
  688. }
  689. FREE_OBJECT(pConnectionInfo);
  690. ReleaseMutex();
  691. }
  692. LPCONNECTION_INFO
  693. FindConnection(
  694. IN WORD ConnectionId
  695. )
  696. /*++
  697. Routine Description:
  698. Returns a pointer to CONNECTION_INFO given a unique connection ID
  699. Arguments:
  700. ConnectionId - value to find
  701. Return Value:
  702. LPCONNECTION_INFO
  703. Success - !NULL
  704. Failure - NULL
  705. --*/
  706. {
  707. LPCONNECTION_INFO pConnectionInfo;
  708. RequestMutex();
  709. for (pConnectionInfo = ConnectionList; pConnectionInfo; ) {
  710. if (pConnectionInfo->ConnectionId == ConnectionId) {
  711. break;
  712. } else {
  713. pConnectionInfo = pConnectionInfo->List;
  714. }
  715. }
  716. ReleaseMutex();
  717. return pConnectionInfo;
  718. }
  719. VOID
  720. QueueConnection(
  721. IN LPSOCKET_INFO pSocketInfo,
  722. IN LPCONNECTION_INFO pConnectionInfo
  723. )
  724. /*++
  725. Routine Description:
  726. Adds a CONNECTION_INFO to the list of connections owned by a SOCKET_INFO.
  727. Points the CONNECTION_INFO back to the SOCKET_INFO
  728. Arguments:
  729. pSocketInfo - owning SOCKET_INFO
  730. pConnectionInfo - CONNECTION_INFO to add
  731. Return Value:
  732. None.
  733. --*/
  734. {
  735. pConnectionInfo->Next = pSocketInfo->Connections;
  736. pSocketInfo->Connections = pConnectionInfo;
  737. pConnectionInfo->OwningSocket = pSocketInfo;
  738. }
  739. LPCONNECTION_INFO
  740. DequeueConnection(
  741. IN LPSOCKET_INFO pSocketInfo,
  742. IN LPCONNECTION_INFO pConnectionInfo
  743. )
  744. /*++
  745. Routine Description:
  746. Removes a CONNECTION_INFO from the list of connections owned by a SOCKET_INFO
  747. Arguments:
  748. pSocketInfo - owning SOCKET_INFO
  749. pConnectionInfo - CONNECTION_INFO to remove
  750. Return Value:
  751. LPCONNECTION_INFO
  752. Success - pointer to removed CONNECTION_INFO (should be same as
  753. pConnectionInfo)
  754. Failure - NULL (not expected)
  755. --*/
  756. {
  757. LPCONNECTION_INFO prev = (LPCONNECTION_INFO)&pSocketInfo->Connections;
  758. LPCONNECTION_INFO p = prev->Next;
  759. while (p && p != pConnectionInfo) {
  760. prev = p;
  761. p = p->Next;
  762. }
  763. ASSERT(p == pConnectionInfo);
  764. prev->Next = p->Next;
  765. p->OwningSocket = NULL;
  766. return p;
  767. }
  768. VOID
  769. KillConnection(
  770. IN LPCONNECTION_INFO pConnectionInfo
  771. )
  772. /*++
  773. Routine Description:
  774. Closes a socket belonging to a connection and cancels all outstanding
  775. requests. The CONNECTION_INFO is deallocated
  776. Arguments:
  777. pConnectionInfo - pointer to CONNECTION_INFO to kill
  778. Return Value:
  779. None.
  780. --*/
  781. {
  782. if (pConnectionInfo->Socket) {
  783. closesocket(pConnectionInfo->Socket);
  784. }
  785. CancelConnectionQueue(&pConnectionInfo->ConnectQueue);
  786. CancelConnectionQueue(&pConnectionInfo->AcceptQueue);
  787. CancelConnectionQueue(&pConnectionInfo->ListenQueue);
  788. CancelConnectionQueue(&pConnectionInfo->SendQueue);
  789. DeallocateConnection(pConnectionInfo);
  790. }
  791. VOID
  792. AbortOrTerminateConnection(
  793. IN LPCONNECTION_INFO pConnectionInfo,
  794. IN BYTE CompletionCode
  795. )
  796. /*++
  797. Routine Description:
  798. Aborts or terminates a connection: closes the socket, dequeues and completes
  799. all outstanding ECBs with relevant code and deallocates the CONNECTION_INFO
  800. structure
  801. The CONNECTION_INFO must NOT be queued on a SOCKET_INFO when this routine
  802. is called
  803. Arguments:
  804. pConnectionInfo - pointer to CONNECTION_INFO to kill
  805. CompletionCode - completion code to put in pending ECBs
  806. Return Value:
  807. None.
  808. --*/
  809. {
  810. if (pConnectionInfo->Socket) {
  811. closesocket(pConnectionInfo->Socket);
  812. }
  813. AbortQueue(&pConnectionInfo->ConnectQueue, CompletionCode);
  814. AbortQueue(&pConnectionInfo->AcceptQueue, CompletionCode);
  815. AbortQueue(&pConnectionInfo->ListenQueue, CompletionCode);
  816. AbortQueue(&pConnectionInfo->SendQueue, CompletionCode);
  817. DeallocateConnection(pConnectionInfo);
  818. }
  819. VOID
  820. CheckPendingSpxRequests(
  821. BOOL *pfOperationPerformed
  822. )
  823. /*++
  824. Routine Description:
  825. Checks the open non-blocking SPX sockets for:
  826. errors
  827. outgoing established connections (connect)
  828. incoming established connections (listen/accept)
  829. data to receive (recv)
  830. send completions (send)
  831. Arguments:
  832. None.
  833. Return Value:
  834. None.
  835. --*/
  836. {
  837. LPSOCKET_INFO pSocketInfo;
  838. *pfOperationPerformed = FALSE ;
  839. RequestMutex();
  840. pSocketInfo = SocketList;
  841. while (pSocketInfo) {
  842. if (pSocketInfo->SpxSocket) {
  843. LPCONNECTION_INFO pConnectionInfo;
  844. pConnectionInfo = pSocketInfo->Connections;
  845. while (pConnectionInfo) {
  846. LPCONNECTION_INFO next;
  847. //
  848. // pluck out the Next field now, in case this CONNECTION_INFO
  849. // is destroyed as the result of an error
  850. //
  851. next = pConnectionInfo->Next;
  852. //
  853. // if this connection has an active socket or we have issued
  854. // SPXListenForConnection against the socket then check the
  855. // state
  856. //
  857. if (pConnectionInfo->Socket
  858. || (pConnectionInfo->State == CI_WAITING)) {
  859. SOCKET sock;
  860. BOOL readable;
  861. BOOL writeable;
  862. BOOL sockError;
  863. CheckSelectRead(pSocketInfo,
  864. pConnectionInfo,
  865. &readable);
  866. CheckSelectWrite(pSocketInfo,
  867. pConnectionInfo,
  868. &writeable);
  869. sock = pConnectionInfo->Socket
  870. ? pConnectionInfo->Socket
  871. : pSocketInfo->Socket
  872. ;
  873. if (CheckSocketState(sock, &readable, &writeable, &sockError)) {
  874. if (!sockError) {
  875. if (readable) {
  876. AsyncReadAction(pSocketInfo,
  877. pConnectionInfo,
  878. pfOperationPerformed);
  879. }
  880. if (writeable) {
  881. AsyncWriteAction(pSocketInfo,
  882. pConnectionInfo,
  883. pfOperationPerformed);
  884. }
  885. } else {
  886. IPXDBGPRINT((__FILE__, __LINE__,
  887. FUNCTION_ANY,
  888. IPXDBG_LEVEL_ERROR,
  889. "CheckPendingSpxRequests: socket %x has error. Connection %08x state %d\n",
  890. sock,
  891. pConnectionInfo,
  892. pConnectionInfo->State
  893. ));
  894. //
  895. // irrespective of the error, we just abort any
  896. // connection that gets an error
  897. //
  898. DequeueConnection(pConnectionInfo->OwningSocket,
  899. pConnectionInfo
  900. );
  901. AbortOrTerminateConnection(pConnectionInfo,
  902. ECB_CC_CONNECTION_ABORTED
  903. );
  904. }
  905. } else {
  906. IPXDBGPRINT((__FILE__, __LINE__,
  907. FUNCTION_ANY,
  908. IPXDBG_LEVEL_ERROR,
  909. "CheckPendingSpxRequests: CheckSocketState returns %d\n",
  910. WSAGetLastError()
  911. ));
  912. }
  913. } else {
  914. IPXDBGPRINT((__FILE__, __LINE__,
  915. FUNCTION_ANY,
  916. IPXDBG_LEVEL_ERROR,
  917. "CheckPendingSpxRequests: connection %04x (%08x) in weird state?\n",
  918. pConnectionInfo->ConnectionId,
  919. pConnectionInfo
  920. ));
  921. }
  922. pConnectionInfo = next;
  923. }
  924. }
  925. pSocketInfo = pSocketInfo->Next;
  926. }
  927. ReleaseMutex();
  928. }
  929. PRIVATE
  930. BOOL
  931. CheckSocketState(
  932. IN SOCKET Socket,
  933. OUT LPBOOL Readable,
  934. OUT LPBOOL Writeable,
  935. OUT LPBOOL Error
  936. )
  937. /*++
  938. Routine Description:
  939. Given a socket descriptor, checks to see if it is in one of the following
  940. states:
  941. readable - if waiting for a connection, connection has been made
  942. else if established, data is ready to be received
  943. writeable - if waiting to make a connection, connection has been
  944. made, else if established, we can send data on this
  945. socket
  946. error - some error has occurred on the socket
  947. Arguments:
  948. Socket - socket descriptor to check
  949. Readable - returned TRUE if readable
  950. Writeable - returned TRUE if writeable
  951. Error - returned TRUE if error on socket
  952. Return Value:
  953. BOOL
  954. TRUE - contents of Readable, Writeable and Error are valid
  955. FALSE - an error occurred performing the select
  956. --*/
  957. {
  958. fd_set errors;
  959. fd_set reads;
  960. fd_set writes;
  961. int n;
  962. static struct timeval timeout = {0, 0};
  963. FD_ZERO(&errors);
  964. FD_ZERO(&reads);
  965. FD_ZERO(&writes);
  966. if (*Readable)
  967. FD_SET(Socket, &reads);
  968. if (*Writeable)
  969. FD_SET(Socket, &writes);
  970. FD_SET(Socket, &errors);
  971. n = select(0, &reads, &writes, &errors, &timeout);
  972. if (n != SOCKET_ERROR) {
  973. *Readable = (BOOL)(reads.fd_count == 1);
  974. *Writeable = (BOOL)(writes.fd_count == 1);
  975. *Error = (BOOL)(errors.fd_count == 1);
  976. return TRUE;
  977. } else if (n) {
  978. IPXDBGPRINT((__FILE__, __LINE__,
  979. FUNCTION_ANY,
  980. IPXDBG_LEVEL_INFO,
  981. "CheckSocketState: select returns %d\n",
  982. WSAGetLastError()
  983. ));
  984. }
  985. return FALSE;
  986. }
  987. PRIVATE
  988. VOID
  989. AsyncReadAction(
  990. IN LPSOCKET_INFO pSocketInfo,
  991. IN LPCONNECTION_INFO pConnectionInfo,
  992. OUT BOOL *ReadPerformed
  993. )
  994. /*++
  995. Routine Description:
  996. A connection has some read action to complete - complete a pending
  997. SPXListenForConnection or SPXListenForSequencedPacket
  998. Arguments:
  999. pSocketInfo - pointer to SOCKET_INFO
  1000. pConnectionInfo - pointer to CONNECTION_INFO
  1001. Return Value:
  1002. None.
  1003. --*/
  1004. {
  1005. *ReadPerformed = FALSE ;
  1006. switch (pConnectionInfo->State) {
  1007. case CI_STARTING:
  1008. IPXDBGPRINT((__FILE__, __LINE__,
  1009. FUNCTION_ANY,
  1010. IPXDBG_LEVEL_INFO,
  1011. "AsyncReadAction: STARTING connection %04x (%08x) readable\n",
  1012. pConnectionInfo->ConnectionId,
  1013. pConnectionInfo
  1014. ));
  1015. break;
  1016. case CI_WAITING:
  1017. if (pConnectionInfo->AcceptQueue.Head) {
  1018. CompleteAccept(pSocketInfo, pConnectionInfo);
  1019. *ReadPerformed = TRUE ;
  1020. } else {
  1021. IPXDBGPRINT((__FILE__, __LINE__,
  1022. FUNCTION_ANY,
  1023. IPXDBG_LEVEL_ERROR,
  1024. "AsyncReadAction: connection %04x (%08x): no AcceptQueue\n",
  1025. pConnectionInfo->ConnectionId,
  1026. pConnectionInfo
  1027. ));
  1028. }
  1029. break;
  1030. case CI_ESTABLISHED:
  1031. if (pSocketInfo->ListenQueue.Head) {
  1032. CompleteReceive(pSocketInfo, pConnectionInfo);
  1033. *ReadPerformed = TRUE ;
  1034. } else {
  1035. IPXDBGPRINT((__FILE__, __LINE__,
  1036. FUNCTION_ANY,
  1037. IPXDBG_LEVEL_WARNING,
  1038. "AsyncReadAction: connection %04x (%08x): no ListenQueue\n",
  1039. pConnectionInfo->ConnectionId,
  1040. pConnectionInfo
  1041. ));
  1042. }
  1043. break;
  1044. case CI_TERMINATING:
  1045. IPXDBGPRINT((__FILE__, __LINE__,
  1046. FUNCTION_ANY,
  1047. IPXDBG_LEVEL_INFO,
  1048. "AsyncReadAction: TERMINATING connection %04x (%08x) readable\n",
  1049. pConnectionInfo->ConnectionId,
  1050. pConnectionInfo
  1051. ));
  1052. break;
  1053. }
  1054. }
  1055. PRIVATE
  1056. VOID
  1057. AsyncWriteAction(
  1058. IN LPSOCKET_INFO pSocketInfo,
  1059. IN LPCONNECTION_INFO pConnectionInfo,
  1060. OUT BOOL *WritePerformed
  1061. )
  1062. /*++
  1063. Routine Description:
  1064. A connection has some write action to complete - complete a pending
  1065. SPXEstablishConnection or SPXSendSequencedPacket
  1066. Arguments:
  1067. pSocketInfo - pointer to SOCKET_INFO
  1068. pConnectionInfo - pointer to CONNECTION_INFO
  1069. Return Value:
  1070. None.
  1071. --*/
  1072. {
  1073. *WritePerformed = FALSE ;
  1074. switch (pConnectionInfo->State) {
  1075. case CI_STARTING:
  1076. if (pConnectionInfo->ConnectQueue.Head) {
  1077. CompleteConnect(pSocketInfo, pConnectionInfo);
  1078. *WritePerformed = TRUE ;
  1079. } else {
  1080. IPXDBGPRINT((__FILE__, __LINE__,
  1081. FUNCTION_ANY,
  1082. IPXDBG_LEVEL_ERROR,
  1083. "AsyncWriteAction: connection %04x (%08x): no ConnectQueue\n",
  1084. pConnectionInfo->ConnectionId,
  1085. pConnectionInfo
  1086. ));
  1087. }
  1088. break;
  1089. case CI_WAITING:
  1090. IPXDBGPRINT((__FILE__, __LINE__,
  1091. FUNCTION_ANY,
  1092. IPXDBG_LEVEL_INFO,
  1093. "AsyncWriteAction: WAITING connection %04x (%08x) is writeable\n",
  1094. pConnectionInfo->ConnectionId,
  1095. pConnectionInfo
  1096. ));
  1097. break;
  1098. case CI_ESTABLISHED:
  1099. if (pConnectionInfo->SendQueue.Head) {
  1100. CompleteSend(pSocketInfo, pConnectionInfo);
  1101. *WritePerformed = TRUE ;
  1102. } else {
  1103. /*
  1104. IPXDBGPRINT((__FILE__, __LINE__,
  1105. FUNCTION_ANY,
  1106. IPXDBG_LEVEL_WARNING,
  1107. "AsyncWriteAction: connection %04x (%08x): no SendQueue\n",
  1108. pConnectionInfo->ConnectionId,
  1109. pConnectionInfo
  1110. ));
  1111. */
  1112. }
  1113. break;
  1114. case CI_TERMINATING:
  1115. IPXDBGPRINT((__FILE__, __LINE__,
  1116. FUNCTION_ANY,
  1117. IPXDBG_LEVEL_INFO,
  1118. "AsyncWriteAction: TERMINATING connection %04x (%08x) writeable\n",
  1119. pConnectionInfo->ConnectionId,
  1120. pConnectionInfo
  1121. ));
  1122. break;
  1123. }
  1124. }
  1125. PRIVATE
  1126. VOID
  1127. CheckSelectRead(
  1128. IN LPSOCKET_INFO pSocketInfo,
  1129. IN LPCONNECTION_INFO pConnectionInfo,
  1130. OUT BOOL *CheckRead
  1131. )
  1132. /*++
  1133. Routine Description:
  1134. See if want to check for Read readiness in select statement.
  1135. Arguments:
  1136. pSocketInfo - pointer to SOCKET_INFO
  1137. pConnectionInfo - pointer to CONNECTION_INFO
  1138. Return Value:
  1139. None.
  1140. --*/
  1141. {
  1142. *CheckRead = FALSE ;
  1143. switch (pConnectionInfo->State)
  1144. {
  1145. case CI_WAITING:
  1146. if (pConnectionInfo->AcceptQueue.Head)
  1147. *CheckRead = TRUE ;
  1148. break;
  1149. case CI_ESTABLISHED:
  1150. if (pSocketInfo->ListenQueue.Head)
  1151. *CheckRead = TRUE ;
  1152. break;
  1153. default:
  1154. break;
  1155. }
  1156. }
  1157. PRIVATE
  1158. VOID
  1159. CheckSelectWrite(
  1160. IN LPSOCKET_INFO pSocketInfo,
  1161. IN LPCONNECTION_INFO pConnectionInfo,
  1162. OUT BOOL *CheckWrite
  1163. )
  1164. /*++
  1165. Routine Description:
  1166. See if want to check for Write readiness in select statement.
  1167. Arguments:
  1168. pSocketInfo - pointer to SOCKET_INFO
  1169. pConnectionInfo - pointer to CONNECTION_INFO
  1170. Return Value:
  1171. None.
  1172. --*/
  1173. {
  1174. *CheckWrite = FALSE ;
  1175. switch (pConnectionInfo->State)
  1176. {
  1177. case CI_STARTING:
  1178. if (pConnectionInfo->ConnectQueue.Head)
  1179. *CheckWrite = TRUE ;
  1180. break;
  1181. case CI_ESTABLISHED:
  1182. if (pConnectionInfo->SendQueue.Head)
  1183. *CheckWrite = TRUE ;
  1184. break;
  1185. default:
  1186. break;
  1187. }
  1188. }
  1189. PRIVATE
  1190. VOID
  1191. CompleteAccept(
  1192. IN LPSOCKET_INFO pSocketInfo,
  1193. IN LPCONNECTION_INFO pConnectionInfo
  1194. )
  1195. /*++
  1196. Routine Description:
  1197. Complete a SPXListenForConnection
  1198. Arguments:
  1199. pSocketInfo - pointer to SOCKET_INFO
  1200. pConnectionInfo - pointer to CONNECTION_INFO
  1201. Return Value:
  1202. None.
  1203. --*/
  1204. {
  1205. SOCKET conn;
  1206. SOCKADDR_IPX remoteAddress;
  1207. int addressLength = sizeof(remoteAddress);
  1208. LPXECB pXecb = pConnectionInfo->AcceptQueue.Head;
  1209. BOOL true = TRUE;
  1210. int rc;
  1211. conn = accept(pSocketInfo->Socket, (LPSOCKADDR)&remoteAddress, &addressLength);
  1212. if (conn != SOCKET_ERROR) {
  1213. IPXDBGPRINT((__FILE__, __LINE__,
  1214. FUNCTION_ANY,
  1215. IPXDBG_LEVEL_INFO,
  1216. "CompleteAccept: connection %04x (%08x) socket=%x\n",
  1217. pConnectionInfo->ConnectionId,
  1218. pConnectionInfo,
  1219. conn
  1220. ));
  1221. //
  1222. // we want to receive the frame headers from this socket
  1223. //
  1224. rc = setsockopt(conn,
  1225. NSPROTO_IPX,
  1226. IPX_RECVHDR,
  1227. (char FAR*)&true,
  1228. sizeof(true)
  1229. );
  1230. rc = !SOCKET_ERROR;
  1231. if (rc != SOCKET_ERROR) {
  1232. //
  1233. // update the CONNECTION_INFO structure with the actual socket
  1234. // identifier and set the connection state to established
  1235. //
  1236. pConnectionInfo->Socket = conn;
  1237. pConnectionInfo->State = CI_ESTABLISHED;
  1238. //
  1239. // update the app's ECB with the connection ID
  1240. //
  1241. SPX_ECB_CONNECTION_ID(pXecb->Ecb) = pConnectionInfo->ConnectionId;
  1242. //
  1243. // and with the partner address info
  1244. //
  1245. CopyMemory(&pXecb->Ecb->DriverWorkspace,
  1246. &remoteAddress.sa_netnum,
  1247. sizeof(pXecb->Ecb->DriverWorkspace)
  1248. );
  1249. //
  1250. // fill in the immediate address field
  1251. //
  1252. CopyMemory(&pXecb->Ecb->ImmediateAddress,
  1253. &remoteAddress.sa_nodenum,
  1254. sizeof(pXecb->Ecb->ImmediateAddress)
  1255. );
  1256. //
  1257. // remove the XECB from AcceptQueue and complete the SPXListenForConnection ECB
  1258. //
  1259. DequeueEcb(pXecb, &pConnectionInfo->AcceptQueue);
  1260. IPXDUMPECB((pXecb->Ecb,
  1261. HIWORD(pXecb->EcbAddress),
  1262. LOWORD(pXecb->EcbAddress),
  1263. ECB_TYPE_SPX,
  1264. FALSE,
  1265. FALSE,
  1266. IS_PROT_MODE(pXecb)
  1267. ));
  1268. CompleteOrQueueEcb(pXecb, ECB_CC_SUCCESS);
  1269. } else {
  1270. IPXDBGPRINT((__FILE__, __LINE__,
  1271. FUNCTION_ANY,
  1272. IPXDBG_LEVEL_ERROR,
  1273. "CompleteAccept: setsockopt(IPX_RECVHDR) returns %d\n",
  1274. WSAGetLastError()
  1275. ));
  1276. closesocket(conn);
  1277. DequeueEcb(pXecb, &pConnectionInfo->AcceptQueue);
  1278. DequeueConnection(pSocketInfo, pConnectionInfo);
  1279. DeallocateConnection(pConnectionInfo);
  1280. CompleteOrQueueEcb(pXecb, ECB_CC_CONNECTION_ABORTED);
  1281. }
  1282. } else {
  1283. IPXDBGPRINT((__FILE__, __LINE__,
  1284. FUNCTION_ANY,
  1285. IPXDBG_LEVEL_ERROR,
  1286. "CompleteAccept: accept() returns %d\n",
  1287. WSAGetLastError()
  1288. ));
  1289. }
  1290. }
  1291. PRIVATE
  1292. VOID
  1293. CompleteReceive(
  1294. IN LPSOCKET_INFO pSocketInfo,
  1295. IN LPCONNECTION_INFO pConnectionInfo
  1296. )
  1297. /*++
  1298. Routine Description:
  1299. Complete a SPXListenForSequencedPacket
  1300. Arguments:
  1301. pSocketInfo - pointer to SOCKET_INFO
  1302. pConnectionInfo - pointer to CONNECTION_INFO
  1303. Return Value:
  1304. None.
  1305. --*/
  1306. {
  1307. LPXECB pXecb;
  1308. int rc;
  1309. BOOL conn_q;
  1310. LPXECB_QUEUE pQueue;
  1311. int len;
  1312. BOOL completeRequest;
  1313. BYTE status;
  1314. //
  1315. // receive packets while there are listen ECBs and data waiting
  1316. //
  1317. while (1) {
  1318. if (pConnectionInfo->ListenQueue.Head) {
  1319. pQueue = &pConnectionInfo->ListenQueue;
  1320. pXecb = pConnectionInfo->ListenQueue.Head;
  1321. conn_q = TRUE;
  1322. IPXDBGPRINT((__FILE__, __LINE__,
  1323. FUNCTION_ANY,
  1324. IPXDBG_LEVEL_INFO,
  1325. "CompleteReceive: XECB %08x from CONNECTION_INFO %08x\n",
  1326. pXecb,
  1327. pConnectionInfo
  1328. ));
  1329. } else if (pSocketInfo->ListenQueue.Head) {
  1330. pQueue = &pSocketInfo->ListenQueue;
  1331. pXecb = pSocketInfo->ListenQueue.Head;
  1332. conn_q = FALSE;
  1333. IPXDBGPRINT((__FILE__, __LINE__,
  1334. FUNCTION_ANY,
  1335. IPXDBG_LEVEL_INFO,
  1336. "CompleteReceive: XECB %08x from SOCKET_INFO %08x\n",
  1337. pXecb,
  1338. pSocketInfo
  1339. ));
  1340. } else {
  1341. break;
  1342. }
  1343. rc = recv(pConnectionInfo->Socket, pXecb->Data, pXecb->Length, 0);
  1344. if (rc != SOCKET_ERROR) {
  1345. len = rc;
  1346. status = ECB_CC_SUCCESS;
  1347. completeRequest = TRUE;
  1348. } else {
  1349. rc = WSAGetLastError();
  1350. if (rc == WSAEMSGSIZE) {
  1351. len = pXecb->Length;
  1352. status = ECB_CC_PACKET_OVERFLOW;
  1353. completeRequest = TRUE;
  1354. } else {
  1355. completeRequest = FALSE;
  1356. //
  1357. // if no data to receive, quit the loop (don't go down error path)
  1358. //
  1359. if (rc == WSAEWOULDBLOCK) {
  1360. break;
  1361. }
  1362. }
  1363. IPXDBGPRINT((__FILE__, __LINE__,
  1364. FUNCTION_ANY,
  1365. IPXDBG_LEVEL_ERROR,
  1366. "CompleteReceive: error %d on socket %08x (CID %04x)\n",
  1367. rc,
  1368. pConnectionInfo->Socket,
  1369. pConnectionInfo->ConnectionId
  1370. ));
  1371. DUMPXECB(pXecb);
  1372. }
  1373. if( rc == WSAEDISCON ) {
  1374. //
  1375. // handle the disconnect case - we still need to complete the
  1376. // ECB.
  1377. //
  1378. LPSPX_PACKET pPacket = (LPSPX_PACKET)pXecb->Buffer;
  1379. status = ECB_CC_SUCCESS;
  1380. pPacket->DestinationConnectId = pConnectionInfo->ConnectionId;
  1381. pPacket->SourceConnectId = pConnectionInfo->RemoteConnectionId;
  1382. pPacket->DataStreamType = SPX_DS_TERMINATE ;
  1383. pPacket->Checksum = 0xffff;
  1384. pPacket->Length = L2BW(SPX_HEADER_LENGTH);
  1385. pPacket->TransportControl = 0;
  1386. pPacket->PacketType = 5;
  1387. pXecb->Length = SPX_HEADER_LENGTH ;
  1388. ScatterData(pXecb);
  1389. DequeueEcb(pXecb, pQueue);
  1390. //
  1391. // Put the remote node address in the ECB's immediate address
  1392. // field
  1393. //
  1394. CopyMemory(pXecb->Ecb->ImmediateAddress,
  1395. pConnectionInfo->RemoteNode,
  1396. sizeof(pXecb->Ecb->ImmediateAddress)
  1397. );
  1398. CompleteOrQueueIo(pXecb, status);
  1399. DequeueConnection(pConnectionInfo->OwningSocket, pConnectionInfo);
  1400. AbortOrTerminateConnection(pConnectionInfo, ECB_CC_CONNECTION_ABORTED);
  1401. break ;
  1402. }
  1403. else if (completeRequest) {
  1404. #if SPX_HACK
  1405. if (pConnectionInfo->Flags & CF_1ST_RECEIVE) {
  1406. pConnectionInfo->Flags &= ~CF_1ST_RECEIVE;
  1407. ModifyFirstReceive(pXecb->Data, &len, pSocketInfo->SocketNumber, pConnectionInfo->Socket);
  1408. }
  1409. #endif
  1410. IPXDBGPRINT((__FILE__, __LINE__,
  1411. FUNCTION_ANY,
  1412. IPXDBG_LEVEL_INFO,
  1413. "CompleteReceive: recv() on socket %#x returns %d bytes (Addr=%08x)\n",
  1414. pConnectionInfo->Socket,
  1415. len,
  1416. pXecb->Data
  1417. ));
  1418. IPXDUMPDATA((pXecb->Data, 0, 0, FALSE, (WORD)len));
  1419. pXecb->Length -= (USHORT) len;
  1420. pXecb->ActualLength += (USHORT)len;
  1421. pXecb->Data += len;
  1422. if (pXecb->ActualLength >= SPX_HEADER_LENGTH) {
  1423. if (pXecb->Flags & XECB_FLAG_FIRST_RECEIVE) {
  1424. LPSPX_PACKET pPacket = (LPSPX_PACKET)pXecb->Buffer;
  1425. //
  1426. // record in the SPX header the local connection id we invented
  1427. //
  1428. pPacket->DestinationConnectId = pConnectionInfo->ConnectionId;
  1429. //
  1430. // record the actual frame length from the header
  1431. //
  1432. pXecb->FrameLength = B2LW(((LPSPX_PACKET)pXecb->Buffer)->Length);
  1433. pXecb->Flags &= ~XECB_FLAG_FIRST_RECEIVE;
  1434. IPXDBGPRINT((__FILE__, __LINE__,
  1435. FUNCTION_ANY,
  1436. IPXDBG_LEVEL_INFO,
  1437. "CompleteReceive: FrameLength=%x (%d)\n",
  1438. pXecb->FrameLength,
  1439. pXecb->FrameLength
  1440. ));
  1441. }
  1442. //
  1443. // if we received all the data in the packet (according to length
  1444. // field in the SPX header) OR we ran out of buffer space, remove
  1445. // the ECB from its queue and complete it
  1446. //
  1447. if (!pXecb->Length || (pXecb->ActualLength == pXecb->FrameLength)) {
  1448. if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
  1449. //
  1450. // update the XECB.Length field to reflect the amount of
  1451. // data received and copy it to the fragmented buffers
  1452. // in VDM. do not overflow buffer if FrameLength turns
  1453. // out to be larger than we expect.
  1454. //
  1455. pXecb->Length = min(pXecb->FrameLength,
  1456. pXecb->ActualLength);
  1457. ScatterData(pXecb);
  1458. }
  1459. DequeueEcb(pXecb, pQueue);
  1460. // DUMPXECB(pXecb);
  1461. IPXDUMPECB((pXecb->Ecb,
  1462. HIWORD(pXecb->EcbAddress),
  1463. LOWORD(pXecb->EcbAddress),
  1464. ECB_TYPE_SPX,
  1465. TRUE,
  1466. TRUE,
  1467. IS_PROT_MODE(pXecb)
  1468. ));
  1469. //
  1470. // Put the remote node address in the ECB's immediate address
  1471. // field
  1472. //
  1473. CopyMemory(pXecb->Ecb->ImmediateAddress,
  1474. pConnectionInfo->RemoteNode,
  1475. sizeof(pXecb->Ecb->ImmediateAddress)
  1476. );
  1477. CompleteOrQueueIo(pXecb, status);
  1478. } else {
  1479. //
  1480. // partial receive. If the listen ECB came off the socket
  1481. // queue then put it on the connection queue: this is the
  1482. // ECB that will be used for this connection until all data
  1483. // received or we get an error
  1484. //
  1485. if (!conn_q) {
  1486. DequeueEcb(pXecb, &pSocketInfo->ListenQueue);
  1487. QueueEcb(pXecb,
  1488. &pConnectionInfo->ListenQueue,
  1489. CONNECTION_LISTEN_QUEUE
  1490. );
  1491. }
  1492. //
  1493. // not enough data to satisfy read: don't continue yet
  1494. //
  1495. break;
  1496. }
  1497. }
  1498. } else {
  1499. //
  1500. // error occurred - abort the connection
  1501. //
  1502. if (!conn_q) {
  1503. DequeueEcb(pXecb, &pSocketInfo->ListenQueue);
  1504. QueueEcb(pXecb,
  1505. &pConnectionInfo->ListenQueue,
  1506. CONNECTION_LISTEN_QUEUE
  1507. );
  1508. }
  1509. DequeueConnection(pConnectionInfo->OwningSocket, pConnectionInfo);
  1510. AbortOrTerminateConnection(pConnectionInfo, ECB_CC_CONNECTION_ABORTED);
  1511. //
  1512. // don't continue in this case
  1513. //
  1514. break;
  1515. }
  1516. }
  1517. }
  1518. PRIVATE
  1519. VOID
  1520. CompleteConnect(
  1521. IN LPSOCKET_INFO pSocketInfo,
  1522. IN LPCONNECTION_INFO pConnectionInfo
  1523. )
  1524. /*++
  1525. Routine Description:
  1526. Complete a SPXEstablishConnection
  1527. Arguments:
  1528. pSocketInfo - pointer to SOCKET_INFO
  1529. pConnectionInfo - pointer to CONNECTION_INFO
  1530. Return Value:
  1531. None.
  1532. --*/
  1533. {
  1534. LPXECB pXecb = pConnectionInfo->ConnectQueue.Head;
  1535. /*
  1536. LPSPX_PACKET pPacket;
  1537. //
  1538. // the connection ID also appears in the first segment of the establish
  1539. // ECB
  1540. //
  1541. pPacket = (LPSPX_PACKET)GET_FAR_POINTER(&ECB_FRAGMENT(pXecb->Ecb, 0)->Address,
  1542. IS_PROT_MODE(pXecb)
  1543. );
  1544. pPacket->Checksum = 0xffff;
  1545. pPacket->Length = L2BW(SPX_HEADER_LENGTH);
  1546. pPacket->TransportControl = 0;
  1547. pPacket->PacketType = 5;
  1548. pPacket->Source.Socket = pSocketInfo->SocketNumber;
  1549. pPacket->ConnectionControl = 0xc0;
  1550. pPacket->DataStreamType = 0;
  1551. pPacket->SourceConnectId = pConnectionInfo->ConnectionId;
  1552. pPacket->DestinationConnectId = 0xffff;
  1553. pPacket->SequenceNumber = 0;
  1554. pPacket->AckNumber = 0;
  1555. pPacket->AllocationNumber = 0;
  1556. */
  1557. pConnectionInfo->State = CI_ESTABLISHED;
  1558. IPXDBGPRINT((__FILE__, __LINE__,
  1559. FUNCTION_ANY,
  1560. IPXDBG_LEVEL_INFO,
  1561. "CompleteConnect: connection %04x (%08x) completed\n",
  1562. pConnectionInfo->ConnectionId,
  1563. pConnectionInfo
  1564. ));
  1565. DUMPCONN(pConnectionInfo);
  1566. DequeueEcb(pXecb, &pConnectionInfo->ConnectQueue);
  1567. IPXDUMPECB((pXecb->Ecb,
  1568. HIWORD(pXecb->EcbAddress),
  1569. LOWORD(pXecb->EcbAddress),
  1570. ECB_TYPE_SPX,
  1571. TRUE,
  1572. TRUE,
  1573. IS_PROT_MODE(pXecb)
  1574. ));
  1575. CompleteOrQueueEcb(pXecb, ECB_CC_SUCCESS);
  1576. }
  1577. PRIVATE
  1578. VOID
  1579. CompleteSend(
  1580. IN LPSOCKET_INFO pSocketInfo,
  1581. IN LPCONNECTION_INFO pConnectionInfo
  1582. )
  1583. /*++
  1584. Routine Description:
  1585. Complete a SPXSendSequencedPacket
  1586. Arguments:
  1587. pSocketInfo - pointer to SOCKET_INFO
  1588. pConnectionInfo - pointer to CONNECTION_INFO
  1589. Return Value:
  1590. None.
  1591. --*/
  1592. {
  1593. LPXECB pXecb = pConnectionInfo->SendQueue.Head;
  1594. int rc;
  1595. BYTE status;
  1596. LPSPX_PACKET pPacket; //Multi-User addition
  1597. int flags = 0; //Multi-User addition
  1598. IPXDBGPRINT((__FILE__, __LINE__,
  1599. FUNCTION_ANY,
  1600. IPXDBG_LEVEL_INFO,
  1601. "CompleteSend: sending %d (0x%x) bytes from %08x\n",
  1602. pXecb->Length,
  1603. pXecb->Length,
  1604. pXecb->Data
  1605. ));
  1606. IPXDUMPECB((pXecb->Ecb,
  1607. HIWORD(pXecb->EcbAddress),
  1608. LOWORD(pXecb->EcbAddress),
  1609. ECB_TYPE_SPX,
  1610. TRUE,
  1611. TRUE,
  1612. IS_PROT_MODE(pXecb)
  1613. ));
  1614. //======Multi-User code merge ==============================
  1615. // 2/18/97 cjc Code copied from _VwSPXSendSequencedPacket (vwspx.c) to fix
  1616. // problem where EndOfMessage bit was being set prematurely and
  1617. // caused BSPXCOM8 error messages with Btrieve.
  1618. //
  1619. // if the app set the END_OF_MESSAGE bit in the ConnectionControl
  1620. // field then set the flags to 0: NWLink will automatically set the
  1621. // end-of-message bit in the packet; otherwise set flags to MSG_PARTIAL
  1622. // to indicate to NWLink that it *shouldn't* set the bit in the packet
  1623. //
  1624. pPacket = (LPSPX_PACKET)GET_FAR_POINTER(
  1625. &(ECB_FRAGMENT(pXecb->Ecb, 0)->Address),
  1626. IS_PROT_MODE(pXecb)
  1627. );
  1628. if (pPacket) {
  1629. flags = (pPacket->ConnectionControl & SPX_END_OF_MESSAGE)
  1630. ? 0
  1631. : MSG_PARTIAL
  1632. ;
  1633. }
  1634. rc = send(pConnectionInfo->Socket, pXecb->Data, pXecb->Length, flags);
  1635. //rc = send(pConnectionInfo->Socket, pXecb->Data, pXecb->Length, 0); //Original
  1636. //======Multi-User code merge End ==============================
  1637. if (rc == pXecb->Length) {
  1638. //
  1639. // all data sent
  1640. //
  1641. status = ECB_CC_SUCCESS;
  1642. } else if (rc == SOCKET_ERROR) {
  1643. rc = WSAGetLastError();
  1644. if (rc == WSAEWOULDBLOCK) {
  1645. //
  1646. // huh???
  1647. //
  1648. IPXDBGPRINT((__FILE__, __LINE__,
  1649. FUNCTION_ANY,
  1650. IPXDBG_LEVEL_ERROR,
  1651. "CompleteSend: send() returns WSAEWOODBLOCK??\n"
  1652. ));
  1653. //
  1654. // leave ECB on queue
  1655. //
  1656. return;
  1657. } else {
  1658. IPXDBGPRINT((__FILE__, __LINE__,
  1659. FUNCTION_ANY,
  1660. IPXDBG_LEVEL_ERROR,
  1661. "CompleteSend: send() returns %d\n",
  1662. rc
  1663. ));
  1664. status = ECB_CC_CONNECTION_ABORTED;
  1665. }
  1666. } else {
  1667. //
  1668. // partial data sent. Update the buffer pointer and length fields
  1669. // and leave this ECB at the head of the send queue
  1670. //
  1671. pXecb->Data += rc;
  1672. pXecb->Length -= (WORD)rc;
  1673. return;
  1674. }
  1675. DequeueEcb(pXecb, &pConnectionInfo->SendQueue);
  1676. CompleteOrQueueIo(pXecb, status);
  1677. }
  1678. #if SPX_HACK
  1679. PRIVATE
  1680. VOID
  1681. ModifyFirstReceive(
  1682. LPBYTE Buffer,
  1683. LPDWORD pLength,
  1684. WORD SocketNumber,
  1685. SOCKET Socket
  1686. )
  1687. {
  1688. WORD len = *(LPWORD)pLength;
  1689. if ((*(ULPWORD)Buffer != 0xffff) && (*(ULPWORD)(Buffer+2) != L2BW(len))) {
  1690. LPSPX_PACKET packet;
  1691. SOCKADDR_IPX remote;
  1692. int rc;
  1693. int remlen;
  1694. IPXDBGPRINT((__FILE__, __LINE__,
  1695. FUNCTION_ANY,
  1696. IPXDBG_LEVEL_INFO,
  1697. "ModifyFirstReceive: Modifying: Buffer=%08x Length=%04x SocketNumber=%04x Socket=%08x\n",
  1698. Buffer,
  1699. len,
  1700. B2LW(SocketNumber),
  1701. Socket
  1702. ));
  1703. MoveMemory(Buffer+42, Buffer, len);
  1704. packet = (LPSPX_PACKET)Buffer;
  1705. packet->Checksum = 0xffff;
  1706. packet->Length = L2BW(42+len);
  1707. packet->TransportControl = 0;
  1708. packet->PacketType = 5;
  1709. CopyMemory((LPVOID)&packet->Destination,
  1710. (LPVOID)&MyInternetAddress.sa_netnum,
  1711. sizeof(INTERNET_ADDRESS)
  1712. );
  1713. packet->Destination.Socket = SocketNumber;
  1714. rc = getpeername(Socket, (LPSOCKADDR)&remote, &remlen);
  1715. if (rc != SOCKET_ERROR) {
  1716. CopyMemory((LPVOID)&packet->Source,
  1717. (LPVOID)&remote.sa_netnum,
  1718. sizeof(NETWARE_ADDRESS)
  1719. );
  1720. } else {
  1721. ZeroMemory((LPVOID)&packet->Source, sizeof(NETWARE_ADDRESS));
  1722. }
  1723. packet->ConnectionControl = 0x40;
  1724. packet->DataStreamType = 0;
  1725. packet->SourceConnectId = 0;
  1726. packet->DestinationConnectId = 0;
  1727. packet->SequenceNumber = 0;
  1728. packet->AckNumber = 0;
  1729. packet->AllocationNumber = 0;
  1730. *pLength += 42;
  1731. }
  1732. }
  1733. #endif