/* ** Receive some application data on a socket. Reads SSL records from the input ** stream, decrypts them and then copies them to the output buffer. ** Called from ssl_SecureRecv() below. ** ** Caller does NOT hold 1stHandshakeLock because that handshake is over. ** Caller doesn't call this until initial handshake is complete. ** For SSLv2, there is no subsequent handshake. ** For SSLv3, the call to ssl3_GatherAppDataRecord may encounter handshake ** messages from a subsequent handshake. ** ** This code is similar to, and easily confused with, ** ssl_GatherRecord1stHandshake() in sslcon.c */ static int DoRecv(sslSocket *ss, unsigned char *out, int len, int flags) { int rv; int amount; int available; /* ssl3_GatherAppDataRecord may call ssl_FinishHandshake, which needs the * 1stHandshakeLock. */ ssl_Get1stHandshakeLock(ss); ssl_GetRecvBufLock(ss); available = ss->gs.writeOffset - ss->gs.readOffset; if (available == 0) { /* Get some more data */ if (ss->version >= SSL_LIBRARY_VERSION_3_0) { /* Wait for application data to arrive. */ rv = ssl3_GatherAppDataRecord(ss, 0); } else { /* See if we have a complete record */ rv = ssl2_GatherRecord(ss, 0); } if (rv <= 0) { if (rv == 0) { /* EOF */ SSL_TRC(10, ("%d: SSL[%d]: ssl_recv EOF", SSL_GETPID(), ss->fd)); goto done; } if ((rv != SECWouldBlock) && (PR_GetError() != PR_WOULD_BLOCK_ERROR)) { /* Some random error */ goto done; } /* ** Gather record is blocked waiting for more record data to ** arrive. Try to process what we have already received */ } else { /* Gather record has finished getting a complete record */ } /* See if any clear data is now available */ available = ss->gs.writeOffset - ss->gs.readOffset; if (available == 0) { /* ** No partial data is available. Force error code to ** EWOULDBLOCK so that caller will try again later. Note ** that the error code is probably EWOULDBLOCK already, ** but if it isn't (for example, if we received a zero ** length record) then this will force it to be correct. */ PORT_SetError(PR_WOULD_BLOCK_ERROR); rv = SECFailure; goto done; } SSL_TRC(30, ("%d: SSL[%d]: partial data ready, available=%d", SSL_GETPID(), ss->fd, available)); } /* Dole out clear data to reader */ amount = PR_MIN(len, available); PORT_Memcpy(out, ss->gs.buf.buf + ss->gs.readOffset, amount); if (!(flags & PR_MSG_PEEK)) { ss->gs.readOffset += amount; } PORT_Assert(ss->gs.readOffset <= ss->gs.writeOffset); rv = amount; SSL_TRC(30, ("%d: SSL[%d]: amount=%d available=%d", SSL_GETPID(), ss->fd, amount, available)); PRINT_BUF(4, (ss, "DoRecv receiving plaintext:", out, amount)); done: ssl_ReleaseRecvBufLock(ss); ssl_Release1stHandshakeLock(ss); return rv; }
static int DoRecv(sslSocket *ss, unsigned char *out, int len, int flags) { int rv; int amount; int available; ssl_Get1stHandshakeLock(ss); ssl_GetRecvBufLock(ss); available = ss->gs.writeOffset - ss->gs.readOffset; if (available == 0) { if (ss->version >= SSL_LIBRARY_VERSION_3_0) { rv = ssl3_GatherAppDataRecord(ss, 0); } else { rv = ssl2_GatherRecord(ss, 0); } if (rv <= 0) { if (rv == 0) { SSL_TRC(10, ("%d: SSL[%d]: ssl_recv EOF", SSL_GETPID(), ss->fd)); goto done; } if ((rv != SECWouldBlock) && (PR_GetError() != PR_WOULD_BLOCK_ERROR)) { goto done; } } else { } available = ss->gs.writeOffset - ss->gs.readOffset; if (available == 0) { PORT_SetError(PR_WOULD_BLOCK_ERROR); rv = SECFailure; goto done; } SSL_TRC(30, ("%d: SSL[%d]: partial data ready, available=%d", SSL_GETPID(), ss->fd, available)); } amount = PR_MIN(len, available); PORT_Memcpy(out, ss->gs.buf.buf + ss->gs.readOffset, amount); if (!(flags & PR_MSG_PEEK)) { ss->gs.readOffset += amount; } PORT_Assert(ss->gs.readOffset <= ss->gs.writeOffset); rv = amount; SSL_TRC(30, ("%d: SSL[%d]: amount=%d available=%d", SSL_GETPID(), ss->fd, amount, available)); PRINT_BUF(4, (ss, "DoRecv receiving plaintext:", out, amount)); done: ssl_ReleaseRecvBufLock(ss); ssl_Release1stHandshakeLock(ss); return rv; }