diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index 8ef555054c0a..2fc6a06cca45 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/lib/ssl/ssl3con.c @@ -32,7 +32,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: ssl3con.c,v 1.16 2001/02/07 00:34:54 nelsonb%netscape.com Exp $ + * $Id: ssl3con.c,v 1.17 2001/03/16 23:25:59 nelsonb%netscape.com Exp $ */ #include "nssrenam.h" @@ -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 1899bd919863..65ab81354408 100644 --- a/security/nss/lib/ssl/sslauth.c +++ b/security/nss/lib/ssl/sslauth.c @@ -30,7 +30,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: sslauth.c,v 1.4 2001/02/09 02:11:30 nelsonb%netscape.com Exp $ + * $Id: sslauth.c,v 1.5 2001/03/16 23:26:02 nelsonb%netscape.com Exp $ */ #include "cert.h" #include "secitem.h" @@ -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 27fc46d89b46..f5b1717d8c07 100644 --- a/security/nss/lib/ssl/sslcon.c +++ b/security/nss/lib/ssl/sslcon.c @@ -32,7 +32,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: sslcon.c,v 1.6 2001/01/30 21:02:24 wtc%netscape.com Exp $ + * $Id: sslcon.c,v 1.7 2001/03/16 23:26:02 nelsonb%netscape.com Exp $ */ #include "nssrenam.h" @@ -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 c91669140d1e..78e683df8526 100644 --- a/security/nss/lib/ssl/ssldef.c +++ b/security/nss/lib/ssl/ssldef.c @@ -32,7 +32,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: ssldef.c,v 1.2 2000/10/07 02:22:22 nelsonb%netscape.com Exp $ + * $Id: ssldef.c,v 1.3 2001/03/16 23:26:03 nelsonb%netscape.com Exp $ */ #include "cert.h" @@ -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 07266f02c47d..fa5c0e6474e3 100644 --- a/security/nss/lib/ssl/sslgathr.c +++ b/security/nss/lib/ssl/sslgathr.c @@ -32,7 +32,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: sslgathr.c,v 1.2 2000/12/02 00:54:01 nelsonb%netscape.com Exp $ + * $Id: sslgathr.c,v 1.3 2001/03/16 23:26:04 nelsonb%netscape.com Exp $ */ #include "cert.h" #include "ssl.h" @@ -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 7ad374693af8..8791b4184b62 100644 --- a/security/nss/lib/ssl/sslimpl.h +++ b/security/nss/lib/ssl/sslimpl.h @@ -33,7 +33,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: sslimpl.h,v 1.10 2001/02/07 17:50:43 wtc%netscape.com Exp $ + * $Id: sslimpl.h,v 1.11 2001/03/16 23:26:04 nelsonb%netscape.com Exp $ */ #ifndef __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 2289336336f7..54fff5713c8f 100644 --- a/security/nss/lib/ssl/sslsecur.c +++ b/security/nss/lib/ssl/sslsecur.c @@ -32,7 +32,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: sslsecur.c,v 1.7 2001/02/09 02:11:30 nelsonb%netscape.com Exp $ + * $Id: sslsecur.c,v 1.8 2001/03/16 23:26:05 nelsonb%netscape.com Exp $ */ #include "cert.h" #include "secitem.h" @@ -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 7e5b1d3bdb2f..6da7e32345ee 100644 --- a/security/nss/lib/ssl/sslsock.c +++ b/security/nss/lib/ssl/sslsock.c @@ -34,7 +34,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: sslsock.c,v 1.13 2001/02/09 02:11:31 nelsonb%netscape.com Exp $ + * $Id: sslsock.c,v 1.14 2001/03/16 23:26:06 nelsonb%netscape.com Exp $ */ #include "seccomon.h" #include "cert.h" @@ -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 (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; + } } - 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); - } - - return ret_flags; + return new_flags; }