/** * Clients should invoke this method when they encounter a connectivity failure on a connection * returned by this route selector. */ public void connectFailed(Route failedRoute, IOException failure) { if (failedRoute.getProxy().type() != Proxy.Type.DIRECT && address.getProxySelector() != null) { // Tell the proxy selector when we fail to connect on a fresh connection. address.getProxySelector().connectFailed(uri, failedRoute.getProxy().address(), failure); } routeDatabase.failed(failedRoute); // If the previously returned route's problem was not related to the connection's spec, and the // next route only changes that, we shouldn't even attempt it. This suppresses it in both this // selector and also in the route database. if (!(failure instanceof SSLHandshakeException) && !(failure instanceof SSLProtocolException)) { while (nextSpecIndex < connectionSpecs.size()) { ConnectionSpec connectionSpec = connectionSpecs.get(nextSpecIndex++); final boolean shouldSendTlsFallbackIndicator = shouldSendTlsFallbackIndicator(connectionSpec); Route toSuppress = new Route( address, lastProxy, lastInetSocketAddress, connectionSpec, shouldSendTlsFallbackIndicator); routeDatabase.failed(toSuppress); } } }
/** Prepares the socket addresses to attempt for the current proxy or host. */ private void resetNextInetSocketAddress(Proxy proxy) throws UnknownHostException { // Clear the addresses. Necessary if getAllByName() below throws! inetSocketAddresses = new ArrayList<>(); String socketHost; int socketPort; if (proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.SOCKS) { socketHost = address.getUriHost(); socketPort = getEffectivePort(uri); } else { SocketAddress proxyAddress = proxy.address(); if (!(proxyAddress instanceof InetSocketAddress)) { throw new IllegalArgumentException( "Proxy.address() is not an " + "InetSocketAddress: " + proxyAddress.getClass()); } InetSocketAddress proxySocketAddress = (InetSocketAddress) proxyAddress; socketHost = getHostString(proxySocketAddress); socketPort = proxySocketAddress.getPort(); } // Try each address for best behavior in mixed IPv4/IPv6 environments. for (InetAddress inetAddress : network.resolveInetAddresses(socketHost)) { inetSocketAddresses.add(new InetSocketAddress(inetAddress, socketPort)); } nextInetSocketAddressIndex = 0; }
/** Returns the next proxy to try. May be PROXY.NO_PROXY but never null. */ private Proxy nextProxy() throws IOException { if (!hasNextProxy()) { throw new SocketException( "No route to " + address.getUriHost() + "; exhausted proxy configurations: " + proxies); } Proxy result = proxies.get(nextProxyIndex++); resetNextInetSocketAddress(result); return result; }
private RouteSelector(Address address, URI uri, OkHttpClient client, Request request) { this.address = address; this.uri = uri; this.client = client; this.routeDatabase = Internal.instance.routeDatabase(client); this.network = Internal.instance.network(client); this.request = request; resetNextProxy(uri, address.getProxy()); }
/** Returns the next connection spec to try. */ private ConnectionSpec nextConnectionSpec() throws IOException { if (!hasNextConnectionSpec()) { throw new SocketException( "No route to " + address.getUriHost() + "; exhausted connection specs: " + connectionSpecs); } return connectionSpecs.get(nextSpecIndex++); }
/** Prepares the connection specs to attempt. */ private void resetConnectionSpecs() { connectionSpecs = new ArrayList<>(); List<ConnectionSpec> specs = address.getConnectionSpecs(); for (int i = 0, size = specs.size(); i < size; i++) { ConnectionSpec spec = specs.get(i); if (request.isHttps() == spec.isTls()) { connectionSpecs.add(spec); } } nextSpecIndex = 0; }
/** Returns the next socket address to try. */ private InetSocketAddress nextInetSocketAddress() throws IOException { if (!hasNextInetSocketAddress()) { throw new SocketException( "No route to " + address.getUriHost() + "; exhausted inet socket addresses: " + inetSocketAddresses); } InetSocketAddress result = inetSocketAddresses.get(nextInetSocketAddressIndex++); resetConnectionSpecs(); return result; }