public Socks5BytestreamSession establishSession(String targetJID, String sessionID)
throws XMPPException, IOException, InterruptedException {
// check if target supports SOCKS5 Bytestream
if (!supportsSocks5(targetJID)) {
throw new XMPPException(targetJID + " doesn't support SOCKS5 Bytestream");
}
// determine SOCKS5 proxies from XMPP-server
List<String> proxies = determineProxies();
// determine address and port of each proxy
List<StreamHost> streamHosts = determineStreamHostInfos(proxies);
// compute digest
String digest = Socks5Utils.createDigest(sessionID, this.connection.getUser(), targetJID);
if (streamHosts.isEmpty()) {
throw new XMPPException("no SOCKS5 proxies available");
}
// prioritize last working SOCKS5 proxy if exists
if (this.proxyPrioritizationEnabled && this.lastWorkingProxy != null) {
StreamHost selectedStreamHost = null;
for (StreamHost streamHost : streamHosts) {
if (streamHost.getJID().equals(this.lastWorkingProxy)) {
selectedStreamHost = streamHost;
break;
}
}
if (selectedStreamHost != null) {
streamHosts.remove(selectedStreamHost);
streamHosts.add(0, selectedStreamHost);
}
}
Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy();
try {
// add transfer digest to local proxy to make transfer valid
socks5Proxy.addTransfer(digest);
// create initiation packet
Bytestream initiation = createBytestreamInitiation(sessionID, targetJID, streamHosts);
// send initiation packet
Packet response = SyncPacketSend.getReply(this.connection, initiation,
getTargetResponseTimeout());
// extract used stream host from response
StreamHostUsed streamHostUsed = ((Bytestream) response).getUsedHost();
StreamHost usedStreamHost = initiation.getStreamHost(streamHostUsed.getJID());
if (usedStreamHost == null) {
throw new XMPPException("Remote user responded with unknown host");
}
// build SOCKS5 client
Socks5Client socks5Client = new Socks5ClientForInitiator(usedStreamHost, digest,
this.connection, sessionID, targetJID);