windows-nt/Source/XPSP1/NT/ds/security/services/w32time/lib/pinglib.cpp
2020-09-26 16:20:57 +08:00

480 lines
16 KiB
C++

//--------------------------------------------------------------------
// PingLib - implementation
// Copyright (C) Microsoft Corporation, 1999
//
// Created by: Louis Thomas (louisth), 10-8-99
//
// Various ways of pinging a server
//
#include "pch.h" // precompiled headers
#include <ipexport.h>
#include <icmpapi.h>
#include <DcInfo.h>
#include "NtpBase.h"
#include "EndianSwap.inl"
//####################################################################
// OLD CODE
#if 0
//--------------------------------------------------------------------
MODULEPRIVATE HRESULT LookupServer(IN WCHAR * wszServerName, OUT sockaddr * psaOut, IN int nAddrSize) {
HRESULT hr;
DWORD dwDataLen;
SOCKET_ADDRESS * psaFound;
// pointers that must be cleaned up
HANDLE hSearch=INVALID_HANDLE_VALUE;
WSAQUERYSETW * pqsResult=NULL;
DebugWPrintf1(L"Looking up server \"%s\":\n", wszServerName);
// initialize the search
// const static GUID guidHostAddressByName = SVCID_INET_HOSTADDRBYNAME;
AFPROTOCOLS apInetUdp={AF_INET, IPPROTO_UDP};
GUID guidNtp=SVCID_NTP_UDP;
WSAQUERYSETW qsSearch;
ZeroMemory(&qsSearch, sizeof(qsSearch));
qsSearch.dwSize=sizeof(qsSearch);
qsSearch.lpszServiceInstanceName=wszServerName;
qsSearch.lpServiceClassId=&guidNtp;
qsSearch.dwNameSpace=NS_ALL;
qsSearch.dwNumberOfProtocols=1;
qsSearch.lpafpProtocols=&apInetUdp;
if (SOCKET_ERROR==WSALookupServiceBegin(&qsSearch, LUP_RETURN_ADDR/*flags*/, &hSearch)) {
_JumpLastError(hr, error, "WSALookupServiceBegin");
}
// get the buffer size for the first value
dwDataLen=1;
_Verify(SOCKET_ERROR==WSALookupServiceNext(hSearch, LUP_RETURN_ADDR/*flags*/, &dwDataLen, &qsSearch), hr, error);
if (WSAEFAULT!=GetLastError()) {
_JumpLastError(hr, error, "WSALookupServiceNext");
}
// allocate the buffer
pqsResult=reinterpret_cast<WSAQUERYSETW *>(LocalAlloc(LMEM_FIXED, dwDataLen));
_JumpIfOutOfMemory(hr, error, pqsResult);
// retrieve the first value
if (SOCKET_ERROR==WSALookupServiceNext(hSearch, LUP_RETURN_ADDR/*flags*/, &dwDataLen, pqsResult)) {
_JumpLastError(hr, error, "WSALookupServiceNext");
}
_Verify(pqsResult->dwNumberOfCsAddrs>0, hr, error);
if (pqsResult->dwNumberOfCsAddrs>1) {
DebugWPrintf1(L"WSALookupServiceNextW returned %d addresses. Using first one.\n", pqsResult->dwNumberOfCsAddrs);
}
psaFound=&(pqsResult->lpcsaBuffer[0].RemoteAddr);
_Verify(nAddrSize==psaFound->iSockaddrLength, hr, error);
*psaOut=*(psaFound->lpSockaddr);
DumpSockaddr(psaOut, nAddrSize);
hr=S_OK;
error:
if (NULL!=pqsResult) {
LocalFree(pqsResult);
}
if (INVALID_HANDLE_VALUE!=hSearch) {
if (SOCKET_ERROR==WSALookupServiceEnd(hSearch)) {
_IgnoreLastError("WSALookupServiceEnd");
}
}
return hr;
}
//--------------------------------------------------------------------
MODULEPRIVATE HRESULT GetSample(WCHAR * wszServerName, TpcGetSamplesArgs * ptgsa) {
HRESULT hr;
NtpPacket npPacket;
NtTimeEpoch teDestinationTimestamp;
unsigned int nIpAddrs;
// must be cleaned up
in_addr * rgiaLocalIpAddrs=NULL;
in_addr * rgiaRemoteIpAddrs=NULL;
hr=MyGetIpAddrs(wszServerName, &rgiaLocalIpAddrs, &rgiaRemoteIpAddrs, &nIpAddrs, NULL);
_JumpIfError(hr, error, "MyGetIpAddrs");
_Verify(0!=nIpAddrs, hr, error);
hr=MyNtpPing(&(rgiaRemoteIpAddrs[0]), 500, &npPacket, &teDestinationTimestamp);
_JumpIfError(hr, error, "MyNtpPing");
{
NtTimeEpoch teOriginateTimestamp=NtTimeEpochFromNtpTimeEpoch(npPacket.teOriginateTimestamp);
NtTimeEpoch teReceiveTimestamp=NtTimeEpochFromNtpTimeEpoch(npPacket.teReceiveTimestamp);
NtTimeEpoch teTransmitTimestamp=NtTimeEpochFromNtpTimeEpoch(npPacket.teTransmitTimestamp);
NtTimeOffset toRoundtripDelay=
(teDestinationTimestamp-teOriginateTimestamp)
- (teTransmitTimestamp-teReceiveTimestamp);
NtTimeOffset toLocalClockOffset=
(teReceiveTimestamp-teOriginateTimestamp)
+ (teTransmitTimestamp-teDestinationTimestamp);
toLocalClockOffset/=2;
NtTimePeriod tpClockTickSize;
g_npstate.tpsc.pfnGetTimeSysInfo(TSI_ClockTickSize, &tpClockTickSize.qw);
TimeSample * pts=(TimeSample *)ptgsa->pbSampleBuf;
pts->dwSize=sizeof(TimeSample);
pts->dwRefid=npPacket.refid.value;
pts->toOffset=toLocalClockOffset.qw;
pts->toDelay=(toRoundtripDelay
+NtTimeOffsetFromNtpTimeOffset(npPacket.toRootDelay)
).qw;
pts->tpDispersion=(tpClockTickSize
+NtpConst::timesMaxSkewRate(abs(teDestinationTimestamp-teOriginateTimestamp))
+NtTimePeriodFromNtpTimePeriod(npPacket.tpRootDispersion)
).qw;
g_npstate.tpsc.pfnGetTimeSysInfo(TSI_TickCount, &(pts->nSysTickCount));
g_npstate.tpsc.pfnGetTimeSysInfo(TSI_PhaseOffset, &(pts->nSysPhaseOffset));
pts->nStratum=npPacket.nStratum;
pts->nLeapFlags=npPacket.nLeapIndicator;
ptgsa->dwSamplesAvailable=1;
ptgsa->dwSamplesReturned=1;
}
hr=S_OK;
error:
if (NULL!=rgiaLocalIpAddrs) {
LocalFree(rgiaLocalIpAddrs);
}
if (NULL!=rgiaRemoteIpAddrs) {
LocalFree(rgiaRemoteIpAddrs);
}
return hr;
}
#endif
//####################################################################
// module public
//--------------------------------------------------------------------
HRESULT MyIcmpPing(in_addr * piaTarget, DWORD dwTimeout, DWORD * pdwResponseTime) {
HRESULT hr;
IPAddr ipaddrDest=piaTarget->S_un.S_addr;
BYTE rgbData[8]={'a','b','c','d','e','f','g','h'};
BYTE rgbResponse[1024];
DWORD dwDataSize;
// must be cleaned up
HANDLE hIcmp=NULL;
// open a handle for icmp access
hIcmp=IcmpCreateFile();
if (NULL==hIcmp) {
_JumpLastError(hr, error, "IcmpCreateFile");
}
// ping
ZeroMemory(rgbResponse, sizeof(rgbResponse));
dwDataSize=IcmpSendEcho(hIcmp, ipaddrDest, rgbData, 8, NULL, rgbResponse, sizeof(rgbResponse), dwTimeout);
if (0==dwDataSize) {
_JumpLastError(hr, error, "IcmpSendEcho");
}
*pdwResponseTime=((icmp_echo_reply *)rgbResponse)->RoundTripTime;
hr=S_OK;
error:
if (NULL!=hIcmp) {
IcmpCloseHandle(hIcmp);
}
return hr;
}
//--------------------------------------------------------------------
HRESULT MyNtpPing(in_addr * piaTarget, DWORD dwTimeout, NtpPacket * pnpPacket, NtTimeEpoch * pteDestinationTimestamp) {
HRESULT hr;
sockaddr saServer;
int nBytesRecvd;
DWORD dwWaitResult;
// must be cleaned up
SOCKET sTest=INVALID_SOCKET;
HANDLE hDataAvailEvent=NULL;
// create a socket
sTest=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (INVALID_SOCKET==sTest) {
_JumpLastError(hr, error, "socket");
}
// fix the destination address
{
sockaddr_in & saiServer=*(sockaddr_in *)(&saServer);
saiServer.sin_port=EndianSwap((unsigned __int16)NtpConst::nPort);
saiServer.sin_family=AF_INET;
saiServer.sin_addr.S_un.S_addr=piaTarget->S_un.S_addr;
}
// connect the socket to the peer
if (SOCKET_ERROR==connect(sTest, &saServer, sizeof(saServer))) {
_JumpLastError(hr, error, "connect");
}
// send an NTP packet
//DebugWPrintf1(L"Sending %d byte SNTP packet.\n", sizeof(NtpPacket));
ZeroMemory(pnpPacket, sizeof(NtpPacket));
pnpPacket->nMode=e_Client;
pnpPacket->nVersionNumber=1;
pnpPacket->teTransmitTimestamp=NtpTimeEpochFromNtTimeEpoch(GetCurrentSystemNtTimeEpoch());
if (SOCKET_ERROR==send(sTest, reinterpret_cast<char *>(pnpPacket), sizeof(NtpPacket), 0/*flags*/)) {
_JumpLastError(hr, error, "send");
}
// create the data available event
hDataAvailEvent=CreateEvent(NULL /*security*/, FALSE /*auto-reset*/, FALSE /*nonsignaled*/, NULL /*name*/);
if (NULL==hDataAvailEvent) {
_JumpLastError(hr, error, "CreateEvent");
}
// bind the event to this socket
if (SOCKET_ERROR==WSAEventSelect(sTest, hDataAvailEvent, FD_READ)) {
_JumpLastError(hr, error, "WSAEventSelect");
}
// listen on the socket
//DebugWPrintf1(L"Waiting for response for %ums...\n", dwTimeout);
dwWaitResult=WaitForSingleObject(hDataAvailEvent, dwTimeout);
if (WAIT_FAILED==dwWaitResult) {
_JumpLastError(hr, error, "WaitForSingleObject");
} else if (WAIT_TIMEOUT==dwWaitResult) {
//DebugWPrintf0(L"No response.\n");
hr=HRESULT_FROM_WIN32(ERROR_TIMEOUT);
_JumpError(hr, error, "WaitForSingleObject");
} else {
// retrieve the data
nBytesRecvd=recv(sTest, reinterpret_cast<char *>(pnpPacket), sizeof(NtpPacket), 0/*flags*/);
*pteDestinationTimestamp=GetCurrentSystemNtTimeEpoch();
if (SOCKET_ERROR==nBytesRecvd) {
_JumpLastError(hr, error, "recv");
}
//DebugWPrintf2(L"Recvd %d of %d bytes.\n", nBytesRecvd, sizeof(NtpPacket));
//DumpNtpPacket(&npPacket,teDestinationTimestamp);
}
// done
hr=S_OK;
error:
if (INVALID_SOCKET!=sTest) {
if (SOCKET_ERROR==closesocket(sTest)) {
_IgnoreLastError("closesocket");
}
}
if (NULL!=hDataAvailEvent) {
CloseHandle(hDataAvailEvent);
}
return hr;
}
//--------------------------------------------------------------------
HRESULT MyGetIpAddrs(const WCHAR * wszDnsName, in_addr ** prgiaLocalIpAddrs, in_addr ** prgiaRemoteIpAddrs, unsigned int *pnIpAddrs, bool * pbRetry) {
AFPROTOCOLS apInetUdp = { AF_INET, IPPROTO_UDP };
bool bRetry = FALSE;
DWORD dwDataLen;
GUID guidNtp = SVCID_NTP_UDP;
HRESULT hr;
HANDLE hSearch = INVALID_HANDLE_VALUE;
in_addr *rgiaLocalIpAddrs = NULL;
in_addr *rgiaRemoteIpAddrs = NULL;
WSAQUERYSETW qsSearch;
WSAQUERYSETW *pqsResult = NULL;
ZeroMemory(&qsSearch, sizeof(qsSearch));
// initialize the search
qsSearch.dwSize = sizeof(qsSearch);
qsSearch.lpszServiceInstanceName = const_cast<WCHAR *>(wszDnsName);
qsSearch.lpServiceClassId = &guidNtp;
qsSearch.dwNameSpace = NS_ALL;
qsSearch.dwNumberOfProtocols = 1;
qsSearch.lpafpProtocols = &apInetUdp;
// begin the search
if (SOCKET_ERROR == WSALookupServiceBegin(&qsSearch, LUP_RETURN_ADDR/*flags*/, &hSearch)) {
hr = HRESULT_FROM_WIN32(WSAGetLastError());
_JumpError(hr, error, "WSALookupServiceBegin");
}
// retrieve the result set
dwDataLen = 5*1024;
pqsResult = (WSAQUERYSETW *)LocalAlloc(LPTR, dwDataLen);
_JumpIfOutOfMemory(hr, error, pqsResult);
if (SOCKET_ERROR == WSALookupServiceNext(hSearch, LUP_RETURN_ADDR/*flags*/, &dwDataLen, pqsResult)) {
hr = HRESULT_FROM_WIN32(WSAGetLastError());
_JumpError(hr, error, "WSALookupServiceNext");
}
_Verify(0 != pqsResult->dwNumberOfCsAddrs, hr, error);
// allocate room for the IP addresses
rgiaLocalIpAddrs = (in_addr *)LocalAlloc(LPTR, sizeof(in_addr) * pqsResult->dwNumberOfCsAddrs);
_JumpIfOutOfMemory(hr, error, rgiaLocalIpAddrs);
rgiaRemoteIpAddrs = (in_addr *)LocalAlloc(LPTR, sizeof(in_addr) * pqsResult->dwNumberOfCsAddrs);
_JumpIfOutOfMemory(hr, error, rgiaRemoteIpAddrs);
// copy the IP addresses
for (unsigned int nIndex = 0; nIndex < pqsResult->dwNumberOfCsAddrs; nIndex++) {
// copy local
_Verify(sizeof(sockaddr) == pqsResult->lpcsaBuffer[nIndex].LocalAddr.iSockaddrLength, hr, error);
_Verify(AF_INET == pqsResult->lpcsaBuffer[nIndex].LocalAddr.lpSockaddr->sa_family, hr, error);
rgiaLocalIpAddrs[nIndex].S_un.S_addr = ((sockaddr_in *)(pqsResult->lpcsaBuffer[nIndex].LocalAddr.lpSockaddr))->sin_addr.S_un.S_addr;
// copy remote
_Verify(sizeof(sockaddr) == pqsResult->lpcsaBuffer[nIndex].RemoteAddr.iSockaddrLength, hr, error);
_Verify(AF_INET == pqsResult->lpcsaBuffer[nIndex].RemoteAddr.lpSockaddr->sa_family, hr, error);
rgiaRemoteIpAddrs[nIndex].S_un.S_addr = ((sockaddr_in *)(pqsResult->lpcsaBuffer[nIndex].RemoteAddr.lpSockaddr))->sin_addr.S_un.S_addr;
}
// Assign out params:
if (NULL != prgiaLocalIpAddrs) { *prgiaLocalIpAddrs = rgiaLocalIpAddrs; }
if (NULL != prgiaRemoteIpAddrs) { *prgiaRemoteIpAddrs = rgiaRemoteIpAddrs; }
if (NULL != pbRetry) { *pbRetry = bRetry; }
if (NULL != pnIpAddrs) { *pnIpAddrs = pqsResult->dwNumberOfCsAddrs; }
rgiaLocalIpAddrs = NULL;
rgiaRemoteIpAddrs = NULL;
hr = S_OK;
error:
if (NULL != pbRetry) {
// Probably shouldn't be removing manual peers. Always retry.
*pbRetry = true;
}
if (NULL != rgiaLocalIpAddrs) {
LocalFree(rgiaLocalIpAddrs);
}
if (NULL != rgiaRemoteIpAddrs) {
LocalFree(rgiaRemoteIpAddrs);
}
if (NULL != pqsResult) {
LocalFree(pqsResult);
}
if (INVALID_HANDLE_VALUE != hSearch) {
if (SOCKET_ERROR == WSALookupServiceEnd(hSearch)) {
HRESULT hr2 = HRESULT_FROM_WIN32(WSAGetLastError());
_IgnoreError(hr2, "WSALookupServiceEnd");
}
}
return hr;
}
//--------------------------------------------------------------------
// initialize the socket layer
HRESULT OpenSocketLayer(void) {
HRESULT hr;
int nRetVal;
WSADATA wdWinsockInfo;
nRetVal=WSAStartup(0x0002/*version*/, &wdWinsockInfo);
if (0!=nRetVal) {
hr=HRESULT_FROM_WIN32(nRetVal);
_JumpError(hr, error, "WSAStartup");
}
//DebugWPrintf4(L"Socket layer initialized. v:0x%04X hv:0x%04X desc:\"%S\" status:\"%S\"\n",
// wdWinsockInfo.wVersion, wdWinsockInfo.wHighVersion, wdWinsockInfo.szDescription,
// wdWinsockInfo.szSystemStatus);
hr=S_OK;
error:
return hr;
}
//--------------------------------------------------------------------
// close down the socket layer
HRESULT CloseSocketLayer(void) {
HRESULT hr;
int nRetVal;
nRetVal=WSACleanup();
if (SOCKET_ERROR==nRetVal) {
_JumpLastError(hr, error, "WSACleanup");
}
//DebugWPrintf0(L"Socket layer cleanup successful\n");
hr=S_OK;
error:
return hr;
}
//--------------------------------------------------------------------
HRESULT GetSystemErrorString(HRESULT hrIn, WCHAR ** pwszError) {
HRESULT hr=S_OK;
DWORD dwResult;
WCHAR * rgParams[2]={
NULL,
(WCHAR *)(ULONG_PTR)hrIn
};
// must be cleaned up
WCHAR * wszErrorMessage=NULL;
WCHAR * wszFullErrorMessage=NULL;
// initialize input params
*pwszError=NULL;
// get the message from the system
dwResult=FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL/*ignored*/, hrIn, 0/*language*/, (WCHAR *)&wszErrorMessage, 0/*min-size*/, NULL/*valist*/);
if (0==dwResult) {
if (ERROR_MR_MID_NOT_FOUND==GetLastError()) {
rgParams[0]=L"";
} else {
_JumpLastError(hr, error, "FormatMessage");
}
} else {
rgParams[0]=wszErrorMessage;
// trim off \r\n if it exists
if (L'\r'==wszErrorMessage[wcslen(wszErrorMessage)-2]) {
wszErrorMessage[wcslen(wszErrorMessage)-2]=L'\0';
}
}
// add the error number
dwResult=FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
L"%1 (0x%2!08X!)", 0, 0/*language*/, (WCHAR *)&wszFullErrorMessage, 0/*min-size*/, (va_list *)rgParams);
if (0==dwResult) {
_JumpLastError(hr, error, "FormatMessage");
}
// success
*pwszError=wszFullErrorMessage;
wszFullErrorMessage=NULL;
hr=S_OK;
error:
if (NULL!=wszErrorMessage) {
LocalFree(wszErrorMessage);
}
if (NULL!=wszFullErrorMessage) {
LocalFree(wszFullErrorMessage);
}
return hr;
}
//--------------------------------------------------------------------
extern "C" void MIDL_user_free(void * pvValue) {
LocalFree(pvValue);
}
//--------------------------------------------------------------------
extern "C" void * MIDL_user_allocate(size_t n) {
return (LocalAlloc(LPTR, n));
}