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.

1396 lines
37 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. vwspx.c
  5. Abstract:
  6. ntVdm netWare (Vw) IPX/SPX Functions
  7. Vw: The peoples' network
  8. Contains internal routines for DOS/WOW SPX calls (netware functions).
  9. The SPX APIs use WinSock to perform the actual operations
  10. Contents:
  11. _VwSPXAbortConnection
  12. _VwSPXEstablishConnection
  13. _VwSPXGetConnectionStatus
  14. _VwSPXInitialize
  15. _VwSPXListenForConnection
  16. _VwSPXListenForSequencedPacket
  17. _VwSPXSendSequencedPacket
  18. _VwSPXTerminateConnection
  19. The SPX functions build on the IPX functions (VWIPX.C). SPX maintains
  20. connections, IPX maintains sockets. A socket may have a list of connections
  21. Author:
  22. Richard L Firth (rfirth) 30-Sep-1993
  23. Environment:
  24. User-mode Win32
  25. Revision History:
  26. 30-Sep-1993 rfirth
  27. Created
  28. --*/
  29. #include "vw.h"
  30. #pragma hdrstop
  31. //
  32. // functions
  33. //
  34. VOID
  35. _VwSPXAbortConnection(
  36. IN WORD SPXConnectionID
  37. )
  38. /*++
  39. Routine Description:
  40. Aborts a connection. Because NWLink doesn't differentiate between abrupt
  41. and graceful closes, this function has the same effect as
  42. VwSPXTerminateConnection
  43. Arguments:
  44. SPXConnectionID - connection to abort
  45. Return Value:
  46. None.
  47. --*/
  48. {
  49. LPCONNECTION_INFO pConnectionInfo;
  50. RequestMutex();
  51. pConnectionInfo = FindConnection(SPXConnectionID);
  52. if (pConnectionInfo) {
  53. DequeueConnection(pConnectionInfo->OwningSocket, pConnectionInfo);
  54. AbortOrTerminateConnection(pConnectionInfo, ECB_CC_CONNECTION_ABORTED);
  55. } else {
  56. IPXDBGPRINT((__FILE__, __LINE__,
  57. FUNCTION_SPXAbortConnection,
  58. IPXDBG_LEVEL_ERROR,
  59. "VwSPXAbortConnection: cannot find connection %04x\n",
  60. SPXConnectionID
  61. ));
  62. }
  63. ReleaseMutex();
  64. }
  65. WORD
  66. _VwSPXEstablishConnection(
  67. IN BYTE retryCount,
  68. IN BYTE watchDogFlag,
  69. OUT ULPWORD pSPXConnectionID,
  70. IN LPECB pEcb,
  71. IN ECB_ADDRESS EcbAddress
  72. )
  73. /*++
  74. Routine Description:
  75. Creates a connection with a remote SPX socket. The remote end can be on
  76. this machine (i.e. same app in DOS world)
  77. This call is Asynchronous
  78. Arguments:
  79. Inputs
  80. retryCount
  81. watchDogFlag
  82. pEcb
  83. EcbAddress
  84. Outputs
  85. pSPXConnectionID
  86. Return Value:
  87. 00h Attempting to talk to remote
  88. EFh Local connection table full
  89. FDh Fragment count not 1; buffer size not 42
  90. FFh Send socket not open
  91. --*/
  92. {
  93. LPXECB pXecb = RetrieveXEcb(ECB_TYPE_SPX, pEcb, EcbAddress);
  94. LPSOCKET_INFO pSocketInfo;
  95. LPCONNECTION_INFO pConnectionInfo;
  96. WORD connectionId;
  97. LPSPX_PACKET pPacket;
  98. SOCKADDR_IPX destination;
  99. int rc;
  100. SOCKET s;
  101. // tommye - MS 30525
  102. //
  103. // Make sure the xecb alloc didn't fail
  104. // We don't know what the real SPX does if a malloc fails.
  105. //
  106. if (pXecb == NULL) {
  107. return SPX_BAD_SEND_REQUEST;
  108. }
  109. pSocketInfo = FindSocket(pXecb->SocketNumber);
  110. if (!pSocketInfo) {
  111. CompleteEcb(pXecb, ECB_CC_NON_EXISTENT_SOCKET);
  112. return SPX_NON_EXISTENT_SOCKET;
  113. }
  114. //
  115. // if no outstanding IPX operations, change socket to SPX
  116. //
  117. if (!pSocketInfo->SpxSocket) {
  118. if (!(pSocketInfo->PendingSends && pSocketInfo->PendingListens)) {
  119. rc = ReopenSocket(pSocketInfo);
  120. } else {
  121. rc = ECB_CC_BAD_SEND_REQUEST;
  122. }
  123. if (rc != SPX_SUCCESS) {
  124. CompleteOrQueueEcb(pXecb, (BYTE)rc);
  125. return SPX_BAD_SEND_REQUEST;
  126. }
  127. }
  128. //
  129. // real SPX will use the ECB to send an ESTABLISH CONNECTION packet. This
  130. // is handled for us within the SPX transport. Nevertheless we must check
  131. // the fragment and dismiss the request if its not sufficient
  132. //
  133. if ((pXecb->Ecb->FragmentCount != 1)
  134. || (ECB_FRAGMENT(pXecb->Ecb, 0)->Length < SPX_HEADER_LENGTH)) {
  135. CompleteEcb(pXecb, ECB_CC_BAD_SEND_REQUEST);
  136. return SPX_BAD_SEND_REQUEST;
  137. }
  138. //
  139. // the socket is open for SPX. Allocate a connection/connection ID
  140. //
  141. pConnectionInfo = AllocateConnection(pSocketInfo);
  142. if (pConnectionInfo) {
  143. //
  144. // create new socket, bound to the same local address as the parent
  145. // socket. This is the 'connection'
  146. //
  147. #if REUSEADDR
  148. connectionId = pSocketInfo->SocketNumber;
  149. rc = CreateSocket(SOCKET_TYPE_SPX, &connectionId, &pConnectionInfo->Socket);
  150. s = pConnectionInfo->Socket;
  151. // if (rc == SPX_SUCCESS) {
  152. #else
  153. s = socket(AF_IPX, SOCK_SEQPACKET, NSPROTO_SPX);
  154. if (s != INVALID_SOCKET) {
  155. u_long arg = !0;
  156. //
  157. // put the socket in non-blocking I/O mode
  158. //
  159. rc = ioctlsocket(s, FIONBIO, &arg);
  160. if (rc != SOCKET_ERROR) {
  161. int true = 1;
  162. rc = setsockopt(s,
  163. NSPROTO_IPX,
  164. IPX_RECVHDR,
  165. (char FAR*)&true,
  166. sizeof(true)
  167. );
  168. if (rc != SOCKET_ERROR) {
  169. pConnectionInfo->Socket = s;
  170. } else {
  171. IPXDBGPRINT((__FILE__, __LINE__,
  172. FUNCTION_SPXEstablishConnection,
  173. IPXDBG_LEVEL_ERROR,
  174. "VwSPXEstablishConnection: setsockopt(IPX_RECVHDR) returns %d\n",
  175. WSAGetLastError()
  176. ));
  177. }
  178. } else {
  179. IPXDBGPRINT((__FILE__, __LINE__,
  180. FUNCTION_SPXEstablishConnection,
  181. IPXDBG_LEVEL_ERROR,
  182. "VwSPXEstablishConnection: ioctlsocket(FIONBIO) returns %d\n",
  183. WSAGetLastError()
  184. ));
  185. }
  186. } else {
  187. rc = WSAGetLastError();
  188. IPXDBGPRINT((__FILE__, __LINE__,
  189. FUNCTION_SPXEstablishConnection,
  190. IPXDBG_LEVEL_ERROR,
  191. "VwSPXEstablishConnection: socket() returns %d\n",
  192. rc
  193. ));
  194. }
  195. #endif
  196. } else {
  197. rc = !SPX_SUCCESS;
  198. }
  199. if (rc == SPX_SUCCESS) {
  200. pConnectionInfo->State = CI_STARTING;
  201. connectionId = pConnectionInfo->ConnectionId;
  202. //
  203. // set the ECB InUse field to 0xF7. Same as snowball by observation (and
  204. // probably correct anyway since it looks as though 0xF7 means 'waiting
  205. // to receive SPX packet', which is true in this case - normally SPX
  206. // creates a connection by sending an establish frame then waits for the
  207. // ack frame
  208. //
  209. pXecb->Ecb->InUse = ECB_IU_LISTENING_SPX;
  210. } else {
  211. //
  212. // if we failed to get CONNECTION_INFO or create the new socket, return
  213. // immediately with an error (socket table full?)
  214. //
  215. if (s != INVALID_SOCKET) {
  216. closesocket(s);
  217. }
  218. if (pConnectionInfo) {
  219. DeallocateConnection(pConnectionInfo);
  220. }
  221. CompleteEcb(pXecb, ECB_CC_CONNECTION_TABLE_FULL);
  222. return SPX_CONNECTION_TABLE_FULL;
  223. }
  224. //
  225. // get the destination info from the SPX header in VDM memory and set up the
  226. // connection. If the connect request would wait then we leave AES to
  227. // periodically check the progress of the request
  228. //
  229. pPacket = (LPSPX_PACKET)GET_FAR_POINTER(&ECB_FRAGMENT(pXecb->Ecb, 0)->Address,
  230. IS_PROT_MODE(pXecb)
  231. );
  232. if (pPacket == NULL) {
  233. CompleteEcb(pXecb, ECB_CC_BAD_SEND_REQUEST);
  234. return SPX_BAD_SEND_REQUEST;
  235. }
  236. //
  237. // fill in the packet details (app shouldn't look at these until the command
  238. // completes). In 16-bit SPX, these values are filled in by the transport.
  239. // Our transport does not return these values, so we have to 'invent' them,
  240. // but since they are fairly static it should be ok (maybe the transport
  241. // should return them)
  242. //
  243. pPacket->Checksum = 0xffff;
  244. pPacket->Length = L2BW(SPX_HEADER_LENGTH);
  245. pPacket->TransportControl = 0;
  246. pPacket->PacketType = SPX_PACKET_TYPE;
  247. pPacket->Source.Socket = pSocketInfo->SocketNumber;
  248. pPacket->ConnectionControl = SPX_SYSTEM_PACKET | SPX_ACK_REQUIRED;
  249. pPacket->DataStreamType = SPX_DS_ESTABLISH;
  250. pPacket->SourceConnectId = pConnectionInfo->ConnectionId;
  251. pPacket->DestinationConnectId = 0xffff;
  252. pPacket->SequenceNumber = 0;
  253. pPacket->AckNumber = 0;
  254. pPacket->AllocationNumber = 0;
  255. //
  256. // get the destination address info
  257. //
  258. CopyMemory(&destination.sa_netnum,
  259. (LPBYTE)&pPacket->Destination,
  260. sizeof(pPacket->Destination)
  261. );
  262. destination.sa_family = AF_IPX;
  263. //
  264. // initiate the connection
  265. //
  266. rc = connect(s, (LPSOCKADDR)&destination, sizeof(destination));
  267. if (rc != SOCKET_ERROR) {
  268. //
  269. // add the CONNECTION_INFO structure to the list of connections owned
  270. // by this socket and set the connection state to ESTABLISHED
  271. //
  272. IPXDBGPRINT((__FILE__, __LINE__,
  273. FUNCTION_SPXEstablishConnection,
  274. IPXDBG_LEVEL_INFO,
  275. "VwSPXEstablishConnection: socket connected\n"
  276. ));
  277. RequestMutex();
  278. QueueConnection(pSocketInfo, pConnectionInfo);
  279. pConnectionInfo->State = CI_ESTABLISHED;
  280. ReleaseMutex();
  281. //
  282. // the connection ID also appears in the first segment of the establish
  283. // ECB
  284. //
  285. pPacket->SourceConnectId = connectionId;
  286. //
  287. // the SPXEstablishConnection ECB is done!
  288. //
  289. CompleteEcb(pXecb, ECB_CC_SUCCESS);
  290. } else {
  291. rc = WSAGetLastError();
  292. if (rc == WSAEWOULDBLOCK) {
  293. //
  294. // the connect request is in progress. Add it to the queue of
  295. // pending SPXEstablishConnection requests (SHOULD ONLY BE 1 PER
  296. // CONNECTION!!!) and add the CONNECTION_INFO structure to the
  297. // owning SOCKET_INFO structure
  298. //
  299. RequestMutex();
  300. QueueEcb(pXecb,
  301. &pConnectionInfo->ConnectQueue,
  302. CONNECTION_CONNECT_QUEUE
  303. );
  304. QueueConnection(pSocketInfo, pConnectionInfo);
  305. ReleaseMutex();
  306. IPXDBGPRINT((__FILE__, __LINE__,
  307. FUNCTION_SPXEstablishConnection,
  308. IPXDBG_LEVEL_INFO,
  309. "VwSPXEstablishConnection: connect() queued\n"
  310. ));
  311. } else {
  312. IPXDBGPRINT((__FILE__, __LINE__,
  313. FUNCTION_SPXEstablishConnection,
  314. IPXDBG_LEVEL_ERROR,
  315. "VwSPXEstablishConnection: connect(%x) returns %d\n",
  316. s,
  317. rc
  318. ));
  319. //
  320. // the connect request failed. Deallocate all resources (socket,
  321. // CONNECTION_INFO, XECB) and return failure
  322. //
  323. closesocket(pConnectionInfo->Socket);
  324. DeallocateConnection(pConnectionInfo);
  325. CompleteEcb(pXecb, ECB_CC_CONNECTION_ABORTED);
  326. return SPX_CONNECTION_ABORTED;
  327. }
  328. }
  329. IPXDBGPRINT((__FILE__, __LINE__,
  330. FUNCTION_SPXEstablishConnection,
  331. IPXDBG_LEVEL_INFO,
  332. "VwSPXEstablishConnection: returning %04x\n",
  333. connectionId
  334. ));
  335. *pSPXConnectionID = connectionId;
  336. return SPX_SUCCESS;
  337. }
  338. WORD
  339. _VwSPXGetConnectionStatus(
  340. IN WORD connectionId,
  341. OUT LPSPX_CONNECTION_STATS pStats
  342. )
  343. /*++
  344. Routine Description:
  345. Returns buffer crammed full of useful statistics or something (hu hu huh)
  346. This call is Synchronous
  347. Arguments:
  348. Inputs
  349. connectionId
  350. pStats
  351. Outputs
  352. on output, buffer in pStats contains:
  353. BYTE ConnectionStatus
  354. BYTE WatchDogActive
  355. WORD LocalConnectionID
  356. WORD RemoteConnectionID
  357. WORD SequenceNumber
  358. WORD LocalAckNumber
  359. WORD LocalAllocationNumber
  360. WORD RemoteAckNumber
  361. WORD RemoteAllocationNumber
  362. WORD LocalSocket
  363. BYTE ImmediateAddress[6]
  364. BYTE RemoteNetwork[4]
  365. WORD RetransmissionCount
  366. WORD RetransmittedPackets
  367. WORD SuppressedPackets
  368. Return Value:
  369. 00h Connection is active
  370. EEh No such connection
  371. --*/
  372. {
  373. int rc;
  374. IPX_SPXCONNSTATUS_DATA buf;
  375. int buflen = sizeof(buf);
  376. LPCONNECTION_INFO pConnectionInfo;
  377. pConnectionInfo = FindConnection(connectionId);
  378. if (!pConnectionInfo) {
  379. return SPX_INVALID_CONNECTION;
  380. }
  381. //
  382. // get the stats
  383. //
  384. rc = getsockopt(pConnectionInfo->Socket,
  385. NSPROTO_IPX,
  386. IPX_SPXGETCONNECTIONSTATUS,
  387. (char FAR*)&buf,
  388. &buflen
  389. );
  390. if (rc == SOCKET_ERROR) {
  391. IPXDBGPRINT((__FILE__, __LINE__,
  392. FUNCTION_SPXGetConnectionStatus,
  393. IPXDBG_LEVEL_ERROR,
  394. "VwSPXGetConnectionStatus: getsockopt() returns %d\n",
  395. WSAGetLastError()
  396. ));
  397. //
  398. // the request to get the stats failed - probably because the socket is
  399. // not yet connected. Fill in those bits we know about
  400. //
  401. ZeroMemory((LPBYTE)pStats, sizeof(*pStats));
  402. } else {
  403. //
  404. // copy the returned fields
  405. //
  406. pStats->RemoteConnectionId = buf.RemoteConnectionId;
  407. pStats->LocalSequenceNumber = buf.LocalSequenceNumber;
  408. pStats->LocalAckNumber = buf.LocalAckNumber;
  409. pStats->LocalAllocNumber = buf.LocalAllocNumber;
  410. pStats->RemoteAckNumber = buf.RemoteAckNumber;
  411. pStats->RemoteAllocNumber = buf.RemoteAllocNumber;
  412. pStats->LocalSocket = buf.LocalSocket;
  413. CopyMemory(&pStats->ImmediateAddress,
  414. &buf.ImmediateAddress,
  415. sizeof(buf.ImmediateAddress)
  416. );
  417. //
  418. // copy remote network as a DWORD. Endian format is same for both
  419. //
  420. *(ULPDWORD)&pStats->RemoteNetwork = *(LPDWORD)&buf.RemoteNetwork;
  421. CopyMemory(&pStats->RemoteNode,
  422. &buf.RemoteNode,
  423. sizeof(buf.RemoteNode)
  424. );
  425. pStats->RemoteSocket = buf.RemoteSocket;
  426. pStats->RetransmissionCount = buf.RetransmissionCount;
  427. pStats->EstimatedRoundTripDelay = buf.EstimatedRoundTripDelay;
  428. pStats->RetransmittedPackets = buf.RetransmittedPackets;
  429. pStats->SuppressedPackets = buf.SuppressedPacket;
  430. }
  431. //
  432. // fill in common, known fields
  433. //
  434. pStats->State = pConnectionInfo->State; // not returned by NWIPX
  435. pStats->WatchDog = 0x02; // see novell dog-umentation
  436. pStats->LocalConnectionId = L2BW(pConnectionInfo->ConnectionId);
  437. pStats->LocalSocket = pConnectionInfo->OwningSocket->SocketNumber;
  438. DUMPSTATS(pStats);
  439. //
  440. // we are returning some kind o stats - therefore success
  441. //
  442. return SPX_SUCCESS;
  443. }
  444. WORD
  445. _VwSPXInitialize(
  446. OUT ULPBYTE pMajorRevisionNumber,
  447. OUT ULPBYTE pMinorRevisionNumber,
  448. OUT ULPWORD pMaxConnections,
  449. OUT ULPWORD pAvailableConnections
  450. )
  451. /*++
  452. Routine Description:
  453. Informs the app that SPX is present on this station
  454. This call is Synchronous
  455. Arguments:
  456. Inputs
  457. Outputs
  458. pMajorRevisionNumber - SPX Major revision number
  459. pminorRevisionNumber - SPX Minor revision number
  460. pMaxConnections - Maximum SPX connections supported
  461. normally from SHELL.CFG
  462. pAvailableConnections - Available SPX connections
  463. Return Value:
  464. 00h Not installed
  465. FFh Installed
  466. --*/
  467. {
  468. //
  469. // The following values are returned same as per Windows For Workgroups
  470. // v3.10
  471. //
  472. *pMajorRevisionNumber = 3;
  473. *pMinorRevisionNumber = 10;
  474. *pMaxConnections = 128;
  475. *pAvailableConnections = *pMaxConnections - 1 ;
  476. return SPX_INSTALLED;
  477. }
  478. VOID
  479. _VwSPXListenForConnection(
  480. IN BYTE retryCount,
  481. IN BYTE watchDogFlag,
  482. IN LPECB pEcb,
  483. IN ECB_ADDRESS EcbAddress
  484. )
  485. /*++
  486. Routine Description:
  487. Listens for an incoming connection request
  488. This call is Asynchronous
  489. Arguments:
  490. Inputs
  491. retryCount
  492. watchDogFlag
  493. pEcb
  494. EcbAddress
  495. Outputs
  496. Nothing
  497. Return Value:
  498. None.
  499. --*/
  500. {
  501. LPXECB pXecb = RetrieveXEcb(ECB_TYPE_SPX, pEcb, EcbAddress);
  502. LPSOCKET_INFO pSocketInfo;
  503. LPCONNECTION_INFO pConnectionInfo;
  504. SOCKET sock;
  505. SOCKET conn;
  506. SOCKADDR_IPX remoteAddress;
  507. int rc;
  508. BYTE completionCode;
  509. // tommye - MS 30525
  510. //
  511. // Make sure the xecb alloc didn't fail
  512. //
  513. if (pXecb == NULL) {
  514. IPXDBGPRINT((__FILE__, __LINE__,
  515. FUNCTION_SPXListenForConnection,
  516. IPXDBG_LEVEL_ERROR,
  517. "RetrieveXEcb returned NULL pointer"
  518. ));
  519. return;
  520. }
  521. //
  522. // it turns out that SPXListenForConnection doesn't need a fragment to
  523. // receive connection info - that is handled by SPXListenForSequencedPacket
  524. // that the app has dutifully initiated
  525. //
  526. pSocketInfo = FindSocket(pXecb->SocketNumber);
  527. if (!pSocketInfo) {
  528. completionCode = ECB_CC_NON_EXISTENT_SOCKET;
  529. goto lc_completion_exit;
  530. }
  531. //
  532. // if no outstanding IPX operations, change socket to SPX
  533. //
  534. if (!pSocketInfo->SpxSocket) {
  535. if (!(pSocketInfo->PendingSends && pSocketInfo->PendingListens)) {
  536. rc = ReopenSocket(pSocketInfo);
  537. } else {
  538. rc = ECB_CC_BAD_LISTEN_REQUEST;
  539. }
  540. if (rc != SPX_SUCCESS) {
  541. completionCode = (BYTE)rc;
  542. goto lc_completion_exit;
  543. }
  544. }
  545. //
  546. // the socket is open for SPX. Allocate a connection/connection ID
  547. //
  548. pConnectionInfo = AllocateConnection(pSocketInfo);
  549. if (!pConnectionInfo) {
  550. completionCode = ECB_CC_CONNECTION_TABLE_FULL;
  551. goto lc_completion_exit;
  552. }
  553. //
  554. // put the socket into listening state and try to accept a connection
  555. //
  556. sock = pSocketInfo->Socket;
  557. //
  558. // If the socket is already listening, will probably return an
  559. // error: just queue
  560. //
  561. rc = listen(sock, MAX_LISTEN_QUEUE_SIZE);
  562. if (rc != SOCKET_ERROR) {
  563. int addressLength = sizeof(remoteAddress);
  564. conn = accept(sock, (LPSOCKADDR)&remoteAddress, &addressLength);
  565. if (conn != SOCKET_ERROR) {
  566. //
  567. // we want to receive the frame headers from this socket
  568. //
  569. BOOL bval = TRUE;
  570. rc = setsockopt(conn,
  571. NSPROTO_IPX,
  572. IPX_RECVHDR,
  573. (char FAR*)&bval,
  574. sizeof(bval)
  575. );
  576. if (rc != SOCKET_ERROR) {
  577. //
  578. // update the CONNECTION_INFO structure with the actual socket
  579. // identifier and set the connection state to established
  580. //
  581. pConnectionInfo->Socket = conn;
  582. pConnectionInfo->State = CI_ESTABLISHED;
  583. //
  584. // add the CONNECTION_INFO structure to the list of connections owned
  585. // by this socket
  586. //
  587. RequestMutex();
  588. QueueConnection(pSocketInfo, pConnectionInfo);
  589. ReleaseMutex();
  590. //
  591. // update the app's ECB with the connection ID
  592. //
  593. SPX_ECB_CONNECTION_ID(pXecb->Ecb) = pConnectionInfo->ConnectionId;
  594. //
  595. // and with the partner address info
  596. //
  597. CopyMemory(&pXecb->Ecb->DriverWorkspace,
  598. &remoteAddress.sa_netnum,
  599. sizeof(pXecb->Ecb->DriverWorkspace)
  600. );
  601. completionCode = ECB_CC_SUCCESS;
  602. goto lc_completion_exit;
  603. } else {
  604. IPXDBGPRINT((__FILE__, __LINE__,
  605. FUNCTION_SPXListenForConnection,
  606. IPXDBG_LEVEL_ERROR,
  607. "VwSPXListenForConnection: setsockopt(RECVHDR) returns %d\n",
  608. WSAGetLastError()
  609. ));
  610. closesocket(conn);
  611. completionCode = ECB_CC_CONNECTION_ABORTED;
  612. goto lc_deallocate_exit;
  613. }
  614. } else {
  615. rc = WSAGetLastError();
  616. if (rc == WSAEWOULDBLOCK) {
  617. //
  618. // the accept request is in progress. Add it to the queue of
  619. // pending SPXListenForConnection requests (SHOULD ONLY BE 1 PER
  620. // CONNECTION!!!) and add the CONNECTION_INFO structure to the
  621. // owning SOCKET_INFO structure
  622. //
  623. pConnectionInfo->State = CI_WAITING; // waiting for incoming connect
  624. RequestMutex();
  625. QueueEcb(pXecb,
  626. &pConnectionInfo->AcceptQueue,
  627. CONNECTION_ACCEPT_QUEUE
  628. );
  629. QueueConnection(pSocketInfo, pConnectionInfo);
  630. pXecb->Ecb->InUse = ECB_IU_AWAITING_CONNECTION;
  631. ReleaseMutex();
  632. } else {
  633. //
  634. // the accept request failed. Deallocate all resources
  635. // (CONNECTION_INFO, XECB) and complete the ECB with a failure
  636. // indication
  637. //
  638. IPXDBGPRINT((__FILE__, __LINE__,
  639. FUNCTION_SPXListenForConnection,
  640. IPXDBG_LEVEL_ERROR,
  641. "VwSPXListenForConnection: accept() returns %d\n",
  642. rc
  643. ));
  644. completionCode = ECB_CC_CONNECTION_ABORTED;
  645. goto lc_deallocate_exit;
  646. }
  647. }
  648. } else {
  649. IPXDBGPRINT((__FILE__, __LINE__,
  650. FUNCTION_SPXListenForConnection,
  651. IPXDBG_LEVEL_ERROR,
  652. "VwSPXListenForConnection: listen() returns %d\n",
  653. WSAGetLastError()
  654. ));
  655. //
  656. // listen failed? Bogus. Complete the ECB and we're outta here
  657. //
  658. completionCode = ECB_CC_CONNECTION_ABORTED;
  659. goto lc_deallocate_exit;
  660. }
  661. //
  662. // here if we queued the listen request
  663. //
  664. return;
  665. lc_deallocate_exit:
  666. DeallocateConnection(pConnectionInfo);
  667. lc_completion_exit:
  668. CompleteEcb(pXecb, completionCode);
  669. }
  670. VOID
  671. _VwSPXListenForSequencedPacket(
  672. IN LPECB pEcb,
  673. IN ECB_ADDRESS EcbAddress
  674. )
  675. /*++
  676. Routine Description:
  677. Attempts to receive an SPX packet. This call is made against the top-level
  678. socket (the socket in SPX-speak, not the connection). We can receive a
  679. packet from any connection assigned to this socket. In this function, we
  680. just queue the ECB (since there is no return status, we expect that the
  681. app has supplied an ESR) and let AES handle it
  682. This call is Asynchronous
  683. Arguments:
  684. Inputs
  685. pEcb
  686. EcbAddress
  687. Outputs
  688. Nothing
  689. Return Value:
  690. None.
  691. --*/
  692. {
  693. LPXECB pXecb = RetrieveXEcb(ECB_TYPE_SPX, pEcb, EcbAddress);
  694. LPSOCKET_INFO pSocketInfo;
  695. int rc;
  696. BOOL dummy ;
  697. BYTE status;
  698. // tommye - MS 30525
  699. //
  700. // Make sure the xecb alloc didn't fail
  701. //
  702. if (pXecb == NULL) {
  703. IPXDBGPRINT((__FILE__, __LINE__,
  704. FUNCTION_SPXListenForSequencedPacket,
  705. IPXDBG_LEVEL_ERROR,
  706. "RetrieveXEcb returned NULL pointer"
  707. ));
  708. return;
  709. }
  710. IPXDBGPRINT((__FILE__, __LINE__,
  711. FUNCTION_SPXListenForSequencedPacket,
  712. IPXDBG_LEVEL_INFO,
  713. "VwSPXListenForSequencedPacket(%04x:%04x) socket=%04x ESR=%04x:%04x\n",
  714. HIWORD(pXecb->EcbAddress),
  715. LOWORD(pXecb->EcbAddress),
  716. B2LW(pXecb->SocketNumber),
  717. HIWORD(pXecb->EsrAddress),
  718. LOWORD(pXecb->EsrAddress)
  719. ));
  720. pSocketInfo = FindSocket(pXecb->SocketNumber);
  721. if (!pSocketInfo) {
  722. status = ECB_CC_NON_EXISTENT_SOCKET;
  723. goto lp_exit;
  724. }
  725. //
  726. // if no outstanding IPX operations, change socket to SPX
  727. //
  728. if (!pSocketInfo->SpxSocket) {
  729. if (!(pSocketInfo->PendingSends && pSocketInfo->PendingListens)) {
  730. rc = ReopenSocket(pSocketInfo);
  731. } else {
  732. rc = ECB_CC_BAD_LISTEN_REQUEST;
  733. }
  734. if (rc != SPX_SUCCESS) {
  735. status = (BYTE)rc;
  736. goto lp_exit;
  737. }
  738. }
  739. //
  740. // the first fragment must be large enough to hold an SPX packet header
  741. //
  742. if ((pXecb->Ecb->FragmentCount == 0)
  743. || (ECB_FRAGMENT(pXecb->Ecb, 0)->Length < SPX_HEADER_LENGTH)) {
  744. status = ECB_CC_BAD_LISTEN_REQUEST;
  745. goto lp_exit;
  746. }
  747. //
  748. // we have a socket and the receive buffer looks good. Get a buffer for recv()
  749. //
  750. if (!GetIoBuffer(pXecb, FALSE, SPX_HEADER_LENGTH)) {
  751. status = ECB_CC_BAD_LISTEN_REQUEST;
  752. goto lp_exit;
  753. } else {
  754. //
  755. // when recv() is attempted against this request, it will be the first
  756. // time we tried to receive anything to this buffer. That means (if we
  757. // get anything) that the buffer will contain the length of the entire
  758. // frame
  759. //
  760. pXecb->Flags |= XECB_FLAG_FIRST_RECEIVE;
  761. }
  762. //
  763. // mark the VDM ECB as in use
  764. //
  765. pXecb->Ecb->InUse = ECB_IU_LISTENING_SPX;
  766. //
  767. // add this ECB to the queue of listens for the top-level socket and quit
  768. //
  769. RequestMutex();
  770. if ((pXecb->Ecb->FragmentCount == 1) &&
  771. (ECB_FRAGMENT(pXecb->Ecb, 0)->Length == SPX_HEADER_LENGTH))
  772. {
  773. QueueEcb(pXecb, &pSocketInfo->HeaderQueue, SOCKET_HEADER_QUEUE);
  774. }
  775. else
  776. {
  777. QueueEcb(pXecb, &pSocketInfo->ListenQueue, SOCKET_LISTEN_QUEUE);
  778. }
  779. ReleaseMutex();
  780. //
  781. // see if we are ready to rock
  782. //
  783. CheckPendingSpxRequests(&dummy);
  784. return;
  785. lp_exit:
  786. CompleteOrQueueEcb(pXecb, status);
  787. }
  788. VOID
  789. _VwSPXSendSequencedPacket(
  790. IN WORD connectionId,
  791. IN LPECB pEcb,
  792. IN ECB_ADDRESS EcbAddress
  793. )
  794. /*++
  795. Routine Description:
  796. Sends a packet on an SPX connection
  797. This call is Asynchronous
  798. Arguments:
  799. Inputs
  800. connectionId
  801. pEcb
  802. EcbAddress
  803. Outputs
  804. Nothing
  805. Return Value:
  806. None.
  807. --*/
  808. {
  809. LPXECB pXecb = RetrieveXEcb(ECB_TYPE_SPX, pEcb, EcbAddress);
  810. LPCONNECTION_INFO pConnectionInfo;
  811. int rc;
  812. BOOL addToQueue;
  813. LPSPX_PACKET pPacket;
  814. // tommye - MS 30525
  815. //
  816. // Make sure the xecb alloc didn't fail
  817. //
  818. if (pXecb == NULL) {
  819. IPXDBGPRINT((__FILE__, __LINE__,
  820. FUNCTION_SPXSendSequencedPacket,
  821. IPXDBG_LEVEL_ERROR,
  822. "RetrieveXEcb returned NULL pointer"
  823. ));
  824. return;
  825. }
  826. IPXDBGPRINT((__FILE__, __LINE__,
  827. FUNCTION_SPXSendSequencedPacket,
  828. IPXDBG_LEVEL_INFO,
  829. "VwSPXSendSequencedPacket(%04x:%04x) Connection=%04x ESR=%04x:%04x\n",
  830. HIWORD(pXecb->EcbAddress),
  831. LOWORD(pXecb->EcbAddress),
  832. connectionId,
  833. HIWORD(pXecb->EsrAddress),
  834. LOWORD(pXecb->EsrAddress)
  835. ));
  836. IPXDUMPECB((pXecb->Ecb,
  837. HIWORD(pXecb->EcbAddress),
  838. LOWORD(pXecb->EcbAddress),
  839. ECB_TYPE_SPX,
  840. TRUE,
  841. TRUE,
  842. IS_PROT_MODE(pXecb)
  843. ));
  844. //
  845. // find the connection. No need to check if this is an SPX socket: if we
  846. // can't find the connection, its a bad connection, else the socket must
  847. // be open for SPX
  848. //
  849. pConnectionInfo = FindConnection(connectionId);
  850. if (!pConnectionInfo || (pConnectionInfo->State != CI_ESTABLISHED)) {
  851. CompleteOrQueueEcb(pXecb, ECB_CC_INVALID_CONNECTION);
  852. return;
  853. }
  854. //
  855. // the first fragment must be large enough to hold an SPX packet header
  856. //
  857. if ((pXecb->Ecb->FragmentCount == 0)
  858. || (ECB_FRAGMENT(pXecb->Ecb, 0)->Length < SPX_HEADER_LENGTH)) {
  859. CompleteOrQueueEcb(pXecb, ECB_CC_BAD_SEND_REQUEST);
  860. return;
  861. }
  862. if (!GetIoBuffer(pXecb, TRUE, SPX_HEADER_LENGTH)) {
  863. CompleteOrQueueEcb(pXecb, ECB_CC_BAD_SEND_REQUEST);
  864. return;
  865. }
  866. pPacket = (LPSPX_PACKET)GET_FAR_POINTER(
  867. &(ECB_FRAGMENT(pXecb->Ecb, 0)->Address),
  868. IS_PROT_MODE(pXecb)
  869. );
  870. //
  871. // fill in the following fields in the SPX header:
  872. //
  873. // Checksum
  874. // Length
  875. // TransportControl
  876. // Source (network, node, socket)
  877. //
  878. // Does real IPX modify these fields in app memory?
  879. // If so, does the app expect modified fields?
  880. // If not, we need to always copy then modify memory,
  881. // even if only 1 fragment
  882. //
  883. pPacket->Checksum = 0xFFFF;
  884. //
  885. // since the transport adds the SPX header, we subtracted the length of
  886. // the header from our transmit length; add it back when updating the
  887. // header in the app's space
  888. //
  889. pPacket->Length = L2BW(pXecb->Length + SPX_HEADER_LENGTH);
  890. pPacket->TransportControl = 0;
  891. CopyMemory((LPBYTE)&pPacket->Source,
  892. &MyInternetAddress.sa_netnum,
  893. sizeof(MyInternetAddress.sa_netnum)
  894. + sizeof(MyInternetAddress.sa_nodenum)
  895. );
  896. pPacket->Source.Socket = pConnectionInfo->OwningSocket->SocketNumber;
  897. //
  898. // if we allocated a buffer then there is >1 fragment. Collect them
  899. //
  900. if (pXecb->Flags & XECB_FLAG_BUFFER_ALLOCATED) {
  901. GatherData(pXecb, SPX_HEADER_LENGTH);
  902. }
  903. //
  904. // mark the VDM ECB as in use
  905. //
  906. pXecb->Ecb->InUse = ECB_IU_SENDING;
  907. //
  908. // if there is a send queued on this connection already, add this request
  909. // to the back of the queue and let AES do the rest
  910. //
  911. RequestMutex();
  912. if (pConnectionInfo->SendQueue.Head) {
  913. addToQueue = TRUE;
  914. } else {
  915. int dataStreamType;
  916. IPXDBGPRINT((__FILE__, __LINE__,
  917. FUNCTION_SPXSendSequencedPacket,
  918. IPXDBG_LEVEL_INFO,
  919. "VwSPXSendSequencedPacket: sending %d (0x%x) bytes from %08x\n",
  920. pXecb->Length,
  921. pXecb->Length,
  922. pXecb->Data
  923. ));
  924. //
  925. // no outstanding sends queued for this connection. Start sending this
  926. // packet
  927. //
  928. dataStreamType = (int)pPacket->DataStreamType;
  929. rc = setsockopt(pConnectionInfo->Socket,
  930. NSPROTO_IPX,
  931. IPX_DSTYPE,
  932. (char FAR*)&dataStreamType,
  933. sizeof(dataStreamType)
  934. );
  935. if (rc != SOCKET_ERROR) {
  936. //
  937. // if the app set the END_OF_MESSAGE bit in the ConnectionControl
  938. // field then set the flags to 0: NWLink will automatically set the
  939. // end-of-message bit in the packet; otherwise set flags to MSG_PARTIAL
  940. // to indicate to NWLink that it *shouldn't* set the bit in the packet
  941. //
  942. int flags = (pPacket->ConnectionControl & SPX_END_OF_MESSAGE)
  943. ? 0
  944. : MSG_PARTIAL
  945. ;
  946. rc = send(pConnectionInfo->Socket, pXecb->Data, pXecb->Length, flags);
  947. IPXDBGPRINT((__FILE__, __LINE__,
  948. FUNCTION_SPXSendSequencedPacket,
  949. IPXDBG_LEVEL_INFO,
  950. "VwSPXSendSequencedPacket: send() returns %d\n",
  951. rc
  952. ));
  953. if (rc == pXecb->Length) {
  954. //
  955. // all data sent
  956. //
  957. CompleteOrQueueIo(pXecb, ECB_CC_SUCCESS);
  958. addToQueue = FALSE;
  959. } else if (rc == SOCKET_ERROR) {
  960. rc = WSAGetLastError();
  961. if (rc == WSAEWOULDBLOCK) {
  962. //
  963. // can't send right now. Queue it for AES
  964. //
  965. addToQueue = TRUE;
  966. }
  967. } else {
  968. //
  969. // partial data sent. Update the buffer pointer and length fields
  970. // and queue this request
  971. //
  972. pXecb->Data += rc;
  973. pXecb->Length -= (WORD)rc;
  974. addToQueue = TRUE;
  975. }
  976. } else {
  977. IPXDBGPRINT((__FILE__, __LINE__,
  978. FUNCTION_SPXSendSequencedPacket,
  979. IPXDBG_LEVEL_ERROR,
  980. "VwSPXSendSequencedPacket: setsockopt(IPX_DSTYPE) returns %d\n",
  981. WSAGetLastError()
  982. ));
  983. CompleteOrQueueIo(pXecb, ECB_CC_BAD_REQUEST);
  984. }
  985. }
  986. //
  987. // if addToQueue set then we can't do anything right now - add this
  988. // request to the send queue
  989. //
  990. if (addToQueue) {
  991. IPXDBGPRINT((__FILE__, __LINE__,
  992. FUNCTION_SPXSendSequencedPacket,
  993. IPXDBG_LEVEL_WARNING,
  994. "VwSPXSendSequencedPacket: adding XECB %08x to send queue\n",
  995. pXecb
  996. ));
  997. QueueEcb(pXecb, &pConnectionInfo->SendQueue, CONNECTION_SEND_QUEUE);
  998. }
  999. ReleaseMutex();
  1000. }
  1001. VOID
  1002. _VwSPXTerminateConnection(
  1003. IN WORD SPXConnectionID,
  1004. IN LPECB pEcb,
  1005. IN ECB_ADDRESS EcbAddress
  1006. )
  1007. /*++
  1008. Routine Description:
  1009. Terminates a connection
  1010. Arguments:
  1011. SPXConnectionID - connection to terminate
  1012. pEcb - pointer to 16-bit ECB to use
  1013. EcbAddress - address of 16-bit ECB in 16:16 format
  1014. Return Value:
  1015. None.
  1016. --*/
  1017. {
  1018. LPCONNECTION_INFO pConnectionInfo;
  1019. LPXECB pXecb = RetrieveXEcb(ECB_TYPE_SPX, pEcb, EcbAddress);
  1020. BYTE status;
  1021. BYTE completionCode;
  1022. // tommye - MS 30525
  1023. //
  1024. // Make sure the xecb alloc didn't fail
  1025. //
  1026. if (pXecb == NULL) {
  1027. return;
  1028. }
  1029. RequestMutex();
  1030. pConnectionInfo = FindConnection(SPXConnectionID);
  1031. if (pConnectionInfo) {
  1032. //
  1033. // once dequeued, pConnectionInfo no longer points to OwningSocket
  1034. //
  1035. WORD socketNumber = pConnectionInfo->OwningSocket->SocketNumber;
  1036. DequeueConnection(pConnectionInfo->OwningSocket, pConnectionInfo);
  1037. if ((pXecb->Ecb->FragmentCount >= 1)
  1038. && (ECB_FRAGMENT(pXecb->Ecb, 0)->Length >= SPX_HEADER_LENGTH)) {
  1039. LPSPX_PACKET pPacket;
  1040. SOCKADDR_IPX remote;
  1041. int remoteLen = sizeof(remote);
  1042. completionCode = ECB_CC_CONNECTION_TERMINATED;
  1043. status = ECB_CC_SUCCESS;
  1044. //
  1045. // fill in the packet header: this would normally contain the
  1046. // acknowledgement packet from the remote partner
  1047. //
  1048. pPacket = (LPSPX_PACKET)GET_FAR_POINTER(
  1049. &(ECB_FRAGMENT(pXecb->Ecb, 0)->Address),
  1050. IS_PROT_MODE(pXecb)
  1051. );
  1052. if (pPacket == NULL) {
  1053. completionCode = ECB_CC_CONNECTION_ABORTED;
  1054. status = ECB_CC_BAD_REQUEST;
  1055. }
  1056. else {
  1057. pPacket->Checksum = 0xffff;
  1058. pPacket->Length = L2BW(SPX_HEADER_LENGTH);
  1059. pPacket->TransportControl = 0;
  1060. pPacket->PacketType = SPX_PACKET_TYPE;
  1061. getpeername(pConnectionInfo->Socket, (LPSOCKADDR)&remote, &remoteLen);
  1062. CopyMemory((LPBYTE)&pPacket->Destination,
  1063. (LPBYTE)&remote.sa_netnum,
  1064. sizeof(NETWARE_ADDRESS)
  1065. );
  1066. CopyMemory((LPBYTE)&pPacket->Source,
  1067. (LPBYTE)&MyInternetAddress.sa_netnum,
  1068. sizeof(INTERNET_ADDRESS)
  1069. );
  1070. pPacket->Source.Socket = socketNumber;
  1071. pPacket->ConnectionControl = SPX_ACK_REQUIRED;
  1072. pPacket->DataStreamType = SPX_DS_TERMINATE;
  1073. pPacket->SourceConnectId = pConnectionInfo->ConnectionId;
  1074. pPacket->DestinationConnectId = 0;
  1075. pPacket->SequenceNumber = 0;
  1076. pPacket->AckNumber = 0;
  1077. pPacket->AllocationNumber = 0;
  1078. }
  1079. } else {
  1080. completionCode = ECB_CC_CONNECTION_ABORTED;
  1081. status = ECB_CC_BAD_REQUEST;
  1082. }
  1083. AbortOrTerminateConnection(pConnectionInfo, completionCode);
  1084. } else {
  1085. status = ECB_CC_INVALID_CONNECTION;
  1086. }
  1087. ReleaseMutex();
  1088. CompleteOrQueueEcb(pXecb, status);
  1089. }