internal void ReceivePartialMessage(PartialMessage message) { var queue = this.partials.GetOrAdd(message.OriginalMessageId, id => new ConcurrentQueue <PartialMessage>()); queue.Enqueue(message); if (queue.Count != message.Count) { return; } if (!this.partials.TryRemove(message.OriginalMessageId, out queue)) { return; } byte[] payload = new byte[queue.Sum(p => p.Payload.Length)]; int offset = 0; foreach (PartialMessage msg in queue.OrderBy(p => p.Header.MessageId)) { byte[] partialPayload = msg.Payload; Buffer.BlockCopy(partialPayload, 0, payload, offset, partialPayload.Length); offset += partialPayload.Length; } MessageSerializer srlzr = this.serializer; if (srlzr == null) { return; } List <Message> messages = srlzr.BufferMessages(payload); if (messages != null && messages.Count == 1) { Receive(messages[0], fromPartials: true); } else { DisconnectAsync(); } }
protected virtual void HandleConnectionMessage(SocketAsyncEventArgs args, MessageHeader header, ref BufferValueReader reader) { UdpConnection connection; if (!TryGetConnection(header.ConnectionId, out connection)) { return; } byte[] buffer = args.Buffer; int offset = args.Offset; int moffset = offset; int remaining = args.BytesTransferred; MessageSerializer serializer = connection.serializer; if (serializer == null) { return; } if (header.State == HeaderState.IV) { serializer.DecryptMessage(header, ref reader); header.IsStillEncrypted = false; if (!serializer.TryGetHeader(reader, args.BytesTransferred, ref header)) { return; } } List <Message> messages = serializer.BufferMessages(ref buffer, ref offset, ref moffset, ref remaining, ref header, ref reader); if (messages != null) { foreach (Message message in messages) { connection.Receive(message); } } reader.Position = 0; }
protected void ReliableReceiveCompleted(object sender, SocketAsyncEventArgs e) { string callCategory = null; #if TRACE int c = GetNextCallId(); callCategory = String.Format("{2}:{4} {3}:ReliableReceiveCompleted({0},{1})", e.BytesTransferred, e.SocketError, this.typeName, c, this.connectionId); #endif Trace.WriteLineIf(NTrace.TraceVerbose, "Entering", callCategory); bool receivedAsync; do { int p; if (e.BytesTransferred == 0 || e.SocketError != SocketError.Success) { Disconnect(); // This is right, don't mess with it anymore. p = Interlocked.Decrement(ref this.pendingAsync); Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Decrement pending: {0}", p), callCategory); Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (error)", callCategory); return; } #if !SILVERLIGHT this.lastActivity = Stopwatch.GetTimestamp(); #else this.lastActivity = DateTime.Now.Ticks; #endif Interlocked.Add(ref this.bytesReceived, e.BytesTransferred); p = Interlocked.Decrement(ref this.pendingAsync); Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Decrement pending: {0}", p), callCategory); this.rmessageLoaded += e.BytesTransferred; int bufferOffset = e.Offset; MessageSerializer slzr = this.serializer; if (slzr == null) { p = Interlocked.Decrement(ref this.pendingAsync); Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Decrement pending: {0}", p), callCategory); Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (no serializer, probably disconnecting)", callCategory); return; } List <Message> messages = slzr.BufferMessages(ref this.rmessageBuffer, ref bufferOffset, ref this.rmessageOffset, ref this.rmessageLoaded, ref this.currentHeader, ref this.rreader, CheckMessageId); if (messages != null) { foreach (Message message in messages) { var args = new MessageEventArgs(this, message); if (message is TempestMessage) { OnTempestMessageReceived(args); } else { OnMessageReceived(args); if (message.Header.IsResponse) { Responses.Receive(message); } } } } Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Exited BufferMessages with new values: {0},{1},{2},{3},{4}", this.rmessageBuffer.Length, bufferOffset, this.rmessageOffset, this.rmessageLoaded, this.rreader.Position), callCategory); e.SetBuffer(this.rmessageBuffer, bufferOffset, this.rmessageBuffer.Length - bufferOffset); p = Interlocked.Increment(ref this.pendingAsync); Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Increment pending: {0}", p), callCategory); lock (this.stateSync) { if (!IsConnected) { p = Interlocked.Decrement(ref this.pendingAsync); Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Decrement pending: {0}", p), callCategory); Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (not connected)", callCategory); return; } receivedAsync = this.reliableSocket.ReceiveAsync(e); } } while (!receivedAsync); Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting", callCategory); }
private Task <bool> SendMessage(Message message, bool isResponse, bool requestingResponse, int responseTimeout, out Task <Message> responseTask) { string callCategory = null; #if TRACE int c = GetNextCallId(); callCategory = String.Format("{1}:{2} {3}:Send({0})", message, this.typeName, this.connectionId, c); #endif Trace.WriteLineIf(NTrace.TraceVerbose, "Entering", callCategory); responseTask = null; TaskCompletionSource <bool> tcs = new TaskCompletionSource <bool> (message); if (message == null) { throw new ArgumentNullException("message"); } if (!IsConnected) { Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (not connected)", callCategory); tcs.SetResult(false); if (requestingResponse) { var responseTcs = new TaskCompletionSource <Message>(); responseTcs.SetCanceled(); responseTask = responseTcs.Task; } return(tcs.Task); } SocketAsyncEventArgs eargs = null; #if NET_4 if (!writerAsyncArgs.TryPop(out eargs)) { while (eargs == null) { int count = bufferCount; if (count == sendBufferLimit) { Trace.WriteLineIf(NTrace.TraceVerbose, "Waiting for writer args", callCategory); SpinWait wait = new SpinWait(); while (!writerAsyncArgs.TryPop(out eargs)) { wait.SpinOnce(); } } else if (count == Interlocked.CompareExchange(ref bufferCount, count + 1, count)) { Trace.WriteLineIf(NTrace.TraceVerbose, "Creating new writer args", callCategory); eargs = new SocketAsyncEventArgs(); eargs.SetBuffer(new byte[1024], 0, 1024); eargs.Completed += ReliableSendCompleted; } } } #else while (eargs == null) { lock (writerAsyncArgs) { if (writerAsyncArgs.Count != 0) { eargs = writerAsyncArgs.Pop(); } else if (bufferCount != sendBufferLimit) { bufferCount++; eargs = new SocketAsyncEventArgs(); eargs.SetBuffer(new byte[1024], 0, 1024); eargs.Completed += ReliableSendCompleted; } } } #endif #if !SILVERLIGHT eargs.AcceptSocket = null; #endif Trace.WriteLineIf(NTrace.TraceVerbose, "Have writer args", callCategory); bool sent; lock (this.sendSync) { if (message.Header == null) { message.Header = new MessageHeader(); } message.Header.MessageId = MessageSerializer.GetNextMessageId(ref this.nextMessageId); if (requestingResponse) { responseTask = Responses.SendFor(message, tcs.Task, responseTimeout); } MessageSerializer slzr = this.serializer; if (slzr == null) { int sp = Interlocked.Decrement(ref this.pendingAsync); Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Decrement pending: {0}", sp), callCategory); #if !NET_4 lock (writerAsyncArgs) #endif writerAsyncArgs.Push(eargs); Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting (serializer is null, probably disconnecting)", callCategory); tcs.SetResult(false); return(tcs.Task); } int length; byte[] buffer = slzr.GetBytes(message, out length, eargs.Buffer); eargs.SetBuffer(buffer, 0, length); eargs.UserToken = new KeyValuePair <NetworkConnection, TaskCompletionSource <bool> > (this, tcs); int p = Interlocked.Increment(ref this.pendingAsync); Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Increment pending: {0}", p), callCategory); if (!IsConnected) { Interlocked.Decrement(ref this.pendingAsync); Trace.WriteLineIf(NTrace.TraceVerbose, String.Format("Decrement pending: {0}", p), callCategory); #if !NET_4 lock (writerAsyncArgs) #endif writerAsyncArgs.Push(eargs); tcs.SetResult(false); return(tcs.Task); } Trace.WriteLineIf(NTrace.TraceVerbose, "Sending", callCategory); sent = !this.reliableSocket.SendAsync(eargs); } if (sent) { Trace.WriteLineIf(NTrace.TraceVerbose, "Send completed synchronously", callCategory); ReliableSendCompleted(this.reliableSocket, eargs); } Trace.WriteLineIf(NTrace.TraceVerbose, "Exiting", callCategory); return(tcs.Task); }
protected Task <bool> SendCore(Message message, bool dontSetId, bool responseRequested, int timeout, out Task <Message> responseTask) { if (message == null) { throw new ArgumentNullException("message"); } responseTask = null; Socket sock = this.socket; MessageSerializer mserialzier = this.serializer; TaskCompletionSource <bool> tcs = new TaskCompletionSource <bool> (message); if (sock == null || mserialzier == null || (!IsConnected && !IsConnecting)) { tcs.TrySetResult(false); if (responseRequested) { var responseTcs = new TaskCompletionSource <Message>(); responseTcs.SetCanceled(); responseTask = responseTcs.Task; } return(tcs.Task); } if (message.Header == null) { message.Header = new MessageHeader(); } if (!dontSetId) { SetMessageId(message); if (responseRequested) { responseTask = Responses.SendFor(message, tcs.Task, timeout); } } IPEndPoint endPoint = IPEndPoint; if (endPoint == null) { tcs.SetResult(false); return(tcs.Task); } SocketAsyncEventArgs e; BufferPool.TryGetBuffer(out e); int length; byte[] buffer = mserialzier.GetBytes(message, out length, e.Buffer); if (!(message is PartialMessage) && length > 490) { byte count = (byte)Math.Ceiling((length / 490f)); int i = 0; int remaining = length; do { int payloadLen = Math.Min(490, remaining); var partial = new PartialMessage { OriginalMessageId = (ushort)message.Header.MessageId, Count = count, Header = new MessageHeader() }; partial.SetPayload(buffer, i, payloadLen); if (i == 0) // We have to fill the gap the original id uses for reliability { partial.Header.MessageId = message.Header.MessageId; } else { SetMessageId(partial); } lock (this.pendingAck) this.pendingAck.Add(partial.Header.MessageId, new Tuple <DateTime, Message> (DateTime.UtcNow, partial)); mserialzier.GetBytes(partial, out length, e.Buffer); e.SetBuffer(0, length); e.RemoteEndPoint = endPoint; remaining -= payloadLen; i += payloadLen; if (remaining == 0) { e.Completed += OnSendCompleted; e.UserToken = tcs; } else { e.Completed += OnPartialSendCompleted; } try { this.lastReliableSendActivity = Stopwatch.GetTimestamp(); if (!sock.SendToAsync(e)) { if (remaining == 0) { OnSendCompleted(this, e); } else { OnPartialSendCompleted(this, e); } } } catch (ObjectDisposedException) { BufferPool.PushBuffer(e); if (remaining == 0) { CleanupSend(e); } else { CleanupPartialSend(e); } tcs.TrySetResult(false); } if (remaining > 0) { BufferPool.TryGetBuffer(out e); } } while (remaining > 0); } else { e.SetBuffer(0, length); e.RemoteEndPoint = endPoint; e.Completed += OnSendCompleted; e.UserToken = tcs; if (message.PreferReliable || message.MustBeReliable) { this.lastReliableSendActivity = Stopwatch.GetTimestamp(); lock (this.pendingAck) this.pendingAck.Add(message.Header.MessageId, new Tuple <DateTime, Message> (DateTime.UtcNow, message)); } try { if (!sock.SendToAsync(e)) { OnSendCompleted(this, e); } } catch (ObjectDisposedException) { CleanupSend(e); tcs.TrySetResult(false); } } return(tcs.Task); }
protected override void OnTempestMessageReceived(MessageEventArgs e) { switch (e.Message.MessageType) { case (ushort)TempestMessageType.Connect: var msg = (ConnectMessage)e.Message; if (!IsConnected) { return; } if (!msg.Protocols.Any()) { DisconnectAsync(ConnectionResult.FailedHandshake); return; } if (this.requiresHandshake) { bool foundHashAlg = false; foreach (string hashAlg in this.signatureHashAlgs) { if (msg.SignatureHashAlgorithms.Contains(hashAlg)) { this.serializer.SigningHashAlgorithm = hashAlg; foundHashAlg = true; break; } } if (!foundHashAlg) { DisconnectAsync(ConnectionResult.FailedHandshake); return; } } ConnectionId = this.provider.GetConnectionId(); foreach (Protocol ip in msg.Protocols) { Protocol lp; if (!this.protocols.TryGetValue(ip.id, out lp) || !lp.CompatibleWith(ip)) { DisconnectAsync(ConnectionResult.IncompatibleVersion); return; } } this.protocols = this.protocols.Values.Intersect(msg.Protocols).ToDictionary(p => p.id); this.receivedProtocols = true; if (!this.requiresHandshake) { this.formallyConnected = true; this.provider.Connect(this); e.Connection.SendAsync(new ConnectedMessage()); } else { while (!this.authReady) { Thread.Sleep(0); } MessageSerializer s = this.serializer; if (s == null) { return; } e.Connection.SendAsync(new AcknowledgeConnectMessage { SignatureHashAlgorithm = s.SigningHashAlgorithm, EnabledProtocols = this.protocols.Values, ConnectionId = ConnectionId, PublicAuthenticationKey = this.provider.PublicAuthenticationKey, PublicEncryptionKey = this.provider.PublicEncryptionKey }); } break; case (ushort)TempestMessageType.FinalConnect: if (!this.receivedProtocols) { DisconnectAsync(ConnectionResult.FailedHandshake); return; } var finalConnect = (FinalConnectMessage)e.Message; if (finalConnect.AESKey == null || finalConnect.AESKey.Length == 0 || finalConnect.PublicAuthenticationKey == null) { DisconnectAsync(ConnectionResult.FailedHandshake); return; } try { byte[] aeskey = this.provider.pkEncryption.Decrypt(finalConnect.AESKey); this.serializer.HMAC = new HMACSHA256(aeskey); this.serializer.AES = new AesManaged { KeySize = 256, Key = aeskey }; } catch { DisconnectAsync(ConnectionResult.FailedHandshake); return; } this.formallyConnected = true; this.provider.Connect(this); SendAsync(new ConnectedMessage { ConnectionId = ConnectionId }); break; } base.OnTempestMessageReceived(e); }