//---------------------------------------------------------------------------


#pragma hdrstop

#include <DateUtils.hpp>
#include "PacketHandllingF.h"
#include "ClientSessionF.h"
#include "VMSCommLibF.h"
#include "VmsProtocolF.h"
//---------------------------------------------------------------------------
#define TERROR(args...)     ASession->SysLogWrite(eLOG_ERROR, ##args)
#define TDEBUG(args...)     ASession->LogWrite(eLOG_DEBUG, ##args)

#pragma package(smart_init)

//---------------------------------------------------------------------------
typedef int (*RecvPktHandlerFunc)(TClientSession *ASession, int APktLen);
//---------------------------------------------------------------------------

static int UnknownPktHandler(TClientSession *ASession, int APktLen)
{
    if (ASession->CDSLogCtlr)
        TERROR("+CLI Invalid packet handler: %s. will be closed.", ASession->IpAddress.c_str());

    MERROR("+CLI Invalid packet handler: %s. will be closed.", ASession->IpAddress.c_str());

    ASession->LogData("ERCV", (BYTE*)ASession->GetRecvBuff(), APktLen);
	ASession->Disconnect();
    return -1;
}
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
static RecvPktHandlerFunc G_FuncPktHandler[e_rpkt_MAX] = {NULL};
//---------------------------------------------------------------------------

struct _init_pkt_handler
{
    //정적 패킷핸들러 함수 초기화
	_init_pkt_handler()
	{
		for (int ii = 0; ii < e_rpkt_MAX; ii++)
		{
        	G_FuncPktHandler[ii] = UnknownPktHandler;
        }
	}
};
static _init_pkt_handler init_pkt_handler;
//---------------------------------------------------------------------------

struct RegisterHandler
{
	RegisterHandler(BYTE AOpCode, RecvPktHandlerFunc AFuncHandler)
	{
		G_FuncPktHandler[(int)AOpCode] = AFuncHandler;
	}
};
//---------------------------------------------------------------------------

#define REGISTER_HANDLER(PKT_TYPE)	\
	static int Handler_##PKT_TYPE(TClientSession* ASession, int APktLen); \
	static RegisterHandler _register_##PKT_TYPE(PKT_TYPE, Handler_##PKT_TYPE); \
	static int Handler_##PKT_TYPE(TClientSession* ASession, int APktLen)

void CALLBACK RecvCompletion(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags)
{
    TClientSession *pSession = static_cast<OverlappedIO*>(lpOverlapped)->FSession;

    if (!pSession->IsConnected)
    {
        MERROR("+SVR RecvCompletion(IsConnected false): %s[%d]", pSession->IpAddress.c_str(), pSession->Socket);
        return;
    }

    /// 에러 발생시 해당 세션 종료
    if (dwError || cbTransferred == 0)
    {
        MERROR("+SVR RecvCompletion(dwError || cbTransferred==0): %s[%d], will be closed", pSession->IpAddress.c_str(), pSession->Socket);
        pSession->Disconnect();
        return;
    }

    /// 받은 데이터 처리
    pSession->OnRead(cbTransferred);
}
//---------------------------------------------------------------------------

void CALLBACK SendCompletion(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags)
{
    TClientSession *pSession = static_cast<OverlappedIO*>(lpOverlapped)->FSession;

    if (!pSession->IsConnected)
    {
        MERROR("+SVR SendCompletion(IsConnected false): %s[%d]", pSession->IpAddress.c_str(), pSession->Socket);
        return;
    }

    /// 에러 발생시 해당 세션 종료
    if (dwError || cbTransferred == 0)
    {
        MERROR("+SVR SendCompletion(dwError || cbTransferred==0): %s[%d], will be closed", pSession->IpAddress.c_str(), pSession->Socket);
        pSession->Disconnect();
        return;
    }

    pSession->OnWriteComplete(cbTransferred, cbTransferred);
}
//---------------------------------------------------------------------------

static TCDSCtlr* FindControllerByIpAddr(AnsiString AIpAddress)
{
    CtlrItr it;
    for(it=CDSCtlrManager->FLists.FObjects.begin(); it != CDSCtlrManager->FLists.FObjects.end(); ++it)
    {
        TCDSCtlr *pObj = (TCDSCtlr*)it->second;

        if (!pObj->Used) continue;

        if (pObj->CTLR_IP.AnsiCompare(AIpAddress) == 0)
        {
            return pObj;
        }
    }

    return NULL;
}
//---------------------------------------------------------------------------
static TCDSCtlr* FindControllerById(AnsiString ACtrlNmbrId)
{
    CtlrItr it;
    for(it=CDSCtlrManager->FLists.FObjects.begin(); it != CDSCtlrManager->FLists.FObjects.end(); ++it)
    {
        TCDSCtlr *pObj = (TCDSCtlr*)it->second;

        if (!pObj->Used) continue;

        if (pObj->CTLR_NMBR_ID.AnsiCompare(ACtrlNmbrId) == 0)
        {
            return pObj;
        }
    }

    return NULL;
}
//---------------------------------------------------------------------------
bool TClientSession::ReqLogin()
{
    MINFO("+CLI Client send request Login Info: %s.", FIpAddress.c_str());

    // VMS ID 요청
    st_vms_id_req req;
    if (!SendRequest((char*)&req, sizeof(req)))
    {
        MERROR("+CLI Client send request faild: %s. will be closed.", FIpAddress.c_str());
        return false;
    }
    FState = eSS_LoginReq;
    return true;
}
//---------------------------------------------------------------------------

bool TClientSession::CheckLoginClient()
{
#if 0
    if (g_AppCfg.IsIpChecking == false)
    {
        return ReqLogin();
    }
#endif

    TCDSCtlr *pCDSCtlr = FindControllerByIpAddr(FIpAddress);
    if (!pCDSCtlr)
    {
        MERROR("+CLI Unknown client address: %s. will be closed.", FIpAddress.c_str());
        return false;
    }

    //이전 접속정보가 있는지 확인한다.
    if (FCDSCtlr)
    {
        TClientSession *pSession = FCDSCtlr->FSession;
        if (pSession)
        {
            //이전 접속을 종료하고 현재 접속을 새로운 VMS 제어기 통신으로 사용한다.
            MERROR("+CLI Client allready connect: %s. old connection will be closed.", FIpAddress.c_str());
            pSession->Disconnect();
        }
    }

    return ReqLogin();

    //
    // VMS ID 요청
    st_vms_id_req req;
    if (!SendRequest((char*)&req, sizeof(req)))
    {
        MERROR("+CLI Client send request faild: %s. will be closed.", FIpAddress.c_str());
        return false;
    }

    FState      = eSS_Connected;   //연결요청 수립
    FCDSCtlr    = pCDSCtlr;
    FCDSLogCtlr = pCDSCtlr;
    FCDSCtlr->FSession = this;
    FCDSCtlr->LOGIN_IPADDR     = FIpAddress;      //연결된 IP주소 설정
    FCDSCtlr->Server.commState = comm_open;
    FCDSCtlr->Server.ConnectTm = Now().FormatString("yyyy-MM-dd hh:nn:ss");
    FCtlrId.printf("%10.010d", FCDSCtlr->CTLR_NMBR.ToIntDef(0));
    POST_MSG(MAINHANDLE, WM_TCP_THREAD, WM_TCP_SERVER_STTS, (int)pCDSCtlr);
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    IPC_JOB_MESSAGE *pMsg = g_jobBuff.GetBuff();
    pMsg->Type   = eVmsScenarioDownload;
    pMsg->ObjPtr = (DWORD)FCDSCtlr->FSession;
    g_jobQ.PushBlocking((DWORD)pMsg);
    return true;
}
//---------------------------------------------------------------------------

bool TClientSession::OnDisconnected()
{
    if (FCDSCtlr)
    {
        FCDSCtlr->Server.DisconnectTm = Now().FormatString("yyyy-MM-dd hh:nn:ss");
        FCDSCtlr->Server.commState    = comm_close;
        FCDSCtlr->FSession            = NULL;
        //FCDSCtlr->LOGIN_IPADDR        = "";

        LERROR("VMS %s disconnected.", CtlrId.c_str());
        MERROR("%s.%d, VMS %s disconnected.", FIpAddress.c_str(), FSocket, CtlrId.c_str());

        TCDSCtlr* pCDSCtlr = FCDSCtlr;
        POST_MSG(MAINHANDLE, WM_TCP_THREAD, WM_TCP_SERVER_STTS, (int)pCDSCtlr);
    }
    else
    {
        MERROR("%s.%d, disconnected.", FIpAddress.c_str(), FSocket);
    }

    FState = eSS_Disconnect;
    return true;
}
//---------------------------------------------------------------------------

/*
* 1개의 패킷을 모두 전송한 후 호출됨
*/
void TClientSession::OnWrite(char *APktPtr, int ASendLen)
{
    st_head *pHd = (st_head*)APktPtr;
    if (!pHd) return;

    if (ASendLen > 0)
    {
        LINFO("SEND: %d Bytes", ASendLen);
        LogData("SEND", APktPtr, ASendLen);
    }
    InfoPacket(pHd->OpCode, ASendLen, true, 0);

    switch(pHd->OpCode)
    {
    case VMS_ID_REQ:            // 0xFF        // server -> client
    case DNLD_SCENARIO_REQ:     // 0x02        // server -> client
    case CTRL_RESET_REQ:        // 0x03        // server -> client
    case DNLD_FILE_REQ:         // 0x04        // server -> client
    case PARAMETER_REQ:         // 0x05        // server -> client
    case CTRL_LED_POWER_REQ:    // 0x06        // server -> client
    case CTRL_FAN_POWER_REQ:    // 0x07        // server -> client
    case CTRL_BRGH_REQ:         // 0x08        // server -> client
    case CTRL_CONFIG_REQ:       // 0x09        // server -> client
    case CTRL_TIME_REQ:         // 0x10        // server -> client
        FTmrSend = Now();
        if (FChkRecvTO == false)
        {
            FTmrRecv = Now();
        }
        FChkRecvTO = true;
        break;
    default:
        FChkRecvTO = false;     // 0x01        // server -> client
        break;
    }
}
//---------------------------------------------------------------------------

/*
*  프로토콜에 따른 처리
*/
void TClientSession::OnRead(int ALen)
{
    st_head *pHd;
    int      pktLen;

    FRecvIdx += ALen;

    if (FRecvIdx > 0)
    {
        LINFO("RECV: %d Bytes", FRecvIdx);
        LogData("RECV", (char*)FRecvBuff, FRecvIdx);
    }

	while(true)
	{
		// 프로토콜 헤더 만큼 데이터가 들어왔는지 체크
        if (FRecvIdx < (int)sizeof(st_head))
        {
            break;
        }
        pHd = (st_head*)FRecvBuff;

		// 프로토콜 헤더의 길이가 비정상적인지 체크
        if (pHd->Length < 0 || pHd->Length > 2048)
        {
            MERROR("+CLI Packet parsing data length overflow: %s, %d bytes", FIpAddress.c_str(), pHd->Length);
            Disconnect();
            break;
        }

        pktLen = (int)(pHd->Length+sizeof(st_head)+1); // 데이터길이, 헤더사이즈, ETX
        if (FRecvIdx < pktLen)
        {
            break;
        }

        try
        {
            if (pHd->OpCode != e_rpkt_NOTIFY_STTS)  // 제어기에서 스스로 올리는 OpCode
            {
                FChkRecvTO = false;
                FTmrRecv   = Now();
            }

            if (FState == eSS_LoginReq && pHd->OpCode != e_rpkt_VMS_ID_RES)
            {
                MERROR("+CLI Not Login Unknown OPCODE: %s, %02. will be closed.", FIpAddress.c_str(), pHd->OpCode);
                Disconnect();
                break;
            }

            // 패킷처리
            InfoPacket(pHd->OpCode, pktLen, false, 0);
            if (G_FuncPktHandler[pHd->OpCode](this, pktLen) < 0)
            {
                Disconnect();
                return;
            }
            SendFlush();
        }
        catch(Exception &e)
        {
            MERROR("+CLI Packet parsing exception: %s, %s, %s", FIpAddress.c_str(), AnsiString(e.ClassName()).c_str(), AnsiString(e.Message).c_str());
            Disconnect();
            break;
        }
	}
}
//---------------------------------------------------------------------------
template <class PKT_TYPE>
bool TClientSession::ParsePacket(PKT_TYPE& pkt, int APktLen)
{
    if (APktLen > FRecvIdx)
    {
        MERROR("+CLI ParsePacket Error: %s, PktLen: %d, RecvIdx: %d", FIpAddress.c_str(), APktLen, FRecvIdx);
        return false;
    }

    memcpy((char*)&pkt, FRecvBuff, APktLen);
    FRecvIdx -= APktLen;
    if (FRecvIdx > 0)
    {
        memmove(FRecvBuff, FRecvBuff+APktLen, FRecvIdx);
    }
    return true;
}
//---------------------------------------------------------------------------

bool TClientSession::InfoPacket(BYTE AOpCode, int ALen, bool ASend, int AResult/*=0*/)
{
    TCDSCtlr* pCDSCtlr = FCDSLogCtlr;

    if (!pCDSCtlr) return -1;
    //if (!pCDSCtlr->FDispLog) return -1;
    //if (!g_LogCfg.Debug) return -1;
    if (!g_LogCfg.Info) return -1;

    AnsiString sCmd;

    switch(AOpCode)
    {
    case VMS_ID_REQ:            // 0xFF        // server -> client
        if (ASend) sCmd = "VMS_ID_REQ";
        else       sCmd = "VMS_ID_RES";
        break;
    case NOTIFY_STTS_ACK:       // 0x01        // server -> client
        if (ASend) sCmd = "NOTIFY_STTS_ACK";
        else       sCmd = "NOTIFY_STTS_RES";
        break;
    case DNLD_SCENARIO_REQ:     // 0x02        // server -> client
        if (ASend) sCmd = "DNLD_SCENARIO_REQ";
        else       sCmd = "DNLD_SCENARIO_RES";
        break;
    case DNLD_FILE_REQ:         // 0x04        // server -> client
        if (ASend) sCmd = "DNLD_FILE_REQ";
        else       sCmd = "DNLD_FILE_RES";
        break;
    case PARAMETER_REQ:         // 0x05        // server -> client
        if (ASend) sCmd = "PARAMETER_REQ";
        else       sCmd = "PARAMETER_RES";
        break;
    case CTRL_LED_POWER_REQ:    // 0x06        // server -> client
        if (ASend) sCmd = "CTRL_LED_POWER_REQ";
        else       sCmd = "CTRL_LED_POWER_RES";
        break;
    case CTRL_FAN_POWER_REQ:    // 0x07        // server -> client
        if (ASend) sCmd = "CTRL_FAN_POWER_REQ";
        else       sCmd = "CTRL_FAN_POWER_RES";
        break;
    case CTRL_BRGH_REQ:         // 0x08        // server -> client
        if (ASend) sCmd = "CTRL_BRGH_REQ";
        else       sCmd = "CTRL_BRGH_RES";
        break;
    case CTRL_CONFIG_REQ:       // 0x09        // server -> client
        if (ASend) sCmd = "CTRL_CONFIG_REQ";
        else       sCmd = "CTRL_CONFIG_RES";
        break;
    case CTRL_TIME_REQ:         // 0x10        // server -> client
        if (ASend) sCmd = "CTRL_TIME_REQ";
        else       sCmd = "CTRL_TIME_RES";
        break;
    case CTRL_RESET_REQ:         // 0x10        // server -> client
        if (ASend) sCmd = "CTRL_RESET_REQ";
        else       sCmd = "CTRL_RESET_RES";
        break;
    default:
        sCmd.printf("UNKNOWN Packet: %02X", AOpCode);
        return false;
    }

    if (ASend)
    {
        if (AResult == 0)
            LINFO("SEND: %s, %d Bytes", sCmd.c_str(), ALen);
        else
            LERROR("SEND FAIL: %s, %d Bytes", sCmd.c_str(), ALen);
    }
    else
    {
        LINFO("RECV: %s, %d Bytes", sCmd.c_str(), ALen);
    }
    return true;
}
//---------------------------------------------------------------------------

/////////////////////////////////////////////////////////
REGISTER_HANDLER(e_rpkt_VMS_ID_RES)
{
	st_vms_id_res res;
	if (false == ASession->ParsePacket(res, APktLen))
	{
        TERROR("%s.%d, VMS_ID_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, VMS_ID_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
		return -1;
	}
    //ASession->InfoPacket(res.OpCode, APktLen, false, 0);

    TDEBUG("VMS_ID_RES: %d bytes, Length:%d, Ack:%02X", APktLen, res.Length, res.Ack);

    AnsiString sVmsId;
    sVmsId.printf("%10.10s", res.vmsid);

    if (ASession->State == eSS_LoginReq)
    {
        TCDSCtlr *pCDSCtlr = FindControllerById(sVmsId);
        if (!pCDSCtlr)
        {
            MERROR("+CLI Unknown client id: %s,%s. will be closed.", ASession->IpAddress.c_str(), sVmsId.c_str());
            ASession->Disconnect();
            return -1;
        }

        if (g_AppCfg.IsIpChecking)
        {
            if (ASession->IpAddress != pCDSCtlr->CTLR_IP)
            {
                MERROR("+CLI Controller IP Address Miss Match: %s,%s. (%s). will be closed.", ASession->IpAddress.c_str(), pCDSCtlr->CTLR_IP.c_str(), sVmsId.c_str());
                ASession->Disconnect();
                return -1;
            }
        }

        //이전 접속정보가 있는지 확인한다.
        if (pCDSCtlr)
        {
            TClientSession *pSession = pCDSCtlr->FSession;
            if (pSession)
            {
                //이전 접속을 종료하고 현재 접속을 새로운 VMS 제어기 통신으로 사용한다.
                MERROR("+CLI Client allready connect: %s. old connection will be closed.", ASession->IpAddress.c_str());
                pSession->Disconnect();
            }
        }

        ASession->State      = eSS_Connected;   //연결요청 수립
        ASession->CDSCtlr    = pCDSCtlr;
        ASession->CDSLogCtlr = pCDSCtlr;
        ASession->CDSCtlr->FSession         = ASession;
        ASession->CDSCtlr->LOGIN_IPADDR     = ASession->IpAddress;      //연결된 IP주소 설정
        ASession->CDSCtlr->Server.commState = comm_open;
        ASession->CDSCtlr->Server.ConnectTm = Now().FormatString("yyyy-MM-dd hh:nn:ss");
        ASession->CtlrId.printf("%10.010d", pCDSCtlr->CTLR_NMBR.ToIntDef(0));
        POST_MSG(MAINHANDLE, WM_TCP_THREAD, WM_TCP_SERVER_STTS, (int)pCDSCtlr);
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        IPC_JOB_MESSAGE *pMsg = g_jobBuff.GetBuff();
        pMsg->Type   = eVmsScenarioDownload;
        pMsg->ObjPtr = (DWORD)ASession;
        g_jobQ.PushBlocking((DWORD)pMsg);
    }
    else
    {
        if (sVmsId != ASession->CtlrId)
        {
            MERROR("+CLI Receive packet Vms Id error: %s, %s. will be closed.", ASession->CtlrId.c_str(), sVmsId.c_str());
            ASession->Disconnect();
            return -2;
        }
    }

    return 0;
}
//---------------------------------------------------------------------------

/////////////////////////////////////////////////////////
REGISTER_HANDLER(e_rpkt_CTRL_RESET_RES)
{
	st_reset_res res;
	if (false == ASession->ParsePacket(res, APktLen))
	{
        TERROR("%s.%d, CTRL_RESET_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, CTRL_RESET_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
		return -1;
	}
    //ASession->InfoPacket(res.OpCode, APktLen, false, 0);

    TDEBUG("CTRL_RESET_RES: %d bytes, Length:%d, Ack:%02X", APktLen, res.Length, res.Ack);

    return 0;
}
//---------------------------------------------------------------------------

/////////////////////////////////////////////////////////
REGISTER_HANDLER(e_rpkt_NOTIFY_STTS)
{
	st_notify_stts res;
	if (false == ASession->ParsePacket(res, APktLen))
	{
        TERROR("%s.%d, NOTIFY_STTS parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, NOTIFY_STTS parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
		return -1;
	}
    if (!ASession->CDSCtlr)
    {
        TERROR("%s.%d, NOTIFY_STTS controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, NOTIFY_STTS controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return -2;
    }
    //ASession->InfoPacket(res.OpCode, APktLen, false, 0);

    st_notify_stts *pData = &res;
    INT_VMS_STATE  *FStts = &ASession->CDSCtlr->RSTATE;

    TDEBUG("NOTIFY_STTS: %d bytes, Length:%d, time: %14.14s, led:%02X, door: %02X, fan:%02X, hetr:%02X, tmpr:%02X, brgh:%02X, comm:%02X",
        APktLen, res.Length, pData->stts.time, pData->stts.led, pData->stts.door, pData->stts.fan, pData->stts.hetr, pData->stts.tmpr, pData->stts.brgh, pData->stts.comm);

    memcpy(FStts->ControllerCurrentTime, pData->stts.time, INT_VMS_MAX_DATETIME);   /* 선택 제어기 시간 (YYYYMMDDHHMMSS) */

    if      (pData->stts.led == 0x00) FStts->ModulePowerStatus = vms_module_power_off;
    else if (pData->stts.led == 0x01) FStts->ModulePowerStatus = vms_module_power_on;
    else                              FStts->ModulePowerStatus = vms_module_power_unknown;

    if      (pData->stts.door == 0x00) FStts->DoorStatus = vms_door_close;
    else if (pData->stts.door == 0x01) FStts->DoorStatus = vms_door_open;
    else                               FStts->DoorStatus = vms_door_unknown;

    if      (pData->stts.fan == 0x00) FStts->FanStatus = vms_fan_off;
    else if (pData->stts.fan == 0x01) FStts->FanStatus = vms_fan_on;
    else                              FStts->FanStatus = vms_fan_unknown;

    if      (pData->stts.hetr == 0x00) FStts->HeaterStatus = vms_heater_off;
    else if (pData->stts.hetr == 0x01) FStts->HeaterStatus = vms_heater_on;
    else                               FStts->HeaterStatus = vms_heater_unknown;

	FStts->BodyTemp          = (short)pData->stts.tmpr;                             /* 함체온도값(℃), 범위(-128~127) */
	FStts->LuminanceStatus   = pData->stts.brgh;                                    /* 화면의 밝기값 (최대 휘도값을 100으로 했을 때의 백분율 값), 범위(0~100) */
	FStts->Wcomm             = pData->stts.comm == 0x00 ? vms_comm_normal : vms_comm_error;   /* 무선통신상태, 0:정상 1:장애 */

    //
    // 응답
    st_notify_stts_ack ack;
    memcpy(ack.vmsid, res.vmsid, MAX_VMS_ID);
    if (!ASession->SendRequest((char*)&ack, sizeof(ack)))
    {
        ASession->Disconnect();
        TERROR("%s.%d, Client ack response send faild. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, Client ack response send faild. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return false;
    }

    POST_MSG(MAINHANDLE, WM_TCP_THREAD, WM_CTLR_STATE_STTS, (int)ASession->CDSCtlr);
    return 0;
}
//---------------------------------------------------------------------------

/////////////////////////////////////////////////////////
REGISTER_HANDLER(e_rpkt_DNLD_SCENARIO_RES)
{
	st_dnld_scenario_res res;
	if (false == ASession->ParsePacket(res, APktLen))
	{
        TERROR("%s.%d, DNLD_SCENARIO_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, DNLD_SCENARIO_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
		return -1;
	}

    if (!ASession->CDSCtlr)
    {
        TERROR("%s.%d, DNLD_SCENARIO_RES controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, DNLD_SCENARIO_RES controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return -2;
    }
    //ASession->InfoPacket(res.OpCode, APktLen, false, 0);

    TDEBUG("DNLD_SCENARIO_RES: %d bytes, Length:%d, Ack:%02X", APktLen, res.Length, res.Ack);

    if (res.Ack != ACK_NORMAL)
    {
        ASession->Disconnect();
        TERROR("%s.%d, DNLD_SCENARIO_RES failed. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, DNLD_SCENARIO_RES failed. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return -3;
    }

    TCDSCtlr *AObj = ASession->CDSCtlr;
    if (AObj)
    {
        if (AObj->CTRLMODE->Schedule)
        {
            VMS_PROVIDE_RESULE ProvideSave;

            memset(&ProvideSave,  0x00, sizeof(ProvideSave));

            ProvideSave.Type    = provide_form;
            ProvideSave.Count   = 1;
            ProvideSave.pObj[0] = (void*)AObj;

            AObj->CTRLMODE->Enable   = object_disable;
            AObj->CTRLMODE->SvcDate  = Now().FormatString("yyyymmddhhnnss");
            AObj->CTRLMODE->SaveFlag = true;
            AObj->CTRLMODE->Result   = true;

            APP_PostDbThreadMessage(dbm_provide_result, sizeof(ProvideSave), &ProvideSave);
        }
    }
    return 0;
}
//---------------------------------------------------------------------------

/////////////////////////////////////////////////////////
REGISTER_HANDLER(e_rpkt_DNLD_FILE_RES)
{
	st_dnld_file_res res;
	if (false == ASession->ParsePacket(res, APktLen))
	{
        TERROR("%s.%d, DNLD_FILE_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, DNLD_FILE_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
		return -1;
	}
    if (!ASession->CDSCtlr)
    {
        TERROR("%s.%d, DNLD_FILE_RES controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, DNLD_FILE_RES controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return -2;
    }
    //ASession->InfoPacket(res.OpCode, APktLen, false, 0);

    TDEBUG("DNLD_FILE_RES: %d bytes, Length:%d, Ack:%02X", APktLen, res.Length, res.Ack);

    if (res.Ack != ACK_NORMAL)
    {
        ASession->Disconnect();
        TERROR("%s.%d, DNLD_FILE_RES failed. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, DNLD_FILE_RES failed. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return -3;
    }

    return 0;
}
//---------------------------------------------------------------------------

/////////////////////////////////////////////////////////
REGISTER_HANDLER(e_rpkt_PARAMETER_RES)
{
	st_parameter_res res;
	if (false == ASession->ParsePacket(res, APktLen))
	{
        TERROR("%s.%d, PARAMETER_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, PARAMETER_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
		return -1;
	}
    if (!ASession->CDSCtlr)
    {
        TERROR("%s.%d, PARAMETER_RES controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, PARAMETER_RES controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return -2;
    }
    //ASession->InfoPacket(res.OpCode, APktLen, false, 0);

    TDEBUG("PARAMETER_RES: %d bytes, Length:%d, Ack:%02X, led:%02X, fan:%02X, fanTmpr:%02X, hetr:%02X, hetrTmpr:%02X, brgh:%02X, brghVal:%02X, brghDay:%02X, brghNight:%02X, time:%14.14s",
        APktLen, res.Length, res.Ack, res.para.led, res.para.fan, res.para.fanTmpr, res.para.hetr, res.para.hetrTmpr, res.para.brgh, res.para.brghVal, res.para.brghDay, res.para.brghNight, res.para.time);

    //파라미터 요청 응답
    if (res.Ack != ACK_NORMAL)
    {
        ASession->Disconnect();
        TERROR("%s.%d, PARAMETER_RES failed. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, PARAMETER_RES failed. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return -3;
    }

    TCDSCtlr *AObj = ASession->CDSCtlr;
    if (AObj)
    {
        AObj->PANL_PWER_MODE = res.para.led;     //	N	NUMBER(3)	Y	2		전광판 전원 모드(0x00:꺼짐,0x01:켜짐,0x02:자동,0x09:알수없음)
        AObj->FAN_MODE       = res.para.fan;           //	N	NUMBER(3)	Y	2		FAN 동작모드(0x00:꺼짐,0x01:켜짐,0x02:자동,0x09:알수없음)
        AObj->FAN_RUN_TMPR   = res.para.fanTmpr;       //	N	NUMBER(3)	Y	30		팬 동작 온도
        AObj->HETR_MODE      = res.para.hetr;          //	N	NUMBER(3)	Y	2		히터 동작모드(0x00:꺼짐,0x01:켜짐,0x02:자동,0x09:알수없음)
        AObj->HETR_RUN_TMPR  = res.para.hetrTmpr;      //	N	NUMBER(3)	Y	0		히터 동작 온도
        AObj->BRGH_MODE      = res.para.brgh;          //	N	NUMBER(3)	Y	2		휘도 모드(0x00:주간,0x01:야간,0x00:자동,0x09:알수없음)
        AObj->BRGH_CURR_STEP = res.para.brghVal;     //	N	NUMBER(3)	Y	40		휘도 현재 단계(0~100)
        AObj->BRGH_WEEK_STEP = res.para.brghDay;     //	N	NUMBER(3)	Y	64		휘도 주간 단계(0~100)
        AObj->BRGH_NGHT_STEP = res.para.brghNight;     //	N	NUMBER(3)	Y	48		휘도 야간 단계(0~100)
        AObj->ParamResTime.printf("%s", res.para.time);

        CTLR_STTS stts;
        stts.Type = 2;
        stts.ObjPtr = (void*)AObj;

        APP_PostDbThreadMessage(dbm_parma_res, sizeof(stts), &stts);
    }
    return 0;
}
//---------------------------------------------------------------------------

/////////////////////////////////////////////////////////
REGISTER_HANDLER(e_rpkt_CTRL_LED_POWER_RES)
{
	st_ctrl_led_power_res res;
	if (false == ASession->ParsePacket(res, APktLen))
	{
        TERROR("%s.%d, CTRL_LED_POWER_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, CTRL_LED_POWER_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
		return -1;
	}
    if (!ASession->CDSCtlr)
    {
        TERROR("%s.%d, CTRL_LED_POWER_RES controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, CTRL_LED_POWER_RES controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return -2;
    }
    //ASession->InfoPacket(res.OpCode, APktLen, false, 0);

    TDEBUG("CTRL_LED_POWER_RES: %d bytes, Length:%d, Ack:%02X", APktLen, res.Length, res.Ack);

    if (res.Ack != ACK_NORMAL)
    {
        ASession->Disconnect();
        TERROR("%s.%d, CTRL_LED_POWER_RES failed. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, CTRL_LED_POWER_RES failed. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return -3;
    }

    return 0;
}
//---------------------------------------------------------------------------

/////////////////////////////////////////////////////////
REGISTER_HANDLER(e_rpkt_CTRL_FAN_POWER_RES)
{
	st_ctrl_fan_power_res res;
	if (false == ASession->ParsePacket(res, APktLen))
	{
        TERROR("%s.%d, CTRL_FAN_POWER_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, CTRL_FAN_POWER_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
		return -1;
	}
    if (!ASession->CDSCtlr)
    {
        TERROR("%s.%d, CTRL_FAN_POWER_RES controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, CTRL_FAN_POWER_RES controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return -2;
    }
    //ASession->InfoPacket(res.OpCode, APktLen, false, 0);

    TDEBUG("CTRL_FAN_POWER_RES: %d bytes, Length:%d, Ack:%02X", APktLen, res.Length, res.Ack);

    if (res.Ack != ACK_NORMAL)
    {
        ASession->Disconnect();
        TERROR("%s.%d, CTRL_FAN_POWER_RES failed. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, CTRL_FAN_POWER_RES failed. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return -3;
    }

    return 0;
}
//---------------------------------------------------------------------------

/////////////////////////////////////////////////////////
REGISTER_HANDLER(e_rpkt_CTRL_BRGH_RES)
{
	st_ctrl_brgh_res res;
	if (false == ASession->ParsePacket(res, APktLen))
	{
        TERROR("%s.%d, CTRL_BRGH_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, CTRL_BRGH_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
		return -1;
	}
    if (!ASession->CDSCtlr)
    {
        TERROR("%s.%d, CTRL_BRGH_RES controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, CTRL_BRGH_RES controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return -2;
    }
    //ASession->InfoPacket(res.OpCode, APktLen, false, 0);

    TDEBUG("CTRL_BRGH_RES: %d bytes, Length:%d, Ack:%02X", APktLen, res.Length, res.Ack);

    if (res.Ack != ACK_NORMAL)
    {
        ASession->Disconnect();
        TERROR("%s.%d, CTRL_BRGH_RES failed. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, CTRL_BRGH_RES failed. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return -3;
    }

    return 0;
}
//---------------------------------------------------------------------------

/////////////////////////////////////////////////////////
REGISTER_HANDLER(e_rpkt_CTRL_CONFIG_RES)
{
	st_ctrl_cfg_res res;
	if (false == ASession->ParsePacket(res, APktLen))
	{
        TERROR("%s.%d, CTRL_CONFIG_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, CTRL_CONFIG_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
		return -1;
	}
    if (!ASession->CDSCtlr)
    {
        TERROR("%s.%d, CTRL_CONFIG_RES controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, CTRL_CONFIG_RES controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return -2;
    }
    //ASession->InfoPacket(res.OpCode, APktLen, false, 0);

    TDEBUG("CTRL_CONFIG_RES: %d bytes, Length:%d, Ack:%02X", APktLen, res.Length, res.Ack);

    if (res.Ack != ACK_NORMAL)
    {
        ASession->Disconnect();
        TERROR("%s.%d, CTRL_CONFIG_RES failed. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, CTRL_CONFIG_RES failed. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return -3;
    }

    return 0;
}
//---------------------------------------------------------------------------

/////////////////////////////////////////////////////////
REGISTER_HANDLER(e_rpkt_CTRL_TIME_RES)
{
	st_ctrl_time_res res;
	if (false == ASession->ParsePacket(res, APktLen))
	{
        TERROR("%s.%d, CTRL_TIME_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, CTRL_TIME_RES parsePacket error. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
		return -1;
	}
    if (!ASession->CDSCtlr)
    {
        TERROR("%s.%d, CTRL_TIME_RES controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, CTRL_TIME_RES controller not found. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return -2;
    }
    //ASession->InfoPacket(res.OpCode, APktLen, false, 0);

    TDEBUG("CTRL_TIME_RES: %d bytes, Length:%d, Ack:%02X", APktLen, res.Length, res.Ack);

    if (res.Ack != ACK_NORMAL)
    {
        ASession->Disconnect();
        TERROR("%s.%d, CTRL_TIME_RES failed. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        MERROR("%s.%d, CTRL_TIME_RES failed. will be closed.", ASession->IpAddress.c_str(), ASession->Socket);
        return -3;
    }

    return 0;
}
//---------------------------------------------------------------------------

int TClientSession::DownloadScenarioForm(bool ASchedule/*=true*/)
{
    int       nSelCnt = 0;
    TCDSCtlr *AObj = FCDSCtlr;
    if (!AObj) return -1;

    int nFormCnt = AObj->pForms->Count();
    if (nFormCnt == 0) return nSelCnt;
    if (nFormCnt > INT_VMS_MAX_FORM) nFormCnt = INT_VMS_MAX_FORM;

    AnsiString sDispStrTm = Now().FormatString("yyyymmddhhnn");
    AnsiString sDispEndTm = (IncMinute(Now(), 10)).FormatString("yyyymmddhhnn");
    if (AObj->CTRLMODE->Control == 'B')
    {
        //디폴트 시나리오인 경우...
        sDispEndTm = "20991231235959";
    }

    st_dnld_scenario_req  req;
    st_scenario          *pScn;
    memset((char*)&req, 0x00, sizeof(st_dnld_scenario_req));

    req.Stx    = VMS_STX;
    req.OpCode = (BYTE)DNLD_SCENARIO_REQ;
    memcpy(req.vmsid, FCtlrId.c_str(), sizeof(req.vmsid));
    req.Length = 0; // count senario//
    //scenario info
    //ETX

    AObj->pForms->Lock();
	try
	{
        for (int ii = 0; ii < nFormCnt; ii++)
        {
            TVmsForm *pForm = AObj->pForms->GetItem(ii);
            if (!pForm->Success) continue;

            pScn = &req.scenario[nSelCnt++];

            pScn->seq        = (BYTE)nSelCnt;                                                   // 시나리오 순번
            pScn->type       = pForm->fileType;                                                 // 표출타입
            if (pForm->fileType == P_FILE_TYPE_VIDEO  ||
                pForm->fileType == P_FILE_TYPE_STREAM)
            {
                pScn->dispEffect = 0x00;                                                            // 표출효과
            }
            else
            {
                pScn->dispEffect = (BYTE)pForm->VMS_FORM_DSPL_MTHD_CD.ToIntDef(0);
            }
            sprintf(pScn->fileName, "%s", pForm->FtpFileName.c_str());                          // 파일명

            pScn->dispTm = (pForm->fileType == P_FILE_TYPE_VIDEO) ? 0 : (BYTE)pForm->DSPL_HH;   // 표출문구 표출시각('03' : 3초)
            memcpy(pScn->dispStrTm, sDispStrTm.c_str(), MAX_DISP_TIME);                         // 표출시작시간(0000 00 00 0000)
            memcpy(pScn->dispEndTm, sDispEndTm.c_str(), MAX_DISP_TIME);                         // 표출종료시각(999912312359)
            pScn->dnldFlag = 'D';                                                               // 파일다운로드 여부 D : 다운로드

            if (nSelCnt >= MAX_SCENARIO) break;
        }
	}
	__finally
	{
        AObj->pForms->UnLock();
	}

    if (nSelCnt == 0) return 0;

    AObj->CTRLMODE->Schedule = ASchedule;   // 스케쥴 모드인 경우 디비에 저장한다.

    req.type   = (AObj->CTRLMODE->Control == 'B') ? 0x00 : 0x01;
    req.cnt    = (BYTE)nSelCnt;     // 해당 VMS의 전체시나리오 수
    req.Length = (short)((nSelCnt * sizeof(st_scenario))+2);
    req.scenario[nSelCnt].seq = VMS_ETX;    //시나리오 구조체의 첫번째가 ETX 자리임

    int nSendBytes = sizeof(st_head) + req.Length + 1;
    if (!SendRequest((char*)&req, nSendBytes))
    {
        SERROR("+CLI DownloadScenarioForm send request faild: %s will be closed.", FIpAddress.c_str());
        MERROR("+CLI DownloadScenarioForm send request faild: %s will be closed.", FIpAddress.c_str());
        Disconnect();
        return -1;
    }

    return nSelCnt;
}
//---------------------------------------------------------------------------

int TClientSession::ReqParameter()
{
    TCDSCtlr *AObj = FCDSCtlr;
    if (!AObj) return -1;

    st_parameter_req  req;
    memcpy(req.vmsid, FCtlrId.c_str(), sizeof(req.vmsid));
    req.OpCode = (BYTE)PARAMETER_REQ;

    if (!SendRequest((char*)&req, sizeof(req)))
    {
        SERROR("+CLI ReqParameter send request faild: %s will be closed.", FIpAddress.c_str());
        MERROR("+CLI ReqParameter send request faild: %s will be closed.", FIpAddress.c_str());
        Disconnect();
        return -1;
    }

    return 1;
}
//---------------------------------------------------------------------------

int TClientSession::ReqLedPowerControl(BYTE AOnOff)
{
    TCDSCtlr *AObj = FCDSCtlr;
    if (!AObj) return -1;

    st_ctrl_led_power_req  req;
    memcpy(req.vmsid, FCtlrId.c_str(), sizeof(req.vmsid));
    req.cmd = AOnOff;

    if (!SendRequest((char*)&req, sizeof(req)))
    {
        SERROR("+CLI ReqLedPowerControl send request faild: %s will be closed.", FIpAddress.c_str());
        MERROR("+CLI ReqLedPowerControl send request faild: %s will be closed.", FIpAddress.c_str());
        Disconnect();
        return -1;
    }

    return 1;
}
//---------------------------------------------------------------------------

int TClientSession::ReqFanPowerControl(BYTE AOnOff)
{
    TCDSCtlr *AObj = FCDSCtlr;
    if (!AObj) return -1;

    st_ctrl_fan_power_req  req;
    memcpy(req.vmsid, FCtlrId.c_str(), sizeof(req.vmsid));
    req.cmd = AOnOff;

    if (!SendRequest((char*)&req, sizeof(req)))
    {
        SERROR("+CLI ReqFanPowerControl send request faild: %s will be closed.", FIpAddress.c_str());
        MERROR("+CLI ReqFanPowerControl send request faild: %s will be closed.", FIpAddress.c_str());
        Disconnect();
        return -1;
    }

    return 1;
}
//---------------------------------------------------------------------------

int TClientSession::ReqTimeControl(char *ATime)
{
    TCDSCtlr *AObj = FCDSCtlr;
    if (!AObj) return -1;

    st_ctrl_time_req  req;
    memcpy(req.vmsid, FCtlrId.c_str(), sizeof(req.vmsid));
    //memcpy(req.set.time, ATime, MAX_SYS_TIME);
    memcpy(req.set.time, AnsiString(Now().FormatString("yyyymmddhhnnss")).c_str(), MAX_SYS_TIME);

    if (!SendRequest((char*)&req, sizeof(req)))
    {
        SERROR("+CLI ReqTimeControl send request faild: %s will be closed.", FIpAddress.c_str());
        MERROR("+CLI ReqTimeControl send request faild: %s will be closed.", FIpAddress.c_str());
        Disconnect();
        return -1;
    }

    return 1;
}
//---------------------------------------------------------------------------

int TClientSession::ReqBrightSet(char *ACmd)
{
    TCDSCtlr *AObj = FCDSCtlr;
    if (!AObj) return -1;

    SIGNT_BRGH_SET *pCmd = (SIGNT_BRGH_SET*)ACmd;
    st_ctrl_brgh_req   req;
    memcpy(req.vmsid, FCtlrId.c_str(), sizeof(req.vmsid));
    req.set.brgh      = pCmd->BrghMode;
    req.set.brghVal   = pCmd->BrghCurrStep;
    req.set.brghDay   = pCmd->BrghWeekStep;
    req.set.brghNight = pCmd->BrghNghtStep;

    if (!SendRequest((char*)&req, sizeof(req)))
    {
        SERROR("+CLI ReqBrightSet send request faild: %s will be closed.", FIpAddress.c_str());
        MERROR("+CLI ReqBrightSet send request faild: %s will be closed.", FIpAddress.c_str());
        Disconnect();
        return -1;
    }

    return 1;
}
//---------------------------------------------------------------------------

int TClientSession::ReqConfigSet(char *ACmd)
{
    TCDSCtlr *AObj = FCDSCtlr;
    if (!AObj) return -1;

    SIGNT_CONFIG_SET *pCmd = (SIGNT_CONFIG_SET*)ACmd;
    st_ctrl_cfg_req   req;
    memcpy(req.vmsid, FCtlrId.c_str(), sizeof(req.vmsid));
    req.set.fanTmpr  = pCmd->FanRunTmpr;
    req.set.hetrTmpr = pCmd->HetrRunTmpr;
    memcpy(req.set.dispOnTm,  pCmd->PanlOnTime,  sizeof(req.set.dispOnTm));
    memcpy(req.set.dispOffTm, pCmd->PanlOffTime, sizeof(req.set.dispOffTm));

    if (!SendRequest((char*)&req, sizeof(req)))
    {
        SERROR("+CLI ReqConfigSet send request faild: %s will be closed.", FIpAddress.c_str());
        MERROR("+CLI ReqConfigSet send request faild: %s will be closed.", FIpAddress.c_str());
        Disconnect();
        return -1;
    }

    return 1;
}
//---------------------------------------------------------------------------

int TClientSession::ReqReset(int AMode)
{
    TCDSCtlr *AObj = FCDSCtlr;
    if (!AObj) return -1;

    st_reset_req  req;
    memcpy(req.vmsid, FCtlrId.c_str(), sizeof(req.vmsid));
    req.OpCode = (BYTE)CTRL_RESET_REQ;
    req.type   = (BYTE)AMode;  //제어기 리셋

    if (!SendRequest((char*)&req, sizeof(req)))
    {
        SERROR("+CLI ReqReset send request faild: %s will be closed.", FIpAddress.c_str());
        MERROR("+CLI ReqReset send request faild: %s will be closed.", FIpAddress.c_str());
        Disconnect();
        return -1;
    }

    return 1;
}
//---------------------------------------------------------------------------


