/// <summary>
        ///   Get all the addresses for the specified <see cref="MultiAddress"/>.
        /// </summary>
        /// <param name="multiaddress">
        ///   The multiaddress to resolve.
        /// </param>
        /// <param name="cancel">
        ///   Is used to stop the task.  When cancelled, the <see cref="TaskCanceledException"/> is raised.
        /// </param>
        /// <returns>
        ///   A task that represents the asynchronous operation. The task's result
        ///   is a sequence of possible multiaddresses.
        /// </returns>
        /// <exception cref="SocketException">
        ///   The host name cannot be resolved.
        /// </exception>
        /// <remarks>
        ///   When the <see cref="NetworkProtocol.Name"/> starts with "dns", then a DNS
        ///   lookup is performed to get all the IP addresses for the host name.  "dn4" and "dns6"
        ///   will filter the result for IPv4 and IPV6 addresses.
        ///   <para>
        ///   When the <see cref="NetworkProtocol.Name"/> is "http" or "https", then
        ///   a "tcp/80" or "tcp/443" is respectively added.
        ///   </para>
        /// </remarks>
        public static async Task <List <MultiAddress> > ResolveAsync(this MultiAddress multiaddress,
                                                                     CancellationToken cancel = default)
        {
            var list = new List <MultiAddress>();

            // HTTP
            var i = multiaddress.Protocols.FindIndex(ma => ma.Name == "http");

            if (i >= 0 && !multiaddress.Protocols.Any(p => p.Name == "tcp"))
            {
                multiaddress = multiaddress.Clone();
                multiaddress.Protocols.InsertRange(i + 1, _http.Protocols);
            }

            // HTTPS
            i = multiaddress.Protocols.FindIndex(ma => ma.Name == "https");
            if (i >= 0 && !multiaddress.Protocols.Any(p => p.Name == "tcp"))
            {
                multiaddress = multiaddress.Clone();
                multiaddress.Protocols.InsertRange(i + 1, _https.Protocols);
            }

            // DNS*
            i = multiaddress.Protocols.FindIndex(ma => ma.Name.StartsWith("dns"));
            if (i < 0)
            {
                list.Add(multiaddress);
                return(list);
            }

            var protocolName = multiaddress.Protocols[i].Name;
            var host         = multiaddress.Protocols[i].Value;

            // TODO: Don't use DNS, but use the IPFS Engine DNS resolver.
            // This will not then expose the domain name in plain text.
            // We also, then get to specify if A and/or AAAA records are needed.
            var addresses = (await Dns.GetHostAddressesAsync(host).ConfigureAwait(false))
                            .Where(a => _supportedDnsAddressFamilies.ContainsKey(a.AddressFamily))
                            .Where(a =>
                                   protocolName == "dns" ||
                                   protocolName == "dns4" && a.AddressFamily == AddressFamily.InterNetwork ||
                                   protocolName == "dns6" && a.AddressFamily == AddressFamily.InterNetworkV6);

            foreach (var addr in addresses)
            {
                var ma0 = new MultiAddress(_supportedDnsAddressFamilies[addr.AddressFamily] + addr);
                var ma1 = multiaddress.Clone();
                ma1.Protocols[i] = ma0.Protocols[0];
                list.Add(ma1);
            }

            return(list);
        }
        public void Cloning()
        {
            var a = new MultiAddress("/dns/libp2p.io/tcp/5001");
            var b = a.Clone();

            Assert.AreEqual(a, b);
            Assert.AreNotSame(a.Protocols, b.Protocols);
        }
Esempio n. 3
0
        /// <inheritdoc />
        public MultiAddress Listen(MultiAddress address,
                                   Action <Stream, MultiAddress, MultiAddress> handler,
                                   CancellationToken cancel)
        {
            var port = address.Protocols
                       .Where(p => p.Name == "tcp")
                       .Select(p => int.Parse(p.Value))
                       .FirstOrDefault();

            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 ipAddress = IPAddress.Parse(ip.Value);
            var endPoint  = new IPEndPoint(ipAddress, port);
            var socket    = new Socket(
                endPoint.AddressFamily,
                SocketType.Stream,
                ProtocolType.Tcp);

            try
            {
                socket.Bind(endPoint);
                socket.Listen(100);
            }
            catch (Exception e)
            {
                socket.Dispose();
                throw new Exception("Bind/listen failed on " + address, e);
            }

            // If no port specified, then add it.
            var actualPort = ((IPEndPoint)socket.LocalEndPoint).Port;

            if (port != actualPort)
            {
                address = address.Clone();
                var protocol = address.Protocols.FirstOrDefault(p => p.Name == "tcp");
                if (protocol != null)
                {
                    protocol.Value = actualPort.ToString();
                }
                else
                {
                    address.Protocols.AddRange(new MultiAddress("/tcp/" + actualPort).Protocols);
                }
            }

            _ = Task.Run(() => ProcessConnection(socket, address, handler, cancel), cancel);

            return(address);
        }
Esempio n. 4
0
        /// <inheritdoc />
        public MultiAddress Listen(MultiAddress address, Action <Stream, MultiAddress, MultiAddress> handler, CancellationToken cancel)
        {
            var port = address.Protocols
                       .Where(p => p.Name == "tcp")
                       .Select(p => Int32.Parse(p.Value))
                       .FirstOrDefault();
            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 ipAddress = IPAddress.Parse(ip.Value);
            var endPoint  = new IPEndPoint(ipAddress, port);
            var socket    = new Socket(
                endPoint.AddressFamily,
                SocketType.Stream,
                ProtocolType.Tcp);

            try
            {
                socket.Bind(endPoint);
                socket.Listen(100);
            }
            catch (Exception e)
            {
                socket.Dispose();
                throw new Exception("Bind/listen failed on " + address, e);
            }

            // If no port specified, then add it.
            var actualPort = ((IPEndPoint)socket.LocalEndPoint).Port;

            if (port != actualPort)
            {
                address = address.Clone();
                var protocol = address.Protocols.FirstOrDefault(p => p.Name == "tcp");
                if (protocol != null)
                {
                    protocol.Value = actualPort.ToString();
                }
                else
                {
                    address.Protocols.AddRange(new MultiAddress("/tcp/" + actualPort).Protocols);
                }
            }

#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            Task.Run(() => ProcessConnection(socket, address, handler, cancel));
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed

            return(address);
        }
Esempio n. 5
0
        /// <inheritdoc />
        public MultiAddress Listen(MultiAddress address,
                                   Action <Stream, MultiAddress, MultiAddress> handler,
                                   CancellationToken cancel)
        {
            var port = address.Protocols
                       .Where(p => p.Name == "udp")
                       .Select(p => int.Parse(p.Value))
                       .FirstOrDefault();
            var ip = address.Protocols
                     .Where(p => p.Name == "ip4" || p.Name == "ip6")
                     .First();
            var ipAddress = IPAddress.Parse(ip.Value);
            var endPoint  = new IPEndPoint(ipAddress, port);
            var socket    = new Socket(
                endPoint.AddressFamily,
                SocketType.Dgram,
                ProtocolType.Udp);

            socket.Bind(endPoint);

            // If no port specified, then add it.
            var actualPort = ((IPEndPoint)socket.LocalEndPoint).Port;

            if (port != actualPort)
            {
                address = address.Clone();
                var protocol = address.Protocols.FirstOrDefault(p => p.Name == "udp");
                if (protocol != null)
                {
                    protocol.Value = actualPort.ToString();
                }
                else
                {
                    address.Protocols.AddRange(new MultiAddress("/udp/" + actualPort).Protocols);
                }
            }

            // TODO: UDP listener
            throw new NotImplementedException();
#if false
            var stream = new DatagramStream(socket, ownsSocket: true);
            handler(stream, address, null);

            return(address);
#endif
        }
        public void Cloning()
        {
            var ma1 = new MultiAddress("/ip4/10.1.10.10/tcp/29087");
            var ma2 = ma1.Clone();

            Assert.Equal(ma1, ma2);
            Assert.NotSame(ma1, ma2);
            Assert.NotSame(ma1.Protocols, ma2.Protocols);
            for (var i = 0; i < ma1.Protocols.Count; ++i)
            {
                var p1 = ma1.Protocols[i];
                var p2 = ma2.Protocols[i];
                Assert.Equal(p1.Code, p2.Code);
                Assert.Equal(p1.Name, p2.Name);
                Assert.Equal(p1.Value, p2.Value);
                Assert.NotSame(p1, p2);
            }
        }