8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 21:23:03 +01:00

Implemented delayed closing of server sockets - it should fix server hang up (see CORE-4680).

Fixed socket disconnect handling to allow graceful shutdown of network connection and avoid a lot of network errors in firebird.log (mostly 10053\10054).
Misc changes.
This commit is contained in:
hvlad 2015-10-16 15:28:51 +00:00
parent 5ab91b67dd
commit 4068a225b4

View File

@ -425,8 +425,10 @@ static int cleanup_ports(const int, const int, void*);
static int fork(); static int fork();
#endif #endif
typedef Array<SOCKET> SocketsArray;
#ifdef WIN_NT #ifdef WIN_NT
static void wsaExitHandler(void*); static int wsaExitHandler(const int, const int, void*);
static int fork(SOCKET, USHORT); static int fork(SOCKET, USHORT);
static THREAD_ENTRY_DECLARE forkThread(THREAD_ENTRY_PARAM); static THREAD_ENTRY_DECLARE forkThread(THREAD_ENTRY_PARAM);
@ -434,9 +436,7 @@ static GlobalPtr<Mutex> forkMutex;
static HANDLE forkEvent = INVALID_HANDLE_VALUE; static HANDLE forkEvent = INVALID_HANDLE_VALUE;
static bool forkThreadStarted = false; static bool forkThreadStarted = false;
typedef Array<SOCKET> SocketsArray;
static SocketsArray* forkSockets; static SocketsArray* forkSockets;
#endif #endif
static void inet_gen_error(bool, rem_port*, const Arg::StatusVector& v); static void inet_gen_error(bool, rem_port*, const Arg::StatusVector& v);
@ -520,6 +520,7 @@ static rem_port* inet_async_receive = NULL;
static GlobalPtr<Mutex> port_mutex; static GlobalPtr<Mutex> port_mutex;
static GlobalPtr<PortsCleanup> inet_ports; static GlobalPtr<PortsCleanup> inet_ports;
static GlobalPtr<SocketsArray> ports_to_close;
rem_port* INET_analyze(ClntAuthBlock* cBlock, rem_port* INET_analyze(ClntAuthBlock* cBlock,
@ -1237,7 +1238,7 @@ static rem_port* alloc_port(rem_port* const parent, const USHORT flags)
{ {
inet_error(false, parent, "WSAStartup", isc_net_init_error, wsaError); inet_error(false, parent, "WSAStartup", isc_net_init_error, wsaError);
} }
gds__register_cleanup(wsaExitHandler, 0); fb_shutdown_callback(0, wsaExitHandler, fb_shut_finish, 0);
#endif #endif
INET_remote_buffer = Config::getTcpRemoteBufferSize(); INET_remote_buffer = Config::getTcpRemoteBufferSize();
if (INET_remote_buffer < MAX_DATA_LW || INET_remote_buffer > MAX_DATA_HW) if (INET_remote_buffer < MAX_DATA_LW || INET_remote_buffer > MAX_DATA_HW)
@ -1565,15 +1566,31 @@ static void disconnect(rem_port* const port)
// is an attempt to return the socket to a state where a graceful shutdown can // is an attempt to return the socket to a state where a graceful shutdown can
// occur. // occur.
// hvlad: for graceful shutdown linger should be turned on (despite of default
// setting by OS)
{ // scope
struct linger lngr = {1, 10};
socklen_t optlen = sizeof(lngr);
if (port->port_linger.l_onoff) if (port->port_linger.l_onoff)
{ lngr = port->port_linger;
setsockopt(port->port_handle, SOL_SOCKET, SO_LINGER,
(SCHAR*) &port->port_linger, sizeof(port->port_linger)); setsockopt(port->port_handle, SOL_SOCKET, SO_LINGER, (SCHAR*)&lngr, sizeof(lngr));
} }
if (port->port_handle != INVALID_SOCKET) if (port->port_handle != INVALID_SOCKET)
{ {
shutdown(port->port_handle, 2); shutdown(port->port_handle, 1);
fd_set fd = {0};
FD_SET(port->port_handle, &fd);
timeval tm = {10, 0};
int n = select(1, &fd, NULL, NULL, &tm);
while (n > 0)
{
char buff[256];
n = recv(port->port_handle, buff, sizeof(buff), 0);
}
} }
MutexLockGuard guard(port_mutex, FB_FUNCTION); MutexLockGuard guard(port_mutex, FB_FUNCTION);
@ -1586,13 +1603,29 @@ static void disconnect(rem_port* const port)
} }
port->port_context = NULL; port->port_context = NULL;
// hvlad: delay closing of the server sockets to prevent its reuse
// by another (newly accepted) port until next select() call. See
// also select_wait() function.
const bool delayClose = (port->port_server_flags && port->port_parent);
// If this is a sub-port, unlink it from its parent // If this is a sub-port, unlink it from its parent
port->unlinkParent(); port->unlinkParent();
inet_ports->unRegisterPort(port); inet_ports->unRegisterPort(port);
if (delayClose)
{
if (port->port_handle != INVALID_SOCKET)
ports_to_close->push(port->port_handle);
if (port->port_channel != INVALID_SOCKET)
ports_to_close->push(port->port_channel);
}
else
{
SOCLOSE(port->port_handle); SOCLOSE(port->port_handle);
SOCLOSE(port->port_channel); SOCLOSE(port->port_channel);
}
port->release(); port->release();
@ -1656,6 +1689,13 @@ static int cleanup_ports(const int, const int, void* /*arg*/)
INET_shutting_down = true; INET_shutting_down = true;
inet_ports->closePorts(); inet_ports->closePorts();
while (ports_to_close->hasData())
{
SOCKET s = ports_to_close->pop();
SOCLOSE(s);
}
return 0; return 0;
} }
@ -1679,7 +1719,7 @@ static int fork()
#endif #endif
#ifdef WIN_NT #ifdef WIN_NT
static void wsaExitHandler(void*) static int wsaExitHandler(const int, const int, void*)
{ {
/************************************** /**************************************
* *
@ -1693,6 +1733,7 @@ static void wsaExitHandler(void*)
**************************************/ **************************************/
SleepEx(0, FALSE); // let select in other thread(s) shutdown gracefully SleepEx(0, FALSE); // let select in other thread(s) shutdown gracefully
WSACleanup(); WSACleanup();
return 0;
} }
@ -2037,6 +2078,13 @@ static bool select_wait( rem_port* main_port, Select* selct)
{ // port_mutex scope { // port_mutex scope
MutexLockGuard guard(port_mutex, FB_FUNCTION); MutexLockGuard guard(port_mutex, FB_FUNCTION);
while (ports_to_close->hasData())
{
SOCKET s = ports_to_close->pop();
SOCLOSE(s);
}
for (rem_port* port = main_port; port; port = port->port_next) for (rem_port* port = main_port; port; port = port->port_next)
{ {
if (port->port_state == rem_port::PENDING && if (port->port_state == rem_port::PENDING &&