/************************************************************
* Details: 网络队列循环处理机制
* Encode: UTF-8
* Platform: Android & Linux
* Author: R&D 2
* Date: 2018-4-2
************************************************************/
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "gterror.h"
#include "gt.h"
#include "gttoolkitext.h"
#include "gtencrypt.h"
#include "gtmessagequeue.h"
#include "gtnetworkloop.h"

GtNetworkLoop *GtNetworkLoop::_instance = NULL;

GtNetworkLoop::GtNetworkLoop():_readTimeout(45)
{
    _networkQueue = NULL;
    _runFlag = true;
}

GtNetworkLoop::~GtNetworkLoop()
{
    if(_networkQueue != NULL)
    {
        delete _networkQueue;
        _networkQueue = NULL;
    }
}

GtNetworkLoop *GtNetworkLoop::instance()
{
    if(_instance == NULL)
    {
        _instance = new GtNetworkLoop();
    }
    return _instance;
}

/************************************************************
*功能：创建网路队列以及本地监听链路
*输入：size队列长度
*输出：无
*返回：true,false
*/
bool GtNetworkLoop::initNetwork(int size)
{
    int socketFd = -1;
    int result = 0;
    int index = 0;
    stNetworkItem item;

    //初始化网络队列
    _networkQueue = new GtNetworkQueue();
    if(!_networkQueue->initNetworkQueue(size))
    {
        GtToolkitExt::logError(__FILE__, __LINE__, "创建网路队列错误");
        return false;
    }
    //创建本地监听socket
    signal(SIGPIPE, SIG_IGN);
    result = GtToolkitExt::tcpSocket(&socketFd);
    if(result != 0 || socketFd < 0)
    {
        return false;
    }
    result = GtToolkitExt::tcpListen(socketFd, 128, NULL, 15000);
    if(result != 0)
    {
        close(socketFd);
        return false;
    }
    memset(&item, 0, sizeof(stNetworkItem));
    item.nSocketFd = socketFd;
    item.lConnectTime = time(NULL);
    item.unType = GtNetworkQueue::NET_TYPE_LOCAL_LISTEN;
    if(!_networkQueue->getEmptyNode(&index, &item))
    {
        close(socketFd);
        return false;
    }
    return true;
}

/************************************************************
*功能：网络队列停止工作
*输入：无
*输出：无
*返回：无
*/
void GtNetworkLoop::stop()
{
    _runFlag = false;
}

/************************************************************
*功能：网络队列循环处理
*输入：无
*输出：无
*返回：无
*/
void GtNetworkLoop::loop()
{
    int result = 0;
    int size = 0;
    int i = 0;
    int maxFd = -1;
    fd_set rSet;
    struct timeval timeVal;
    stNetworkItem item;

    while(_runFlag)
    {
        size = _networkQueue->size();
        if(size <= 0)
        {
            continue;
        }
        timeVal.tv_sec = 1;
        timeVal.tv_usec = 0;
        FD_ZERO(&rSet);
        for(i = 0; i < size; i++)
        {
            memset(&item, 0, sizeof(stNetworkItem));
            if(_networkQueue->getNode(i, &item))
            {
                if(item.unType != 0 && item.nSocketFd > -1)
                {
                    FD_SET(item.nSocketFd, &rSet);
                    maxFd = (maxFd < item.nSocketFd) ? item.nSocketFd : maxFd;
                }
            }
        }
        if(maxFd == -1)
        {
            continue;
        }
        result = select(maxFd + 1, &rSet, NULL, NULL, &timeVal);
        if(result < 0)
        {
            continue;
        }
        else if(result == 0)
        {
            continue;
        }
        else
        {
            for(i = 0; i < size; i++)
            {
                memset(&item, 0, sizeof(stNetworkItem));
                if(_networkQueue->getNode(i, &item))
                {
                    if(item.unType != 0 && item.nSocketFd > -1 && FD_ISSET(item.nSocketFd, &rSet))
                    {
                        if(item.unType == GtNetworkQueue::NET_TYPE_LOCAL_LISTEN)
                        {
                            establishConnect(&item);
                        }
                        else if(item.unType == GtNetworkQueue::NET_TYPE_LOCAL_CONNECT)
                        {
                            receiveLocalRequest(i, &item);
                        }
                        break;
                    }
                }
            }
        }
        clearTimeoutSocket();
    }
    _networkQueue->releaseNetworkQueue();
}

/************************************************************
*功能：接受本地网络链路请求
*输入：item=网络队列项属性
*输出：无
*返回：无
*/
void GtNetworkLoop::establishConnect(stNetworkItem *item)
{
    int result = 0;
    int index = 0;
    int socketFd = -1;
    char connIP[128];
    stNetworkItem localItem;

    if(item == NULL)
    {
        return;
    }
    memset(connIP, 0, sizeof(connIP));
    result = GtToolkitExt::tcpAccept(item->nSocketFd, &socketFd, connIP);
    if(result != 0 || socketFd < 0)
    {
        GtToolkitExt::logError(__FILE__, __LINE__, "本地通信链路Accept错误<%d>", result);
        return;
    }
    memset(&localItem, 0, sizeof(stNetworkItem));
    localItem.nSocketFd = socketFd;
    localItem.unType = GtNetworkQueue::NET_TYPE_LOCAL_CONNECT;
    localItem.lConnectTime = time(NULL);
    if(!_networkQueue->getEmptyNode(&index, &localItem))
    {
        close(socketFd);
        GtToolkitExt::logError(__FILE__, __LINE__, "网络队列已满");
        return;
    }
}

/************************************************************
*功能：接收本地网络请求数据，并插入到消息队列
*输入：index=网络队列序号
*输入：item=网络队列项属性
*输出：无
*返回：无
*/
void GtNetworkLoop::receiveLocalRequest(int index, stNetworkItem *item)
{
    int result = 0;
    int msgIndex = 0;
    long crc32 = 0;
    stMessageItem msgItem;

    if(item == NULL || index < 0)
    {
        return;
    }
    memset(&msgItem, 0, sizeof(stMessageItem));
    //读取本地请求数据
    result = GtToolkitExt::readN(item->nSocketFd, &msgItem.msg.msgTag, sizeof(stMessageTag), _readTimeout);
    if(result != 0)
    {
        if(result == GtError::ERROR_CLOSED)
        {
            close(item->nSocketFd);
            _networkQueue->recycleNode(index);
            //GtToolkitExt::logError(__FILE__, __LINE__, "本地通信链路[%d]已关闭<%d>", item->nSocketFd, result);
        }
        else
        {
            //GtToolkitExt::logError(__FILE__, __LINE__, "本地请求数据读取错误<%d>", result);
        }
        return;
    }
    if(msgItem.msg.msgTag.ulDataSize > 0)
    {
        result = GtToolkitExt::readN(item->nSocketFd, msgItem.msg.strData, msgItem.msg.msgTag.ulDataSize, _readTimeout);
        if(result != 0)
        {
            if(result == GtError::ERROR_CLOSED)
            {
                close(item->nSocketFd);
                _networkQueue->recycleNode(index);
                GtToolkitExt::logError(__FILE__, __LINE__, "本地通信链路[%d]已关闭<%d>", item->nSocketFd, result);
            }
            else
            {
                GtToolkitExt::logError(__FILE__, __LINE__, "读取本地链路数据错误<%d>", result);
            }
            return;
        }
    }
    //CRC校验
    crc32 = GtEncrypt::crc32(msgItem.msg.strData, msgItem.msg.msgTag.ulDataSize);
    if(crc32 != msgItem.msg.msgTag.lCRC)
    {
        GtToolkitExt::logError(__FILE__, __LINE__, "数据CRC校验错误");
        return;
    }
    //GtToolkitExt::logInfo(__FILE__, __LINE__, "%s", &msgItem.msg.strData[2]);
    //转换本地请求数据报文
    if(msgItem.msg.msgTag.ulType == 1 || msgItem.msg.msgTag.ulType == 2)
    {

    }
    else
    {
        GtToolkitExt::logError(__FILE__, __LINE__, "未授权的本地请求，已忽略");
        return;
    }
    //将本地请求加入到消息队列等待处理
    msgItem.lTime = time(NULL);
    msgItem.nValidTime = msgItem.lTime + _readTimeout;
    msgItem.unStatus = 1;
    msgItem.nRoute = item->nSocketFd;
    if(!GtMessageQueue::instance()->getEmptyNodeSecure(&msgIndex, &msgItem))
    {
        //localResponse(item->nSocketFd, &msgItem.msg.msgTag, GtError::ERROR_MESSAGE_QUEUE_FULL, (char *)"Message queue full");
        GtToolkitExt::logError(__FILE__, __LINE__, "消息队列已满");
        return;
    }
}

/************************************************************
*功能：清除超时的socket链路
*输入：无
*输入：无
*输出：无
*返回：无
*/
void GtNetworkLoop::clearTimeoutSocket()
{
    int size = 0;
    int i = 0;
    stNetworkItem item;

    size = _networkQueue->size();
    for(i = 0; i < size; i++)
    {
        memset(&item, 0, sizeof(stNetworkItem));
        if(_networkQueue->getNode(i, &item))
        {
            if(item.unType == GtNetworkQueue::NET_TYPE_LOCAL_CONNECT && item.nSocketFd > -1)
            {
                time_t ltime = time(NULL);
                if(ltime - item.lConnectTime >= 120)
                {
                    GtToolkitExt::logInfo(__FILE__, __LINE__, "清除超时的链路[%d]", item.nSocketFd);
                    close(item.nSocketFd);
                    item.nSocketFd = -1;
                    _networkQueue->setNode(i, &item);
                }
            }
        }
    }
}
