// // NextRecord - called typically in Callback // to indicate that we need more bytes from the wire // to be decrypted. It is called either by a worker // thread or by the Read directly, it reads one chunk // of data, and attempts to decrypt. As soon as it has // the chunk of unencrypted data, it returns it in // m_ArrivingData and m_ExistingAmount contains, // the amount data that was decrypted. // // ASSUMES: we have an empty buffer of unencrypted bytes // RETURNS: upon error, by either leaving this buffer empty (0), // with an Exception set on this object, or on success, // by updating the global state (m_ArrivingData) // with unencrypted bytes // // WARNING: Can Throw! // private void NextRecord(byte[] buffer, int length) { byte[] packet = null; GlobalLog.Assert( (m_ExistingAmount == 0), "m_ExistingAmount != 0", "Has assumed internal SSL buffer would be empty"); // // This LOOP below will keep going until (EITHER): // 1) we have ONE succesful chunk of unencrypted data // 2) we have an error either from a renegotiate handhake (OR) Read (OR) Decrypt // do { packet = ReadFullRecord(buffer, length); if (packet == null) { return; } lock (this) { SecureChannel chkSecureChannel = SecureChannel; if (chkSecureChannel == null) { return; } int errorCode = chkSecureChannel.Decrypt(packet, ref m_ArrivingData); if (errorCode == (int)SecurityStatus.OK) { // SUCCESS - we have our decrypted Bytes GlobalLog.Print("TlsStream::NextRecord called (success) Decrypt[" + (m_ArrivingData != null ? (Encoding.ASCII.GetString(m_ArrivingData, 0, Math.Min(m_ArrivingData.Length, 512))) : "null") + "]"); break; } else { // ERROR - examine what kind ProtocolToken message = new ProtocolToken(packet, errorCode); GlobalLog.Print("TlsStream:: Decrypt errorCode = " + errorCode.ToString()); if (message.Renegotiate) { // HANDSHAKE - do a handshake between us and server InnerException = Handshake(message); if (InnerException != null) { return; // failure } // CONTINUE - Read On! we pick up from where // we were before the handshake and try to get // one block of unencrypted bytes, the earlier block // of data was control information for the handshake. // We need to read in the new header. if (ForceRead(buffer, 0, length) < length) { InnerException = new IOException(SR.GetString(SR.net_io_readfailure)); return; //failure } } else if (message.CloseConnection) { // CLOSE - server ordered us to shut down Close(); // close down the socket return; } else { // EXCEPTION - throw later on InnerException = message.GetException(); return; } } } // continue here in the case where we had a handshake, and needed // to reget new Data } while (true); // m_ExistingAmount was 0 on entry! if (m_ArrivingData == null) { return; } m_ExistingAmount = m_ArrivingData.Length; return; }