| |
@@ -940,6 +940,10 @@
|
| |
#define CONN_TURBO_PERCENTILE 50 /* proportion of threads allowed to be in turbo mode */
|
| |
#define CONN_TURBO_HYSTERESIS 0 /* avoid flip flopping in and out of turbo mode */
|
| |
|
| |
+ #define CONN_TIMEOUT_READ_SECURE 100 /* on secure connection a read can block if there
|
| |
+ * nothing to read. This timeout (millisecond)
|
| |
+ * is the maximum delay a worker will poll the connection
|
| |
+ */
|
| |
void
|
| |
connection_make_new_pb(Slapi_PBlock *pb, Connection *conn)
|
| |
{
|
| |
@@ -1091,11 +1095,78 @@
|
| |
return 0;
|
| |
}
|
| |
|
| |
+ /* this function is specific to secure socket that are in blocking mode
|
| |
+ * It polls the socket to check if we can read it
|
| |
+ * It returns
|
| |
+ * ret < 0: a poll failed (different from E_WOULD_BLOCK) 'err' is set
|
| |
+ * ret = 0: the socket can not be read for ioblocktimeout
|
| |
+ * ret > 0: the socket can be read
|
| |
+ */
|
| |
+ static int
|
| |
+ connection_poll_read_secure(Connection *conn, PRInt32 *err)
|
| |
+ {
|
| |
+ int32_t ioblocktimeout_waits = conn->c_ioblocktimeout / CONN_TIMEOUT_READ_SECURE;
|
| |
+ int32_t waits_done = 0;
|
| |
+ struct PRPollDesc pr_pd;
|
| |
+ PRInt32 ret;
|
| |
+ PRInt32 syserr = 0;
|
| |
+ PRIntervalTime timeout = PR_MillisecondsToInterval(CONN_TIMEOUT_READ_SECURE);
|
| |
+
|
| |
+ /* The purpose of the loop is to check we can read the socket within the ioblocktimeout limit */
|
| |
+ do {
|
| |
+ pr_pd.fd = (PRFileDesc *) conn->c_prfd;
|
| |
+ pr_pd.in_flags = PR_POLL_READ;
|
| |
+ pr_pd.out_flags = 0;
|
| |
+ ret = PR_Poll(&pr_pd, 1, timeout);
|
| |
+ if (ret > 1) {
|
| |
+ /* most frequent case. Socket can be read right now so exit from the loop */
|
| |
+ break;
|
| |
+ } else if (ret == 0) {
|
| |
+ /* timeout */
|
| |
+ waits_done++;
|
| |
+ } else if (ret < 0) {
|
| |
+ syserr = PR_GetOSError();
|
| |
+ if (SLAPD_SYSTEM_WOULD_BLOCK_ERROR(syserr)) {
|
| |
+ /* If we would block, let's count it as a timeout and continue the loop */
|
| |
+ waits_done++;
|
| |
+ ret = 0;
|
| |
+ } else {
|
| |
+ /* A failure on a poll, no need to continue */
|
| |
+ *err = PR_GetError();
|
| |
+ break;
|
| |
+ }
|
| |
+ }
|
| |
+
|
| |
+ if (waits_done > ioblocktimeout_waits) {
|
| |
+ /* We have been polling longer than ioblocktimeout
|
| |
+ * It is time to say it hang for too long
|
| |
+ */
|
| |
+ slapi_log_err(SLAPI_LOG_INFO, "connection_poll_read_secure",
|
| |
+ "Timeout (%d ms) while reading secured conn %" PRIu64 "\n", conn->c_ioblocktimeout, conn->c_connid);
|
| |
+ ret = 0;
|
| |
+ break;
|
| |
+ }
|
| |
+ } while (ret == 0);
|
| |
+
|
| |
+ /* At this point we have 3 options
|
| |
+ * ret < 0: a poll failed
|
| |
+ * ret = 0: the socket can not be read for ioblocktimeout
|
| |
+ * ret > 0: the socket can be read
|
| |
+ */
|
| |
+ return (int) ret;
|
| |
+ }
|
| |
/* Either read read data into the connection buffer, or fail with err set */
|
| |
static int
|
| |
connection_read_ldap_data(Connection *conn, PRInt32 *err)
|
| |
{
|
| |
int ret = 0;
|
| |
+ if (conn->c_flags & CONN_FLAG_SSL) {
|
| |
+ ret = connection_poll_read_secure(conn, err);
|
| |
+ if (ret <= 0) {
|
| |
+ /* The socket hang for ioblocktimeout or poll failed */
|
| |
+ return ret;
|
| |
+ }
|
| |
+ }
|
| |
ret = PR_Recv(conn->c_prfd, conn->c_private->c_buffer, conn->c_private->c_buffer_size, 0, PR_INTERVAL_NO_WAIT);
|
| |
if (ret < 0) {
|
| |
*err = PR_GetError();
|
| |
@@ -1140,7 +1211,7 @@
|
| |
{
|
| |
ber_len_t len = 0;
|
| |
int ret = 0;
|
| |
- int waits_done = 0;
|
| |
+ int32_t waits_done = 0;
|
| |
ber_int_t msgid;
|
| |
int new_operation = 1; /* Are we doing the first I/O read for a new operation ? */
|
| |
char *buffer = conn->c_private->c_buffer;
|
| |
Bug Description:
A secure socket is configured in blocking mode. If an event
is detected on a secure socket a worker, tries to read the request.
The read can hang indefinitely if there is nothing to read.
As a consequence ioblocktimeout is not enforced when reading secure socket
Fix Description:
The fix is specific to secure socket read.
Before reading it polls the socket for a read. The socket is poll
(with a 0.1s timeout) until read is possible or sum of poll timeout
is greater than ioblocktimeout.
https://pagure.io/389-ds-base/issue/50329
Reviewed by: Mark Reynolds
Platforms tested: F28
Flag Day: no
Doc impact: no