Esempio n. 1
0
 public UdpUnicaster(Identity identity, UdpClient udpClient, AcknowledgementCoordinator acknowledgementCoordinator, IObjectPool <byte[]> sendReceiveBufferPool, UdpClientRemoteInfo remoteInfo, IAuditCounter resendsCounter, IAuditAggregator <int> resendsAggregator, IAuditAggregator <double> outboundMessageRateLimitAggregator, IAuditAggregator <double> sendQueueDepthAggregator)
 {
     this.outboundPacketMemoryStreamPool = new ByteArrayPoolBackedMemoryStreamPool(sendReceiveBufferPool);
     this.identity  = identity;
     this.udpClient = udpClient;
     this.acknowledgementCoordinator = acknowledgementCoordinator;
     this.remoteInfo        = remoteInfo;
     this.resendsCounter    = resendsCounter;
     this.resendsAggregator = resendsAggregator;
     this.outboundMessageRateLimitAggregator = outboundMessageRateLimitAggregator;
     this.sendQueueDepthAggregator           = sendQueueDepthAggregator;
 }
        private void HandleAnnouncement(UdpClientRemoteInfo remoteInfo, AnnouncementDto x)
        {
            announcementsReceivedCounter.Increment();

            var            peerIdentity           = x.Identity;
            var            peerId                 = peerIdentity.Id;
            bool           isNewlyDiscoveredRoute = false;
            RoutingContext addedRoutingContext    = null;
            UdpUnicaster   addedUnicaster         = null;
            var            routingContext         = routingContextsByPeerId.GetOrAdd(
                peerId,
                add => {
                isNewlyDiscoveredRoute = true;
                var unicastReceivePort = int.Parse((string)x.Identity.Properties[UdpConstants.kUnicastPortIdentityPropertyKey]);
                var unicastIpAddress   = remoteInfo.IPEndpoint.Address;
                var unicastEndpoint    = new IPEndPoint(unicastIpAddress, unicastReceivePort);
                var unicastRemoteInfo  = new UdpClientRemoteInfo {
                    Socket     = remoteInfo.Socket,
                    IPEndpoint = unicastEndpoint
                };

                addedUnicaster = udpUnicasterFactory.Create(unicastRemoteInfo);
                return(addedRoutingContext = new RoutingContext(addedUnicaster));
            });

            if (addedRoutingContext == routingContext)
            {
                addedUnicaster.Initialize();
            }
            if (isNewlyDiscoveredRoute)
            {
                routingTable.Register(peerId, routingContext);
            }

            peerTable.GetOrAdd(peerId).HandleInboundPeerIdentityUpdate(peerIdentity);
        }
Esempio n. 3
0
        public void Unicast(UdpClientRemoteInfo remoteInfo, MemoryStream[] frames, Action action)
        {
            // Frames larger than half the maximum packet size certainly cannot be packed together.
            var       smallFrames = new List <MemoryStream>(frames.Length);
            var       largeFrames = new List <MemoryStream>(frames.Length);
            const int kHalfMaximumTransportSize = UdpConstants.kMaximumTransportSize / 2;

            for (var i = 0; i < frames.Length; i++)
            {
                var frame = frames[i];
                if (frame.Length <= kHalfMaximumTransportSize)
                {
                    smallFrames.Add(frame);
                }
                else
                {
                    largeFrames.Add(frame);
                }
            }

            // Order small frames ascending by size, large frames descending by size.
            smallFrames.Sort(new MemoryStreamByPositionComparer());
            largeFrames.Sort(new ReverseComparer <MemoryStream>(new MemoryStreamByPositionComparer()));

            // Place large frames into outbound buffers.
            var outboundBuffers = new List <MemoryStream>(frames.Length);

            foreach (var largeFrame in largeFrames)
            {
                var outboundBuffer = outboundMemoryStreamPool.TakeObject();
                outboundBuffer.Write(largeFrame.GetBuffer(), 0, (int)largeFrame.Position);
                outboundBuffers.Add(outboundBuffer);
            }

            // Place small frames into outbound buffers. Note that as the
            // small frames are ascending in size and the buffers are descending
            // in size, while we iterate if a small frame cannot fit into the
            // next outbound buffer then none of the following small frames can either.
            int activeOutboundBufferIndex = 0;

            foreach (var smallFrame in smallFrames)
            {
                // precompute greatest outbound buffer permission for which
                // we will still be able to fit into the buffer.
                int frameSize = (int)smallFrame.Position;
                int greatestFittableBufferPosition = UdpConstants.kMaximumTransportSize - frameSize;

                // Attempt to place the small frame into existing outbound buffers
                bool placed = false;
                while (!placed && activeOutboundBufferIndex != outboundBuffers.Count)
                {
                    var outboundBuffer = outboundBuffers[activeOutboundBufferIndex];
                    if (outboundBuffer.Position > greatestFittableBufferPosition)
                    {
                        activeOutboundBufferIndex++;
                    }
                    else
                    {
                        outboundBuffer.Write(smallFrame.GetBuffer(), 0, (int)smallFrame.Position);
                        placed = true;
                    }
                }

                // If no existing outbound buffer had space, allocate a new one
                if (!placed)
                {
                    AssertEquals(outboundBuffers.Count, activeOutboundBufferIndex);
                    var outboundBuffer = outboundMemoryStreamPool.TakeObject();
                    outboundBuffer.Write(smallFrame.GetBuffer(), 0, (int)smallFrame.Position);
                    outboundBuffers.Add(outboundBuffer);
                }
            }

//         Console.WriteLine($"Batched {frames.Length} to {outboundBuffers.Count} buffers.");

            int sendsRemaining = outboundBuffers.Count;

            foreach (var outboundBuffer in outboundBuffers)
            {
                var job = new UdpUnicastJob {
                    OutboundBuffer        = outboundBuffer,
                    RemoteInfo            = remoteInfo,
                    SendCompletionHandler = () => {
                        outboundBuffer.SetLength(0);
                        outboundMemoryStreamPool.ReturnObject(outboundBuffer);
                        if (Interlocked.Decrement(ref sendsRemaining) == 0)
                        {
                            action();
                        }
                    }
                };
                unicastJobQueue.Enqueue(job);
            }

//         int sendsRemaining = outboundBuffers.Count;
//         Parallel.ForEach(
//            outboundBuffers,
//            outboundBuffer => {
//               outboundBytesAggregator.Put(outboundBuffer.Length);
//
//               var e = new SocketAsyncEventArgs();
//               e.RemoteEndPoint = remoteInfo.IPEndpoint;
//               e.SetBuffer(outboundBuffer.GetBuffer(), 0, (int)outboundBuffer.Position);
//               e.Completed += (sender, args) => {
//                  // Duplicate code with below.
//                  args.SetBuffer(null, 0, 0);
//                  args.Dispose();
//
//                  outboundBuffer.SetLength(0);
//                  outboundMemoryStreamPool.ReturnObject(outboundBuffer);
//
//                  if (Interlocked.Decrement(ref sendsRemaining) == 0) {
//                     action();
//                  }
//               };
//
//               const int kSendStateAsync = 1;
//               const int kSendStateDone = 2;
//               const int kSendStateError = 3;
//               int sendState;
//               try {
//                  bool completingAsynchronously = remoteInfo.Socket.SendToAsync(e);
//                  sendState = completingAsynchronously ? kSendStateAsync : kSendStateDone;
//               } catch (ObjectDisposedException) when (isShutdown) {
//                  sendState = kSendStateError;
//               }
//
//               if (sendState == kSendStateDone || sendState == kSendStateError) {
//                  // Completed synchronously so e.Completed won't be called.
//                  e.SetBuffer(null, 0, 0);
//                  e.Dispose();
//
//                  outboundBuffer.SetLength(0);
//                  outboundMemoryStreamPool.ReturnObject(outboundBuffer);
//
//                  if (Interlocked.Decrement(ref sendsRemaining) == 0) {
//                     action();
//                  }
//               }
//            });

//         int sendsRemaining = outboundBuffers.Count;
//         foreach (var outboundBuffer in outboundBuffers) {
//            outboundBytesAggregator.Put(outboundBuffer.Length);
//
//            var e = new SocketAsyncEventArgs();
//            e.RemoteEndPoint = remoteInfo.IPEndpoint;
//            e.SetBuffer(outboundBuffer.GetBuffer(), 0, (int)outboundBuffer.Position);
//            e.Completed += (sender, args) => {
//               // Duplicate code with below.
//               args.SetBuffer(null, 0, 0);
//               args.Dispose();
//
//               outboundBuffer.SetLength(0);
//               outboundMemoryStreamPool.ReturnObject(outboundBuffer);
//
//               if (Interlocked.Decrement(ref sendsRemaining) == 0) {
//                  action();
//               }
//            };
//
//            const int kSendStateAsync = 1;
//            const int kSendStateDone = 2;
//            const int kSendStateError = 3;
//            int sendState;
//            try {
//               bool completingAsynchronously = remoteInfo.Socket.SendToAsync(e);
//               sendState = completingAsynchronously ? kSendStateAsync : kSendStateDone;
//            } catch (ObjectDisposedException) when (isShutdown) {
//               sendState = kSendStateError;
//            }
//
//            if (sendState == kSendStateDone || sendState == kSendStateError) {
//               // Completed synchronously so e.Completed won't be called.
//               e.SetBuffer(null, 0, 0);
//               e.Dispose();
//
//               outboundBuffer.SetLength(0);
//               outboundMemoryStreamPool.ReturnObject(outboundBuffer);
//
//               if (sendState == kSendStateError) {
//                  // Don't send remaining messages.
//                  // To the application, this appears like packet loss.
//                  action();
//                  return;
//               } else if (Interlocked.Decrement(ref sendsRemaining) == 0) {
//                  action();
//               }
//            }
//         }
        }
Esempio n. 4
0
 public UdpUnicaster Create(UdpClientRemoteInfo remoteInfo)
 {
     return(new UdpUnicaster(identity, udpClient, acknowledgementCoordinator, sendReceiveBufferPool, remoteInfo, resendsCounter, resendsAggregator, outboundMessageRateLimitAggregator, sendQueueDepthAggregator));
 }