/*
* PtokaX - hub server for Direct Connect peer to peer network.
* Copyright (C) 2002-2005 Ptaczek, Ptaczek at PtokaX dot org
* Copyright (C) 2004-2022 Petr Kozelka, PPK at PtokaX dot org
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3
* as published by the Free Software Foundation.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
#include "stdinc.h"
//---------------------------------------------------------------------------
#include "serviceLoop.h"
//---------------------------------------------------------------------------
#include <fstream>
#include <string>
#include <algorithm>
#include "colUsers.h"
#include "eventqueue.h"
#include "GlobalDataQueue.h"
#include "hashBanManager.h"
#include "hashRegManager.h"
#include "hashUsrManager.h"
#include "LanguageManager.h"
#include "LuaScriptManager.h"
#include "ProfileManager.h"
#include "ServerManager.h"
#include "SettingManager.h"
#include "UdpDebug.h"
#include "User.h"
#include "utility.h"
#include "ZlibUtility.h"
//---------------------------------------------------------------------------
#ifdef _WIN32
#pragma hdrstop
#endif
//---------------------------------------------------------------------------
#ifdef _WITH_SQLITE
#include "DB-SQLite.h"
#elif _WITH_POSTGRES
#include "DB-PostgreSQL.h"
#elif _WITH_MYSQL
#include "DB-MySQL.h"
#endif
#include "LuaScript.h"
#include "RegThread.h"
//---------------------------------------------------------------------------
#ifdef _BUILD_GUI
#include "../gui.win/MainWindowPageUsersChat.h"
#endif
//---------------------------------------------------------------------------
ServiceLoop * ServiceLoop::m_Ptr = NULL;
#if defined(_WIN32) && !defined(_WIN_IOT)
HANDLE ServiceLoop::m_hLoopEvents[2] = { NULL, NULL };
DWORD ServiceLoop::m_dwMainThreadId = 0;
#endif
ServiceLoop::CFlyP2PGuardArray ServiceLoop::g_ProxyArray;
bool ServiceLoop::g_ProxyGuardLoad;
//---------------------------------------------------------------------------
#if defined(_WIN32) && !defined(_WIN_IOT)
unsigned __stdcall ExecuteLoop(void *)
{
DWORD dwRet = 0;
while (true)
{
dwRet = ::WaitForMultipleObjects(2, ServiceLoop::m_hLoopEvents, FALSE, INFINITE);
if (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_TIMEOUT)
{
::Sleep(100);
#ifdef _BUILD_GUI
::PostMessage(ServerManager::m_hMainWindow, WM_PX_DO_LOOP, 0, 0);
#else
::PostThreadMessage(ServiceLoop::m_dwMainThreadId, WM_PX_DO_LOOP, 0, 0);
#endif
}
else if (dwRet == (WAIT_OBJECT_0 + 1))
{
break;
}
}
return 0;
}
#endif
//---------------------------------------------------------------------------
ServiceLoop::AcceptedSocket::AcceptedSocket() : m_pNext(NULL),
#ifdef _WIN32
m_Socket(INVALID_SOCKET)
#else
m_Socket(-1)
#endif
{
// ...
};
//---------------------------------------------------------------------------
void ServiceLoop::Looper()
{
// PPK ... two loop stategy for saving badwith
if (m_bRecv == true)
{
ReceiveLoop();
}
else
{
SendLoop();
EventQueue::m_Ptr->ProcessEvents();
}
if (ServerManager::m_bServerTerminated == false)
{
m_bRecv = !m_bRecv;
#if defined(_WIN32) && !defined(_WIN_IOT)
if (::SetEvent(m_hLoopEvents[0]) == 0)
{
AppendDebugLog("%s - [ERR] Cannot set m_hLoopEvent in ServiceLoop::Looper\n");
exit(EXIT_FAILURE);
}
#endif
}
else
{
#if defined(_WIN32) && !defined(_WIN_IOT)
if (::SetEvent(m_hLoopEvents[1]) == 0)
{
AppendDebugLog("%s - [ERR] Cannot set m_hLoopEvent in ServiceLoop::Looper\n");
exit(EXIT_FAILURE);
}
#endif
// tell the scripts about the end
ScriptManager::m_Ptr->OnExit();
// send last possible global data
GlobalDataQueue::m_Ptr->SendFinalQueue();
#if defined(_WIN32) && !defined(_WIN_IOT)
::WaitForSingleObject(m_hThreadHandle, INFINITE);
#endif
ServerManager::FinalStop(true);
}
}
//---------------------------------------------------------------------------
ServiceLoop::ServiceLoop() : m_ui64LstUptmTck(ServerManager::m_ui64ActualTick), m_pAcceptedSocketsS(NULL), m_pAcceptedSocketsE(NULL), m_dLoggedUsers(0), m_dActualSrvLoopLogins(0), m_ui32LastSendRest(0), m_ui32SendRestsPeak(0), m_ui32LastRecvRest(0), m_ui32RecvRestsPeak(0), m_ui32LoopsForLogins(0), m_bRecv(true)
{
ServerManager::m_bServerTerminated = false;
#ifdef _WIN32
#ifdef _WIN_IOT
m_ui64LastSecond = ::GetTickCount64() / 1000;
#ifdef FLYLINKDC_REMOVE_REGISTER_THREAD
m_ui64LastRegToHublist = ::GetTickCount64() / 1000;
#endif
#else
m_dwMainThreadId = ::GetCurrentThreadId();
m_hLoopEvents[0] = ::CreateEvent(NULL, FALSE, FALSE, NULL);
if (m_hLoopEvents[0] == NULL)
{
AppendDebugLog("%s - [ERR] Cannot create m_hLoopEvent in ServiceLoop::ServiceLoop\n");
exit(EXIT_FAILURE);
}
m_hLoopEvents[1] = ::CreateEvent(NULL, FALSE, FALSE, NULL);
if (m_hLoopEvents[1] == NULL)
{
AppendDebugLog("%s - [ERR] Cannot create m_hTerminateEvent in ServiceLoop::ServiceLoop\n");
exit(EXIT_FAILURE);
}
m_hThreadHandle = (HANDLE)::_beginthreadex(NULL, 0, ExecuteLoop, NULL, 0, NULL);
if (m_hThreadHandle == 0)
{
AppendDebugLog("%s - [ERR] Failed to create hThreadHandle in ServiceLoop::ServiceLoop\n");
exit(EXIT_FAILURE);
}
#endif
#else
#ifdef __MACH__
mach_timespec_t mts;
clock_get_time(ServerManager::m_csMachClock, &mts);
m_ui64LastSecond = mts.tv_sec;
#ifdef FLYLINKDC_REMOVE_REGISTER_THREAD
m_ui64LastRegToHublist = mts.tv_sec;
#endif
#else
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
m_ui64LastSecond = ts.tv_sec;
#ifdef FLYLINKDC_REMOVE_REGISTER_THREAD
m_ui64LastRegToHublist = ts.tv_sec;
#endif
#endif
#endif
}
//---------------------------------------------------------------------------
ServiceLoop::~ServiceLoop()
{
AcceptedSocket * cursck = NULL,
* nextsck = m_pAcceptedSocketsS;
while (nextsck != NULL)
{
cursck = nextsck;
nextsck = cursck->m_pNext;
shutdown_and_close(cursck->m_Socket, SHUT_RDWR);
delete cursck;
}
#ifdef _WIN32
#ifndef _WIN_IOT
if (m_hThreadHandle != 0)
{
::CloseHandle(m_hThreadHandle);
}
if (m_hLoopEvents[0] != NULL)
{
::CloseHandle(m_hLoopEvents[0]);
}
if (m_hLoopEvents[1] != NULL)
{
::CloseHandle(m_hLoopEvents[1]);
}
#endif
#endif
Cout(string("MainLoop terminated."));
}
//---------------------------------------------------------------------------
void ServiceLoop::loadProxyGuard()
{
if (g_ProxyGuardLoad == false)
{
g_ProxyGuardLoad = true;
std::ifstream l_file("proxy_list.ini");
std::string l_currentLine;
if (l_file.is_open())
{
g_ProxyArray.reserve(5400);
uint32_t a = 0, b = 0, c = 0, d = 0, a2 = 0, b2 = 0, c2 = 0, d2 = 0;
bool l_end_file;
do
{
l_end_file = getline(l_file, l_currentLine).eof();
if (!l_currentLine.empty() && isdigit((unsigned char)l_currentLine[0]))
{
if (l_currentLine.find('-') != std::string::npos && std::count(l_currentLine.begin(), l_currentLine.end(), '.') >= 6)
{
const int l_Items = sscanf(l_currentLine.c_str(), "%u.%u.%u.%u-%u.%u.%u.%u", &a, &b, &c, &d, &a2, &b2, &c2, &d2);
if (l_Items == 8)
{
const uint32_t l_startIP = (a << 24) + (b << 16) + (c << 8) + d;
//const uint32_t ttt = ntohl(inet_addr("192.168.1.2"));
const uint32_t l_endIP = (a2 << 24) + (b2 << 16) + (c2 << 8) + d2 + 1;
if (l_startIP >= l_endIP)
{
#ifndef _WIN32
syslog(LOG_NOTICE, "Error range: [%s]", l_currentLine.c_str());
#endif
printf("Error range: [%s]\r\n", l_currentLine.c_str());
}
else
{
g_ProxyArray.emplace_back(CFlyIPRange(l_startIP, l_endIP));
}
}
else
{
#ifndef _WIN32
syslog(LOG_NOTICE, "Error mask d.d.d.d-d.d.d.d: [%s]", l_currentLine.c_str());
#endif
printf("Error mask d.d.d.d-d.d.d.d: [%s]\r\n", l_currentLine.c_str());
}
}
}
else
{
}
}
while (!l_end_file);
g_ProxyArray.shrink_to_fit();
#ifndef _WIN32
syslog(LOG_NOTICE, "Load proxy list from RoLex: count: [%u]", unsigned(g_ProxyArray.size()));
#endif
printf("Load proxy list from RoLex: count: [%u]\r\n", unsigned(g_ProxyArray.size()));
}
}
}
//---------------------------------------------------------------------------
bool ServiceLoop::isProxy(const in_addr& p_ip4)
{
// TODO - speed
#ifndef _WIN32
const uint32_t l_ip4 = htonl(p_ip4.s_addr);
#else
const uint32_t l_ip4 = htonl(p_ip4.S_un.S_addr);
#endif
for (auto i = g_ProxyArray.cbegin(); i != g_ProxyArray.cend(); ++i)
{
if (l_ip4 >= i->m_start_ip && l_ip4 < i->m_stop_ip)
return true;
}
return false;
}
//---------------------------------------------------------------------------
void ServiceLoop::AcceptUser(AcceptedSocket *pAccptSocket)
{
bool bIPv6 = false;
char sIP[40] = { 0 };
Hash128 ui128IpHash;
uint16_t ui16IpTableIdx = 0;
loadProxyGuard();
in_addr ipv4addr = { 0 };
if (pAccptSocket->m_Addr.ss_family == AF_INET6)
{
memcpy(ui128IpHash, &((struct sockaddr_in6 *)&pAccptSocket->m_Addr)->sin6_addr.s6_addr, 16);
if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&pAccptSocket->m_Addr)->sin6_addr))
{
memcpy(&ipv4addr, ((struct sockaddr_in6 *)&pAccptSocket->m_Addr)->sin6_addr.s6_addr + 12, 4);
strcpy(sIP, inet_ntoa(ipv4addr));
ui16IpTableIdx = ui128IpHash[14] * ui128IpHash[15];
}
else
{
bIPv6 = true;
#if defined(_WIN32) && !defined(_WIN64) && !defined(_WIN_IOT)
win_inet_ntop(&((struct sockaddr_in6 *)&pAccptSocket->m_Addr)->sin6_addr, sIP, 40);
#else
inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&pAccptSocket->m_Addr)->sin6_addr, sIP, 40);
#endif
ui16IpTableIdx = GetIpTableIdx(ui128IpHash);
}
}
else
{
strcpy(sIP, inet_ntoa(((struct sockaddr_in *)&pAccptSocket->m_Addr)->sin_addr));
ui128IpHash[10] = 255;
ui128IpHash[11] = 255;
memcpy(ui128IpHash + 12, &((struct sockaddr_in *)&pAccptSocket->m_Addr)->sin_addr.s_addr, 4);
ui16IpTableIdx = ui128IpHash[14] * ui128IpHash[15];
}
#ifdef FLYLINKDC_USE_SET_SOCKET_BUFFER
// set the recv buffer
#ifdef _WIN32
int32_t bufsize = 8192;
if (setsockopt(pAccptSocket->m_Socket, SOL_SOCKET, SO_RCVBUF, (char *) &bufsize, sizeof(bufsize)) == SOCKET_ERROR)
{
int iError = WSAGetLastError();
UdpDebug::m_Ptr->BroadcastFormat("[SYS] setsockopt failed on attempt to set SO_RCVBUF. IP: %s Err: %s (%d)", sIP, WSErrorStr(iError), iError);
#else
int bufsize = 8192;
if (setsockopt(pAccptSocket->m_Socket, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)) == -1)
{
UdpDebug::m_Ptr->BroadcastFormat("[SYS] setsockopt failed on attempt to set SO_RCVBUF. IP: %s Err: %s (%d)", sIP, ErrnoStr(errno), errno);
#endif
shutdown_and_close(pAccptSocket->m_Socket, SHUT_RDWR);
return;
}
// set the send buffer
bufsize = 32768;
#ifdef _WIN32
if (setsockopt(pAccptSocket->m_Socket, SOL_SOCKET, SO_SNDBUF, (char *) &bufsize, sizeof(bufsize)) == SOCKET_ERROR)
{
int iError = WSAGetLastError();
UdpDebug::m_Ptr->BroadcastFormat("[SYS] setsockopt failed on attempt to set SO_SNDBUF. IP: %s Err: %s (%d)", sIP, WSErrorStr(iError), iError);
#else
if (setsockopt(pAccptSocket->m_Socket, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)) == -1)
{
UdpDebug::m_Ptr->BroadcastFormat("[SYS] setsockopt failed on attempt to set SO_SNDBUF. IP: %s Err: %s (%d)", sIP, ErrnoStr(errno), errno);
#endif
shutdown_and_close(pAccptSocket->m_Socket, SHUT_RDWR);
return;
}
#endif // FLYLINKDC_USE_SET_SOCKET_BUFFER
// set sending of keepalive packets
#ifdef _WIN32
bool bKeepalive = true;
setsockopt(pAccptSocket->m_Socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&bKeepalive, sizeof(bKeepalive));
#else
int iKeepAlive = 1;
if (setsockopt(pAccptSocket->m_Socket, SOL_SOCKET, SO_KEEPALIVE, &iKeepAlive, sizeof(iKeepAlive)) == -1)
{
UdpDebug::m_Ptr->BroadcastFormat("[SYS] setsockopt failed on attempt to set SO_KEEPALIVE. IP: %s Err: %s (%d)", sIP, ErrnoStr(errno), errno);
shutdown_and_close(pAccptSocket->m_Socket, SHUT_RDWR);
return;
}
#endif
// set non-blocking mode
#ifdef _WIN32
uint32_t block = 1;
if (ioctlsocket(pAccptSocket->m_Socket, FIONBIO, (unsigned long *)&block) == SOCKET_ERROR)
{
int iError = WSAGetLastError();
UdpDebug::m_Ptr->BroadcastFormat("[SYS] ioctlsocket failed on attempt to set FIONBIO. IP: %s Err: %s (%d)", sIP, WSErrorStr(iError), iError);
#else
int oldFlag = fcntl(pAccptSocket->m_Socket, F_GETFL, 0);
if (fcntl(pAccptSocket->m_Socket, F_SETFL, oldFlag | O_NONBLOCK) == -1)
{
UdpDebug::m_Ptr->BroadcastFormat("[SYS] fcntl failed on attempt to set O_NONBLOCK. IP: %s Err: %s (%d)", sIP, ErrnoStr(errno), errno);
#endif
shutdown_and_close(pAccptSocket->m_Socket, SHUT_RDWR);
return;
}
#ifdef FLYLINKDC_USE_REDIR
if (SettingManager::m_Ptr->m_bBools[SETBOOL_REDIRECT_ALL] == true)
{
if (SettingManager::m_Ptr->m_sTexts[SETTXT_REDIRECT_ADDRESS] != NULL)
{
int iMsgLen = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "<%s> %s %s|%s", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_YOU_REDIR_TO], SettingManager::m_Ptr->m_sTexts[SETTXT_REDIRECT_ADDRESS],
SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_REDIRECT_ADDRESS]);
if (iMsgLen > 0)
{
send(pAccptSocket->m_Socket, ServerManager::m_pGlobalBuffer, iMsgLen, 0);
ServerManager::m_ui64BytesSent += iMsgLen;
GlobalDataQueue::m_Ptr->PrometheusSendBytes(__func__,iMsgLen);
}
}
shutdown_and_close(pAccptSocket->m_Socket, SHUT_RDWR);
return;
}
#endif
time_t acc_time;
time(&acc_time);
BanItem * Ban = BanManager::m_Ptr->FindFull(ui128IpHash, acc_time);
if (Ban != NULL)
{
if (((Ban->m_ui8Bits & BanManager::FULL) == BanManager::FULL) == true)
{
const int iMsgLen = GenerateBanMessage(Ban, acc_time);
if (iMsgLen != 0)
{
send(pAccptSocket->m_Socket, ServerManager::m_pGlobalBuffer, iMsgLen, 0);
}
shutdown_and_close(pAccptSocket->m_Socket, SHUT_RD);
// UdpDebug::m_Ptr->BroadcastFormat("[SYS] Banned ip %s - connection closed.", sIP);
return;
}
}
RangeBanItem * RangeBan = BanManager::m_Ptr->FindFullRange(ui128IpHash, acc_time);
if (RangeBan != NULL)
{
if (((RangeBan->m_ui8Bits & BanManager::FULL) == BanManager::FULL) == true)
{
int iMsgLen = GenerateRangeBanMessage(RangeBan, acc_time);
if (iMsgLen != 0)
{
send(pAccptSocket->m_Socket, ServerManager::m_pGlobalBuffer, iMsgLen, 0);
}
shutdown_and_close(pAccptSocket->m_Socket, SHUT_RD);
// UdpDebug::m_Ptr->BroadcastFormat("[SYS] Range Banned ip %s - connection closed.", sIP);
return;
}
}
const bool l_is_proxy = isProxy(ipv4addr);
if (l_is_proxy)
{
//const char* l_proxy_ban_msg = "Hi proxy user!";
//send(pAccptSocket->m_Socket, l_proxy_ban_msg, strlen(l_proxy_ban_msg), 0);
UdpDebug::m_Ptr->BroadcastFormat("[SYS] Proxy user ip %s", sIP);
#ifndef _WIN32
syslog(LOG_NOTICE, "Proxy user ip %s", sIP);
#endif
printf("Proxy user ip %s\r\n", sIP);
//shutdown_and_close(pAccptSocket->m_Socket, SHUT_RD);
//return;
}
ServerManager::m_ui32Joins++;
// set properties of the new user object
User * pUser = new (std::nothrow) User();
if (pUser == NULL)
{
shutdown_and_close(pAccptSocket->m_Socket, SHUT_RDWR);
AppendDebugLog("%s - [MEM] Cannot allocate pUser in ServiceLoop::AcceptUser\n");
return;
}
pUser->m_LogInOut.m_ui64LogonTick = ServerManager::m_ui64ActualTick;
pUser->m_Socket = pAccptSocket->m_Socket;
memcpy(pUser->m_ui128IpHash, ui128IpHash, 16);
pUser->m_ui16IpTableIdx = ui16IpTableIdx;
pUser->SetIP(sIP);
pUser->m_is_proxy_user = l_is_proxy;
if (bIPv6 == true)
{
pUser->m_ui32BoolBits |= User::BIT_IPV6;
}
else
{
pUser->m_ui32BoolBits |= User::BIT_IPV4;
}
if (Ban != NULL)
{
uint32_t hash = 0;
if (((Ban->m_ui8Bits & BanManager::NICK) == BanManager::NICK) == true)
{
hash = Ban->m_ui32NickHash;
}
const int iMsglen = GenerateBanMessage(Ban, acc_time);
pUser->m_LogInOut.m_pBan = UserBan::CreateUserBan(ServerManager::m_pGlobalBuffer, iMsglen, hash);
if (pUser->m_LogInOut.m_pBan == NULL)
{
shutdown_and_close(pAccptSocket->m_Socket, SHUT_RDWR);
AppendDebugLog("%s - [MEM] Cannot allocate new uBan in ServiceLoop::AcceptUser\n");
delete pUser;
return;
}
}
else if (RangeBan != NULL)
{
int iMsgLen = GenerateRangeBanMessage(RangeBan, acc_time);
pUser->m_LogInOut.m_pBan = UserBan::CreateUserBan(ServerManager::m_pGlobalBuffer, iMsgLen, 0);
if (pUser->m_LogInOut.m_pBan == NULL)
{
shutdown_and_close(pAccptSocket->m_Socket, SHUT_RDWR);
AppendDebugLog("%s - [MEM] Cannot allocate new uBan in ServiceLoop::AcceptUser1\n");
delete pUser;
return;
}
}
// Everything is ok, now add to users...
Users::m_Ptr->AddUser(pUser);
}
//---------------------------------------------------------------------------
void ServiceLoop::ReceiveLoop()
{
#ifndef _WIN32
timespec ts;
#ifdef __MACH__
mach_timespec_t mts;
clock_get_time(ServerManager::m_csMachClock, &mts);
ts.tv_sec = mts.tv_sec;
ts.tv_nsec = mts.tv_nsec;
#else
clock_gettime(CLOCK_MONOTONIC, &ts);
#endif
if ((uint64_t)ts.tv_sec != m_ui64LastSecond)
{
m_ui64LastSecond = ts.tv_sec;
ServerManager::OnSecTimer();
}
#ifdef FLYLINKDC_REMOVE_REGISTER_THREAD
if (SettingManager::m_Ptr->m_bBools[SETBOOL_AUTO_REG] == true)
{
if (((uint64_t)ts.tv_sec - m_ui64LastRegToHublist) >= 901) // 15 min 1 sec is hublist register interval
{
m_ui64LastRegToHublist = ts.tv_sec;
ServerManager::OnRegTimer();
}
}
#endif
ScriptOnTimer((uint64_t(ts.tv_sec) * 1000) + (uint64_t(ts.tv_nsec) / 1000000));
#elif defined(_WIN32) && defined(_WIN_IOT)
uint64_t ui64Millis = (uint64_t)::GetTickCount64();
uint64_t ui64Secs = ui64Millis / 1000;
if (ui64Secs != ui64LastSecond)
{
ui64LastSecond = ui64Secs;
ServerManager::OnSecTimer();
}
#ifdef FLYLINKDC_REMOVE_REGISTER_THREAD
if (SettingManager::m_Ptr->m_bBools[SETBOOL_AUTO_REG] == true)
{
if ((ui64Secs - ui64LastRegToHublist) >= 901) // 15 min 1 sec is hublist register interval
{
ui64LastRegToHublist = ui64Secs;
ServerManager::OnRegTimer();
}
}
#endif
ScriptOnTimer(ui64Millis);
#endif
// Receiving loop for process all incoming data and store in queues
uint32_t iRecvRests = 0;
ServerManager::m_ui8SrCntr++;
if (ServerManager::m_ui8SrCntr >= 7 || (Users::m_Ptr->m_ui16ActSearchs + Users::m_Ptr->m_ui16PasSearchs) > 8 ||
Users::m_Ptr->m_ui16ActSearchs > 5)
{
ServerManager::m_ui8SrCntr = 0;
}
if (ServerManager::m_ui64ActualTick - m_ui64LstUptmTck > 60)
{
time_t acctime;
time(&acctime);
acctime -= ServerManager::m_tStartTime;
uint64_t iValue = acctime / 86400;
acctime -= (time_t)(86400 * iValue);
ServerManager::m_ui64Days = iValue;
iValue = acctime / 3600;
acctime -= (time_t)(3600 * iValue);
ServerManager::m_ui64Hours = iValue;
iValue = acctime / 60;
ServerManager::m_ui64Mins = iValue;
if (ServerManager::m_ui64Mins == 0 || ServerManager::m_ui64Mins == 15 || ServerManager::m_ui64Mins == 30 || ServerManager::m_ui64Mins == 45)
{
RegManager::m_Ptr->Save(false, true);
}
m_ui64LstUptmTck = ServerManager::m_ui64ActualTick;
}
AcceptedSocket * CurSck = NULL,
* NextSck = nullptr;
{
Lock l(m_csAcceptQueue);
if (m_pAcceptedSocketsS != NULL)
{
NextSck = m_pAcceptedSocketsS;
m_pAcceptedSocketsS = nullptr;
m_pAcceptedSocketsE = nullptr;
}
}
while (NextSck != NULL)
{
CurSck = NextSck;
NextSck = CurSck->m_pNext;
AcceptUser(CurSck);
delete CurSck;
}
User * curUser = NULL,
* nextUser = Users::m_Ptr->m_pUserListS;
while (nextUser != 0 && ServerManager::m_bServerTerminated == false)
{
curUser = nextUser;
nextUser = curUser->m_pNext;
// PPK ... true == we have rest ;)
if (curUser->DoRecv() == true)
{
iRecvRests++;
//Memo("Rest " + string(curUser->Nick, curUser->NickLen) + ": '" + string(curUser->pRecvBuf) + "'");
}
// curUser->ProcessLines();
//}
switch (curUser->m_ui8State)
{
case User::STATE_SOCKET_ACCEPTED:
{
if (ServerManager::m_ui64ActualTick != curUser->m_LogInOut.m_ui64LogonTick)
{
if (curUser->MakeLock() == false)
{
curUser->Close();
continue;
}
curUser->m_ui8State = User::STATE_KEY_OR_SUP;
}
break;
}
case User::STATE_KEY_OR_SUP:
{
// check logon timeout for iState 1
if (ServerManager::m_ui64ActualTick - curUser->m_LogInOut.m_ui64LogonTick > 20)
{
UdpDebug::m_Ptr->BroadcastFormat("[SYS] Login timeout 1 for %s - user (%s) disconnected.", curUser->m_sIP, curUser->m_sNick);
curUser->Close();
continue;
}
break;
}
case User::STATE_IPV4_CHECK:
{
// check IPv4Check timeout
if ((ServerManager::m_ui64ActualTick - curUser->m_LogInOut.m_ui64IPv4CheckTick) > 10)
{
UdpDebug::m_Ptr->BroadcastFormat("[SYS] IPv4Check timeout for %s (%s).", curUser->m_sNick, curUser->m_sIP);
curUser->m_ui8State = User::STATE_ADDME;
continue;
}
break;
}
case User::STATE_ADDME:
{
// PPK ... Add user, but only if send $GetNickList (or have quicklist supports) <- important, used by flooders !!!
if (((curUser->m_ui32BoolBits & User::BIT_GETNICKLIST) == User::BIT_GETNICKLIST) == false &&
((curUser->m_ui32SupportBits & User::SUPPORTBIT_QUICKLIST) == User::SUPPORTBIT_QUICKLIST) == false &&
((curUser->m_ui32BoolBits & User::BIT_PINGER) == User::BIT_PINGER) == true)
continue;
// without Welcome message
// curUser->SendFormat("clsServiceLoop::ReceiveLoop->User::STATE_ADDME", true, "%s|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_NAME_WLCM]);
curUser->SendFormat("ServiceLoop::ReceiveLoop->User::STATE_ADDME", true, "%s%" PRIu64 " %s, %" PRIu64 " %s, %" PRIu64 " %s / %s: %u)|", SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_NAME_WLCM], ServerManager::m_ui64Days, LanguageManager::m_Ptr->m_sTexts[LAN_DAYS_LWR],
ServerManager::m_ui64Hours, LanguageManager::m_Ptr->m_sTexts[LAN_HOURS_LWR], ServerManager::m_ui64Mins, LanguageManager::m_Ptr->m_sTexts[LAN_MINUTES_LWR], LanguageManager::m_Ptr->m_sTexts[LAN_USERS], ServerManager::m_ui32Logged);
curUser->m_ui8State = User::STATE_ADDME_1LOOP;
continue;
}
case User::STATE_ADDME_1LOOP:
{
// PPK ... added login delay.
if (m_dLoggedUsers >= m_dActualSrvLoopLogins && ((curUser->m_ui32BoolBits & User::BIT_OPERATOR) == User::BIT_OPERATOR) == false)
{
if (ServerManager::m_ui64ActualTick - curUser->m_LogInOut.m_ui64LogonTick > 300)
{
UdpDebug::m_Ptr->BroadcastFormat("[SYS] Login timeout (%d) 3 for %s (%s) - user disconnected.", (int)curUser->m_ui8State, curUser->m_sNick, curUser->m_sIP);
curUser->Close();
}
continue;
}
// PPK ... is not more needed, free mem ;)
curUser->FreeBuffer();
if ((curUser->m_ui32BoolBits & User::BIT_IPV6) == User::BIT_IPV6 && ((curUser->m_ui32BoolBits & User::SUPPORTBIT_IPV4) == User::SUPPORTBIT_IPV4) == false)
{
in_addr ipv4addr;
ipv4addr.s_addr = INADDR_NONE;
if (curUser->m_ui128IpHash[0] == 32 && curUser->m_ui128IpHash[1] == 2) // 6to4 tunnel
{
memcpy(&ipv4addr, curUser->m_ui128IpHash + 2, 4);
}
else if (curUser->m_ui128IpHash[0] == 32 && curUser->m_ui128IpHash[1] == 1 && curUser->m_ui128IpHash[2] == 0 && curUser->m_ui128IpHash[3] == 0) // teredo tunnel
{
uint32_t ui32Ip = 0;
memcpy(&ui32Ip, curUser->m_ui128IpHash + 12, 4);
ui32Ip ^= 0xffffffff;
memcpy(&ipv4addr, &ui32Ip, 4);
}
if (ipv4addr.s_addr != INADDR_NONE)
{
strcpy(curUser->m_sIPv4, inet_ntoa(ipv4addr));
curUser->m_ui8IPv4Len = (uint8_t)strlen(curUser->m_sIPv4);
curUser->m_ui32BoolBits |= User::BIT_IPV4;
}
}
//New User Connected ... the user is operator ? invoke lua User/OpConnected
const uint32_t iBeforeLuaLen = curUser->m_ui32SendBufDataLen;
const bool bRet = ScriptManager::m_Ptr->UserConnected(curUser);
if (curUser->m_ui8State >= User::STATE_CLOSING) // connection closed by script?
{
if (bRet == false) // only when all scripts process userconnected
{
ScriptManager::m_Ptr->UserDisconnected(curUser);
}
continue;
}
if (iBeforeLuaLen < curUser->m_ui32SendBufDataLen)
{
const size_t szNeededLen = curUser->m_ui32SendBufDataLen - iBeforeLuaLen;
void * sOldBuf = curUser->m_LogInOut.m_pBuffer;
curUser->m_LogInOut.m_pBuffer = (char *)realloc(sOldBuf, szNeededLen + 1);
if (curUser->m_LogInOut.m_pBuffer == NULL)
{
curUser->m_ui32BoolBits |= User::BIT_ERROR;
curUser->Close();
AppendDebugLogFormat("[MEM] Cannot allocate %zu bytes for sLockUsrConn in ServiceLoop::ReceiveLoop\n", szNeededLen+1);
continue;
}
memcpy(curUser->m_LogInOut.m_pBuffer, curUser->m_pSendBuf + iBeforeLuaLen, szNeededLen);
curUser->m_LogInOut.m_ui32UserConnectedLen = (uint32_t)szNeededLen;
curUser->m_LogInOut.m_pBuffer[curUser->m_LogInOut.m_ui32UserConnectedLen] = '\0';
curUser->m_ui32SendBufDataLen = iBeforeLuaLen;
curUser->m_pSendBuf[curUser->m_ui32SendBufDataLen] = '\0';
}
// PPK ... wow user is accepted, now add it :)
if (((curUser->m_ui32BoolBits & User::BIT_HAVE_BADTAG) == User::BIT_HAVE_BADTAG) == true)
{
curUser->HasSuspiciousTag();
}
// alex82 ... HideUser / ������� �����
if (((curUser->m_ui32InfoBits & User::INFOBIT_HIDDEN) == User::INFOBIT_HIDDEN) == false)
{
curUser->Add2Userlist();
ServerManager::m_ui64TotalShare += curUser->m_ui64SharedSize;
curUser->m_ui32BoolBits |= User::BIT_HAVE_SHARECOUNTED;
}
m_dLoggedUsers++;
curUser->m_ui8State = User::STATE_ADDME_2LOOP;
#ifdef _BUILD_GUI
if (::SendMessage(MainWindowPageUsersChat::m_Ptr->m_hWndPageItems[MainWindowPageUsersChat::BTN_AUTO_UPDATE_USERLIST], BM_GETCHECK, 0, 0) == BST_CHECKED)
{
MainWindowPageUsersChat::m_Ptr->AddUser(curUser);
}
#endif
// if(sqldb) sqldb->AddVisit(curUser);
#ifdef FLYLINKDC_USE_DB
#ifdef _WITH_SQLITE
DBSQLite::m_Ptr->UpdateRecord(curUser);
#elif _WITH_POSTGRES
DBPostgreSQL::m_Ptr->UpdateRecord(curUser);
#elif _WITH_MYSQL
DBMySQL::m_Ptr->UpdateRecord(curUser);
#endif
#endif
// PPK ... change to NoHello supports
int iMsgLen = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "$Hello %s|", curUser->m_sNick);
if (iMsgLen > 0)
{
GlobalDataQueue::m_Ptr->AddQueueItem(ServerManager::m_pGlobalBuffer, iMsgLen, NULL, 0, GlobalDataQueue::CMD_HELLO);
}
// alex82 ... HideUser / ������� �����
if (((curUser->m_ui32InfoBits & User::INFOBIT_HIDDEN) == User::INFOBIT_HIDDEN) == false)
{
GlobalDataQueue::m_Ptr->UserIPStore(curUser);
switch (SettingManager::m_Ptr->m_ui8FullMyINFOOption)
{
case 0:
GlobalDataQueue::m_Ptr->AddQueueItem(curUser->m_sMyInfoLong, curUser->m_ui16MyInfoLongLen, NULL, 0, GlobalDataQueue::CMD_MYINFO);
break;
case 1:
GlobalDataQueue::m_Ptr->AddQueueItem(curUser->m_sMyInfoShort, curUser->m_ui16MyInfoShortLen, curUser->m_sMyInfoLong, curUser->m_ui16MyInfoLongLen, GlobalDataQueue::CMD_MYINFO);
break;
case 2:
GlobalDataQueue::m_Ptr->AddQueueItem(curUser->m_sMyInfoShort, curUser->m_ui16MyInfoShortLen, NULL, 0, GlobalDataQueue::CMD_MYINFO);
break;
default:
break;
}
#ifdef USE_FLYLINKDC_EXT_JSON
/*
// TODO ExtJSON
if (curUser->m_user_ext_info)
{
const std::string& l_ext_json = curUser->m_user_ext_info->GetExtJSONCommand();
if (!l_ext_json.empty())
{
// TODO ExtJSON if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_DELAY] == 0 || ServerManager::m_ui64ActualTick > ((60 * SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MYINFO_DELAY]) + pUser->getLastExtJSONSendTick()))
//if (curUser->getLastExtJSONSendTick() || ServerManager::m_ui64ActualTick > curUser->getLastExtJSONSendTick() + 60)
{
GlobalDataQueue::m_Ptr->AddQueueItem(l_ext_json.c_str(), l_ext_json.size(), NULL, 0, GlobalDataQueue::CMD_EXTJSON);
curUser->setLastExtJSONSendTick(ServerManager::m_ui64ActualTick);
}
}
}
*/
#endif
// alex82 ... HideUserKey / ������ ���� �����
if (((curUser->m_ui32BoolBits & User::BIT_OPERATOR) == User::BIT_OPERATOR) == true && ((curUser->m_ui32InfoBits & User::INFOBIT_HIDE_KEY) == User::INFOBIT_HIDE_KEY) == false)
{
GlobalDataQueue::m_Ptr->OpListStore(curUser->m_sNick);
}
}
curUser->m_ui64LastMyINFOSendTick = ServerManager::m_ui64ActualTick;
break;
}
case User::STATE_ADDED:
if (curUser->m_pCmdToUserStrt != NULL)
{
PrcsdToUsrCmd * cur = NULL,
* next = curUser->m_pCmdToUserStrt;
curUser->m_pCmdToUserStrt = NULL;
curUser->m_pCmdToUserEnd = NULL;
while (next != NULL)
{
cur = next;
next = cur->m_pNext;
if (cur->m_ui32Loops >= 2)
{
User * ToUser = HashManager::m_Ptr->FindUser(cur->m_nick);
if (ToUser == cur->m_pToUser)
{
if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_PM_COUNT_TO_USER] == 0 || cur->m_ui32PmCount == 0)
{
cur->m_pToUser->SendCharDelayed(cur->m_sCommand, cur->m_ui32Len);
}
else
{
if (cur->m_pToUser->m_ui32ReceivedPmCount == 0)
{
cur->m_pToUser->m_ui64ReceivedPmTick = ServerManager::m_ui64ActualTick;
}
else if (cur->m_pToUser->m_ui32ReceivedPmCount >= (uint32_t)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_PM_COUNT_TO_USER])
{
if (cur->m_pToUser->m_ui64ReceivedPmTick + 60 < ServerManager::m_ui64ActualTick)
{
cur->m_pToUser->m_ui64ReceivedPmTick = ServerManager::m_ui64ActualTick;
cur->m_pToUser->m_ui32ReceivedPmCount = 0;
}
else
{
if (cur->m_ui32PmCount == 1)
{
curUser->SendFormat("ServiceLoop::ReceiveLoop->User::STATE_ADDED1", true, "$To: %s From: %s $<%s> %s %s %s!|",
curUser->m_sNick, cur->m_nick.c_str(), SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_SRY_LST_MSG_BCS],
cur->m_nick.c_str(), LanguageManager::m_Ptr->m_sTexts[LAN_EXC_MSG_LIMIT]);
}
else
{
curUser->SendFormat("ServiceLoop::ReceiveLoop->User::STATE_ADDED2", true,
"$To: %s From: %s $<%s> %s %u %s %s %s!|", curUser->m_sNick,
cur->m_nick.c_str(), SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_HUB_SEC], LanguageManager::m_Ptr->m_sTexts[LAN_SORRY_LAST],
cur->m_ui32PmCount, LanguageManager::m_Ptr->m_sTexts[LAN_MSGS_NOT_SENT], cur->m_nick.c_str(), LanguageManager::m_Ptr->m_sTexts[LAN_EXC_MSG_LIMIT]);
}
safe_free(cur->m_sCommand);
delete cur;
continue;
}
}
cur->m_pToUser->SendCharDelayed(cur->m_sCommand, cur->m_ui32Len);
cur->m_pToUser->m_ui32ReceivedPmCount += cur->m_ui32PmCount;
}
}
}
else
{
cur->m_ui32Loops++;
if (curUser->m_pCmdToUserStrt == NULL)
{
cur->m_pNext = NULL;
curUser->m_pCmdToUserStrt = cur;
curUser->m_pCmdToUserEnd = cur;
}
else
{
curUser->m_pCmdToUserEnd->m_pNext = cur;
curUser->m_pCmdToUserEnd = cur;
}
continue;
}
safe_free(cur->m_sCommand);
delete cur;
}
}
if (ServerManager::m_ui8SrCntr == 0)
{
if (curUser->m_pCmdActive6Search != NULL)
{
if (curUser->m_pCmdActive4Search != NULL)
{
GlobalDataQueue::m_Ptr->AddQueueItem(curUser->m_pCmdActive6Search->m_sCommand, curUser->m_pCmdActive6Search->m_ui32Len,
curUser->m_pCmdActive4Search->m_sCommand, curUser->m_pCmdActive4Search->m_ui32Len, GlobalDataQueue::CMD_ACTIVE_SEARCH_V64);
}
else
{
GlobalDataQueue::m_Ptr->AddQueueItem(curUser->m_pCmdActive6Search->m_sCommand, curUser->m_pCmdActive6Search->m_ui32Len, NULL, 0, GlobalDataQueue::CMD_ACTIVE_SEARCH_V6);
}
}
else if (curUser->m_pCmdActive4Search != NULL)
{
GlobalDataQueue::m_Ptr->AddQueueItem(curUser->m_pCmdActive4Search->m_sCommand, curUser->m_pCmdActive4Search->m_ui32Len, NULL, 0, GlobalDataQueue::CMD_ACTIVE_SEARCH_V4);
}
if (curUser->m_pCmdPassiveSearch != NULL)
{
uint8_t ui8CmdType = GlobalDataQueue::CMD_PASSIVE_SEARCH_V4;
if ((curUser->m_ui32BoolBits & User::BIT_IPV6) == User::BIT_IPV6)
{
if ((curUser->m_ui32BoolBits & User::BIT_IPV4) == User::BIT_IPV4)
{
if ((curUser->m_ui32BoolBits & User::BIT_IPV6_ACTIVE) == User::BIT_IPV6_ACTIVE)
{
ui8CmdType = GlobalDataQueue::CMD_PASSIVE_SEARCH_V4_ONLY;
}
else if ((curUser->m_ui32BoolBits & User::BIT_IPV4_ACTIVE) == User::BIT_IPV4_ACTIVE)
{
ui8CmdType = GlobalDataQueue::CMD_PASSIVE_SEARCH_V6_ONLY;
}
else
{
ui8CmdType = GlobalDataQueue::CMD_PASSIVE_SEARCH_V64;
}
}
else
{
ui8CmdType = GlobalDataQueue::CMD_PASSIVE_SEARCH_V6;
}
}
GlobalDataQueue::m_Ptr->AddQueueItem(curUser->m_pCmdPassiveSearch->m_sCommand, curUser->m_pCmdPassiveSearch->m_ui32Len, NULL, 0, ui8CmdType);
User::DeletePrcsdUsrCmd(curUser->m_pCmdPassiveSearch);
}
// PPK ... deflood memory cleanup, if is not needed anymore
if (curUser->m_sLastChat != NULL && curUser->m_ui16LastChatLines < 2 &&
(curUser->m_ui64SameChatsTick + SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_MAIN_CHAT_TIME]) < ServerManager::m_ui64ActualTick)
{
safe_free(curUser->m_sLastChat);
curUser->m_ui16LastChatLen = 0;
curUser->m_ui16SameMultiChats = 0;
curUser->m_ui16LastChatLines = 0;
}
if (curUser->m_sLastPM != NULL && curUser->m_ui16LastPmLines < 2 &&
(curUser->m_ui64SamePMsTick + SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_PM_TIME]) < ServerManager::m_ui64ActualTick)
{
safe_free(curUser->m_sLastPM);
curUser->m_ui16LastPMLen = 0;
curUser->m_ui16SameMultiPms = 0;
curUser->m_ui16LastPmLines = 0;
}
if (!curUser->m_LastSearch.empty() && (curUser->m_ui64SameSearchsTick + SettingManager::m_Ptr->m_i16Shorts[SETSHORT_SAME_SEARCH_TIME]) < ServerManager::m_ui64ActualTick)
{
curUser->m_LastSearch.clear();
}
}
continue;
case User::STATE_CLOSING:
{
if (((curUser->m_ui32BoolBits & User::BIT_ERROR) == User::BIT_ERROR) == false && curUser->m_ui32SendBufDataLen != 0)
{
if (curUser->m_LogInOut.m_ui32ToCloseLoops != 0 || ((curUser->m_ui32BoolBits & User::BIT_PINGER) == User::BIT_PINGER) == true)
{
curUser->Try2Send();
curUser->m_LogInOut.m_ui32ToCloseLoops--;
continue;
}
}
curUser->m_ui8State = User::STATE_REMME;
continue;
}
// if user is marked as dead, remove him
case User::STATE_REMME:
{
shutdown_and_close(curUser->m_Socket, SHUT_RD);
// linked list
Users::m_Ptr->RemUser(curUser);
delete curUser;
continue;
}
default:
{
// check logon timeout
if (ServerManager::m_ui64ActualTick - curUser->m_LogInOut.m_ui64LogonTick > 60)
{
UdpDebug::m_Ptr->BroadcastFormat("[SYS] Login timeout (%d) 2 for %s (%s) - user disconnected.", (int)curUser->m_ui8State, curUser->m_sNick, curUser->m_sIP);
curUser->Close();
continue;
}
break;
}
}
}
if (ServerManager::m_ui8SrCntr == 0)
{
Users::m_Ptr->m_ui16ActSearchs = 0;
Users::m_Ptr->m_ui16PasSearchs = 0;
}
m_ui32LastRecvRest = iRecvRests;
m_ui32RecvRestsPeak = iRecvRests > m_ui32RecvRestsPeak ? iRecvRests : m_ui32RecvRestsPeak;
}
//---------------------------------------------------------------------------
void ServiceLoop::SendLoop()
{
GlobalDataQueue::m_Ptr->PrepareQueueItems();
// PPK ... send loop
// now logging users get changed myinfo with myinfos
// old users get it in this loop from queue -> badwith saving !!! no more twice myinfo =)
// Sending Loop
uint32_t iSendRests = 0;
User * curUser = NULL,
* nextUser = Users::m_Ptr->m_pUserListS;
while (nextUser != 0 && ServerManager::m_bServerTerminated == false)
{
curUser = nextUser;
nextUser = curUser->m_pNext;
switch (curUser->m_ui8State)
{
case User::STATE_ADDME_2LOOP:
{
// alex82 ... HideUser / ������� �����
if (((curUser->m_ui32InfoBits & User::INFOBIT_HIDDEN) == User::INFOBIT_HIDDEN) == false)
{
ServerManager::m_ui32Logged++;
}
if (ServerManager::m_ui32Peak < ServerManager::m_ui32Logged)
{
ServerManager::m_ui32Peak = ServerManager::m_ui32Logged;
if (SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_USERS_PEAK] < (int16_t)ServerManager::m_ui32Peak)
SettingManager::m_Ptr->SetShort(SETSHORT_MAX_USERS_PEAK, (int16_t)ServerManager::m_ui32Peak);
}
curUser->m_ui8State = User::STATE_ADDED;
// finaly send the nicklist/myinfos/oplist
curUser->AddUserList();
// PPK ... UserIP2 supports
if (((curUser->m_ui32SupportBits & User::SUPPORTBIT_USERIP2) == User::SUPPORTBIT_USERIP2) == true && ((curUser->m_ui32BoolBits & User::BIT_QUACK_SUPPORTS) == User::BIT_QUACK_SUPPORTS) == false && ProfileManager::m_Ptr->IsAllowed(curUser, ProfileManager::SENDALLUSERIP) == false)
{
curUser->SendFormat("ServiceLoop::SendLoop->User::STATE_ADDME_2LOOP1", true, "$UserIP %s %s|", curUser->m_sNick, (curUser->m_sIPv4[0] == '\0' ? curUser->m_sIP : curUser->m_sIPv4));
}
curUser->m_ui32BoolBits &= ~User::BIT_GETNICKLIST;
// PPK ... send motd ???
if (SettingManager::m_Ptr->m_ui16PreTextsLens[SettingManager::SETPRETXT_MOTD] != 0)
{
if (SettingManager::m_Ptr->m_bBools[SETBOOL_MOTD_AS_PM] == true)
{
curUser->SendFormat("ServiceLoop::SendLoop->User::STATE_ADDME_2LOOP2", true, SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_MOTD], curUser->m_sNick);
}
else
{
curUser->SendCharDelayed(SettingManager::m_Ptr->m_sPreTexts[SettingManager::SETPRETXT_MOTD], SettingManager::m_Ptr->m_ui16PreTextsLens[SettingManager::SETPRETXT_MOTD]);
}
}
// check for Debug subscription
if (((curUser->m_ui32BoolBits & User::BIT_OPERATOR) == User::BIT_OPERATOR) == true)
UdpDebug::m_Ptr->CheckUdpSub(curUser, true);
if (curUser->m_LogInOut.m_ui32UserConnectedLen != 0)
{
curUser->PutInSendBuf(curUser->m_LogInOut.m_pBuffer, curUser->m_LogInOut.m_ui32UserConnectedLen);
curUser->FreeBuffer();
}
// Login struct no more needed, free mem ! ;)
curUser->m_LogInOut.Clean();
// PPK ... send all login data from buffer !
curUser->Try2Send();
// apply one loop delay to avoid double sending of hello and oplist
continue;
}
case User::STATE_ADDED:
{
if (((curUser->m_ui32BoolBits & User::BIT_GETNICKLIST) == User::BIT_GETNICKLIST) == true)
{
curUser->AddUserList();
curUser->m_ui32BoolBits &= ~User::BIT_GETNICKLIST;
}
// process global data queues
if (GlobalDataQueue::m_Ptr->m_bHaveItems == true)
{
GlobalDataQueue::m_Ptr->ProcessQueues(curUser);
}
if (GlobalDataQueue::m_Ptr->m_pSingleItems != NULL)
{
GlobalDataQueue::m_Ptr->ProcessSingleItems(curUser);
}
// send data acumulated by queues above
// if sending caused error, close the user
if (curUser->m_ui32SendBufDataLen != 0)
{
// PPK ... true = we have rest ;)
if (curUser->Try2Send() == true)
{
iSendRests++;
}
}
break;
}
case User::STATE_CLOSING:
case User::STATE_REMME:
continue;
default:
curUser->Try2Send();
break;
}
}
GlobalDataQueue::m_Ptr->ClearQueues();
if (m_ui32LoopsForLogins >= 40)
{
m_dLoggedUsers = 0;
m_ui32LoopsForLogins = 0;
m_dActualSrvLoopLogins = 0;
}
m_dActualSrvLoopLogins += (double)SettingManager::m_Ptr->m_i16Shorts[SETSHORT_MAX_SIMULTANEOUS_LOGINS] / 40;
m_ui32LoopsForLogins++;
m_ui32LastSendRest = iSendRests;
m_ui32SendRestsPeak = iSendRests > m_ui32SendRestsPeak ? iSendRests : m_ui32SendRestsPeak;
}
//---------------------------------------------------------------------------
#ifdef _WIN32
void ServiceLoop::AcceptSocket(SOCKET &s, const sockaddr_storage &addr)
{
#else
void ServiceLoop::AcceptSocket(int& s, const sockaddr_storage &addr)
{
#endif
AcceptedSocket * pNewSocket = new (std::nothrow) AcceptedSocket;
if (pNewSocket == NULL)
{
shutdown_and_close(s, SHUT_RDWR);
AppendDebugLog("%s - [MEM] Cannot allocate pNewSocket in ServiceLoop::AcceptSocket\n");
return;
}
pNewSocket->m_Socket = s;
memcpy(&pNewSocket->m_Addr, &addr, sizeof(sockaddr_storage));
pNewSocket->m_pNext = NULL;
Lock l(m_csAcceptQueue);
if (m_pAcceptedSocketsS == NULL)
{
m_pAcceptedSocketsS = pNewSocket;
m_pAcceptedSocketsE = pNewSocket;
}
else
{
m_pAcceptedSocketsE->m_pNext = pNewSocket;
m_pAcceptedSocketsE = pNewSocket;
}
}
//---------------------------------------------------------------------------
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: m_Addr.
↑ V1042 This file is marked with copyleft license, which requires you to open the derived source code.
↑ V641 The size of the '& pAccptSocket->m_Addr' buffer is not a multiple of the element size of the type 'struct sockaddr_in6'.
↑ V641 The size of the '& pAccptSocket->m_Addr' buffer is not a multiple of the element size of the type 'struct sockaddr_in6'.
↑ V641 The size of the '& pAccptSocket->m_Addr' buffer is not a multiple of the element size of the type 'struct sockaddr_in6'.
↑ V641 The size of the '& pAccptSocket->m_Addr' buffer is not a multiple of the element size of the type 'struct sockaddr_in6'.