2017-07-21 23:05:46 +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.transport.jingle_s5b ;
2017-07-19 23:15:17 +02:00
2017-07-21 18:29:27 +02:00
import java.io.IOException ;
2017-07-19 23:15:17 +02:00
import java.util.Collections ;
2017-07-21 18:29:27 +02:00
import java.util.Iterator ;
2017-07-19 23:15:17 +02:00
import java.util.List ;
2017-07-21 18:29:27 +02:00
import java.util.concurrent.TimeoutException ;
2017-07-22 00:26:50 +02:00
import java.util.logging.Level ;
import java.util.logging.Logger ;
2017-07-19 23:15:17 +02:00
2017-07-21 18:29:27 +02:00
import org.jivesoftware.smack.SmackException ;
2017-07-19 23:15:17 +02:00
import org.jivesoftware.smack.XMPPConnection ;
2017-07-21 18:29:27 +02:00
import org.jivesoftware.smack.XMPPException ;
2017-07-22 00:26:50 +02:00
import org.jivesoftware.smack.packet.IQ ;
2017-07-27 11:37:32 +02:00
import org.jivesoftware.smack.packet.Stanza ;
2017-08-04 14:06:12 +02:00
import org.jivesoftware.smack.util.Async ;
2017-07-22 00:26:50 +02:00
import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamSession ;
2017-07-21 17:58:57 +02:00
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy ;
2017-07-21 18:29:27 +02:00
import org.jivesoftware.smackx.bytestreams.socks5.Socks5Utils ;
2017-07-19 23:15:17 +02:00
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream ;
2017-07-22 00:26:50 +02:00
import org.jivesoftware.smackx.jingle.JingleManager ;
2017-07-27 18:09:49 +02:00
import org.jivesoftware.smackx.jingle.callbacks.JingleTransportCallback ;
2017-08-04 23:05:59 +02:00
import org.jivesoftware.smackx.jingle.component.JingleSession ;
import org.jivesoftware.smackx.jingle.component.JingleTransport ;
import org.jivesoftware.smackx.jingle.component.JingleTransportCandidate ;
2017-08-03 23:01:55 +02:00
import org.jivesoftware.smackx.jingle.element.JingleContentTransportCandidateElement ;
import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement ;
2017-07-27 23:31:04 +02:00
import org.jivesoftware.smackx.jingle.element.JingleContentTransportInfoElement ;
import org.jivesoftware.smackx.jingle.element.JingleElement ;
import org.jivesoftware.smackx.jingle.exception.FailedTransportException ;
2017-07-22 00:26:50 +02:00
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 ;
2017-07-19 23:15:17 +02:00
import org.jxmpp.jid.FullJid ;
/ * *
2017-07-21 23:05:46 +02:00
* Jingle SOCKS5Bytestream transport component .
2017-07-19 23:15:17 +02:00
* /
2017-07-21 23:51:06 +02:00
public class JingleS5BTransport extends JingleTransport < JingleS5BTransportElement > {
2017-07-19 23:15:17 +02:00
2017-07-22 00:26:50 +02:00
private static final Logger LOGGER = Logger . getLogger ( JingleS5BTransport . class . getName ( ) ) ;
2017-07-19 23:15:17 +02:00
public static final String NAMESPACE_V1 = " urn:xmpp:jingle:transports:s5b:1 " ;
public static final String NAMESPACE = NAMESPACE_V1 ;
2017-08-04 14:06:12 +02:00
private static final int MAX_TIMEOUT = 10 * 1000 ;
2017-07-21 23:05:46 +02:00
2017-07-19 23:15:17 +02:00
private final String sid ;
2017-08-03 23:01:55 +02:00
private String ourDstAddr ;
private String theirDstAddr ;
2017-08-05 00:43:54 +02:00
private Bytestream . Mode mode ;
2017-07-19 23:15:17 +02:00
2017-07-21 18:29:27 +02:00
// PEERS candidate of OUR choice.
2017-08-03 15:11:34 +02:00
private JingleS5BTransportCandidate ourSelectedCandidate ;
private JingleS5BTransportCandidate theirSelectedCandidate ;
2017-07-19 23:15:17 +02:00
2017-07-27 18:09:49 +02:00
private JingleTransportCallback callback ;
2017-07-21 18:29:27 +02:00
/ * *
2017-08-03 23:01:55 +02:00
* Create transport as initiator .
2017-08-04 14:06:12 +02:00
* @param initiator initiator of the Jingle session .
* @param responder responder .
* @param sid sessionId of the Jingle session .
* @param mode TCP / UDP .
* @param ourCandidates our proxy candidates .
2017-07-21 18:29:27 +02:00
* /
2017-08-04 14:06:12 +02:00
JingleS5BTransport ( FullJid initiator , FullJid responder , String sid , Bytestream . Mode mode , List < JingleTransportCandidate < ? > > ourCandidates ) {
2017-08-03 23:01:55 +02:00
this . sid = sid ;
2017-08-05 00:43:54 +02:00
this . mode = mode ;
2017-08-03 23:01:55 +02:00
this . ourDstAddr = Socks5Utils . createDigest ( sid , initiator , responder ) ;
Socks5Proxy . getSocks5Proxy ( ) . addTransfer ( ourDstAddr ) ;
for ( JingleTransportCandidate < ? > c : ourCandidates ) {
addOurCandidate ( c ) ;
}
2017-07-21 23:05:46 +02:00
}
2017-08-02 20:52:52 +02:00
/ * *
2017-08-03 23:01:55 +02:00
* Create simple transport as responder .
2017-08-04 14:06:12 +02:00
* @param initiator initiator of the Jingle session .
* @param responder responder .
* @param ourCandidates our proxy candidates .
* @param other transport of the other party .
2017-08-02 20:52:52 +02:00
* /
2017-08-04 14:06:12 +02:00
JingleS5BTransport ( FullJid initiator , FullJid responder , List < JingleTransportCandidate < ? > > ourCandidates , JingleS5BTransport other ) {
2017-08-05 14:30:00 +02:00
this . sid = other . getSid ( ) ;
2017-08-05 00:43:54 +02:00
this . mode = other . mode ;
2017-08-05 14:30:00 +02:00
this . ourDstAddr = Socks5Utils . createDigest ( sid , responder , initiator ) ;
2017-08-03 23:01:55 +02:00
Socks5Proxy . getSocks5Proxy ( ) . addTransfer ( ourDstAddr ) ;
this . theirDstAddr = other . theirDstAddr ;
for ( JingleTransportCandidate < ? > c : ourCandidates ) {
addOurCandidate ( c ) ;
}
for ( JingleTransportCandidate < ? > c : other . getTheirCandidates ( ) ) {
addTheirCandidate ( c ) ;
}
2017-07-21 18:29:27 +02:00
}
2017-07-19 23:15:17 +02:00
2017-08-02 20:52:52 +02:00
/ * *
2017-08-03 23:01:55 +02:00
* Create custom transport as responder .
2017-08-04 14:06:12 +02:00
* @param sid sessionId of the Jingle session .
2017-08-05 00:43:54 +02:00
* @param mode UPD / TCP .
2017-08-04 14:06:12 +02:00
* @param ourDstAddr SOCKS5 destination address ( digest )
* @param theirDstAddr SOCKS5 destination address ( digest )
* @param ourCandidates our proxy candidates .
* @param theirCandidates their proxy candidates .
2017-08-02 20:52:52 +02:00
* /
2017-08-05 00:43:54 +02:00
JingleS5BTransport ( String sid , Bytestream . Mode mode , String ourDstAddr , String theirDstAddr , List < JingleTransportCandidate < ? > > ourCandidates , List < JingleTransportCandidate < ? > > theirCandidates ) {
2017-07-19 23:15:17 +02:00
this . sid = sid ;
2017-08-05 00:43:54 +02:00
this . mode = mode ;
2017-08-03 23:01:55 +02:00
this . ourDstAddr = ourDstAddr ;
Socks5Proxy . getSocks5Proxy ( ) . addTransfer ( ourDstAddr ) ;
this . theirDstAddr = theirDstAddr ;
for ( JingleTransportCandidate < ? > c : ( ourCandidates ! = null ? ourCandidates :
Collections . < JingleS5BTransportCandidate > emptySet ( ) ) ) {
2017-08-03 15:11:34 +02:00
addOurCandidate ( c ) ;
}
2017-08-03 23:01:55 +02:00
for ( JingleTransportCandidate < ? > c : ( theirCandidates ! = null ? theirCandidates :
Collections . < JingleS5BTransportCandidate > emptySet ( ) ) ) {
2017-08-03 15:11:34 +02:00
addTheirCandidate ( c ) ;
2017-07-19 23:15:17 +02:00
}
}
2017-08-02 20:52:52 +02:00
/ * *
* Copy constructor .
2017-08-04 14:06:12 +02:00
* @param original which will be copied .
2017-08-02 20:52:52 +02:00
* /
2017-08-03 23:01:55 +02:00
public JingleS5BTransport ( JingleS5BTransport original ) {
this . sid = original . sid ;
this . ourDstAddr = original . ourDstAddr ;
this . theirDstAddr = original . theirDstAddr ;
2017-08-05 00:43:54 +02:00
this . mode = original . mode ;
2017-08-03 23:01:55 +02:00
for ( JingleTransportCandidate < ? > c : original . getOurCandidates ( ) ) {
addOurCandidate ( new JingleS5BTransportCandidate ( ( JingleS5BTransportCandidate ) c ) ) ;
}
for ( JingleTransportCandidate < ? > c : original . getTheirCandidates ( ) ) {
addTheirCandidate ( new JingleS5BTransportCandidate ( ( JingleS5BTransportCandidate ) c ) ) ;
2017-08-02 20:52:52 +02:00
}
2017-08-01 17:12:27 +02:00
}
2017-07-19 23:15:17 +02:00
@Override
public JingleS5BTransportElement getElement ( ) {
JingleS5BTransportElement . Builder builder = JingleS5BTransportElement . getBuilder ( )
. setStreamId ( sid )
2017-08-03 23:01:55 +02:00
. setDestinationAddress ( ourDstAddr )
2017-08-05 00:43:54 +02:00
. setMode ( mode ) ;
2017-07-19 23:15:17 +02:00
2017-08-03 15:11:34 +02:00
for ( JingleTransportCandidate < ? > candidate : getOurCandidates ( ) ) {
2017-07-21 17:58:57 +02:00
builder . addTransportCandidate ( ( JingleS5BTransportCandidateElement ) candidate . getElement ( ) ) ;
2017-07-19 23:15:17 +02:00
}
return builder . build ( ) ;
}
2017-07-21 23:05:46 +02:00
public String getSid ( ) {
return sid ;
}
2017-08-03 23:01:55 +02:00
public String getOurDstAddr ( ) {
return ourDstAddr ;
2017-07-21 17:58:57 +02:00
}
2017-08-03 23:01:55 +02:00
public String getTheirDstAddr ( ) {
return theirDstAddr ;
}
2017-08-05 00:43:54 +02:00
public Bytestream . Mode getMode ( ) {
return mode ;
2017-07-21 17:58:57 +02:00
}
2017-07-19 23:15:17 +02:00
@Override
public String getNamespace ( ) {
return NAMESPACE ;
}
@Override
2017-07-27 22:23:10 +02:00
public void establishIncomingBytestreamSession ( XMPPConnection connection , JingleTransportCallback callback , JingleSession session )
2017-07-21 23:05:46 +02:00
throws SmackException . NotConnectedException , InterruptedException {
2017-07-27 18:09:49 +02:00
this . callback = callback ;
2017-07-25 20:25:36 +02:00
establishBytestreamSession ( connection ) ;
2017-07-19 23:15:17 +02:00
}
2017-08-03 23:01:55 +02:00
@Override
public void prepare ( XMPPConnection connection ) {
JingleSession session = getParent ( ) . getParent ( ) ;
if ( getOurDstAddr ( ) = = null ) {
2017-08-04 22:48:33 +02:00
ourDstAddr = Socks5Utils . createDigest ( session . getSessionId ( ) , session . getOurJid ( ) , session . getPeer ( ) ) ;
2017-08-03 23:01:55 +02:00
Socks5Proxy . getSocks5Proxy ( ) . addTransfer ( ourDstAddr ) ;
}
2017-08-05 00:43:54 +02:00
if ( mode = = null ) {
mode = Bytestream . Mode . tcp ;
2017-08-03 23:01:55 +02:00
}
if ( getOurCandidates ( ) . size ( ) = = 0 ) {
List < JingleTransportCandidate < ? > > candidates = JingleS5BTransportManager . getInstanceFor ( connection ) . collectCandidates ( ) ;
for ( JingleTransportCandidate < ? > c : candidates ) {
addOurCandidate ( c ) ;
}
}
}
2017-07-19 23:15:17 +02:00
@Override
2017-07-27 22:23:10 +02:00
public void establishOutgoingBytestreamSession ( XMPPConnection connection , JingleTransportCallback callback , JingleSession session )
2017-07-21 23:05:46 +02:00
throws SmackException . NotConnectedException , InterruptedException {
2017-07-27 18:09:49 +02:00
this . callback = callback ;
2017-07-25 20:25:36 +02:00
establishBytestreamSession ( connection ) ;
2017-07-21 23:05:46 +02:00
}
2017-08-05 14:30:00 +02:00
@SuppressWarnings ( " ReferenceEquality " )
2017-07-25 20:25:36 +02:00
void establishBytestreamSession ( XMPPConnection connection )
2017-07-21 23:05:46 +02:00
throws SmackException . NotConnectedException , InterruptedException {
2017-08-03 23:01:55 +02:00
Socks5Proxy . getSocks5Proxy ( ) . addTransfer ( ourDstAddr ) ;
2017-07-21 23:05:46 +02:00
JingleS5BTransportManager transportManager = JingleS5BTransportManager . getInstanceFor ( connection ) ;
2017-08-03 15:11:34 +02:00
this . ourSelectedCandidate = connectToCandidates ( MAX_TIMEOUT ) ;
2017-07-21 23:05:46 +02:00
2017-08-03 15:11:34 +02:00
if ( ourSelectedCandidate = = CANDIDATE_FAILURE ) {
2017-07-21 23:05:46 +02:00
connection . createStanzaCollectorAndSend ( transportManager . createCandidateError ( this ) ) ;
2017-07-22 00:26:50 +02:00
return ;
2017-07-21 23:05:46 +02:00
}
2017-08-03 15:11:34 +02:00
if ( ourSelectedCandidate = = null ) {
2017-07-22 00:26:50 +02:00
throw new AssertionError ( " MUST NOT BE NULL. " ) ;
}
2017-07-19 23:15:17 +02:00
2017-08-03 15:11:34 +02:00
connection . createStanzaCollectorAndSend ( transportManager . createCandidateUsed ( this , ourSelectedCandidate ) ) ;
2017-07-22 01:01:50 +02:00
connectIfReady ( ) ;
2017-07-19 23:15:17 +02:00
}
2017-08-05 14:30:00 +02:00
@SuppressWarnings ( " ReferenceEquality " )
2017-07-21 18:31:42 +02:00
public JingleS5BTransportCandidate connectToCandidates ( int timeout ) {
2017-08-03 15:11:34 +02:00
if ( getTheirCandidates ( ) . size ( ) = = 0 ) {
return CANDIDATE_FAILURE ;
}
int _timeout = timeout / getTheirCandidates ( ) . size ( ) ; //TODO: Wise?
for ( JingleTransportCandidate < ? > c : getTheirCandidates ( ) ) {
JingleS5BTransportCandidate candidate = ( JingleS5BTransportCandidate ) c ;
2017-07-21 18:29:27 +02:00
try {
2017-08-03 15:11:34 +02:00
return candidate . connect ( _timeout , true ) ;
2017-07-21 18:29:27 +02:00
} catch ( IOException | TimeoutException | InterruptedException | SmackException | XMPPException e ) {
2017-07-27 23:31:04 +02:00
LOGGER . log ( Level . WARNING , " Exception while connecting to candidate: " + e , e ) ;
2017-07-21 18:29:27 +02:00
}
}
2017-07-21 18:31:42 +02:00
// Failed to connect to any candidate.
2017-07-21 23:51:06 +02:00
return CANDIDATE_FAILURE ;
2017-07-21 18:29:27 +02:00
}
2017-08-04 15:08:49 +02:00
@Override
public void cleanup ( ) {
Socks5Proxy . getSocks5Proxy ( ) . removeTransfer ( ourDstAddr ) ;
}
2017-08-05 14:30:00 +02:00
@SuppressWarnings ( " ReferenceEquality " )
2017-07-22 00:26:50 +02:00
void connectIfReady ( ) {
2017-08-04 14:06:12 +02:00
final JingleS5BTransportManager jingleS5BTransportManager = JingleS5BTransportManager . getInstanceFor ( getParent ( ) . getParent ( ) . getJingleManager ( ) . getConnection ( ) ) ;
final JingleSession session = getParent ( ) . getParent ( ) ;
2017-07-22 00:26:50 +02:00
2017-08-03 15:11:34 +02:00
if ( ourSelectedCandidate = = null | | theirSelectedCandidate = = null ) {
2017-07-22 00:26:50 +02:00
// Not yet ready if we or peer did not yet decide on a candidate.
LOGGER . log ( Level . INFO , " Not ready. " ) ;
return ;
}
2017-08-03 15:11:34 +02:00
if ( ourSelectedCandidate = = CANDIDATE_FAILURE & & theirSelectedCandidate = = CANDIDATE_FAILURE ) {
2017-07-22 00:26:50 +02:00
LOGGER . log ( Level . INFO , " Failure. " ) ;
2017-07-27 18:09:49 +02:00
callback . onTransportFailed ( new FailedTransportException ( null ) ) ;
2017-07-22 00:26:50 +02:00
return ;
}
2017-08-02 20:52:52 +02:00
LOGGER . log ( Level . INFO , ( session . isInitiator ( ) ? " Initiator " : " Responder " ) + " is ready. " ) ;
2017-07-22 00:26:50 +02:00
//Determine nominated candidate.
JingleS5BTransportCandidate nominated ;
2017-08-03 15:11:34 +02:00
if ( ourSelectedCandidate ! = CANDIDATE_FAILURE & & theirSelectedCandidate ! = CANDIDATE_FAILURE ) {
2017-07-25 20:25:36 +02:00
2017-08-03 15:11:34 +02:00
if ( ourSelectedCandidate . getPriority ( ) > theirSelectedCandidate . getPriority ( ) ) {
nominated = ourSelectedCandidate ;
} else if ( ourSelectedCandidate . getPriority ( ) < theirSelectedCandidate . getPriority ( ) ) {
nominated = theirSelectedCandidate ;
2017-07-22 00:26:50 +02:00
} else {
2017-08-03 15:11:34 +02:00
nominated = getParent ( ) . getParent ( ) . isInitiator ( ) ? ourSelectedCandidate : theirSelectedCandidate ;
2017-07-22 00:26:50 +02:00
}
2017-07-25 20:25:36 +02:00
2017-08-03 15:11:34 +02:00
} else if ( ourSelectedCandidate ! = CANDIDATE_FAILURE ) {
nominated = ourSelectedCandidate ;
2017-07-22 00:26:50 +02:00
} else {
2017-08-03 15:11:34 +02:00
nominated = theirSelectedCandidate ;
2017-07-22 00:26:50 +02:00
}
2017-08-04 14:06:12 +02:00
boolean isProxy = nominated . getType ( ) = = JingleS5BTransportCandidateElement . Type . proxy ;
2017-08-03 15:11:34 +02:00
if ( nominated = = theirSelectedCandidate ) {
2017-07-25 20:25:36 +02:00
2017-07-22 00:26:50 +02:00
LOGGER . log ( Level . INFO , " Their choice, so our proposed candidate is used. " ) ;
2017-07-25 20:25:36 +02:00
2017-07-22 00:26:50 +02:00
try {
2017-08-01 17:12:27 +02:00
nominated = nominated . connect ( MAX_TIMEOUT , false ) ;
2017-07-22 00:26:50 +02:00
} catch ( InterruptedException | IOException | XMPPException | SmackException | TimeoutException e ) {
LOGGER . log ( Level . INFO , " Could not connect to our candidate. " , e ) ;
2017-08-04 14:06:12 +02:00
Async . go ( new Runnable ( ) {
@Override
public void run ( ) {
try {
session . getJingleManager ( ) . getConnection ( ) . createStanzaCollectorAndSend ( jingleS5BTransportManager . createProxyError ( JingleS5BTransport . this ) ) ;
} catch ( SmackException . NotConnectedException | InterruptedException e1 ) {
LOGGER . log ( Level . SEVERE , " Could not send proxy error: " + e , e ) ;
}
}
} ) ;
2017-07-27 18:09:49 +02:00
callback . onTransportFailed ( new S5BTransportException . CandidateError ( e ) ) ;
2017-07-22 00:26:50 +02:00
return ;
}
2017-08-02 20:52:52 +02:00
if ( isProxy ) {
2017-07-22 00:26:50 +02:00
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 ) ;
2017-07-27 18:09:49 +02:00
callback . onTransportFailed ( new S5BTransportException . ProxyError ( e ) ) ;
2017-07-22 00:26:50 +02:00
return ;
}
}
2017-08-01 17:12:27 +02:00
LOGGER . log ( Level . INFO , " Start transmission on " + nominated . getCandidateId ( ) ) ;
2017-07-25 20:25:36 +02:00
this . bytestreamSession = new Socks5BytestreamSession ( nominated . getSocket ( ) , ! isProxy ) ;
2017-07-27 18:09:49 +02:00
callback . onTransportReady ( this . bytestreamSession ) ;
2017-07-22 00:26:50 +02:00
}
//Our choice
else {
LOGGER . log ( Level . INFO , " Our choice, so their candidate was used. " ) ;
if ( ! isProxy ) {
2017-08-01 17:12:27 +02:00
LOGGER . log ( Level . INFO , " Start transmission on " + nominated . getCandidateId ( ) ) ;
2017-07-25 20:25:36 +02:00
this . bytestreamSession = new Socks5BytestreamSession ( nominated . getSocket ( ) , true ) ;
2017-07-27 18:09:49 +02:00
callback . onTransportReady ( this . bytestreamSession ) ;
2017-07-22 00:26:50 +02:00
} else {
LOGGER . log ( Level . INFO , " Our choice was their external proxy. wait for candidate-activate. " ) ;
}
}
}
2017-08-02 20:52:52 +02:00
private void activateProxy ( JingleS5BTransportCandidate candidate ) throws SmackException . NotConnectedException , InterruptedException , XMPPException . XMPPErrorException , SmackException . NoResponseException {
2017-08-04 14:06:12 +02:00
LOGGER . log ( Level . INFO , " Activate proxy: " + candidate . getCandidateId ( ) + " " + candidate . getStreamHost ( ) . getAddress ( ) + " : " + candidate . getStreamHost ( ) . getPort ( ) + " " + candidate . getStreamHost ( ) . getJID ( ) + " for " + getParent ( ) . getParent ( ) . getPeer ( ) ) ;
2017-08-02 20:52:52 +02:00
Bytestream activate = new Bytestream ( getSid ( ) ) ;
activate . setMode ( null ) ;
activate . setType ( IQ . Type . set ) ;
activate . setTo ( candidate . getStreamHost ( ) . getJID ( ) ) ;
activate . setToActivate ( getParent ( ) . getParent ( ) . getPeer ( ) ) ;
activate . setFrom ( getParent ( ) . getParent ( ) . getOurJid ( ) ) ;
getParent ( ) . getParent ( ) . getJingleManager ( ) . getConnection ( ) . createStanzaCollectorAndSend ( activate ) . nextResultOrThrow ( ) ;
}
2017-08-04 14:06:12 +02:00
@Override
public void handleSessionAccept ( JingleContentTransportElement transportElement , XMPPConnection connection ) {
JingleS5BTransportElement transport = ( JingleS5BTransportElement ) transportElement ;
theirDstAddr = transport . getDestinationAddress ( ) ;
for ( JingleContentTransportCandidateElement c : transport . getCandidates ( ) ) {
JingleS5BTransportCandidateElement candidate = ( JingleS5BTransportCandidateElement ) c ;
addTheirCandidate ( new JingleS5BTransportCandidate ( candidate ) ) ;
}
}
2017-07-19 23:15:17 +02:00
@Override
2017-07-29 22:21:36 +02:00
public IQ handleTransportInfo ( JingleContentTransportInfoElement info , JingleElement wrapping ) {
2017-07-19 23:15:17 +02:00
switch ( info . getElementName ( ) ) {
case JingleS5BTransportInfoElement . CandidateUsed . ELEMENT :
2017-07-22 00:26:50 +02:00
handleCandidateUsed ( ( JingleS5BTransportInfoElement ) info , wrapping ) ;
2017-07-29 22:21:36 +02:00
break ;
2017-07-19 23:15:17 +02:00
case JingleS5BTransportInfoElement . CandidateActivated . ELEMENT :
handleCandidateActivate ( ( JingleS5BTransportInfoElement ) info ) ;
2017-07-29 22:21:36 +02:00
break ;
2017-07-19 23:15:17 +02:00
case JingleS5BTransportInfoElement . CandidateError . ELEMENT :
handleCandidateError ( ( JingleS5BTransportInfoElement ) info ) ;
2017-07-29 22:21:36 +02:00
break ;
2017-07-19 23:15:17 +02:00
case JingleS5BTransportInfoElement . ProxyError . ELEMENT :
handleProxyError ( ( JingleS5BTransportInfoElement ) info ) ;
2017-07-29 22:21:36 +02:00
break ;
2017-07-19 23:15:17 +02:00
default :
throw new AssertionError ( " Unknown transport-info element: " + info . getElementName ( ) ) ;
}
2017-07-29 22:21:36 +02:00
return IQ . createResultIQ ( wrapping ) ;
2017-07-19 23:15:17 +02:00
}
2017-07-22 00:26:50 +02:00
private void handleCandidateUsed ( JingleS5BTransportInfoElement info , JingleElement wrapping ) {
JingleManager jingleManager = getParent ( ) . getParent ( ) . getJingleManager ( ) ;
2017-07-19 23:15:17 +02:00
String candidateId = ( ( JingleS5BTransportInfoElement . CandidateUsed ) info ) . getCandidateId ( ) ;
2017-07-22 00:26:50 +02:00
// Received second candidate-used -> out-of-order!
2017-08-03 15:11:34 +02:00
if ( theirSelectedCandidate ! = null ) {
2017-07-22 00:26:50 +02:00
try {
2017-08-01 17:12:27 +02:00
jingleManager . getConnection ( ) . sendStanza ( JingleElement . createJingleErrorOutOfOrder ( wrapping ) ) ;
//jingleManager.getConnection().createStanzaCollectorAndSend(JingleElement.createJingleErrorOutOfOrder(wrapping));
2017-07-22 00:26:50 +02:00
} catch ( SmackException . NotConnectedException | InterruptedException e ) {
LOGGER . log ( Level . SEVERE , " Could not respond to candidate-used transport-info: " + e , e ) ;
}
2017-07-21 18:29:27 +02:00
return ;
}
2017-08-03 15:11:34 +02:00
Iterator < JingleTransportCandidate < ? > > ourCandidates = getOurCandidates ( ) . iterator ( ) ;
2017-07-21 18:29:27 +02:00
while ( ourCandidates . hasNext ( ) ) {
JingleS5BTransportCandidate candidate = ( JingleS5BTransportCandidate ) ourCandidates . next ( ) ;
if ( candidate . getCandidateId ( ) . equals ( candidateId ) ) {
2017-08-03 15:11:34 +02:00
theirSelectedCandidate = candidate ;
2017-07-21 18:29:27 +02:00
}
}
2017-08-03 15:11:34 +02:00
if ( theirSelectedCandidate = = null ) {
2017-08-01 17:12:27 +02:00
LOGGER . log ( Level . SEVERE , " ILLEGAL CANDIDATE ID!!! " ) ;
2017-07-21 18:29:27 +02:00
//TODO: Alert! Illegal candidateId!
2017-07-19 23:15:17 +02:00
}
2017-07-22 01:01:50 +02:00
connectIfReady ( ) ;
2017-07-19 23:15:17 +02:00
}
private void handleCandidateActivate ( JingleS5BTransportInfoElement info ) {
2017-08-03 15:11:34 +02:00
this . bytestreamSession = new Socks5BytestreamSession ( ourSelectedCandidate . getSocket ( ) ,
ourSelectedCandidate . getStreamHost ( ) . getJID ( ) . asBareJid ( ) . equals ( getParent ( ) . getParent ( ) . getPeer ( ) . asBareJid ( ) ) ) ;
2017-07-27 18:09:49 +02:00
callback . onTransportReady ( this . bytestreamSession ) ;
2017-07-19 23:15:17 +02:00
}
private void handleCandidateError ( JingleS5BTransportInfoElement info ) {
2017-08-03 15:11:34 +02:00
theirSelectedCandidate = CANDIDATE_FAILURE ;
2017-07-22 01:01:50 +02:00
connectIfReady ( ) ;
2017-07-19 23:15:17 +02:00
}
private void handleProxyError ( JingleS5BTransportInfoElement info ) {
2017-07-27 18:09:49 +02:00
callback . onTransportFailed ( new S5BTransportException . ProxyError ( null ) ) ;
2017-07-19 23:15:17 +02:00
}
/ * *
* Internal dummy candidate used to represent failure .
* Kinda depressing , isn ' t it ?
* /
private final static JingleS5BTransportCandidate CANDIDATE_FAILURE = new JingleS5BTransportCandidate ( null , null , - 1 , null ) ;
2017-07-27 11:37:32 +02:00
@Override
protected boolean isNonFatalException ( Exception exception ) {
return false ;
}
@Override
protected void handleStanza ( Stanza stanza ) throws SmackException . NotConnectedException , InterruptedException {
}
2017-07-19 23:15:17 +02:00
}