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.

943 lines
21 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. net\routing\ip\rtrmgr\mhrtbt.c
  5. Abstract:
  6. Multicast heartbeat
  7. Revision History:
  8. Amritansh Raghav
  9. --*/
  10. #include "allinc.h"
  11. HANDLE g_hMHbeatSocketEvent;
  12. DWORD
  13. SetMHeartbeatInfo(
  14. IN PICB picb,
  15. IN PRTR_INFO_BLOCK_HEADER pInfoHdr
  16. )
  17. /*++
  18. Routine Description
  19. Sets multicast heartbeat information passed to the ICB.
  20. Locks
  21. Must be called with ICB_LIST lock held as WRITER
  22. Arguments
  23. picb The ICB of the interface for whom the multicast hearbeat
  24. related variables have to be set
  25. pInfoHdr Interface Info header
  26. Return Value
  27. None
  28. --*/
  29. {
  30. PMCAST_HBEAT_INFO pInfo;
  31. PRTR_TOC_ENTRY pToc;
  32. DWORD dwResult;
  33. PMCAST_HBEAT_CB pHbeatCb;
  34. TraceEnter("SetMHeartbeatInfo");
  35. pHbeatCb = &picb->mhcHeartbeatInfo;
  36. pToc = GetPointerToTocEntry(IP_MCAST_HEARBEAT_INFO,
  37. pInfoHdr);
  38. if(!pToc)
  39. {
  40. //
  41. // Leave things as they are
  42. //
  43. TraceLeave("SetMHeartbeatInfo");
  44. return NO_ERROR;
  45. }
  46. pInfo = (PMCAST_HBEAT_INFO)GetInfoFromTocEntry(pInfoHdr,
  47. pToc);
  48. if((pToc->InfoSize is 0) or (pInfo is NULL))
  49. {
  50. //
  51. // If the size is zero, stop detecting
  52. //
  53. DeActivateMHeartbeat(picb);
  54. //
  55. // Also, blow away any old info
  56. //
  57. ZeroMemory(pHbeatCb,
  58. sizeof(MCAST_HBEAT_CB));
  59. //
  60. // Set the socket to invalid
  61. //
  62. pHbeatCb->sHbeatSocket = INVALID_SOCKET;
  63. return NO_ERROR;
  64. }
  65. //
  66. // Set the info present. We dont care if resolution is in progress
  67. // because it will find that the name has changed or that detection has
  68. // been deactivated and will not do anything
  69. //
  70. //
  71. // If the address protocol or port changes deactivate the heartbeat
  72. //
  73. if((pInfo->bActive is FALSE) or
  74. (wcsncmp(pInfo->pwszGroup,
  75. pHbeatCb->pwszGroup,
  76. MAX_GROUP_LEN) isnot 0) or
  77. (pInfo->byProtocol isnot pHbeatCb->byProtocol) or
  78. (pInfo->wPort isnot pHbeatCb->wPort))
  79. {
  80. DeActivateMHeartbeat(picb);
  81. }
  82. //
  83. // Copy out the info
  84. //
  85. wcsncpy(pHbeatCb->pwszGroup,
  86. pInfo->pwszGroup,
  87. MAX_GROUP_LEN);
  88. pHbeatCb->pwszGroup[MAX_GROUP_LEN - 1] = UNICODE_NULL;
  89. pHbeatCb->wPort = pInfo->wPort;
  90. pHbeatCb->byProtocol = pInfo->byProtocol;
  91. pHbeatCb->ullDeadInterval =
  92. (ULONGLONG)(60 * SYS_UNITS_IN_1_SEC * pInfo->ulDeadInterval);
  93. //
  94. // Leave the group and socket as they are
  95. //
  96. //
  97. // If the info says that detection should be on, but the i/f is not
  98. // detecting, either it is being switched on or it was deactivated due
  99. // to a info change and needs to be on
  100. //
  101. dwResult = NO_ERROR;
  102. if((pHbeatCb->bActive is FALSE) and
  103. (pInfo->bActive is TRUE))
  104. {
  105. pHbeatCb->bActive = TRUE;
  106. dwResult = ActivateMHeartbeat(picb);
  107. if(dwResult isnot NO_ERROR)
  108. {
  109. Trace2(ERR,
  110. "SetMHeartbeatInfo: Error %d activating hbeat for %S",
  111. GetLastError(),
  112. picb->pwszName);
  113. ZeroMemory(pHbeatCb,
  114. sizeof(MCAST_HBEAT_CB));
  115. }
  116. }
  117. TraceLeave("SetMHeartbeatInfo");
  118. return dwResult;
  119. }
  120. DWORD
  121. GetMHeartbeatInfo(
  122. PICB picb,
  123. PRTR_TOC_ENTRY pToc,
  124. PBYTE pbDataPtr,
  125. PRTR_INFO_BLOCK_HEADER pInfoHdr,
  126. PDWORD pdwSize
  127. )
  128. /*++
  129. Routine Description
  130. Gets the multicast hearbeat info related to the interface
  131. Locks
  132. Called with ICB_LIST lock held as READER
  133. Arguments
  134. picb The ICB of the interface whose multicast heartbeat information
  135. is being retrieved
  136. pToc Pointer to TOC for router discovery info
  137. pbDataPtr Pointer to start of data buffer
  138. pInfoHdr Pointer to the header of the whole info
  139. pdwSize [IN] Size of data buffer
  140. [OUT] Size of buffer consumed
  141. Return Value
  142. --*/
  143. {
  144. PMCAST_HBEAT_INFO pInfo;
  145. PMCAST_HBEAT_CB pHbeatCb;
  146. TraceEnter("GetMHeartbeatInfo");
  147. if(*pdwSize < sizeof(MCAST_HBEAT_INFO))
  148. {
  149. *pdwSize = sizeof(MCAST_HBEAT_INFO);
  150. TraceLeave("GetMHeartbeatInfo");
  151. return ERROR_INSUFFICIENT_BUFFER;
  152. }
  153. *pdwSize = pToc->InfoSize = sizeof(MCAST_HBEAT_INFO);
  154. //pToc->InfoVersion IP_MCAST_HEARBEAT_INFO;
  155. pToc->InfoType = IP_MCAST_HEARBEAT_INFO;
  156. pToc->Count = 1;
  157. pToc->Offset = (ULONG)(pbDataPtr - (PBYTE) pInfoHdr);
  158. pInfo = (PMCAST_HBEAT_INFO)pbDataPtr;
  159. pHbeatCb = &picb->mhcHeartbeatInfo;
  160. wcsncpy(pHbeatCb->pwszGroup,
  161. pInfo->pwszGroup,
  162. MAX_GROUP_LEN);
  163. pHbeatCb->pwszGroup[MAX_GROUP_LEN - 1] = UNICODE_NULL;
  164. pInfo->bActive = pHbeatCb->bActive;
  165. pInfo->byProtocol = pHbeatCb->byProtocol;
  166. pInfo->wPort = pHbeatCb->wPort;
  167. pInfo->ulDeadInterval =
  168. (ULONG)(pHbeatCb->ullDeadInterval/(60 * SYS_UNITS_IN_1_SEC));
  169. TraceLeave("GetMHeartbeatInfo");
  170. return NO_ERROR;
  171. }
  172. DWORD
  173. ActivateMHeartbeat(
  174. PICB picb
  175. )
  176. /*++
  177. Routine Description
  178. Function to activate heartbeat detection. If there is no info or the
  179. detection is configured to be inactive, we quit. We try to get the
  180. group address. If a name is given we queue a worker to resolve the
  181. group name, otherwise we start detection
  182. Locks
  183. ICB_LIST lock held as WRITER
  184. Arguments
  185. picb ICB of the interface to activate
  186. Return Value
  187. --*/
  188. {
  189. PMCAST_HBEAT_CB pHbeatCb;
  190. CHAR pszGroup[MAX_GROUP_LEN];
  191. PHEARTBEAT_CONTEXT pContext;
  192. DWORD dwResult;
  193. TraceEnter("ActivateMHeartbeat");
  194. pHbeatCb = &picb->mhcHeartbeatInfo;
  195. if((pHbeatCb->bActive is FALSE) or
  196. (pHbeatCb->bResolutionInProgress is TRUE))
  197. {
  198. return NO_ERROR;
  199. }
  200. //
  201. // Convert to ansi
  202. //
  203. WideCharToMultiByte(CP_ACP,
  204. 0,
  205. pHbeatCb->pwszGroup,
  206. -1,
  207. pszGroup,
  208. MAX_GROUP_LEN,
  209. NULL,
  210. NULL);
  211. pHbeatCb->dwGroup = inet_addr((CONST CHAR *)pszGroup);
  212. if(pHbeatCb->dwGroup is INADDR_NONE)
  213. {
  214. //
  215. // we need to resolve the name. This will be done in a
  216. // worker function. Create a context for the function and
  217. // queue it
  218. //
  219. pContext = HeapAlloc(IPRouterHeap,
  220. 0,
  221. sizeof(HEARTBEAT_CONTEXT));
  222. if(pContext is NULL)
  223. {
  224. Trace2(ERR,
  225. "SetMHeartbeatInfo: Error %d allocating context for %S",
  226. GetLastError(),
  227. picb->pwszName);
  228. return ERROR_NOT_ENOUGH_MEMORY;
  229. }
  230. pContext->dwIfIndex = picb->dwIfIndex;
  231. pContext->picb = picb;
  232. CopyMemory(&pContext->pwszGroup,
  233. pHbeatCb->pwszGroup,
  234. sizeof(MCAST_HBEAT_INFO));
  235. dwResult = QueueAsyncFunction(ResolveHbeatName,
  236. pContext,
  237. FALSE);
  238. if(dwResult isnot NO_ERROR)
  239. {
  240. HeapFree(IPRouterHeap,
  241. 0,
  242. pContext);
  243. Trace2(ERR,
  244. "SetMHeartbeatInfo: Error %d queuing worker for %S",
  245. GetLastError(),
  246. picb->pwszName);
  247. return dwResult;
  248. }
  249. pHbeatCb->bResolutionInProgress = TRUE;
  250. return NO_ERROR;
  251. }
  252. //
  253. // No need to do name resultion. Just start
  254. //
  255. dwResult = StartMHeartbeat(picb);
  256. if(dwResult isnot NO_ERROR)
  257. {
  258. Trace2(ERR,
  259. "SetMHeartbeatInfo: Error %d starting hbeat for %S",
  260. dwResult,
  261. picb->pwszName);
  262. }
  263. return dwResult;
  264. }
  265. DWORD
  266. StartMHeartbeat(
  267. IN PICB picb
  268. )
  269. /*++
  270. Routine Description
  271. Activates router discovery messages on an interface. The interface must
  272. already be bound.
  273. Locks
  274. Called with the ICB_LIST lock held as WRITER
  275. Arguments
  276. picb The ICB of the interface to activate
  277. Return Value
  278. NO_ERROR or some error code
  279. --*/
  280. {
  281. PMCAST_HBEAT_CB pHbeatCb;
  282. DWORD dwResult;
  283. TraceEnter("ActivateMHeartbeat");
  284. if((picb->dwAdminState isnot IF_ADMIN_STATUS_UP) or
  285. (picb->dwOperationalState < IF_OPER_STATUS_CONNECTING))
  286. {
  287. TraceLeave("ActivateMHeartbeat");
  288. return NO_ERROR;
  289. }
  290. pHbeatCb = &picb->mhcHeartbeatInfo;
  291. dwResult = CreateHbeatSocket(picb);
  292. if(dwResult isnot NO_ERROR)
  293. {
  294. Trace2(ERR,
  295. "ActivateMHeartbeat: Couldnt create socket for %S. Error %d",
  296. picb->pwszName,
  297. dwResult);
  298. TraceLeave("ActivateMHeartbeat");
  299. return dwResult;
  300. }
  301. //
  302. // Yes we are active
  303. //
  304. pHbeatCb->bActive = TRUE;
  305. TraceLeave("ActivateMHeartbeat");
  306. return NO_ERROR;
  307. }
  308. DWORD
  309. CreateHbeatSocket(
  310. IN PICB picb
  311. )
  312. /*++
  313. Routine Description
  314. Creates a socket to listen to multicast hearbeat messages
  315. Locks
  316. ICB_LIST lock must be held as WRITER
  317. Arguments
  318. picb The ICB of the interface for which the socket has to be created
  319. Return Value
  320. NO_ERROR or some error code
  321. --*/
  322. {
  323. PMCAST_HBEAT_CB pHbeatCb;
  324. DWORD i, dwResult, dwBytesReturned;
  325. struct linger lingerOption;
  326. BOOL bOption, bLoopback;
  327. SOCKADDR_IN sinSockAddr;
  328. struct ip_mreq imOption;
  329. TraceEnter("CreateHbeatSocket");
  330. if(picb->bBound)
  331. {
  332. Trace1(ERR,
  333. "CreateHbeatSocket: Can not activate heartbeat on %S as it is not bound",
  334. picb->pwszName);
  335. TraceLeave("CreateHbeatSocket");
  336. return ERROR_CAN_NOT_COMPLETE;
  337. }
  338. //
  339. // Create the sockets for the interface
  340. //
  341. pHbeatCb = &(picb->mhcHeartbeatInfo);
  342. pHbeatCb->sHbeatSocket = INVALID_SOCKET;
  343. if(pHbeatCb->byProtocol is IPPROTO_RAW)
  344. {
  345. //
  346. // If we are raw proto, then the port number contains protocol
  347. //
  348. pHbeatCb->sHbeatSocket = WSASocket(AF_INET,
  349. SOCK_RAW,
  350. LOBYTE(pHbeatCb->wPort),
  351. NULL,
  352. 0,
  353. MHBEAT_SOCKET_FLAGS);
  354. }
  355. else
  356. {
  357. IpRtAssert(pHbeatCb->byProtocol is IPPROTO_UDP);
  358. pHbeatCb->sHbeatSocket = WSASocket(AF_INET,
  359. SOCK_DGRAM,
  360. IPPROTO_UDP,
  361. NULL,
  362. 0,
  363. MHBEAT_SOCKET_FLAGS);
  364. }
  365. if(pHbeatCb->sHbeatSocket is INVALID_SOCKET)
  366. {
  367. dwResult = WSAGetLastError();
  368. Trace2(ERR,
  369. "CreateHbeatSocket: Couldnt create socket on %S. Error %d",
  370. picb->pwszName,
  371. dwResult);
  372. TraceLeave("CreateHbeatSocket");
  373. return dwResult;
  374. }
  375. #if 0
  376. //
  377. // Set to SO_DONTLINGER
  378. //
  379. bOption = TRUE;
  380. if(setsockopt(pHbeatCb->sHbeatSocket,
  381. SOL_SOCKET,
  382. SO_DONTLINGER,
  383. (const char FAR*)&bOption,
  384. sizeof(BOOL)) is SOCKET_ERROR)
  385. {
  386. Trace1(ERR,
  387. "CreateHbeatSocket: Couldnt set linger option - continuing. Error %d",
  388. WSAGetLastError());
  389. }
  390. #endif
  391. //
  392. // Set to SO_REUSEADDR
  393. //
  394. bOption = TRUE;
  395. if(setsockopt(pHbeatCb->sHbeatSocket,
  396. SOL_SOCKET,
  397. SO_REUSEADDR,
  398. (const char FAR*)&bOption,
  399. sizeof(BOOL)) is SOCKET_ERROR)
  400. {
  401. Trace1(ERR,
  402. "CreateHbeatSocket: Couldnt set reuse option - continuing. Error %d",
  403. WSAGetLastError());
  404. }
  405. //
  406. // we are interested in READ events only and want the event to be set
  407. // for those
  408. //
  409. if(WSAEventSelect(pHbeatCb->sHbeatSocket,
  410. g_hMHbeatSocketEvent,
  411. FD_READ) is SOCKET_ERROR)
  412. {
  413. dwResult = WSAGetLastError();
  414. Trace2(ERR,
  415. "CreateHbeatSocket: WSAEventSelect() failed for socket on %S.Error %d",
  416. picb->pwszName,
  417. dwResult);
  418. closesocket(pHbeatCb->sHbeatSocket);
  419. pHbeatCb->sHbeatSocket = INVALID_SOCKET;
  420. return dwResult;
  421. }
  422. //
  423. // Bind to one of the addresses on the interface. We just bind to the
  424. // first address (and the port if specified)
  425. //
  426. sinSockAddr.sin_family = AF_INET;
  427. sinSockAddr.sin_addr.s_addr = picb->pibBindings[0].dwAddress;
  428. if(pHbeatCb->byProtocol is IPPROTO_UDP)
  429. {
  430. sinSockAddr.sin_port = pHbeatCb->wPort;
  431. }
  432. else
  433. {
  434. sinSockAddr.sin_port = 0;
  435. }
  436. if(bind(pHbeatCb->sHbeatSocket,
  437. (const struct sockaddr FAR*)&sinSockAddr,
  438. sizeof(SOCKADDR_IN)) is SOCKET_ERROR)
  439. {
  440. dwResult = WSAGetLastError();
  441. Trace3(ERR,
  442. "CreateHbeatSocket: Couldnt bind to %s on interface %S. Error %d",
  443. inet_ntoa(*(PIN_ADDR)&(picb->pibBindings[0].dwAddress)),
  444. picb->pwszName,
  445. dwResult);
  446. closesocket(pHbeatCb->sHbeatSocket);
  447. pHbeatCb->sHbeatSocket = INVALID_SOCKET;
  448. return dwResult;
  449. }
  450. #if 0
  451. //
  452. // Join the multicast session
  453. //
  454. sinSockAddr.sin_family = AF_INET;
  455. sinSockAddr.sin_addr.s_addr = pHbeatCb->dwGroup;
  456. sinSockAddr.sin_port = 0;
  457. if(WSAJoinLeaf(pHbeatCb->sHbeatSocket,
  458. (const struct sockaddr FAR*)&sinSockAddr,
  459. sizeof(SOCKADDR_IN),
  460. NULL,
  461. NULL,
  462. NULL,
  463. NULL,
  464. JL_BOTH) is INVALID_SOCKET)
  465. {
  466. dwResult = WSAGetLastError();
  467. Trace2(ERR,
  468. "CreateHbeatSocket: Couldnt join multicast group over %s on %S",
  469. inet_ntoa(*(PIN_ADDR)&(picb->pibBindings[i].dwAddress)),
  470. picb->pwszName);
  471. closesocket(pHbeatCb->sHbeatSocket);
  472. pHbeatCb->sHbeatSocket = INVALID_SOCKET;
  473. return dwResult;
  474. }
  475. #else
  476. sinSockAddr.sin_addr.s_addr = picb->pibBindings[0].dwAddress;
  477. if(setsockopt(pHbeatCb->sHbeatSocket,
  478. IPPROTO_IP,
  479. IP_MULTICAST_IF,
  480. (PBYTE)&sinSockAddr.sin_addr,
  481. sizeof(IN_ADDR)) is SOCKET_ERROR)
  482. {
  483. dwResult = WSAGetLastError();
  484. Trace2(ERR,
  485. "CreateHbeatSocket: Couldnt enable mcast over %s on %S",
  486. inet_ntoa(*(PIN_ADDR)&(picb->pibBindings[0].dwAddress)),
  487. picb->pwszName);
  488. closesocket(pHbeatCb->sHbeatSocket);
  489. pHbeatCb->sHbeatSocket = INVALID_SOCKET;
  490. return dwResult;
  491. }
  492. imOption.imr_multiaddr.s_addr = pHbeatCb->dwGroup;
  493. imOption.imr_interface.s_addr = picb->pibBindings[0].dwAddress;
  494. if(setsockopt(pHbeatCb->sHbeatSocket,
  495. IPPROTO_IP,
  496. IP_ADD_MEMBERSHIP,
  497. (PBYTE)&imOption,
  498. sizeof(imOption)) is SOCKET_ERROR)
  499. {
  500. dwResult = WSAGetLastError();
  501. Trace3(ERR,
  502. "CreateHbeatSocket: Couldnt join %d.%d.%d.%d on socket over %s on %S",
  503. PRINT_IPADDR(pHbeatCb->dwGroup),
  504. inet_ntoa(*(PIN_ADDR)&(picb->pibBindings[0].dwAddress)),
  505. picb->pwszName);
  506. closesocket(pHbeatCb->sHbeatSocket);
  507. pHbeatCb->sHbeatSocket = INVALID_SOCKET;
  508. return dwResult;
  509. }
  510. #endif
  511. TraceLeave("CreateHbeatSocket");
  512. return NO_ERROR;
  513. }
  514. VOID
  515. DeleteHbeatSocket(
  516. IN PICB picb
  517. )
  518. /*++
  519. Routine Description
  520. Deletes the sockets (if any) created for running Router Discovery
  521. Locks
  522. Arguments
  523. picb The interface whose sockets need to be deleted
  524. Return Value
  525. --*/
  526. {
  527. PMCAST_HBEAT_CB pHbeatCb;
  528. DWORD i;
  529. pHbeatCb = &(picb->mhcHeartbeatInfo);
  530. if(pHbeatCb->sHbeatSocket isnot INVALID_SOCKET)
  531. {
  532. closesocket(pHbeatCb->sHbeatSocket);
  533. }
  534. pHbeatCb->sHbeatSocket = INVALID_SOCKET;
  535. }
  536. DWORD
  537. DeActivateMHeartbeat(
  538. IN PICB picb
  539. )
  540. {
  541. PMCAST_HBEAT_CB pHbeatCb;
  542. TraceEnter("DeActivateMHeartbeat");
  543. pHbeatCb = &(picb->mhcHeartbeatInfo);
  544. if(!pHbeatCb->bActive)
  545. {
  546. return NO_ERROR;
  547. }
  548. DeleteHbeatSocket(picb);
  549. pHbeatCb->bActive = FALSE;
  550. TraceLeave("DeActivateMHeartbeat");
  551. return NO_ERROR;
  552. }
  553. VOID
  554. HandleMHeartbeatMessages(
  555. VOID
  556. )
  557. /*++
  558. Routine Description
  559. Locks
  560. Arguments
  561. Return Value
  562. --*/
  563. {
  564. PLIST_ENTRY pleNode;
  565. PICB picb;
  566. DWORD i, dwResult, dwRcvAddrLen, dwSizeOfHeader;
  567. DWORD dwBytesRead, dwFlags;
  568. WSANETWORKEVENTS wsaNetworkEvents;
  569. SOCKADDR_IN sinFrom;
  570. WSABUF wsaRcvBuf;
  571. SYSTEMTIME stSysTime;
  572. ULARGE_INTEGER uliTime;
  573. wsaRcvBuf.len = 0;
  574. wsaRcvBuf.buf = NULL;
  575. GetSystemTime(&stSysTime);
  576. SystemTimeToFileTime(&stSysTime,
  577. (PFILETIME)&uliTime);
  578. TraceEnter("HandleMHeartbeatMessages");
  579. for(pleNode = ICBList.Flink;
  580. pleNode isnot &ICBList;
  581. pleNode = pleNode->Flink)
  582. {
  583. picb = CONTAINING_RECORD(pleNode, ICB, leIfLink);
  584. //
  585. // If the interface has no bindings, or isnot involved in
  586. // multicast heartbeat detection, we wouldnt have
  587. // opened a socket on it so the FD_READ notification cant be for it
  588. //
  589. if((picb->bBound is FALSE) or
  590. (picb->mhcHeartbeatInfo.bActive is FALSE))
  591. {
  592. continue;
  593. }
  594. if(picb->mhcHeartbeatInfo.sHbeatSocket is INVALID_SOCKET)
  595. {
  596. continue;
  597. }
  598. if(WSAEnumNetworkEvents(picb->mhcHeartbeatInfo.sHbeatSocket,
  599. NULL,
  600. &wsaNetworkEvents) is SOCKET_ERROR)
  601. {
  602. dwResult = GetLastError();
  603. Trace1(ERR,
  604. "HandleMHeartbeatMessages: WSAEnumNetworkEvents() returned %d",
  605. dwResult);
  606. continue;
  607. }
  608. if(!(wsaNetworkEvents.lNetworkEvents & FD_READ))
  609. {
  610. //
  611. // Read bit isnot set and we arent interested in anything else
  612. //
  613. continue;
  614. }
  615. if(wsaNetworkEvents.iErrorCode[FD_READ_BIT] isnot NO_ERROR)
  616. {
  617. Trace2(ERR,
  618. "HandleMHeartbeatMessages: Error %d associated with socket on %S for FD_READ",
  619. wsaNetworkEvents.iErrorCode[FD_READ_BIT],
  620. picb->pwszName);
  621. continue;
  622. }
  623. dwRcvAddrLen = sizeof(SOCKADDR_IN);
  624. dwFlags = 0;
  625. //
  626. // We dont want the data, we just want to clear out the read
  627. // notification
  628. //
  629. dwResult = WSARecvFrom(picb->mhcHeartbeatInfo.sHbeatSocket,
  630. &wsaRcvBuf,
  631. 1,
  632. &dwBytesRead,
  633. &dwFlags,
  634. (struct sockaddr FAR*)&sinFrom,
  635. &dwRcvAddrLen,
  636. NULL,
  637. NULL);
  638. if(dwResult is SOCKET_ERROR)
  639. {
  640. dwResult = WSAGetLastError();
  641. if(dwResult isnot WSAEMSGSIZE)
  642. {
  643. Trace3(ERR,
  644. "HandleMHeartbeatMessages: Error %d in WSARecvFrom on %S. Bytes read %d",
  645. dwResult,
  646. picb->pwszName,
  647. dwBytesRead);
  648. continue;
  649. }
  650. }
  651. //
  652. // If the message is on the group we need to hear from
  653. // then update the last heard time
  654. //
  655. picb->mhcHeartbeatInfo.ullLastHeard = uliTime.QuadPart;
  656. }
  657. TraceLeave("HandleMHeartbeatMessages");
  658. }