- Naming style migrated to camel-case - P7lib logger sources added - Vcpkg manifest, CMake presets and build moved to root - SDL2, Vulkan and RmlUi dependencies added - Logger LOG macro added - Logger configuration - SDL2 window configuration - Vulkan configuration - RmlUi configuration - SDL event loop
1951 lines
61 KiB
C++
1951 lines
61 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
// /
|
|
// 2012-2020 (c) Baical /
|
|
// /
|
|
// This library is free software; you can redistribute it and/or /
|
|
// modify it under the terms of the GNU Lesser General Public /
|
|
// License as published by the Free Software Foundation; either /
|
|
// version 3.0 of the License, or (at your option) any later version. /
|
|
// /
|
|
// This library is distributed in the hope that it will be useful, /
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU /
|
|
// Lesser General Public License for more details. /
|
|
// /
|
|
// You should have received a copy of the GNU Lesser General Public /
|
|
// License along with this library. /
|
|
// /
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// This header file provide functionality to deliver data to baical server /
|
|
// over UDP /
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "CommonClient.h"
|
|
#include "ClBaical.h"
|
|
|
|
|
|
#define COMMUNICATION_THREAD_IDLE_TIMEOUT (5)
|
|
#define COMMUNICATION_THREAD_EXIT_TIMEOUT (5000)
|
|
#define COMMUNICATION_RESPONSE_TIMEOUT (100)
|
|
#define COMMUNICATION_DATA_SEGMENT_MAX_DURATION (750)
|
|
#define COMMUNICATION_IDLE_TIMEOUT (1000)
|
|
#define COMMUNICATION_LOSSES_MAX (60) //percents
|
|
|
|
#define COMMUNICATION_MAX_DELIVERY_FAILS (10)
|
|
#define SOCKET_RECEIVE_RESPONSE_TIMEOUT (10)
|
|
|
|
#define CONNECTION_SIGNAL (MEVENT_SIGNAL_0)
|
|
|
|
#define THREAD_EXIT_SIGNAL (MEVENT_SIGNAL_0)
|
|
#define THREAD_DATA_SIGNAL (MEVENT_SIGNAL_0 + 1)
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//CClBaical
|
|
CClBaical::CClBaical(tXCHAR **i_pArgs, tINT32 i_iCount)
|
|
: CClient(IP7_Client::eBaical, i_pArgs, i_iCount)
|
|
, m_lReject_Mem(0)
|
|
, m_lReject_Con(0)
|
|
, m_lReject_Int(0)
|
|
|
|
, m_bIs_Winsock(FALSE)
|
|
, m_pSocket(NULL)
|
|
, m_wClient_ID(0xFFFF)
|
|
, m_pBPool(NULL)
|
|
|
|
, m_pData_Wnd(NULL)
|
|
, m_pData_Wnd_Cell(NULL)
|
|
, m_bData_Wnd_Fixed(FALSE)
|
|
, m_dwData_Wnd_Max_Count(0)
|
|
, m_dwData_Wnd_Size(0)
|
|
, m_dwData_Wnd_TimeStamp(0)
|
|
, m_dwData_Wnd_First_ID(TPACKET_MAX_ID + 1)
|
|
, m_dwData_Wnd_Last_ID(TPACKET_MAX_ID + 1)
|
|
, m_bData_Resending(FALSE)
|
|
|
|
, m_dwDelivery_Fails(0)
|
|
, m_bIs_Response_Waiting(FALSE)
|
|
|
|
, m_pData_Queue_Out(NULL)
|
|
, m_pData_Queue_In(NULL)
|
|
|
|
, m_dwLast_Packet_ID(0)
|
|
, m_dwServiceTimeStamp(0)
|
|
|
|
, m_dwExit_TimeOut(COMMUNICATION_THREAD_EXIT_TIMEOUT)
|
|
|
|
, m_pPacket_Control(NULL)
|
|
, m_bBig_Endian(FALSE)
|
|
|
|
, m_bConn_Event(TRUE)
|
|
, m_bComm_Thread(FALSE)
|
|
, m_hComm_Thread(0) //NULL
|
|
, m_bChnl_Thread(FALSE)
|
|
, m_hChnl_Thread(0) //NULL
|
|
|
|
, m_bLocalHost(FALSE)
|
|
, m_bExtension(FALSE)
|
|
|
|
, m_pHdrUsrData(NULL)
|
|
, m_pHdrUsrPacket(NULL)
|
|
, m_uHdrUsrSize(0)
|
|
, m_uHdrUsrChannel(USER_PACKET_CHANNEL_ID_MAX_SIZE)
|
|
{
|
|
memset(&m_hCS_Data_Out, 0, sizeof(m_hCS_Data_Out));
|
|
memset(&m_hCS_Data_In, 0, sizeof(m_hCS_Data_In));
|
|
|
|
//1. base init
|
|
if (ECLIENT_STATUS_OK == m_eStatus)
|
|
{
|
|
m_eStatus = Init_Base(i_pArgs, i_iCount);
|
|
}
|
|
|
|
//2. initialize network layer and sockets
|
|
if (ECLIENT_STATUS_OK == m_eStatus)
|
|
{
|
|
m_eStatus = Init_Sockets(i_pArgs, i_iCount);
|
|
}
|
|
|
|
//3. Initialize Pool
|
|
if (ECLIENT_STATUS_OK == m_eStatus)
|
|
{
|
|
m_eStatus = Init_Pool(i_pArgs, i_iCount);
|
|
}
|
|
|
|
//4. Initialize variables
|
|
if (ECLIENT_STATUS_OK == m_eStatus)
|
|
{
|
|
m_eStatus = Init_Members(i_pArgs, i_iCount);
|
|
}
|
|
|
|
//5. Initialize crash handler
|
|
if (ECLIENT_STATUS_OK == m_eStatus)
|
|
{
|
|
Init_Crash_Handler(i_pArgs, i_iCount);
|
|
}
|
|
|
|
}//CClBaical
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//~CClBaical
|
|
CClBaical::~CClBaical()
|
|
{
|
|
Uninit_Crash_Handler();
|
|
|
|
Close();
|
|
|
|
CClient::Unshare();
|
|
|
|
if (m_pData_Queue_Out)
|
|
{
|
|
pAList_Cell l_pElement = NULL;
|
|
|
|
while ((l_pElement = m_pData_Queue_Out->Get_First()))
|
|
{
|
|
CTPacket *l_pPacket = m_pData_Queue_Out->Get_Data(l_pElement);
|
|
m_pData_Queue_Out->Del(l_pElement, FALSE);
|
|
m_pBPool->Push_Buffer(l_pPacket);
|
|
}
|
|
|
|
m_pData_Queue_Out->Clear(TRUE);
|
|
delete m_pData_Queue_Out;
|
|
m_pData_Queue_Out = NULL;
|
|
}
|
|
|
|
|
|
if (m_pData_Queue_In)
|
|
{
|
|
pAList_Cell l_pElement = NULL;
|
|
|
|
while ((l_pElement = m_pData_Queue_In->Get_First()))
|
|
{
|
|
CTPacket *l_pPacket = m_pData_Queue_In->Get_Data(l_pElement);
|
|
m_pData_Queue_In->Del(l_pElement, FALSE);
|
|
m_pBPool->Push_Buffer(l_pPacket);
|
|
}
|
|
|
|
m_pData_Queue_In->Clear(TRUE);
|
|
delete m_pData_Queue_In;
|
|
m_pData_Queue_In = NULL;
|
|
}
|
|
|
|
|
|
if (m_pData_Wnd)
|
|
{
|
|
pAList_Cell l_pElement = NULL;
|
|
|
|
while ((l_pElement = m_pData_Wnd->Get_First()))
|
|
{
|
|
CTPacket *l_pPacket = m_pData_Wnd->Get_Data(l_pElement);
|
|
m_pData_Wnd->Del(l_pElement, FALSE);
|
|
m_pBPool->Push_Buffer(l_pPacket);
|
|
}
|
|
|
|
m_pData_Wnd->Clear(TRUE);
|
|
delete m_pData_Wnd;
|
|
m_pData_Wnd = NULL;
|
|
}
|
|
|
|
//stop sockets
|
|
if (m_bIs_Winsock)
|
|
{
|
|
WSA_UnInit();
|
|
}
|
|
|
|
if (m_pSocket)
|
|
{
|
|
delete m_pSocket;
|
|
m_pSocket = NULL;
|
|
}
|
|
|
|
//clear pool
|
|
if (m_pBPool)
|
|
{
|
|
delete m_pBPool;
|
|
m_pBPool = NULL;
|
|
}
|
|
|
|
LOCK_DESTROY(m_hCS_Data_Out);
|
|
LOCK_DESTROY(m_hCS_Data_In);
|
|
} //~CClBaical
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Init_Base
|
|
eClient_Status CClBaical::Init_Base(tXCHAR **i_pArgs,
|
|
tINT32 i_iCount
|
|
)
|
|
{
|
|
eClient_Status l_eReturn = ECLIENT_STATUS_OK;
|
|
UNUSED_ARG(i_pArgs);
|
|
UNUSED_ARG(i_iCount);
|
|
|
|
return l_eReturn;
|
|
}//Init_Base
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Init_Sockets
|
|
eClient_Status CClBaical::Init_Sockets(tXCHAR **i_pArgs,
|
|
tINT32 i_iCount
|
|
)
|
|
{
|
|
eClient_Status l_eReturn = ECLIENT_STATUS_OK;
|
|
|
|
if (FALSE == WSA_Init())
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_Network);
|
|
|
|
JOURNAL_CRITICAL(m_pLog,
|
|
TM("Socket initialization fail !"));
|
|
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
}
|
|
else
|
|
{
|
|
m_bIs_Winsock = TRUE;
|
|
}
|
|
|
|
if (ECLIENT_STATUS_OK == l_eReturn)
|
|
{
|
|
tXCHAR *l_pAddr = NULL;
|
|
tXCHAR *l_pPort = NULL;
|
|
|
|
tADDR_INFO *l_pInfo = NULL;
|
|
tADDR_INFO *l_pNext = NULL;
|
|
tADDR_INFO l_tHint;
|
|
|
|
memset(&l_tHint, 0, sizeof(l_tHint));
|
|
|
|
l_pAddr = Get_Argument_Text_Value(i_pArgs, i_iCount,
|
|
(tXCHAR*)CLIENT_COMMAND_LINE_BAICAL_ADDRESS);
|
|
if (NULL == l_pAddr)
|
|
{
|
|
l_pAddr = (tXCHAR*)TM("127.0.0.1");
|
|
}
|
|
|
|
l_pPort = Get_Argument_Text_Value(i_pArgs, i_iCount,
|
|
(tXCHAR*)CLIENT_COMMAND_LINE_BAICAL_PORT);
|
|
|
|
if (NULL == l_pPort)
|
|
{
|
|
l_pPort = (tXCHAR*)TM("9009");
|
|
}
|
|
|
|
|
|
if ( (0 == PStrICmp(l_pAddr, TM("127.0.0.1")))
|
|
|| (0 == PStrICmp(l_pAddr, TM("::1")))
|
|
)
|
|
{
|
|
m_bLocalHost = TRUE;
|
|
}
|
|
|
|
l_tHint.ai_family = AF_UNSPEC; //AF_INET;
|
|
l_tHint.ai_socktype = SOCK_DGRAM;
|
|
l_tHint.ai_protocol = IPPROTO_UDP;
|
|
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
|
|
//http://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx
|
|
//http://linux.die.net/man/3/getaddrinfo
|
|
if (0 == GET_ADDR_INFO(l_pAddr, l_pPort, &l_tHint, &l_pInfo))
|
|
{
|
|
for(l_pNext = l_pInfo; l_pNext != NULL ;l_pNext=l_pNext->ai_next)
|
|
{
|
|
if ( ( (AF_INET == l_pNext->ai_family)
|
|
|| (AF_INET6 == l_pNext->ai_family)
|
|
)
|
|
&& (SOCK_DGRAM == l_pNext->ai_socktype)
|
|
&& (IPPROTO_UDP == l_pNext->ai_protocol)
|
|
)
|
|
{
|
|
m_pSocket = new CUDP_Socket(m_pLog,
|
|
(sockaddr*) l_pNext->ai_addr,
|
|
FALSE);
|
|
if (m_pSocket)
|
|
{
|
|
if (m_pSocket->Initialized())
|
|
{
|
|
l_eReturn = ECLIENT_STATUS_OK;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
delete m_pSocket;
|
|
m_pSocket = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} //if (0 == GetAddrInfoW
|
|
|
|
if (l_pInfo)
|
|
{
|
|
FREE_ADDR_INFO(l_pInfo);
|
|
l_pInfo = NULL;
|
|
}
|
|
|
|
if (ECLIENT_STATUS_OK != l_eReturn)
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_Network);
|
|
}
|
|
}//if (ECLIENT_STATUS_OK == l_eReturn)
|
|
|
|
return l_eReturn;
|
|
}//Init_Sockets
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Init_Pool
|
|
eClient_Status CClBaical::Init_Pool(tXCHAR **i_pArgs,
|
|
tINT32 i_iCount
|
|
)
|
|
{
|
|
tXCHAR *l_pArg_Value = NULL;
|
|
tUINT32 l_dwMax_Memory = 0x100000; //1mb by default
|
|
tUINT32 l_dwPacket_Size = TPACKET_DEF_SIZE;
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//packet size
|
|
l_pArg_Value = Get_Argument_Text_Value(i_pArgs, i_iCount,
|
|
(tXCHAR*)CLIENT_COMMAND_PACKET_BAICAL_SIZE);
|
|
if (l_pArg_Value)
|
|
{
|
|
l_dwPacket_Size = (tUINT32)PStrToInt(l_pArg_Value);
|
|
|
|
if (TPACKET_MIN_SIZE > l_dwPacket_Size)
|
|
{
|
|
l_dwPacket_Size = TPACKET_MIN_SIZE;
|
|
}
|
|
else if (TPACKET_MAX_SIZE < l_dwPacket_Size)
|
|
{
|
|
l_dwPacket_Size = TPACKET_MAX_SIZE;
|
|
}
|
|
}
|
|
|
|
if (m_bLocalHost)
|
|
{
|
|
l_dwPacket_Size = TPACKET_MAX_SIZE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//pool size
|
|
l_pArg_Value = Get_Argument_Text_Value(i_pArgs, i_iCount,
|
|
(tXCHAR*)CLIENT_COMMAND_POOL_SIZE);
|
|
if (l_pArg_Value)
|
|
{
|
|
l_dwMax_Memory = 1024 * (tUINT32)PStrToInt(l_pArg_Value);
|
|
|
|
if (16384 > l_dwMax_Memory)
|
|
{
|
|
l_dwMax_Memory = 16384;
|
|
}
|
|
}
|
|
|
|
//check that memory is enough to store 20 packets
|
|
if (l_dwMax_Memory < (l_dwPacket_Size * 20))
|
|
{
|
|
l_dwMax_Memory = l_dwPacket_Size * 20;
|
|
|
|
JOURNAL_WARNING(m_pLog,
|
|
TM("Pool size is not enought to store 20 packets, enlarge up to %d"),
|
|
l_dwMax_Memory
|
|
);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//window size
|
|
|
|
//size of the transmission window in packets. Sometimes is useful to manage it
|
|
//if server aggressively loose incoming packets
|
|
//Min = 1
|
|
//max = ((pool size / packet size) / 2)
|
|
|
|
//here is possible maximal window length
|
|
tUINT32 l_uWnd_Max_Total = (SERVER_REPORT_SIZE - SERVER_REPORT_HEADER_SIZE) * 8;
|
|
//if window size is more than half of all memory we resize the window length
|
|
tUINT32 l_uWnd_Max_Mem = (l_dwMax_Memory / l_dwPacket_Size) / 2;
|
|
//if window size is more than socket buffer size, truncate to it
|
|
tUINT32 l_uWnd_Max_Net = (m_pSocket->GetSendBufferSize() / l_dwPacket_Size) - 1;
|
|
tUINT32 l_uWnd_Max_Usr = l_uWnd_Max_Total;
|
|
|
|
|
|
l_pArg_Value = Get_Argument_Text_Value(i_pArgs, i_iCount,
|
|
(tXCHAR*)CLIENT_COMMAND_WINDOW_BAICAL_SIZE);
|
|
if (l_pArg_Value)
|
|
{
|
|
l_uWnd_Max_Usr = (tUINT32)PStrToInt(l_pArg_Value);
|
|
|
|
if (1 > l_uWnd_Max_Usr)
|
|
{
|
|
l_uWnd_Max_Usr = 1;
|
|
}
|
|
|
|
m_bData_Wnd_Fixed = TRUE;
|
|
}
|
|
|
|
//select minimum window size
|
|
m_dwData_Wnd_Max_Count = l_uWnd_Max_Total;
|
|
if (l_uWnd_Max_Mem < m_dwData_Wnd_Max_Count) m_dwData_Wnd_Max_Count = l_uWnd_Max_Mem;
|
|
if (l_uWnd_Max_Net < m_dwData_Wnd_Max_Count) m_dwData_Wnd_Max_Count = l_uWnd_Max_Net;
|
|
if (l_uWnd_Max_Usr < m_dwData_Wnd_Max_Count) m_dwData_Wnd_Max_Count = l_uWnd_Max_Usr;
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//initialize pool
|
|
m_pBPool = new CBuffers_Pool(m_pLog,
|
|
l_dwMax_Memory / 10, //10%
|
|
l_dwMax_Memory, //100%
|
|
l_dwPacket_Size,
|
|
0
|
|
);
|
|
|
|
if ( (NULL != m_pBPool)
|
|
&& (FALSE == m_pBPool->Get_Initialized())
|
|
)
|
|
{
|
|
JOURNAL_CRITICAL(m_pLog, TM("Pool initialization failed"));
|
|
|
|
delete m_pBPool;
|
|
m_pBPool = NULL;
|
|
}
|
|
|
|
JOURNAL_INFO(m_pLog,
|
|
TM("Pool: Max memory = %d, Packet size = %d, Window length = %d"),
|
|
l_dwMax_Memory,
|
|
l_dwPacket_Size,
|
|
m_dwData_Wnd_Max_Count
|
|
);
|
|
|
|
if (NULL == m_pBPool)
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_MemoryAllocation);
|
|
}
|
|
|
|
return (NULL != m_pBPool) ? ECLIENT_STATUS_OK : ECLIENT_STATUS_INTERNAL_ERROR;
|
|
}//Init_Pool
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Init_Members
|
|
eClient_Status CClBaical::Init_Members(tXCHAR **i_pArgs,
|
|
tINT32 i_iCount
|
|
)
|
|
{
|
|
eClient_Status l_eReturn = ECLIENT_STATUS_OK;
|
|
tXCHAR *l_pArg_Value = NULL;
|
|
|
|
if (ECLIENT_STATUS_OK == l_eReturn)
|
|
{
|
|
LOCK_CREATE(m_hCS_Data_Out);
|
|
LOCK_CREATE(m_hCS_Data_In);
|
|
}
|
|
|
|
if (ECLIENT_STATUS_OK == l_eReturn)
|
|
{
|
|
m_pData_Queue_Out = new CBList<CTPacket*>();
|
|
if (NULL == m_pData_Queue_Out)
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_MemoryAllocation);
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
JOURNAL_CRITICAL(m_pLog, TM("Data queue [out] initialization failed"));
|
|
}
|
|
}
|
|
|
|
|
|
if (ECLIENT_STATUS_OK == l_eReturn)
|
|
{
|
|
m_pData_Queue_In = new CBList<CTPacket*>();
|
|
if (NULL == m_pData_Queue_In)
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_MemoryAllocation);
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
JOURNAL_CRITICAL(m_pLog, TM("Data queue [in] initialization failed"));
|
|
}
|
|
}
|
|
|
|
if (ECLIENT_STATUS_OK == l_eReturn)
|
|
{
|
|
m_pData_Wnd = new CBList<CTPacket*>();
|
|
if (NULL == m_pData_Wnd)
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_MemoryAllocation);
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
JOURNAL_CRITICAL(m_pLog, TM("Data lagoon initialization failed"));
|
|
}
|
|
}
|
|
|
|
if (ECLIENT_STATUS_OK == l_eReturn)
|
|
{
|
|
tUINT32 l_dwHTime = 0;
|
|
tUINT32 l_dwLTime = 0;
|
|
tWCHAR l_pProc_Name[TPACKET_PROCESS_NAME_MAX_LEN];
|
|
tUINT32 l_dwEndian = 0x1;
|
|
tUINT8 l_bLittleE = *(tUINT8*)&l_dwEndian;
|
|
|
|
l_pProc_Name[0] = 0;
|
|
|
|
CProc::Get_Process_Time(&l_dwHTime, &l_dwLTime);
|
|
|
|
l_pArg_Value = Get_Argument_Text_Value(i_pArgs, i_iCount,
|
|
(tXCHAR*)CLIENT_COMMAND_LINE_NAME);
|
|
if (!l_pArg_Value)
|
|
{
|
|
CProc::Get_Process_Name(l_pProc_Name, LENGTH(l_pProc_Name));
|
|
}
|
|
else
|
|
{
|
|
#ifdef UTF8_ENCODING
|
|
Convert_UTF8_To_UTF16((const char*)l_pArg_Value,
|
|
l_pProc_Name,
|
|
LENGTH(l_pProc_Name)
|
|
);
|
|
#else
|
|
PStrCpy((tXCHAR*)l_pProc_Name, LENGTH(l_pProc_Name), l_pArg_Value);
|
|
#endif
|
|
}
|
|
|
|
m_cPacket_Hello.Fill(CLIENT_PROTOCOL_VERSION,
|
|
(tUINT16)m_pBPool->Get_Buffer_Size(),
|
|
CProc::Get_Process_ID(),
|
|
l_dwHTime,
|
|
l_dwLTime,
|
|
l_pProc_Name
|
|
);
|
|
|
|
Inc_Packet_ID(&m_dwLast_Packet_ID);
|
|
|
|
if (!l_bLittleE)
|
|
{
|
|
m_bBig_Endian = TRUE;
|
|
m_cPacket_Hello.Set_Flag(TPACKET_FLAG_BIG_ENDIAN_CLN);
|
|
m_cPacket_Data_Report.Set_Flag(TPACKET_FLAG_BIG_ENDIAN_CLN);
|
|
m_cPacket_Alive.Set_Flag(TPACKET_FLAG_BIG_ENDIAN_CLN);
|
|
m_cPacket_Bye.Set_Flag(TPACKET_FLAG_BIG_ENDIAN_CLN);
|
|
}
|
|
|
|
m_cPacket_Hello.Set_Flag(TPACKET_FLAG_EXTENSION);
|
|
|
|
#if defined(GTX64)
|
|
m_cPacket_Hello.Set_Flag(TPACKET_FLAG_ARCH_64);
|
|
#endif
|
|
|
|
m_cPacket_Hello.Finalize(m_dwLast_Packet_ID, m_wClient_ID);
|
|
|
|
m_pPacket_Control = static_cast<CTPacket*>(&m_cPacket_Hello);
|
|
}
|
|
|
|
if (ECLIENT_STATUS_OK == l_eReturn)
|
|
{
|
|
l_pArg_Value = Get_Argument_Text_Value(i_pArgs, i_iCount,
|
|
(tXCHAR*)CLIENT_COMMAND_LINE_BAICAL_EXIT_TIMEOUT);
|
|
if (l_pArg_Value)
|
|
{
|
|
m_dwExit_TimeOut = PStrToInt(l_pArg_Value);
|
|
if (15 < m_dwExit_TimeOut)
|
|
{
|
|
m_dwExit_TimeOut = 15;
|
|
}
|
|
|
|
m_dwExit_TimeOut *= 1000;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//threads initialization
|
|
|
|
if (ECLIENT_STATUS_OK == l_eReturn)
|
|
{
|
|
if (FALSE == m_cConn_Event.Init(1, EMEVENT_SINGLE_MANUAL))
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_OS);
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
JOURNAL_ERROR(m_pLog, TM("Connection event wasn't created !"));
|
|
}
|
|
}
|
|
|
|
if (ECLIENT_STATUS_OK == l_eReturn)
|
|
{
|
|
if (FALSE == m_cComm_Event.Init(1, EMEVENT_SINGLE_AUTO))
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_OS);
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
JOURNAL_ERROR(m_pLog, TM("Exit event wasn't created !"));
|
|
}
|
|
}
|
|
|
|
if (ECLIENT_STATUS_OK == l_eReturn)
|
|
{
|
|
if (FALSE == CThShell::Create(&Static_Comm_Routine,
|
|
this,
|
|
&m_hComm_Thread,
|
|
TM("P7:Comm")
|
|
)
|
|
)
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_OS);
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
JOURNAL_ERROR(m_pLog, TM("Communication thread wasn't created !"));
|
|
}
|
|
else
|
|
{
|
|
m_bComm_Thread = TRUE;
|
|
}
|
|
}
|
|
|
|
if (ECLIENT_STATUS_OK == l_eReturn)
|
|
{
|
|
if (FALSE == m_cChnl_Event.Init(2, EMEVENT_SINGLE_AUTO, EMEVENT_MULTI))
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_OS);
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
JOURNAL_ERROR(m_pLog, TM("Exit event wasn't created !"));
|
|
}
|
|
}
|
|
|
|
if (ECLIENT_STATUS_OK == l_eReturn)
|
|
{
|
|
if (FALSE == CThShell::Create(&Static_Chnl_Routine,
|
|
this,
|
|
&m_hChnl_Thread,
|
|
TM("P7:Channel")
|
|
)
|
|
)
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_OS);
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
JOURNAL_ERROR(m_pLog, TM("Channel thread wasn't created !"));
|
|
}
|
|
else
|
|
{
|
|
m_bChnl_Thread = TRUE;
|
|
}
|
|
}
|
|
|
|
return l_eReturn;
|
|
}//Init_Members
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Inc_Packet_ID
|
|
void CClBaical::Inc_Packet_ID(tUINT32 * o_pPacketID)
|
|
{
|
|
++(*o_pPacketID);
|
|
if ( TPACKET_MAX_ID < (*o_pPacketID) )
|
|
{
|
|
(*o_pPacketID) = 1;
|
|
}
|
|
}//Inc_Packet_ID
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Process_Incoming_Packet
|
|
tBOOL CClBaical::Process_Incoming_Packet(CTPacket *i_pPacket)
|
|
{
|
|
tBOOL l_bResult = TRUE;
|
|
|
|
if (NULL == i_pPacket)
|
|
{
|
|
l_bResult = FALSE;
|
|
}
|
|
|
|
//check packet integrity
|
|
if ( (l_bResult)
|
|
&& (TRUE == i_pPacket->Is_Damaged())
|
|
)
|
|
{
|
|
JOURNAL_ERROR(m_pLog,
|
|
TM("Packet is corrupted (CRC32) Packet ID=%d, Size=%d, Type=%d, CRC=0x%X"),
|
|
i_pPacket->Get_ID(),
|
|
i_pPacket->Get_Size(),
|
|
i_pPacket->Get_Type(),
|
|
i_pPacket->Get_Crc()
|
|
);
|
|
|
|
m_bIs_Response_Waiting = FALSE;
|
|
m_dwDelivery_Fails ++;
|
|
l_bResult = FALSE;
|
|
}
|
|
|
|
if (FALSE == m_bIs_Response_Waiting)
|
|
{
|
|
l_bResult = FALSE;
|
|
JOURNAL_WARNING(m_pLog,
|
|
TM("Drop packet, ID = %d"),
|
|
i_pPacket->Get_ID()
|
|
);
|
|
}
|
|
|
|
if (l_bResult)
|
|
{
|
|
m_wClient_ID = i_pPacket->Get_Client_ID();
|
|
}
|
|
|
|
if (l_bResult)
|
|
{
|
|
eTPacket_Type l_eType = i_pPacket->Get_Type();
|
|
if (ETPT_ACKNOWLEDGMENT == l_eType)
|
|
{
|
|
CTPAcknowledgment l_cServerResponse(i_pPacket);
|
|
|
|
//verify that response source ID is equal to control ID
|
|
if ( (m_pPacket_Control)
|
|
&& (l_cServerResponse.Get_Source_ID() == m_pPacket_Control->Get_ID())
|
|
)
|
|
{
|
|
m_bIs_Response_Waiting = FALSE;
|
|
m_pData_Wnd_Cell = NULL;
|
|
m_dwDelivery_Fails = 0;
|
|
|
|
if (l_cServerResponse.Get_Result())
|
|
{
|
|
if (ETPT_CLIENT_HELLO == m_pPacket_Control->Get_Type())
|
|
{
|
|
LOCK_ENTER(m_hCS_Data_In);
|
|
if (TPACKET_FLAG_EXTENSION & i_pPacket->Get_Flags())
|
|
{
|
|
m_bExtension = TRUE;
|
|
}
|
|
else
|
|
{
|
|
m_bExtension = FALSE;
|
|
}
|
|
LOCK_EXIT(m_hCS_Data_In);
|
|
}
|
|
|
|
//if this is response to data report packet ...
|
|
if (ETPT_CLIENT_DATA_REPORT == m_pPacket_Control->Get_Type())
|
|
{
|
|
pAList_Cell l_pElement = NULL;
|
|
while ((l_pElement = m_pData_Wnd->Get_First()) != NULL)
|
|
{
|
|
CTPacket * l_pPacket = m_pData_Wnd->Get_Data(l_pElement);
|
|
m_pData_Wnd->Del(l_pElement, FALSE);
|
|
m_pBPool->Push_Buffer(l_pPacket);
|
|
}
|
|
|
|
m_dwData_Wnd_First_ID = TPACKET_MAX_ID + 1;
|
|
m_dwData_Wnd_Last_ID = TPACKET_MAX_ID + 1;
|
|
m_dwData_Wnd_Size = 0;
|
|
m_bData_Resending = FALSE;
|
|
}
|
|
else if (m_bConn_Event)
|
|
{
|
|
m_bConn_Event = FALSE;
|
|
m_cConn_Event.Set(CONNECTION_SIGNAL);
|
|
}
|
|
|
|
//control packet is local class packet
|
|
//it is not necessary to return it to pool
|
|
m_pPacket_Control = NULL;
|
|
}
|
|
else //server set this flag to 0 when it not recognize this client
|
|
{
|
|
Reset_Connetion();
|
|
}
|
|
|
|
if (TPACKET_FLAG_EXTENSION & i_pPacket->Get_Flags())
|
|
{
|
|
Parse_Extensions(l_cServerResponse.Get_Buffer() + ACKNOWLEDGMENT_SIZE,
|
|
(size_t)l_cServerResponse.Get_Size() - ACKNOWLEDGMENT_SIZE
|
|
);
|
|
}
|
|
|
|
if (TPACKET_FLAG_EXTRA_DATA & i_pPacket->Get_Flags())
|
|
{
|
|
LOCK_ENTER(m_hCS_Data_In);
|
|
m_pData_Queue_In->Add_After(m_pData_Queue_In->Get_Last(), i_pPacket);
|
|
LOCK_EXIT(m_hCS_Data_In);
|
|
|
|
m_cChnl_Event.Set(THREAD_DATA_SIGNAL);
|
|
|
|
i_pPacket = NULL;
|
|
}
|
|
}
|
|
}
|
|
else if (ETPT_SERVER_DATA_REPORT == l_eType)
|
|
{
|
|
CTPData_Window_Report l_cServerReport(i_pPacket);
|
|
|
|
if (l_cServerReport.Get_Source_ID() == m_pPacket_Control->Get_ID() )
|
|
{
|
|
tUINT32 l_dwTotal = m_pData_Wnd->Count();
|
|
m_bIs_Response_Waiting = FALSE;
|
|
m_pData_Wnd_Cell = NULL;
|
|
m_bData_Resending = TRUE;
|
|
|
|
pAList_Cell l_pEl = m_pData_Wnd->Get_First();
|
|
pAList_Cell l_pEl_Exch = NULL;
|
|
while (l_pEl)
|
|
{
|
|
CTPacket *l_pPacket = m_pData_Wnd->Get_Data(l_pEl);
|
|
|
|
l_pEl_Exch = m_pData_Wnd->Get_Next(l_pEl);
|
|
|
|
if (FALSE == l_cServerReport.Is_ID(m_cPacket_Data_Report.Get_First_ID(),
|
|
l_pPacket->Get_ID()
|
|
)
|
|
)
|
|
{
|
|
m_pData_Wnd->Del(l_pEl, FALSE);
|
|
m_pBPool->Push_Buffer(l_pPacket);
|
|
}
|
|
|
|
l_pEl = l_pEl_Exch;
|
|
}
|
|
|
|
if (m_pData_Wnd->Count())
|
|
{
|
|
JOURNAL_ERROR(m_pLog,
|
|
TM("Server report: count of lost packets: %d, total: %d"),
|
|
m_pData_Wnd->Count(),
|
|
l_dwTotal
|
|
);
|
|
|
|
if ( (!m_bData_Wnd_Fixed)
|
|
&& ((m_pData_Wnd->Count() * 100 / l_dwTotal) >= COMMUNICATION_LOSSES_MAX)
|
|
)
|
|
{
|
|
JOURNAL_ERROR(m_pLog,
|
|
TM("Recalculate transmission window due to network losses, new length: %d"),
|
|
m_dwData_Wnd_Max_Count
|
|
);
|
|
m_dwData_Wnd_Max_Count = (l_dwTotal - m_pData_Wnd->Count());
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
m_bData_Resending = FALSE;
|
|
JOURNAL_ERROR(m_pLog,
|
|
TM("Server report: empty report is received !")
|
|
);
|
|
}
|
|
|
|
m_pPacket_Control = NULL;
|
|
}
|
|
} // else if (ETPT_SERVER_DATA_REPORT == l_eType)
|
|
}//if (l_bResult)
|
|
|
|
if (i_pPacket)
|
|
{
|
|
m_pBPool->Push_Buffer(i_pPacket);
|
|
}
|
|
|
|
return l_bResult;
|
|
}//Process_Incoming_Packet
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Get_Delivered_Packet
|
|
CTPacket * CClBaical::Get_Delivered_Packet()
|
|
{
|
|
CTPacket *l_pReturn = NULL;
|
|
tBOOL l_bFilled = FALSE;
|
|
|
|
if (TRUE == m_bIs_Response_Waiting)
|
|
{
|
|
//if timeout is exceed we flush flag of waiting and resend the same control packet
|
|
if (CTicks::Difference(GetTickCount(), m_dwServiceTimeStamp) >= COMMUNICATION_RESPONSE_TIMEOUT)
|
|
{
|
|
JOURNAL_ERROR(m_pLog,
|
|
TM("Server Response waiting timeout. Resending ...")
|
|
);
|
|
|
|
m_bIs_Response_Waiting = FALSE;
|
|
m_dwDelivery_Fails ++;
|
|
}
|
|
else
|
|
{
|
|
l_bFilled = TRUE;
|
|
}
|
|
}
|
|
|
|
//Do we have control packet
|
|
if ( (FALSE == l_bFilled)
|
|
&& (m_pPacket_Control)
|
|
)
|
|
{
|
|
m_dwServiceTimeStamp = GetTickCount();
|
|
l_bFilled = TRUE;
|
|
m_bIs_Response_Waiting = TRUE;
|
|
l_pReturn = m_pPacket_Control;
|
|
}
|
|
|
|
//if we sending data packets and some limits are exceed ....
|
|
//we send report packet
|
|
if ( (FALSE == l_bFilled)
|
|
&& (FALSE == m_bData_Resending)
|
|
&& (m_pData_Wnd->Count())
|
|
)
|
|
{
|
|
if ( (CTicks::Difference(GetTickCount(), m_dwData_Wnd_TimeStamp) >= COMMUNICATION_DATA_SEGMENT_MAX_DURATION)
|
|
|| (m_dwData_Wnd_Max_Count <= m_pData_Wnd->Count())
|
|
)
|
|
{
|
|
l_pReturn = Create_Data_Wnd_Report();
|
|
l_bFilled = TRUE;
|
|
}
|
|
} //if ((FALSE == l_bFilled) && (0 == m_dwDelivery_Fails))
|
|
|
|
|
|
if (FALSE == l_bFilled)
|
|
{
|
|
if (FALSE == m_bData_Resending)
|
|
{
|
|
l_pReturn = Pull_Firt_Data_Packet();
|
|
if (l_pReturn)
|
|
{
|
|
//if data window is empty - this is first data packet
|
|
//we need to check ID for overflow, to be sure that all ID
|
|
//inside data window will be sequential
|
|
if ( (0 == m_pData_Wnd->Count()) &&
|
|
((m_dwLast_Packet_ID + m_dwData_Wnd_Max_Count + 128) >= TPACKET_MAX_ID)
|
|
)
|
|
{
|
|
m_dwLast_Packet_ID = 1;
|
|
}
|
|
else
|
|
{
|
|
Inc_Packet_ID(&m_dwLast_Packet_ID);
|
|
}
|
|
|
|
//we store time when we start sending data
|
|
if (0 == m_pData_Wnd->Count())
|
|
{
|
|
m_dwData_Wnd_TimeStamp = GetTickCount();
|
|
|
|
//JOURNAL_DEBUG(m_pLog,
|
|
// L"Start sending data");
|
|
}
|
|
|
|
if (m_bBig_Endian)
|
|
{
|
|
l_pReturn->Set_Flag(TPACKET_FLAG_BIG_ENDIAN_CLN);
|
|
}
|
|
|
|
l_pReturn->Finalize(m_dwLast_Packet_ID, m_wClient_ID);
|
|
|
|
m_dwData_Wnd_Size += l_pReturn->Get_Size();
|
|
m_pData_Wnd->Add_After(m_pData_Wnd->Get_Last(), l_pReturn);
|
|
m_dwServiceTimeStamp = GetTickCount();
|
|
l_bFilled = TRUE;
|
|
}
|
|
else if (m_pData_Wnd->Count())
|
|
{
|
|
l_pReturn = Create_Data_Wnd_Report();
|
|
l_bFilled = TRUE;
|
|
}
|
|
}//if (FALSE == m_bData_Resending)
|
|
else if (m_pData_Wnd->Count())
|
|
{
|
|
//if redeliver all packets from data window
|
|
if (m_pData_Wnd_Cell == m_pData_Wnd->Get_Last())
|
|
{
|
|
if ( (TPACKET_MAX_ID > m_dwData_Wnd_First_ID)
|
|
&& (TPACKET_MAX_ID > m_dwData_Wnd_Last_ID)
|
|
)
|
|
{
|
|
l_pReturn = &m_cPacket_Data_Report;
|
|
m_pPacket_Control = &m_cPacket_Data_Report;
|
|
|
|
Inc_Packet_ID(&m_dwLast_Packet_ID);
|
|
|
|
m_cPacket_Data_Report.Fill(m_dwData_Wnd_First_ID, m_dwData_Wnd_Last_ID);
|
|
m_cPacket_Data_Report.Finalize(m_dwLast_Packet_ID, m_wClient_ID);
|
|
|
|
m_bIs_Response_Waiting = TRUE;
|
|
m_dwServiceTimeStamp = GetTickCount();
|
|
m_pData_Wnd_Cell = NULL;
|
|
l_bFilled = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pData_Wnd_Cell = m_pData_Wnd->Get_Next(m_pData_Wnd_Cell);
|
|
l_pReturn = m_pData_Wnd->Get_Data(m_pData_Wnd_Cell);
|
|
m_dwServiceTimeStamp = GetTickCount();
|
|
l_bFilled = TRUE;
|
|
}
|
|
}//else if (m_pData_Wnd->Count())
|
|
|
|
} //if (FALSE == l_bFilled)
|
|
|
|
|
|
//nothing to send, let's sent alive packet.
|
|
if ( (FALSE == l_bFilled)
|
|
&& (0 == m_pData_Wnd->Count())
|
|
&& (CTicks::Difference(GetTickCount(), m_dwServiceTimeStamp) >= COMMUNICATION_IDLE_TIMEOUT)
|
|
)
|
|
{
|
|
l_pReturn = &m_cPacket_Alive;
|
|
Inc_Packet_ID(&m_dwLast_Packet_ID);
|
|
l_pReturn->Finalize(m_dwLast_Packet_ID, m_wClient_ID);
|
|
m_bIs_Response_Waiting = TRUE;
|
|
m_dwServiceTimeStamp = GetTickCount();
|
|
l_bFilled = TRUE;
|
|
m_pPacket_Control = l_pReturn;
|
|
}
|
|
|
|
return l_pReturn;
|
|
}//Get_Delivered_Packet
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Is_Ready_To_Exit
|
|
tBOOL CClBaical::Is_Ready_To_Exit()
|
|
{
|
|
tBOOL l_bResult = TRUE;
|
|
if (FALSE == m_bConnected)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
LOCK_ENTER(m_hCS_Data_Out);
|
|
|
|
l_bResult = ( (0 == m_pData_Queue_Out->Count()) && (0 == m_pData_Wnd->Count()) );
|
|
|
|
LOCK_EXIT(m_hCS_Data_Out);
|
|
|
|
return l_bResult;
|
|
}//Is_Ready_To_Exit
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Set_Connected
|
|
void CClBaical::Set_Connected(tBOOL i_bConnected)
|
|
{
|
|
if (i_bConnected == m_bConnected)
|
|
{
|
|
return;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//update internal state
|
|
LOCK_ENTER(m_hCS);
|
|
m_bConnected = i_bConnected;
|
|
|
|
if (i_bConnected)
|
|
{
|
|
m_dwConnection_Resets ++;
|
|
}
|
|
LOCK_EXIT(m_hCS);
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
JOURNAL_ERROR(m_pLog,
|
|
TM("Set connection : %s"),
|
|
(m_bConnected) ? TM("ON") : TM("OFF")
|
|
);
|
|
}//Set_Connection_Status
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Reset_Connetion
|
|
void CClBaical::Reset_Connetion()
|
|
{
|
|
CTPacket * l_pPacket = NULL;
|
|
|
|
JOURNAL_WARNING(m_pLog, TM("Reset Connection"));
|
|
|
|
if (m_pPacket_Control)
|
|
{
|
|
m_pPacket_Control = NULL;
|
|
}
|
|
|
|
//m_dwDelivery_Fails = 0;
|
|
m_bIs_Response_Waiting = FALSE;
|
|
m_pData_Wnd_Cell = NULL;
|
|
m_dwData_Wnd_First_ID = TPACKET_MAX_ID + 1;
|
|
m_dwData_Wnd_Last_ID = TPACKET_MAX_ID + 1;
|
|
m_dwData_Wnd_Size = 0;
|
|
m_bData_Resending = FALSE;
|
|
|
|
pAList_Cell l_pElement = NULL;
|
|
while ((l_pElement = m_pData_Wnd->Get_First()) != NULL)
|
|
{
|
|
l_pPacket = m_pData_Wnd->Get_Data(l_pElement);
|
|
m_pData_Wnd->Del(l_pElement, FALSE);
|
|
m_pBPool->Push_Buffer(l_pPacket);
|
|
}
|
|
|
|
//shutdown all connections for clients and update reset counter
|
|
Update_Channels_Status(FALSE, m_dwConnection_Resets + 1);
|
|
|
|
//protect list against user calls
|
|
LOCK_ENTER(m_hCS);
|
|
|
|
while ((l_pPacket = Pull_Firt_Data_Packet()) != NULL)
|
|
{
|
|
m_pBPool->Push_Buffer(l_pPacket);
|
|
}
|
|
|
|
m_dwConnection_Resets ++;
|
|
|
|
LOCK_EXIT(m_hCS);
|
|
|
|
//if connection is established - inform all clients about it
|
|
if (m_bConnected)
|
|
{
|
|
LOCK_ENTER(m_hCS);
|
|
m_dwConnection_Resets ++;
|
|
LOCK_EXIT(m_hCS);
|
|
Update_Channels_Status(m_bConnected, m_dwConnection_Resets);
|
|
}
|
|
|
|
Inc_Packet_ID(&m_dwLast_Packet_ID);
|
|
m_cPacket_Hello.Finalize(m_dwLast_Packet_ID, m_wClient_ID);
|
|
|
|
m_pPacket_Control = static_cast<CTPacket*>(&m_cPacket_Hello);
|
|
}//Reset_Connetion
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//RoutineCreate_Data_Wnd_Report
|
|
CTPacket * CClBaical::Create_Data_Wnd_Report()
|
|
{
|
|
CTPacket *l_pResult = NULL;
|
|
|
|
m_dwData_Wnd_First_ID = TPACKET_MAX_ID + 1;
|
|
m_dwData_Wnd_Last_ID = TPACKET_MAX_ID + 1;
|
|
|
|
CTPacket *l_pLagoonPacket = m_pData_Wnd->Get_Data(m_pData_Wnd->Get_First());
|
|
if (l_pLagoonPacket)
|
|
{
|
|
m_dwData_Wnd_First_ID = l_pLagoonPacket->Get_ID();
|
|
}
|
|
|
|
l_pLagoonPacket = m_pData_Wnd->Get_Data(m_pData_Wnd->Get_Last());
|
|
if (l_pLagoonPacket)
|
|
{
|
|
m_dwData_Wnd_Last_ID = l_pLagoonPacket->Get_ID();
|
|
}
|
|
|
|
if ( (TPACKET_MAX_ID > m_dwData_Wnd_First_ID)
|
|
&& (TPACKET_MAX_ID > m_dwData_Wnd_Last_ID)
|
|
)
|
|
{
|
|
Inc_Packet_ID(&m_dwLast_Packet_ID);
|
|
m_cPacket_Data_Report.Fill(m_dwData_Wnd_First_ID, m_dwData_Wnd_Last_ID);
|
|
m_cPacket_Data_Report.Finalize(m_dwLast_Packet_ID, m_wClient_ID);
|
|
|
|
l_pResult = &m_cPacket_Data_Report;
|
|
m_bIs_Response_Waiting = TRUE;
|
|
m_dwServiceTimeStamp = GetTickCount();
|
|
m_pPacket_Control = l_pResult;
|
|
}
|
|
|
|
return l_pResult;
|
|
}//RoutineCreate_Data_Wnd_Report
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Pull_Firt_Data_Packet
|
|
CTPacket *CClBaical::Pull_Firt_Data_Packet()
|
|
{
|
|
CTPacket * l_pResult = NULL;
|
|
|
|
LOCK_ENTER(m_hCS_Data_Out);
|
|
|
|
pAList_Cell l_pElement = m_pData_Queue_Out->Get_First();
|
|
if (l_pElement)
|
|
{
|
|
l_pResult = m_pData_Queue_Out->Get_Data(l_pElement);
|
|
m_pData_Queue_Out->Del(l_pElement, FALSE);
|
|
}
|
|
|
|
if (m_pHdrUsrPacket == l_pResult)
|
|
{
|
|
m_pHdrUsrPacket = 0;
|
|
m_pHdrUsrData = 0;
|
|
m_uHdrUsrSize = 0;
|
|
m_uHdrUsrChannel = USER_PACKET_CHANNEL_ID_MAX_SIZE;
|
|
}
|
|
|
|
LOCK_EXIT(m_hCS_Data_Out);
|
|
|
|
return l_pResult;
|
|
}//Pull_Firt_Data_Packet
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Pull_Last_Data_Packet
|
|
CTPacket *CClBaical::Reuse_Data_Packet(CTPData &i_rData, tUINT32 i_uChannel_ID, tUINT32 i_uSize)
|
|
{
|
|
CTPacket *l_pResult = NULL;
|
|
|
|
LOCK_ENTER(m_hCS_Data_Out);
|
|
|
|
pAList_Cell l_pElement = m_pData_Queue_Out->Get_Last();
|
|
if (l_pElement)
|
|
{
|
|
l_pResult = m_pData_Queue_Out->Get_Data(l_pElement);
|
|
m_pData_Queue_Out->Del(l_pElement, FALSE);
|
|
}
|
|
|
|
if ( (m_pHdrUsrPacket)
|
|
&& (m_uHdrUsrChannel == i_uChannel_ID)
|
|
&& ((i_uSize + m_uHdrUsrSize) <= CHANNEL_PACKETS_UNION_MAX_SIZE)
|
|
)
|
|
{
|
|
m_uHdrUsrSize += i_uSize;
|
|
sH_User_Raw l_sHeader = { INIT_USER_HEADER(m_uHdrUsrSize, m_uHdrUsrChannel) };
|
|
memcpy(m_pHdrUsrData, &l_sHeader, sizeof(l_sHeader));
|
|
|
|
if (l_pResult)
|
|
{
|
|
i_rData.Attach(l_pResult);
|
|
if (0 >= i_rData.Get_Tail_Size())
|
|
{
|
|
i_rData.Detach();
|
|
m_pData_Queue_Out->Add_After(m_pData_Queue_Out->Get_Last(), l_pResult);
|
|
l_pResult = m_pBPool->Pull_Buffer();
|
|
i_rData.Attach(l_pResult);
|
|
i_rData.Initialize();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
l_pResult = m_pBPool->Pull_Buffer();
|
|
i_rData.Attach(l_pResult);
|
|
i_rData.Initialize();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_uHdrUsrSize = i_uSize + (tUINT32)sizeof(sH_User_Raw);
|
|
m_uHdrUsrChannel = i_uChannel_ID;
|
|
|
|
sH_User_Raw l_sHeader = { INIT_USER_HEADER(m_uHdrUsrSize, m_uHdrUsrChannel) };
|
|
|
|
if (l_pResult)
|
|
{
|
|
i_rData.Attach(l_pResult);
|
|
if (sizeof(l_sHeader) >= i_rData.Get_Tail_Size())
|
|
{
|
|
i_rData.Detach();
|
|
m_pData_Queue_Out->Add_After(m_pData_Queue_Out->Get_Last(), l_pResult);
|
|
l_pResult = m_pBPool->Pull_Buffer();
|
|
i_rData.Attach(l_pResult);
|
|
i_rData.Initialize();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
l_pResult = m_pBPool->Pull_Buffer();
|
|
i_rData.Attach(l_pResult);
|
|
i_rData.Initialize();
|
|
}
|
|
|
|
m_pHdrUsrPacket = l_pResult;
|
|
m_pHdrUsrData = i_rData.Get_Tail();
|
|
|
|
memcpy(m_pHdrUsrData, &l_sHeader, sizeof(l_sHeader));
|
|
i_rData.Append_Size((tUINT16)sizeof(l_sHeader));
|
|
}
|
|
|
|
LOCK_EXIT(m_hCS_Data_Out);
|
|
|
|
return l_pResult;
|
|
}//Pull_Last_Data_Packet
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Push_Last_Data_Packet
|
|
tBOOL CClBaical::Push_Last_Data_Packet(CTPacket *i_pPacket)
|
|
{
|
|
if (NULL == i_pPacket)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
LOCK_ENTER(m_hCS_Data_Out);
|
|
|
|
m_pData_Queue_Out->Add_After(m_pData_Queue_Out->Get_Last(), i_pPacket);
|
|
|
|
LOCK_EXIT(m_hCS_Data_Out);
|
|
|
|
return TRUE;
|
|
}//Push_Last_Data_Packet
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Parse_Extensions
|
|
void CClBaical::Parse_Extensions(tUINT8 *i_pBuffer, size_t i_szBuffer)
|
|
{
|
|
while (i_szBuffer > sizeof(sH_Ext))
|
|
{
|
|
sH_Ext *l_pExt = (sH_Ext*)i_pBuffer;
|
|
|
|
if (ETPE_SERVER_NETWORK_INFO == l_pExt->wType)
|
|
{
|
|
sH_Ext_Srv_Info *l_pInfo = (sH_Ext_Srv_Info*)(i_pBuffer + sizeof(sH_Ext));
|
|
//for the time being ignore almost all fields, except buffer size on server side:
|
|
if (FALSE == m_bData_Wnd_Fixed)
|
|
{
|
|
//even if it will overflow we will check it in next IF
|
|
tUINT32 l_uiNewWndSize = (l_pInfo->dwSocket_Buffer / m_pBPool->Get_Buffer_Size()) - 1;
|
|
|
|
//we will apply only server wnd value if it is less then local to fit in all limitations for both sides
|
|
if (l_uiNewWndSize < m_dwData_Wnd_Max_Count)
|
|
{
|
|
m_dwData_Wnd_Max_Count = l_uiNewWndSize;
|
|
}
|
|
}
|
|
}
|
|
else if (ETPE_USER_DATA == l_pExt->wType)
|
|
{
|
|
//skip here
|
|
}
|
|
else
|
|
{
|
|
JOURNAL_ERROR(m_pLog, TM("Unknown extension packet [%d:%d]"), (tUINT32)l_pExt->wType, (tUINT32)l_pExt->wSize);
|
|
}
|
|
|
|
i_pBuffer += l_pExt->wSize;
|
|
i_szBuffer -= l_pExt->wSize;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Parse_User_Data
|
|
void CClBaical::Parse_User_Data(tUINT8 *i_pBuffer, size_t i_szBuffer)
|
|
{
|
|
tUINT32 l_dwChannelId = 0;
|
|
tUINT32 l_dwPacketSize = 0;
|
|
IP7C_Channel *l_pChannel = NULL;
|
|
tUINT8 *l_pStop = i_pBuffer + i_szBuffer;
|
|
|
|
LOCK_ENTER(m_hCS_Reg);
|
|
|
|
while (i_pBuffer < l_pStop)
|
|
{
|
|
l_dwChannelId = GET_USER_HEADER_CHANNEL_ID(((sH_User_Raw*)i_pBuffer)->dwBits);
|
|
l_dwPacketSize = GET_USER_HEADER_SIZE(((sH_User_Raw*)i_pBuffer)->dwBits);
|
|
|
|
if (USER_PACKET_CHANNEL_ID_MAX_SIZE > l_dwChannelId)
|
|
{
|
|
l_pChannel = m_pChannels[l_dwChannelId];
|
|
}
|
|
|
|
if (l_pChannel)
|
|
{
|
|
l_pChannel->On_Receive(l_dwChannelId,
|
|
i_pBuffer + sizeof(sH_User_Data),
|
|
l_dwPacketSize - sizeof(sH_User_Data),
|
|
m_bBig_Endian
|
|
);
|
|
}
|
|
else
|
|
{
|
|
JOURNAL_ERROR(m_pLog,
|
|
TM("Channel %d is not registered!"),
|
|
l_dwChannelId
|
|
);
|
|
}
|
|
|
|
i_pBuffer += l_dwPacketSize;
|
|
}
|
|
|
|
LOCK_EXIT(m_hCS_Reg);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Update_Channels_Status
|
|
void CClBaical::Update_Channels_Status(tBOOL i_bConnected, tUINT32 i_dwResets)
|
|
{
|
|
sP7C_Status l_sStatus = {FALSE, 0};
|
|
l_sStatus.bConnected = i_bConnected;
|
|
l_sStatus.dwResets = i_dwResets;
|
|
|
|
LOCK_ENTER(m_hCS_Reg);
|
|
for (tUINT32 l_dwI = 0; l_dwI < USER_PACKET_CHANNEL_ID_MAX_SIZE; l_dwI++)
|
|
{
|
|
if (m_pChannels[l_dwI])
|
|
{
|
|
m_pChannels[l_dwI]->On_Status(l_dwI, &l_sStatus);
|
|
}
|
|
}
|
|
LOCK_EXIT(m_hCS_Reg);
|
|
}//Update_Channels_Status
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Comm_Routine
|
|
void CClBaical::Comm_Routine()
|
|
{
|
|
tUINT32 l_dwExit_Signal_Time = 0;
|
|
tBOOL l_bExit_Signal = FALSE;
|
|
tBOOL l_bExit = FALSE;
|
|
tUINT32 l_dwSignal = MEVENT_TIME_OUT;
|
|
tUINT32 l_dwWait_TimeOut = COMMUNICATION_THREAD_IDLE_TIMEOUT;
|
|
CTPacket *l_pReceived_Packet = NULL;
|
|
CTPacket *l_pSent_Packet = NULL;
|
|
tUINT32 l_dwReceived = 0;
|
|
tBOOL l_bConnected_Cur = FALSE;
|
|
sockaddr_storage l_tAddress;
|
|
|
|
memset(&l_tAddress, 0, sizeof(l_tAddress));
|
|
|
|
while (FALSE == l_bExit)
|
|
{
|
|
l_dwSignal = m_cComm_Event.Wait(l_dwWait_TimeOut);
|
|
|
|
if (THREAD_EXIT_SIGNAL == l_dwSignal)
|
|
{
|
|
l_dwExit_Signal_Time = GetTickCount();
|
|
l_bExit_Signal = TRUE;
|
|
}
|
|
|
|
//have to close thread ....
|
|
if ( l_bExit_Signal )
|
|
{
|
|
if (Is_Ready_To_Exit())
|
|
{
|
|
Inc_Packet_ID(&m_dwLast_Packet_ID);
|
|
m_cPacket_Bye.Finalize(m_dwLast_Packet_ID, m_wClient_ID);
|
|
|
|
if (UDP_SOCKET_OK != m_pSocket->Send((char*)m_cPacket_Bye.Get_Buffer(),
|
|
m_cPacket_Bye.Get_Size())
|
|
)
|
|
{
|
|
JOURNAL_ERROR(m_pLog, TM("<<< m_pSocket->Send Failed"));
|
|
}
|
|
|
|
l_bExit = TRUE;
|
|
}
|
|
else if (CTicks::Difference(GetTickCount(), l_dwExit_Signal_Time) > m_dwExit_TimeOut)
|
|
{
|
|
JOURNAL_ERROR(m_pLog,
|
|
TM("Exit imeout is exceed, not of all packets were sent !"));
|
|
l_bExit = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( (MEVENT_TIME_OUT == l_dwSignal)
|
|
&& (FALSE == l_bExit)
|
|
)
|
|
{
|
|
//initiate timeout value, if we receive something or will be ready to send we will put 0 as value
|
|
l_dwWait_TimeOut = COMMUNICATION_THREAD_IDLE_TIMEOUT;
|
|
|
|
if (NULL == l_pReceived_Packet)
|
|
{
|
|
l_pReceived_Packet = m_pBPool->Pull_Buffer();
|
|
}
|
|
|
|
if (l_pReceived_Packet)
|
|
{
|
|
l_dwReceived = 0;
|
|
if (UDP_SOCKET_OK == m_pSocket->Recv(&l_tAddress,
|
|
(char*)l_pReceived_Packet->Get_Buffer(),
|
|
l_pReceived_Packet->Get_Buffer_Size(),
|
|
&l_dwReceived,
|
|
m_bIs_Response_Waiting ? SOCKET_RECEIVE_RESPONSE_TIMEOUT : 0
|
|
)
|
|
)
|
|
{
|
|
if ( (l_dwReceived)
|
|
&& (FALSE == m_pSocket->Is_Server_Address(&l_tAddress))
|
|
)
|
|
{
|
|
l_dwReceived = 0;
|
|
JOURNAL_ERROR(m_pLog,
|
|
TM("<<<: Packet from wrong adress !"));
|
|
}
|
|
|
|
if (l_dwReceived)
|
|
{
|
|
PACKET_PRINT(m_pLog, TM("[INP]"), l_pReceived_Packet);
|
|
|
|
//l_pPacket will be freed inside function or stored ...
|
|
Process_Incoming_Packet(l_pReceived_Packet);
|
|
|
|
////////////////////////////////////////////////////////
|
|
// We pass packet to the stream, now packet it is head
|
|
// pain of the stream, we can forget about it
|
|
////////////////////////////////////////////////////////
|
|
l_pReceived_Packet = NULL;
|
|
l_dwWait_TimeOut = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
while ((l_pSent_Packet = Get_Delivered_Packet()) != NULL)
|
|
{
|
|
l_dwWait_TimeOut = 0;
|
|
PACKET_PRINT(m_pLog, TM("[OUT]"), l_pSent_Packet);
|
|
|
|
if (UDP_SOCKET_OK != m_pSocket->Send((char*)l_pSent_Packet->Get_Buffer(),
|
|
l_pSent_Packet->Get_Size())
|
|
)
|
|
{
|
|
//nothing to do ... continue sending ....
|
|
//error message will be printed inside socket object
|
|
}
|
|
}
|
|
|
|
l_bConnected_Cur = m_bConnected;
|
|
|
|
if (COMMUNICATION_MAX_DELIVERY_FAILS <= m_dwDelivery_Fails)
|
|
{
|
|
l_bConnected_Cur = FALSE;
|
|
}
|
|
else
|
|
{
|
|
l_bConnected_Cur = TRUE;
|
|
}
|
|
|
|
if (l_bConnected_Cur != m_bConnected)
|
|
{
|
|
if (FALSE == l_bConnected_Cur)
|
|
{
|
|
//clear connection event, it used to wait for connection
|
|
m_bConn_Event = TRUE;
|
|
m_cConn_Event.Clr(CONNECTION_SIGNAL);
|
|
|
|
Set_Connected(FALSE);
|
|
Reset_Connetion();// << Update_Channels_Status(...)
|
|
JOURNAL_INFO(m_pLog, TM("------->Drop Connection<-------"));
|
|
}
|
|
else
|
|
{
|
|
Set_Connected(TRUE);
|
|
//after Set_Connected because they can update m_bConnected,
|
|
//m_dwConnection_Resets
|
|
Update_Channels_Status(m_bConnected, m_dwConnection_Resets);
|
|
JOURNAL_INFO(m_pLog, TM("<-------Establish Connection------->"));
|
|
}
|
|
}
|
|
} // if (WAIT_TIMEOUT == l_dwSignal)
|
|
}//while (FALSE == l_bExit)
|
|
|
|
|
|
if (l_pReceived_Packet)
|
|
{
|
|
m_pBPool->Push_Buffer(l_pReceived_Packet);
|
|
l_pReceived_Packet = NULL;
|
|
}
|
|
}//Comm_Routine
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Chnl_Routine
|
|
void CClBaical::Chnl_Routine()
|
|
{
|
|
tBOOL l_bExit = FALSE;
|
|
tUINT32 l_dwSignal = 0;
|
|
pAList_Cell l_pElement = NULL;
|
|
CTPacket *l_pPacket = NULL;
|
|
|
|
while (FALSE == l_bExit)
|
|
{
|
|
l_dwSignal = m_cChnl_Event.Wait(INFINITE);
|
|
|
|
if (THREAD_EXIT_SIGNAL == l_dwSignal)
|
|
{
|
|
l_bExit = TRUE;
|
|
}
|
|
else if (THREAD_DATA_SIGNAL == l_dwSignal)
|
|
{
|
|
l_pPacket = NULL;
|
|
|
|
LOCK_ENTER(m_hCS_Data_In);
|
|
l_pElement = m_pData_Queue_In->Get_First();
|
|
if (l_pElement)
|
|
{
|
|
l_pPacket = m_pData_Queue_In->Get_Data(l_pElement);
|
|
m_pData_Queue_In->Del(l_pElement, FALSE);
|
|
}
|
|
LOCK_EXIT(m_hCS_Data_In);
|
|
|
|
if (l_pPacket)
|
|
{
|
|
if (TPACKET_FLAG_EXTENSION & l_pPacket->Get_Flags()) //new server case v>4.3
|
|
{
|
|
tUINT8 *l_pBuffer = l_pPacket->Get_Buffer() + ACKNOWLEDGMENT_SIZE;
|
|
size_t l_szBuffer = (size_t)l_pPacket->Get_Size() - ACKNOWLEDGMENT_SIZE;
|
|
|
|
while (l_szBuffer > sizeof(sH_Ext))
|
|
{
|
|
sH_Ext *l_pExt = (sH_Ext*)l_pBuffer;
|
|
|
|
if (ETPE_SERVER_NETWORK_INFO == l_pExt->wType)
|
|
{
|
|
//skip, was processed by communication thread
|
|
}
|
|
else if (ETPE_USER_DATA == l_pExt->wType)
|
|
{
|
|
Parse_User_Data(l_pBuffer + sizeof(sH_Ext), l_pExt->wSize - sizeof(sH_Ext));
|
|
}
|
|
else
|
|
{
|
|
JOURNAL_ERROR(m_pLog, TM("Unknown extension packet [%d:%d]"), (tUINT32)l_pExt->wType, (tUINT32)l_pExt->wSize);
|
|
}
|
|
|
|
l_pBuffer += l_pExt->wSize;
|
|
l_szBuffer -= l_pExt->wSize;
|
|
}
|
|
|
|
}
|
|
else //old server case v<=4.3
|
|
{
|
|
Parse_User_Data(l_pPacket->Get_Buffer() + ACKNOWLEDGMENT_SIZE,
|
|
(size_t)l_pPacket->Get_Size() - ACKNOWLEDGMENT_SIZE);
|
|
}
|
|
|
|
m_pBPool->Push_Buffer(l_pPacket);
|
|
l_pPacket = NULL;
|
|
}
|
|
else
|
|
{
|
|
JOURNAL_ERROR(m_pLog,
|
|
TM("Get event [Data In], but no buffers were found!")
|
|
);
|
|
}
|
|
} //else if ( (WAIT_OBJECT_0 + 1) == l_dwSignal)
|
|
}
|
|
}//Chnl_Routine
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Get_Info
|
|
tBOOL CClBaical::Get_Info(sP7C_Info *o_pInfo)
|
|
{
|
|
if (NULL == o_pInfo)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
LOCK_ENTER(m_hCS);
|
|
|
|
//memcpy(&(o_pInfo->sServer), m_pSocket->Get_Address(), sizeof(sockaddr_storage));
|
|
|
|
m_pBPool->Get_Memory_Info((tUINT32*)&o_pInfo->dwMem_Used,
|
|
(tUINT32*)&o_pInfo->dwMem_Free,
|
|
(tUINT32*)&o_pInfo->dwMem_Alloc
|
|
);
|
|
|
|
o_pInfo->dwReject_Mem = m_lReject_Mem;
|
|
o_pInfo->dwReject_Con = m_lReject_Con;
|
|
o_pInfo->dwReject_Int = m_lReject_Int;
|
|
|
|
LOCK_EXIT(m_hCS);
|
|
|
|
return TRUE;
|
|
}//Get_Info
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Flush
|
|
tBOOL CClBaical::Close()
|
|
{
|
|
tBOOL l_bStack_Trace = TRUE;
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//notify channels about closing
|
|
sP7C_Status l_sStatus = {FALSE, 0};
|
|
l_sStatus.bConnected = FALSE;
|
|
l_sStatus.dwResets = 0;
|
|
|
|
if (m_bFlushChannels)
|
|
{
|
|
LOCK_ENTER(m_hCS_Reg);
|
|
for (tUINT32 l_dwI = 0; l_dwI < USER_PACKET_CHANNEL_ID_MAX_SIZE; l_dwI++)
|
|
{
|
|
if (m_pChannels[l_dwI])
|
|
{
|
|
m_pChannels[l_dwI]->On_Flush(l_dwI, &l_bStack_Trace);
|
|
m_pChannels[l_dwI]->On_Status(l_dwI, &l_sStatus);
|
|
}
|
|
}
|
|
LOCK_EXIT(m_hCS_Reg);
|
|
}
|
|
|
|
|
|
m_cComm_Event.Set(THREAD_EXIT_SIGNAL);
|
|
m_cChnl_Event.Set(THREAD_EXIT_SIGNAL);
|
|
|
|
if (m_bComm_Thread)
|
|
{
|
|
if (TRUE == CThShell::Close(m_hComm_Thread, 60000))
|
|
{
|
|
m_hComm_Thread = 0;//NULL;
|
|
m_bComm_Thread = FALSE;
|
|
}
|
|
else
|
|
{
|
|
JOURNAL_CRITICAL(m_pLog, TM("Can't close communication thread !"));
|
|
}
|
|
}
|
|
|
|
if (m_bChnl_Thread)
|
|
{
|
|
if (TRUE == CThShell::Close(m_hChnl_Thread, 60000))
|
|
{
|
|
m_hChnl_Thread = 0;//NULL;
|
|
m_bChnl_Thread = FALSE;
|
|
}
|
|
else
|
|
{
|
|
JOURNAL_CRITICAL(m_pLog, TM("Can't close channels thread !"));
|
|
}
|
|
}
|
|
|
|
//to prevent sending new data
|
|
LOCK_ENTER(m_hCS);
|
|
m_bConnected = FALSE;
|
|
LOCK_EXIT(m_hCS);
|
|
|
|
return TRUE;
|
|
}//Flush
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Flush
|
|
void CClBaical::Flush()
|
|
{
|
|
//nothing to do, component is designed in such a way to deliver new data as
|
|
//fast as possible, nothing to flush
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Connection_Wait
|
|
tBOOL CClBaical::Connection_Wait(tUINT32 i_dwMilliseconds)
|
|
{
|
|
if (CONNECTION_SIGNAL == m_cConn_Event.Wait(i_dwMilliseconds))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}//Connection_Wait
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Sent
|
|
eClient_Status CClBaical::Sent(tUINT32 i_dwChannel_ID,
|
|
sP7C_Data_Chunk *i_pChunks,
|
|
tUINT32 i_dwCount,
|
|
tUINT32 i_dwSize
|
|
)
|
|
{
|
|
eClient_Status l_eReturn = ECLIENT_STATUS_OK;
|
|
CTPacket *l_pPacket = NULL;
|
|
tUINT32 l_dwTotal_Size = i_dwSize + (tUINT32)sizeof(sH_User_Raw);
|
|
tUINT32 l_dwPacket_Size = 0;
|
|
//Wanr: variables without default value!
|
|
tBOOL l_bExit;
|
|
tUINT32 l_dwChunk_Offs;
|
|
CTPData l_cData;
|
|
|
|
if (ECLIENT_STATUS_OK != m_eStatus)
|
|
{
|
|
ATOMIC_INC(&m_lReject_Int);
|
|
return m_eStatus;
|
|
}
|
|
|
|
if ( (NULL == i_pChunks)
|
|
|| (0 >= i_dwCount)
|
|
|| (USER_PACKET_MAX_SIZE <= l_dwTotal_Size)
|
|
|| (USER_PACKET_CHANNEL_ID_MAX_SIZE <= i_dwChannel_ID)
|
|
)
|
|
{
|
|
//InterlockedIncrement(&m_lReject_Int);
|
|
return ECLIENT_STATUS_WRONG_PARAMETERS;
|
|
}
|
|
|
|
//N.B. We do not check i_dwSize and real size of all chunks in release mode!!!
|
|
#ifdef _DEBUG
|
|
//tUINT32 l_dwReal_Size = 0;
|
|
//for (tUINT32 l_dwI = 0; l_dwI < i_dwCount; l_dwI ++)
|
|
//{
|
|
// if (i_pChunks[l_dwI].pData)
|
|
// {
|
|
// l_dwReal_Size += i_pChunks[l_dwI].dwSize;
|
|
// }
|
|
// else
|
|
// {
|
|
// break;
|
|
// }
|
|
//}
|
|
//
|
|
//if (l_dwReal_Size != i_dwSize)
|
|
//{
|
|
// ATOMIC_INC(&m_lReject_Int);
|
|
// return ECLIENT_STATUS_WRONG_PARAMETERS;
|
|
//}
|
|
#endif
|
|
|
|
LOCK_ENTER(m_hCS);
|
|
|
|
if (FALSE == m_bConnected)
|
|
{
|
|
ATOMIC_INC(&m_lReject_Con);
|
|
l_eReturn = ECLIENT_STATUS_OFF;
|
|
goto l_lExit;
|
|
}
|
|
|
|
l_dwPacket_Size = m_pBPool->Get_Buffer_Size() - CLIENT_DATA_HEADER_SIZE;
|
|
|
|
//if size is more than available ...
|
|
//If we will use all buffers from Pool for data - we can cause DoS.
|
|
//no packets in Pool for incoming data from server, communication is broken
|
|
if ( (l_dwTotal_Size + (l_dwPacket_Size * 3) )
|
|
> (l_dwPacket_Size * m_pBPool->Get_Free_Count())
|
|
)
|
|
{
|
|
ATOMIC_INC(&m_lReject_Mem);
|
|
l_eReturn = ECLIENT_STATUS_NO_FREE_BUFFERS;
|
|
goto l_lExit;
|
|
}
|
|
|
|
l_bExit = FALSE;
|
|
l_dwChunk_Offs = 0;
|
|
|
|
//extract last packet form data queue, and update header if new packet belongs to the same channel!
|
|
l_pPacket = Reuse_Data_Packet(l_cData, i_dwChannel_ID, i_dwSize);
|
|
|
|
while ( (FALSE == l_bExit)
|
|
&& (l_pPacket)
|
|
)
|
|
{
|
|
//if packet free size is larger or equal to chunk size
|
|
if ( l_cData.Get_Tail_Size() >= i_pChunks->dwSize )
|
|
{
|
|
memcpy(l_cData.Get_Tail(),
|
|
((tUINT8*)i_pChunks->pData) + l_dwChunk_Offs,
|
|
i_pChunks->dwSize
|
|
);
|
|
|
|
l_cData.Append_Size((tUINT16)i_pChunks->dwSize);
|
|
|
|
//current chunk was moved, we reduce chunks amount
|
|
--i_dwCount;
|
|
|
|
//if there is no more chunks - move packet to queue
|
|
if (0 >= i_dwCount)
|
|
{
|
|
Push_Last_Data_Packet(l_pPacket);
|
|
l_cData.Detach();
|
|
l_pPacket = NULL;
|
|
l_bExit = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//we are finish with that chunk
|
|
//i_pChunks->dwSize = 0;
|
|
l_dwChunk_Offs = 0;
|
|
|
|
//go to next chunk
|
|
i_pChunks ++;
|
|
|
|
//if packet is filled - put it to data queue
|
|
if (0 >= l_cData.Get_Tail_Size())
|
|
{
|
|
Push_Last_Data_Packet(l_pPacket);
|
|
l_cData.Detach();
|
|
|
|
l_pPacket = m_pBPool->Pull_Buffer();
|
|
if (l_pPacket)
|
|
{
|
|
l_cData.Attach(l_pPacket);
|
|
l_cData.Initialize();
|
|
}
|
|
else
|
|
{
|
|
l_eReturn = ECLIENT_STATUS_NO_FREE_BUFFERS;
|
|
l_bExit = TRUE;
|
|
ATOMIC_INC(&m_lReject_Mem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else //if chunk data is greater than packet free space
|
|
{
|
|
memcpy(l_cData.Get_Tail(),
|
|
((tUINT8*)i_pChunks->pData) + l_dwChunk_Offs,
|
|
l_cData.Get_Tail_Size()
|
|
);
|
|
l_dwChunk_Offs += l_cData.Get_Tail_Size();
|
|
i_pChunks->dwSize -= l_cData.Get_Tail_Size();
|
|
|
|
l_cData.Append_Size(l_cData.Get_Tail_Size());
|
|
|
|
Push_Last_Data_Packet(l_pPacket);
|
|
l_cData.Detach();
|
|
|
|
l_pPacket = m_pBPool->Pull_Buffer();
|
|
if (l_pPacket)
|
|
{
|
|
l_cData.Attach(l_pPacket);
|
|
l_cData.Initialize();
|
|
}
|
|
else
|
|
{
|
|
l_eReturn = ECLIENT_STATUS_NO_FREE_BUFFERS;
|
|
l_bExit = TRUE;
|
|
ATOMIC_INC(&m_lReject_Mem);
|
|
}
|
|
}
|
|
} //while (FALSE == l_bExit)
|
|
|
|
|
|
l_lExit:
|
|
|
|
LOCK_EXIT(m_hCS);
|
|
|
|
return l_eReturn;
|
|
|
|
}//Sent
|