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); } }