/** * Returns the response to the SOCKS5 Bytestream request containing the SOCKS5 proxy used. * * @param selectedHost the used SOCKS5 proxy * @return the response to the SOCKS5 Bytestream request */ private Bytestream createUsedHostResponse(StreamHost selectedHost) { Bytestream response = new Bytestream(this.bytestreamRequest.getSessionID()); response.setTo(this.bytestreamRequest.getFrom()); response.setType(IQ.Type.RESULT); response.setPacketID(this.bytestreamRequest.getPacketID()); response.setUsedHost(selectedHost.getJID()); return response; }
/** * Accepts the SOCKS5 Bytestream initialization request and returns the socket to send/receive * data. * * <p>Before accepting the SOCKS5 Bytestream request you can set timeouts by invoking {@link * #setTotalConnectTimeout(int)} and {@link #setMinimumConnectTimeout(int)}. * * @return the socket to send/receive data * @throws XMPPException if connection to all SOCKS5 proxies failed or if stream is invalid. * @throws InterruptedException if the current thread was interrupted while waiting */ public Socks5BytestreamSession accept() throws XMPPException, InterruptedException { Collection<StreamHost> streamHosts = this.bytestreamRequest.getStreamHosts(); // throw exceptions if request contains no stream hosts if (streamHosts.size() == 0) { cancelRequest(); } StreamHost selectedHost = null; Socket socket = null; String digest = Socks5Utils.createDigest( this.bytestreamRequest.getSessionID(), this.bytestreamRequest.getFrom(), this.manager.getConnection().getUser()); /* * determine timeout for each connection attempt; each SOCKS5 proxy has the same amount of * time so that the first does not consume the whole timeout */ int timeout = Math.max(getTotalConnectTimeout() / streamHosts.size(), getMinimumConnectTimeout()); for (StreamHost streamHost : streamHosts) { String address = streamHost.getAddress() + ":" + streamHost.getPort(); // check to see if this address has been blacklisted int failures = getConnectionFailures(address); if (CONNECTION_FAILURE_THRESHOLD > 0 && failures >= CONNECTION_FAILURE_THRESHOLD) { continue; } // establish socket try { // build SOCKS5 client final Socks5Client socks5Client = new Socks5Client(streamHost, digest); // connect to SOCKS5 proxy with a timeout socket = socks5Client.getSocket(timeout); // set selected host selectedHost = streamHost; break; } catch (TimeoutException e) { incrementConnectionFailures(address); } catch (IOException e) { incrementConnectionFailures(address); } catch (XMPPException e) { incrementConnectionFailures(address); } } // throw exception if connecting to all SOCKS5 proxies failed if (selectedHost == null || socket == null) { cancelRequest(); } // send used-host confirmation Bytestream response = createUsedHostResponse(selectedHost); this.manager.getConnection().sendPacket(response); return new Socks5BytestreamSession( socket, selectedHost.getJID().equals(this.bytestreamRequest.getFrom())); }