Example #1
0
        private static void HandleInboundDataEventCompletionCallback(InboundDataEvent inboundSomethingEvent)
        {
            var self = inboundSomethingEvent.UdpClient;
            var e    = inboundSomethingEvent.SocketArgs;
            var sw   = inboundSomethingEvent.StopWatch;

            inboundSomethingEvent.DataBufferPool.ReturnObject(inboundSomethingEvent.Data);
            inboundSomethingEvent.Data = null;
            self.inboundSomethingEventPool.ReturnObject(inboundSomethingEvent);

            // analytics
            self.inboundBytesAggregator.Put(e.BytesTransferred);
            self.inboundReceiveProcessDispatchLatencyAggregator.Put(sw.ElapsedMilliseconds);

            // return to pool
            try {
                e.Dispose();

//            var referenceRemoteEndpoint = (IPEndPoint)e.UserToken;
//            e.RemoteEndPoint = new IPEndPoint(referenceRemoteEndpoint.Address, referenceRemoteEndpoint.Port);
//            e.AcceptSocket.ReceiveFromAsync(e);
            } catch (ObjectDisposedException) when(self.isShutdown)
            {
                // socket was probably shut down
            }
        }
        /// <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);
            }
        }
      /// <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);
         }
      }