1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2024-06-25 04:44:49 +02:00
Smack/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/jingle_s5b/JingleS5BTransportSession.java

302 lines
11 KiB
Java
Raw Normal View History

2017-06-23 22:48:28 +02:00
/**
*
* Copyright 2017 Paul Schaub
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.jingle.transports.jingle_s5b;
import java.io.IOException;
import java.net.Socket;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.IQ;
2017-06-25 14:25:17 +02:00
import org.jivesoftware.smackx.bytestreams.BytestreamSession;
import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamSession;
2017-06-23 22:48:28 +02:00
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Client;
2017-06-25 14:25:17 +02:00
import org.jivesoftware.smackx.bytestreams.socks5.Socks5ClientForInitiator;
2017-06-23 22:48:28 +02:00
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Utils;
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
import org.jivesoftware.smackx.jingle.JingleManager;
import org.jivesoftware.smackx.jingle.JingleSession;
import org.jivesoftware.smackx.jingle.element.Jingle;
2017-06-24 17:46:03 +02:00
import org.jivesoftware.smackx.jingle.element.JingleContent;
2017-06-23 22:48:28 +02:00
import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidate;
import org.jivesoftware.smackx.jingle.transports.JingleTransportInitiationCallback;
2017-06-25 14:25:17 +02:00
import org.jivesoftware.smackx.jingle.transports.JingleTransportInitiationException;
2017-06-23 22:48:28 +02:00
import org.jivesoftware.smackx.jingle.transports.JingleTransportManager;
import org.jivesoftware.smackx.jingle.transports.JingleTransportSession;
import org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransport;
import org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransportCandidate;
2017-06-25 14:25:17 +02:00
import org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransportInfo;
2017-06-23 22:48:28 +02:00
/**
* LOL.
*/
public class JingleS5BTransportSession extends JingleTransportSession<JingleS5BTransport> {
private static final Logger LOGGER = Logger.getLogger(JingleS5BTransportSession.class.getName());
private final JingleS5BTransportManager transportManager;
2017-06-24 17:46:03 +02:00
private Socket connectedSocket;
2017-06-25 14:25:17 +02:00
private JingleS5BTransportCandidate localUsedCandidate;
private JingleS5BTransportCandidate remoteUsedCandidate;
private JingleTransportInitiationCallback callback;
private boolean remoteError = false;
private boolean localError = false;
2017-06-24 17:46:03 +02:00
2017-06-23 22:48:28 +02:00
public JingleS5BTransportSession(JingleSession jingleSession) {
super(jingleSession);
transportManager = JingleS5BTransportManager.getInstanceFor(jingleSession.getConnection());
}
@Override
public JingleS5BTransport createTransport() {
if (localTransport != null) {
return (JingleS5BTransport) localTransport;
}
return createTransport(JingleManager.randomId(), Bytestream.Mode.tcp);
}
private JingleS5BTransport createTransport(String sid, Bytestream.Mode mode) {
2017-06-25 14:25:17 +02:00
JingleSession jSession = jingleSession.get();
if (jSession == null) {
throw new NullPointerException("Lost reference to JingleSession.");
}
2017-06-23 22:48:28 +02:00
JingleS5BTransport.Builder builder = JingleS5BTransport.getBuilder();
for (Bytestream.StreamHost host : transportManager.getLocalStreamHosts()) {
JingleS5BTransportCandidate candidate = new JingleS5BTransportCandidate(host, 100);
builder.addTransportCandidate(candidate);
}
List<Bytestream.StreamHost> availableStreamHosts = null;
try {
availableStreamHosts = transportManager.getAvailableStreamHosts();
2017-06-25 14:25:17 +02:00
} catch (XMPPException.XMPPErrorException | SmackException.NoResponseException | InterruptedException |
SmackException.NotConnectedException e) {
2017-06-23 22:48:28 +02:00
LOGGER.log(Level.WARNING, "Could not get available StreamHosts: " + e, e);
}
for (Bytestream.StreamHost host : availableStreamHosts != null ?
availableStreamHosts : Collections.<Bytestream.StreamHost>emptyList()) {
JingleS5BTransportCandidate candidate = new JingleS5BTransportCandidate(host, 0);
builder.addTransportCandidate(candidate);
}
builder.setStreamId(sid);
builder.setMode(mode);
2017-06-25 14:25:17 +02:00
builder.setDestinationAddress(Socks5Utils.createDigest(sid, jSession.getLocal(), jSession.getRemote()));
2017-06-23 22:48:28 +02:00
return builder.build();
}
@Override
public void initiateOutgoingSession(JingleTransportInitiationCallback callback) {
2017-06-25 14:25:17 +02:00
this.callback = callback;
initiateSession();
}
@Override
public void initiateIncomingSession(JingleTransportInitiationCallback callback) {
this.callback = callback;
initiateSession();
}
private void initiateSession() {
2017-06-24 17:46:03 +02:00
JingleSession jSession = jingleSession.get();
if (jSession == null) {
throw new NullPointerException("Lost reference to jingleSession.");
}
2017-06-23 22:48:28 +02:00
JingleS5BTransport receivedTransport = (JingleS5BTransport) remoteTransport;
Socket socket = null;
JingleS5BTransportCandidate workedForUs = null;
for (JingleContentTransportCandidate c : receivedTransport.getCandidates()) {
JingleS5BTransportCandidate candidate = (JingleS5BTransportCandidate) c;
Bytestream.StreamHost streamHost = candidate.getStreamHost();
String address = streamHost.getAddress();
try {
Socks5Client socks5Client = new Socks5Client(streamHost, receivedTransport.getDestinationAddress());
socket = socks5Client.getSocket(10 * 1000);
workedForUs = candidate;
} catch (IOException | XMPPException | InterruptedException | TimeoutException | SmackException e) {
LOGGER.log(Level.WARNING, "Could not connect to remotes address " + address + " with dstAddr "
+ receivedTransport.getDestinationAddress());
}
2017-06-24 17:46:03 +02:00
JingleContent content = jSession.getContents().get(0);
Jingle response;
2017-06-23 22:48:28 +02:00
if (socket != null) {
2017-06-24 17:46:03 +02:00
connectedSocket = socket;
2017-06-25 14:25:17 +02:00
localUsedCandidate = workedForUs;
2017-06-23 22:48:28 +02:00
2017-06-24 17:46:03 +02:00
response = transportManager.createCandidateUsed(jSession.getRemote(),
jSession.getSessionId(), content.getSenders(), content.getCreator(),
2017-06-25 14:25:17 +02:00
content.getName(), receivedTransport.getStreamId(), localUsedCandidate.getCandidateId());
2017-06-24 17:46:03 +02:00
} else {
2017-06-25 14:25:17 +02:00
localError = true;
2017-06-24 17:46:03 +02:00
response = transportManager.createCandidateError(jSession.getRemote(),
jSession.getSessionId(), content.getSenders(), content.getCreator(),
content.getName(), receivedTransport.getStreamId());
}
try {
jSession.getConnection().sendStanza(response);
} catch (SmackException.NotConnectedException | InterruptedException e) {
LOGGER.log(Level.WARNING, "Could not send candidate-used.", e);
2017-06-23 22:48:28 +02:00
}
2017-06-25 14:25:17 +02:00
closeIfBothSidesFailed();
2017-06-23 22:48:28 +02:00
}
}
2017-06-25 14:25:17 +02:00
private boolean closeIfBothSidesFailed() {
JingleSession jSession = jingleSession.get();
if (jSession != null) {
if (localError && remoteError) {
callback.onException(new JingleTransportInitiationException.CandidateError());
return true;
}
}
}
private JingleS5BTransportCandidate determineUsedCandidate() {
if (localUsedCandidate == null && remoteUsedCandidate == null) {
return null;
}
if (remoteUsedCandidate == null) {
return localUsedCandidate;
}
2017-06-23 22:48:28 +02:00
2017-06-25 14:25:17 +02:00
if (localUsedCandidate == null) {
return remoteUsedCandidate;
}
if (localUsedCandidate.getPriority() > remoteUsedCandidate.getPriority()) {
return localUsedCandidate;
}
if (localUsedCandidate.getPriority() < remoteUsedCandidate.getPriority()) {
return remoteUsedCandidate;
}
return jingleSession.get().isInitiator() ? localUsedCandidate : remoteUsedCandidate;
}
public IQ handleCandidateUsed(Jingle candidateUsed) {
JingleS5BTransportInfo info = (JingleS5BTransportInfo) candidateUsed.getContents().get(0)
.getJingleTransport().getInfos().get(0);
String candidateId = ((JingleS5BTransportInfo.CandidateUsed) info).getCandidateId();
for (JingleContentTransportCandidate c : localTransport.getCandidates()) {
JingleS5BTransportCandidate candidate = (JingleS5BTransportCandidate) c;
if (candidate.getCandidateId().equals(candidateId)) {
remoteUsedCandidate = candidate;
break;
}
}
if (remoteUsedCandidate == null) {
callback.onException(new Exception("Unknown candidate"));
return IQ.createResultIQ(candidateUsed);
}
if (localUsedCandidate != null) {
JingleS5BTransportCandidate used = determineUsedCandidate();
// Our candidate is nominated.
if (used == remoteUsedCandidate) {
if (used.getType() == JingleS5BTransportCandidate.Type.proxy) {
}
callback.onSessionInitiated();
}
// Remotes candidate is nominated.
else {
if (connectedSocket != null) {
callback.onSessionInitiated(new Socks5BytestreamSession(connectedSocket,
used.getJid().asBareJid().equals(jingleSession.get().getRemote().asBareJid())));
} else {
throw new AssertionError("Connected socket is null.");
}
}
}
return IQ.createResultIQ(candidateUsed);
2017-06-23 22:48:28 +02:00
}
@Override
public String getNamespace() {
return transportManager.getNamespace();
}
@Override
public IQ handleTransportInfo(Jingle transportInfo) {
2017-06-25 14:25:17 +02:00
JingleS5BTransport transport = (JingleS5BTransport) transportInfo.getContents().get(0).getJingleTransport();
JingleS5BTransportInfo info = (JingleS5BTransportInfo) transport.getInfos().get(0);
if (info != null) {
switch (info.getElementName()) {
case JingleS5BTransportInfo.CandidateUsed.ELEMENT:
return handleCandidateUsed(transportInfo);
case JingleS5BTransportInfo.CandidateActivated.ELEMENT:
case JingleS5BTransportInfo.CandidateError.ELEMENT:
remoteError = true;
closeIfBothSidesFailed();
if (localUsedCandidate.getType() != JingleS5BTransportCandidate.Type.proxy) {
//TODO: Connect
} else {
}
break;
case JingleS5BTransportInfo.ProxyError.ELEMENT:
}
}
2017-06-23 22:48:28 +02:00
}
@Override
public JingleTransportManager<JingleS5BTransport> transportManager() {
return JingleS5BTransportManager.getInstanceFor(jingleSession.get().getConnection());
}
}