mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 16:43:03 +01:00
Frontported fix for CORE-3194: Number of connections to linux superclassic has limit equal 508
This commit is contained in:
parent
44cc684fb7
commit
20b15687c9
@ -667,6 +667,7 @@ AC_CHECK_HEADERS(semaphore.h)
|
||||
AC_CHECK_HEADERS(float.h)
|
||||
AC_CHECK_HEADERS(atomic.h)
|
||||
AC_CHECK_HEADERS(atomic_ops.h)
|
||||
AC_CHECK_HEADERS(poll.h)
|
||||
|
||||
dnl check for ICU presence
|
||||
AC_CHECK_HEADER(unicode/ucnv.h,,AC_MSG_ERROR(ICU support not found - please install development ICU package))
|
||||
@ -790,6 +791,7 @@ AC_CHECK_FUNCS(semtimedop)
|
||||
AC_CHECK_FUNCS(fegetenv)
|
||||
AC_CHECK_FUNCS(strerror_r)
|
||||
AC_CHECK_FUNCS(fdatasync fsync)
|
||||
AC_CHECK_FUNCS(poll)
|
||||
dnl AC_CHECK_FUNCS(AO_compare_and_swap_full)
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([[#include <atomic_ops.h>]], [[AO_T x; AO_compare_and_swap_full(&x, 0, 0); return 0;]])],
|
||||
|
@ -88,9 +88,13 @@
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/wait.h>
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
|
||||
#if defined(HAVE_POLL_H)
|
||||
#include <poll.h>
|
||||
#elif defined(HAVE_SYS_SELECT_H)
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
#endif // !WIN_NT
|
||||
|
||||
const int INET_RETRY_CALL = 5;
|
||||
@ -229,12 +233,175 @@ const SLONG DEF_MAX_DATA = 8192;
|
||||
|
||||
const int SELECT_TIMEOUT = 60; // Dispatch thread select timeout (sec)
|
||||
|
||||
struct slct_t
|
||||
class Select
|
||||
{
|
||||
int slct_width;
|
||||
int slct_count;
|
||||
#ifdef HAVE_POLL
|
||||
private:
|
||||
static const int SEL_INIT_EVENTS = POLLIN;
|
||||
static const int SEL_CHECK_MASK = POLLIN;
|
||||
|
||||
pollfd* getPollFd(int n)
|
||||
{
|
||||
pollfd* const end = slct_poll.end();
|
||||
for (pollfd* pf = slct_poll.begin(); pf < end; ++pf)
|
||||
{
|
||||
if (n == pf->fd)
|
||||
{
|
||||
return pf;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int compare(const void* a, const void* b)
|
||||
{
|
||||
// use C-cast here to be for sure compatible with libc
|
||||
return ((pollfd*)a)->fd - ((pollfd*)b)->fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
#ifdef HAVE_POLL
|
||||
Select()
|
||||
: slct_time(0), slct_count(0), slct_poll(*getDefaultMemoryPool())
|
||||
{ }
|
||||
#else
|
||||
Select()
|
||||
: slct_time(0), slct_count(0), slct_width(0)
|
||||
{
|
||||
memset(&slct_fdset, 0, sizeof slct_fdset);
|
||||
}
|
||||
#endif
|
||||
|
||||
enum HandleState {SEL_BAD, SEL_DISCONNECTED, SEL_NO_DATA, SEL_READY};
|
||||
|
||||
HandleState ok(const rem_port* port)
|
||||
{
|
||||
SOCKET n = port->port_handle;
|
||||
#if defined(WIN_NT)
|
||||
return FD_ISSET(n, &slct_fdset) ? SEL_READY : SEL_NO_DATA;
|
||||
#elif defined(HAVE_POLL)
|
||||
const pollfd* pf = getPollFd(n);
|
||||
if (pf)
|
||||
{
|
||||
return pf->events & SEL_CHECK_MASK ? SEL_READY : SEL_NO_DATA;
|
||||
}
|
||||
return (n < 0) ? (port->port_flags & PORT_disconnect ? SEL_DISCONNECTED : SEL_BAD) : SEL_NO_DATA;
|
||||
#else
|
||||
if (n < 0 || n >= FD_SETSIZE)
|
||||
{
|
||||
return port->port_flags & PORT_disconnect ? SEL_DISCONNECTED : SEL_BAD;
|
||||
}
|
||||
return (n < slct_width && FD_ISSET(n, &slct_fdset)) ? SEL_READY : SEL_NO_DATA;
|
||||
#endif
|
||||
}
|
||||
|
||||
void unset(SOCKET handle)
|
||||
{
|
||||
#if defined(HAVE_POLL)
|
||||
pollfd* pf = getPollFd(handle);
|
||||
if (pf)
|
||||
{
|
||||
pf->events = 0;
|
||||
}
|
||||
#else
|
||||
FD_CLR(handle, &slct_fdset);
|
||||
--slct_count;
|
||||
#endif
|
||||
}
|
||||
|
||||
void set(SOCKET handle)
|
||||
{
|
||||
#ifdef HAVE_POLL
|
||||
pollfd* pf = getPollFd(handle);
|
||||
if (pf)
|
||||
{
|
||||
pf->events = SEL_INIT_EVENTS;
|
||||
return;
|
||||
}
|
||||
pollfd f;
|
||||
f.fd = handle;
|
||||
f.events = SEL_INIT_EVENTS;
|
||||
slct_poll.push(f);
|
||||
#else
|
||||
FD_SET(handle, &slct_fdset);
|
||||
#ifdef WIN_NT
|
||||
++slct_width;
|
||||
#else
|
||||
slct_width = MAX(slct_width, handle + 1);
|
||||
#endif // WIN_NT
|
||||
#endif // HAVE_POLL
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
slct_count = 0;
|
||||
#if defined(HAVE_POLL)
|
||||
slct_poll.clear();
|
||||
#else
|
||||
slct_width = 0;
|
||||
FD_ZERO(&slct_fdset);
|
||||
#endif
|
||||
}
|
||||
|
||||
int select(timeval* timeout)
|
||||
{
|
||||
bool hasRequest = false;
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
pollfd* const end = slct_poll.end();
|
||||
for (pollfd* pf = slct_poll.begin(); pf < end; ++pf)
|
||||
{
|
||||
pf->revents = pf->events;
|
||||
if (pf->events & SEL_CHECK_MASK)
|
||||
{
|
||||
hasRequest = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasRequest)
|
||||
{
|
||||
errno = NOTASOCKET;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int milliseconds = timeout ? timeout->tv_sec * 1000 + timeout->tv_usec / 1000 : -1;
|
||||
slct_count = ::poll(slct_poll.begin(), slct_poll.getCount(), milliseconds);
|
||||
|
||||
for (pollfd* pf = slct_poll.begin(); pf < end; ++pf)
|
||||
{
|
||||
pf->events = pf->revents;
|
||||
}
|
||||
#else
|
||||
#ifdef WIN_NT
|
||||
slct_count = ::select(FD_SETSIZE, &slct_fdset, NULL, NULL, timeout);
|
||||
#else
|
||||
|
||||
|
||||
slct_count = ::select(slct_width, &slct_fdset, NULL, NULL, timeout);
|
||||
#endif // WIN_NT
|
||||
#endif // HAVE_POLL
|
||||
|
||||
|
||||
return slct_count;
|
||||
}
|
||||
|
||||
int getCount()
|
||||
{
|
||||
return slct_count;
|
||||
}
|
||||
|
||||
time_t slct_time;
|
||||
|
||||
private:
|
||||
int slct_count;
|
||||
#ifdef HAVE_POLL
|
||||
Firebird::HalfStaticArray<pollfd, 8> slct_poll;
|
||||
#else
|
||||
int slct_width;
|
||||
fd_set slct_fdset;
|
||||
#endif
|
||||
};
|
||||
|
||||
static bool accept_connection(rem_port*, const P_CNCT*);
|
||||
@ -309,9 +476,9 @@ static bool packet_send(rem_port*, const SCHAR*, SSHORT);
|
||||
static rem_port* receive(rem_port*, PACKET *);
|
||||
static rem_port* select_accept(rem_port*);
|
||||
|
||||
static void select_port(rem_port*, slct_t*, RemPortPtr&);
|
||||
static void select_port(rem_port*, Select*, RemPortPtr&);
|
||||
static bool select_multi(rem_port*, UCHAR* buffer, SSHORT bufsize, SSHORT* length, RemPortPtr&);
|
||||
static bool select_wait(rem_port*, slct_t*);
|
||||
static bool select_wait(rem_port*, Select*);
|
||||
static int send_full(rem_port*, PACKET *);
|
||||
static int send_partial(rem_port*, PACKET *);
|
||||
|
||||
@ -365,7 +532,7 @@ SLONG INET_remote_buffer;
|
||||
static Firebird::GlobalPtr<Firebird::Mutex> init_mutex;
|
||||
static volatile bool INET_initialized = false;
|
||||
static volatile bool INET_shutting_down = false;
|
||||
static slct_t INET_select = { 0, 0, 0 };
|
||||
static Select INET_select;
|
||||
static rem_port* inet_async_receive = NULL;
|
||||
|
||||
|
||||
@ -759,7 +926,7 @@ rem_port* INET_connect(const TEXT* name,
|
||||
}
|
||||
|
||||
if (! setNoNagleOption(port))
|
||||
{
|
||||
{
|
||||
inet_error(true, port, "setsockopt TCP_NODELAY", isc_net_connect_listen_err, INET_ERRNO);
|
||||
}
|
||||
}
|
||||
@ -1168,20 +1335,15 @@ static rem_port* aux_connect(rem_port* port, PACKET* packet)
|
||||
timeout.tv_sec = port->port_connect_timeout;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
fd_set slct_fdset;
|
||||
FD_ZERO(&slct_fdset);
|
||||
FD_SET(port->port_channel, &slct_fdset);
|
||||
Select slct;
|
||||
slct.set(port->port_channel);
|
||||
|
||||
int inetErrNo = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
const int count =
|
||||
#ifdef WIN_NT
|
||||
select(FD_SETSIZE, &slct_fdset, NULL, NULL, &timeout);
|
||||
#else
|
||||
select(port->port_channel + 1, &slct_fdset, NULL, NULL, &timeout);
|
||||
#endif
|
||||
slct.select(&timeout);
|
||||
const int count = slct.getCount();
|
||||
inetErrNo = INET_ERRNO;
|
||||
|
||||
if (count != -1 || !INTERRUPT_ERROR(inetErrNo))
|
||||
@ -1461,10 +1623,10 @@ static void disconnect(rem_port* const port)
|
||||
#ifdef DEBUG
|
||||
if (INET_trace & TRACE_summary)
|
||||
{
|
||||
fprintf(stdout, "INET_count_send = %lu packets\n", INET_count_send);
|
||||
fprintf(stdout, "INET_bytes_send = %lu bytes\n", INET_bytes_send);
|
||||
fprintf(stdout, "INET_count_recv = %lu packets\n", INET_count_recv);
|
||||
fprintf(stdout, "INET_bytes_recv = %lu bytes\n", INET_bytes_recv);
|
||||
fprintf(stdout, "INET_count_send = %u packets\n", INET_count_send);
|
||||
fprintf(stdout, "INET_bytes_send = %u bytes\n", INET_bytes_send);
|
||||
fprintf(stdout, "INET_count_recv = %u packets\n", INET_count_recv);
|
||||
fprintf(stdout, "INET_bytes_recv = %u bytes\n", INET_bytes_recv);
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
@ -1826,7 +1988,7 @@ static rem_port* receive( rem_port* main_port, PACKET * packet)
|
||||
op_rec_count++;
|
||||
if (INET_trace & TRACE_operations)
|
||||
{
|
||||
fprintf(stdout, "%04lu: OP Recd %5lu opcode %d\n",
|
||||
fprintf(stdout, "%04u: OP Recd %5u opcode %d\n",
|
||||
inet_debug_timer(),
|
||||
op_rec_count, packet->p_operation);
|
||||
fflush(stdout);
|
||||
@ -1949,7 +2111,7 @@ static rem_port* select_accept( rem_port* main_port)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void select_port(rem_port* main_port, slct_t* selct, RemPortPtr& port)
|
||||
static void select_port(rem_port* main_port, Select* selct, RemPortPtr& port)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -1971,33 +2133,36 @@ static void select_port(rem_port* main_port, slct_t* selct, RemPortPtr& port)
|
||||
|
||||
for (port = main_port; port; port = port->port_next)
|
||||
{
|
||||
const SOCKET n = port->port_handle;
|
||||
#ifdef WIN_NT
|
||||
const int ok = FD_ISSET(n, &selct->slct_fdset);
|
||||
#else
|
||||
if (n < 0 || n >= FD_SETSIZE)
|
||||
Select::HandleState result = selct->ok(port);
|
||||
selct->unset(port->port_handle);
|
||||
switch (result)
|
||||
{
|
||||
if (port->port_flags & PORT_disconnect)
|
||||
case Select::SEL_BAD:
|
||||
if (port->port_state == rem_port::BROKEN)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
|
||||
return;
|
||||
}
|
||||
const int ok = n < selct->slct_width && FD_ISSET(n, &selct->slct_fdset);
|
||||
#endif
|
||||
if (ok)
|
||||
{
|
||||
case Select::SEL_DISCONNECTED:
|
||||
continue;
|
||||
|
||||
case Select::SEL_READY:
|
||||
port->port_dummy_timeout = port->port_dummy_packet_interval;
|
||||
FD_CLR(n, &selct->slct_fdset);
|
||||
--selct->slct_count;
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (port->port_dummy_timeout < 0) {
|
||||
|
||||
if (port->port_dummy_timeout < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool select_wait( rem_port* main_port, slct_t* selct)
|
||||
static bool select_wait( rem_port* main_port, Select* selct)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -2016,8 +2181,7 @@ static bool select_wait( rem_port* main_port, slct_t* selct)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
selct->slct_count = selct->slct_width = 0;
|
||||
FD_ZERO(&selct->slct_fdset);
|
||||
selct->clear();
|
||||
bool found = false;
|
||||
|
||||
// Use the time interval between select() calls to expire
|
||||
@ -2075,16 +2239,10 @@ static bool select_wait( rem_port* main_port, slct_t* selct)
|
||||
port->port_handle);
|
||||
|
||||
// this will lead to receive() which will break bad connection
|
||||
selct->slct_count = selct->slct_width = 0;
|
||||
FD_ZERO(&selct->slct_fdset);
|
||||
selct->clear();
|
||||
if (!badSocket)
|
||||
{
|
||||
FD_SET(port->port_handle, &selct->slct_fdset);
|
||||
#ifdef WIN_NT
|
||||
++selct->slct_width;
|
||||
#else
|
||||
selct->slct_width = port->port_handle + 1;
|
||||
#endif
|
||||
selct->set(port->port_handle);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -2094,12 +2252,7 @@ static bool select_wait( rem_port* main_port, slct_t* selct)
|
||||
// if process is shuting down - don't listen on main port
|
||||
if (!INET_shutting_down || port != main_port)
|
||||
{
|
||||
FD_SET(port->port_handle, &selct->slct_fdset);
|
||||
#ifdef WIN_NT
|
||||
++selct->slct_width;
|
||||
#else
|
||||
selct->slct_width = MAX(selct->slct_width, port->port_handle + 1);
|
||||
#endif
|
||||
selct->set(port->port_handle);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
@ -2130,30 +2283,26 @@ static bool select_wait( rem_port* main_port, slct_t* selct)
|
||||
timeout.tv_sec = SELECT_TIMEOUT;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
#ifdef WIN_NT
|
||||
selct->slct_count = select(FD_SETSIZE, &selct->slct_fdset, NULL, NULL, &timeout);
|
||||
#else
|
||||
selct->slct_count = select(selct->slct_width, &selct->slct_fdset, NULL, NULL, &timeout);
|
||||
#endif
|
||||
selct->select(&timeout);
|
||||
const int inetErrNo = INET_ERRNO;
|
||||
|
||||
//if (INET_shutting_down) {
|
||||
// return false;
|
||||
//}
|
||||
|
||||
if (selct->slct_count != -1)
|
||||
if (selct->getCount() != -1)
|
||||
{
|
||||
// if selct->slct_count is zero it means that we timed out of
|
||||
// select with nothing to read or accept, so clear the fd_set
|
||||
// bit as this value is undefined on some platforms (eg. HP-UX),
|
||||
// when the select call times out. Once these bits are cleared
|
||||
// they can be used in select_port()
|
||||
if (selct->slct_count == 0)
|
||||
if (selct->getCount() == 0)
|
||||
{
|
||||
Firebird::MutexLockGuard guard(port_mutex);
|
||||
for (rem_port* port = main_port; port; port = port->port_next)
|
||||
{
|
||||
FD_CLR(port->port_handle, &selct->slct_fdset);
|
||||
selct->unset(port->port_handle);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -2197,7 +2346,7 @@ static int send_full( rem_port* port, PACKET * packet)
|
||||
op_sent_count++;
|
||||
if (INET_trace & TRACE_operations)
|
||||
{
|
||||
fprintf(stdout, "%05lu: OP Sent %5lu opcode %d\n", inet_debug_timer(),
|
||||
fprintf(stdout, "%05u: OP Sent %5u opcode %d\n", inet_debug_timer(),
|
||||
op_sent_count, packet->p_operation);
|
||||
fflush(stdout);
|
||||
}
|
||||
@ -2226,7 +2375,7 @@ static int send_partial( rem_port* port, PACKET * packet)
|
||||
op_sentp_count++;
|
||||
if (INET_trace & TRACE_operations)
|
||||
{
|
||||
fprintf(stdout, "%05lu: OP Sent %5lu opcode %d (partial)\n", inet_debug_timer(),
|
||||
fprintf(stdout, "%05u: OP Sent %5u opcode %d (partial)\n", inet_debug_timer(),
|
||||
op_sentp_count, packet->p_operation);
|
||||
fflush(stdout);
|
||||
}
|
||||
@ -2802,7 +2951,7 @@ static void packet_print(const TEXT* string, const UCHAR* packet, int length, UL
|
||||
for (int l = length; l > 0; --l)
|
||||
sum += *packet++;
|
||||
|
||||
fprintf(stdout, "%05lu: PKT %s\t(%lu): length = %4d, checksum = %d\n",
|
||||
fprintf(stdout, "%05u: PKT %s\t(%u): length = %4d, checksum = %d\n",
|
||||
inet_debug_timer(), string, counter, length, sum);
|
||||
fflush(stdout);
|
||||
}
|
||||
@ -2875,18 +3024,14 @@ static bool packet_receive(rem_port* port, UCHAR* buffer, SSHORT buffer_length,
|
||||
|
||||
if ( !(port->port_flags & PORT_async) )
|
||||
{
|
||||
fd_set slct_fdset;
|
||||
FD_ZERO(&slct_fdset);
|
||||
FD_SET(ph, &slct_fdset);
|
||||
Select slct;
|
||||
slct.set(ph);
|
||||
|
||||
int slct_count;
|
||||
for (;;)
|
||||
{
|
||||
#if (defined WIN_NT)
|
||||
slct_count = select(FD_SETSIZE, &slct_fdset, NULL, NULL, time_ptr);
|
||||
#else
|
||||
slct_count = select(port->port_handle + 1, &slct_fdset, NULL, NULL, time_ptr);
|
||||
#endif
|
||||
slct.select(time_ptr);
|
||||
slct_count = slct.getCount();
|
||||
inetErrNo = INET_ERRNO;
|
||||
|
||||
// restore original timeout value FSG 3 MAY 2001
|
||||
@ -2916,7 +3061,7 @@ static bool packet_receive(rem_port* port, UCHAR* buffer, SSHORT buffer_length,
|
||||
#ifdef DEBUG
|
||||
if (INET_trace & TRACE_operations)
|
||||
{
|
||||
fprintf(stdout, "%05lu: OP Sent: op_dummy\n", inet_debug_timer());
|
||||
fprintf(stdout, "%05u: OP Sent: op_dummy\n", inet_debug_timer());
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user