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.

1970 lines
52 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. commapi.c
  5. Abstract:
  6. This module contains the interface functions to interface with
  7. the comm. subsystem. These functions are used by the Replicator and
  8. the Name Space Manager.
  9. Functions:
  10. Portability:
  11. This module is portable
  12. Author:
  13. Pradeep Bahl (PradeepB) Dec-1992
  14. Revision History:
  15. Modification date Person Description of modification
  16. ----------------- ------- ----------------------------
  17. --*/
  18. /*
  19. * Includes
  20. */
  21. #include <string.h>
  22. #include <stdio.h>
  23. #include "wins.h"
  24. #include <winsock2.h>
  25. #include "nms.h"
  26. #include "winscnf.h"
  27. #include "comm.h"
  28. #include "assoc.h"
  29. #include "nmsdb.h"
  30. #include "winsmsc.h"
  31. #include "winsevt.h"
  32. #include "rpl.h"
  33. /*
  34. * Local Macro Declarations
  35. */
  36. /*
  37. * Local Typedef Declarations
  38. */
  39. /*
  40. * Global Variable Definitions
  41. */
  42. COMM_HDL_T QservDlgList; //list of Q server dialogues.
  43. HANDLE CommUdpBuffHeapHdl; //handle to heap used for allocating
  44. //buffers for storing datagrams
  45. HANDLE CommUdpDlgHeapHdl; //handle to heap used for allocating
  46. //dlgs for udp buffers
  47. HANDLE sThdEvtArr[2]; //used by the Push thread in
  48. //ECommProcessDlg
  49. SOCKET CommPnPNotificationSocket = INVALID_SOCKET; //to receive addr change notification
  50. SOCKET CommTcpPortHandle = INVALID_SOCKET; //stores TCP port (socket) #
  51. SOCKET CommUdpPortHandle = INVALID_SOCKET; //stores UDP port (socket) #
  52. SOCKET CommNtfSockHandle = INVALID_SOCKET; //stores socket # of socket used
  53. //for listening for connection
  54. //notification messages from another
  55. //thread in the local WINS)
  56. struct sockaddr_in CommNtfSockAdd; //stores address bound to
  57. //connection notification socket
  58. #if SPX > 0
  59. SOCKET CommSpxPortHandle = INVALID_SOCKET; //stores SPX port (socket) #
  60. SOCKET CommIpxPortHandle = INVALID_SOCKET; //stores IPX port (socket) #
  61. SOCKET CommIpxNtfSockHandle = INVALID_SOCKET; //stores socket # of socket used
  62. //for listening for connection
  63. //notification messages from another
  64. //thread in the local WINS)
  65. struct sockaddr_ipx CommIpxNtfSockAdd; //stores address bound to
  66. //connection notification socket
  67. #endif
  68. COMM_HDL_T CommExNbtDlgHdl; /*explicit dialogue (used for
  69. *sending UDP requests to nbt nodes */
  70. //
  71. // get rid of it when support for rpc function WinsGetNameAndAdd is
  72. // removed.
  73. //
  74. #if USENETBT == 0
  75. FUTURES("Remove this when support for WinsGetNameOrIpAdd is removed")
  76. FUTURES("Check out ECommGetMyAdd")
  77. BYTE HostName[NMSDB_MAX_NAM_LEN];
  78. #endif
  79. /*
  80. * Local Variable Definitions
  81. */
  82. /*
  83. Externals
  84. */
  85. /*
  86. * Local Function Prototype Declarations
  87. */
  88. VOID
  89. InitOwnAddTbl(
  90. VOID
  91. );
  92. //
  93. // function definitions
  94. //
  95. DWORD
  96. CommCreatePnPNotificationSocket(
  97. )
  98. /*++
  99. Routine Description:
  100. Arguments:
  101. none.
  102. Return Value:
  103. Registry Error.
  104. --*/
  105. {
  106. DWORD Error = ERROR_SUCCESS;
  107. //
  108. // Create a socket
  109. //
  110. //--ft 06/01/2000: make multiple calls to CommCreatePnPNotificationSocket safe
  111. //CommCreatePnPNotificationSocket is called from both ECommInit and ECommGetMyAdd
  112. if (CommPnPNotificationSocket == INVALID_SOCKET)
  113. {
  114. CommPnPNotificationSocket = socket(
  115. PF_INET,
  116. SOCK_DGRAM,
  117. IPPROTO_UDP );
  118. if ( CommPnPNotificationSocket == INVALID_SOCKET ) {
  119. Error = WSAGetLastError();
  120. DBGPRINT1( ERR,"could not create PnP notification socket, %ld.\n", Error );
  121. }
  122. }
  123. return Error;
  124. }
  125. VOID
  126. CommInterfaceChangeNotification(
  127. DWORD Error,
  128. DWORD cbTransferred,
  129. LPWSAOVERLAPPED lpOverlapped,
  130. DWORD dwFlags
  131. )
  132. /*++
  133. Routine Description:
  134. Arguments:
  135. none.
  136. Return Value:
  137. Registry Error.
  138. --*/
  139. {
  140. DBGPRINT1(FLOW, "CommInterfaceChangeNotification with Error value = (%x)\n", Error);
  141. if ( Error == ERROR_SUCCESS ) {
  142. //
  143. // reregister intrface change notification before we process
  144. // the current list change. This is required to avoid misssing
  145. // any interface changes that occur while we are processing
  146. // the current list.
  147. ECommRegisterAddrChange();
  148. if (ECommGetMyAdd(&NmsLocalAdd) == WINS_SUCCESS)
  149. {
  150. WinsEvtLogDetEvt(
  151. TRUE,
  152. WINS_PNP_ADDR_CHANGED,
  153. NULL,
  154. __LINE__,
  155. "dd",
  156. pNmsDbOwnAddTbl->WinsAdd.Add.IPAdd,
  157. NmsLocalAdd.Add.IPAdd);
  158. if (pNmsDbOwnAddTbl->WinsAdd.Add.IPAdd != NmsLocalAdd.Add.IPAdd)
  159. {
  160. //
  161. // Send the reconfig message to the Pull thread
  162. //
  163. // Note: The PULL thread will deallocate memory pointed
  164. // to be pWinsCnf when it gets done
  165. //
  166. ERplInsertQue(
  167. WINS_E_WINSCNF,
  168. QUE_E_CMD_ADDR_CHANGE,
  169. NULL, //no dlg handle
  170. NULL, //no msg
  171. 0, //msg len
  172. NULL, //client ctx
  173. 0
  174. );
  175. }
  176. }
  177. } else {
  178. WINSEVT_LOG_M(Error, WINS_EVT_SFT_ERR);
  179. }
  180. DBGLEAVE("CommInterfaceChangeNotification\n");
  181. }
  182. VOID
  183. ECommRegisterAddrChange()
  184. {
  185. //--ft: bug 86768; 'overlap' shouldn't be allocated on the stack
  186. //since it is passed down to WSAIoctl on an overlapped socket.
  187. static WSAOVERLAPPED overlap;
  188. DWORD Error;
  189. DWORD byteRet;
  190. RtlZeroMemory( &overlap, sizeof(WSAOVERLAPPED));
  191. Error = WSAIoctl(
  192. CommPnPNotificationSocket,
  193. SIO_ADDRESS_LIST_CHANGE,
  194. NULL,
  195. 0,
  196. NULL,
  197. 0,
  198. &byteRet,
  199. &overlap,
  200. CommInterfaceChangeNotification
  201. );
  202. if ( Error != ERROR_SUCCESS && Error == SOCKET_ERROR) {
  203. Error = WSAGetLastError();
  204. if (Error == WSA_IO_PENDING) {
  205. Error = ERROR_SUCCESS;
  206. } else {
  207. DBGPRINT1( ERR,"SIO_INTERFACE_LIST_CHANGE ioctl failed, %ld.\n", Error );
  208. }
  209. }
  210. if (Error != ERROR_SUCCESS ) {
  211. WINSEVT_LOG_M(Error, WINS_EVT_SFT_ERR);
  212. }
  213. return ;
  214. }
  215. VOID
  216. ECommInit(
  217. VOID
  218. )
  219. /*++
  220. Routine Description:
  221. This function is called by the main thread of the process at
  222. process invocation time. It initializes the communication subsystem.
  223. This comprises of
  224. 1)create the TCP and UDP ports
  225. 2)create the TCP and UDP listener threads
  226. None
  227. Externals Used:
  228. None
  229. Called by:
  230. Init() in nms.c
  231. Comments:
  232. None
  233. Return Value:
  234. None
  235. --*/
  236. {
  237. //
  238. // Initialize lists, Tables and Memory
  239. //
  240. CommInit();
  241. //
  242. // Initialize the owner address table with own address
  243. //
  244. InitOwnAddTbl();
  245. // Now register for address change notification
  246. CommCreatePnPNotificationSocket();
  247. ECommRegisterAddrChange();
  248. //
  249. // Create the TCP and UDP ports
  250. //
  251. CommCreatePorts( );
  252. DBGIF(fWinsCnfRplEnabled)
  253. //
  254. // Signal Rpl PULL Thd so that it can go on
  255. //
  256. WinsMscSignalHdl(
  257. RplSyncWTcpThdEvtHdl
  258. );
  259. //
  260. // Init the event array used by ECommProcessDlg (in Push thread)
  261. //
  262. sThdEvtArr[0] = RplSyncWTcpThdEvtHdl;
  263. sThdEvtArr[1] = NmsTermEvt;
  264. /*
  265. * Create the TCP listener thread to monitor the TCP port
  266. */
  267. CommCreateTcpThd();
  268. //
  269. // if Wins is not coming up in the initially paused state, create
  270. // the udp thread.
  271. //
  272. #if INIT_TIME_PAUSE_TEST > 0
  273. // if (!fWinsCnfInitStatePaused)
  274. {
  275. /*
  276. * Create the UDP listener thread to monitor the TCP port
  277. */
  278. CommCreateUdpThd();
  279. }
  280. #else
  281. CommCreateUdpThd();
  282. #endif
  283. return;
  284. }
  285. #if PRSCONN
  286. __inline
  287. ECommIsBlockValid
  288. (
  289. PCOMM_HDL_T pDlgHdl
  290. )
  291. {
  292. return(CommIsBlockValid(pDlgHdl));
  293. }
  294. __inline
  295. BOOL
  296. ECommIsDlgActive
  297. (
  298. PCOMM_HDL_T pDlgHdl
  299. )
  300. /*++
  301. Routine Description:
  302. Arguments:
  303. pDlgHdl -- check if dlg is active
  304. Externals Used:
  305. None
  306. Called by:
  307. Replicator
  308. Comments:
  309. None
  310. Return Value:
  311. --*/
  312. {
  313. #if 0
  314. //
  315. // Check if block is valid. It won't be if the dlg was terminated earlier
  316. //
  317. if (!CommIsBlockValid(pDlgHdl))
  318. {
  319. return(FALSE);
  320. }
  321. #endif
  322. //
  323. //
  324. // Check whether the dlg is still active (i.e. the association is still
  325. // valid.
  326. // CommIsDlgActive is an inline function.
  327. //
  328. return(CommIsDlgActive(pDlgHdl));
  329. }
  330. #endif
  331. STATUS
  332. ECommStartDlg(
  333. PCOMM_ADD_T pAdd, // Address
  334. COMM_TYP_E CommTyp_e,
  335. PCOMM_HDL_T pDlgHdl
  336. )
  337. /*++
  338. Routine Description:
  339. Arguments:
  340. pAdd -- Address of the WINS server with which to start a dlg
  341. CommTyp_e -- Type of dialogue (Pull, Push, Notifier, etc)
  342. pDlgHdl -- Will contain handle to dlg on successful completion of
  343. the function
  344. Externals Used:
  345. None
  346. Called by:
  347. Replicator
  348. Comments:
  349. None
  350. Return Value:
  351. Success status codes -- WINS_SUCCESS
  352. Error status codes -- One of the STATUS codes (see wins.h)
  353. --*/
  354. {
  355. PCOMMASSOC_ASSOC_CTX_T pAssocCtx;
  356. PCOMMASSOC_DLG_CTX_T pDlgCtx;
  357. STATUS RetStat = WINS_SUCCESS;
  358. #ifdef WINSDBG
  359. struct in_addr InAddr;
  360. LPBYTE pstrAdd;
  361. #endif
  362. DBGENTER("ECommStartDlg\n");
  363. /*
  364. Allocate a dlg ctx block
  365. */
  366. pDlgHdl->pEnt = CommAssocAllocDlg();
  367. try {
  368. pDlgCtx = pDlgHdl->pEnt;
  369. pDlgCtx->Role_e = COMMASSOC_DLG_E_EXPLICIT;
  370. pDlgCtx->Typ_e = CommTyp_e;
  371. pDlgHdl->SeqNo = pDlgCtx->Top.SeqNo; //no need actually. (explicit dlg)
  372. //
  373. // Set up an association if we are not simulating an NBT node
  374. //
  375. if (CommTyp_e != COMM_E_NBT)
  376. {
  377. /*
  378. * set up an association
  379. */
  380. CommAssocSetUpAssoc(
  381. pDlgHdl,
  382. pAdd,
  383. CommTyp_e,
  384. &pAssocCtx
  385. );
  386. pDlgCtx->State_e = COMMASSOC_DLG_E_ACTIVE;
  387. //
  388. // No need to store sequence no. since there will never
  389. // be a danger of the assoc. block being reused by some
  390. // some other dialogue (this is an explicit dialogue)
  391. //
  392. pDlgCtx->AssocHdl.pEnt = pAssocCtx;
  393. pDlgCtx->Typ_e = CommTyp_e;
  394. }
  395. else //simulate an NBT node
  396. {
  397. //
  398. // Create a connection to the remote WINS
  399. //
  400. CommConnect(
  401. pAdd,
  402. #if SPX > 0
  403. pAdd->AddTyp_e == COMM_ADD_E_TCPUDPIP ? CommWinsTcpPortNo :
  404. CommWinsSpxPortNo,
  405. #else
  406. CommWinsTcpPortNo,
  407. #endif
  408. &pDlgCtx->SockNo
  409. );
  410. }
  411. } // end of try { }
  412. except(EXCEPTION_EXECUTE_HANDLER) {
  413. //
  414. // Cleanup and reraise the exception
  415. //
  416. CommAssocDeallocDlg(pDlgHdl->pEnt);
  417. pDlgHdl->pEnt = NULL; //let us cover all bases. See SndPushNtf //in rplpull.c
  418. WINS_RERAISE_EXC_M();
  419. }
  420. #ifdef WINSDBG
  421. #if SPX == 0
  422. InAddr.s_addr = htonl(pAdd->Add.IPAdd);
  423. pstrAdd = inet_ntoa(InAddr);
  424. #else
  425. if (pAdd->Add.AddTyp_e == COMM_E_ADD_TCPUDPIP)
  426. {
  427. InAddr.s_addr = htonl(pAdd->Add.IPAdd);
  428. pstrAdd = inet_ntoa(InAddr);
  429. }
  430. else
  431. {
  432. pstrAdd = pAdd->Add.nodenum;
  433. }
  434. #endif
  435. DBGPRINT1(FLOW, "Leaving ECommStartDlg. Dlg started with Host at address -- (%s)\n", pstrAdd);
  436. #endif
  437. DBGLEAVE("ECommStartDlg\n");
  438. return(RetStat);
  439. }
  440. VOID
  441. ECommSndCmd(
  442. IN PCOMM_HDL_T pDlgHdl,
  443. IN MSG_T pMsg,
  444. IN MSG_LEN_T MsgLen,
  445. OUT PMSG_T ppRspMsg,
  446. OUT PMSG_LEN_T pRspMsgLen
  447. )
  448. /*++
  449. Routine Description:
  450. This function is used by the Replicator to send commands to Replicators on remote WINSs. It is also used by the Name Space Manager of a Q
  451. server to send name queriies to the Name Space Manager of an RQ server.
  452. Arguments:
  453. pDlgHdl -- handle to dialogue to use for sending command
  454. pMsg -- Msg (Cmd) to send
  455. MsgLen -- Length of Message
  456. ppRspMsg -- Buffer containing response to command
  457. pRspLen -- Length of response buffer
  458. Externals Used:
  459. None
  460. Called by:
  461. RplPull functions
  462. Comments:
  463. None
  464. Return Value:
  465. None
  466. --*/
  467. {
  468. PCOMMASSOC_ASSOC_CTX_T pAssocCtx;
  469. PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt;
  470. DWORD MsgTyp;
  471. DWORD Opc;
  472. ULONG uTmp;
  473. STATUS RetStat = WINS_SUCCESS;
  474. /*
  475. No need to lock the dialogue since:
  476. currently, only the thread (excluding the COMSYS threads) that
  477. creates a dialogue (explicit dialogue) sends messages on it.
  478. In the future, when multiple threads share the same
  479. dialogue, I will need to lock it or build an elaborate
  480. asynch notification mechanism (for responses)
  481. Also, there is no need to lock the associaation since only this
  482. thread would ever look at it
  483. */
  484. /*
  485. * Send the command
  486. */
  487. CommSend(
  488. pDlgCtx->Typ_e,
  489. &pDlgCtx->AssocHdl,
  490. pMsg,
  491. MsgLen
  492. );
  493. pAssocCtx = pDlgCtx->AssocHdl.pEnt;
  494. /*
  495. Wait for a response
  496. */
  497. RetStat = CommReadStream(
  498. pAssocCtx->SockNo,
  499. TRUE, //do timed recv
  500. ppRspMsg,
  501. pRspMsgLen
  502. );
  503. /*
  504. if bytes read are 0, there was a disconnect. If RetStat is not
  505. success, maybe the recv. timed out or the most severe of
  506. all conditions, maybe the SOCKET_ERROR got returned by
  507. the first RecvData() call in CommReadStream. As far as the
  508. client is concerned, all of these conditions indicate
  509. COMM failure to it. Let us raise that exception.
  510. */
  511. if (( *pRspMsgLen == 0) || (RetStat != WINS_SUCCESS))
  512. {
  513. WINS_RAISE_EXC_M(WINS_EXC_COMM_FAIL);
  514. }
  515. COMM_GET_HEADER_M(*ppRspMsg, Opc, uTmp, MsgTyp);
  516. /*
  517. Let us check that this is not the stop assoc message
  518. */
  519. if (MsgTyp == COMM_STOP_REQ_ASSOC_MSG)
  520. {
  521. //
  522. // We do not disconnect the socket. It will be disconnected as
  523. // a result of an end dialogue on this explicit association
  524. //
  525. // CommDisc(pAssocCtx->SockNo);
  526. //
  527. // Free the buffer
  528. //
  529. ECommFreeBuff(*ppRspMsg);
  530. WINS_RAISE_EXC_M(WINS_EXC_COMM_FAIL);
  531. }
  532. /*
  533. * Strip off the header before returning to the client
  534. * (Replicator)
  535. */
  536. *ppRspMsg = *ppRspMsg + COMM_HEADER_SIZE;
  537. *pRspMsgLen = *pRspMsgLen - COMM_HEADER_SIZE;
  538. return;
  539. } // ECommSndCmd
  540. STATUS
  541. ECommSndRsp(
  542. PCOMM_HDL_T pDlgHdl,
  543. MSG_T pMsg,
  544. MSG_LEN_T MsgLen
  545. )
  546. /*++
  547. Routine Description:
  548. This function is called by the Comm. clients to send messages to
  549. destinations identified by the dialogue. No responses are expected to
  550. these messages.
  551. The function is used for sending responses.
  552. Arguments:
  553. pDlgHdl - handle to dlg to use for sending response
  554. pMsg - message (response) to send
  555. MsgLen - length of message
  556. Externals Used:
  557. None
  558. Called by:
  559. NmsNmh functions, RplPush functions
  560. Comments:
  561. None
  562. Return Value:
  563. Success status codes -- WINS_SUCCESS
  564. Error status codes --
  565. --*/
  566. {
  567. BOOL fLocked = FALSE;
  568. STATUS RetStat = WINS_SUCCESS;
  569. PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt;
  570. DBGENTER("ECommSndRsp\n");
  571. FUTURES("Since we do not want the overhead of an if test for responding")
  572. FUTURES("to nbt requests, split up this function into one callable by")
  573. FUTURES("replicator and the other one by NBT threads. Do note that ")
  574. FUTURES("this will take away some cleanliness of interfacing with COMM")
  575. try {
  576. /*
  577. Check if the dialogue is for UDP communication. If it is, there
  578. is no need for any synchronization.
  579. There is no need to lock the dialogue prior to checking it because
  580. if it is a UDP dialogue, it has to be the one that was allocated
  581. for this request (i.e. there is no possibility that we are now
  582. looking at another UDP dialogue).
  583. */
  584. if (pDlgCtx->Typ_e != COMM_E_UDP)
  585. {
  586. /*
  587. * Lock the dialogue block so that it is not deleted from
  588. * under us. Actually, as things stand currently, an explicit
  589. * dialogue is never used by more than one thread. So, we don't
  590. * have to lock a dialogue if it is an explicit dialogue. Let
  591. * us do it anyway since in the forseeable future, we could have
  592. * multiple threads using the same dialogue (Replicator threads -
  593. * Pull and Notifier). This is small insurance to save us
  594. * from later headaches.
  595. */
  596. fLocked = CommLockBlock(pDlgHdl);
  597. if (fLocked)
  598. {
  599. CommSend(
  600. pDlgCtx->Typ_e,
  601. &pDlgCtx->AssocHdl,
  602. pMsg,
  603. MsgLen
  604. );
  605. }
  606. else //dialogue could not be locked
  607. {
  608. WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_LOCK_ERR);
  609. DBGPRINT0(ERR, "ECommSndRsp: Could not lock the dialogue\n");
  610. /*
  611. *If Dialogue block could not be locked, it means
  612. *that it was freed by the TCP listener thread (Check
  613. *DelAssoc() in comm.c). This would happen only
  614. *if the connection terminated or if a stop assoc
  615. *message was received on it.
  616. *Return a COMM_FAIL error. This will return in
  617. *a search for a termination handler. It is *ok*
  618. * to take this overhead since this is a
  619. * rare error case
  620. */
  621. return(WINS_COMM_FAIL);
  622. }
  623. if (CommUnlockBlock(pDlgHdl) == WINS_FAILURE)
  624. {
  625. RetStat = WINS_FAILURE;
  626. }
  627. else //successfully unlocked the dialogue
  628. {
  629. fLocked = FALSE;
  630. }
  631. }
  632. else // it is dialogue for UDP communication with an NBT node
  633. {
  634. CommSendUdp(
  635. 0,
  636. &(pDlgCtx->FromAdd),
  637. pMsg,
  638. MsgLen
  639. );
  640. /*
  641. We have sent the response. We should now get rid of
  642. the dialogue from the dialogue table. This will
  643. free the heap memory
  644. */
  645. CommAssocDeleteUdpDlgInTbl( pDlgCtx );
  646. }
  647. }
  648. finally {
  649. if (fLocked)
  650. {
  651. CommUnlockBlock(pDlgHdl);
  652. }
  653. }
  654. DBGLEAVE("ECommSndRsp\n");
  655. return(RetStat);
  656. }
  657. STATUS
  658. ECommSendMsg(
  659. PCOMM_HDL_T pDlgHdl,
  660. PCOMM_ADD_T pAdd,
  661. MSG_T pMsg,
  662. MSG_LEN_T MsgLen
  663. )
  664. /*++
  665. Routine Description:
  666. This function is used by the name challenge manager to send queries
  667. and release request to nbt nodes.
  668. It is also used by the replicator to send a Push notification to
  669. a WINS (pull pnr)
  670. Arguments:
  671. pDlgHdl - handle to dlg to use for sending message
  672. pAdd - Address of node to send message to
  673. pMsg - Message to send
  674. MsgLen - Length of message to send
  675. Externals Used:
  676. None
  677. Called by:
  678. NmsChl functions
  679. Comments:
  680. Return Value:
  681. Success status codes -- WINS_SUCCESS
  682. Error status codes --
  683. --*/
  684. {
  685. PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt;
  686. struct sockaddr_in TgtAdd;
  687. //
  688. // if the dialogue is mapped to the UDP port, send a UDP packet
  689. //
  690. if (pDlgCtx->Typ_e == COMM_E_UDP)
  691. {
  692. //
  693. // Don't change from host to net order. CommSendUdp does
  694. // that
  695. //
  696. TgtAdd.sin_addr.s_addr = pAdd->Add.IPAdd;
  697. if(TgtAdd.sin_addr.s_addr == INADDR_NONE)
  698. {
  699. return(WINS_FAILURE);
  700. }
  701. TgtAdd.sin_family = PF_INET;
  702. TgtAdd.sin_port = htons(WINS_NBT_PORT);
  703. //
  704. // Send the message via netbt
  705. //
  706. CommSendUdp( 0, &TgtAdd, pMsg, MsgLen );
  707. }
  708. else // it is a dialogue mapped to a TCP connection
  709. {
  710. //
  711. // Send the message
  712. //
  713. CommSend(
  714. pDlgCtx->Typ_e,
  715. &pDlgCtx->AssocHdl,
  716. pMsg,
  717. MsgLen
  718. );
  719. }
  720. return(WINS_SUCCESS);
  721. }
  722. STATUS
  723. ECommEndDlg(
  724. PCOMM_HDL_T pDlgHdl
  725. )
  726. /*++
  727. Routine Description:
  728. This function is used to end a dialogue.
  729. The processing depends upon the type of dialogue
  730. 1)if the dlg is an implicit UDP dialogue. it is deleted from
  731. the dlg table and the memory is freed.
  732. 2)if the dlg is an implicit dlg, a stop assoc.
  733. message is sent on the association
  734. 3)if the dlg is an explicit dlg, a stop assoc. message is
  735. message is sent on the association and the association is
  736. terminated
  737. Arguments:
  738. pDlgHdl - Handle to dlg to end
  739. Externals Used:
  740. None
  741. Called by:
  742. RplPull functions, HandleUpdNtf in rplpush.c (by the Push thread)
  743. Comments:
  744. Currently, there is no need to lock an explicit dialogue since only
  745. one thread accesses it any time (currently). In the future, if we
  746. have multiple threads accessing the same dialogue, we will do locking
  747. Return Value:
  748. Success status codes -- WINS_SUCCESS
  749. Error status codes --
  750. --*/
  751. {
  752. BYTE Msg[COMMASSOC_ASSOC_MSG_SIZE];
  753. DWORD MsgLen = COMMASSOC_ASSOC_MSG_SIZE;
  754. PCOMMASSOC_ASSOC_CTX_T pAssocCtx;
  755. PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt;
  756. BOOL fLocked;
  757. DBGENTER("ECommEndDlg\n");
  758. //
  759. // If there is no dialogue to be ended, return WINS_INVALID_HDL
  760. // Note: There can be cases in failure recovery where ECommEndDlg
  761. // may be called to end a dialogue that was never got started or
  762. // got ended prematurely. Though an error status is returned, the
  763. // caller, when doing failure recovery, may ignore the return status
  764. // of this function. In case of fatal error conditions, an exception
  765. // will be raised which the caller can not ignore.
  766. //
  767. if (pDlgCtx == NULL)
  768. {
  769. DBGLEAVE("ECommEndDlg\n");
  770. return(WINS_INVALID_HDL);
  771. }
  772. //
  773. // In case it is an implicit UDP dialogue, there is no danger
  774. // of it being freed from under us, so there is no need to lock.
  775. // In case it is an implicit TCP dialogue, it could get freed
  776. // and even reallocated from under us, but reallocation will only
  777. // be for TCP, so there is no danger since we do lock the dlg
  778. // block if it is a TCP dlg block (if there has been a reallocation,
  779. // the lock attempt will fail.)
  780. //
  781. if (pDlgCtx->Role_e == COMMASSOC_DLG_E_IMPLICIT)
  782. {
  783. if (pDlgCtx->Typ_e == COMM_E_UDP)
  784. {
  785. //
  786. // Delete the dialogue from the table and free the
  787. // heap memory
  788. //
  789. CommAssocDeleteUdpDlgInTbl( pDlgCtx );
  790. }
  791. else // it is a TCP dialogue.
  792. {
  793. fLocked = CommLockBlock(pDlgHdl);
  794. //
  795. // If we could lock it, the dlg is ok. If we could not
  796. // lock it, it means that the dlg was freed due to the
  797. // the assoc. going down. We have nothing more to do.
  798. //
  799. if (fLocked)
  800. {
  801. pAssocCtx = pDlgCtx->AssocHdl.pEnt;
  802. //
  803. // The stop assoc. message will result in the
  804. // the other WINS terminating the connection which
  805. // result in all cleanup at our end
  806. //
  807. CommAssocFrmStopAssocReq(
  808. pAssocCtx,
  809. Msg,
  810. MsgLen,
  811. COMMASSOC_E_MSG_ERR
  812. );
  813. try {
  814. CommSendAssoc(
  815. pAssocCtx->SockNo,
  816. Msg,
  817. MsgLen
  818. );
  819. }
  820. except(EXCEPTION_EXECUTE_HANDLER) {
  821. //
  822. // No need to do any cleanup. This is an
  823. // implicit dlg. The tcp listener thread will
  824. // do the cleanup. Currently, it never calls
  825. // ECommEndDlg for an implicit dlg so the client
  826. // has got to be rpl
  827. //
  828. DBGPRINTEXC("CommEndDlg");
  829. }
  830. CommUnlockBlock(pDlgHdl);
  831. }
  832. }
  833. }
  834. else // it is an explicit dialogue
  835. {
  836. if (pDlgCtx->Typ_e != COMM_E_NBT)
  837. {
  838. CommEndAssoc(&pDlgCtx->AssocHdl);
  839. }
  840. /*
  841. * Dealloc the dialogue in order to put it in the free list
  842. */
  843. CommAssocDeallocDlg( pDlgCtx );
  844. #if PRSCONN
  845. FUTURES("Init the dlg hdl in the caller - good software engineering practice")
  846. //
  847. // The dlg is ended. Let us init the dlg hdl to null so that
  848. // it is not used again. Strictly speaking, we should do let
  849. // the caller do this. For now, we will do it here
  850. //
  851. ECOMM_INIT_DLG_HDL_M(pDlgHdl);
  852. #endif
  853. }
  854. DBGLEAVE("ECommEndDlg\n");
  855. return(WINS_SUCCESS);
  856. }
  857. #if 0
  858. ECommSendtoAllQ(
  859. MSG_T pMsg,
  860. MSG_LEN_T MsgLen
  861. )
  862. /*++
  863. Routine Description:
  864. This function is called to send a message to all Q servers.
  865. Arguments:
  866. Externals Used:
  867. None
  868. Called by:
  869. Comments:
  870. May use it in the future. Needs work.
  871. Return Value:
  872. Success status codes --
  873. Error status codes --
  874. --*/
  875. {
  876. /*
  877. if there is no dialogue pertaining to a Q server, return failure
  878. */
  879. if (IsListEmpty(&QservDlgList))
  880. {
  881. return(WINS_FAILURE);
  882. }
  883. /*
  884. find all the dialogues pertaining to Q servers
  885. */
  886. while ((pQservDlg = GetNext(&QservDlgList)) != &QservDlgList)
  887. {
  888. CommSendAssoc(pQservDlg->pAssocCtx->SockNo, pMsg, MsgLen);
  889. }
  890. return(WINS_SUCCESS);
  891. }
  892. #endif
  893. STATUS
  894. ECommAlloc(
  895. OUT LPVOID *ppBuff,
  896. IN DWORD BuffSize
  897. )
  898. /*++
  899. Routine Description:
  900. This function is called by by the replicator to allocate a buffer for
  901. sending to another WINS (over a TCP connection)
  902. Arguments:
  903. ppBuff - Buffer allocated by function
  904. BuffSize - Size of buffer to be allocated
  905. Externals Used:
  906. None
  907. Return Value:
  908. Success status codes -- WINS_SUCCESS
  909. Error status codes --
  910. Error Handling:
  911. Called by:
  912. Side Effects:
  913. Comments:
  914. Challenge manager should not call this function. When it is coded,
  915. it will call AllocUdpBuff which will be made an external for this
  916. purpose (CommAllocUdpBuff)
  917. --*/
  918. {
  919. DWORD Size = COMM_HEADER_SIZE +
  920. sizeof(COMM_BUFF_HEADER_T) + sizeof(LONG);
  921. PCOMM_BUFF_HEADER_T pCommHdr;
  922. WinsMscAlloc( Size + BuffSize, ppBuff);
  923. #if 0
  924. *ppBuff = CommAlloc(
  925. NULL, //no table
  926. Size + BuffSize
  927. );
  928. #endif
  929. pCommHdr = (PCOMM_BUFF_HEADER_T)((LPBYTE)(*ppBuff) + sizeof(LONG));
  930. pCommHdr->Typ_e = COMM_E_TCP; //until we know better
  931. *ppBuff = (LPBYTE)(*ppBuff) + Size;
  932. return(WINS_SUCCESS);
  933. }
  934. #if 0
  935. VOID
  936. ECommDealloc(
  937. LPVOID pBuff
  938. )
  939. /*++
  940. Routine Description:
  941. This is a wrapper around CommDealloc. It conforms to the
  942. prototype required by RtlInitializeGenericTbl func.
  943. Arguments:
  944. pBuf -- Buffer to deallocate
  945. Externals Used:
  946. None
  947. Return Value:
  948. None
  949. Error Handling:
  950. Called by:
  951. Side Effects:
  952. Comments:
  953. Not being used currently
  954. --*/
  955. {
  956. LPVOID pTmp = (LPBYTE)pBuff - COMM_HEADER_SIZE;
  957. WinsMscDealloc(pTmp);
  958. #if 0
  959. CommDealloc(NULL, pTmp);
  960. #endif
  961. return;
  962. }
  963. #endif
  964. DWORD
  965. ECommCompAdd(
  966. PCOMM_ADD_T pFirstAdd,
  967. PCOMM_ADD_T pSecAdd
  968. )
  969. /*++
  970. Routine Description:
  971. the function compares two host addresses
  972. Arguments:
  973. pFirstAdd - Address of a node
  974. pSecondAdd - Address of a node
  975. Externals Used:
  976. None
  977. Return Value:
  978. COMM_SAME_ADD
  979. COMM_DIFF_ADD
  980. Error Handling:
  981. Called by:
  982. Side Effects:
  983. Comments:
  984. None
  985. --*/
  986. {
  987. #if 0
  988. if ((pFirstAdd->AddTyp_e == COMM_ADD_E_TCPUDPIP) &&
  989. (pSecAdd->AddTyp_e == COMM_ADD_E_TCPUDPIP))
  990. #endif
  991. {
  992. if (pFirstAdd->Add.IPAdd == pSecAdd->Add.IPAdd)
  993. {
  994. return(COMM_SAME_ADD);
  995. }
  996. }
  997. return(COMM_DIFF_ADD);
  998. }
  999. int
  1000. __cdecl
  1001. ECommCompareAdd(
  1002. const void *pKey1,
  1003. const void *pKey2
  1004. )
  1005. /*++
  1006. Routine Description:
  1007. the function compares two host addresses
  1008. Arguments:
  1009. pFirstAdd - Address of a node
  1010. pSecondAdd - Address of a node
  1011. Externals Used:
  1012. None
  1013. Return Value:
  1014. Error Handling:
  1015. Called by:
  1016. Side Effects:
  1017. Comments:
  1018. None
  1019. --*/
  1020. {
  1021. const COMM_ADD_T *pFirstAdd = pKey1;
  1022. const COMM_ADD_T *pSecAdd = pKey2;
  1023. return (pFirstAdd->Add.IPAdd > pSecAdd->Add.IPAdd) ?
  1024. 1 :
  1025. (pFirstAdd->Add.IPAdd < pSecAdd->Add.IPAdd) ?
  1026. -1:
  1027. 0;
  1028. }
  1029. VOID
  1030. ECommFreeBuff(
  1031. IN MSG_T pMsg
  1032. )
  1033. /*++
  1034. Routine Description:
  1035. This function is called to free a buffer allocated earlier by
  1036. COMSYS. The function checks the buffer header to determine which
  1037. deallocation function to call
  1038. The usefulness of this function stems from the fact that a buffer
  1039. can be made independent of the dialogue (or association) it came from
  1040. in the sense that we don't need to pass information about such a
  1041. dlg or assoc when freeing the buffer. This saves us from locking
  1042. and unlocking.
  1043. Arguments:
  1044. pMsg -- Buffer to free
  1045. Externals Used:
  1046. None
  1047. Return Value:
  1048. None
  1049. Error Handling:
  1050. Called by:
  1051. Side Effects:
  1052. SndNamRegRsp, SndNamRelRsp, SndNamQueryRsp in nmsnmh.c
  1053. Comments:
  1054. None
  1055. --*/
  1056. {
  1057. #if USENETBT > 0
  1058. PCOMM_BUFF_HEADER_T pHdr = (PCOMM_BUFF_HEADER_T)
  1059. (pMsg - COMM_NETBT_REM_ADD_SIZE -
  1060. sizeof(COMM_BUFF_HEADER_T));
  1061. #else
  1062. PCOMM_BUFF_HEADER_T pHdr = (PCOMM_BUFF_HEADER_T)
  1063. (pMsg - sizeof(COMM_BUFF_HEADER_T));
  1064. #endif
  1065. if (pHdr->Typ_e == COMM_E_UDP)
  1066. {
  1067. WinsMscHeapFree(
  1068. CommUdpBuffHeapHdl,
  1069. pHdr
  1070. );
  1071. }
  1072. else
  1073. {
  1074. WinsMscHeapFree(CommAssocTcpMsgHeapHdl, (LPBYTE)pHdr - sizeof(LONG));
  1075. // WinsMscDealloc((LPBYTE)pHdr - sizeof(LONG));
  1076. }
  1077. return;
  1078. }
  1079. VOID
  1080. InitOwnAddTbl(
  1081. VOID
  1082. )
  1083. /*++
  1084. Routine Description:
  1085. This function uses the local address of the WINS (i.e. the host
  1086. address) to overwrite the NmsDbOwnAddTbl array entry
  1087. pertaining to the local WINS if different
  1088. Arguments:
  1089. None
  1090. Externals Used:
  1091. None
  1092. Return Value:
  1093. None
  1094. Error Handling:
  1095. Called by:
  1096. CommInit (in the main thread)
  1097. Side Effects:
  1098. Comments:
  1099. There is no need to synchronize over the NmsDbOwnAddTbl since
  1100. the PULL thread will not touch it until it initiates the pull protocol
  1101. --*/
  1102. {
  1103. COMM_IP_ADD_T IPAddInDbTbl;
  1104. //
  1105. // if the address of the owner with owner id = NMSDB_LOCAL_OWNER_ID
  1106. // is different from mine (i.e. local WINS)
  1107. // change it to mine. I always own all entries tagged with
  1108. // owner id of 0. The fact that the address is different
  1109. // means that the database was earlier used by a WINS at
  1110. // a different address.
  1111. //
  1112. IPAddInDbTbl = pNmsDbOwnAddTbl->WinsAdd.Add.IPAdd;
  1113. if (
  1114. IPAddInDbTbl != NmsLocalAdd.Add.IPAdd
  1115. )
  1116. {
  1117. //
  1118. // IPAddInDbTbl will be zero if there is no entry in the
  1119. // local db having NMSDB_LOCAL_OWNER_ID as the owner field
  1120. // value
  1121. //
  1122. NmsDbWriteOwnAddTbl (
  1123. IPAddInDbTbl == 0 ?
  1124. NMSDB_E_INSERT_REC : NMSDB_E_MODIFY_REC,
  1125. NMSDB_LOCAL_OWNER_ID,
  1126. &NmsLocalAdd,
  1127. NMSDB_E_WINS_ACTIVE,
  1128. &NmsDbStartVersNo,
  1129. &NmsDbUid
  1130. );
  1131. pNmsDbOwnAddTbl->WinsAdd = NmsLocalAdd;
  1132. pNmsDbOwnAddTbl->WinsState_e = NMSDB_E_WINS_ACTIVE;
  1133. pNmsDbOwnAddTbl->MemberPrec = WINSCNF_HIGH_PREC;
  1134. pNmsDbOwnAddTbl->StartVersNo = NmsDbStartVersNo;
  1135. pNmsDbOwnAddTbl->Uid = NmsDbUid;
  1136. }
  1137. return;
  1138. }
  1139. BOOL
  1140. ECommProcessDlg(
  1141. PCOMM_HDL_T pDlgHdl,
  1142. COMM_NTF_CMD_E Cmd_e
  1143. )
  1144. /*++
  1145. Routine Description:
  1146. This function is called to either start or stop monitoring a
  1147. dialogue. It sends a message to the TCP listener thread (a UDP
  1148. datagram) on the notification socket.
  1149. Arguments:
  1150. pDlgHdl - Dialogue handle
  1151. Cmd_e - Cmd (COMM_E_NTF_START_MON or COMM_E_NTF_STOP_MON)
  1152. Externals Used:
  1153. RplSyncWTcpThdEvtHdl
  1154. Return Value:
  1155. None
  1156. Error Handling:
  1157. Called by:
  1158. SndUpdNtf in rplpull.c, HdlUpdNtf in rplpush.c
  1159. Side Effects:
  1160. Comments:
  1161. The client should not expect to use the dailogue after calling
  1162. this functions
  1163. Only the Push thread calls this function
  1164. --*/
  1165. {
  1166. COMM_NTF_MSG_T NtfMsg;
  1167. BOOL fRetStat = TRUE;
  1168. DWORD ArrInd;
  1169. DBGENTER("ECommProcessDlg\n");
  1170. //
  1171. //Format the message to send in the UDP datagram
  1172. //
  1173. if (CommLockBlock(pDlgHdl))
  1174. {
  1175. PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt;
  1176. PCOMMASSOC_ASSOC_CTX_T pAssocCtx = pDlgCtx->AssocHdl.pEnt;
  1177. NtfMsg.SockNo = pAssocCtx->SockNo;
  1178. NtfMsg.Cmd_e = Cmd_e;
  1179. NtfMsg.AssocHdl = pDlgCtx->AssocHdl;
  1180. NtfMsg.DlgHdl = *pDlgHdl;
  1181. CHECK("If TCP protocol is installed. If not, use the Spx notification socket")
  1182. CommUnlockBlock(pDlgHdl);
  1183. CommSendUdp(
  1184. CommNtfSockHandle,
  1185. //CommUdpPortHandle, //sending port
  1186. &CommNtfSockAdd, //Address to send to
  1187. (LPBYTE)&NtfMsg, //socket no to send
  1188. COMM_NTF_MSG_SZ
  1189. );
  1190. DBGPRINT2(DET,
  1191. "ECommProcessDlg: Sent %s monitoring message to TCP listener thread for socket no (%d)\n",
  1192. Cmd_e == COMM_E_NTF_START_MON ? "start" : "stop",
  1193. NtfMsg.SockNo
  1194. );
  1195. //
  1196. // if the command is to "stop monitoring the dlg" we have to wait
  1197. // until the TCP listener thread has receive this message and
  1198. // taken the socket out of its array of sockets
  1199. //
  1200. if (Cmd_e == COMM_E_NTF_STOP_MON)
  1201. {
  1202. //
  1203. //Wait to be signaled by the TCP listener thread indicating that
  1204. // it has removed the socket from the list of sockets that it
  1205. // is monitoring. We also want to check the term. event since
  1206. // the tcp thread may have terminated as a result of
  1207. // a termination of WINS.
  1208. //
  1209. //WinsMscWaitInfinite(RplSyncWTcpThdEvtHdl);
  1210. WinsMscWaitUntilSignaled(
  1211. sThdEvtArr,
  1212. sizeof(sThdEvtArr)/sizeof(HANDLE),
  1213. &ArrInd,
  1214. FALSE
  1215. );
  1216. if (ArrInd == 0)
  1217. {
  1218. if (fCommDlgError)
  1219. {
  1220. DBGPRINT0(ERR, "ECommProcessDlg: The tcp listener thread indicated that the IMPLICIT assoc has been deallocated. TIMING WINDOW\n");
  1221. fRetStat = FALSE;
  1222. fCommDlgError = FALSE;
  1223. }
  1224. }
  1225. else
  1226. {
  1227. //
  1228. //Signaled for termination
  1229. //
  1230. WinsMscTermThd(WINS_SUCCESS, WINS_DB_SESSION_EXISTS);
  1231. }
  1232. }
  1233. }
  1234. else
  1235. {
  1236. DBGPRINT1(ERR, "ECommProcessDlg: Could not lock the (%s) dlg block. Maybe the assocication and dialogue got deallocated\n", Cmd_e == COMM_E_NTF_STOP_MON ? "IMPLICIT" : "EXPLICIT");
  1237. fRetStat = FALSE;
  1238. }
  1239. //
  1240. // All done. Return
  1241. //
  1242. DBGLEAVE("ECommProcessDlg\n");
  1243. return(fRetStat);
  1244. }
  1245. //--ft: 11/30/99
  1246. STATUS
  1247. CommRaiseMyDnsAdd(
  1248. IN OUT LPSOCKET_ADDRESS_LIST pAddrList
  1249. )
  1250. //++
  1251. //Routine Description:
  1252. //
  1253. // This function is called to find out the address returned by DNS when
  1254. // the server address is queried through gethostbyname().
  1255. //
  1256. //Arguments:
  1257. // pAddrList - the list of local interfaces as returned by WSAIoctl(SIO_ADDRESS_LIST_QUERY)
  1258. //--
  1259. {
  1260. DWORD Error = ERROR_SUCCESS;
  1261. struct hostent *pHostEnt;
  1262. BYTE HostName[NMSDB_MAX_NAM_LEN];
  1263. CHAR **pHostIter;
  1264. // Get host's name
  1265. if (gethostname(HostName, NMSDB_MAX_NAM_LEN) == SOCKET_ERROR)
  1266. {
  1267. return WSAGetLastError();
  1268. }
  1269. // Get host's HOSTENT structure
  1270. pHostEnt = gethostbyname(HostName);
  1271. if (pHostEnt == NULL)
  1272. {
  1273. return WSAGetLastError();
  1274. }
  1275. // For each address returned by DNS
  1276. for (pHostIter = pHostEnt->h_addr_list; (*pHostIter) != NULL; pHostIter++)
  1277. {
  1278. INT i;
  1279. // For each address in the interfaces list
  1280. for (i = 0; i < pAddrList->iAddressCount; i++)
  1281. {
  1282. LPSOCKADDR_IN pSockIf = (LPSOCKADDR_IN)(pAddrList->Address[i].lpSockaddr);
  1283. // it is assumed the address is IP (DWORD size)
  1284. if (WINSMSC_COMPARE_MEMORY_M(
  1285. (*pHostIter),
  1286. &(pSockIf->sin_addr),
  1287. pHostEnt->h_length) == (UINT)pHostEnt->h_length)
  1288. {
  1289. // bring the DNS address in front of the interfaces list if needed
  1290. // this is where the address to be used will be picked up from
  1291. if (i != 0)
  1292. {
  1293. LPSOCKADDR_IN pSockIfAtZero = (LPSOCKADDR_IN)(pAddrList->Address[0].lpSockaddr);
  1294. WINSMSC_COPY_MEMORY_M(
  1295. pSockIfAtZero,
  1296. pSockIf,
  1297. sizeof(SOCKADDR_IN)
  1298. );
  1299. }
  1300. // return success
  1301. return Error;
  1302. } // end_if success in matching dns address with if address
  1303. } // end_for each interface address
  1304. } // end_for each dns address
  1305. // at this point is kind'a weird: either no DNS address could be found in the interfaces list
  1306. // or the interfaces list is just empty (no interfaces?)
  1307. // in either cases, this will be handled by the caller - the interfaces list is untouched
  1308. return Error;
  1309. }
  1310. STATUS
  1311. ECommGetMyAdd(
  1312. IN OUT PCOMM_ADD_T pAdd
  1313. )
  1314. /*++
  1315. Routine Description:
  1316. This function is called to find out the name and address of the
  1317. local machine and store it for later use.
  1318. Arguments:
  1319. pAdd - pointer to buffer to contain the address
  1320. Externals Used:
  1321. NmsLocalAdd
  1322. Return Value:
  1323. None
  1324. Error Handling:
  1325. Called by:
  1326. Init() in nms.c
  1327. Side Effects:
  1328. Comments:
  1329. THIS MUST BE THE FIRST COMM FUNCTION TO BE CALLED IN WINS. This
  1330. is so that WSAStartup is called prior to calling any winsock functions
  1331. --*/
  1332. {
  1333. DWORD Error;
  1334. int RetVal;
  1335. DWORD RetStat = WINS_SUCCESS;
  1336. NTSTATUS RetStatus;
  1337. static BOOL bWSAStarted = FALSE;
  1338. WSADATA wskData;
  1339. DBGENTER("ECommGetMyAdd\n");
  1340. /*
  1341. * Let us call the WSAStartup function. This function needs
  1342. * to be called before any other wins socket function can be
  1343. * called.
  1344. */
  1345. // added the bWSAStarted variable to avoid making several subsequent
  1346. // calls to WSAStartup. Also it looks like there is no matching
  1347. // WSACleanup call at this time.
  1348. if (!bWSAStarted)
  1349. {
  1350. if (WSAStartup(0x101, &wskData) || (wskData.wVersion != 0x101))
  1351. {
  1352. WinsEvtLogDetEvt(
  1353. FALSE,
  1354. WINS_PNP_FAILURE,
  1355. NULL,
  1356. __LINE__,
  1357. "d",
  1358. WINS_EXC_FATAL_ERR);
  1359. WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
  1360. }
  1361. bWSAStarted = TRUE;
  1362. }
  1363. //
  1364. // If this is a cluster machine, always use cluster Ip resource address
  1365. //
  1366. if (WinsClusterIpAddress)
  1367. {
  1368. pAdd->Add.IPAdd = WinsClusterIpAddress;
  1369. }
  1370. else
  1371. {
  1372. DWORD dwAddrListSz = 0; // size of the ioctl out buffer
  1373. LPSOCKET_ADDRESS_LIST pAddrList = NULL; // pointer to the ioctl out buffer
  1374. Error = CommCreatePnPNotificationSocket();
  1375. if (Error == ERROR_SUCCESS)
  1376. {
  1377. // make one Ioctl call to get the required size of the output buffer
  1378. // this should fail with SOCKET_ERROR and with LastError = WSAEFAULT
  1379. Error = WSAIoctl(
  1380. CommPnPNotificationSocket,
  1381. SIO_ADDRESS_LIST_QUERY,
  1382. NULL,
  1383. 0,
  1384. NULL,
  1385. 0,
  1386. &dwAddrListSz,
  1387. NULL,
  1388. NULL
  1389. );
  1390. }
  1391. // if CommCreatePnPNotificationSocket failed, Error is supposed to be a WSAError
  1392. // and not SOCKET_ERROR. This avoids calling WSAIoctl a second time and the error
  1393. // will be captured in the next if()
  1394. // we should get an error with the LastError = WSAEFAULT
  1395. if (Error == SOCKET_ERROR && WSAGetLastError() == WSAEFAULT)
  1396. {
  1397. WinsMscAlloc(dwAddrListSz, &pAddrList);
  1398. // make a second IoctlCall in order to get the list of addresses in
  1399. // the newly allocated buffer. This is expected to succeed
  1400. Error = WSAIoctl(
  1401. CommPnPNotificationSocket,
  1402. SIO_ADDRESS_LIST_QUERY,
  1403. NULL,
  1404. 0,
  1405. pAddrList,
  1406. dwAddrListSz,
  1407. &dwAddrListSz,
  1408. NULL,
  1409. NULL
  1410. );
  1411. }
  1412. // on success, go raise the first address known by DNS
  1413. // this hack is needed in order to get the first adaptor from the binding list.
  1414. // It seems like gethostbyname returns the adaptors in binding order while WSAIoctl does not.
  1415. if (Error == 0)
  1416. {
  1417. // this is another hack: it looks like DNS is not refreshing the addresses instantly. For instance,
  1418. // plugging out the cable for the first ip from the DNS list triggers CommInterfaceChangeNotification
  1419. // but while in this function gethostbyname() still shows the address that went away as the first
  1420. // one in the list. Add 1/2 sec delay here to let DNS update its addresses and after that attempt
  1421. // to raise in the list returned by SIO_ADDRESS_LIST_QUERY the first address known by DNS.
  1422. Sleep(500);
  1423. Error = CommRaiseMyDnsAdd(pAddrList);
  1424. }
  1425. if (Error != 0)
  1426. {
  1427. Error = WSAGetLastError();
  1428. WinsEvtLogDetEvt(
  1429. FALSE,
  1430. WINS_PNP_FAILURE,
  1431. NULL,
  1432. __LINE__,
  1433. "d",
  1434. Error);
  1435. DBGPRINT1(ERR,
  1436. "ECommGetMyAdd:WSAIoctl(SIO_ADDRESS_LIST_QUERY) failed with error %d\n", Error);
  1437. if (pAddrList != NULL)
  1438. {
  1439. WinsMscDealloc(pAddrList);
  1440. pAddrList = NULL;
  1441. }
  1442. WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
  1443. }
  1444. if (pAddrList->iAddressCount > 0)
  1445. {
  1446. // why fooling around - pAdd->Add.IPAdd is a DWORD anyhow.
  1447. pAdd->Add.IPAdd =
  1448. ((LPSOCKADDR_IN)(pAddrList->Address[0].lpSockaddr))->sin_addr.s_addr;
  1449. }
  1450. else
  1451. {
  1452. // just in case no addresses were passed up by the Ioctl, set the address
  1453. // to 0. It will be seen as such a couple lines down.
  1454. pAdd->Add.IPAdd = 0;
  1455. }
  1456. if (pAddrList != NULL)
  1457. {
  1458. WinsMscDealloc(pAddrList);
  1459. pAddrList = NULL;
  1460. }
  1461. //
  1462. // Initialize the structure
  1463. //
  1464. pAdd->Add.IPAdd = ntohl(pAdd->Add.IPAdd);
  1465. }
  1466. //
  1467. // This prints the address in reverse order, that's ok
  1468. //
  1469. DBGPRINT1(DET, "ECommGetMyAdd: Binding to Nbt interface %s\n",
  1470. inet_ntoa(*(struct in_addr *)&pAdd->Add.IPAdd));
  1471. //
  1472. // If we have a 0 address or a loopback address, it means that the
  1473. // address went away. Wait for one to come back.
  1474. //
  1475. if ((WinsCnf.State_e != WINSCNF_E_TERMINATING) &&
  1476. ((pAdd->Add.IPAdd & 0xff000000) != (INADDR_LOOPBACK & 0xff000000)) &&
  1477. (pAdd->Add.IPAdd != 0))
  1478. {
  1479. try
  1480. {
  1481. if (WinsCnfNbtHandle)
  1482. {
  1483. NTSTATUS status;
  1484. IO_STATUS_BLOCK iosb;
  1485. tWINS_SET_INFO setInfo;
  1486. // if there is already a Nbt handle, just rebind it
  1487. setInfo.IpAddress = pAdd->Add.IPAdd;
  1488. // this ioctl is just notifying NetBt on the address change.
  1489. // it should succeed with STATUS_SUCCESS - no reason for 'pending'
  1490. // hence no reason for passing down an Apc or an event handle.
  1491. status = NtDeviceIoControlFile(
  1492. WinsCnfNbtHandle, // Handle
  1493. NULL, // Event
  1494. NULL, // ApcRoutine
  1495. NULL, // ApcContext
  1496. &iosb, // IoStatusBlock
  1497. IOCTL_NETBT_WINS_SET_INFO, // IoControlCode
  1498. &setInfo, // InputBuffer
  1499. sizeof(tWINS_SET_INFO), // Buffer Length
  1500. NULL, // Output Buffer
  1501. 0 // Output BufferSize
  1502. );
  1503. ASSERT(status == STATUS_SUCCESS);
  1504. }
  1505. else
  1506. {
  1507. // open netbt handle with interface having this address
  1508. CommOpenNbt(pAdd->Add.IPAdd);
  1509. }
  1510. // We need to get all netbt interfaces' Ip addresses. They are sent
  1511. // via multicast packet to other wins servers to support find self
  1512. // partner feature.
  1513. CommGetNetworkAdd();
  1514. pAdd->AddTyp_e = COMM_ADD_E_TCPUDPIP;
  1515. pAdd->AddLen = sizeof(COMM_IP_ADD_T);
  1516. }
  1517. except(EXCEPTION_EXECUTE_HANDLER)
  1518. {
  1519. WinsEvtLogDetEvt(
  1520. FALSE,
  1521. WINS_PNP_FAILURE,
  1522. NULL,
  1523. __LINE__,
  1524. "d",
  1525. GetExceptionCode());
  1526. WINS_RERAISE_EXC_M();
  1527. }
  1528. }
  1529. else
  1530. {
  1531. RetStat = WINS_FAILURE;
  1532. }
  1533. DBGLEAVE("ECommGetMyAdd\n");
  1534. return(RetStat);
  1535. }