#include "qfmclient.h"
#include "fmcrypt.h"
#include "workutil.h"
#include <windows.h>
#include <QByteArray>
#include <QJsonDocument>
#include <QJsonParseError>
#include <QJsonObject>
#include <QFile>
#include <Qdebug>

#ifdef WIN32
#include <direct.h>
#include <windows.h>
#include <winsock.h>
#include <DbgHelp.h>
//#pragma comment(lib, "ws2_32.lib")
//#pragma comment(lib, "fmcrypt.lib")
//#pragma comment(lib, "DbgHelp.lib")
#else
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <unistd.h>
#endif

unsigned int QFmClient::s_reqCount = 0;

QFmClient::QFmClient(QObject *parent) : QThread(parent)
{
    _endflag = false;
}

bool QFmClient::Init(QString proxy_IP, unsigned short proxy_port, unsigned short listen_prot, unsigned short long_timeout, unsigned short short_timeout)
{ 

    if(proxy_IP.size() == 0 ||
            proxy_port <= 0 ||
            listen_prot <= 0 ||
            short_timeout <= 0 ||
            long_timeout <= 0
            )
        return false;

    if(proxy_IP.toStdString().size() > 30)
        return false;

    strcpy(_proxyIP, proxy_IP.toStdString().c_str());
    _proxyIP[proxy_IP.toStdString().size()] = 0;

    this->_proxyPort    = proxy_port;
    this->_clientPort   = listen_prot;
    this->_shortTimeOut = short_timeout;
    this->_longTimeOut  = long_timeout;

#ifdef WIN32
    WORD   wVersionRequested;
    WSADATA   wsaData;
    int   err;

    wVersionRequested = MAKEWORD(2,2);
    err  =  WSAStartup(wVersionRequested, &wsaData);

#endif

    memset(_codeKey, 0, MAX_CODE_KEY);
    memset(_codeBuf, 0, MAX_BUF_LEN);
    memset(_recvbuf, 0, MAX_BUF_LEN);
    memset(_tempbuf, 0, MAX_BUF_LEN);
    memset(_sendbuf, 0, MAX_BUF_LEN);

    _codeFlag = 1;
    _fmMSS = 1024;

    return true;
}

int QFmClient::RecvSockData(int sock, char *buffer, int length)
{
#ifdef WIN32
    return  ::recv(sock, buffer, length, 0);
#else
    return  ::read(sock, buffer, length);
#endif
}

void QFmClient::WaitAndSleep(int elapse)
{
#ifdef WIN32
    Sleep(elapse);
#else
    sleep(elapse/1000);
#endif
}

bool QFmClient::WaitForConnectReqFromPos()
{
    int sin_size = sizeof(struct sockaddr_in);
    struct sockaddr_in c_add;

    if(0 < _acceptedSock)
    {
        RecvSockData(_acceptedSock, _recvbuf, (MAX_BUF_LEN - 1));

        CloseSocket(&_acceptedSock);
    }

    _acceptedSock = accept(_listenSock, (struct sockaddr *)(&c_add), &sin_size);
    if(-1 == _acceptedSock)
    {
        qDebug() << "accept socket fail!\r\n";

        return false;
    }

    qDebug() << "accept ok, ZF Client get connection from POS!\r\n";

    return true;
}

int QFmClient::CheckIsCompleteJsonData(int * count, char * data)
{
   int loop = 0;

   while(data[loop])
    {
        if ('{' == data[loop])
        {
            (*count) ++;
        }

        if ('}' == data[loop])
        {
            (*count) --;
        }

        loop++;

        if (0 == (*count))
        {
            break;
        }
    }
    return loop;
}

#ifdef WIN32
int QFmClient::GBKToUTF8(unsigned char * lpGBKStr,int gbkLen, unsigned char * lpUTF8Str,int nUTF8StrLen)
{
    wchar_t * lpUnicodeStr = NULL;
    int nRetLen = 0;

    if(!lpGBKStr)  //如果GBK字符串为NULL则出错退出
        return 0;

    nRetLen = MultiByteToWideChar(CP_ACP,0,(char *)lpGBKStr,gbkLen,NULL,NULL);  //获取转换到Unicode编码后所需要的字符空间长度
    //lpUnicodeStr = new WCHAR[nRetLen + 1];  //为Unicode字符串空间
    lpUnicodeStr = (WCHAR*)malloc( sizeof(WCHAR)*(nRetLen + 1));
    nRetLen = MultiByteToWideChar(CP_ACP,0,(char *)lpGBKStr,gbkLen,lpUnicodeStr,nRetLen);  //转换到Unicode编码
    if(!nRetLen)  //转换失败则出错退出
        return 0;

    nRetLen = WideCharToMultiByte(CP_UTF8,0,lpUnicodeStr,nRetLen,NULL,0,NULL,NULL);  //获取转换到UTF8编码后所需要的字符空间长度

    if(!lpUTF8Str)  //输出缓冲区为空则返回转换后需要的空间大小
    {
        if(lpUnicodeStr)
            free(lpUnicodeStr);
        return nRetLen;
    }

    if(nUTF8StrLen < nRetLen)  //如果输出缓冲区长度不够则退出
    {
        if(lpUnicodeStr)
            free(lpUnicodeStr);
        return 0;
    }

    nRetLen = WideCharToMultiByte(CP_UTF8,0,lpUnicodeStr,nRetLen,(char *)lpUTF8Str,nUTF8StrLen,NULL,NULL);  //转换到UTF8编码

    if(lpUnicodeStr)
        free(lpUnicodeStr);

    return nRetLen;
}

int QFmClient::UTF8ToGBK(unsigned char * lpUTF8Str,unsigned char * lpGBKStr,int nGBKStrLen)
{
    wchar_t * lpUnicodeStr = NULL;
    int nRetLen = 0;

    if(!lpUTF8Str)  //如果UTF8字符串为NULL则出错退出
        return 0;

    nRetLen = MultiByteToWideChar(CP_UTF8,0,(char *)lpUTF8Str,-1,NULL,NULL);  //获取转换到Unicode编码后所需要的字符空间长度
    //lpUnicodeStr = new WCHAR[nRetLen + 1];  //为Unicode字符串空间
    lpUnicodeStr = (WCHAR*)malloc( sizeof(WCHAR)*(nRetLen + 1));
    nRetLen = MultiByteToWideChar(CP_UTF8,0,(char *)lpUTF8Str,-1,lpUnicodeStr,nRetLen);  //转换到Unicode编码
    if(!nRetLen)  //转换失败则出错退出
        return 0;

    nRetLen = WideCharToMultiByte(CP_ACP,0,lpUnicodeStr,-1,NULL,NULL,NULL,NULL);  //获取转换到GBK编码后所需要的字符空间长度

    if(!lpGBKStr)  //输出缓冲区为空则返回转换后需要的空间大小
    {
        if(lpUnicodeStr)
            free(lpUnicodeStr);
        return nRetLen;
    }

    if(nGBKStrLen < nRetLen)  //如果输出缓冲区长度不够则退出
    {
        if(lpUnicodeStr)
            free(lpUnicodeStr);
        return 0;
    }

    nRetLen = WideCharToMultiByte(CP_ACP,0,lpUnicodeStr,-1,(char *)lpGBKStr,nRetLen,NULL,NULL);  //转换到GBK编码

    if(lpUnicodeStr)
        free(lpUnicodeStr);

    return nRetLen;
}
#endif

char * QFmClient::DecodeRecvData(char * buf, int length, int * dLength)
{
    int curKeyPos = _curKeyPos;

    char * rltPtr = ZH_decodeRecvData(_codeBuf, buf, length, dLength, (char *)_codeKey, _keyLength, &curKeyPos);

    _curKeyPos = (char)curKeyPos;

    return rltPtr;
}

int QFmClient::WaitAndReadDataFromPos(int type, int flag)
{
    qDebug() << "wait and receive data from POS...\r\n";

    _rcvLength = 0;

    int recbytes, finLen, curPos = 0, prosLen = 0, checkCount = 0;
    int i = 0;
    do
    {
        char * precvBuf;

        if (0 >= (recbytes = RecvSockData(_acceptedSock, _tempbuf, (MAX_BUF_LEN - 1))))
        {
#ifdef WIN32
            qDebug() << "recv() return : " << recbytes << ";error : " << WSAGetLastError() << ";\r\n";
#endif
            qDebug() << "read data from socket " << _acceptedSock << " fail!\r\n";

            return -1;
        }
#ifdef	WIN32
        if(type)
        {

            memcpy( _sendbuf, _tempbuf, recbytes );

            recbytes = GBKToUTF8( (unsigned char *)_sendbuf, recbytes, (unsigned char *)_tempbuf, MAX_BUF_LEN - 100);
        }
#endif
        precvBuf = _tempbuf;

        _tempbuf[recbytes] = '\0';

        if(1 == flag)
            precvBuf = DecodeRecvData(_tempbuf, recbytes, &recbytes);

        qDebug() << "received data from socket " << _acceptedSock << " : " << precvBuf;

        while(0 < recbytes)
        {
            finLen = CheckIsCompleteJsonData(&checkCount, precvBuf + prosLen);

            if (((0 == checkCount) && ( '}' != precvBuf[ prosLen + finLen - 1])) || ((MAX_BUF_LEN - 1) < curPos + finLen))
            {
                qDebug() << "checkCount out!\r\n";
                return -1;
            }

            memcpy(_recvbuf + curPos, precvBuf + prosLen, finLen);

            curPos += finLen;
            prosLen += finLen;

            if (0 == checkCount)
            {
                _recvbuf[curPos] = '\0';
                _rcvLength = curPos;
                curPos = 0;
                checkCount = 0;
                qDebug() << "checkCount = 0";

                goto finishRecv;
            }

            recbytes -= finLen;
        }

        prosLen = 0;
    }while(1);

finishRecv:
    return 0;
}

void QFmClient::AddReqCount(QJsonObject& object)
{
    s_reqCount %= MAX_REQ_COUNT;
    s_reqCount ++;
    object["clientReqCount"] = (int)s_reqCount;
}

int QFmClient::CheckReqFromPos(char * pJsonData, int dLength, int chkValue)
{
    return ZH_checkChkValue(pJsonData, dLength, chkValue);
}

int QFmClient::ProcessPosReqData(QJsonObject& object)
{
    int flag = 0;
    QByteArray recvdata(_recvbuf);

    QJsonParseError json_error;
    QJsonDocument doc = QJsonDocument::fromJson(recvdata, &json_error);

    if(json_error.error != QJsonParseError::NoError || !doc.isObject())
    {
        qDebug() << "error request json data!\r\n";
        return -1;
    }

    object = doc.object();

    do
    {
        _sockTimeOut = _longTimeOut;
        if(object.contains("reqtype"))
        {
            if(object["reqtype"] != 72)
            {
                 _sockTimeOut = _shortTimeOut;
            }

            if(object["reqtype"] == 72 || object["reqtype"] == 71)
            {
                flag = 1;
            }

        }else
        {
            qDebug() << "not found reqtype";
            flag = -1;
            break;
        }

        if(!object.contains("checkValue") || !object["checkValue"].isDouble())
        {
            qDebug() << "checkValue failed!\r\n";
            flag = -1;
            break;
        }

        AddReqCount(object);

    }while(0);

    return flag;

}

int QFmClient::Try2ConnectZhProxy()
{
    struct sockaddr_in proxyAddr;
    int rlt = 0;

    unsigned long ul = 1;
    unsigned long sendsize = 32;
    BOOL bNoDelay = TRUE;
    fd_set fs;

    struct timeval cntTO = {_shortTimeOut,0};

#ifdef WIN32
    int sockTimeOut = _sockTimeOut * 1000;
#else
    struct timeval sockTimeOut={_sockTimeOut,0};
#endif

    _zhProxySock = socket(AF_INET, SOCK_STREAM, 0);

    memset(&proxyAddr, 0, sizeof(struct sockaddr_in));

    proxyAddr.sin_addr.s_addr =inet_addr(_proxyIP);
    proxyAddr.sin_family   =  AF_INET;
    proxyAddr.sin_port  =  htons(_proxyPort);

#ifdef WIN32
    ioctlsocket(_zhProxySock, FIONBIO, &ul);
#else
    ioctl(_zhProxySock, FIONBIO, &ul);
#endif

    ::connect(_zhProxySock, (struct sockaddr *)&proxyAddr, sizeof(struct sockaddr));

    FD_ZERO(&fs);
    FD_SET(_zhProxySock, &fs);

    rlt = select(_zhProxySock + 1, 0, &fs, 0, &cntTO);

    if (0 >= rlt)
    {
#ifdef WIN32
        closesocket(_zhProxySock);
#else
        closesocket(_zhProxySock);
#endif
        return -1;
    }

    ul = 0;
#ifdef WIN32
    ioctlsocket(_zhProxySock, FIONBIO, &ul);
#else
    ioctl(_zhProxySock, FIONBIO, &ul);
#endif

#ifdef WIN32
    //setsockopt(g_clientInfo.zhProxySock, SOL_SOCKET, SO_SNDBUF, (char*)&sendsize,sizeof(int));
    setsockopt(_zhProxySock, IPPROTO_TCP, TCP_NODELAY,  (char FAR *)&bNoDelay, sizeof(BOOL));
    setsockopt(_zhProxySock, SOL_SOCKET, SO_SNDTIMEO, (char *)&sockTimeOut, sizeof(int));
    setsockopt(_zhProxySock, SOL_SOCKET, SO_RCVTIMEO, (char *)&sockTimeOut, sizeof(int));
#else
    setsockopt(_zhProxySock, SOL_SOCKET, SO_RCVTIMEO, (char *)&sockTimeOut, sizeof(struct timeval));
    setsockopt(_zhProxySock, SOL_SOCKET, SO_SNDTIMEO, (char *)&sockTimeOut, sizeof(struct timeval));
#endif

    return 0;
}

void QFmClient::GetKey()
{
    _curKeyPos = 0;
    _keyLength = ZH_getKey((char *)_codeKey, _tempbuf, 0);
}

char * QFmClient::EncodeSendData(char * buf, int length, int * eLength)
{
    return ZH_encodeSendData(_codeBuf, buf, length, eLength, (char *)_codeKey, _keyLength);
}

int QFmClient::SendSocketData(int sock, char * buf, int length, int flag)
{
    char * psendBuf = buf;
    int tmplen = 0, tmp = _fmMSS, tmpsize = _fmMSS, len = 0;

    if (1 == flag)
    {
        psendBuf = EncodeSendData(buf, length, &length);
    }

#ifdef WIN32
    if(length <= tmp)
    {
        return send(sock, psendBuf, length, 0);
    }else
    {
        while(tmplen < length)
        {
            if(tmplen + tmp > length)
            {
                tmpsize = length - tmplen;
                tmplen = length;
            }else
            {
                tmpsize = tmp;
                tmplen += tmp;
            }
            send(sock, psendBuf + len, tmpsize, 0);
            len = tmplen;
        }
    }
    return tmplen;
#else
  return write(sock, psendBuf, length);
#endif
}

int QFmClient::SendCtrlInfo2Proxy()
{
    int sendRlt, offset = 1;

    _tempbuf[0] = _codeFlag;

    if (_codeFlag)
    {
        GetKey();
        offset += (1 + _tempbuf[1]);
    }

    _tempbuf[offset] = _sockTimeOut;

    sendRlt = SendSocketData(_zhProxySock, _tempbuf, MAX_CTRL_INFO_LEN, 0);

    if (sendRlt != MAX_CTRL_INFO_LEN)
    {
#ifdef WIN32
        qDebug() << "recv() return : " << sendRlt << ";error : " << WSAGetLastError() << ";\r\n";
#endif
        return -1;
    }

    return 0;
}

int QFmClient::RecvAndCheckDataFromSock(int sock, int flag, int type)  //type = 0 proxy re, = 1 pos re
{
    int recbytes, finLen, curPos = 0, prosLen = 0, checkCount = 0;
    int i = 0;
    do
    {
        char * precvBuf;

        if (0 >= (recbytes = RecvSockData(sock, _tempbuf, (MAX_BUF_LEN - 1))))
        {
#ifdef WIN32
            qDebug() << "recv() return : " << recbytes << ";error : " << WSAGetLastError() << ";\r\n";
#endif
            qDebug() << "read data from socket "<< sock <<" fail!\r\n";

            return -1;
        }
#ifdef	WIN32
        if(type)
        {

            memcpy( _sendbuf, _tempbuf, recbytes );

            recbytes = GBKToUTF8( (unsigned char *)_sendbuf, recbytes, (unsigned char *)_tempbuf, MAX_BUF_LEN - 100);
        }
#endif
        precvBuf = _tempbuf;

        _tempbuf[recbytes] = '\0';

        if (1 == flag)
        {
            precvBuf = DecodeRecvData(_tempbuf, recbytes, &recbytes);
        }

        qDebug() << "received data from socket " << sock << " : " << precvBuf;

        while(0 < recbytes)
        {
            finLen = CheckIsCompleteJsonData(&checkCount, precvBuf + prosLen);

            if (((0 == checkCount) && ( '}' != precvBuf[ prosLen + finLen - 1])) || ((MAX_BUF_LEN - 1) < curPos + finLen))
            {
                qDebug() << "checkCount out!\r\n";
                return -1;
            }

            memcpy(_recvbuf + curPos, precvBuf + prosLen, finLen);

            curPos += finLen;
            prosLen += finLen;

            if (0 == checkCount)
            {//a complete json data received


                _recvbuf[curPos] = '\0';
                _rcvLength = curPos;
                curPos = 0;
                checkCount = 0;
                qDebug() << "checkCount = 0";

                goto finishRecv;
            }

            recbytes -= finLen;
        }

        prosLen = 0;
    }while(1);

finishRecv:
    return 0;
}

int QFmClient::SendData2ZhProxyAndWaitRspData()
{
    int rlt, length;

    length = strlen(_sendbuf);

    rlt = SendSocketData(_zhProxySock, _sendbuf, length, _codeFlag);

    if (rlt != length)
    {
#ifdef WIN32
        qDebug() << "recv() return : " << rlt << ";error : " << WSAGetLastError() << ";\r\n";
#endif
        qDebug() << "send data to socket failed!\r\n";
        return -1;
    }

     qDebug() << "wait and receive data from ZH Proxy...\r\n";

    if (0 != RecvAndCheckDataFromSock(_zhProxySock, _codeFlag,0))
    {
         qDebug() << "receive data or check data failed\r\n";
         return -1;
    }

    return 0;
}

int QFmClient::CheckRecvedData()
{
    QByteArray recvdata(_recvbuf);

    QJsonParseError json_error;
    QJsonDocument doc = QJsonDocument::fromJson(recvdata, &json_error);

    if(json_error.error != QJsonParseError::NoError || !doc.isObject())
    {
        qDebug() << "error request json data!\r\n";
        return -1;
    }
    return 0;
}

int QFmClient::ProcessZhProxyRspDataAndSend2Pos()
{
    int rlt, length;

    if (0 != CheckRecvedData())
    {
        return -1;
    }

    memcpy( _tempbuf, _recvbuf, strlen(_recvbuf) );
    //UTF8ToGBK(g_clientInfo.tmpBuf, g_clientInfo.rcvBuf,MAX_SEND_RCV_BUF_LEN -100);

    length = strlen(_recvbuf);

    rlt = SendSocketData(_acceptedSock, _recvbuf, length, 0);

    if (rlt != length)
    {
#ifdef WIN32
        qDebug() << "recv() return : " << rlt << ";error : " << WSAGetLastError() << ";\r\n";
#endif
        return -1;
    }

    return  0;
}

void QFmClient::BackupPosReq(char * req)
{
    QFile file(qApp->applicationDirPath()+ "/" + ROLL_BACK_FILE_NAME);
    int wl = strlen(req);

    if(file.open(QFile::ReadWrite))
    {
        wl = ZH_encodeBkData(req, wl, (char *)_codeKey, _keyLength, _codeBuf);
        file.write(_codeBuf, wl);
        file.close();
    }
}



void QFmClient::run()
{
    QString ip;
    QString port;

    if(!readvalueforkey("pos.ini", "all", "ip",ip) ||
            !readvalueforkey("pos.ini", "all", "port", port))

    {
        qDebug() << "read pos.ini failed";
        return ;
    }

    if(!Init(ip.toStdString().c_str(), port.toInt(), 34952, 30, 5))
    {
        qDebug() << "Init QFmClient failed";
        emit Error("Init QFmClient failed");
    }

    do
    {
        CloseSocket(&_acceptedSock);
        CloseSocket(&_listenSock);
        CheckRollBackData();

        if(!StartListenport())
        {
          qDebug() << "Start Listen port : " << _clientPort <<" failed";
          WaitAndSleep(3000);
          continue ;
        }


        do
        {
            int rlt, needBackup;

            if (!WaitForConnectReqFromPos())
            {
                break;
            }

            if (0 != WaitAndReadDataFromPos(1, 0))
            {
                CloseSocket(&_acceptedSock);

                continue;
            }

            QJsonObject object;
            char temp_recv[MAX_BUF_LEN] = {0};
            strcpy(temp_recv, _recvbuf);
            needBackup = ProcessPosReqData(object);

            if (0 > needBackup)
            {
                CloseSocket(&_acceptedSock);
                continue;
            }

            if (0 != Try2ConnectZhProxy())
            {
                qDebug() << "connect to proxy failed";
                CloseSocket(&_acceptedSock);

                continue;
            }

            if (0 != SendCtrlInfo2Proxy())
            {
                CloseSocket(&_acceptedSock);
                continue;
            }

            memset(_sendbuf, 0, MAX_BUF_LEN);
            QString temp = QString(QJsonDocument(object).toJson());
            strcpy(_sendbuf, temp.toStdString().c_str());

            rlt = SendData2ZhProxyAndWaitRspData();

            if (0 == rlt)
            {
                rlt = ProcessZhProxyRspDataAndSend2Pos();
            }

            CloseSocket(&_zhProxySock);

            if (0 != rlt)
            {
                if (1 == needBackup)
                {//is write off data, need to check roll back
                    BackupPosReq(temp_recv);

                    break;
                }

                CloseSocket(&_acceptedSock);
            }
        }while(1);

        WaitAndSleep(3000);

    }while(!_endflag);

    qDebug() << "Exit ZH Client!\r\n";

#ifdef WIN32
    WSACleanup();
#endif

}

void QFmClient::CloseSocket(int *sock)
{
    if(0 < *sock)
    {
#ifdef WIN32
    closesocket(*sock);
#else
    close(*sock);
#endif
    *sock = 0;
    }
}

bool QFmClient::StartListenport()
{
    struct sockaddr_in s_add;

    int reuse = 1;

#ifdef WIN32
    _listenSock = socket(AF_INET, SOCK_STREAM, 0);
#else
    _listenSock = socket(AF_INET, SOCK_STREAM, 0);
#endif

    if(-1 == _listenSock)
    {
        return false;
    }

    memset(&s_add, 0, sizeof(struct sockaddr_in));
    s_add.sin_family=AF_INET;
    s_add.sin_addr.s_addr=htonl(INADDR_ANY);
    s_add.sin_port=htons(_clientPort);

    setsockopt(_listenSock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));

    if(-1 == bind(_listenSock,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
    {
        return false;
    }

    if(-1 == listen(_listenSock,1))
    {
        return false;
    }

    return true;
}

void QFmClient::CheckRollBackData()
{

    QString filename = qApp->applicationDirPath() + "/" + ROLL_BACK_FILE_NAME;

    FILE *file = fopen(filename.toStdString().c_str(), "rb");

    if (0 == file)
    {//no data need to be roll back
        return;
    }

    qDebug() << "need to roll back data...\r\n";

    fseek(file, 0, SEEK_SET);
    fseek(file, 0, SEEK_END);

    int readLen = ftell(file);

    fseek(file, 0, SEEK_SET);

    memset(_codeBuf, 0, MAX_BUF_LEN);
    int rlt = fread(_codeBuf, readLen, 1, file);
    fclose(file);

    if (1 != rlt || 0 >= readLen)
    {
        qDebug() << "roll back file error, file length error!\r\n";
        remove(filename.toStdString().c_str());
        return ;
    }

    memset(_sendbuf, 0, MAX_BUF_LEN);
    ZH_decodeBkData(_codeBuf, _sendbuf, readLen);

    //qDebug() << "rollback data:" << _sendbuf;
    qDebug() << "\r\n";

    QByteArray senddata(_sendbuf);

    QJsonParseError json_error;
    QJsonDocument doc = QJsonDocument::fromJson(senddata, &json_error);

    if(json_error.error != QJsonParseError::NoError || !doc.isObject())
    {
        qDebug() << "error rbk json data!\r\n";
        remove(filename.toStdString().c_str());
        return ;
    }

    QJsonObject json = doc.object();
    json["reqtype"] = 3;
    AddReqCount(json);

    memset(_sendbuf, 0, MAX_BUF_LEN);
    QString temp = QString(QJsonDocument(json).toJson());
    strcpy(_sendbuf, temp.toStdString().c_str());

    qDebug() << "rollback data:" << _sendbuf;
    qDebug() << "\r\n";

    do
    {
        WaitAndSleep(5000);

        if (0 != Try2ConnectZhProxy())
        {
            qDebug() << "roll back data: connect ZH Proxy failed, will try after 5 seconds...\r\n";

            continue;
        }

        if (0 != SendCtrlInfo2Proxy())
        {
            qDebug() << "roll back data: send ctrl info 2 ZH Proxy failed, will try after 5 seconds...\r\n";

            continue;
        }

        if (0 != SendData2ZhProxyAndWaitRspData())
        {
            qDebug() << "roll back data: send data to proxy fail, will try after 5 seconds...\r\n";

            continue;
        }

        break;
    }while(1);

    qDebug() << "roll back ok!\r\n";

    CloseSocket(&_zhProxySock);

    remove(filename.toStdString().c_str());

    return;
}

