summaryrefslogtreecommitdiff
path: root/security/nss/lib/ssl
diff options
context:
space:
mode:
authornelsonb%netscape.com <devnull@localhost>2001-03-16 23:26:06 +0000
committernelsonb%netscape.com <devnull@localhost>2001-03-16 23:26:06 +0000
commitd8ab311c760a8eacecb68be525b42741eebed383 (patch)
tree78ef3ceb522f6a80c425841f0d49a7b821dc6035 /security/nss/lib/ssl
parent50fbf2ed9c277623fc1014197175409bfbf9933a (diff)
downloadnss-hg-d8ab311c760a8eacecb68be525b42741eebed383.tar.gz
Reinterpret the READ and WRITE poll flags depending on the state of the
socket and the SSL handshake. Rename the badly named "connected" flag. Bugzilla bugs 56924, 56926, 66706. Modified Files: ssl3con.c sslauth.c sslcon.c ssldef.c sslgathr.c sslimpl.h sslsecur.c sslsock.c
Diffstat (limited to 'security/nss/lib/ssl')
-rw-r--r--security/nss/lib/ssl/ssl3con.c21
-rw-r--r--security/nss/lib/ssl/sslauth.c2
-rw-r--r--security/nss/lib/ssl/sslcon.c3
-rw-r--r--security/nss/lib/ssl/ssldef.c6
-rw-r--r--security/nss/lib/ssl/sslgathr.c4
-rw-r--r--security/nss/lib/ssl/sslimpl.h16
-rw-r--r--security/nss/lib/ssl/sslsecur.c79
-rw-r--r--security/nss/lib/ssl/sslsock.c102
8 files changed, 161 insertions, 72 deletions
diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c
index e46a4cae5..f264ff532 100644
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -1327,6 +1327,7 @@ spec_locked_loser:
if (!(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) {
+ ss->handshakeBegun = 1;
count = ssl_SendSavedWriteData(ss, &ss->pendingBuf,
&ssl_DefSend);
if (count < 0 && PR_GetError() != PR_WOULD_BLOCK_ERROR) {
@@ -1335,6 +1336,7 @@ spec_locked_loser:
}
}
} else if (write->len > 0) {
+ ss->handshakeBegun = 1;
count = ssl_DefSend(ss, write->buf, write->len,
flags & ~ssl_SEND_FLAG_MASK);
if (count < 0) {
@@ -1455,12 +1457,12 @@ ssl3_HandleNoCertificate(sslSocket *ss)
/* If the server has required client-auth blindly but doesn't
* actually look at the certificate it won't know that no
* certificate was presented so we shutdown the socket to ensure
- * an error. We only do this if we aren't connected because
- * if we're redoing the handshake we know the server is paying
- * attention to the certificate.
+ * an error. We only do this if we haven't already completed the
+ * first handshake because if we're redoing the handshake we
+ * know the server is paying attention to the certificate.
*/
if ((ss->requireCertificate == 1) ||
- (!ss->connected && (ss->requireCertificate > 1))) {
+ (!ss->firstHsDone && (ss->requireCertificate > 1))) {
PRFileDesc * lower;
ss->sec->uncache(ss->sec->ci.sid);
@@ -4616,7 +4618,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
*/
if ((sid->peerCert == NULL) && ss->requestCertificate &&
((ss->requireCertificate == 1) ||
- ((ss->requireCertificate == 2) && !ss->connected))) {
+ ((ss->requireCertificate == 2) && !ss->firstHsDone))) {
++ssl3stats.hch_sid_cache_not_ok;
ss->sec->uncache(sid);
@@ -6494,9 +6496,9 @@ xmit_loser:
ssl_ReleaseXmitBufLock(ss); /*************************************/
- /* we're connected now. */
+ /* The first handshake is now completed. */
ss->handshake = NULL;
- ss->connected = PR_TRUE;
+ ss->firstHsDone = PR_TRUE;
ss->gather->writeOffset = 0;
ss->gather->readOffset = 0;
@@ -7445,7 +7447,8 @@ ssl3_ConstructV2CipherSpecsHack(sslSocket *ss, unsigned char *cs, int *size)
}
/*
-** If ssl3 socket is connected and in idle state, then start a new handshake.
+** If ssl3 socket has completed the first handshake, and is in idle state,
+** then start a new handshake.
** If flushCache is true, the SID cache will be flushed first, forcing a
** "Full" handshake (not a session restart handshake), to be done.
**
@@ -7460,7 +7463,7 @@ ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache)
PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) );
- if (!ss->connected ||
+ if (!ss->firstHsDone ||
((ss->version >= SSL_LIBRARY_VERSION_3_0) &&
ss->ssl3 && (ss->ssl3->hs.ws != idle_handshake))) {
PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED);
diff --git a/security/nss/lib/ssl/sslauth.c b/security/nss/lib/ssl/sslauth.c
index d96f12ad3..96bfbd6a8 100644
--- a/security/nss/lib/ssl/sslauth.c
+++ b/security/nss/lib/ssl/sslauth.c
@@ -84,7 +84,7 @@ SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1,
*op = SSL_SECURITY_STATUS_OFF;
}
- if (ss->useSecurity && ss->connected) {
+ if (ss->useSecurity && ss->firstHsDone) {
PORT_Assert(ss->sec != 0);
sec = ss->sec;
diff --git a/security/nss/lib/ssl/sslcon.c b/security/nss/lib/ssl/sslcon.c
index 05d5ed744..99bc0a787 100644
--- a/security/nss/lib/ssl/sslcon.c
+++ b/security/nss/lib/ssl/sslcon.c
@@ -546,6 +546,7 @@ ssl2_SendErrorMessage(sslSocket *ss, int error)
SSL_TRC(3, ("%d: SSL[%d]: sending error %d", SSL_GETPID(), ss->fd, error));
+ ss->handshakeBegun = 1;
rv = (*sec->send)(ss, msg, sizeof(msg), 0);
if (rv >= 0) {
rv = SECSuccess;
@@ -3102,6 +3103,7 @@ invalid:
/* Send it to the server */
DUMP_MSG(29, (ss, msg, sendLen));
+ ss->handshakeBegun = 1;
rv = (*sec->send)(ss, msg, sendLen, 0);
ssl_ReleaseXmitBufLock(ss); /***************************************/
@@ -3595,6 +3597,7 @@ ssl2_HandleClientHelloMessage(sslSocket *ss)
DUMP_MSG(29, (ss, msg, sendLen));
+ ss->handshakeBegun = 1;
sent = (*sec->send)(ss, msg, sendLen, 0);
if (sent < 0) {
goto loser;
diff --git a/security/nss/lib/ssl/ssldef.c b/security/nss/lib/ssl/ssldef.c
index c91643ecc..76434c56f 100644
--- a/security/nss/lib/ssl/ssldef.c
+++ b/security/nss/lib/ssl/ssldef.c
@@ -115,8 +115,10 @@ int ssl_DefSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
if (rv < 0) {
PRErrorCode err = PR_GetError();
if (err == PR_WOULD_BLOCK_ERROR) {
+ ss->lastWriteBlocked = 1;
return count ? count : rv;
}
+ ss->lastWriteBlocked = 0;
MAP_ERROR(PR_CONNECT_ABORTED_ERROR, PR_CONNECT_RESET_ERROR)
/* Loser */
return rv;
@@ -130,6 +132,7 @@ int ssl_DefSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
}
break;
}
+ ss->lastWriteBlocked = 0;
return count;
}
@@ -157,8 +160,10 @@ int ssl_DefWrite(sslSocket *ss, const unsigned char *buf, int len)
if (rv < 0) {
PRErrorCode err = PR_GetError();
if (err == PR_WOULD_BLOCK_ERROR) {
+ ss->lastWriteBlocked = 1;
return count ? count : rv;
}
+ ss->lastWriteBlocked = 0;
MAP_ERROR(PR_CONNECT_ABORTED_ERROR, PR_CONNECT_RESET_ERROR)
/* Loser */
return rv;
@@ -172,6 +177,7 @@ int ssl_DefWrite(sslSocket *ss, const unsigned char *buf, int len)
}
break;
}
+ ss->lastWriteBlocked = 0;
return count;
}
diff --git a/security/nss/lib/ssl/sslgathr.c b/security/nss/lib/ssl/sslgathr.c
index e9176172f..1d316db84 100644
--- a/security/nss/lib/ssl/sslgathr.c
+++ b/security/nss/lib/ssl/sslgathr.c
@@ -139,7 +139,7 @@ ssl2_GatherData(sslSocket *ss, sslGather *gs, int flags)
/* Probably finished this piece */
switch (gs->state) {
case GS_HEADER:
- if ((ss->enableSSL3 || ss->enableTLS) && !ss->connected) {
+ if ((ss->enableSSL3 || ss->enableTLS) && !ss->firstHsDone) {
PORT_Assert( ssl_Have1stHandshakeLock(ss) );
@@ -183,7 +183,7 @@ ssl2_GatherData(sslSocket *ss, sslGather *gs, int flags)
return SECFailure;
}
}
- } /* ((ss->enableSSL3 || ss->enableTLS) && !ss->connected) */
+ } /* ((ss->enableSSL3 || ss->enableTLS) && !ss->firstHsDone) */
/* we've got the first 3 bytes. The header may be two or three. */
if (gs->hdr[0] & 0x80) {
diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h
index 7eb52e56c..53aba0a86 100644
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -238,6 +238,11 @@ typedef struct sslOptionsStr {
unsigned int detectRollBack : 1; /* 14 */
} sslOptions;
+typedef enum { sslHandshakingUndetermined = 0,
+ sslHandshakingAsClient,
+ sslHandshakingAsServer
+} sslHandshakingType;
+
/*
** SSL Socket struct
**
@@ -254,20 +259,23 @@ struct sslSocketStr {
unsigned int useSecurity : 1;
unsigned int requestCertificate : 1;
unsigned int requireCertificate : 2;
-
unsigned int handshakeAsClient : 1;
unsigned int handshakeAsServer : 1;
unsigned int enableSSL2 : 1;
+
unsigned int enableSSL3 : 1;
unsigned int enableTLS : 1;
-
unsigned int clientAuthRequested: 1;
unsigned int noCache : 1;
unsigned int fdx : 1; /* simultaneous read/write threads */
unsigned int v2CompatibleHello : 1; /* Send v3+ client hello in v2 format */
unsigned int detectRollBack : 1; /* Detect rollback to SSL v3 */
- unsigned int connected : 1; /* initial handshake is complete. */
+ unsigned int firstHsDone : 1; /* first handshake is complete. */
+
unsigned int recvdCloseNotify : 1; /* received SSL EOF. */
+ unsigned int lastWriteBlocked : 1;
+ unsigned int TCPconnected : 1;
+ unsigned int handshakeBegun : 1;
/* version of the protocol to use */
SSL3ProtocolVersion version;
@@ -353,6 +361,8 @@ const unsigned char * preferredCipher;
PRUint16 maybeAllowedByPolicy; /* copy of global policy bits. */
PRUint16 chosenPreference; /* SSL2 cipher preferences. */
+ sslHandshakingType handshaking;
+
ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED];
};
diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c
index f5f5bab16..9d03ed872 100644
--- a/security/nss/lib/ssl/sslsecur.c
+++ b/security/nss/lib/ssl/sslsecur.c
@@ -143,12 +143,12 @@ ssl_Do1stHandshake(sslSocket *ss)
/* for v3 this is done in ssl3_HandleFinished() */
if ((ss->sec != NULL) && /* used SSL */
(ss->handshakeCallback != NULL) && /* has callback */
- (!ss->connected) && /* only first time */
+ (!ss->firstHsDone) && /* only first time */
(ss->version < SSL_LIBRARY_VERSION_3_0)) { /* not ssl3 */
- ss->connected = PR_TRUE;
+ ss->firstHsDone = PR_TRUE;
(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
}
- ss->connected = PR_TRUE;
+ ss->firstHsDone = PR_TRUE;
ss->gather->writeOffset = 0;
ss->gather->readOffset = 0;
break;
@@ -187,7 +187,7 @@ AlwaysBlock(sslSocket *ss)
void
ssl_SetAlwaysBlock(sslSocket *ss)
{
- if (!ss->connected) {
+ if (!ss->firstHsDone) {
ss->handshake = AlwaysBlock;
ss->nextHandshake = 0;
}
@@ -200,6 +200,7 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool asServer)
{
sslSocket *ss;
SECStatus rv;
+ PRNetAddr addr;
ss = ssl_FindSocket(s);
if (!ss) {
@@ -218,9 +219,14 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool asServer)
ssl_Get1stHandshakeLock(ss);
ssl_GetSSL3HandshakeLock(ss);
- ss->connected = PR_FALSE;
- ss->handshake = asServer ? ssl2_BeginServerHandshake
- : ssl2_BeginClientHandshake;
+ ss->firstHsDone = PR_FALSE;
+ if ( asServer ) {
+ ss->securityHandshake = ssl2_BeginServerHandshake;
+ ss->handshaking = sslHandshakingAsServer;
+ } else {
+ ss->securityHandshake = ssl2_BeginClientHandshake;
+ ss->handshaking = sslHandshakingAsClient;
+ }
ss->nextHandshake = 0;
ss->securityHandshake = 0;
@@ -244,6 +250,9 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool asServer)
ssl_ReleaseSSL3HandshakeLock(ss);
ssl_Release1stHandshakeLock(ss);
+ if (!ss->TCPconnected)
+ ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr));
+
SSL_UNLOCK_WRITER(ss);
SSL_UNLOCK_READER(ss);
@@ -369,10 +378,11 @@ SSL_ForceHandshake(PRFileDesc *fd)
} else if (gatherResult == SECWouldBlock) {
PORT_SetError(PR_WOULD_BLOCK_ERROR);
}
- } else if (!ss->connected) {
+ } else if (!ss->firstHsDone) {
rv = ssl_Do1stHandshake(ss);
} else {
- /* tried to force handshake on a connected SSL 2 socket. */
+ /* tried to force handshake on an SSL 2 socket that has
+ ** already completed the handshake. */
rv = SECSuccess; /* just pretend we did it. */
}
@@ -882,32 +892,29 @@ ssl_SecureConnect(sslSocket *ss, const PRNetAddr *sa)
PORT_Assert(ss->sec != 0);
- /* First connect to server */
- rv = osfd->methods->connect(osfd, sa, ss->cTimeout);
- if (rv < 0) {
- int olderrno = PR_GetError();
- SSL_DBG(("%d: SSL[%d]: connect failed, errno=%d",
- SSL_GETPID(), ss->fd, olderrno));
- if ((olderrno == PR_IS_CONNECTED_ERROR) ||
- (olderrno == PR_IN_PROGRESS_ERROR)) {
- /*
- ** Connected or trying to connect. Caller is Using a non-blocking
- ** connect. Go ahead and set things up.
- */
- } else {
- return rv;
- }
- }
-
- SSL_TRC(5, ("%d: SSL[%d]: secure connect completed, setting up handshake",
- SSL_GETPID(), ss->fd));
-
if ( ss->handshakeAsServer ) {
ss->securityHandshake = ssl2_BeginServerHandshake;
+ ss->handshaking = sslHandshakingAsServer;
} else {
ss->securityHandshake = ssl2_BeginClientHandshake;
+ ss->handshaking = sslHandshakingAsClient;
}
-
+
+ /* connect to server */
+ rv = osfd->methods->connect(osfd, sa, ss->cTimeout);
+ if (rv == PR_SUCCESS) {
+ ss->TCPconnected = 1;
+ } else {
+ int err = PR_GetError();
+ SSL_DBG(("%d: SSL[%d]: connect failed, errno=%d",
+ SSL_GETPID(), ss->fd, err));
+ if (err == PR_IS_CONNECTED_ERROR) {
+ ss->TCPconnected = 1;
+ }
+ }
+
+ SSL_TRC(5, ("%d: SSL[%d]: secure connect completed, rv == %d",
+ SSL_GETPID(), ss->fd, rv));
return rv;
}
@@ -917,8 +924,9 @@ ssl_SecureClose(sslSocket *ss)
int rv;
if (ss->version >= SSL_LIBRARY_VERSION_3_0 &&
- ss->connected &&
+ ss->firstHsDone &&
!(ss->shutdownHow & ssl_SHUTDOWN_SEND) &&
+ !ss->recvdCloseNotify &&
(ss->ssl3 != NULL)) {
(void) SSL3_SendAlert(ss, alert_warning, close_notify);
@@ -943,7 +951,8 @@ ssl_SecureShutdown(sslSocket *ss, int nsprHow)
if ((sslHow & ssl_SHUTDOWN_SEND) != 0 &&
!(ss->shutdownHow & ssl_SHUTDOWN_SEND) &&
(ss->version >= SSL_LIBRARY_VERSION_3_0) &&
- ss->connected &&
+ ss->firstHsDone &&
+ !ss->recvdCloseNotify &&
(ss->ssl3 != NULL)) {
(void) SSL3_SendAlert(ss, alert_warning, close_notify);
@@ -992,7 +1001,7 @@ ssl_SecureRecv(sslSocket *ss, unsigned char *buf, int len, int flags)
rv = 0;
/* If any of these is non-zero, the initial handshake is not done. */
- if (!ss->connected) {
+ if (!ss->firstHsDone) {
ssl_Get1stHandshakeLock(ss);
if (ss->handshake || ss->nextHandshake || ss->securityHandshake) {
rv = ssl_Do1stHandshake(ss);
@@ -1054,7 +1063,7 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
if (len > 0)
ss->writerThread = PR_GetCurrentThread();
/* If any of these is non-zero, the initial handshake is not done. */
- if (!ss->connected) {
+ if (!ss->firstHsDone) {
ssl_Get1stHandshakeLock(ss);
if (ss->handshake || ss->nextHandshake || ss->securityHandshake) {
rv = ssl_Do1stHandshake(ss);
@@ -1214,7 +1223,7 @@ SSL_GetSessionID(PRFileDesc *fd)
ssl_Get1stHandshakeLock(ss);
ssl_GetSSL3HandshakeLock(ss);
- if (ss->useSecurity && ss->connected && ss->sec && ss->sec->ci.sid) {
+ if (ss->useSecurity && ss->firstHsDone && ss->sec && ss->sec->ci.sid) {
sid = ss->sec->ci.sid;
item = (SECItem *)PORT_Alloc(sizeof(SECItem));
if (sid->version < SSL_LIBRARY_VERSION_3_0) {
diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c
index 431345db3..ab9c8c0a2 100644
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -897,6 +897,7 @@ SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd)
{
sslSocket * ns = NULL;
PRStatus rv;
+ PRNetAddr addr;
if (model == NULL) {
/* Just create a default socket if we're given NULL for the model */
@@ -922,6 +923,10 @@ SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd)
#ifdef _WIN32
PR_Sleep(PR_INTERVAL_NO_WAIT); /* workaround NT winsock connect bug. */
#endif
+ ns = ssl_FindSocket(fd);
+ PORT_Assert(ns);
+ if (ns)
+ ns->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ns, &addr));
return fd;
}
@@ -984,10 +989,13 @@ ssl_Accept(PRFileDesc *fd, PRNetAddr *sockaddr, PRIntervalTime timeout)
if ( ns->useSecurity ) {
if ( ns->handshakeAsClient ) {
ns->handshake = ssl2_BeginClientHandshake;
+ ss->handshaking = sslHandshakingAsClient;
} else {
ns->handshake = ssl2_BeginServerHandshake;
+ ss->handshaking = sslHandshakingAsServer;
}
}
+ ns->TCPconnected = 1;
return newfd;
loser:
@@ -1236,6 +1244,7 @@ ssl_GetPeerInfo(sslSocket *ss)
if (rv < 0) {
return SECFailure;
}
+ ss->TCPconnected = 1;
/* we have to mask off the high byte because AIX is lame */
if ((sin.inet.family & 0xff) == PR_AF_INET) {
PR_ConvertIPv4AddrToIPv6(sin.inet.ip, &ci->peer);
@@ -1277,13 +1286,16 @@ SSL_SetSockPeerID(PRFileDesc *fd, char *peerID)
return SECSuccess;
}
+#define PR_POLL_RW (PR_POLL_WRITE | PR_POLL_READ)
+
static PRInt16 PR_CALLBACK
-ssl_Poll(PRFileDesc *fd, PRInt16 how_flags, PRInt16 *out_flags)
+ssl_Poll(PRFileDesc *fd, PRInt16 how_flags, PRInt16 *p_out_flags)
{
sslSocket *ss;
- PRInt16 ret_flags = how_flags; /* should select on these flags. */
+ PRInt16 new_flags = how_flags; /* should select on these flags. */
+ PRNetAddr addr;
- *out_flags = 0;
+ *p_out_flags = 0;
ss = ssl_GetPrivate(fd);
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in SSL_Poll",
@@ -1291,27 +1303,73 @@ ssl_Poll(PRFileDesc *fd, PRInt16 how_flags, PRInt16 *out_flags)
return 0; /* don't poll on this socket */
}
- if ((ret_flags & PR_POLL_WRITE) &&
- ss->useSecurity &&
- !ss->connected &&
- /* XXX There needs to be a better test than the following. */
- /* Don't check ss->securityHandshake. */
- (ss->handshake || ss->nextHandshake)) {
- /* The user is trying to write, but the handshake is blocked waiting
- * to read, so tell NSPR NOT to poll on write.
- */
- ret_flags ^= PR_POLL_WRITE; /* don't select on write. */
- ret_flags |= PR_POLL_READ; /* do select on read. */
- }
-
- if ((ret_flags & PR_POLL_READ) && (SSL_DataPending(fd) > 0)) {
- *out_flags = PR_POLL_READ; /* it's ready already. */
-
- } else if (ret_flags && (fd->lower->methods->poll != NULL)) {
- ret_flags = fd->lower->methods->poll(fd->lower, ret_flags, out_flags);
+ if (ss->useSecurity &&
+ ss->handshaking != sslHandshakingUndetermined &&
+ !ss->firstHsDone &&
+ (how_flags & PR_POLL_RW)) {
+ if (!ss->TCPconnected) {
+ ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr));
+ }
+ /* If it's not connected, then presumably the application is polling
+ ** on read or write appropriately, so don't change it.
+ */
+ if (ss->TCPconnected) {
+ if (!ss->handshakeBegun) {
+ /* If the handshake has not begun, poll on read or write
+ ** based on the local application's role in the handshake,
+ ** not based on what the application requested.
+ */
+ new_flags &= ~PR_POLL_RW;
+ if (ss->handshaking == sslHandshakingAsClient) {
+ new_flags |= PR_POLL_WRITE;
+ } else { /* handshaking as server */
+ new_flags |= PR_POLL_READ;
+ }
+ } else
+ /* First handshake is in progress */
+ if (ss->lastWriteBlocked) {
+ if (new_flags & PR_POLL_READ) {
+ /* The caller is waiting for data to be received,
+ ** but the initial handshake is blocked on write, or the
+ ** client's first handshake record has not been written.
+ ** The code should select on write, not read.
+ */
+ new_flags ^= PR_POLL_READ; /* don't select on read. */
+ new_flags |= PR_POLL_WRITE; /* do select on write. */
+ }
+ } else if (new_flags & PR_POLL_WRITE) {
+ /* The caller is trying to write, but the handshake is
+ ** blocked waiting for data to read, and the first
+ ** handshake has been sent. so do NOT to poll on write.
+ */
+ new_flags ^= PR_POLL_WRITE; /* don't select on write. */
+ new_flags |= PR_POLL_READ; /* do select on read. */
+ }
+ }
+ } else if ((new_flags & PR_POLL_READ) && (SSL_DataPending(fd) > 0)) {
+ *p_out_flags = PR_POLL_READ; /* it's ready already. */
+ return new_flags;
+ }
+ if (new_flags && (fd->lower->methods->poll != NULL)) {
+ PRInt16 lower_out_flags = 0;
+ PRInt16 lower_new_flags;
+ lower_new_flags = fd->lower->methods->poll(fd->lower, new_flags,
+ &lower_out_flags);
+ if ((lower_new_flags & lower_out_flags) && (how_flags != new_flags)) {
+ PRInt16 out_flags = lower_out_flags & ~PR_POLL_RW;
+ if (lower_out_flags & PR_POLL_READ)
+ out_flags |= PR_POLL_WRITE;
+ if (lower_out_flags & PR_POLL_WRITE)
+ out_flags |= PR_POLL_READ;
+ *p_out_flags = out_flags;
+ new_flags = how_flags;
+ } else {
+ *p_out_flags = lower_out_flags;
+ new_flags = lower_new_flags;
+ }
}
- return ret_flags;
+ return new_flags;
}