Skip to content

Commit bf2cbbe

Browse files
committed
Implemented send & receive timeouts in fbclient
1 parent f7ec79f commit bf2cbbe

12 files changed

Lines changed: 109 additions & 42 deletions

File tree

src/include/firebird/impl/consts_pub.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@
138138
#define isc_dpb_search_path 105
139139
#define isc_dpb_blr_request_search_path 106
140140
#define isc_dpb_gbak_restore_has_schema 107
141+
#define isc_dpb_send_timeout 108
142+
#define isc_dpb_receive_timeout 109
141143

142144

143145
/**************************************************/
@@ -329,6 +331,8 @@
329331
#define isc_spb_os_user 122
330332
#define isc_spb_config 123
331333
#define isc_spb_expected_db 124
334+
#define isc_spb_send_timeout 125
335+
#define isc_spb_receive_timeout 126
332336

333337
#define isc_spb_connect_timeout isc_dpb_connect_timeout
334338
#define isc_spb_dummy_packet_interval isc_dpb_dummy_packet_interval

src/include/gen/Firebird.pas

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4341,6 +4341,8 @@ IPerformanceStatsImpl = class(IPerformanceStats)
43414341
isc_dpb_search_path = byte(105);
43424342
isc_dpb_blr_request_search_path = byte(106);
43434343
isc_dpb_gbak_restore_has_schema = byte(107);
4344+
isc_dpb_send_timeout = byte(108);
4345+
isc_dpb_receive_timeout = byte(109);
43444346
isc_dpb_address = byte(1);
43454347
isc_dpb_addr_protocol = byte(1);
43464348
isc_dpb_addr_endpoint = byte(2);
@@ -4432,6 +4434,8 @@ IPerformanceStatsImpl = class(IPerformanceStats)
44324434
isc_spb_os_user = byte(122);
44334435
isc_spb_config = byte(123);
44344436
isc_spb_expected_db = byte(124);
4437+
isc_spb_send_timeout = byte(125);
4438+
isc_spb_receive_timeout = byte(126);
44354439
isc_action_svc_backup = byte(1);
44364440
isc_action_svc_restore = byte(2);
44374441
isc_action_svc_repair = byte(3);

src/remote/client/interface.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7988,7 +7988,7 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned
79887988
{
79897989
ISC_utf8ToSystem(node_name);
79907990
port = INET_analyze(&cBlock, attach_name, node_name.c_str(), flags & ANALYZE_USER_VFY, pb,
7991-
cBlock.getConfig(), ref_db_name, cryptCb, AF_UNIX);
7991+
&parSet, cBlock.getConfig(), ref_db_name, cryptCb, AF_UNIX);
79927992
}
79937993
else
79947994
#endif
@@ -8011,7 +8011,7 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned
80118011
}
80128012

80138013
port = INET_analyze(&cBlock, attach_name, node_name.c_str(), flags & ANALYZE_USER_VFY, pb,
8014-
cBlock.getConfig(), ref_db_name, cryptCb, inet_af);
8014+
&parSet, cBlock.getConfig(), ref_db_name, cryptCb, inet_af);
80158015
}
80168016

80178017
// We have a local connection string. If it's a file on a network share,
@@ -8028,7 +8028,7 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned
80288028
ISC_utf8ToSystem(node_name);
80298029

80308030
port = INET_analyze(&cBlock, expanded_name, node_name.c_str(), flags & ANALYZE_USER_VFY, pb,
8031-
cBlock.getConfig(), ref_db_name, cryptCb);
8031+
&parSet, cBlock.getConfig(), ref_db_name, cryptCb);
80328032
}
80338033
}
80348034
#endif
@@ -8043,7 +8043,7 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned
80438043
ISC_utf8ToSystem(node_name);
80448044

80458045
port = INET_analyze(&cBlock, expanded_name, node_name.c_str(), flags & ANALYZE_USER_VFY, pb,
8046-
cBlock.getConfig(), ref_db_name, cryptCb);
8046+
&parSet, cBlock.getConfig(), ref_db_name, cryptCb);
80478047
}
80488048
}
80498049
#endif
@@ -8066,7 +8066,7 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned
80668066
if (!port)
80678067
{
80688068
port = INET_analyze(&cBlock, attach_name, INET_LOCALHOST, flags & ANALYZE_USER_VFY, pb,
8069-
cBlock.getConfig(), ref_db_name, cryptCb);
8069+
&parSet, cBlock.getConfig(), ref_db_name, cryptCb);
80708070
}
80718071
}
80728072
}

src/remote/inet.cpp

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@
7777
#include <unistd.h>
7878
#endif
7979

80+
#ifdef HAVE_SYS_TIME_H
81+
#include <sys/time.h>
82+
#endif
8083

8184

8285
#ifdef WIN_NT
@@ -632,6 +635,7 @@ static rem_port* inet_try_connect( PACKET*,
632635
const PathName&,
633636
const TEXT*,
634637
ClumpletReader&,
638+
const ParametersSet*,
635639
RefPtr<const Config>*,
636640
const PathName*,
637641
int);
@@ -657,7 +661,7 @@ static int send_partial(rem_port*, PACKET *);
657661

658662
static RemoteXdr* xdrinet_create(rem_port*, UCHAR *, USHORT, enum xdr_op);
659663
static bool setNoNagleOption(rem_port*);
660-
static bool setKeepAlive(SOCKET);
664+
static bool setKeepAlive(SOCKET, rem_port* = nullptr);
661665
static FPTR_INT tryStopMainThread = 0;
662666

663667

@@ -797,6 +801,7 @@ rem_port* INET_analyze(ClntAuthBlock* cBlock,
797801
const TEXT* node_name,
798802
bool uv_flag,
799803
ClumpletReader &dpb,
804+
const ParametersSet* par,
800805
RefPtr<const Config>* config,
801806
const PathName* ref_db_name,
802807
ICryptKeyCallback* cryptCb,
@@ -900,7 +905,7 @@ rem_port* INET_analyze(ClntAuthBlock* cBlock,
900905
}
901906
}
902907

903-
rem_port* port = inet_try_connect(packet, rdb, file_name, node_name, dpb, config, ref_db_name, af);
908+
rem_port* port = inet_try_connect(packet, rdb, file_name, node_name, dpb, par, config, ref_db_name, af);
904909
P_ACPT* accept;
905910

906911
for (;;)
@@ -1032,6 +1037,7 @@ rem_port* INET_connect(const TEXT* name,
10321037
PACKET* packet,
10331038
USHORT flag,
10341039
ClumpletReader* dpb,
1040+
const ParametersSet* par,
10351041
RefPtr<const Config>* config,
10361042
int af,
10371043
bool disableTcp)
@@ -1069,7 +1075,7 @@ rem_port* INET_connect(const TEXT* name,
10691075
{
10701076
port->port_config = *config;
10711077
}
1072-
REMOTE_get_timeout_params(port, dpb);
1078+
REMOTE_get_timeout_params(port, dpb, par);
10731079

10741080
const RefPtr<const Config> portConfig = port->getPortConfig();
10751081
const bool explicitTcpPort = !packet && name && name[0];
@@ -1225,7 +1231,7 @@ rem_port* INET_connect(const TEXT* name,
12251231
return listener_socket(port, flag, pai);
12261232

12271233
// client
1228-
if (!setKeepAlive(port->port_handle))
1234+
if (!setKeepAlive(port->port_handle, port))
12291235
gds__log("setsockopt: error setting SO_KEEPALIVE");
12301236

12311237
if (!setNoNagleOption(port))
@@ -1553,7 +1559,7 @@ static rem_port* listener_socket(rem_port* port, USHORT flag, const addrinfo* pa
15531559
}
15541560
else
15551561
{
1556-
if (! setKeepAlive(port->port_handle))
1562+
if (! setKeepAlive(port->port_handle, port))
15571563
{
15581564
inet_error(true, port, "setsockopt SO_KEEPALIVE", isc_net_connect_listen_err, INET_ERRNO);
15591565
}
@@ -1701,7 +1707,7 @@ rem_port* INET_reconnect(SOCKET handle, bool unixSocket)
17011707
else
17021708
#endif
17031709
{
1704-
if (! setKeepAlive(port->port_handle)) {
1710+
if (! setKeepAlive(port->port_handle, port)) {
17051711
gds__log("inet server err: setting KEEPALIVE socket option \n");
17061712
}
17071713

@@ -1731,7 +1737,7 @@ rem_port* INET_server(SOCKET sock)
17311737
port->port_server_flags |= SRVR_server;
17321738
port->port_handle = sock;
17331739

1734-
if (! setKeepAlive(port->port_handle)) {
1740+
if (! setKeepAlive(port->port_handle, port)) {
17351741
gds__log("inet server err: setting KEEPALIVE socket option \n");
17361742
}
17371743

@@ -1870,7 +1876,7 @@ static rem_port* alloc_port(rem_port* const parent, const USHORT flags)
18701876
}
18711877

18721878
rem_port* const port = FB_NEW rem_port(rem_port::INET, INET_remote_buffer * 2);
1873-
REMOTE_get_timeout_params(port, 0);
1879+
REMOTE_get_timeout_params(port, nullptr, nullptr);
18741880

18751881
TEXT buffer[BUFFER_SMALL];
18761882
gethostname(buffer, sizeof(buffer));
@@ -3397,6 +3403,7 @@ static rem_port* inet_try_connect(PACKET* packet,
33973403
const PathName& file_name,
33983404
const TEXT* node_name,
33993405
ClumpletReader& dpb,
3406+
const ParametersSet* par,
34003407
RefPtr<const Config>* config,
34013408
const PathName* ref_db_name,
34023409
int af)
@@ -3431,7 +3438,7 @@ static rem_port* inet_try_connect(PACKET* packet,
34313438
rem_port* port = NULL;
34323439
try
34333440
{
3434-
port = INET_connect(node_name, packet, false, &dpb, config, af);
3441+
port = INET_connect(node_name, packet, false, &dpb, par, config, af);
34353442
}
34363443
catch (const Exception&)
34373444
{
@@ -3534,21 +3541,26 @@ static bool packet_receive(rem_port* port, UCHAR* buffer, SSHORT buffer_length,
35343541
}
35353542

35363543
timeval timeout{};
3537-
timeval* time_ptr = NULL;
3544+
timeval* time_ptr = &timeout;
35383545

3539-
if (port->port_protocol == 0)
3546+
if (port->port_protocol == 0 && port->port_connect_timeout)
35403547
{
35413548
// If the protocol is 0 we are still in the process of establishing
35423549
// a connection. Add a time out to the wait.
35433550
timeout.tv_sec = port->port_connect_timeout;
3544-
time_ptr = &timeout;
3551+
}
3552+
else if (port->port_receive_timeout)
3553+
{
3554+
// Should stop waiting and report error
3555+
timeout.tv_sec = port->port_receive_timeout;
35453556
}
35463557
else if (port->port_dummy_packet_interval > 0)
35473558
{
35483559
// Set the time interval for sending dummy packets to the client
35493560
timeout.tv_sec = port->port_dummy_packet_interval;
3550-
time_ptr = &timeout;
35513561
}
3562+
else
3563+
time_ptr = nullptr;
35523564

35533565
// On Linux systems (and possibly others too) select will eventually
35543566
// change timout values so save it here for later reuse.
@@ -3623,7 +3635,7 @@ static bool packet_receive(rem_port* port, UCHAR* buffer, SSHORT buffer_length,
36233635

36243636
if (!slct_count)
36253637
{
3626-
if (port->port_protocol == 0)
3638+
if (port->port_protocol == 0 || port->port_receive_timeout)
36273639
return false;
36283640

36293641
#ifdef DEBUG
@@ -3905,7 +3917,19 @@ static bool setNoNagleOption(rem_port* port)
39053917
return true;
39063918
}
39073919

3908-
static bool setKeepAlive(SOCKET s)
3920+
static bool setTimeout(SOCKET s, int timeout, int optname)
3921+
{
3922+
#ifdef WIN_NT
3923+
DWORD tv = timeout * 1000;
3924+
#else
3925+
struct timeval tv;
3926+
tv.tv_sec = timeout;
3927+
tv.tv_usec = 0;
3928+
#endif
3929+
return setsockopt(s, SOL_SOCKET, optname, &tv, sizeof(tv)) >= 0;
3930+
}
3931+
3932+
static bool setKeepAlive(SOCKET s, rem_port* port)
39093933
{
39103934
/**************************************
39113935
*
@@ -3914,14 +3938,32 @@ static bool setKeepAlive(SOCKET s)
39143938
**************************************
39153939
*
39163940
* Functional description
3917-
* Set SO_KEEPALIVE, return false
3918-
* in case of unexpected error
3941+
* Set SO_KEEPALIVE, SO_SNDTIMEO & SO_RCVTIMEO,
3942+
* return false in case of unexpected error.
39193943
*
39203944
**************************************/
39213945
constexpr int optval = 1;
39223946
const int n = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
39233947
(SCHAR*) &optval, sizeof(optval));
3924-
return n != -1;
3948+
if (n < 0)
3949+
return false;
3950+
3951+
if (port)
3952+
{
3953+
if (port->port_send_timeout)
3954+
{
3955+
if (!setTimeout(s, port->port_send_timeout, SO_SNDTIMEO))
3956+
return false;
3957+
}
3958+
3959+
if (port->port_receive_timeout)
3960+
{
3961+
if (!setTimeout(s, port->port_receive_timeout, SO_RCVTIMEO))
3962+
return false;
3963+
}
3964+
}
3965+
3966+
return true;
39253967
}
39263968

39273969
void setStopMainThread(FPTR_INT func)

src/remote/inet_proto.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,14 @@ namespace Firebird
3333
class ClumpletReader;
3434
}
3535

36-
rem_port* INET_analyze(ClntAuthBlock*, const Firebird::PathName&, const TEXT*,
37-
bool, Firebird::ClumpletReader&, Firebird::RefPtr<const Firebird::Config>*,
36+
struct ParametersSet;
37+
38+
rem_port* INET_analyze(ClntAuthBlock*, const Firebird::PathName&, const TEXT*, bool,
39+
Firebird::ClumpletReader&, const ParametersSet*, Firebird::RefPtr<const Firebird::Config>*,
3840
const Firebird::PathName*, Firebird::ICryptKeyCallback*, int af = AF_UNSPEC);
3941
rem_port* INET_connect(const TEXT*, struct packet*, USHORT, Firebird::ClumpletReader*,
40-
Firebird::RefPtr<const Firebird::Config>*, int af = AF_UNSPEC,
41-
bool disableTcp = false);
42+
const ParametersSet* par, Firebird::RefPtr<const Firebird::Config>*,
43+
int af = AF_UNSPEC, bool disableTcp = false);
4244
bool INET_shouldListenUnix(const TEXT*, bool disableTcp);
4345
rem_port* INET_listenUnix(USHORT);
4446
void INET_addUnixListener(rem_port*, USHORT);

src/remote/remot_proto.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,15 @@ struct RemoteXdr : public xdr_t
4949

5050
struct rem_fmt;
5151
struct Rdb;
52+
struct ParametersSet;
5253
typedef bool PacketReceive(rem_port*, UCHAR*, SSHORT, SSHORT*);
5354
typedef bool PacketSend(rem_port*, const SCHAR*, SSHORT);
5455
typedef bool ProtoWrite(RemoteXdr*);
5556
enum LegacyPlugin {PLUGIN_NEW = 0, PLUGIN_LEGACY, PLUGIN_TRUSTED};
5657

5758
void REMOTE_cleanup_transaction (struct Rtr *);
5859
USHORT REMOTE_compute_batch_size(const rem_port*, USHORT, P_OP, const rem_fmt*) noexcept;
59-
void REMOTE_get_timeout_params(rem_port* port, Firebird::ClumpletReader* pb);
60+
void REMOTE_get_timeout_params(rem_port* port, Firebird::ClumpletReader* pb, const ParametersSet* par);
6061
struct Rrq* REMOTE_find_request (struct Rrq *, USHORT);
6162
void REMOTE_free_packet(rem_port*, PACKET*, bool = false);
6263
struct rem_str* REMOTE_make_string (const SCHAR*);

src/remote/remote.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,10 @@ const ParametersSet dpbParam =
7272
isc_dpb_os_user,
7373
isc_dpb_config,
7474
isc_dpb_utf8_filename,
75-
isc_dpb_map_attach
75+
isc_dpb_map_attach,
76+
isc_dpb_connect_timeout,
77+
isc_dpb_send_timeout,
78+
isc_dpb_receive_timeout
7679
};
7780

7881
const ParametersSet spbParam =
@@ -96,7 +99,10 @@ const ParametersSet spbParam =
9699
isc_spb_os_user,
97100
isc_spb_config,
98101
isc_spb_utf8_filename,
99-
0
102+
0,
103+
isc_spb_connect_timeout,
104+
isc_spb_send_timeout,
105+
isc_spb_receive_timeout
100106
};
101107

102108
const ParametersSet connectParam =
@@ -120,6 +126,9 @@ const ParametersSet connectParam =
120126
CNCT_user,
121127
0,
122128
0,
129+
0,
130+
0,
131+
0,
123132
0
124133
};
125134

@@ -352,7 +361,7 @@ void REMOTE_free_packet(rem_port* port, PACKET* packet, bool partial)
352361
}
353362

354363

355-
void REMOTE_get_timeout_params(rem_port* port, ClumpletReader* pb)
364+
void REMOTE_get_timeout_params(rem_port* port, ClumpletReader* pb, const ParametersSet* par)
356365
{
357366
/**************************************
358367
*
@@ -368,13 +377,12 @@ void REMOTE_get_timeout_params(rem_port* port, ClumpletReader* pb)
368377
* is no other specification.
369378
*
370379
**************************************/
371-
//bool got_dpb_connect_timeout = false;
372-
373-
fb_assert(isc_dpb_connect_timeout == isc_spb_connect_timeout);
374-
375-
port->port_connect_timeout = pb && pb->find(isc_dpb_connect_timeout) ?
380+
port->port_connect_timeout = pb && pb->find(par->connect_timeout) ?
376381
pb->getInt() : port->getPortConfig()->getConnectionTimeout();
377382

383+
port->port_send_timeout = pb && pb->find(par->send_timeout) ? pb->getInt() : 0;
384+
port->port_receive_timeout = pb && pb->find(par->receive_timeout) ? pb->getInt() : 0;
385+
378386
port->port_flags |= PORT_dummy_pckt_set;
379387
port->port_dummy_packet_interval = port->getPortConfig()->getDummyPacketInterval();
380388
if (port->port_dummy_packet_interval < 0)

0 commit comments

Comments
 (0)