📄 ntpsock.cpp
字号:
// NtpSock.cpp: implementation of the CNtpSock class.
//
//////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <string.h>
#include "NtpSock.h"
#ifdef __Win32__
#include <Ws2tcpip.h>
#endif
#ifdef __REDHATLINUX__
#include <sys/types.h>
//#include <cygwin/in.h>
#include <netinet/in.h>
#endif
static unsigned int mInitCount = 0;
static bool InitWS2_32()
{
bool success = true;
#ifdef __Win32__
if(!mInitCount)
{
WSADATA stWSAData;
success = !WSAStartup(0x0101, &stWSAData);
}
mInitCount ++;
#endif
return success;
}
static void ShutdownWS2_32()
{
bool success = true;
#ifdef __Win32__
mInitCount--;
if(!mInitCount)
{
WSACleanup();
}
#endif
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CNtpSocket::CNtpSocket()
{
#ifdef __Win32__
InitWS2_32();
m_hSocket = INVALID_SOCKET; //default to an invalid scoket descriptor
#endif
}
CNtpSocket::~CNtpSocket()
{
#ifdef __Win32__
ShutdownWS2_32();
Close();
#endif
}
Bool8 CNtpSocket::Create(int type)
{
//NTP Uses UDP instead of the usual TCP
m_hSocket = socket(AF_INET,type, 0);
if(m_hSocket == INVALID_SOCKET)
return false;
if(SetSockBlock(0))
return false;
if(ReuseAddr())
return false;
return true;
}
Bool8 CNtpSocket::Connect(char *pszHostAddress, int nPort)
{
//must have been created first
//ASSERT(m_hSocket != INVALID_SOCKET);
//Determine if the address is in dotted notation
struct sockaddr_in sockAddr;
// ZeroMemory(&sockAddr, sizeof(sockAddr));
memset(&sockAddr,0,sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons((u_short)nPort);
sockAddr.sin_addr.s_addr = inet_addr(pszHostAddress);
//If the address is not dotted notation, then do a DNS
//lookup of it.
if (sockAddr.sin_addr.s_addr == INADDR_NONE)
{
/*
LPHOSTENT lphost;
lphost = gethostbyname(pszHostAddress);
if (lphost != NULL)
sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;
else
*/
return false;
}
//Call the protected version which takes an address
//in the form of a standard C style struct.
return Connect((SOCKADDR*)&sockAddr, sizeof(sockAddr));
}
Bool8 CNtpSocket::Connect(const SOCKADDR* lpSockAddr, int nSockAddrLen)
{
int nConnect = connect(m_hSocket, lpSockAddr, nSockAddrLen);
return (nConnect == 0);
}
int CNtpSocket::Send(char *pszBuf, int nBuf,struct sockaddr_in *toAddr)
{
//must have been created first
//ASSERT(m_hSocket != INVALID_SOCKET);
int len = sizeof(struct sockaddr);
len = sendto(m_hSocket, pszBuf, nBuf, 0,(struct sockaddr *)toAddr,len);
return len;
}
int CNtpSocket::Receive(LPSTR pszBuf, int nBuf, struct sockaddr_in *fromAddr)
{
//must have been created first
//ASSERT(m_hSocket != INVALID_SOCKET);
// struct sockaddr FAR* from,
// int FAR* fromlen
//socklen_t len = sizeof(sockaddr);
//return recvfrom(m_hSocket, pszBuf, nBuf, 0, (struct sockaddr *)fromAddr, &len);
char rcvBuf[200];
int rcvBufLen = 200;
memset(rcvBuf,0,sizeof(rcvBuf));
int minLen = sizeof(NtpBasicInfo);
#ifdef __Win32__
int len = sizeof(sockaddr);
#endif
#ifdef __REDHATLINUX__
socklen_t len = sizeof(sockaddr);
#endif
int retLen = recvfrom(m_hSocket, rcvBuf, rcvBufLen, 0, (struct sockaddr *)fromAddr, &len);
if(retLen >= minLen)
{
memcpy(pszBuf,rcvBuf,nBuf);
return retLen;
}
else
return -1;
}
void CNtpSocket::Close()
{
if (m_hSocket != INVALID_SOCKET)
{
shutdown(m_hSocket,2);
#ifdef __Win32__
closesocket(m_hSocket);
#else
close(m_hSocket);
#endif
}
}
int CNtpSocket::IsReadible(unsigned long dwTimeout)
{
timeval timeout;
timeout.tv_sec = dwTimeout / 1000;
timeout.tv_usec = dwTimeout % 1000;
fd_set fds;
FD_ZERO(&fds);
FD_SET(m_hSocket, &fds);
int nStatus;
#ifdef __Win32__
nStatus = select(0, &fds, NULL, NULL,NULL); // &timeout);
#else
//nStatus = select(1, &fds, NULL, NULL,NULL);
nStatus = select(FD_SETSIZE + 1, &fds, NULL, NULL,NULL);
#endif
return nStatus;
}
int CNtpSocket::Bind(unsigned short port)
{
struct sockaddr_in addr1;
int len = sizeof(addr1);
addr1.sin_family = AF_INET;
addr1.sin_port = htons(port);
addr1.sin_addr.s_addr = INADDR_ANY;
int err = ::bind(m_hSocket, (sockaddr *)&addr1,len);
if (err == INVALID_SOCKET)
{
return err;
}
return err;
}
int CNtpSocket::ReuseAddr()
{
int one = 1;
int err = ::setsockopt(m_hSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(int));
return err;
}
int CNtpSocket::NoDelay()
{
int one = 1;
int err = ::setsockopt(m_hSocket, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(int));
return err;
}
int CNtpSocket::KeepAlive()
{
int one = 1;
int err = ::setsockopt(m_hSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&one, sizeof(int));
return err;
}
int CNtpSocket::SetLoopBack(int lb)
{
const int loopback = lb; //0; //禁止回馈
int ret = setsockopt(m_hSocket,IPPROTO_IP,IP_MULTICAST_LOOP,(char*)&loopback,sizeof(loopback));
return ret;
}
int CNtpSocket::SetSocketSndBufSize(unsigned int inNewSize)
{
int bufSize = inNewSize;
int err = ::setsockopt(m_hSocket, SOL_SOCKET, SO_SNDBUF, (char*)&bufSize, sizeof(int));
return err;
}
int CNtpSocket::SetSocketRcvBufSize(unsigned int inNewSize)
{
int bufSize = inNewSize;
int err = ::setsockopt(m_hSocket, SOL_SOCKET, SO_RCVBUF, (char*)&bufSize, sizeof(int));
return err;
}
int CNtpSocket::SetSockBlock(unsigned long blockingIO)
{
int err;
#ifdef __Win32__
err = ioctlsocket(m_hSocket, FIONBIO, &blockingIO);
#else
err = ioctl(m_hSocket, FIONBIO, &blockingIO);
#endif
return err;
}
int CNtpSocket::SetSockBroadcast(unsigned long broadcast)
{
int err;
#ifdef __Win32__
err = setsockopt(m_hSocket, SOL_SOCKET, SO_BROADCAST, (char*)&broadcast,sizeof(broadcast));
#else
//U32 notblock = broadcast; //nonblockingIO;
err = ioctl(m_hSocket, FIONBIO, &broadcast);
#endif
return err;
}
int CNtpSocket::SetIPLoop()
{
int loop = 1;
int err = setsockopt(m_hSocket, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
return err;
}
int CNtpSocket::SetSockMulticast(char *multicastAddr, bool isTrue)
{
int err = 0;
// #ifdef __Win32__
struct ip_mreq mreq;
memset(&mreq, 0, sizeof(mreq));
mreq.imr_interface.s_addr = INADDR_ANY;
mreq.imr_multiaddr.s_addr = inet_addr(multicastAddr); //MULTICAST_IP);
if(isTrue)
//加入一个多播组
err = setsockopt(m_hSocket,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char*)&mreq,sizeof(mreq));
else
//加入一个多播组
err = setsockopt(m_hSocket,IPPROTO_IP,IP_DROP_MEMBERSHIP,(char*)&mreq,sizeof(mreq));
// #endif
return err;
}
#ifdef __Win32__
DWORD WINAPI _StartDataRecvThread( LPVOID param )
#else
void* _StartDataRecvThread( void * param )
#endif
{
CConnectionPeer *pConn = (CConnectionPeer *) param;
pConn->DataRecvThread();
#ifdef __Win32__
return 0;
#endif
}
#ifdef __Win32__
DWORD WINAPI _StartDataSendThread( LPVOID param )
#else
void* _StartDataSendThread( void * param )
#endif
{
CConnectionPeer *pConn = (CConnectionPeer *) param;
pConn->DataSendThread();
#ifdef __Win32__
return 0;
#endif
}
#ifdef __Win32__
DWORD WINAPI _StartMultiCastSendThread( LPVOID param )
#else
void* _StartMultiCastSendThread( void * param )
#endif
{
CConnectionPeer *pConn = (CConnectionPeer *) param;
pConn->MultiCastSendThread();
#ifdef __Win32__
return 0;
#endif
}
CConnectionPeer::CConnectionPeer(unsigned int castType,Bool8 isServer,char *serverAddr,unsigned short port)
{
mIsServer = isServer;
mCastType = castType;
mUniCastPeriod = 5000;
memset(mServerAddr,0,sizeof(mServerAddr));
if(mIsServer)
{
if(serverAddr != NULL)
strcpy(mServerAddr,serverAddr);
}
mLocalPort = port;
#ifdef __Win32__
mRecvThreadHandle = NULL;
mMultiCastThreadHandle = NULL;
m_hToken = NULL;
#else
mRecvThreadHandle = 0;
mMultiCastThreadHandle = 0;
#endif
mServerPort = port;
pLog = NULL;
mMultiCastPeriod = 1000;
memset(mMultiCastAddr,0,sizeof(mMultiCastAddr));
mIsGetNetDelay = false;
mIsGetServerAddr = false;
mNetDelay = 0;
}
CConnectionPeer::~CConnectionPeer()
{
}
int CConnectionPeer::DealRecvData()
{
return OS_NoError;
}
int CConnectionPeer::SendTimeSynData()
{
if( mServerAddr == NULL)
return OS_HasError;
struct sockaddr_in toAddr;
memset(&toAddr,0,sizeof(toAddr));
if( mIsServer )
toAddr.sin_port = htons(mServerPort);
else
toAddr.sin_port = htons(mLocalPort);
toAddr.sin_family = AF_INET;
toAddr.sin_addr.s_addr = inet_addr(mServerAddr);
NtpBasicInfo nbi;
memset(&nbi,0,sizeof(nbi));
int nSendSize = sizeof(NtpBasicInfo);
// ZeroMemory(&nbi, nSendSize);
memset(&nbi,0,nSendSize);
nbi.m_LiVnMode = 35; //Encoded representation which represents NTP Client Request & NTP version 3.0
// only test
/* CNtpTime testTm1 = CNtpTime::GetCurrentTime();
SYSTEMTIME st = SYSTEMTIME(testTm1);
printf("st 请求消息发送以前时间,%04d-%02d-%02d %02d:%02d:%02d:%03d \n",
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
*/ // test end
nbi.m_TransmitTimestamp = CNtpTime::GetCurrentTime();
//Send off the NtpBasicInfo packet
if (!mPeerSocket.Send((char *)&nbi, nSendSize, &toAddr))
return OS_HasError;
if(pLog)
{
if(mIsServer)
pLog->AddMsgIntoTail("服务器成功发送时间同步请求");
else
pLog->AddMsgIntoTail("客户机成功发送时间同步请求");
}
return OS_NoError;
}
void CConnectionPeer::DataRecvThread()
{
char logBuffer[500];
//char timeBuffer[500];
NtpFullPacket nfp;
NtpServerResponse response;
struct sockaddr_in fromAddr;
while(1)
{
int lRet = mPeerSocket.IsReadible(0);
if( lRet < 0 )
return;
else if( lRet == 0 )
{
#ifdef __Win32__
Sleep(1000);
#endif
#ifdef __REDHATLINUX__
usleep(1000*1000);
#endif
continue;
}
response.m_DestinationTime = CNtpTime::GetCurrentTime();
//read back the response into the NtpFullPacket struct
int nReceiveSize = sizeof(NtpFullPacket);
//ZeroMemory(&nfp, nReceiveSize);
memset(&nfp,0,sizeof(nfp));
memset(&fromAddr,0,sizeof(fromAddr));
lRet = mPeerSocket.Receive((char *) &nfp, nReceiveSize, &fromAddr);
if( lRet < 0)
continue;
response.m_DestinationTime = CNtpTime::GetCurrentTime();
char mode;
mode = nfp.m_Basic.m_LiVnMode & 0x07;
//if( pLog )
//{
memset(logBuffer, 0, sizeof(logBuffer));
if( mode == 4 ) /// 服务器发来的响应消息
sprintf(logBuffer, "收到服务器的响应消息,地址%s 端口 %d",
inet_ntoa(fromAddr.sin_addr),ntohs(fromAddr.sin_port));
else if( mode == 3) /// 客户端发来的请求消息
sprintf(logBuffer, "收到客户端发来的请求消息,地址%s 端口 %d",
inet_ntoa(fromAddr.sin_addr),ntohs(fromAddr.sin_port));
else if( mode == 5) /// 服务器多播消息
sprintf(logBuffer, "收到服务器多播消息,地址%s 端口 %d",
inet_ntoa(fromAddr.sin_addr),ntohs(fromAddr.sin_port));
if(pLog)
pLog->AddMsgIntoTail(logBuffer);
//}
/// 服务器处理响应客户端单播请求
if( mIsServer )
{
//if( (mode == 3) || ( (mode == 5) && GetIsUniCast() ))
if( mode == 3 )
{
/// 回复客户端
///Li = 0 Vn保存 Mode=4 Stratum=1
nfp.m_Basic.m_LiVnMode = ( nfp.m_Basic.m_LiVnMode & 0xF8) + 4;
nfp.m_Basic.m_Stratum = 1;
/// 保留Poll
///
nfp.m_Basic.m_RootDelay = 0;
nfp.m_Basic.m_RootDispersion = 0;
nfp.m_Basic.m_ReferenceID[0] = 0; //NULL;
nfp.m_Basic.m_ReferenceTimestamp.m_dwFractional = 0;
nfp.m_Basic.m_ReferenceTimestamp.m_dwInteger = 0;
nfp.m_Basic.m_OriginateTimestamp = nfp.m_Basic.m_TransmitTimestamp;
nfp.m_Basic.m_ReceiveTimestamp = response.m_DestinationTime;
nfp.m_Basic.m_TransmitTimestamp = CNtpTime::GetCurrentTime();
//int nSendSize = sizeof(NtpBasicInfo);
int nSendSize = sizeof(NtpFullPacket);
lRet = mPeerSocket.Send((char *) &nfp, nSendSize, &fromAddr);
if( lRet == nSendSize )
{
strcpy(logBuffer,"服务器成功发送响应");
pLog->AddMsgIntoTail(logBuffer);
}
else
{
strcpy(logBuffer,"服务器发送响应消息失败");
pLog->AddMsgIntoTail(logBuffer);
}
}
/// 服务器和外部时钟服务器进行时间同步
else if( mode == 4 )
{
response.m_nStratum = nfp.m_Basic.m_Stratum;
response.m_nLeapIndicator = (nfp.m_Basic.m_LiVnMode & 0xC0) >> 6;
response.m_OriginateTime = nfp.m_Basic.m_OriginateTimestamp;
response.m_ReceiveTime = nfp.m_Basic.m_ReceiveTimestamp;
response.m_TransmitTime = nfp.m_Basic.m_TransmitTimestamp;
response.m_RoundTripDelay = (response.m_DestinationTime - response.m_OriginateTime) - (response.m_ReceiveTime - response.m_TransmitTime);
response.m_LocalClockOffset = ((response.m_ReceiveTime - response.m_OriginateTime) + (response.m_TransmitTime - response.m_DestinationTime)) / 2;
RepairSystemTime(&response);
}
}
/// 客户机处理服务器响应
if(!mIsServer)
{
if( mode == 4 )
{
/// 处理通常单播
if( !(mIsAnyCast || mIsMultiCast) )
{
SYSTEMTIME st;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -