mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-24 04:52:05 +01:00
Fix all errors in transports
This commit is contained in:
parent
e28bfa1a64
commit
e967849e5a
8 changed files with 139 additions and 241 deletions
|
@ -232,7 +232,7 @@ public class JingleSession {
|
||||||
|
|
||||||
JingleTransport<?> transport = entry.getValue().getTransport();
|
JingleTransport<?> transport = entry.getValue().getTransport();
|
||||||
JingleContentTransportInfoElement info = entry.getKey().getTransport().getInfo();
|
JingleContentTransportInfoElement info = entry.getKey().getTransport().getInfo();
|
||||||
transport.handleTransportInfo(info);
|
transport.handleTransportInfo(info, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
return IQ.createResultIQ(request);
|
return IQ.createResultIQ(request);
|
||||||
|
@ -378,6 +378,14 @@ public class JingleSession {
|
||||||
return role == Role.initiator ? initiator : responder;
|
return role == Role.initiator ? initiator : responder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isInitiator() {
|
||||||
|
return role == Role.initiator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isResponder() {
|
||||||
|
return role == Role.responder;
|
||||||
|
}
|
||||||
|
|
||||||
public String getSessionId() {
|
public String getSessionId() {
|
||||||
return sessionId;
|
return sessionId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.util.List;
|
||||||
import org.jivesoftware.smack.SmackException;
|
import org.jivesoftware.smack.SmackException;
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement;
|
import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.JingleElement;
|
||||||
import org.jivesoftware.smackx.jingle.transport.BytestreamSessionEstablishedListener;
|
import org.jivesoftware.smackx.jingle.transport.BytestreamSessionEstablishedListener;
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContentTransportInfoElement;
|
import org.jivesoftware.smackx.jingle.element.JingleContentTransportInfoElement;
|
||||||
|
|
||||||
|
@ -90,7 +91,7 @@ public abstract class JingleTransport<D extends JingleContentTransportElement> {
|
||||||
return peersProposal;
|
return peersProposal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void handleTransportInfo(JingleContentTransportInfoElement info);
|
public abstract void handleTransportInfo(JingleContentTransportInfoElement info, JingleElement wrapping);
|
||||||
|
|
||||||
public void setParent(JingleContent parent) {
|
public void setParent(JingleContent parent) {
|
||||||
if (this.parent != parent) {
|
if (this.parent != parent) {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.jivesoftware.smackx.bytestreams.BytestreamListener;
|
||||||
import org.jivesoftware.smackx.bytestreams.BytestreamRequest;
|
import org.jivesoftware.smackx.bytestreams.BytestreamRequest;
|
||||||
import org.jivesoftware.smackx.bytestreams.BytestreamSession;
|
import org.jivesoftware.smackx.bytestreams.BytestreamSession;
|
||||||
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
|
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.JingleElement;
|
||||||
import org.jivesoftware.smackx.jingle.internal.JingleTransport;
|
import org.jivesoftware.smackx.jingle.internal.JingleTransport;
|
||||||
import org.jivesoftware.smackx.jingle.internal.JingleTransportCandidate;
|
import org.jivesoftware.smackx.jingle.internal.JingleTransportCandidate;
|
||||||
import org.jivesoftware.smackx.jingle.transport.BytestreamSessionEstablishedListener;
|
import org.jivesoftware.smackx.jingle.transport.BytestreamSessionEstablishedListener;
|
||||||
|
@ -111,7 +112,7 @@ public class JingleIBBTransport extends JingleTransport<JingleIBBTransportElemen
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleTransportInfo(JingleContentTransportInfoElement info) {
|
public void handleTransportInfo(JingleContentTransportInfoElement info, JingleElement wrapping) {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,6 @@ public class JingleIBBTransportManager extends Manager implements JingleTranspor
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(JingleTransportManager manager) {
|
public int compareTo(JingleTransportManager manager) {
|
||||||
return 0;
|
return -1; // We are literally the worst.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,21 +21,28 @@ import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
import org.jivesoftware.smack.SmackException;
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
import org.jivesoftware.smack.XMPPException;
|
import org.jivesoftware.smack.XMPPException;
|
||||||
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
|
import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamSession;
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy;
|
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy;
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Utils;
|
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Utils;
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
|
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
|
||||||
|
import org.jivesoftware.smackx.jingle.JingleManager;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.JingleContentTransportInfoElement;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.JingleElement;
|
||||||
|
import org.jivesoftware.smackx.jingle.internal.JingleContent;
|
||||||
|
import org.jivesoftware.smackx.jingle.internal.JingleSession;
|
||||||
|
import org.jivesoftware.smackx.jingle.internal.JingleTransport;
|
||||||
|
import org.jivesoftware.smackx.jingle.internal.JingleTransportCandidate;
|
||||||
import org.jivesoftware.smackx.jingle.transport.BytestreamSessionEstablishedListener;
|
import org.jivesoftware.smackx.jingle.transport.BytestreamSessionEstablishedListener;
|
||||||
import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement;
|
import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement;
|
||||||
import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportElement;
|
import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportElement;
|
||||||
import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportInfoElement;
|
import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportInfoElement;
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContentTransportInfoElement;
|
|
||||||
import org.jivesoftware.smackx.jingle.internal.JingleContent;
|
|
||||||
import org.jivesoftware.smackx.jingle.internal.JingleTransport;
|
|
||||||
import org.jivesoftware.smackx.jingle.internal.JingleTransportCandidate;
|
|
||||||
|
|
||||||
import org.jxmpp.jid.FullJid;
|
import org.jxmpp.jid.FullJid;
|
||||||
|
|
||||||
|
@ -44,6 +51,8 @@ import org.jxmpp.jid.FullJid;
|
||||||
*/
|
*/
|
||||||
public class JingleS5BTransport extends JingleTransport<JingleS5BTransportElement> {
|
public class JingleS5BTransport extends JingleTransport<JingleS5BTransportElement> {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(JingleS5BTransport.class.getName());
|
||||||
|
|
||||||
public static final String NAMESPACE_V1 = "urn:xmpp:jingle:transports:s5b:1";
|
public static final String NAMESPACE_V1 = "urn:xmpp:jingle:transports:s5b:1";
|
||||||
public static final String NAMESPACE = NAMESPACE_V1;
|
public static final String NAMESPACE = NAMESPACE_V1;
|
||||||
|
|
||||||
|
@ -134,9 +143,15 @@ public class JingleS5BTransport extends JingleTransport<JingleS5BTransportElemen
|
||||||
|
|
||||||
if (selectedCandidate == CANDIDATE_FAILURE) {
|
if (selectedCandidate == CANDIDATE_FAILURE) {
|
||||||
connection.createStanzaCollectorAndSend(transportManager.createCandidateError(this));
|
connection.createStanzaCollectorAndSend(transportManager.createCandidateError(this));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (selectedCandidate == null) {
|
||||||
|
throw new AssertionError("MUST NOT BE NULL.");
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.createStanzaCollectorAndSend(transportManager.createCandidateUsed(this, selectedCandidate));
|
||||||
|
//connectIfReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
public JingleS5BTransportCandidate connectToCandidates(int timeout) {
|
public JingleS5BTransportCandidate connectToCandidates(int timeout) {
|
||||||
|
@ -153,12 +168,105 @@ public class JingleS5BTransport extends JingleTransport<JingleS5BTransportElemen
|
||||||
return CANDIDATE_FAILURE;
|
return CANDIDATE_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void connectIfReady() {
|
||||||
|
JingleS5BTransportManager jingleS5BTransportManager = JingleS5BTransportManager.getInstanceFor(getParent().getParent().getJingleManager().getConnection());
|
||||||
|
JingleS5BTransport peers = (JingleS5BTransport) getPeersProposal();
|
||||||
|
JingleSession session = getParent().getParent();
|
||||||
|
|
||||||
|
if (getSelectedCandidate() == null || peers.getSelectedCandidate() == null) {
|
||||||
|
// Not yet ready if we or peer did not yet decide on a candidate.
|
||||||
|
LOGGER.log(Level.INFO, "Not ready.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getSelectedCandidate() == CANDIDATE_FAILURE && peers.getSelectedCandidate() == CANDIDATE_FAILURE) {
|
||||||
|
LOGGER.log(Level.INFO, "Failure.");
|
||||||
|
//jingleSession.onTransportMethodFailed(getNamespace());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.log(Level.INFO, "Ready.");
|
||||||
|
|
||||||
|
//Determine nominated candidate.
|
||||||
|
JingleS5BTransportCandidate nominated;
|
||||||
|
if (getSelectedCandidate() != CANDIDATE_FAILURE && peers.getSelectedCandidate() != CANDIDATE_FAILURE) {
|
||||||
|
if (getSelectedCandidate().getPriority() > peers.getSelectedCandidate().getPriority()) {
|
||||||
|
nominated = getSelectedCandidate();
|
||||||
|
} else if (getSelectedCandidate().getPriority() < peers.getSelectedCandidate().getPriority()) {
|
||||||
|
nominated = peers.getSelectedCandidate();
|
||||||
|
} else {
|
||||||
|
nominated = getParent().getParent().isInitiator() ? getSelectedCandidate() : peers.getSelectedCandidate();
|
||||||
|
}
|
||||||
|
} else if (getSelectedCandidate() != CANDIDATE_FAILURE) {
|
||||||
|
nominated = getSelectedCandidate();
|
||||||
|
} else {
|
||||||
|
nominated = peers.getSelectedCandidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nominated == peers.getSelectedCandidate()) {
|
||||||
|
LOGGER.log(Level.INFO, "Their choice, so our proposed candidate is used.");
|
||||||
|
boolean isProxy = nominated.getType() == JingleS5BTransportCandidateElement.Type.proxy;
|
||||||
|
try {
|
||||||
|
nominated = nominated.connect(MAX_TIMEOUT);
|
||||||
|
} catch (InterruptedException | IOException | XMPPException | SmackException | TimeoutException e) {
|
||||||
|
LOGGER.log(Level.INFO, "Could not connect to our candidate.", e);
|
||||||
|
//TODO: Proxy-Error
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isProxy) {
|
||||||
|
LOGGER.log(Level.INFO, "Is external proxy. Activate it.");
|
||||||
|
Bytestream activate = new Bytestream(getSid());
|
||||||
|
activate.setMode(null);
|
||||||
|
activate.setType(IQ.Type.set);
|
||||||
|
activate.setTo(nominated.getStreamHost().getJID());
|
||||||
|
activate.setToActivate(getParent().getParent().getPeer());
|
||||||
|
activate.setFrom(getParent().getParent().getOurJid());
|
||||||
|
|
||||||
|
try {
|
||||||
|
getParent().getParent().getJingleManager().getConnection().createStanzaCollectorAndSend(activate).nextResultOrThrow();
|
||||||
|
} catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not activate proxy.", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.log(Level.INFO, "Send candidate-activate.");
|
||||||
|
JingleElement candidateActivate = jingleS5BTransportManager.createCandidateActivated((JingleS5BTransport) nominated.getParent(), nominated);
|
||||||
|
|
||||||
|
try {
|
||||||
|
session.getJingleManager().getConnection().createStanzaCollectorAndSend(candidateActivate)
|
||||||
|
.nextResultOrThrow();
|
||||||
|
} catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not send candidate-activated", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.log(Level.INFO, "Start transmission.");
|
||||||
|
Socks5BytestreamSession bs = new Socks5BytestreamSession(nominated.getSocket(), !isProxy);
|
||||||
|
//callback.onSessionInitiated(bs);
|
||||||
|
|
||||||
|
}
|
||||||
|
//Our choice
|
||||||
|
else {
|
||||||
|
LOGGER.log(Level.INFO, "Our choice, so their candidate was used.");
|
||||||
|
boolean isProxy = nominated.getType() == JingleS5BTransportCandidateElement.Type.proxy;
|
||||||
|
if (!isProxy) {
|
||||||
|
LOGGER.log(Level.INFO, "Direct connection.");
|
||||||
|
Socks5BytestreamSession bs = new Socks5BytestreamSession(nominated.getSocket(), true);
|
||||||
|
//callback.onSessionInitiated(bs);
|
||||||
|
} else {
|
||||||
|
LOGGER.log(Level.INFO, "Our choice was their external proxy. wait for candidate-activate.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleTransportInfo(JingleContentTransportInfoElement info) {
|
public void handleTransportInfo(JingleContentTransportInfoElement info, JingleElement wrapping) {
|
||||||
switch (info.getElementName()) {
|
switch (info.getElementName()) {
|
||||||
|
|
||||||
case JingleS5BTransportInfoElement.CandidateUsed.ELEMENT:
|
case JingleS5BTransportInfoElement.CandidateUsed.ELEMENT:
|
||||||
handleCandidateUsed((JingleS5BTransportInfoElement) info);
|
handleCandidateUsed((JingleS5BTransportInfoElement) info, wrapping);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case JingleS5BTransportInfoElement.CandidateActivated.ELEMENT:
|
case JingleS5BTransportInfoElement.CandidateActivated.ELEMENT:
|
||||||
|
@ -178,13 +286,19 @@ public class JingleS5BTransport extends JingleTransport<JingleS5BTransportElemen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleCandidateUsed(JingleS5BTransportInfoElement info) {
|
private void handleCandidateUsed(JingleS5BTransportInfoElement info, JingleElement wrapping) {
|
||||||
|
JingleManager jingleManager = getParent().getParent().getJingleManager();
|
||||||
String candidateId = ((JingleS5BTransportInfoElement.CandidateUsed) info).getCandidateId();
|
String candidateId = ((JingleS5BTransportInfoElement.CandidateUsed) info).getCandidateId();
|
||||||
|
|
||||||
JingleS5BTransport peers = (JingleS5BTransport) getPeersProposal();
|
JingleS5BTransport peers = (JingleS5BTransport) getPeersProposal();
|
||||||
|
|
||||||
|
// Received second candidate-used -> out-of-order!
|
||||||
if (peers.getSelectedCandidate() != null) {
|
if (peers.getSelectedCandidate() != null) {
|
||||||
//TODO: Alert! We already received one candidateUsed previously!
|
try {
|
||||||
|
jingleManager.getConnection().createStanzaCollectorAndSend(JingleElement.createJingleErrorOutOfOrder(wrapping));
|
||||||
|
} catch (SmackException.NotConnectedException | InterruptedException e) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Could not respond to candidate-used transport-info: " + e, e);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.util.ArrayList;
|
||||||
import org.jivesoftware.smackx.jingle.adapter.JingleTransportAdapter;
|
import org.jivesoftware.smackx.jingle.adapter.JingleTransportAdapter;
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidateElement;
|
import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidateElement;
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement;
|
import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement;
|
||||||
|
import org.jivesoftware.smackx.jingle.internal.JingleTransportCandidate;
|
||||||
import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement;
|
import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement;
|
||||||
import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportElement;
|
import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportElement;
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@ public class JingleS5BTransportAdapter implements JingleTransportAdapter<JingleS
|
||||||
@Override
|
@Override
|
||||||
public JingleS5BTransport transportFromElement(JingleContentTransportElement element) {
|
public JingleS5BTransport transportFromElement(JingleContentTransportElement element) {
|
||||||
JingleS5BTransportElement s5b = (JingleS5BTransportElement) element;
|
JingleS5BTransportElement s5b = (JingleS5BTransportElement) element;
|
||||||
ArrayList<JingleS5BTransportCandidate> candidates = new ArrayList<>();
|
ArrayList<JingleTransportCandidate<?>> candidates = new ArrayList<>();
|
||||||
|
|
||||||
for (JingleContentTransportCandidateElement e : element.getCandidates()) {
|
for (JingleContentTransportCandidateElement e : element.getCandidates()) {
|
||||||
candidates.add(JingleS5BTransportCandidate.fromElement((JingleS5BTransportCandidateElement) e));
|
candidates.add(JingleS5BTransportCandidate.fromElement((JingleS5BTransportCandidateElement) e));
|
||||||
|
|
|
@ -275,6 +275,6 @@ public final class JingleS5BTransportManager extends Manager implements JingleTr
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(JingleTransportManager manager) {
|
public int compareTo(JingleTransportManager manager) {
|
||||||
return 0;
|
return 1; // We are #1!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,227 +0,0 @@
|
||||||
/**
|
|
||||||
*
|
|
||||||
* 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.transport.legacy;
|
|
||||||
|
|
||||||
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;
|
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamSession;
|
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Client;
|
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.Socks5ClientForInitiator;
|
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy;
|
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Utils;
|
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
|
|
||||||
import org.jivesoftware.smackx.jingle.transports.JingleTransportInitiationCallback;
|
|
||||||
import org.jivesoftware.smackx.jingle.transports.JingleTransportSession;
|
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContentElement;
|
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidateElement;
|
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement;
|
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleElement;
|
|
||||||
import org.jivesoftware.smackx.jingle.transport.jingle_s5b.JingleS5BTransportManager;
|
|
||||||
import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportCandidateElement;
|
|
||||||
import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportElement;
|
|
||||||
import org.jivesoftware.smackx.jingle.transport.jingle_s5b.element.JingleS5BTransportInfoElement;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handler that handles Jingle Socks5Bytestream transports (XEP-0260).
|
|
||||||
*/
|
|
||||||
public class JingleS5BTransportSession extends JingleTransportSession<JingleS5BTransportElement> {
|
|
||||||
|
|
||||||
|
|
||||||
private void initiateSession() {
|
|
||||||
Socks5Proxy.getSocks5Proxy().addTransfer(createTransport().getDestinationAddress());
|
|
||||||
JingleContentElement content = jingleSession.getContents().get(0);
|
|
||||||
UsedCandidate usedCandidate = chooseFromProposedCandidates(theirProposal);
|
|
||||||
if (usedCandidate == null) {
|
|
||||||
ourChoice = CANDIDATE_FAILURE;
|
|
||||||
JingleElement candidateError = transportManager().createCandidateError(
|
|
||||||
jingleSession.getRemote(), jingleSession.getInitiator(), jingleSession.getSessionId(),
|
|
||||||
content.getSenders(), content.getCreator(), content.getName(), theirProposal.getStreamId());
|
|
||||||
try {
|
|
||||||
jingleSession.getConnection().sendStanza(candidateError);
|
|
||||||
} catch (SmackException.NotConnectedException | InterruptedException e) {
|
|
||||||
LOGGER.log(Level.WARNING, "Could not send candidate-error.", e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ourChoice = usedCandidate;
|
|
||||||
JingleElement jingle = transportManager().createCandidateUsed(jingleSession.getRemote(), jingleSession.getInitiator(), jingleSession.getSessionId(),
|
|
||||||
content.getSenders(), content.getCreator(), content.getName(), theirProposal.getStreamId(), ourChoice.candidate.getCandidateId());
|
|
||||||
try {
|
|
||||||
jingleSession.getConnection().createStanzaCollectorAndSend(jingle)
|
|
||||||
.nextResultOrThrow();
|
|
||||||
} catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) {
|
|
||||||
LOGGER.log(Level.WARNING, "Could not send candidate-used.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
connectIfReady();
|
|
||||||
}
|
|
||||||
|
|
||||||
private UsedCandidate chooseFromProposedCandidates(JingleS5BTransportElement proposal) {
|
|
||||||
for (JingleContentTransportCandidateElement c : proposal.getCandidates()) {
|
|
||||||
JingleS5BTransportCandidateElement candidate = (JingleS5BTransportCandidateElement) c;
|
|
||||||
|
|
||||||
try {
|
|
||||||
return connectToTheirCandidate(candidate);
|
|
||||||
} catch (InterruptedException | TimeoutException | XMPPException | SmackException | IOException e) {
|
|
||||||
LOGGER.log(Level.WARNING, "Could not connect to " + candidate.getHost(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOGGER.log(Level.WARNING, "Failed to connect to any candidate.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ handleCandidateUsed(JingleElement jingle) {
|
|
||||||
JingleS5BTransportInfoElement info = (JingleS5BTransportInfoElement) jingle.getContents().get(0).getTransport().getInfo();
|
|
||||||
String candidateId = ((JingleS5BTransportInfoElement.CandidateUsed) info).getCandidateId();
|
|
||||||
theirChoice = new UsedCandidate(ourProposal, ourProposal.getCandidate(candidateId), null);
|
|
||||||
|
|
||||||
if (theirChoice.candidate == null) {
|
|
||||||
/*
|
|
||||||
TODO: Booooooh illegal candidateId!! Go home!!!!11elf
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
connectIfReady();
|
|
||||||
|
|
||||||
return IQ.createResultIQ(jingle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ handleCandidateActivate(JingleElement jingle) {
|
|
||||||
LOGGER.log(Level.INFO, "handleCandidateActivate");
|
|
||||||
Socks5BytestreamSession bs = new Socks5BytestreamSession(ourChoice.socket,
|
|
||||||
ourChoice.candidate.getJid().asBareJid().equals(jingleSession.getRemote().asBareJid()));
|
|
||||||
callback.onSessionInitiated(bs);
|
|
||||||
return IQ.createResultIQ(jingle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ handleCandidateError(JingleElement jingle) {
|
|
||||||
theirChoice = CANDIDATE_FAILURE;
|
|
||||||
connectIfReady();
|
|
||||||
return IQ.createResultIQ(jingle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ handleProxyError(JingleElement jingle) {
|
|
||||||
//TODO
|
|
||||||
return IQ.createResultIQ(jingle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine, which candidate (ours/theirs) is the nominated one.
|
|
||||||
* Connect to this candidate. If it is a proxy and it is ours, activate it and connect.
|
|
||||||
* If its a proxy and it is theirs, wait for activation.
|
|
||||||
* If it is not a proxy, just connect.
|
|
||||||
*/
|
|
||||||
private void connectIfReady() {
|
|
||||||
JingleContentElement content = jingleSession.getContents().get(0);
|
|
||||||
if (ourChoice == null || theirChoice == null) {
|
|
||||||
// Not yet ready.
|
|
||||||
LOGGER.log(Level.INFO, "Not ready.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ourChoice == CANDIDATE_FAILURE && theirChoice == CANDIDATE_FAILURE) {
|
|
||||||
LOGGER.log(Level.INFO, "Failure.");
|
|
||||||
jingleSession.onTransportMethodFailed(getNamespace());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGGER.log(Level.INFO, "Ready.");
|
|
||||||
|
|
||||||
//Determine nominated candidate.
|
|
||||||
UsedCandidate nominated;
|
|
||||||
if (ourChoice != CANDIDATE_FAILURE && theirChoice != CANDIDATE_FAILURE) {
|
|
||||||
if (ourChoice.candidate.getPriority() > theirChoice.candidate.getPriority()) {
|
|
||||||
nominated = ourChoice;
|
|
||||||
} else if (ourChoice.candidate.getPriority() < theirChoice.candidate.getPriority()) {
|
|
||||||
nominated = theirChoice;
|
|
||||||
} else {
|
|
||||||
nominated = jingleSession.isInitiator() ? ourChoice : theirChoice;
|
|
||||||
}
|
|
||||||
} else if (ourChoice != CANDIDATE_FAILURE) {
|
|
||||||
nominated = ourChoice;
|
|
||||||
} else {
|
|
||||||
nominated = theirChoice;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nominated == theirChoice) {
|
|
||||||
LOGGER.log(Level.INFO, "Their choice, so our proposed candidate is used.");
|
|
||||||
boolean isProxy = nominated.candidate.getType() == JingleS5BTransportCandidateElement.Type.proxy;
|
|
||||||
try {
|
|
||||||
nominated = connectToOurCandidate(nominated.candidate);
|
|
||||||
} catch (InterruptedException | IOException | XMPPException | SmackException | TimeoutException e) {
|
|
||||||
LOGGER.log(Level.INFO, "Could not connect to our candidate.", e);
|
|
||||||
//TODO: Proxy-Error
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isProxy) {
|
|
||||||
LOGGER.log(Level.INFO, "Is external proxy. Activate it.");
|
|
||||||
Bytestream activate = new Bytestream(ourProposal.getStreamId());
|
|
||||||
activate.setMode(null);
|
|
||||||
activate.setType(IQ.Type.set);
|
|
||||||
activate.setTo(nominated.candidate.getJid());
|
|
||||||
activate.setToActivate(jingleSession.getRemote());
|
|
||||||
activate.setFrom(jingleSession.getLocal());
|
|
||||||
try {
|
|
||||||
jingleSession.getConnection().createStanzaCollectorAndSend(activate).nextResultOrThrow();
|
|
||||||
} catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) {
|
|
||||||
LOGGER.log(Level.WARNING, "Could not activate proxy.", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGGER.log(Level.INFO, "Send candidate-activate.");
|
|
||||||
JingleElement candidateActivate = transportManager().createCandidateActivated(
|
|
||||||
jingleSession.getRemote(), jingleSession.getInitiator(), jingleSession.getSessionId(),
|
|
||||||
content.getSenders(), content.getCreator(), content.getName(), nominated.transport.getStreamId(),
|
|
||||||
nominated.candidate.getCandidateId());
|
|
||||||
try {
|
|
||||||
jingleSession.getConnection().createStanzaCollectorAndSend(candidateActivate)
|
|
||||||
.nextResultOrThrow();
|
|
||||||
} catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) {
|
|
||||||
LOGGER.log(Level.WARNING, "Could not send candidate-activated", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGGER.log(Level.INFO, "Start transmission.");
|
|
||||||
Socks5BytestreamSession bs = new Socks5BytestreamSession(nominated.socket, !isProxy);
|
|
||||||
callback.onSessionInitiated(bs);
|
|
||||||
|
|
||||||
}
|
|
||||||
//Our choice
|
|
||||||
else {
|
|
||||||
LOGGER.log(Level.INFO, "Our choice, so their candidate was used.");
|
|
||||||
boolean isProxy = nominated.candidate.getType() == JingleS5BTransportCandidateElement.Type.proxy;
|
|
||||||
if (!isProxy) {
|
|
||||||
LOGGER.log(Level.INFO, "Direct connection.");
|
|
||||||
Socks5BytestreamSession bs = new Socks5BytestreamSession(nominated.socket, true);
|
|
||||||
callback.onSessionInitiated(bs);
|
|
||||||
} else {
|
|
||||||
LOGGER.log(Level.INFO, "Our choice was their external proxy. wait for candidate-activate.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in a new issue