/****************************************************************************
** File name    :  HTSntpc.cpp
** Description  :  sntp client
** 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_ = "HTSntpc.cpp";
#include "HTGlobal.h"
#include "HTSntp.h"
#include "HTNtptime.h"

static string GetHostIP(const string& strHost)
{
    //WSADATA wsa;
    //::WSAStartup(MAKEWORD(2, 0), &wsa);
#ifdef _WIN32
    PHOSTENT hostinfo;
#else
    struct hostent *hostinfo;
#endif
    hostinfo = gethostbyname(strHost.c_str());
    if (hostinfo != NULL)
    {
        //DWORD dwIP = (DWORD)htonl((*(struct in_addr *)*hostinfo->h_addr_list).S_un.S_addr);
        string strIP = inet_ntoa(*(struct in_addr *)*hostinfo->h_addr_list);
        return strIP;
    }

    //::WSACleanup();
    return strHost;
}

//设置套接字超时时间 
static bool SetTimeout(int s, int nTime, bool bRecv)
{
    int ret = ::setsockopt(s, SOL_SOCKET, bRecv ? SO_RCVTIMEO : SO_SNDTIMEO, (char *)&nTime, sizeof(nTime));
    return ret != -1;
}

// init socket evnet
int initSocket()
{
#ifdef _WIN32
    u16_t     wVersionRequested;
    u8_t      wsMajorVersion = 1;
    u8_t      wsMinorVersion = 1;
    WSADATA   wsaData_server;
    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 -1;
    }

    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 -1;
    }
#endif
    return 0;
}

int iSntpc(int argc, char* argv[])
{
    if (argc != 3) return 0;

    vector<string> vecTimeSvr;
    vecTimeSvr.push_back(argv[1]);
    //vecTimeSvr.push_back("time.windows.com");
    //vecTimeSvr.push_back("time.nist.gov");
    //vecTimeSvr.push_back("time-nw.nist.gov");
    //vecTimeSvr.push_back("pool.ntp.org");
    //vecTimeSvr.push_back("europe.pool.ntp.org");
    //vecTimeSvr.push_back("asia.pool.ntp.org");
    //vecTimeSvr.push_back("oceania.pool.ntp.org");
    //vecTimeSvr.push_back("north-america.pool.ntp.org");
    //vecTimeSvr.push_back("south-america.pool.ntp.org");
    //vecTimeSvr.push_back("africa.pool.ntp.org");
    //vecTimeSvr.push_back("ca.pool.ntp.org");
    //vecTimeSvr.push_back("uk.pool.ntp.org");
    //vecTimeSvr.push_back("us.pool.ntp.org");
    //vecTimeSvr.push_back("au.pool.ntp.org");
    initSocket();
    for (size_t i = 0; i < vecTimeSvr.size(); ++i)
    {
        string strHostName = vecTimeSvr[i];
        string strIP = GetHostIP(strHostName);
        cout << strHostName << ": " << strIP << endl;

        int addr_len = sizeof(struct sockaddr_in);
        sockaddr_in SvrIp;
        SvrIp.sin_family = AF_INET;
        SvrIp.sin_addr.s_addr = inet_addr(strIP.c_str());
        SvrIp.sin_port = htons(atoi(argv[2]));

        int nLenRcv = 0;
        char szBuff[48] = { '\0' };
        szBuff[0] = 3 | (4 << 3);
        int sSession = socket(AF_INET, SOCK_DGRAM, 0);

        if (connect(sSession, (struct sockaddr *) &SvrIp, sizeof(struct sockaddr)) != 0) {
            perror("connect error");
            exit(-1);
        }

        SetTimeout(sSession, 3000, FALSE);
        if (-1 != sendto(sSession, szBuff, 48, 0, (sockaddr*)&SvrIp, addr_len))
        {
            SetTimeout(sSession, 3000, TRUE);
            memset(szBuff, 0x00, sizeof(szBuff));
#ifdef _WIN32
            nLenRcv = recvfrom(sSession, szBuff, 48, 0, (sockaddr*)&SvrIp, &addr_len);
#else
            nLenRcv = recvfrom(sSession, szBuff, 48, 0, (struct sockaddr *)&SvrIp, (socklen_t*)&addr_len);
#endif
        }
        else
        {
            cout << "send request failed!" << endl;
            perror("connect error");
        }
#ifdef _WIN32
        closesocket(sSession);
#else
        close(sSession);
#endif
        if (nLenRcv == 48)
        {
            time_t t = 0;
            for (int i = 40; i <= 43; i++)
            {
                unsigned char c = (unsigned char)szBuff[i];
                t = (t << 8) | c;
            }

            t -= 2209075200;	// 1970.1.1 0:0:0
            t += 8 * 60 * 60;	// UTC to Beijin

            tm *_t = gmtime(&t);
            printf("get sntpd time: %04d-%02d-%-2d %02d:%02d:%02d-%d\n", (_t->tm_year + 1900), (_t->tm_mon + 1), _t->tm_mday,
                _t->tm_hour, _t->tm_min, _t->tm_sec, _t->tm_wday);
            cout << (_t->tm_year + 1900) << "-" << (_t->tm_mon + 1) << "-" << (_t->tm_mday) << " " << _t->tm_hour << ":" << _t->tm_min << ":" << _t->tm_sec << endl;
        }
        else
        {
            cout << "recieve data failed!" << endl;
        }
        cout << endl;
    }
#ifdef _WIN32
    WSACleanup();
#endif
    return 0;
}

