mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-23 20:42:06 +01:00
Rewrote S5BTransportSession
This commit is contained in:
parent
5eba48b7d8
commit
69b3f5837e
8 changed files with 298 additions and 331 deletions
|
@ -70,7 +70,7 @@ public abstract class JingleContentTransport implements ExtensionElement {
|
||||||
XmlStringBuilder xml = new XmlStringBuilder(this);
|
XmlStringBuilder xml = new XmlStringBuilder(this);
|
||||||
addExtraAttributes(xml);
|
addExtraAttributes(xml);
|
||||||
|
|
||||||
if (candidates.isEmpty() && infos.isEmpty()) {
|
if (candidates.isEmpty() && info == null) {
|
||||||
xml.closeEmptyElement();
|
xml.closeEmptyElement();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,3 +1,19 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 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;
|
package org.jivesoftware.smackx.jingle.transports;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.jingle.transports;
|
package org.jivesoftware.smackx.jingle.transports;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
|
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
import org.jivesoftware.smackx.jingle.JingleSession;
|
import org.jivesoftware.smackx.jingle.JingleSession;
|
||||||
import org.jivesoftware.smackx.jingle.element.Jingle;
|
import org.jivesoftware.smackx.jingle.element.Jingle;
|
||||||
|
@ -28,12 +26,11 @@ import org.jivesoftware.smackx.jingle.element.JingleContentTransport;
|
||||||
* Created by vanitas on 20.06.17.
|
* Created by vanitas on 20.06.17.
|
||||||
*/
|
*/
|
||||||
public abstract class JingleTransportSession<T extends JingleContentTransport> {
|
public abstract class JingleTransportSession<T extends JingleContentTransport> {
|
||||||
protected final WeakReference<JingleSession> jingleSession;
|
protected final JingleSession jingleSession;
|
||||||
protected JingleContentTransport remoteTransport;
|
protected T ourProposal, theirProposal;
|
||||||
protected JingleContentTransport localTransport;
|
|
||||||
|
|
||||||
public JingleTransportSession(JingleSession session) {
|
public JingleTransportSession(JingleSession session) {
|
||||||
this.jingleSession = new WeakReference<>(session);
|
this.jingleSession = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract T createTransport();
|
public abstract T createTransport();
|
||||||
|
@ -47,10 +44,12 @@ public abstract class JingleTransportSession<T extends JingleContentTransport> {
|
||||||
JingleContentTransport t = content.getJingleTransport();
|
JingleContentTransport t = content.getJingleTransport();
|
||||||
|
|
||||||
if (t != null && t.getNamespace().equals(getNamespace())) {
|
if (t != null && t.getNamespace().equals(getNamespace())) {
|
||||||
remoteTransport = t;
|
setTheirProposal(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract void setTheirProposal(JingleContentTransport transport);
|
||||||
|
|
||||||
public abstract void initiateOutgoingSession(JingleTransportInitiationCallback callback);
|
public abstract void initiateOutgoingSession(JingleTransportInitiationCallback callback);
|
||||||
|
|
||||||
public abstract void initiateIncomingSession(JingleTransportInitiationCallback callback);
|
public abstract void initiateIncomingSession(JingleTransportInitiationCallback callback);
|
||||||
|
|
|
@ -28,6 +28,7 @@ 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.JingleSession;
|
import org.jivesoftware.smackx.jingle.JingleSession;
|
||||||
import org.jivesoftware.smackx.jingle.element.Jingle;
|
import org.jivesoftware.smackx.jingle.element.Jingle;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.JingleContentTransport;
|
||||||
import org.jivesoftware.smackx.jingle.transports.JingleTransportInitiationCallback;
|
import org.jivesoftware.smackx.jingle.transports.JingleTransportInitiationCallback;
|
||||||
import org.jivesoftware.smackx.jingle.transports.JingleTransportManager;
|
import org.jivesoftware.smackx.jingle.transports.JingleTransportManager;
|
||||||
import org.jivesoftware.smackx.jingle.transports.JingleTransportSession;
|
import org.jivesoftware.smackx.jingle.transports.JingleTransportSession;
|
||||||
|
@ -46,29 +47,27 @@ public class JingleIBBTransportSession extends JingleTransportSession<JingleIBBT
|
||||||
@Override
|
@Override
|
||||||
public JingleIBBTransport createTransport() {
|
public JingleIBBTransport createTransport() {
|
||||||
|
|
||||||
if (remoteTransport == null) {
|
if (theirProposal == null) {
|
||||||
return new JingleIBBTransport();
|
return new JingleIBBTransport();
|
||||||
} else {
|
} else {
|
||||||
JingleIBBTransport existing = (JingleIBBTransport) remoteTransport;
|
return new JingleIBBTransport(theirProposal.getBlockSize(), theirProposal.getSessionId());
|
||||||
return new JingleIBBTransport(existing.getBlockSize(), existing.getSessionId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initiateOutgoingSession(JingleTransportInitiationCallback callback) {
|
public void setTheirProposal(JingleContentTransport transport) {
|
||||||
LOGGER.log(Level.INFO, "Initiate Jingle InBandBytestream session.");
|
theirProposal = (JingleIBBTransport) transport;
|
||||||
if (jingleSession.get() == null) {
|
|
||||||
callback.onException(new NullPointerException("Lost reference to JingleSession."));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JingleIBBTransport ibbTransport = (JingleIBBTransport) remoteTransport;
|
@Override
|
||||||
BytestreamSession session;
|
public void initiateOutgoingSession(JingleTransportInitiationCallback callback) {
|
||||||
|
LOGGER.log(Level.INFO, "Initiate Jingle InBandBytestream session.");
|
||||||
|
|
||||||
|
BytestreamSession session;
|
||||||
try {
|
try {
|
||||||
session = InBandBytestreamManager.getByteStreamManager(jingleSession.get().getConnection())
|
session = InBandBytestreamManager.getByteStreamManager(jingleSession.getConnection())
|
||||||
.establishSession(jingleSession.get().getRemote(), ibbTransport.getSessionId());
|
.establishSession(jingleSession.getRemote(), theirProposal.getSessionId());
|
||||||
callback.onSessionInitiated(session);
|
callback.onSessionInitiated(session);
|
||||||
} catch (SmackException.NoResponseException | InterruptedException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) {
|
} catch (SmackException.NoResponseException | InterruptedException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) {
|
||||||
callback.onException(e);
|
callback.onException(e);
|
||||||
|
@ -78,17 +77,12 @@ public class JingleIBBTransportSession extends JingleTransportSession<JingleIBBT
|
||||||
@Override
|
@Override
|
||||||
public void initiateIncomingSession(final JingleTransportInitiationCallback callback) {
|
public void initiateIncomingSession(final JingleTransportInitiationCallback callback) {
|
||||||
LOGGER.log(Level.INFO, "Await Jingle InBandBytestream session.");
|
LOGGER.log(Level.INFO, "Await Jingle InBandBytestream session.");
|
||||||
if (jingleSession.get() == null) {
|
|
||||||
callback.onException(new NullPointerException("Lost reference to JingleSession."));
|
|
||||||
}
|
|
||||||
|
|
||||||
final JingleIBBTransport ibbTransport = (JingleIBBTransport) remoteTransport;
|
InBandBytestreamManager.getByteStreamManager(jingleSession.getConnection()).addIncomingBytestreamListener(new BytestreamListener() {
|
||||||
|
|
||||||
InBandBytestreamManager.getByteStreamManager(jingleSession.get().getConnection()).addIncomingBytestreamListener(new BytestreamListener() {
|
|
||||||
@Override
|
@Override
|
||||||
public void incomingBytestreamRequest(BytestreamRequest request) {
|
public void incomingBytestreamRequest(BytestreamRequest request) {
|
||||||
if (request.getFrom().asFullJidIfPossible().equals(jingleSession.get().getRemote())
|
if (request.getFrom().asFullJidIfPossible().equals(jingleSession.getRemote())
|
||||||
&& request.getSessionID().equals(ibbTransport.getSessionId())) {
|
&& request.getSessionID().equals(theirProposal.getSessionId())) {
|
||||||
BytestreamSession session;
|
BytestreamSession session;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -116,6 +110,6 @@ public class JingleIBBTransportSession extends JingleTransportSession<JingleIBBT
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JingleTransportManager<JingleIBBTransport> transportManager() {
|
public JingleTransportManager<JingleIBBTransport> transportManager() {
|
||||||
return JingleIBBTransportManager.getInstanceFor(jingleSession.get().getConnection());
|
return JingleIBBTransportManager.getInstanceFor(jingleSession.getConnection());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,82 +34,70 @@ 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.JingleManager;
|
||||||
import org.jivesoftware.smackx.jingle.JingleSession;
|
import org.jivesoftware.smackx.jingle.JingleSession;
|
||||||
import org.jivesoftware.smackx.jingle.JingleUtil;
|
|
||||||
import org.jivesoftware.smackx.jingle.element.Jingle;
|
import org.jivesoftware.smackx.jingle.element.Jingle;
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContent;
|
import org.jivesoftware.smackx.jingle.element.JingleContent;
|
||||||
|
import org.jivesoftware.smackx.jingle.element.JingleContentTransport;
|
||||||
import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidate;
|
import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidate;
|
||||||
import org.jivesoftware.smackx.jingle.transports.JingleTransportInitiationCallback;
|
import org.jivesoftware.smackx.jingle.transports.JingleTransportInitiationCallback;
|
||||||
import org.jivesoftware.smackx.jingle.transports.JingleTransportInitiationException;
|
|
||||||
import org.jivesoftware.smackx.jingle.transports.JingleTransportManager;
|
|
||||||
import org.jivesoftware.smackx.jingle.transports.JingleTransportSession;
|
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.JingleS5BTransport;
|
||||||
import org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransportCandidate;
|
import org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransportCandidate;
|
||||||
import org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransportInfo;
|
import org.jivesoftware.smackx.jingle.transports.jingle_s5b.elements.JingleS5BTransportInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LOL.
|
* Created by vanitas on 26.06.17.
|
||||||
*/
|
*/
|
||||||
public class JingleS5BTransportSession extends JingleTransportSession<JingleS5BTransport> {
|
public class JingleS5BTransportSession extends JingleTransportSession<JingleS5BTransport> {
|
||||||
private static final Logger LOGGER = Logger.getLogger(JingleS5BTransportSession.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(JingleS5BTransportSession.class.getName());
|
||||||
private final JingleS5BTransportManager transportManager;
|
|
||||||
|
|
||||||
private final JingleUtil jutil;
|
|
||||||
private Socket connectedSocket;
|
|
||||||
private JingleS5BTransportCandidate localUsedCandidate;
|
|
||||||
private JingleS5BTransportCandidate remoteUsedCandidate;
|
|
||||||
private JingleTransportInitiationCallback callback;
|
private JingleTransportInitiationCallback callback;
|
||||||
private boolean remoteError = false;
|
|
||||||
private boolean localError = false;
|
|
||||||
|
|
||||||
public JingleS5BTransportSession(JingleSession jingleSession) {
|
public JingleS5BTransportSession(JingleSession jingleSession) {
|
||||||
super(jingleSession);
|
super(jingleSession);
|
||||||
transportManager = JingleS5BTransportManager.getInstanceFor(jingleSession.getConnection());
|
|
||||||
jutil = new JingleUtil(jingleSession.getConnection());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private UsedCandidate ourChoice, theirChoice;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JingleS5BTransport createTransport() {
|
public JingleS5BTransport createTransport() {
|
||||||
if (localTransport != null) {
|
if (ourProposal == null) {
|
||||||
return (JingleS5BTransport) localTransport;
|
ourProposal = createTransport(JingleManager.randomId(), Bytestream.Mode.tcp);
|
||||||
|
}
|
||||||
|
return ourProposal;
|
||||||
}
|
}
|
||||||
|
|
||||||
return createTransport(JingleManager.randomId(), Bytestream.Mode.tcp);
|
@Override
|
||||||
|
public void setTheirProposal(JingleContentTransport transport) {
|
||||||
|
theirProposal = (JingleS5BTransport) transport;
|
||||||
}
|
}
|
||||||
|
|
||||||
private JingleS5BTransport createTransport(String sid, Bytestream.Mode mode) {
|
public JingleS5BTransport createTransport(String sid, Bytestream.Mode mode) {
|
||||||
JingleSession jSession = jingleSession.get();
|
JingleS5BTransport.Builder jb = JingleS5BTransport.getBuilder()
|
||||||
if (jSession == null) {
|
.setStreamId(sid).setMode(mode).setDestinationAddress(
|
||||||
throw new NullPointerException("Lost reference to JingleSession.");
|
Socks5Utils.createDigest(sid, jingleSession.getLocal(), jingleSession.getRemote()));
|
||||||
|
|
||||||
|
//Local host
|
||||||
|
for (Bytestream.StreamHost host : transportManager().getLocalStreamHosts()) {
|
||||||
|
jb.addTransportCandidate(new JingleS5BTransportCandidate(host, 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
JingleS5BTransport.Builder builder = JingleS5BTransport.getBuilder();
|
List<Bytestream.StreamHost> remoteHosts;
|
||||||
|
|
||||||
for (Bytestream.StreamHost host : transportManager.getLocalStreamHosts()) {
|
|
||||||
JingleS5BTransportCandidate candidate = new JingleS5BTransportCandidate(host, 100);
|
|
||||||
builder.addTransportCandidate(candidate);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Bytestream.StreamHost> availableStreamHosts = null;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
availableStreamHosts = transportManager.getAvailableStreamHosts();
|
remoteHosts = transportManager().getAvailableStreamHosts();
|
||||||
} catch (XMPPException.XMPPErrorException | SmackException.NoResponseException | InterruptedException |
|
} catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) {
|
||||||
SmackException.NotConnectedException e) {
|
LOGGER.log(Level.WARNING, "Could not determine available StreamHosts.", e);
|
||||||
LOGGER.log(Level.WARNING, "Could not get available StreamHosts: " + e, e);
|
remoteHosts = Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Bytestream.StreamHost host : availableStreamHosts != null ?
|
for (Bytestream.StreamHost host : remoteHosts) {
|
||||||
availableStreamHosts : Collections.<Bytestream.StreamHost>emptyList()) {
|
jb.addTransportCandidate(new JingleS5BTransportCandidate(host, 0));
|
||||||
JingleS5BTransportCandidate candidate = new JingleS5BTransportCandidate(host, 0);
|
|
||||||
builder.addTransportCandidate(candidate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.setStreamId(sid);
|
return jb.build();
|
||||||
builder.setMode(mode);
|
}
|
||||||
builder.setDestinationAddress(Socks5Utils.createDigest(sid, jSession.getLocal(), jSession.getRemote()));
|
|
||||||
localTransport = builder.build();
|
|
||||||
|
|
||||||
return (JingleS5BTransport) localTransport;
|
public void setTheirTransport(JingleContentTransport transport) {
|
||||||
|
theirProposal = (JingleS5BTransport) transport;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -125,277 +113,246 @@ public class JingleS5BTransportSession extends JingleTransportSession<JingleS5BT
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initiateSession() {
|
private void initiateSession() {
|
||||||
JingleSession jSession = jingleSession.get();
|
JingleContent content = jingleSession.getContents().get(0);
|
||||||
if (jSession == null) {
|
UsedCandidate usedCandidate = chooseFromProposedCandidates(theirProposal);
|
||||||
throw new NullPointerException("Lost reference to jingleSession.");
|
if (usedCandidate == null) {
|
||||||
}
|
ourChoice = CANDIDATE_FAILURE;
|
||||||
|
Jingle candidateError = transportManager().createCandidateError(
|
||||||
JingleS5BTransport receivedTransport = (JingleS5BTransport) remoteTransport;
|
jingleSession.getRemote(), jingleSession.getInitiator(), jingleSession.getSessionId(),
|
||||||
|
content.getSenders(), content.getCreator(), content.getName(), theirProposal.getStreamId());
|
||||||
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 {
|
try {
|
||||||
Socks5Client socks5Client = new Socks5Client(streamHost, receivedTransport.getDestinationAddress());
|
jingleSession.getConnection().sendStanza(candidateError);
|
||||||
socket = socks5Client.getSocket(10 * 1000);
|
|
||||||
workedForUs = candidate;
|
|
||||||
LOGGER.log(Level.INFO, "Connected to remote address " + address + " with dstAddr "
|
|
||||||
+ receivedTransport.getDestinationAddress());
|
|
||||||
break;
|
|
||||||
|
|
||||||
} catch (IOException | XMPPException | InterruptedException | TimeoutException | SmackException e) {
|
|
||||||
LOGGER.log(Level.WARNING, "Could not connect to remotes address " + address + " with dstAddr "
|
|
||||||
+ receivedTransport.getDestinationAddress());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JingleContent content = jSession.getContents().get(0);
|
|
||||||
|
|
||||||
Jingle response;
|
|
||||||
|
|
||||||
if (socket != null) {
|
|
||||||
connectedSocket = socket;
|
|
||||||
localUsedCandidate = workedForUs;
|
|
||||||
|
|
||||||
response = transportManager.createCandidateUsed(jSession.getRemote(), jSession.getInitiator(),
|
|
||||||
jSession.getSessionId(), content.getSenders(), content.getCreator(),
|
|
||||||
content.getName(), receivedTransport.getStreamId(), localUsedCandidate.getCandidateId());
|
|
||||||
|
|
||||||
} else {
|
|
||||||
localError = true;
|
|
||||||
response = transportManager.createCandidateError(jSession.getRemote(), jSession.getInitiator(),
|
|
||||||
jSession.getSessionId(), content.getSenders(), content.getCreator(),
|
|
||||||
content.getName(), receivedTransport.getStreamId());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
jSession.getConnection().sendStanza(response);
|
|
||||||
} catch (SmackException.NotConnectedException | InterruptedException e) {
|
} catch (SmackException.NotConnectedException | InterruptedException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not send candidate-error.", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ourChoice = usedCandidate;
|
||||||
|
Jingle 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);
|
LOGGER.log(Level.WARNING, "Could not send candidate-used.", e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
closeIfBothSidesFailed();
|
connectIfReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean closeIfBothSidesFailed() {
|
private UsedCandidate chooseFromProposedCandidates(JingleS5BTransport proposal) {
|
||||||
JingleSession jSession = jingleSession.get();
|
for (JingleContentTransportCandidate c : proposal.getCandidates()) {
|
||||||
if (jSession != null) {
|
JingleS5BTransportCandidate candidate = (JingleS5BTransportCandidate) c;
|
||||||
if (localError && remoteError) {
|
|
||||||
callback.onException(new JingleTransportInitiationException.CandidateError());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JingleS5BTransportCandidate determineUsedCandidate() {
|
try {
|
||||||
if (localUsedCandidate == null && remoteUsedCandidate == null) {
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remoteUsedCandidate == null) {
|
private UsedCandidate connectToTheirCandidate(JingleS5BTransportCandidate candidate)
|
||||||
return localUsedCandidate;
|
throws InterruptedException, TimeoutException, SmackException, XMPPException, IOException {
|
||||||
|
Bytestream.StreamHost streamHost = candidate.getStreamHost();
|
||||||
|
String address = streamHost.getAddress();
|
||||||
|
Socks5Client socks5Client = new Socks5Client(streamHost, theirProposal.getDestinationAddress());
|
||||||
|
Socket socket = socks5Client.getSocket(10 * 1000);
|
||||||
|
LOGGER.log(Level.INFO, "Connected to their StreamHost " + address + " using dstAddr "
|
||||||
|
+ theirProposal.getDestinationAddress());
|
||||||
|
return new UsedCandidate(theirProposal, candidate, socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (localUsedCandidate == null) {
|
private UsedCandidate connectToOurCandidate(JingleS5BTransportCandidate candidate)
|
||||||
return remoteUsedCandidate;
|
throws InterruptedException, TimeoutException, SmackException, XMPPException, IOException {
|
||||||
}
|
Bytestream.StreamHost streamHost = candidate.getStreamHost();
|
||||||
|
String address = streamHost.getAddress();
|
||||||
if (localUsedCandidate.getPriority() > remoteUsedCandidate.getPriority()) {
|
Socks5ClientForInitiator socks5Client = new Socks5ClientForInitiator(
|
||||||
return localUsedCandidate;
|
streamHost, ourProposal.getDestinationAddress(), jingleSession.getConnection(),
|
||||||
}
|
jingleSession.getSessionId(), jingleSession.getRemote());
|
||||||
|
Socket socket = socks5Client.getSocket(10 * 1000);
|
||||||
if (localUsedCandidate.getPriority() < remoteUsedCandidate.getPriority()) {
|
LOGGER.log(Level.INFO, "Connected to our StreamHost " + address + " using dstAddr "
|
||||||
return remoteUsedCandidate;
|
+ theirProposal.getDestinationAddress());
|
||||||
}
|
return new UsedCandidate(ourProposal, candidate, socket);
|
||||||
|
|
||||||
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 jutil.createErrorMalformedRequest(candidateUsed);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (localUsedCandidate != null || localError) {
|
|
||||||
try {
|
|
||||||
connect(determineUsedCandidate());
|
|
||||||
} catch (SmackException.NotConnectedException | InterruptedException e) {
|
|
||||||
callback.onException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return IQ.createResultIQ(candidateUsed);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void connect(JingleS5BTransportCandidate candidate) throws SmackException.NotConnectedException, InterruptedException {
|
|
||||||
JingleSession jSession = jingleSession.get();
|
|
||||||
if (jSession == null) {
|
|
||||||
throw new NullPointerException("Lost reference to JingleSession.");
|
|
||||||
}
|
|
||||||
JingleContent content = jSession.getContents().get(0);
|
|
||||||
|
|
||||||
// Used candidate belongs to remote.
|
|
||||||
if (candidate == localUsedCandidate) {
|
|
||||||
|
|
||||||
if (connectedSocket != null) {
|
|
||||||
callback.onSessionInitiated(new Socks5BytestreamSession(connectedSocket,
|
|
||||||
candidate.getJid().asBareJid().equals(jSession.getRemote().asBareJid())));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new AssertionError("Connected socket is null.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used candidate belongs to us.
|
|
||||||
else {
|
|
||||||
|
|
||||||
if (candidate.getType() == JingleS5BTransportCandidate.Type.proxy) {
|
|
||||||
|
|
||||||
if (!candidate.getJid().asBareJid().equals(jSession.getLocal().asBareJid())) {
|
|
||||||
//activate proxy
|
|
||||||
Bytestream activateProxy = new Bytestream(((JingleS5BTransport) localTransport).getStreamId());
|
|
||||||
activateProxy.setToActivate(candidate.getJid());
|
|
||||||
activateProxy.setTo(candidate.getJid());
|
|
||||||
Bytestream result;
|
|
||||||
try {
|
|
||||||
result = jSession.getConnection().createStanzaCollectorAndSend(activateProxy).nextResultOrThrow();
|
|
||||||
} catch (SmackException.NoResponseException | XMPPException.XMPPErrorException |
|
|
||||||
SmackException.NotConnectedException | InterruptedException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Could not activate proxy server: " + e, e);
|
|
||||||
|
|
||||||
//send proxy error
|
|
||||||
jSession.getConnection().sendStanza(transportManager.createProxyError(
|
|
||||||
jSession.getRemote(), jSession.getInitiator(), jSession.getSessionId(),
|
|
||||||
content.getSenders(), content.getCreator(), content.getName(),
|
|
||||||
((JingleS5BTransport) localTransport).getStreamId()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
transportManager.createCandidateActivated(jSession.getRemote(), jSession.getInitiator(), jSession.getSessionId(),
|
|
||||||
content.getSenders(), content.getCreator(), content.getName(), ((JingleS5BTransport) localTransport).getStreamId(),
|
|
||||||
candidate.getCandidateId());
|
|
||||||
}
|
|
||||||
|
|
||||||
Socks5ClientForInitiator socks5Client = new Socks5ClientForInitiator(candidate.getStreamHost(),
|
|
||||||
((JingleS5BTransport) localTransport).getDestinationAddress(),
|
|
||||||
jSession.getConnection(), ((JingleS5BTransport) localTransport).getStreamId(),
|
|
||||||
jSession.getLocal());
|
|
||||||
try {
|
|
||||||
connectedSocket = socks5Client.getSocket(10 * 1000);
|
|
||||||
} catch (IOException | XMPPException | SmackException | InterruptedException | TimeoutException e) {
|
|
||||||
callback.onException(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback.onSessionInitiated(new Socks5BytestreamSession(connectedSocket, true));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
//TODO: Find out how to react.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ handleCandidateActivated(Jingle candidateActivated) {
|
|
||||||
JingleContent content = candidateActivated.getContents().get(0);
|
|
||||||
JingleS5BTransportInfo info = (JingleS5BTransportInfo) content.getJingleTransport().getInfos().get(0);
|
|
||||||
if (!info.getElementName().equals(JingleS5BTransportInfo.CandidateActivated.ELEMENT)) {
|
|
||||||
throw new AssertionError("Element mus be candidateActivated.");
|
|
||||||
}
|
|
||||||
|
|
||||||
JingleS5BTransportInfo.CandidateActivated activated = (JingleS5BTransportInfo.CandidateActivated) info;
|
|
||||||
if (!localUsedCandidate.getCandidateId().equals(activated.getCandidateId())) {
|
|
||||||
throw new AssertionError("CandidateID must be equal.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connectedSocket == null) {
|
|
||||||
throw new AssertionError("connected Socket must not be null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
callback.onSessionInitiated(new Socks5BytestreamSession(connectedSocket,
|
|
||||||
jingleSession.get().getRemote().asBareJid().equals(localUsedCandidate.getJid().asBareJid())));
|
|
||||||
|
|
||||||
return IQ.createResultIQ(candidateActivated);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ handleCandidateError(Jingle candidateError) {
|
|
||||||
remoteError = true;
|
|
||||||
|
|
||||||
if (closeIfBothSidesFailed()) {
|
|
||||||
return IQ.createResultIQ(candidateError);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (localUsedCandidate != null || localError) {
|
|
||||||
try {
|
|
||||||
connect(determineUsedCandidate());
|
|
||||||
} catch (SmackException.NotConnectedException | InterruptedException e) {
|
|
||||||
callback.onException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return IQ.createResultIQ(candidateError);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IQ handleProxyError(Jingle proxyError) {
|
|
||||||
|
|
||||||
return IQ.createResultIQ(proxyError);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getNamespace() {
|
public String getNamespace() {
|
||||||
return transportManager.getNamespace();
|
return JingleS5BTransport.NAMESPACE_V1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IQ handleTransportInfo(Jingle transportInfo) {
|
public IQ handleTransportInfo(Jingle transportInfo) {
|
||||||
JingleS5BTransport transport = (JingleS5BTransport) transportInfo.getContents().get(0).getJingleTransport();
|
JingleS5BTransportInfo info = (JingleS5BTransportInfo) transportInfo.getContents().get(0).getJingleTransport().getInfo();
|
||||||
JingleS5BTransportInfo info = (JingleS5BTransportInfo) transport.getInfos().get(0);
|
|
||||||
|
|
||||||
if (info != null) {
|
|
||||||
|
|
||||||
switch (info.getElementName()) {
|
switch (info.getElementName()) {
|
||||||
case JingleS5BTransportInfo.CandidateUsed.ELEMENT:
|
case JingleS5BTransportInfo.CandidateUsed.ELEMENT:
|
||||||
return handleCandidateUsed(transportInfo);
|
return handleCandidateUsed(transportInfo);
|
||||||
|
|
||||||
case JingleS5BTransportInfo.CandidateActivated.ELEMENT:
|
case JingleS5BTransportInfo.CandidateActivated.ELEMENT:
|
||||||
return handleCandidateActivated(transportInfo);
|
return handleCandidateActivate(transportInfo);
|
||||||
|
|
||||||
case JingleS5BTransportInfo.CandidateError.ELEMENT:
|
case JingleS5BTransportInfo.CandidateError.ELEMENT:
|
||||||
return handleCandidateError(transportInfo);
|
return handleCandidateError(transportInfo);
|
||||||
|
|
||||||
case JingleS5BTransportInfo.ProxyError.ELEMENT:
|
case JingleS5BTransportInfo.ProxyError.ELEMENT:
|
||||||
return handleProxyError(transportInfo);
|
return handleProxyError(transportInfo);
|
||||||
|
}
|
||||||
default:
|
//We should never go here, but lets be gracious...
|
||||||
return IQ.createResultIQ(transportInfo);
|
return IQ.createResultIQ(transportInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IQ handleCandidateUsed(Jingle jingle) {
|
||||||
|
JingleS5BTransportInfo info = (JingleS5BTransportInfo) jingle.getContents().get(0).getJingleTransport().getInfo();
|
||||||
|
String candidateId = ((JingleS5BTransportInfo.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(Jingle jingle) {
|
||||||
|
Socks5BytestreamSession bs = new Socks5BytestreamSession(ourChoice.socket,
|
||||||
|
ourChoice.candidate.getJid().asBareJid().equals(jingleSession.getRemote().asBareJid()));
|
||||||
|
callback.onSessionInitiated(bs);
|
||||||
|
return IQ.createResultIQ(jingle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IQ handleCandidateError(Jingle jingle) {
|
||||||
|
theirChoice = CANDIDATE_FAILURE;
|
||||||
|
connectIfReady();
|
||||||
|
return IQ.createResultIQ(jingle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IQ handleProxyError(Jingle jingle) {
|
||||||
|
//TODO
|
||||||
|
return IQ.createResultIQ(jingle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connectIfReady() {
|
||||||
|
if (ourChoice == null || theirChoice == null) {
|
||||||
|
// Not yet ready.
|
||||||
|
LOGGER.log(Level.INFO, "Not ready.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ourChoice == CANDIDATE_FAILURE && theirChoice == CANDIDATE_FAILURE) {
|
||||||
|
// TODO: Transport failed.
|
||||||
} else {
|
} else {
|
||||||
return jutil.createErrorMalformedRequest(transportInfo);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proxy. Needs activation.
|
||||||
|
if (nominated.candidate.getType() == JingleS5BTransportCandidate.Type.proxy) {
|
||||||
|
//Our proxy. Activate it.
|
||||||
|
if (nominated == theirChoice) {
|
||||||
|
JingleContent content = jingleSession.getContents().get(0);
|
||||||
|
|
||||||
|
Bytestream activateProxy = new Bytestream(ourProposal.getStreamId());
|
||||||
|
activateProxy.setToActivate(nominated.candidate.getJid());
|
||||||
|
activateProxy.setTo(nominated.candidate.getJid());
|
||||||
|
//Send proxy activation.
|
||||||
|
try {
|
||||||
|
jingleSession.getConnection().createStanzaCollectorAndSend(activateProxy).nextResultOrThrow();
|
||||||
|
//Connect
|
||||||
|
try {
|
||||||
|
nominated = connectToOurCandidate(nominated.candidate);
|
||||||
|
Socks5BytestreamSession bs = new Socks5BytestreamSession(nominated.socket,
|
||||||
|
nominated.candidate.getJid().asBareJid().equals(jingleSession.getLocal().asBareJid()));
|
||||||
|
callback.onSessionInitiated(bs);
|
||||||
|
} catch (TimeoutException | SmackException | IOException | XMPPException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not connect to our own proxy after activation.", e);
|
||||||
|
//TODO: ???
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Could not activate proxy. Send proxy-error
|
||||||
|
catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not activate proxy at " + nominated.candidate.getJid(), e);
|
||||||
|
Jingle proxyError = transportManager().createProxyError(
|
||||||
|
jingleSession.getRemote(), jingleSession.getInitiator(),
|
||||||
|
jingleSession.getSessionId(), content.getSenders(),
|
||||||
|
content.getCreator(), content.getName(), nominated.transport.getStreamId());
|
||||||
|
try {
|
||||||
|
jingleSession.getConnection().sendStanza(proxyError);
|
||||||
|
}
|
||||||
|
//Could not send proxy-error. WTF?
|
||||||
|
catch (SmackException.NotConnectedException | InterruptedException e1) {
|
||||||
|
LOGGER.log(Level.WARNING, "Could not send proxy-error.", e1);
|
||||||
|
}
|
||||||
|
callback.onException(e);
|
||||||
|
}
|
||||||
|
//Send candidate-activate.
|
||||||
|
Jingle 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Else wait for activation.
|
||||||
|
}
|
||||||
|
// Direct connection. Go ahead.
|
||||||
|
else {
|
||||||
|
Socks5BytestreamSession bs;
|
||||||
|
if (nominated == ourChoice) {
|
||||||
|
bs = new Socks5BytestreamSession(nominated.socket,
|
||||||
|
nominated.candidate.getJid().asBareJid().equals(jingleSession.getRemote().asBareJid()));
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
nominated = connectToOurCandidate(theirChoice.candidate);
|
||||||
|
} catch (InterruptedException | IOException | XMPPException | SmackException | TimeoutException e) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Failed to connect to our own StreamHost!");
|
||||||
|
callback.onException(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bs = new Socks5BytestreamSession(nominated.socket,
|
||||||
|
nominated.candidate.getJid().asBareJid().equals(jingleSession.getLocal().asBareJid()));
|
||||||
|
}
|
||||||
|
callback.onSessionInitiated(bs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JingleTransportManager<JingleS5BTransport> transportManager() {
|
public JingleS5BTransportManager transportManager() {
|
||||||
return JingleS5BTransportManager.getInstanceFor(jingleSession.get().getConnection());
|
return JingleS5BTransportManager.getInstanceFor(jingleSession.getConnection());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class UsedCandidate {
|
||||||
|
private final Socket socket;
|
||||||
|
private final JingleS5BTransport transport;
|
||||||
|
private final JingleS5BTransportCandidate candidate;
|
||||||
|
|
||||||
|
public UsedCandidate(JingleS5BTransport transport, JingleS5BTransportCandidate candidate, Socket socket) {
|
||||||
|
this.socket = socket;
|
||||||
|
this.transport = transport;
|
||||||
|
this.candidate = candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final UsedCandidate CANDIDATE_FAILURE = new UsedCandidate(null, null, null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,8 +39,8 @@ public class JingleS5BTransport extends JingleContentTransport {
|
||||||
private final String dstAddr;
|
private final String dstAddr;
|
||||||
private final Bytestream.Mode mode;
|
private final Bytestream.Mode mode;
|
||||||
|
|
||||||
protected JingleS5BTransport(List<JingleContentTransportCandidate> candidates, List<JingleContentTransportInfo> infos, String streamId, String dstAddr, Bytestream.Mode mode) {
|
protected JingleS5BTransport(List<JingleContentTransportCandidate> candidates, JingleContentTransportInfo info, String streamId, String dstAddr, Bytestream.Mode mode) {
|
||||||
super(candidates, infos);
|
super(candidates, info);
|
||||||
StringUtils.requireNotNullOrEmpty(streamId, "sid MUST be neither null, nor empty.");
|
StringUtils.requireNotNullOrEmpty(streamId, "sid MUST be neither null, nor empty.");
|
||||||
this.streamId = streamId;
|
this.streamId = streamId;
|
||||||
this.dstAddr = dstAddr;
|
this.dstAddr = dstAddr;
|
||||||
|
@ -94,7 +94,7 @@ public class JingleS5BTransport extends JingleContentTransport {
|
||||||
private String dstAddr;
|
private String dstAddr;
|
||||||
private Bytestream.Mode mode;
|
private Bytestream.Mode mode;
|
||||||
private ArrayList<JingleContentTransportCandidate> candidates = new ArrayList<>();
|
private ArrayList<JingleContentTransportCandidate> candidates = new ArrayList<>();
|
||||||
private ArrayList<JingleContentTransportInfo> infos = new ArrayList<>();
|
private JingleContentTransportInfo info = null;
|
||||||
|
|
||||||
public Builder setStreamId(String sid) {
|
public Builder setStreamId(String sid) {
|
||||||
this.streamId = sid;
|
this.streamId = sid;
|
||||||
|
@ -116,29 +116,29 @@ public class JingleS5BTransport extends JingleContentTransport {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder addTransportInfo(JingleContentTransportInfo info) {
|
public Builder setTransportInfo(JingleContentTransportInfo info) {
|
||||||
this.infos.add(info);
|
this.info = info;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setCandidateUsed(String candidateId) {
|
public Builder setCandidateUsed(String candidateId) {
|
||||||
return addTransportInfo(JingleS5BTransportInfo.CandidateUsed(candidateId));
|
return setTransportInfo(JingleS5BTransportInfo.CandidateUsed(candidateId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setCandidateActivated(String candidateId) {
|
public Builder setCandidateActivated(String candidateId) {
|
||||||
return addTransportInfo(JingleS5BTransportInfo.CandidateActivated(candidateId));
|
return setTransportInfo(JingleS5BTransportInfo.CandidateActivated(candidateId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setCandidateError() {
|
public Builder setCandidateError() {
|
||||||
return addTransportInfo(JingleS5BTransportInfo.CandidateError());
|
return setTransportInfo(JingleS5BTransportInfo.CandidateError());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setProxyError() {
|
public Builder setProxyError() {
|
||||||
return addTransportInfo(JingleS5BTransportInfo.ProxyError());
|
return setTransportInfo(JingleS5BTransportInfo.ProxyError());
|
||||||
}
|
}
|
||||||
|
|
||||||
public JingleS5BTransport build() {
|
public JingleS5BTransport build() {
|
||||||
return new JingleS5BTransport(candidates, infos, streamId, dstAddr, mode);
|
return new JingleS5BTransport(candidates, info, streamId, dstAddr, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,23 +83,23 @@ public class JingleS5BTransportProvider extends JingleContentTransportProvider<J
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JingleS5BTransportInfo.CandidateActivated.ELEMENT:
|
case JingleS5BTransportInfo.CandidateActivated.ELEMENT:
|
||||||
builder.addTransportInfo(JingleS5BTransportInfo.CandidateActivated(
|
builder.setTransportInfo(JingleS5BTransportInfo.CandidateActivated(
|
||||||
parser.getAttributeValue(null,
|
parser.getAttributeValue(null,
|
||||||
JingleS5BTransportInfo.CandidateActivated.ATTR_CID)));
|
JingleS5BTransportInfo.CandidateActivated.ATTR_CID)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JingleS5BTransportInfo.CandidateUsed.ELEMENT:
|
case JingleS5BTransportInfo.CandidateUsed.ELEMENT:
|
||||||
builder.addTransportInfo(JingleS5BTransportInfo.CandidateUsed(
|
builder.setTransportInfo(JingleS5BTransportInfo.CandidateUsed(
|
||||||
parser.getAttributeValue(null,
|
parser.getAttributeValue(null,
|
||||||
JingleS5BTransportInfo.CandidateUsed.ATTR_CID)));
|
JingleS5BTransportInfo.CandidateUsed.ATTR_CID)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JingleS5BTransportInfo.CandidateError.ELEMENT:
|
case JingleS5BTransportInfo.CandidateError.ELEMENT:
|
||||||
builder.addTransportInfo(JingleS5BTransportInfo.CandidateError());
|
builder.setTransportInfo(JingleS5BTransportInfo.CandidateError());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JingleS5BTransportInfo.ProxyError.ELEMENT:
|
case JingleS5BTransportInfo.ProxyError.ELEMENT:
|
||||||
builder.addTransportInfo(JingleS5BTransportInfo.ProxyError());
|
builder.setTransportInfo(JingleS5BTransportInfo.ProxyError());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smackx.jingle.transports.jingle_s5b;
|
package org.jivesoftware.smackx.jingle.transports.jingle_s5b;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.assertNotNull;
|
||||||
import static junit.framework.TestCase.assertNull;
|
import static junit.framework.TestCase.assertNull;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
@ -114,10 +115,10 @@ public class JingleS5BTransportTest extends SmackTestSuite {
|
||||||
JingleS5BTransport candidateErrorTransport = new JingleS5BTransportProvider()
|
JingleS5BTransport candidateErrorTransport = new JingleS5BTransportProvider()
|
||||||
.parse(TestUtils.getParser(candidateError));
|
.parse(TestUtils.getParser(candidateError));
|
||||||
assertNull(candidateErrorTransport.getDestinationAddress());
|
assertNull(candidateErrorTransport.getDestinationAddress());
|
||||||
assertEquals(1, candidateErrorTransport.getInfos().size());
|
assertNotNull(candidateErrorTransport.getInfo());
|
||||||
assertEquals("vj3hs98y", candidateErrorTransport.getStreamId());
|
assertEquals("vj3hs98y", candidateErrorTransport.getStreamId());
|
||||||
assertEquals(JingleS5BTransportInfo.CandidateError(),
|
assertEquals(JingleS5BTransportInfo.CandidateError(),
|
||||||
candidateErrorTransport.getInfos().get(0));
|
candidateErrorTransport.getInfo());
|
||||||
assertEquals(candidateError, candidateErrorTransport.toXML().toString());
|
assertEquals(candidateError, candidateErrorTransport.toXML().toString());
|
||||||
|
|
||||||
String proxyError =
|
String proxyError =
|
||||||
|
@ -127,10 +128,10 @@ public class JingleS5BTransportTest extends SmackTestSuite {
|
||||||
JingleS5BTransport proxyErrorTransport = new JingleS5BTransportProvider()
|
JingleS5BTransport proxyErrorTransport = new JingleS5BTransportProvider()
|
||||||
.parse(TestUtils.getParser(proxyError));
|
.parse(TestUtils.getParser(proxyError));
|
||||||
assertNull(proxyErrorTransport.getDestinationAddress());
|
assertNull(proxyErrorTransport.getDestinationAddress());
|
||||||
assertEquals(1, proxyErrorTransport.getInfos().size());
|
assertNotNull(proxyErrorTransport.getInfo());
|
||||||
assertEquals("vj3hs98y", proxyErrorTransport.getStreamId());
|
assertEquals("vj3hs98y", proxyErrorTransport.getStreamId());
|
||||||
assertEquals(JingleS5BTransportInfo.ProxyError(),
|
assertEquals(JingleS5BTransportInfo.ProxyError(),
|
||||||
proxyErrorTransport.getInfos().get(0));
|
proxyErrorTransport.getInfo());
|
||||||
assertEquals(proxyError, proxyErrorTransport.toXML().toString());
|
assertEquals(proxyError, proxyErrorTransport.toXML().toString());
|
||||||
|
|
||||||
String candidateUsed =
|
String candidateUsed =
|
||||||
|
@ -139,12 +140,12 @@ public class JingleS5BTransportTest extends SmackTestSuite {
|
||||||
"</transport>";
|
"</transport>";
|
||||||
JingleS5BTransport candidateUsedTransport = new JingleS5BTransportProvider()
|
JingleS5BTransport candidateUsedTransport = new JingleS5BTransportProvider()
|
||||||
.parse(TestUtils.getParser(candidateUsed));
|
.parse(TestUtils.getParser(candidateUsed));
|
||||||
assertEquals(1, candidateUsedTransport.getInfos().size());
|
assertNotNull(candidateUsedTransport.getInfo());
|
||||||
assertEquals(JingleS5BTransportInfo.CandidateUsed("hr65dqyd"),
|
assertEquals(JingleS5BTransportInfo.CandidateUsed("hr65dqyd"),
|
||||||
candidateUsedTransport.getInfos().get(0));
|
candidateUsedTransport.getInfo());
|
||||||
assertEquals("hr65dqyd",
|
assertEquals("hr65dqyd",
|
||||||
((JingleS5BTransportInfo.CandidateUsed)
|
((JingleS5BTransportInfo.CandidateUsed)
|
||||||
candidateUsedTransport.getInfos().get(0)).getCandidateId());
|
candidateUsedTransport.getInfo()).getCandidateId());
|
||||||
assertEquals(candidateUsed, candidateUsedTransport.toXML().toString());
|
assertEquals(candidateUsed, candidateUsedTransport.toXML().toString());
|
||||||
|
|
||||||
String candidateActivated =
|
String candidateActivated =
|
||||||
|
@ -153,12 +154,12 @@ public class JingleS5BTransportTest extends SmackTestSuite {
|
||||||
"</transport>";
|
"</transport>";
|
||||||
JingleS5BTransport candidateActivatedTransport = new JingleS5BTransportProvider()
|
JingleS5BTransport candidateActivatedTransport = new JingleS5BTransportProvider()
|
||||||
.parse(TestUtils.getParser(candidateActivated));
|
.parse(TestUtils.getParser(candidateActivated));
|
||||||
assertEquals(1, candidateActivatedTransport.getInfos().size());
|
assertNotNull(candidateActivatedTransport.getInfo());
|
||||||
assertEquals(JingleS5BTransportInfo.CandidateActivated("hr65dqyd"),
|
assertEquals(JingleS5BTransportInfo.CandidateActivated("hr65dqyd"),
|
||||||
candidateActivatedTransport.getInfos().get(0));
|
candidateActivatedTransport.getInfo());
|
||||||
assertEquals("hr65dqyd",
|
assertEquals("hr65dqyd",
|
||||||
((JingleS5BTransportInfo.CandidateActivated)
|
((JingleS5BTransportInfo.CandidateActivated)
|
||||||
candidateActivatedTransport.getInfos().get(0)).getCandidateId());
|
candidateActivatedTransport.getInfo()).getCandidateId());
|
||||||
assertEquals(candidateActivated, candidateActivatedTransport.toXML().toString());
|
assertEquals(candidateActivated, candidateActivatedTransport.toXML().toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue