/*********************************************************************** * Gathers in and handles records/messages until either the handshake is * complete or application data is available. * * Called from ssl_Do1stHandshake() via function pointer ss->handshake. * Caller must hold handshake lock. * This function acquires and releases the RecvBufLock. * * returns SECSuccess for success. * returns SECWouldBlock when that value is returned by * ssl3_GatherCompleteHandshake(). * returns SECFailure on all other errors. * * The gather functions called by ssl_GatherRecord1stHandshake are expected * to return values interpreted as follows: * 1 : the function completed without error. * 0 : the function read EOF. * -1 : read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error. * -2 : the function wants ssl_GatherRecord1stHandshake to be called again * immediately, by ssl_Do1stHandshake. * * This code is similar to, and easily confused with, DoRecv() in sslsecur.c * * This function is called from ssl_Do1stHandshake(). * The following functions put ssl_GatherRecord1stHandshake into ss->handshake: * ssl_BeginClientHandshake * ssl3_RestartHandshakeAfterCertReq * ssl3_RestartHandshakeAfterServerCert * ssl_BeginServerHandshake */ SECStatus ssl_GatherRecord1stHandshake(sslSocket *ss) { int rv; PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); ssl_GetRecvBufLock(ss); /* Wait for handshake to complete, or application data to arrive. */ rv = ssl3_GatherCompleteHandshake(ss, 0); SSL_TRC(10, ("%d: SSL[%d]: handshake gathering, rv=%d", SSL_GETPID(), ss->fd, rv)); ssl_ReleaseRecvBufLock(ss); if (rv <= 0) { if (rv == SECWouldBlock) { /* Progress is blocked waiting for callback completion. */ SSL_TRC(10, ("%d: SSL[%d]: handshake blocked (need %d)", SSL_GETPID(), ss->fd, ss->gs.remainder)); return SECWouldBlock; } if (rv == 0) { /* EOF. Loser */ PORT_SetError(PR_END_OF_FILE_ERROR); } return SECFailure; /* rv is < 0 here. */ } ss->handshake = NULL; return SECSuccess; }
/* Try to make progress on an SSL handshake by attempting to read the ** next handshake from the peer, and sending any responses. ** For non-blocking sockets, returns PR_ERROR_WOULD_BLOCK if it cannot ** read the next handshake from the underlying socket. ** For SSLv2, returns when handshake is complete or fatal error occurs. ** For SSLv3, returns when handshake is complete, or application data has ** arrived that must be taken by application before handshake can continue, ** or a fatal error occurs. ** Application should use handshake completion callback to tell which. */ SECStatus SSL_ForceHandshake(PRFileDesc *fd) { sslSocket *ss; SECStatus rv = SECFailure; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in ForceHandshake", SSL_GETPID(), fd)); return rv; } /* Don't waste my time */ if (!ss->opt.useSecurity) return SECSuccess; if (!ssl_SocketIsBlocking(ss)) { ssl_GetXmitBufLock(ss); if (ss->pendingBuf.len != 0) { int sent = ssl_SendSavedWriteData(ss); if ((sent < 0) && (PORT_GetError() != PR_WOULD_BLOCK_ERROR)) { ssl_ReleaseXmitBufLock(ss); return SECFailure; } } ssl_ReleaseXmitBufLock(ss); } ssl_Get1stHandshakeLock(ss); if (ss->version >= SSL_LIBRARY_VERSION_3_0) { int gatherResult; ssl_GetRecvBufLock(ss); gatherResult = ssl3_GatherCompleteHandshake(ss, 0); ssl_ReleaseRecvBufLock(ss); if (gatherResult > 0) { rv = SECSuccess; } else if (gatherResult == 0) { PORT_SetError(PR_END_OF_FILE_ERROR); } else if (gatherResult == SECWouldBlock) { PORT_SetError(PR_WOULD_BLOCK_ERROR); } } else if (!ss->firstHsDone) { rv = ssl_Do1stHandshake(ss); } else { /* tried to force handshake on an SSL 2 socket that has ** already completed the handshake. */ rv = SECSuccess; /* just pretend we did it. */ } ssl_Release1stHandshakeLock(ss); return rv; }
/* Repeatedly gather in a record and when complete, Handle that record. * Repeat this until some application data is received. * * Returns 1 when application data is available. * Returns 0 if ssl3_GatherData hits EOF. * Returns -1 on read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error. * Returns -2 on SECWouldBlock return from ssl3_HandleRecord. * * Called from DoRecv in sslsecur.c * Caller must hold the recv buf lock. */ int ssl3_GatherAppDataRecord(sslSocket *ss, int flags) { int rv; PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); do { rv = ssl3_GatherCompleteHandshake(ss, flags); } while (rv > 0 && ss->gs.buf.len == 0); return rv; }