private void HandleRetransmittedHandshakeRecord(int epoch, byte[] buf, int off, int len) { /* * TODO Need to handle the case where the previous inbound flight contains * messages from two epochs. */ if (len < 12) { return; } int fragment_length = TlsUtilities.ReadUint24(buf, off + 9); if (len != (fragment_length + 12)) { return; } int seq = TlsUtilities.ReadUint16(buf, off + 4); if (seq >= mNextReceiveSeq) { return; } byte msg_type = TlsUtilities.ReadUint8(buf, off); // TODO This is a hack that only works until we try to support renegotiation int expectedEpoch = msg_type == HandshakeType.finished ? 1 : 0; if (epoch != expectedEpoch) { return; } int length = TlsUtilities.ReadUint24(buf, off + 1); int fragment_offset = TlsUtilities.ReadUint24(buf, off + 6); if (fragment_offset + fragment_length > length) { return; } DtlsReassembler reassembler = (DtlsReassembler)mCurrentInboundFlight[seq]; if (reassembler != null) { reassembler.ContributeFragment(msg_type, length, buf, off + 12, fragment_offset, fragment_length); if (CheckAll(mCurrentInboundFlight)) { ResendOutboundFlight(); ResetAll(mCurrentInboundFlight); } } }
internal Message ReceiveMessage() { if (mSending) { mSending = false; PrepareInboundFlight(); } // Check if we already have the next message waiting { DtlsReassembler next = (DtlsReassembler)mCurrentInboundFlight[mNextReceiveSeq]; if (next != null) { byte[] body = next.GetBodyIfComplete(); if (body != null) { mPreviousInboundFlight = null; return(UpdateHandshakeMessagesDigest(new Message(mNextReceiveSeq++, next.MsgType, body))); } } } byte[] buf = null; // TODO Check the conditions under which we should reset this int readTimeoutMillis = 1000; for (;;) { int receiveLimit = mRecordLayer.GetReceiveLimit(); if (buf == null || buf.Length < receiveLimit) { buf = new byte[receiveLimit]; } // TODO Handle records containing multiple handshake messages try { for (; ;) { int received = mRecordLayer.Receive(buf, 0, receiveLimit, readTimeoutMillis); if (received < 0) { break; } if (received < 12) { continue; } int fragment_length = TlsUtilities.ReadUint24(buf, 9); if (received != (fragment_length + 12)) { continue; } int seq = TlsUtilities.ReadUint16(buf, 4); if (seq > (mNextReceiveSeq + MAX_RECEIVE_AHEAD)) { continue; } byte msg_type = TlsUtilities.ReadUint8(buf, 0); int length = TlsUtilities.ReadUint24(buf, 1); int fragment_offset = TlsUtilities.ReadUint24(buf, 6); if (fragment_offset + fragment_length > length) { continue; } if (seq < mNextReceiveSeq) { /* * NOTE: If we Receive the previous flight of incoming messages in full * again, retransmit our last flight */ if (mPreviousInboundFlight != null) { DtlsReassembler reassembler = (DtlsReassembler)mPreviousInboundFlight[seq]; if (reassembler != null) { reassembler.ContributeFragment(msg_type, length, buf, 12, fragment_offset, fragment_length); if (CheckAll(mPreviousInboundFlight)) { ResendOutboundFlight(); /* * TODO[DTLS] implementations SHOULD back off handshake packet * size during the retransmit backoff. */ readTimeoutMillis = System.Math.Min(readTimeoutMillis * 2, 60000); ResetAll(mPreviousInboundFlight); } } } } else { DtlsReassembler reassembler = (DtlsReassembler)mCurrentInboundFlight[seq]; if (reassembler == null) { reassembler = new DtlsReassembler(msg_type, length); mCurrentInboundFlight[seq] = reassembler; } reassembler.ContributeFragment(msg_type, length, buf, 12, fragment_offset, fragment_length); if (seq == mNextReceiveSeq) { byte[] body = reassembler.GetBodyIfComplete(); if (body != null) { mPreviousInboundFlight = null; return(UpdateHandshakeMessagesDigest(new Message(mNextReceiveSeq++, reassembler.MsgType, body))); } } } } } catch (IOException) { // NOTE: Assume this is a timeout for the moment } ResendOutboundFlight(); /* * TODO[DTLS] implementations SHOULD back off handshake packet size during the * retransmit backoff. */ readTimeoutMillis = System.Math.Min(readTimeoutMillis * 2, 60000); } }