IQ result = xmppSession.query(new IQ(target, IQ.Type.SET, new Socks5ByteStream(sessionId, streamHosts, hash)));
// 5.3.3 Target Acknowledges Bytestream
// 6.3.3 Target Acknowledges Bytestream
Socks5ByteStream socks5ByteStream = result.getExtension(Socks5ByteStream.class);
StreamHost usedStreamHost = null;
for (StreamHost streamHost : streamHosts) {
if (socks5ByteStream.getStreamHostUsed() != null && socks5ByteStream.getStreamHostUsed().equals(streamHost.getJid())) {
usedStreamHost = streamHost;
break;
}
}
if (usedStreamHost == null) {
throw new IOException("Target did not respond with a stream host.");
}
Socket socket;
if (!usedStreamHost.getJid().equals(requester)) {
// 6.3.4 Requester Establishes SOCKS5 Connection with StreamHost
socket = new Socket();
socket.connect(new InetSocketAddress(usedStreamHost.getHost(), usedStreamHost.getPort()));
Socks5Protocol.establishClientConnection(socket, hash, 0);
// 6.3.5 Activation of Bytestream
xmppSession.query(new IQ(usedStreamHost.getJid(), IQ.Type.SET, Socks5ByteStream.activate(sessionId, target)));
} else {
socket = localSocks5Server.getSocket(hash);
}
if (socket == null) {
throw new IOException("Not connected to stream host");
}
return new S5bSession(sessionId, socket, usedStreamHost.getJid());
} finally {
localSocks5Server.removeConnection(hash);
}
}