示例#1
0
        /// <inheritdoc />
        public async Task <Stream> ConnectAsync(MultiAddress address,
                                                CancellationToken cancel = default)
        {
            var port = address.Protocols
                       .Where(p => p.Name == "tcp")
                       .Select(p => int.Parse(p.Value))
                       .First();

            var ip = address.Protocols
                     .FirstOrDefault(p => p.Name == "ip4" || p.Name == "ip6");

            if (ip == null)
            {
                throw new ArgumentException($"Missing IP address in '{address}'.", nameof(address));
            }

            var socket = new Socket(
                ip.Name == "ip4" ? AddressFamily.InterNetwork : AddressFamily.InterNetworkV6,
                SocketType.Stream,
                ProtocolType.Tcp);

            var latency = MinReadTimeout; // keep compiler happy
            var start   = DateTime.Now;

            try
            {
                Log.Trace("connecting to " + address);

                // Handle cancellation of the connect attempt by disposing
                // of the socket.  This will force ConnectAsync to return.
                await using (var _ = cancel.Register(() =>
                {
                    if (socket != null)
                    {
                        socket?.Dispose();
                    }

                    socket = null;
                }))
                {
                    var ipaddr = IPAddress.Parse(ip.Value);
                    await socket.ConnectAsync(ipaddr, port).ConfigureAwait(false);
                }

                latency = DateTime.Now - start;
                Log.Trace($"connected to {address} in {latency.TotalMilliseconds} ms");
            }
            catch (Exception) when(cancel.IsCancellationRequested)
            {
                // eat it, the caller has cancelled and doesn't care.
            }
            catch (Exception)
            {
                latency = DateTime.Now - start;
                Log.Trace($"failed to {address} in {latency.TotalMilliseconds} ms");
                socket?.Dispose();
                throw;
            }

            if (cancel.IsCancellationRequested)
            {
                Log.Trace("cancel " + address);
                socket?.Dispose();
                cancel.ThrowIfCancellationRequested();
            }

            var timeout = (int)Math.Max(MinReadTimeout.TotalMilliseconds, latency.TotalMilliseconds * 3);

            socket.LingerState    = new LingerOption(false, 0);
            socket.ReceiveTimeout = timeout;
            socket.SendTimeout    = timeout;
            Stream stream = new NetworkStream(socket, true);

            stream.ReadTimeout  = timeout;
            stream.WriteTimeout = timeout;

            stream = new DuplexBufferedStream(stream);

            if (!cancel.IsCancellationRequested)
            {
                return(stream);
            }

            Log.Trace("cancel " + address);
            await stream.DisposeAsync();

            cancel.ThrowIfCancellationRequested();

            return(stream);
        }
示例#2
0
        private static void ProcessConnection(Socket socket,
                                              MultiAddress address,
                                              Action <Stream, MultiAddress, MultiAddress> handler,
                                              CancellationToken cancel)
        {
            Log.Debug("listening on " + address);

            // Handle cancellation of the listener
            cancel.Register(() =>
            {
                Log.Debug("Got cancel on " + address);

                try
                {
                    if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                    {
                        socket.Shutdown(SocketShutdown.Both);
                        socket.Dispose();
                    }
                    else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                    {
                        socket.Shutdown(SocketShutdown.Receive);
                    }
                    else // must be windows
                    {
                        socket.Dispose();
                    }
                }
                catch (Exception e)
                {
                    Log.Warn($"Cancelling listener: {e.Message}");
                }
                finally
                {
                    socket = null;
                }
            });

            try
            {
                while (!cancel.IsCancellationRequested)
                {
                    var conn = socket.Accept();

                    MultiAddress remote = null;
                    if (conn.RemoteEndPoint is IPEndPoint endPoint)
                    {
                        var s = new StringBuilder();
                        s.Append(endPoint.AddressFamily == AddressFamily.InterNetwork ? "/ip4/" : "/ip6/");
                        s.Append(endPoint.Address);
                        s.Append("/tcp/");
                        s.Append(endPoint.Port);
                        remote = new MultiAddress(s.ToString());
                        Log.Debug("connection from " + remote);
                    }

                    conn.NoDelay = true;
                    Stream peer = new NetworkStream(conn, true);

                    peer = new DuplexBufferedStream(peer);

                    try
                    {
                        handler(peer, address, remote);
                    }
                    catch (Exception e)
                    {
                        Log.Error("listener handler failed " + address, e);
                        peer.Dispose();
                    }
                }
            }
            catch (Exception) when(cancel.IsCancellationRequested)
            {
                // ignore
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Log.Error("listener failed " + address, e);
            }
            finally
            {
                socket?.Dispose();
            }

            Log.Debug("stop listening on " + address);
        }
示例#3
0
 public void Setup()
 {
     _random = new Random();
     _inner  = new MemoryStream();
     _stream = new DuplexBufferedStream(_inner, 16);
 }
示例#4
0
        void ProcessConnection(Socket socket, MultiAddress address, Action <Stream, MultiAddress, MultiAddress> handler, CancellationToken cancel)
        {
            log.Debug("listening on " + address);

            // Handle cancellation of the listener
            cancel.Register(() =>
            {
                log.Debug("Got cancel on " + address);

                try
                {
                    // .Net Standard on Unix neeeds this to cancel the Accept
#if !NET461
                    if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                    {
                        socket.Shutdown(SocketShutdown.Both);
                        socket.Dispose();
                    }
                    else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                    {
                        socket.Shutdown(SocketShutdown.Receive);
                    }
                    else // must be windows
                    {
                        socket.Dispose();
                    }
#else
                    socket.Dispose();
#endif
                }
                catch (Exception e)
                {
                    log.Warn($"Cancelling listener: {e.Message}");
                }
                finally
                {
                    socket = null;
                }
            });

            try
            {
                while (!cancel.IsCancellationRequested)
                {
                    Socket conn = socket.Accept();
                    if (conn == null)
                    {
                        log.Warn("Null socket from Accept");
                        continue;
                    }
                    MultiAddress remote   = null;
                    var          endPoint = conn.RemoteEndPoint as IPEndPoint;
                    if (endPoint != null)
                    {
                        var s = new StringBuilder();
                        s.Append(endPoint.AddressFamily == AddressFamily.InterNetwork ? "/ip4/" : "/ip6/");
                        s.Append(endPoint.Address.ToString());
                        s.Append("/tcp/");
                        s.Append(endPoint.Port);
                        remote = new MultiAddress(s.ToString());
                        log.Debug("connection from " + remote);
                    }

                    conn.NoDelay = true;
                    Stream peer = new NetworkStream(conn, ownsSocket: true);
#if !NETSTANDARD14
                    // BufferedStream not available in .Net Standard 1.4
                    peer = new DuplexBufferedStream(peer);
#endif
                    try
                    {
                        handler(peer, address, remote);
                    }
                    catch (Exception e)
                    {
                        log.Error("listener handler failed " + address, e);
                        peer.Dispose();
                    }
                }
            }
            catch (Exception) when(cancel.IsCancellationRequested)
            {
                // eat it
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                log.Error("listener failed " + address, e);
                // eat it and give up
            }
            finally
            {
                if (socket != null)
                {
                    socket.Dispose();
                }
            }

            log.Debug("stop listening on " + address);
        }
示例#5
0
        /// <inheritdoc />
        public async Task <Stream> ConnectAsync(MultiAddress address, CancellationToken cancel = default(CancellationToken))
        {
            var port = address.Protocols
                       .Where(p => p.Name == "tcp")
                       .Select(p => Int32.Parse(p.Value))
                       .First();
            var ip = address.Protocols
                     .Where(p => p.Name == "ip4" || p.Name == "ip6")
                     .FirstOrDefault();

            if (ip == null)
            {
                throw new ArgumentException($"Missing IP address in '{address}'.", "address");
            }
            var socket = new Socket(
                ip.Name == "ip4" ? AddressFamily.InterNetwork : AddressFamily.InterNetworkV6,
                SocketType.Stream,
                ProtocolType.Tcp);

            TimeSpan latency = MinReadTimeout; // keep compiler happy

            try
            {
                log.Trace("connecting to " + address);
                var start = DateTime.Now;

                // Handle cancellation of the connect attempt by disposing
                // of the socket.  This will force ConnectAsync to return.
                using (var _ = cancel.Register(() => { socket?.Dispose(); socket = null; }))
                {
                    await socket.ConnectAsync(ip.Value, port);
                };

                latency = DateTime.Now - start;
                log.Trace($"connected to {address} in {latency.TotalMilliseconds} ms");
            }
            catch (Exception) when(cancel.IsCancellationRequested)
            {
                // eat it, the caller has cancelled and doesn't care.
            }
            catch (Exception)
            {
                socket?.Dispose();
                throw;
            }
            if (cancel.IsCancellationRequested)
            {
                log.Trace("cancel " + address);
                socket?.Dispose();
                cancel.ThrowIfCancellationRequested();
            }

            var timeout = (int)Math.Max(MinReadTimeout.TotalMilliseconds, latency.TotalMilliseconds * 3);

            socket.LingerState    = new LingerOption(false, 0);
            socket.ReceiveTimeout = timeout;
            socket.SendTimeout    = timeout;
            Stream stream = new NetworkStream(socket, ownsSocket: true);

            stream.ReadTimeout  = timeout;
            stream.WriteTimeout = timeout;

#if !NETSTANDARD14
            // BufferedStream not available in .Net Standard 1.4
            stream = new DuplexBufferedStream(stream);
#endif

            if (cancel.IsCancellationRequested)
            {
                log.Trace("cancel " + address);
                stream.Dispose();
                cancel.ThrowIfCancellationRequested();
            }

            return(stream);
        }