/// <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); }
/// <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); }
/// <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); }
/// <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); } }