Ejemplo n.º 1
0
        /// <summary>
        /// Invoke when a datagram is received from a socket.
        /// </summary>
        /// <param name="receive"></param>
        /// <param name="respond"></param>
        /// <param name="args"></param>
        public void OnReceive(Socket receive, Socket respond, SocketAsyncEventArgs args)
        {
            var source = new KIpEndpoint((IPEndPoint)args.RemoteEndPoint);

            logger.LogTrace("Received incoming packet of {Length} from {Endpoint}.", args.BytesTransferred, source);

            try
            {
                // no data found
                if (args.BytesTransferred == 0)
                {
                    return;
                }

                // some error occurred?
                if (args.SocketError != SocketError.Success)
                {
                    logger.LogError("Socket error while receiving UDP data: {SocketError}.", args.SocketError);
                    return;
                }

                // we only care about receive from events
                if (args.LastOperation != SocketAsyncOperation.ReceiveFrom &&
                    args.LastOperation != SocketAsyncOperation.ReceiveMessageFrom)
                {
                    logger.LogError("Unxpected operation while receiving UDP data: {LastOperation}.", args.LastOperation);
                    return;
                }

                // deserialize message sequence
                var packet = serializer.Read(new ReadOnlyMemory <byte>(args.Buffer, args.Offset, args.BytesTransferred), new KMessageContext <TNodeId>(formats.Select(i => i.ContentType)));
                if (packet.Format == null || packet.Sequence == null)
                {
                    logger.LogWarning("Invalid or empty packet.");
                    return;
                }

                Task.Run(async() =>
                {
                    try
                    {
                        logger.LogTrace("Decoded packet as {Format} from {Endpoint}.", packet.Format, source);
                        await OnReceiveAsync(receive, respond, source, packet, CancellationToken.None);
                    }
                    catch (Exception e)
                    {
                        logger.LogError(e, "Unhandled exception receiving UDP packet.");
                    }
                });
            }
            catch (Exception e)
            {
                logger.LogError(e, "Exception during UDP receive.");
            }
        }
        /// <summary>
        /// Invoked when a receive operation completes.
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="args"></param>
        void RecvArgs_Completed(Socket socket, SocketAsyncEventArgs args)
        {
            // extract source endpoint
            var source = new KIpEndpoint((IPEndPoint)args.RemoteEndPoint);
            var length = args.BytesTransferred;

            logger.LogTrace("Received incoming UDP packet of {Length} from {Endpoint}.", length, source);

            // should only be receiving packets from our message loop
            if (args.LastOperation != SocketAsyncOperation.ReceiveMessageFrom)
            {
                logger.LogTrace("Unexpected packet operation {Operation}.", args.LastOperation);
                return;
            }
            // some error occurred?
            if (args.SocketError != SocketError.Success)
            {
                return;
            }

            // we only care about receive from events
            if (args.LastOperation != SocketAsyncOperation.ReceiveMessageFrom &&
                args.LastOperation != SocketAsyncOperation.ReceiveFrom)
            {
                return;
            }

            // no data found
            if (args.BytesTransferred == 0)
            {
                return;
            }

            // socket is unbound, ignore
            if (socket.IsBound == false)
            {
                return;
            }

            // deserialize message sequence
            var packet = serializer.Read(new ReadOnlyMemory <byte>(args.Buffer, args.Offset, args.BytesTransferred), new KMessageContext <TNodeId>(formats.Select(i => i.ContentType)));

            if (packet.Format == null || packet.Sequence == null)
            {
                return;
            }

            Task.Run(async() =>
            {
                try
                {
                    logger.LogTrace("Decoded packet as {Format} from {Endpoint}.", packet.Format, source);
                    await OnReceiveAsync(socket, source, packet, CancellationToken.None);
                }
                catch (Exception e)
                {
                    logger.LogError(e, "Unhandled exception dispatching incoming packet.");
                }
            });

            // continue receiving if socket still available
            // this lock is blocking, but should be okay since this event handler can stall
            using (sync.LockAsync().GetAwaiter().GetResult())
            {
                // reset remote endpoint
                args.RemoteEndPoint = source.Protocol switch
                {
                    KIpAddressFamily.IPv4 => new IPEndPoint(IPAddress.Any, 0),
                    KIpAddressFamily.IPv6 => new IPEndPoint(IPAddress.IPv6Any, 0),
                    _ => throw new InvalidOperationException(),
                };

                try
                {
                    socket.ReceiveMessageFromAsync(args);
                }
                catch (ObjectDisposedException)
                {
                    // we must have been terminated, ignore
                }
            }
        }