/****************************************************************************
** File name    :  HTSntpd.cpp
** Description  :  sntpd server
** Create date  :  2020.06.11
** Auther by    :  Liuyx
** Version info :  V1.0.01
** Copyrigth By:  xi'an huatek, Inc Co., Ltd
** Update record:
** DATE         AUTHER   DESC
** -------------------------------------------------------------------------
** 2020.06.11   Liuyx    first build
****************************************************************************/
static const char *_FILE_ = "HTSntpd.cpp";
#include "HTGlobal.h"
#include "HTSntp.h"
#include "HTNtptime.h"

#define ERROR_SOCKET          0   //初始化套接字错误     
#define ERROR_RCV_PACKET      1   //接收客户端数据包错误   
#define ERROR_SEND_PACKET     2   //发送数据包错误   
#define ERROR_WINSOCK_STACK   3   //载入套接字堆栈错误   
#define ERROR_WINSOCK_VERSION 4   //套接字版本错误   
#define ERROR_BIND_SERVER     5   //绑定服务器端口错误   
#define ERROR_REPLY           6   //调用回复客户端程序错误   


int   m_hNtpServerSocket;
struct sockaddr_in fsin;
NtpBasicInfo       nbi;
NtpFullPacket      nfp;
int nReceivefromSize = sizeof(nbi);
int alen = sizeof(fsin);
int nSendSize = sizeof(NtpFullPacket);

/************************************************************************/
/*  函数原型：reply()
参数类型：
返回值：  返回值在定义中已说明
基本原理：收包，填包，发包                                          */
/************************************************************************/
int reply()
{
    ulong   dwError;
    int nSendtoSize;

    SYSTEMTIME   st1;
    SYSTEMTIME   st2;

    char szBuffer[128];

    int rc = 0;

    printf("waiting packets.........................\n");
#ifdef _WIN32
    rc = recvfrom(m_hNtpServerSocket, szBuffer, 128, 0, (struct sockaddr *)&fsin, &alen);
#else
    rc = recvfrom(m_hNtpServerSocket, szBuffer, 128, 0, (struct sockaddr *)&fsin, (socklen_t*)&alen);
#endif
    memcpy(&nbi, szBuffer, sizeof(nbi));
    if (rc == -1)
    {
        //printf("%s",inet_ntoa(*(struct in_addr*)(fsin.sin_addr));   

        printf(("Could not receive from the SNTP client , get_last_error returns: %lu\n"), get_last_error());

        dwError = get_last_error();

        set_last_error(dwError);

        return ERROR_RCV_PACKET;
    }
    else
    {
        printf("packet was successfully received\n");

        memset(&nfp, 0, nSendSize);

        nfp.m_Basic.m_LiVnMode = (nbi.m_LiVnMode == 27) ? 28 : 26;
        nfp.m_Basic.m_OriginateTimestamp = nbi.m_TransmitTimestamp;  //发包过来的已经是网络字节序   
        nfp.m_Basic.m_ReferenceTimestamp = host2network(MyGetCurrentTime());
        nfp.m_Basic.m_ReceiveTimestamp = nfp.m_Basic.m_ReferenceTimestamp;
        //Sleep(100);   
        nfp.m_Basic.m_TransmitTimestamp = host2network(MyGetCurrentTime());
    }

    nSendtoSize = sizeof(NtpFullPacket);

    if (sendto(m_hNtpServerSocket, (char *)& nfp, nSendtoSize, 0, (struct sockaddr *) &fsin, sizeof(fsin)) == -1)

    {
        printf(("Failed in  send NTP reply to the SNTP client, get_last_error returns %lu\n"), get_last_error());

        dwError = get_last_error();

        set_last_error(dwError);

        return ERROR_SEND_PACKET;
    }

    //////////////////////////////////////////////////////////////////////////   

    st1 = NtpTimePacket2SystemTime(network2host(nfp.m_Basic.m_OriginateTimestamp));
    st2 = NtpTimePacket2SystemTime(network2host(nfp.m_Basic.m_TransmitTimestamp));

    printf("Time was successfully send to NTP client\n");
    printf(("                            DD/MM/YYYY  HH:MM:SS.MS\n"));
    printf(("Client Originate Date was   %02d/%02d/%04d, %02d:%02d:%02d.%03d\n"),
        st1.wDay, st1.wMonth, st1.wYear, st1.wHour, st1.wMinute, st1.wSecond, st1.wMilliseconds);
    printf(("Server Transmit Date was     %02d/%02d/%04d, %02d:%02d:%02d.%03d\n"),
        st2.wDay, st2.wMonth, st2.wYear, st2.wHour, st2.wMinute, st2.wSecond, st2.wMilliseconds);
    printf(("   T2=%f %lu,%lu\n   T3=%f %lu,%lu\n"),
        NtpTimePacket2Double(network2host(nfp.m_Basic.m_ReceiveTimestamp)),
        network2host(nfp.m_Basic.m_ReceiveTimestamp).m_dwInteger,
        network2host(nfp.m_Basic.m_ReceiveTimestamp).m_dwFractional,
        NtpTimePacket2Double(network2host(nfp.m_Basic.m_TransmitTimestamp)),
        network2host(nfp.m_Basic.m_TransmitTimestamp).m_dwInteger,
        network2host(nfp.m_Basic.m_TransmitTimestamp).m_dwFractional);

    return 0;
}


int iSntpd(int argc_server, char *argv[])
{
    char     service[128] = "sntp";
    u16_t     wVersionRequested;
    u8_t      wsMajorVersion = 1;
    u8_t      wsMinorVersion = 1;
#ifdef _WIN32
    WSADATA   wsaData_server;
#endif
    int qlen = 0;
    u16_t nPort = 102;
    ulong   dwError;

    switch (argc_server)
    {
    case    1:
        break;
    case    2:
        strcpy(service, argv[1]);
        break;
    default:
        printf("usage: UDPtimed [port]\n");
    }

    //////////////////////////////////////////////////////////////////////////   
#ifdef _WIN32
    wVersionRequested = ((u16_t)(((u8_t)(wsMinorVersion)) | ((u16_t)((u8_t)(wsMajorVersion))) << 8));

    if (WSAStartup(wVersionRequested, &wsaData_server))
    {
        printf("Failed to load winsock stack\n");
        return ERROR_WINSOCK_STACK;
    }

    if ((u8_t)(wsaData_server.wVersion) != wsMajorVersion || (u8_t)(((u16_t)(wsaData_server.wVersion) != wsMinorVersion) >> 8) & 0xFF)
    {
        printf("Winsock stack does not support version which this program requires\n");
        return ERROR_WINSOCK_VERSION;
    }
#endif
    //////////////////////////////////////////////////////////////////////////   

    memset(&nbi, 0, nReceivefromSize);
    // m_hNtpServerSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);    
    m_hNtpServerSocket = (int)socket(AF_INET, SOCK_DGRAM, 0);
    if (m_hNtpServerSocket == -1)
    {
        printf(("Failed to create server socket, get_last_error returns: %lu\n"), get_last_error());
        return ERROR_SOCKET;
    }

    memset(&fsin, 0, sizeof(fsin));
    fsin.sin_family = AF_INET;
    fsin.sin_addr.s_addr = INADDR_ANY;
    fsin.sin_port = htons(nPort);


    if (bind(m_hNtpServerSocket, (struct sockaddr *)&fsin, sizeof(fsin)) == -1)
    {
        printf(("can't bind to %s port: %d\n, get_last_error returns: %lu\n"), service, nPort, get_last_error());
        dwError = get_last_error();

        set_last_error(dwError);

        return ERROR_BIND_SERVER;
    }

    while (1)
    {
        if (reply() < 0)
        {
            dwError = get_last_error();

            set_last_error(dwError);

            return ERROR_REPLY;
        }
    }
#ifdef _WIN32
    WSACleanup();
#endif
    return 0;
}

