//-------------------------------------------------------------------- // 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 #include #include #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(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(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(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(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)); }