private async Task StartInternal()
        {
            while (!cancel.IsCancellationRequested)
            {
                var rec = await client.ReceiveAsync().WithCancellation(cancel.Token);

                Debug.Assert(rec.Buffer.Length > 0);
                try
                {
                    DiscoveryAnnounceMessage messageReq;
                    messageReq = settings.MessageSerializer.Deserialize <DiscoveryAnnounceMessage>(rec.Buffer);

                    var endpoint = new IPEndPoint(rec.RemoteEndPoint.Address, messageReq.ServicePort);
                    if (!compatibilityChecker.IsCompatibleWith(endpoint, messageReq.Version))
                    {
                        continue;
                    }
                    PeerDiscoveryMode mode = PeerDiscoveryMode.UdpDiscovery;
                    bool isLoopback        = messageReq.PeerId.Equals(announce.PeerId);
                    if (isLoopback)
                    {
                        mode |= PeerDiscoveryMode.Loopback;
                    }
                    registry.UpdatePeers(new PeerUpdateInfo[] { new PeerUpdateInfo(endpoint, mode, TimeSpan.Zero) });

                    logger.LogTrace($"Received request from {rec.RemoteEndPoint.Address}.");
                }
                catch (OperationCanceledException)
                {
                    return;
                }
                catch (Exception e)
                {
                    logger.LogDebug($"Cannot read message from {rec.RemoteEndPoint}. Reason: {e.Message}");
                    continue;
                }

                try
                {
                    await client.SendAsync(announceBytes, announceBytes.Length, rec.RemoteEndPoint).WithCancellation(cancel.Token);
                }
                catch (OperationCanceledException)
                {
                    return;
                }
                catch (SocketException)
                {
                    logger.LogTrace($"Client {rec.RemoteEndPoint} closed connection befory reply.");
                }
                catch (Exception e)
                {
                    logger.LogDebug($"Error sending response to client {rec.RemoteEndPoint}: {e.Message}");
                }
            }
        }
示例#2
0
        public async Task Discover()
        {
            using (client = new UdpClient())
            {
                var ip = new IPEndPoint(IPAddress.Broadcast, settings.UdpAnnouncePort);

                Debug.Assert(announceBytes.Length > 0);
                var lengthSent = await client.SendAsync(announceBytes, announceBytes.Length, ip);

                if (lengthSent != announceBytes.Length)
                {
                    throw new InvalidOperationException("Cannot send discovery datagram.");
                }

                var timeout = new CancellationTokenSource(settings.UdpDiscoveryTimeout);
                while (!timeout.IsCancellationRequested)
                {
                    DiscoveryAnnounceMessage response = null;
                    try
                    {
                        var responseData = await client.ReceiveAsync().WithCancellation(timeout.Token);

                        response = settings.MessageSerializer.Deserialize <DiscoveryAnnounceMessage>(responseData.Buffer);
                        var endpoint = new IPEndPoint(responseData.RemoteEndPoint.Address, response.ServicePort);
                        if (!compatibilityChecker.IsCompatibleWith(endpoint, response.Version))
                        {
                            continue;
                        }
                        PeerDiscoveryMode mode = PeerDiscoveryMode.UdpDiscovery;
                        bool isLoopback        = response.PeerId.Equals(announce.PeerId);
                        if (isLoopback)
                        {
                            mode |= PeerDiscoveryMode.Loopback;
                        }
                        registry.UpdatePeers(new PeerUpdateInfo[] { new PeerUpdateInfo(endpoint, mode, TimeSpan.Zero) });
                    }
                    catch (OperationCanceledException)
                    {
                        break;
                    }
                    catch (Exception e)
                    {
                        logger.LogDebug($"Cannot deserialize discovery response: {e}");
                    }
                }
            }
        }
        public void OnActionExecuting(ActionExecutingContext context)
        {
            if (!context.HttpContext.Request.Headers.TryGetValue(VersionHeaderName, out StringValues valueString))
            {
                ProcessInvalidVersion(context, $"Missing header {VersionHeaderName}");
                return;
            }

            if (!ClientVersion.TryParse(valueString, out ClientVersion version))
            {
                ProcessInvalidVersion(context, $"Invalid value of header {VersionHeaderName}");
                return;
            }

            if (!CompatibilityChecker.IsCompatibleWith(CompatibilitySet.Network, context.HttpContext.Connection.RemoteIpAddress.ToString(), version))
            {
                ProcessInvalidVersion(context, $"Server is incompatible with version defined in header {VersionHeaderName}");
                return;
            }

            // validate if this is not request from myself
            if (!context.HttpContext.Request.Headers.TryGetValue(InstanceHeaderName, out valueString))
            {
                ProcessInvalidVersion(context, $"Missing header {InstanceHeaderName}");
                return;
            }

            if (!Hash.TryParse(valueString, out Hash hash))
            {
                ProcessInvalidVersion(context, $"Invalid value of header {InstanceHeaderName}");
                return;
            }

            // validate input type header
            if (!context.HttpContext.Request.Headers.TryGetValue(TypeHeaderName, out StringValues _))
            {
                ProcessInvalidVersion(context, $"Missing header {TypeHeaderName}");
                return;
            }

            var controller = (IHttpApiController)context.Controller;

            controller.RemoteIpAddress = context.HttpContext.Connection.RemoteIpAddress;
            controller.PeerId          = hash;
            controller.IsLoopback      = hash.Equals(InstanceHash.Hash);
        }