public void ProcessAcknowledgement(AcknowledgementDto ack)
        {
            Signal signal;

            if (signalsByAckId.TryRemove(ack.MessageId, out signal))
            {
#if DEBUG
                Interlocked.Increment(ref DebugRuntimeStats.out_rs_acked);
#endif
                signal.Set();
            }
        }
        public async Task SendAcknowledgementAsync(Guid destination, AcknowledgementDto acknowledgement)
        {
            var ms = outboundAcknowledgementMemoryStreamPool.TakeObject();

            ms.SetLength(0);
            await AsyncSerialize.ToAsync(ms, acknowledgement).ConfigureAwait(false);

            unhandledSendRequestQueue.Enqueue(
                new SendRequest {
                Data           = ms,
                DataOffset     = 0,
                DataLength     = (int)ms.Position,
                DataBufferPool = outboundAcknowledgementMemoryStreamPool,
                IsReliable     = false
            });
            workSignal.Set();
        }
        /// <summary>
        /// Processes an inbound data event.
        /// This is assumed to be invoked on an IOCP thread so a goal is to do as little as possible.
        /// </summary>
        public void HandleInboundDataEvent(InboundDataEvent e, Action <InboundDataEvent> returnInboundDataEvent)
        {
#if DEBUG
            Interlocked.Increment(ref DebugRuntimeStats.in_de);
#endif

            // Deserialize inbound payloads
            SCG.List <object> payloads = new SCG.List <object>();
            try {
                using (var ms = new MemoryStream(e.Data, e.DataOffset, e.DataLength, false, true)) {
                    while (ms.Position < ms.Length)
                    {
                        payloads.Add(Deserialize.From(ms));
                    }
                }
            } catch (Exception ex) {
                if (!isShutdown)
                {
                    logger.Warn("Error at payload deserialize", ex);
                }
                return;
            }
            returnInboundDataEvent(e);
#if DEBUG
            Interlocked.Add(ref DebugRuntimeStats.in_payload, payloads.Count);
#endif

            // Categorize inbound payloads
            var acknowledgements  = new SCG.List <AcknowledgementDto>();
            var announcements     = new SCG.List <AnnouncementDto>();
            var reliablePackets   = new SCG.List <PacketDto>();
            var unreliablePackets = new SCG.List <PacketDto>();
            foreach (var payload in payloads)
            {
                if (payload is AcknowledgementDto)
                {
                    acknowledgements.Add((AcknowledgementDto)payload);
                }
                else if (payload is AnnouncementDto)
                {
                    announcements.Add((AnnouncementDto)payload);
                }
                else if (payload is PacketDto)
                {
                    // Filter packets not destined to us.
                    var packet = (PacketDto)payload;
                    if (!identity.Matches(packet.ReceiverId, IdentityMatchingScope.Broadcast))
                    {
                        tossedCounter.Increment();
                        continue;
                    }

                    // Bin into reliable vs unreliable.
                    if (packet.IsReliable())
                    {
                        reliablePackets.Add(packet);
                    }
                    else
                    {
                        unreliablePackets.Add(packet);
                    }
                }
            }

            // Process acks to prevent resends.
            foreach (var ack in acknowledgements)
            {
#if DEBUG
                Interlocked.Increment(ref DebugRuntimeStats.in_ack);
#endif
                acknowledgementCoordinator.ProcessAcknowledgement(ack);
#if DEBUG
                Interlocked.Increment(ref DebugRuntimeStats.in_ack_done);
#endif
            }

            // Process announcements as they are necessary for routing.
            foreach (var announcement in announcements)
            {
#if DEBUG
                Interlocked.Increment(ref DebugRuntimeStats.in_ann);
#endif
                HandleAnnouncement(e.RemoteInfo, announcement);
            }

            // Ack inbound reliable messages to prevent resends.
            foreach (var packet in reliablePackets)
            {
#if DEBUG
                Interlocked.Increment(ref DebugRuntimeStats.in_out_ack);
#endif
                var            ack = AcknowledgementDto.Create(packet.Id);
                RoutingContext routingContext;
                if (routingContextsByPeerId.TryGetValue(packet.SenderId, out routingContext))
                {
                    routingContext.SendAcknowledgementAsync(packet.SenderId, ack).Forget();
                }
                else
                {
                    payloadSender.BroadcastAsync(ack).Forget();
                }
#if DEBUG
                Interlocked.Increment(ref DebugRuntimeStats.in_out_ack_done);
#endif
            }

            // Test reliable packets' guids against bloom filter.
            var isNewByPacketId            = duplicateFilter.TestPacketIdsAreNew(new HashSet <Guid>(reliablePackets.Select(p => p.Id)));
            var standalonePacketsToProcess = new SCG.List <PacketDto>(unreliablePackets);
            var chunksToProcess            = new SCG.List <MultiPartChunkDto>();
            foreach (var packet in reliablePackets)
            {
                // Toss out duplicate packets
                if (!isNewByPacketId[packet.Id])
                {
                    duplicateReceivesCounter.Increment();
                    continue;
                }

                // Bin into multipart chunk vs not
                var multiPartChunk = packet.Message.Body as MultiPartChunkDto;
                if (multiPartChunk != null)
                {
                    multiPartChunksBytesReceivedAggregator.Put(multiPartChunk.BodyLength);
                    chunksToProcess.Add(multiPartChunk);
                }
                else
                {
                    standalonePacketsToProcess.Add(packet);
                }
            }

            // Kick off async stanadalone packet process on thread pool.
            foreach (var packet in standalonePacketsToProcess)
            {
                inboundMessageDispatcher.DispatchAsync(packet.Message).Forget();
            }

            // Synchronously handle multipart chunk processing.
            foreach (var chunk in chunksToProcess)
            {
                multiPartPacketReassembler.HandleInboundMultiPartChunk(chunk);
            }
        }
 public Task SendAcknowledgementAsync(Guid destination, AcknowledgementDto acknowledgement)
 {
     return(unicaster.SendAcknowledgementAsync(destination, acknowledgement));
 }