// // Binds a socket to a proxy identified by provided address // public async Task BindAsync(SocketAddress endpoint, CancellationToken ct) { if (_cleanedUp) { throw new ObjectDisposedException(this.GetType().FullName); } if (endpoint == null) { throw new ArgumentNullException(nameof(endpoint)); } if (IsListening) { throw new InvalidOperationException("Socket is listening"); } try { await _internal.BindAsync(endpoint, ct).ConfigureAwait(false); IsBound = true; } catch (OperationCanceledException) { throw; } catch (Exception e) { throw SocketException.Create($"Exception binding to {endpoint.ToString()}", e); } }
// // Opens the socket and links as active // public async Task ConnectAsync(SocketAddress endpoint, CancellationToken ct) { if (_cleanedUp) { throw new ObjectDisposedException(this.GetType().FullName); } if (endpoint == null) { throw new ArgumentNullException("endpoint"); } if (IsListening) { throw new InvalidOperationException("Socket is listening"); } try { await _internal.ConnectAsync(endpoint, ct).ConfigureAwait(false); Connected = true; IsBound = true; } catch (Exception e) when(!(e is SocketException) && !(e is OperationCanceledException)) { throw new SocketException($"Exception connecting to {endpoint.ToString()}", e, e.GetSocketError()); } }
/// <summary> /// Collate a list of entries into one big host entry /// </summary> /// <param name="address"></param> /// <param name="entries"></param> /// <returns></returns> internal static DnsHostEntry ToEntry(SocketAddress address, IEnumerable <DnsHostEntry> entries) { if (entries == null || !entries.Any()) { return(new DnsHostEntry { HostName = address.ToString(), Aliases = new string[0], AddressList = new SocketAddress[] { address } }); } string hostName = string.Empty; var addressList = new List <SocketAddress>(); var aliases = new List <string>(); foreach (var entry in entries) { hostName = entry.HostName; if (entry.AddressList != null) { addressList.AddRange(entry.AddressList); } if (entry.Aliases != null) { aliases.AddRange(entry.Aliases); } } return(new DnsHostEntry { HostName = hostName, Aliases = aliases.ToArray(), AddressList = addressList.ToArray() }); }
// // Without cancellation token // public async Task BindAsync(SocketAddress endpoint) { var cts = new CancellationTokenSource(ConnectTimeout); try { await BindAsync(endpoint, cts.Token).ConfigureAwait(false); } catch (OperationCanceledException) when(cts.IsCancellationRequested) { throw new TimeoutException( $"Timeout after {ConnectTimeout.ToString()} binding to {endpoint.ToString()}."); } }
/// <summary> /// Match record against address /// </summary> /// <param name="record"></param> /// <param name="address"></param> /// <param name="type"></param> /// <returns></returns> public static bool Matches(this INameRecord record, SocketAddress address, NameRecordType type) { if (address.Family == AddressFamily.Collection) { return(Matches(record, (SocketAddressCollection)address, type)); } if (Matches(record, address.ToString(), type)) { return(true); } if (address.Family == AddressFamily.InterNetworkV6) { return(Matches(record, Reference.FromSocketAddress((Inet6SocketAddress)address), type)); } return(false); }
/// <summary> /// Connect to a target on first of bound proxies, or use ping based dynamic lookup /// </summary> /// <param name="address"></param> /// <param name="ct"></param> /// <returns></returns> public override async Task ConnectAsync(SocketAddress address, CancellationToken ct) { if (address.Family == AddressFamily.Bound) { // Unwrap proxy and connect address. If not bound, use local address to bind to. if (_bindList == null) { await BindAsync(((BoundSocketAddress)address).LocalAddress, ct); } address = ((BoundSocketAddress)address).RemoteAddress; } // Get the named host from the registry if it exists - there should only be one... Host = null; var hostList = await Provider.NameService.LookupAsync( address.ToString(), NameRecordType.Host, ct).ConfigureAwait(false); foreach (var host in hostList) { Host = host; break; } // If there is no host in the registry, create a fake host record for this address if (Host == null) { Host = new NameRecord(NameRecordType.Host, address.ToString()); } else if (!Host.Name.Equals(address.ToString(), StringComparison.CurrentCultureIgnoreCase)) { // Translate the address to host address address = new ProxySocketAddress(Host.Name); } // Set bind list before connecting if it is not already set during Bind bool autoBind = _bindList == null; if (autoBind) { var bindList = new HashSet <INameRecord>(); foreach (var proxyRef in Host.References) { var results = await Provider.NameService.LookupAsync( proxyRef, NameRecordType.Proxy, ct).ConfigureAwait(false); bindList.AddRange(results); } _bindList = bindList.Any() ? bindList : null; } bool connected = false; if (_bindList != null) { // Try to connect through each proxy in the bind list foreach (var proxy in _bindList) { connected = await ConnectAsync(address, proxy, ct).ConfigureAwait(false); if (connected) { break; } } // If there was a bind list and we could not connect through it, throw if (!connected && !autoBind) { throw new SocketException(SocketError.NoHost); } _bindList = null; } if (!connected) { await PingAsync(address, async (response, proxy, ct2) => { if (connected) { return(Disposition.Done); } if (response.Error == (int)SocketError.Success) { try { connected = await ConnectAsync(address, proxy, ct).ConfigureAwait(false); } catch (Exception) { return(Disposition.Retry); } } return(connected ? Disposition.Done : Disposition.Continue); }, (ex) => { if (!connected) { throw new SocketException( "Could not link socket on proxy", ex, SocketError.NoHost); } }, ct).ConfigureAwait(false); ct.ThrowIfCancellationRequested(); } await Provider.NameService.AddOrUpdateAsync(Host, ct).ConfigureAwait(false); }