List <Message> BufferMessages(ref byte[] buffer, ref int bufferOffset, ref int messageOffset, ref int remainingData, ref MessageHeader header, ref BufferValueReader reader, Func <MessageHeader, bool> messageIdCallback = null) { List <Message> messages = new List <Message>(); string callCategory = null; #if TRACE int c = GetNextCallId(); callCategory = String.Format("{0} {1}:BufferMessages({2},{3},{4},{5},{6})", this.connectionType, c, buffer.Length, bufferOffset, messageOffset, remainingData, reader.Position); #endif Trace.WriteLineIf(NTrace.TraceVerbose, "Entering", callCategory); BufferValueReader currentReader = reader; int length = 0; while (remainingData >= BaseHeaderLength) { if (!TryGetHeader(currentReader, remainingData, ref header)) { Trace.WriteLineIf(NTrace.TraceVerbose, "Message not ready", callCategory); break; } if (header == null || header.Message == null) { header = null; Disconnect(); Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (header not found)", callCategory); return(null); } length = header.MessageLength; if (length > MaxMessageSize) { header = null; Disconnect(); Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (bad message size)", callCategory); return(null); } if (header.State == HeaderState.IV) { DecryptMessage(header, ref currentReader); header.IsStillEncrypted = false; continue; } if (messageIdCallback != null && !messageIdCallback(header)) { header = null; Disconnect(); Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (message id callback was false)", callCategory); return(null); } if (remainingData < length) { bufferOffset += remainingData; Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Message not fully received (boffset={0})", bufferOffset), callCategory); break; } try { Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Reading payload for message {0}", header.Message), callCategory); header.Message.ReadPayload(header.SerializationContext, currentReader); if (!header.Message.Encrypted && header.Message.Authenticated) { // Zero out length for message signing comparison #if SAFE for (int i = LengthOffset + messageOffset; i < LengthOffset + sizeof(int) + messageOffset; ++i) { buffer[i] = 0; } #else fixed(byte *bptr = buffer) * ((int *)(bptr + (LengthOffset + messageOffset))) = 0; #endif int payloadLength = reader.Position; byte[] signature = reader.ReadBytes(); if (!VerifyMessage(this.signingHashAlgorithm, header.Message, signature, buffer, messageOffset, payloadLength - messageOffset)) { Disconnect(ConnectionResult.MessageAuthenticationFailed); Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (message auth failed)", callCategory); return(null); } } } catch (Exception ex) { header = null; Disconnect(); Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting for error: " + ex, callCategory); return(null); } messages.Add(header.Message); currentReader = reader; header = null; if (length < buffer.Length) { messageOffset += length; bufferOffset = messageOffset; remainingData -= length; } else { messageOffset = 0; bufferOffset = 0; remainingData = 0; currentReader.Position = 0; } Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("EOL: moffset={0},boffest={1},rdata={2},rpos={3}", messageOffset, bufferOffset, remainingData, reader.Position), callCategory); } if (remainingData > 0 || messageOffset + BaseHeaderLength >= buffer.Length) { Trace.WriteLineIf(NTrace.TraceVerbose, (remainingData > 0) ? String.Format("Data remaining: {0:N0}", remainingData) : "Insufficient room for a header", callCategory); int knownRoomNeeded = (remainingData > BaseHeaderLength) ? remainingData : BaseHeaderLength; if (header != null && remainingData >= BaseHeaderLength) { knownRoomNeeded = header.MessageLength; } int pos = reader.Position - messageOffset; Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Room needed: {0:N0} bytes", knownRoomNeeded), callCategory); if (messageOffset + knownRoomNeeded <= buffer.Length) { // bufferOffset is only moved on complete headers, so it's still == messageOffset. bufferOffset = messageOffset + remainingData; //reader.Position = pos; Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Exiting (sufficient room; boffest={0},rpos={1})", bufferOffset, pos), callCategory); return(messages); } byte[] destinationBuffer = buffer; if (knownRoomNeeded > buffer.Length) { reader.Dispose(); destinationBuffer = new byte[header.MessageLength]; reader = new BufferValueReader(destinationBuffer); } Buffer.BlockCopy(buffer, messageOffset, destinationBuffer, 0, remainingData); reader.Position = pos; messageOffset = 0; bufferOffset = remainingData; buffer = destinationBuffer; Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Exiting (moved message to front, moffset={1},boffset={2},rpos={0})", reader.Position, messageOffset, bufferOffset), callCategory); } else { Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting", callCategory); } return(messages); }
public bool TryGetHeader(BufferValueReader reader, int remaining, ref MessageHeader header) { string callCategory = null; #if TRACE int c = GetNextCallId(); callCategory = String.Format("{0} {1}:TryGetHeader({2},{3})", this.connectionType, c, reader.Position, remaining); #endif Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Entering {0}", (header == null) ? "without existing header" : "with existing header"), callCategory); int mlen; bool isContinued; Message msg = null; Protocol p; int headerLength = BaseHeaderLength; if (header == null) { header = new MessageHeader(); } else if (header.State == HeaderState.Complete) { return(true); } else if (header.HeaderLength > 0) { headerLength = header.HeaderLength; } try { if (header.State >= HeaderState.Protocol) { p = header.Protocol; } else { byte pid = reader.ReadByte(); if (!this.protocols.TryGetValue(pid, out p)) { Trace.WriteLineIf(NTrace.TraceWarning, "Exiting (Protocol " + pid + " not found)", callCategory); return(true); } header.Protocol = p; header.State = HeaderState.Protocol; if (this.serializationContext == null) { if (this.connection != null) { this.serializationContext = new SerializationContext(this.connection, this.protocols); } else { this.serializationContext = new SerializationContext(this.protocols); } } header.SerializationContext = this.serializationContext; } if (header.State < HeaderState.CID) { header.ConnectionId = reader.ReadInt32(); header.State = HeaderState.CID; } if (header.State >= HeaderState.Type) { msg = header.Message; } else { ushort type = reader.ReadUInt16(); msg = header.Message = p.Create(type); header.State = HeaderState.Type; if (msg == null) { Trace.WriteLineIf(NTrace.TraceWarning, "Exiting (Message " + type + " not found)", callCategory); return(true); } msg.Header = header; if (msg.Encrypted) { header.IsStillEncrypted = true; } Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Have " + msg.GetType().Name), callCategory); } if (header.State >= HeaderState.Length) { mlen = header.MessageLength; } else { mlen = reader.ReadInt32(); if (mlen <= 0) { Trace.WriteLineIf(NTrace.TraceWarning, "Exiting (length invalid)", callCategory); return(true); } header.MessageLength = mlen; header.State = HeaderState.Length; Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Have message of length: {0}", mlen), callCategory); } if (header.State == HeaderState.IV) { if (header.IsStillEncrypted) { Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (message not buffered)", callCategory); return(!(remaining < mlen)); } else if (header.Message.Encrypted) { reader.Position = 0; } } else if (msg.Encrypted) // && AES != null) { int ivLength = reader.ReadInt32(); //AES.IV.Length; headerLength += ivLength + sizeof(int); if (remaining < headerLength) { reader.Position -= sizeof(int); Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (header not buffered (IV))", callCategory); return(false); } byte[] iv = reader.ReadBytes(ivLength); header.HeaderLength = headerLength; header.State = HeaderState.IV; header.IV = iv; if (remaining < mlen) { Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (message not buffered)", callCategory); return(false); } Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (need to decrypt)", callCategory); return(true); } if (header.State < HeaderState.MessageId) { int identV = reader.ReadInt32(); header.MessageId = identV & ~ResponseFlag; header.IsResponse = (identV & ResponseFlag) == ResponseFlag; header.State = (header.IsResponse) ? HeaderState.MessageId : HeaderState.Complete; Trace.WriteLineIf(NTrace.TraceVerbose, "Have message ID: " + header.MessageId, callCategory); } if (header.State < HeaderState.ResponseMessageId) { header.ResponseMessageId = reader.ReadInt32(); header.State = HeaderState.Complete; Trace.WriteLineIf(NTrace.TraceVerbose, "Have message in resoponse to ID: " + header.ResponseMessageId); } Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting", callCategory); return(true); } catch (Exception ex) { Trace.WriteLineIf(NTrace.TraceError, "Exiting (error): " + ex, callCategory); header = null; return(true); } }