From 68f0773b6f5ae038aecd4e320f69695b0fe762d4 Mon Sep 17 00:00:00 2001 From: "nelsonb%netscape.com" Date: Fri, 16 Mar 2001 23:26:06 +0000 Subject: [PATCH] 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 --- security/nss/lib/ssl/ssl3con.c | 23 ++++--- security/nss/lib/ssl/sslauth.c | 4 +- security/nss/lib/ssl/sslcon.c | 5 +- security/nss/lib/ssl/ssldef.c | 8 ++- security/nss/lib/ssl/sslgathr.c | 6 +- security/nss/lib/ssl/sslimpl.h | 18 ++++-- security/nss/lib/ssl/sslsecur.c | 81 ++++++++++++++----------- security/nss/lib/ssl/sslsock.c | 104 +++++++++++++++++++++++++------- 8 files changed, 169 insertions(+), 80 deletions(-) diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index d1441eadd00..36369762bb7 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 996ab22b31e..232d4a7048c 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 2fc7464a196..e53cc6ea080 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 a36a732f8a1..d9b6abbb358 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 51f570ebfff..a54bf6f4590 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 b293083d212..a03d6985658 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 0abcf60bcb7..09a382daf56 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 347af934b40..fc0b20bf630 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; }