mirror of
https://github.com/mangosfour/server.git
synced 2025-12-20 07:37:02 +00:00
* Add #include <stdio.h> to some fiels where related functions call. * Avoid template dependent lookup for fields in class LockedQueue.
1423 lines
32 KiB
C++
1423 lines
32 KiB
C++
/** \file SocketHandler.cpp
|
|
** \date 2004-02-13
|
|
** \author grymse@alhem.net
|
|
**/
|
|
/*
|
|
Copyright (C) 2004-2007 Anders Hedstrom
|
|
|
|
This library is made available under the terms of the GNU GPL.
|
|
|
|
If you would like to use this library in a closed-source application,
|
|
a separate license agreement is available. For information about
|
|
the closed-source license agreement for the C++ sockets library,
|
|
please visit http://www.alhem.net/Sockets/license.html and/or
|
|
email license@alhem.net.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
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, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
#ifdef _WIN32
|
|
#ifdef _MSC_VER
|
|
#pragma warning(disable:4786)
|
|
#endif
|
|
#endif
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
|
|
#include "SocketHandler.h"
|
|
#include "UdpSocket.h"
|
|
#include "ResolvSocket.h"
|
|
#include "ResolvServer.h"
|
|
#include "TcpSocket.h"
|
|
#include "Mutex.h"
|
|
#include "Utility.h"
|
|
#include "SocketAddress.h"
|
|
|
|
#ifdef SOCKETS_NAMESPACE
|
|
namespace SOCKETS_NAMESPACE {
|
|
#endif
|
|
|
|
|
|
//#ifdef _DEBUG
|
|
//#define DEB(x) x; fflush(stderr);
|
|
//#else
|
|
#define DEB(x)
|
|
//#endif
|
|
|
|
|
|
SocketHandler::SocketHandler(StdLog *p)
|
|
:m_stdlog(p)
|
|
,m_mutex(m_mutex)
|
|
,m_b_use_mutex(false)
|
|
,m_maxsock(0)
|
|
,m_preverror(-1)
|
|
,m_errcnt(0)
|
|
,m_tlast(0)
|
|
#ifdef ENABLE_SOCKS4
|
|
,m_socks4_host(0)
|
|
,m_socks4_port(0)
|
|
,m_bTryDirect(false)
|
|
#endif
|
|
#ifdef ENABLE_RESOLVER
|
|
,m_resolv_id(0)
|
|
,m_resolver(NULL)
|
|
#endif
|
|
#ifdef ENABLE_POOL
|
|
,m_b_enable_pool(false)
|
|
#endif
|
|
#ifdef ENABLE_TRIGGERS
|
|
,m_next_trigger_id(0)
|
|
#endif
|
|
#ifdef ENABLE_DETACH
|
|
,m_slave(false)
|
|
#endif
|
|
{
|
|
FD_ZERO(&m_rfds);
|
|
FD_ZERO(&m_wfds);
|
|
FD_ZERO(&m_efds);
|
|
}
|
|
|
|
|
|
SocketHandler::SocketHandler(Mutex& mutex,StdLog *p)
|
|
:m_stdlog(p)
|
|
,m_mutex(mutex)
|
|
,m_b_use_mutex(true)
|
|
,m_maxsock(0)
|
|
,m_preverror(-1)
|
|
,m_errcnt(0)
|
|
,m_tlast(0)
|
|
#ifdef ENABLE_SOCKS4
|
|
,m_socks4_host(0)
|
|
,m_socks4_port(0)
|
|
,m_bTryDirect(false)
|
|
#endif
|
|
#ifdef ENABLE_RESOLVER
|
|
,m_resolv_id(0)
|
|
,m_resolver(NULL)
|
|
#endif
|
|
#ifdef ENABLE_POOL
|
|
,m_b_enable_pool(false)
|
|
#endif
|
|
#ifdef ENABLE_TRIGGERS
|
|
,m_next_trigger_id(0)
|
|
#endif
|
|
#ifdef ENABLE_DETACH
|
|
,m_slave(false)
|
|
#endif
|
|
{
|
|
m_mutex.Lock();
|
|
FD_ZERO(&m_rfds);
|
|
FD_ZERO(&m_wfds);
|
|
FD_ZERO(&m_efds);
|
|
}
|
|
|
|
|
|
SocketHandler::~SocketHandler()
|
|
{
|
|
#ifdef ENABLE_RESOLVER
|
|
if (m_resolver)
|
|
{
|
|
m_resolver -> Quit();
|
|
}
|
|
#endif
|
|
{
|
|
while (m_sockets.size())
|
|
{
|
|
DEB( fprintf(stderr, "Emptying sockets list in SocketHandler destructor, %d instances\n", (int)m_sockets.size());)
|
|
socket_m::iterator it = m_sockets.begin();
|
|
Socket *p = it -> second;
|
|
if (p)
|
|
{
|
|
DEB( fprintf(stderr, " fd %d\n", p -> GetSocket());)
|
|
p -> Close();
|
|
DEB( fprintf(stderr, " fd closed %d\n", p -> GetSocket());)
|
|
// p -> OnDelete(); // hey, I turn this back on. what's the worst that could happen??!!
|
|
// MinionSocket breaks, calling MinderHandler methods in OnDelete -
|
|
// MinderHandler is already gone when that happens...
|
|
|
|
// only delete socket when controlled
|
|
// ie master sockethandler can delete non-detached sockets
|
|
// and a slave sockethandler can only delete a detach socket
|
|
if (p -> DeleteByHandler()
|
|
#ifdef ENABLE_DETACH
|
|
&& !(m_slave ^ p -> IsDetached())
|
|
#endif
|
|
)
|
|
{
|
|
p -> SetErasedByHandler();
|
|
delete p;
|
|
}
|
|
m_sockets.erase(it);
|
|
}
|
|
else
|
|
{
|
|
m_sockets.erase(it);
|
|
}
|
|
DEB( fprintf(stderr, "next\n");)
|
|
}
|
|
DEB( fprintf(stderr, "/Emptying sockets list in SocketHandler destructor, %d instances\n", (int)m_sockets.size());)
|
|
}
|
|
#ifdef ENABLE_RESOLVER
|
|
if (m_resolver)
|
|
{
|
|
delete m_resolver;
|
|
}
|
|
#endif
|
|
if (m_b_use_mutex)
|
|
{
|
|
m_mutex.Unlock();
|
|
}
|
|
}
|
|
|
|
|
|
Mutex& SocketHandler::GetMutex() const
|
|
{
|
|
return m_mutex;
|
|
}
|
|
|
|
|
|
#ifdef ENABLE_DETACH
|
|
void SocketHandler::SetSlave(bool x)
|
|
{
|
|
m_slave = x;
|
|
}
|
|
|
|
|
|
bool SocketHandler::IsSlave()
|
|
{
|
|
return m_slave;
|
|
}
|
|
#endif
|
|
|
|
|
|
void SocketHandler::RegStdLog(StdLog *log)
|
|
{
|
|
m_stdlog = log;
|
|
}
|
|
|
|
|
|
void SocketHandler::LogError(Socket *p,const std::string& user_text,int err,const std::string& sys_err,loglevel_t t)
|
|
{
|
|
if (m_stdlog)
|
|
{
|
|
m_stdlog -> error(this, p, user_text, err, sys_err, t);
|
|
}
|
|
}
|
|
|
|
|
|
void SocketHandler::Add(Socket *p)
|
|
{
|
|
if (p -> GetSocket() == INVALID_SOCKET)
|
|
{
|
|
LogError(p, "Add", -1, "Invalid socket", LOG_LEVEL_WARNING);
|
|
if (p -> CloseAndDelete())
|
|
{
|
|
m_delete.push_back(p);
|
|
}
|
|
return;
|
|
}
|
|
if (m_add.find(p -> GetSocket()) != m_add.end())
|
|
{
|
|
LogError(p, "Add", (int)p -> GetSocket(), "Attempt to add socket already in add queue", LOG_LEVEL_FATAL);
|
|
m_delete.push_back(p);
|
|
return;
|
|
}
|
|
m_add[p -> GetSocket()] = p;
|
|
}
|
|
|
|
|
|
void SocketHandler::Get(SOCKET s,bool& r,bool& w,bool& e)
|
|
{
|
|
if (s >= 0)
|
|
{
|
|
r = FD_ISSET(s, &m_rfds) ? true : false;
|
|
w = FD_ISSET(s, &m_wfds) ? true : false;
|
|
e = FD_ISSET(s, &m_efds) ? true : false;
|
|
}
|
|
}
|
|
|
|
|
|
void SocketHandler::Set(SOCKET s,bool bRead,bool bWrite,bool bException)
|
|
{
|
|
DEB( fprintf(stderr, "Set(%d, %s, %s, %s)\n", s, bRead ? "true" : "false", bWrite ? "true" : "false", bException ? "true" : "false");)
|
|
if (s >= 0)
|
|
{
|
|
if (bRead)
|
|
{
|
|
if (!FD_ISSET(s, &m_rfds))
|
|
{
|
|
FD_SET(s, &m_rfds);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FD_CLR(s, &m_rfds);
|
|
}
|
|
if (bWrite)
|
|
{
|
|
if (!FD_ISSET(s, &m_wfds))
|
|
{
|
|
FD_SET(s, &m_wfds);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FD_CLR(s, &m_wfds);
|
|
}
|
|
if (bException)
|
|
{
|
|
if (!FD_ISSET(s, &m_efds))
|
|
{
|
|
FD_SET(s, &m_efds);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FD_CLR(s, &m_efds);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int SocketHandler::Select(long sec,long usec)
|
|
{
|
|
struct timeval tv;
|
|
tv.tv_sec = sec;
|
|
tv.tv_usec = usec;
|
|
return Select(&tv);
|
|
}
|
|
|
|
|
|
int SocketHandler::Select()
|
|
{
|
|
if (!m_fds_callonconnect.empty() ||
|
|
#ifdef ENABLE_DETACH
|
|
(!m_slave && !m_fds_detach.empty()) ||
|
|
#endif
|
|
!m_fds_timeout.empty() ||
|
|
!m_fds_retry.empty() ||
|
|
!m_fds_close.empty() ||
|
|
!m_fds_erase.empty())
|
|
{
|
|
return Select(0, 200000);
|
|
}
|
|
return Select(NULL);
|
|
}
|
|
|
|
|
|
int SocketHandler::Select(struct timeval *tsel)
|
|
{
|
|
size_t ignore = 0;
|
|
while (m_add.size() > ignore)
|
|
{
|
|
if (m_sockets.size() >= FD_SETSIZE)
|
|
{
|
|
LogError(NULL, "Select", (int)m_sockets.size(), "FD_SETSIZE reached", LOG_LEVEL_WARNING);
|
|
break;
|
|
}
|
|
socket_m::iterator it = m_add.begin();
|
|
SOCKET s = it -> first;
|
|
Socket *p = it -> second;
|
|
DEB( fprintf(stderr, "Trying to add fd %d, m_add.size() %d, ignore %d\n", (int)s, (int)m_add.size(), (int)ignore);)
|
|
//
|
|
if (m_sockets.find(p -> GetSocket()) != m_sockets.end())
|
|
{
|
|
LogError(p, "Add", (int)p -> GetSocket(), "Attempt to add socket already in controlled queue", LOG_LEVEL_FATAL);
|
|
// %! it's a dup, don't add to delete queue, just ignore it
|
|
m_delete.push_back(p);
|
|
m_add.erase(it);
|
|
// ignore++;
|
|
continue;
|
|
}
|
|
if (!p -> CloseAndDelete())
|
|
{
|
|
StreamSocket *scp = dynamic_cast<StreamSocket *>(p);
|
|
if (scp && scp -> Connecting()) // 'Open' called before adding socket
|
|
{
|
|
Set(s,false,true);
|
|
}
|
|
else
|
|
{
|
|
TcpSocket *tcp = dynamic_cast<TcpSocket *>(p);
|
|
bool bWrite = tcp ? tcp -> GetOutputLength() != 0 : false;
|
|
if (p -> IsDisableRead())
|
|
{
|
|
Set(s, false, bWrite);
|
|
}
|
|
else
|
|
{
|
|
Set(s, true, bWrite);
|
|
}
|
|
}
|
|
m_maxsock = (s > m_maxsock) ? s : m_maxsock;
|
|
}
|
|
else
|
|
{
|
|
LogError(p, "Add", (int)p -> GetSocket(), "Trying to add socket with SetCloseAndDelete() true", LOG_LEVEL_WARNING);
|
|
}
|
|
// only add to m_fds (process fd_set events) if
|
|
// slave handler and detached/detaching socket
|
|
// master handler and non-detached socket
|
|
#ifdef ENABLE_DETACH
|
|
if (!(m_slave ^ p -> IsDetach()))
|
|
#endif
|
|
{
|
|
m_fds.push_back(s);
|
|
}
|
|
m_sockets[s] = p;
|
|
//
|
|
m_add.erase(it);
|
|
}
|
|
#ifdef MACOSX
|
|
fd_set rfds;
|
|
fd_set wfds;
|
|
fd_set efds;
|
|
FD_COPY(&m_rfds, &rfds);
|
|
FD_COPY(&m_wfds, &wfds);
|
|
FD_COPY(&m_efds, &efds);
|
|
#else
|
|
fd_set rfds = m_rfds;
|
|
fd_set wfds = m_wfds;
|
|
fd_set efds = m_efds;
|
|
#endif
|
|
int n;
|
|
if (m_b_use_mutex)
|
|
{
|
|
m_mutex.Unlock();
|
|
n = select( (int)(m_maxsock + 1),&rfds,&wfds,&efds,tsel);
|
|
m_mutex.Lock();
|
|
}
|
|
else
|
|
{
|
|
n = select( (int)(m_maxsock + 1),&rfds,&wfds,&efds,tsel);
|
|
}
|
|
if (n == -1)
|
|
{
|
|
/*
|
|
EBADF An invalid file descriptor was given in one of the sets.
|
|
EINTR A non blocked signal was caught.
|
|
EINVAL n is negative. Or struct timeval contains bad time values (<0).
|
|
ENOMEM select was unable to allocate memory for internal tables.
|
|
*/
|
|
if (Errno != m_preverror || m_errcnt++ % 10000 == 0)
|
|
{
|
|
LogError(NULL, "select", Errno, StrError(Errno));
|
|
DEB( fprintf(stderr, "m_maxsock: %d\n", m_maxsock);
|
|
fprintf(stderr, "%s\n", Errno == EINVAL ? "EINVAL" :
|
|
Errno == EINTR ? "EINTR" :
|
|
Errno == EBADF ? "EBADF" :
|
|
Errno == ENOMEM ? "ENOMEM" : "<another>");
|
|
// test bad fd
|
|
for (SOCKET i = 0; i <= m_maxsock; i++)
|
|
{
|
|
bool t = false;
|
|
FD_ZERO(&rfds);
|
|
FD_ZERO(&wfds);
|
|
FD_ZERO(&efds);
|
|
if (FD_ISSET(i, &m_rfds))
|
|
{
|
|
FD_SET(i, &rfds);
|
|
t = true;
|
|
}
|
|
if (FD_ISSET(i, &m_wfds))
|
|
{
|
|
FD_SET(i, &wfds);
|
|
t = true;
|
|
}
|
|
if (FD_ISSET(i, &m_efds))
|
|
{
|
|
FD_SET(i, &efds);
|
|
t = true;
|
|
}
|
|
if (t && m_sockets.find(i) == m_sockets.end())
|
|
{
|
|
fprintf(stderr, "Bad fd in fd_set: %d\n", i);
|
|
}
|
|
}
|
|
) // DEB
|
|
m_preverror = Errno;
|
|
}
|
|
/// \todo rebuild fd_set's from active sockets list (m_sockets) here
|
|
}
|
|
else
|
|
if (!n)
|
|
{
|
|
m_preverror = -1;
|
|
}
|
|
else
|
|
if (n > 0)
|
|
{
|
|
for (socket_v::iterator it2 = m_fds.begin(); it2 != m_fds.end() && n; it2++)
|
|
{
|
|
SOCKET i = *it2;
|
|
if (FD_ISSET(i, &rfds))
|
|
{
|
|
socket_m::iterator itmp = m_sockets.find(i);
|
|
if (itmp != m_sockets.end()) // found
|
|
{
|
|
Socket *p = itmp -> second;
|
|
// new SSL negotiate method
|
|
#ifdef HAVE_OPENSSL
|
|
if (p -> IsSSLNegotiate())
|
|
{
|
|
p -> SSLNegotiate();
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
p -> OnRead();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogError(NULL, "GetSocket/handler/1", (int)i, "Did not find expected socket using file descriptor", LOG_LEVEL_WARNING);
|
|
}
|
|
n--;
|
|
}
|
|
if (FD_ISSET(i, &wfds))
|
|
{
|
|
socket_m::iterator itmp = m_sockets.find(i);
|
|
if (itmp != m_sockets.end()) // found
|
|
{
|
|
Socket *p = itmp -> second;
|
|
// new SSL negotiate method
|
|
#ifdef HAVE_OPENSSL
|
|
if (p -> IsSSLNegotiate())
|
|
{
|
|
p -> SSLNegotiate();
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
p -> OnWrite();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogError(NULL, "GetSocket/handler/2", (int)i, "Did not find expected socket using file descriptor", LOG_LEVEL_WARNING);
|
|
}
|
|
n--;
|
|
}
|
|
if (FD_ISSET(i, &efds))
|
|
{
|
|
socket_m::iterator itmp = m_sockets.find(i);
|
|
if (itmp != m_sockets.end()) // found
|
|
{
|
|
Socket *p = itmp -> second;
|
|
p -> OnException();
|
|
}
|
|
else
|
|
{
|
|
LogError(NULL, "GetSocket/handler/3", (int)i, "Did not find expected socket using file descriptor", LOG_LEVEL_WARNING);
|
|
}
|
|
n--;
|
|
}
|
|
} // m_fds loop
|
|
m_preverror = -1;
|
|
} // if (n > 0)
|
|
|
|
// check CallOnConnect - EVENT
|
|
if (!m_fds_callonconnect.empty())
|
|
{
|
|
socket_v tmp = m_fds_callonconnect;
|
|
for (socket_v::iterator it = tmp.begin(); it != tmp.end(); it++)
|
|
{
|
|
Socket *p = NULL;
|
|
{
|
|
socket_m::iterator itmp = m_sockets.find(*it);
|
|
if (itmp != m_sockets.end()) // found
|
|
{
|
|
p = itmp -> second;
|
|
}
|
|
else
|
|
{
|
|
LogError(NULL, "GetSocket/handler/4", (int)*it, "Did not find expected socket using file descriptor", LOG_LEVEL_WARNING);
|
|
}
|
|
}
|
|
if (p)
|
|
{
|
|
// if (p -> CallOnConnect() && p -> Ready() )
|
|
{
|
|
p -> SetConnected(); // moved here from inside if (tcp) check below
|
|
#ifdef HAVE_OPENSSL
|
|
if (p -> IsSSL()) // SSL Enabled socket
|
|
p -> OnSSLConnect();
|
|
else
|
|
#endif
|
|
#ifdef ENABLE_SOCKS4
|
|
if (p -> Socks4())
|
|
p -> OnSocks4Connect();
|
|
else
|
|
#endif
|
|
{
|
|
TcpSocket *tcp = dynamic_cast<TcpSocket *>(p);
|
|
if (tcp)
|
|
{
|
|
if (tcp -> GetOutputLength())
|
|
{
|
|
p -> OnWrite();
|
|
}
|
|
}
|
|
#ifdef ENABLE_RECONNECT
|
|
if (tcp && tcp -> IsReconnect())
|
|
p -> OnReconnect();
|
|
else
|
|
#endif
|
|
{
|
|
// LogError(p, "Calling OnConnect", 0, "Because CallOnConnect", LOG_LEVEL_INFO);
|
|
p -> OnConnect();
|
|
}
|
|
}
|
|
// p -> SetCallOnConnect( false );
|
|
AddList(p -> GetSocket(), LIST_CALLONCONNECT, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#ifdef ENABLE_DETACH
|
|
// check detach of socket if master handler - EVENT
|
|
if (!m_slave && !m_fds_detach.empty())
|
|
{
|
|
// %! why not using tmp list here??!?
|
|
for (socket_v::iterator it = m_fds_detach.begin(); it != m_fds_detach.end(); it++)
|
|
{
|
|
Socket *p = NULL;
|
|
{
|
|
socket_m::iterator itmp = m_sockets.find(*it);
|
|
if (itmp != m_sockets.end()) // found
|
|
{
|
|
p = itmp -> second;
|
|
}
|
|
else
|
|
{
|
|
LogError(NULL, "GetSocket/handler/5", (int)*it, "Did not find expected socket using file descriptor", LOG_LEVEL_WARNING);
|
|
}
|
|
}
|
|
if (p)
|
|
{
|
|
// if (p -> IsDetach())
|
|
{
|
|
Set(p -> GetSocket(), false, false, false);
|
|
// After DetachSocket(), all calls to Handler() will return a reference
|
|
// to the new slave SocketHandler running in the new thread.
|
|
p -> DetachSocket();
|
|
// Adding the file descriptor to m_fds_erase will now also remove the
|
|
// socket from the detach queue - tnx knightmad
|
|
m_fds_erase.push_back(p -> GetSocket());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
// check Connecting - connection timeout - conditional event
|
|
if (m_fds_timeout.size())
|
|
{
|
|
time_t tnow = time(NULL);
|
|
if (tnow != m_tlast)
|
|
{
|
|
socket_v tmp = m_fds_timeout;
|
|
DEB( fprintf(stderr, "Checking %d socket(s) for timeout\n", tmp.size());)
|
|
for (socket_v::iterator it = tmp.begin(); it != tmp.end(); it++)
|
|
{
|
|
Socket *p = NULL;
|
|
{
|
|
socket_m::iterator itmp = m_sockets.find(*it);
|
|
if (itmp != m_sockets.end()) // found
|
|
{
|
|
p = itmp -> second;
|
|
}
|
|
else
|
|
{
|
|
itmp = m_add.find(*it);
|
|
if (itmp != m_add.end())
|
|
{
|
|
p = itmp -> second;
|
|
}
|
|
else
|
|
{
|
|
LogError(NULL, "GetSocket/handler/6", (int)*it, "Did not find expected socket using file descriptor", LOG_LEVEL_WARNING);
|
|
}
|
|
}
|
|
}
|
|
if (p)
|
|
{
|
|
if (p -> Timeout(tnow))
|
|
{
|
|
StreamSocket *scp = dynamic_cast<StreamSocket *>(p);
|
|
if (scp && scp -> Connecting())
|
|
p -> OnConnectTimeout();
|
|
else
|
|
p -> OnTimeout();
|
|
p -> SetTimeout(0);
|
|
}
|
|
}
|
|
}
|
|
m_tlast = tnow;
|
|
} // tnow != tlast
|
|
}
|
|
// check retry client connect - EVENT
|
|
if (!m_fds_retry.empty())
|
|
{
|
|
socket_v tmp = m_fds_retry;
|
|
for (socket_v::iterator it = tmp.begin(); it != tmp.end(); it++)
|
|
{
|
|
Socket *p = NULL;
|
|
{
|
|
socket_m::iterator itmp = m_sockets.find(*it);
|
|
if (itmp != m_sockets.end()) // found
|
|
{
|
|
p = itmp -> second;
|
|
}
|
|
else
|
|
{
|
|
LogError(NULL, "GetSocket/handler/7", (int)*it, "Did not find expected socket using file descriptor", LOG_LEVEL_WARNING);
|
|
}
|
|
}
|
|
if (p)
|
|
{
|
|
// if (p -> RetryClientConnect())
|
|
{
|
|
TcpSocket *tcp = dynamic_cast<TcpSocket *>(p);
|
|
SOCKET nn = *it; //(*it3).first;
|
|
tcp -> SetRetryClientConnect(false);
|
|
DEB( fprintf(stderr, "Close() before retry client connect\n");)
|
|
p -> Close(); // removes from m_fds_retry
|
|
std::auto_ptr<SocketAddress> ad = p -> GetClientRemoteAddress();
|
|
if (ad.get())
|
|
{
|
|
tcp -> Open(*ad);
|
|
}
|
|
else
|
|
{
|
|
LogError(p, "RetryClientConnect", 0, "no address", LOG_LEVEL_ERROR);
|
|
}
|
|
Add(p);
|
|
m_fds_erase.push_back(nn);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// check close and delete - conditional event
|
|
if (!m_fds_close.empty())
|
|
{
|
|
socket_v tmp = m_fds_close;
|
|
DEB( fprintf(stderr, "m_fds_close.size() == %d\n", (int)m_fds_close.size());)
|
|
for (socket_v::iterator it = tmp.begin(); it != tmp.end(); it++)
|
|
{
|
|
Socket *p = NULL;
|
|
{
|
|
socket_m::iterator itmp = m_sockets.find(*it);
|
|
if (itmp != m_sockets.end()) // found
|
|
{
|
|
p = itmp -> second;
|
|
}
|
|
else
|
|
{
|
|
itmp = m_add.find(*it);
|
|
if (itmp != m_add.end())
|
|
{
|
|
p = itmp -> second;
|
|
}
|
|
else
|
|
{
|
|
LogError(NULL, "GetSocket/handler/8", (int)*it, "Did not find expected socket using file descriptor", LOG_LEVEL_WARNING);
|
|
}
|
|
}
|
|
}
|
|
if (p)
|
|
{
|
|
// if (p -> CloseAndDelete() )
|
|
{
|
|
TcpSocket *tcp = dynamic_cast<TcpSocket *>(p);
|
|
// new graceful tcp - flush and close timeout 5s
|
|
if (tcp && p -> IsConnected() && tcp -> GetFlushBeforeClose() &&
|
|
#ifdef HAVE_OPENSSL
|
|
!tcp -> IsSSL() &&
|
|
#endif
|
|
p -> TimeSinceClose() < 5)
|
|
{
|
|
DEB( fprintf(stderr, " close(1)\n");)
|
|
if (tcp -> GetOutputLength())
|
|
{
|
|
LogError(p, "Closing", (int)tcp -> GetOutputLength(), "Sending all data before closing", LOG_LEVEL_INFO);
|
|
}
|
|
else // shutdown write when output buffer is empty
|
|
if (!(tcp -> GetShutdown() & SHUT_WR))
|
|
{
|
|
SOCKET nn = *it;
|
|
if (nn != INVALID_SOCKET && shutdown(nn, SHUT_WR) == -1)
|
|
{
|
|
LogError(p, "graceful shutdown", Errno, StrError(Errno), LOG_LEVEL_ERROR);
|
|
}
|
|
tcp -> SetShutdown(SHUT_WR);
|
|
}
|
|
}
|
|
else
|
|
#ifdef ENABLE_RECONNECT
|
|
if (tcp && p -> IsConnected() && tcp -> Reconnect())
|
|
{
|
|
SOCKET nn = *it; //(*it3).first;
|
|
DEB( fprintf(stderr, " close(2) fd %d\n", nn);)
|
|
p -> SetCloseAndDelete(false);
|
|
tcp -> SetIsReconnect();
|
|
p -> SetConnected(false);
|
|
DEB( fprintf(stderr, "Close() before reconnect\n");)
|
|
p -> Close(); // dispose of old file descriptor (Open creates a new)
|
|
p -> OnDisconnect();
|
|
std::auto_ptr<SocketAddress> ad = p -> GetClientRemoteAddress();
|
|
if (ad.get())
|
|
{
|
|
tcp -> Open(*ad);
|
|
}
|
|
else
|
|
{
|
|
LogError(p, "Reconnect", 0, "no address", LOG_LEVEL_ERROR);
|
|
}
|
|
tcp -> ResetConnectionRetries();
|
|
Add(p);
|
|
m_fds_erase.push_back(nn);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
SOCKET nn = *it; //(*it3).first;
|
|
DEB( fprintf(stderr, " close(3) fd %d GetSocket() %d\n", nn, p -> GetSocket());)
|
|
if (tcp && p -> IsConnected() && tcp -> GetOutputLength())
|
|
{
|
|
LogError(p, "Closing", (int)tcp -> GetOutputLength(), "Closing socket while data still left to send", LOG_LEVEL_WARNING);
|
|
}
|
|
#ifdef ENABLE_POOL
|
|
if (p -> Retain() && !p -> Lost())
|
|
{
|
|
PoolSocket *p2 = new PoolSocket(*this, p);
|
|
p2 -> SetDeleteByHandler();
|
|
Add(p2);
|
|
//
|
|
p -> SetCloseAndDelete(false); // added - remove from m_fds_close
|
|
}
|
|
else
|
|
#endif // ENABLE_POOL
|
|
{
|
|
Set(p -> GetSocket(),false,false,false);
|
|
DEB( fprintf(stderr, "Close() before OnDelete\n");)
|
|
p -> Close();
|
|
}
|
|
p -> OnDelete();
|
|
if (p -> DeleteByHandler())
|
|
{
|
|
p -> SetErasedByHandler();
|
|
}
|
|
m_fds_erase.push_back(nn);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// check erased sockets
|
|
bool check_max_fd = false;
|
|
while (!m_fds_erase.empty())
|
|
{
|
|
socket_v::iterator it = m_fds_erase.begin();
|
|
SOCKET nn = *it;
|
|
#ifdef ENABLE_DETACH
|
|
{
|
|
for (socket_v::iterator it = m_fds_detach.begin(); it != m_fds_detach.end(); it++)
|
|
{
|
|
if (*it == nn)
|
|
{
|
|
m_fds_detach.erase(it);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
{
|
|
for (socket_v::iterator it = m_fds.begin(); it != m_fds.end(); it++)
|
|
{
|
|
if (*it == nn)
|
|
{
|
|
m_fds.erase(it);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
{
|
|
socket_m::iterator it = m_sockets.find(nn);
|
|
if (it != m_sockets.end())
|
|
{
|
|
Socket *p = it -> second;
|
|
/* Sometimes a SocketThread class can finish its run before the master
|
|
sockethandler gets here. In that case, the SocketThread has set the
|
|
'ErasedByHandler' flag on the socket which will make us end up with a
|
|
double delete on the socket instance.
|
|
The fix is to make sure that the master sockethandler only can delete
|
|
non-detached sockets, and a slave sockethandler only can delete
|
|
detach sockets. */
|
|
if (p -> ErasedByHandler()
|
|
#ifdef ENABLE_DETACH
|
|
&& !(m_slave ^ p -> IsDetached())
|
|
#endif
|
|
)
|
|
{
|
|
#ifdef ENABLE_TRIGGERS
|
|
bool again = false;
|
|
do
|
|
{
|
|
again = false;
|
|
for (std::map<int, Socket *>::iterator it = m_trigger_src.begin(); it != m_trigger_src.end(); it++)
|
|
{
|
|
int id = it -> first;
|
|
Socket *src = it -> second;
|
|
if (src == p)
|
|
{
|
|
for (std::map<Socket *, bool>::iterator it = m_trigger_dst[id].begin(); it != m_trigger_dst[id].end(); it++)
|
|
{
|
|
Socket *dst = it -> first;
|
|
if (Valid(dst))
|
|
{
|
|
dst -> OnCancelled(id);
|
|
}
|
|
}
|
|
m_trigger_src.erase(m_trigger_src.find(id));
|
|
m_trigger_dst.erase(m_trigger_dst.find(id));
|
|
again = true;
|
|
break;
|
|
}
|
|
}
|
|
} while (again);
|
|
#endif
|
|
delete p;
|
|
}
|
|
m_sockets.erase(it);
|
|
}
|
|
}
|
|
m_fds_erase.erase(it);
|
|
check_max_fd = true;
|
|
}
|
|
// calculate max file descriptor for select() call
|
|
if (check_max_fd)
|
|
{
|
|
m_maxsock = 0;
|
|
for (socket_v::iterator it = m_fds.begin(); it != m_fds.end(); it++)
|
|
{
|
|
SOCKET s = *it;
|
|
m_maxsock = s > m_maxsock ? s : m_maxsock;
|
|
}
|
|
}
|
|
// remove Add's that fizzed
|
|
while (!m_delete.empty())
|
|
{
|
|
std::list<Socket *>::iterator it = m_delete.begin();
|
|
Socket *p = *it;
|
|
p -> OnDelete();
|
|
m_delete.erase(it);
|
|
if (p -> DeleteByHandler()
|
|
#ifdef ENABLE_DETACH
|
|
&& !(m_slave ^ p -> IsDetached())
|
|
#endif
|
|
)
|
|
{
|
|
p -> SetErasedByHandler();
|
|
#ifdef ENABLE_TRIGGERS
|
|
bool again = false;
|
|
do
|
|
{
|
|
again = false;
|
|
for (std::map<int, Socket *>::iterator it = m_trigger_src.begin(); it != m_trigger_src.end(); it++)
|
|
{
|
|
int id = it -> first;
|
|
Socket *src = it -> second;
|
|
if (src == p)
|
|
{
|
|
for (std::map<Socket *, bool>::iterator it = m_trigger_dst[id].begin(); it != m_trigger_dst[id].end(); it++)
|
|
{
|
|
Socket *dst = it -> first;
|
|
if (Valid(dst))
|
|
{
|
|
dst -> OnCancelled(id);
|
|
}
|
|
}
|
|
m_trigger_src.erase(m_trigger_src.find(id));
|
|
m_trigger_dst.erase(m_trigger_dst.find(id));
|
|
again = true;
|
|
break;
|
|
}
|
|
}
|
|
} while (again);
|
|
#endif
|
|
delete p;
|
|
}
|
|
}
|
|
return n;
|
|
}
|
|
|
|
|
|
#ifdef ENABLE_RESOLVER
|
|
bool SocketHandler::Resolving(Socket *p0)
|
|
{
|
|
std::map<Socket *, bool>::iterator it = m_resolve_q.find(p0);
|
|
return it != m_resolve_q.end();
|
|
}
|
|
#endif
|
|
|
|
|
|
bool SocketHandler::Valid(Socket *p0)
|
|
{
|
|
for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++)
|
|
{
|
|
Socket *p = it -> second;
|
|
if (p0 == p)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool SocketHandler::OkToAccept(Socket *)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
|
|
size_t SocketHandler::GetCount()
|
|
{
|
|
/*
|
|
printf(" m_sockets : %d\n", m_sockets.size());
|
|
printf(" m_add : %d\n", m_add.size());
|
|
printf(" m_delete : %d\n", m_delete.size());
|
|
*/
|
|
return m_sockets.size() + m_add.size() + m_delete.size();
|
|
}
|
|
|
|
|
|
#ifdef ENABLE_SOCKS4
|
|
void SocketHandler::SetSocks4Host(ipaddr_t a)
|
|
{
|
|
m_socks4_host = a;
|
|
}
|
|
|
|
|
|
void SocketHandler::SetSocks4Host(const std::string& host)
|
|
{
|
|
Utility::u2ip(host, m_socks4_host);
|
|
}
|
|
|
|
|
|
void SocketHandler::SetSocks4Port(port_t port)
|
|
{
|
|
m_socks4_port = port;
|
|
}
|
|
|
|
|
|
void SocketHandler::SetSocks4Userid(const std::string& id)
|
|
{
|
|
m_socks4_userid = id;
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef ENABLE_RESOLVER
|
|
int SocketHandler::Resolve(Socket *p,const std::string& host,port_t port)
|
|
{
|
|
// check cache
|
|
ResolvSocket *resolv = new ResolvSocket(*this, p, host, port);
|
|
resolv -> SetId(++m_resolv_id);
|
|
resolv -> SetDeleteByHandler();
|
|
ipaddr_t local;
|
|
Utility::u2ip("127.0.0.1", local);
|
|
if (!resolv -> Open(local, m_resolver_port))
|
|
{
|
|
LogError(resolv, "Resolve", -1, "Can't connect to local resolve server", LOG_LEVEL_FATAL);
|
|
}
|
|
Add(resolv);
|
|
m_resolve_q[p] = true;
|
|
DEB( fprintf(stderr, " *** Resolve '%s:%d' id#%d m_resolve_q size: %d p: %p\n", host.c_str(), port, resolv -> GetId(), m_resolve_q.size(), p);)
|
|
return resolv -> GetId();
|
|
}
|
|
|
|
|
|
#ifdef ENABLE_IPV6
|
|
int SocketHandler::Resolve6(Socket *p,const std::string& host,port_t port)
|
|
{
|
|
// check cache
|
|
ResolvSocket *resolv = new ResolvSocket(*this, p, host, port, true);
|
|
resolv -> SetId(++m_resolv_id);
|
|
resolv -> SetDeleteByHandler();
|
|
ipaddr_t local;
|
|
Utility::u2ip("127.0.0.1", local);
|
|
if (!resolv -> Open(local, m_resolver_port))
|
|
{
|
|
LogError(resolv, "Resolve", -1, "Can't connect to local resolve server", LOG_LEVEL_FATAL);
|
|
}
|
|
Add(resolv);
|
|
m_resolve_q[p] = true;
|
|
return resolv -> GetId();
|
|
}
|
|
#endif
|
|
|
|
|
|
int SocketHandler::Resolve(Socket *p,ipaddr_t a)
|
|
{
|
|
// check cache
|
|
ResolvSocket *resolv = new ResolvSocket(*this, p, a);
|
|
resolv -> SetId(++m_resolv_id);
|
|
resolv -> SetDeleteByHandler();
|
|
ipaddr_t local;
|
|
Utility::u2ip("127.0.0.1", local);
|
|
if (!resolv -> Open(local, m_resolver_port))
|
|
{
|
|
LogError(resolv, "Resolve", -1, "Can't connect to local resolve server", LOG_LEVEL_FATAL);
|
|
}
|
|
Add(resolv);
|
|
m_resolve_q[p] = true;
|
|
return resolv -> GetId();
|
|
}
|
|
|
|
|
|
#ifdef ENABLE_IPV6
|
|
int SocketHandler::Resolve(Socket *p,in6_addr& a)
|
|
{
|
|
// check cache
|
|
ResolvSocket *resolv = new ResolvSocket(*this, p, a);
|
|
resolv -> SetId(++m_resolv_id);
|
|
resolv -> SetDeleteByHandler();
|
|
ipaddr_t local;
|
|
Utility::u2ip("127.0.0.1", local);
|
|
if (!resolv -> Open(local, m_resolver_port))
|
|
{
|
|
LogError(resolv, "Resolve", -1, "Can't connect to local resolve server", LOG_LEVEL_FATAL);
|
|
}
|
|
Add(resolv);
|
|
m_resolve_q[p] = true;
|
|
return resolv -> GetId();
|
|
}
|
|
#endif
|
|
|
|
|
|
void SocketHandler::EnableResolver(port_t port)
|
|
{
|
|
if (!m_resolver)
|
|
{
|
|
m_resolver_port = port;
|
|
m_resolver = new ResolvServer(port);
|
|
}
|
|
}
|
|
|
|
|
|
bool SocketHandler::ResolverReady()
|
|
{
|
|
return m_resolver ? m_resolver -> Ready() : false;
|
|
}
|
|
#endif // ENABLE_RESOLVER
|
|
|
|
|
|
#ifdef ENABLE_SOCKS4
|
|
void SocketHandler::SetSocks4TryDirect(bool x)
|
|
{
|
|
m_bTryDirect = x;
|
|
}
|
|
|
|
|
|
ipaddr_t SocketHandler::GetSocks4Host()
|
|
{
|
|
return m_socks4_host;
|
|
}
|
|
|
|
|
|
port_t SocketHandler::GetSocks4Port()
|
|
{
|
|
return m_socks4_port;
|
|
}
|
|
|
|
|
|
const std::string& SocketHandler::GetSocks4Userid()
|
|
{
|
|
return m_socks4_userid;
|
|
}
|
|
|
|
|
|
bool SocketHandler::Socks4TryDirect()
|
|
{
|
|
return m_bTryDirect;
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef ENABLE_RESOLVER
|
|
bool SocketHandler::ResolverEnabled()
|
|
{
|
|
return m_resolver ? true : false;
|
|
}
|
|
|
|
|
|
port_t SocketHandler::GetResolverPort()
|
|
{
|
|
return m_resolver_port;
|
|
}
|
|
#endif // ENABLE_RESOLVER
|
|
|
|
|
|
#ifdef ENABLE_POOL
|
|
ISocketHandler::PoolSocket *SocketHandler::FindConnection(int type,const std::string& protocol,SocketAddress& ad)
|
|
{
|
|
for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end() && !m_sockets.empty(); it++)
|
|
{
|
|
PoolSocket *pools = dynamic_cast<PoolSocket *>(it -> second);
|
|
if (pools)
|
|
{
|
|
if (pools -> GetSocketType() == type &&
|
|
pools -> GetSocketProtocol() == protocol &&
|
|
// %! pools -> GetClientRemoteAddress() &&
|
|
*pools -> GetClientRemoteAddress() == ad)
|
|
{
|
|
m_sockets.erase(it);
|
|
pools -> SetRetain(); // avoid Close in Socket destructor
|
|
return pools; // Caller is responsible that this socket is deleted
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void SocketHandler::EnablePool(bool x)
|
|
{
|
|
m_b_enable_pool = x;
|
|
}
|
|
|
|
|
|
bool SocketHandler::PoolEnabled()
|
|
{
|
|
return m_b_enable_pool;
|
|
}
|
|
#endif
|
|
|
|
|
|
void SocketHandler::Remove(Socket *p)
|
|
{
|
|
#ifdef ENABLE_RESOLVER
|
|
std::map<Socket *, bool>::iterator it4 = m_resolve_q.find(p);
|
|
if (it4 != m_resolve_q.end())
|
|
m_resolve_q.erase(it4);
|
|
#endif
|
|
if (p -> ErasedByHandler())
|
|
{
|
|
return;
|
|
}
|
|
for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++)
|
|
{
|
|
if (it -> second == p)
|
|
{
|
|
LogError(p, "Remove", -1, "Socket destructor called while still in use", LOG_LEVEL_WARNING);
|
|
m_sockets.erase(it);
|
|
return;
|
|
}
|
|
}
|
|
for (socket_m::iterator it2 = m_add.begin(); it2 != m_add.end(); it2++)
|
|
{
|
|
if ((*it2).second == p)
|
|
{
|
|
LogError(p, "Remove", -2, "Socket destructor called while still in use", LOG_LEVEL_WARNING);
|
|
m_add.erase(it2);
|
|
return;
|
|
}
|
|
}
|
|
for (std::list<Socket *>::iterator it3 = m_delete.begin(); it3 != m_delete.end(); it3++)
|
|
{
|
|
if (*it3 == p)
|
|
{
|
|
LogError(p, "Remove", -3, "Socket destructor called while still in use", LOG_LEVEL_WARNING);
|
|
m_delete.erase(it3);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void SocketHandler::CheckSanity()
|
|
{
|
|
CheckList(m_fds, "active sockets"); // active sockets
|
|
CheckList(m_fds_erase, "sockets to be erased"); // should always be empty anyway
|
|
CheckList(m_fds_callonconnect, "checklist CallOnConnect");
|
|
#ifdef ENABLE_DETACH
|
|
CheckList(m_fds_detach, "checklist Detach");
|
|
#endif
|
|
CheckList(m_fds_timeout, "checklist Timeout");
|
|
CheckList(m_fds_retry, "checklist retry client connect");
|
|
CheckList(m_fds_close, "checklist close and delete");
|
|
}
|
|
|
|
|
|
void SocketHandler::CheckList(socket_v& ref,const std::string& listname)
|
|
{
|
|
for (socket_v::iterator it = ref.begin(); it != ref.end(); it++)
|
|
{
|
|
SOCKET s = *it;
|
|
if (m_sockets.find(s) != m_sockets.end())
|
|
continue;
|
|
if (m_add.find(s) != m_add.end())
|
|
continue;
|
|
bool found = false;
|
|
for (std::list<Socket *>::iterator it = m_delete.begin(); it != m_delete.end(); it++)
|
|
{
|
|
Socket *p = *it;
|
|
if (p -> GetSocket() == s)
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found)
|
|
{
|
|
fprintf(stderr, "CheckList failed for \"%s\": fd %d\n", listname.c_str(), s);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void SocketHandler::AddList(SOCKET s,list_t which_one,bool add)
|
|
{
|
|
if (s == INVALID_SOCKET)
|
|
{
|
|
DEB( fprintf(stderr, "AddList: invalid_socket\n");)
|
|
return;
|
|
}
|
|
socket_v& ref =
|
|
(which_one == LIST_CALLONCONNECT) ? m_fds_callonconnect :
|
|
#ifdef ENABLE_DETACH
|
|
(which_one == LIST_DETACH) ? m_fds_detach :
|
|
#endif
|
|
(which_one == LIST_TIMEOUT) ? m_fds_timeout :
|
|
(which_one == LIST_RETRY) ? m_fds_retry :
|
|
(which_one == LIST_CLOSE) ? m_fds_close : m_fds_close;
|
|
if (add)
|
|
{
|
|
#ifdef ENABLE_DETACH
|
|
DEB( fprintf(stderr, "AddList; %5d: %s: %s\n", s, (which_one == LIST_CALLONCONNECT) ? "CallOnConnect" :
|
|
(which_one == LIST_DETACH) ? "Detach" :
|
|
(which_one == LIST_TIMEOUT) ? "Timeout" :
|
|
(which_one == LIST_RETRY) ? "Retry" :
|
|
(which_one == LIST_CLOSE) ? "Close" : "<undef>",
|
|
add ? "Add" : "Remove");)
|
|
#else
|
|
DEB( fprintf(stderr, "AddList; %5d: %s: %s\n", s, (which_one == LIST_CALLONCONNECT) ? "CallOnConnect" :
|
|
(which_one == LIST_TIMEOUT) ? "Timeout" :
|
|
(which_one == LIST_RETRY) ? "Retry" :
|
|
(which_one == LIST_CLOSE) ? "Close" : "<undef>",
|
|
add ? "Add" : "Remove");)
|
|
#endif
|
|
}
|
|
if (add)
|
|
{
|
|
for (socket_v::iterator it = ref.begin(); it != ref.end(); it++)
|
|
{
|
|
if (*it == s) // already there
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
ref.push_back(s);
|
|
return;
|
|
}
|
|
// remove
|
|
for (socket_v::iterator it = ref.begin(); it != ref.end(); it++)
|
|
{
|
|
if (*it == s)
|
|
{
|
|
ref.erase(it);
|
|
break;
|
|
}
|
|
}
|
|
//DEB( fprintf(stderr, "/AddList\n");)
|
|
}
|
|
|
|
|
|
#ifdef ENABLE_TRIGGERS
|
|
int SocketHandler::TriggerID(Socket *src)
|
|
{
|
|
int id = m_next_trigger_id++;
|
|
m_trigger_src[id] = src;
|
|
return id;
|
|
}
|
|
|
|
|
|
bool SocketHandler::Subscribe(int id, Socket *dst)
|
|
{
|
|
if (m_trigger_src.find(id) != m_trigger_src.end())
|
|
{
|
|
std::map<Socket *, bool>::iterator it = m_trigger_dst[id].find(dst);
|
|
if (it != m_trigger_dst[id].end())
|
|
{
|
|
m_trigger_dst[id][dst] = true;
|
|
return true;
|
|
}
|
|
LogError(dst, "Subscribe", id, "Already subscribed", LOG_LEVEL_INFO);
|
|
return false;
|
|
}
|
|
LogError(dst, "Subscribe", id, "Trigger id not found", LOG_LEVEL_INFO);
|
|
return false;
|
|
}
|
|
|
|
|
|
bool SocketHandler::Unsubscribe(int id, Socket *dst)
|
|
{
|
|
if (m_trigger_src.find(id) != m_trigger_src.end())
|
|
{
|
|
std::map<Socket *, bool>::iterator it = m_trigger_dst[id].find(dst);
|
|
if (it != m_trigger_dst[id].end())
|
|
{
|
|
m_trigger_dst[id].erase(it);
|
|
return true;
|
|
}
|
|
LogError(dst, "Unsubscribe", id, "Not subscribed", LOG_LEVEL_INFO);
|
|
return false;
|
|
}
|
|
LogError(dst, "Unsubscribe", id, "Trigger id not found", LOG_LEVEL_INFO);
|
|
return false;
|
|
}
|
|
|
|
|
|
void SocketHandler::Trigger(int id, Socket::TriggerData& data, bool erase)
|
|
{
|
|
if (m_trigger_src.find(id) != m_trigger_src.end())
|
|
{
|
|
data.SetSource( m_trigger_src[id] );
|
|
for (std::map<Socket *, bool>::iterator it = m_trigger_dst[id].begin(); it != m_trigger_dst[id].end(); it++)
|
|
{
|
|
Socket *dst = it -> first;
|
|
if (Valid(dst))
|
|
{
|
|
dst -> OnTrigger(id, data);
|
|
}
|
|
}
|
|
if (erase)
|
|
{
|
|
m_trigger_src.erase(m_trigger_src.find(id));
|
|
m_trigger_dst.erase(m_trigger_dst.find(id));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogError(NULL, "Trigger", id, "Trigger id not found", LOG_LEVEL_INFO);
|
|
}
|
|
}
|
|
#endif // ENABLE_TRIGGERS
|
|
|
|
|
|
#ifdef SOCKETS_NAMESPACE
|
|
}
|
|
#endif
|
|
|