private void Receive(object sender, SocketAsyncEventArgs args) { var cnd = (Tuple <Socket, BufferValueReader>)args.UserToken; Socket socket = cnd.Item1; BufferValueReader reader = cnd.Item2; if (args.BytesTransferred == 0 || args.SocketError != SocketError.Success) { reader.Dispose(); args.Dispose(); Interlocked.Decrement(ref this.pendingAsync); return; } int offset = args.Offset; reader.Position = offset; MessageHeader header = null; // We don't currently support partial messages, so an incomplete message is a bad one. if (!this.connectionlessSerializer.TryGetHeader(reader, args.BytesTransferred, ref header) || header.Message == null) { Interlocked.Decrement(ref this.pendingAsync); StartReceive(socket, args, reader); return; } if (header.ConnectionId == 0) { HandleConnectionlessMessage(args, header, ref reader); } else { HandleConnectionMessage(args, header, ref reader); } Interlocked.Decrement(ref this.pendingAsync); StartReceive(socket, args, reader); }
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); }