1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2025-09-15 12:09:38 +02:00

Add Fault-tolerant for incoming IbbByteStream fallback

This commit is contained in:
cmeng-git 2018-12-17 09:03:25 +08:00
parent fb2a9b2167
commit d5edbc7a30
4 changed files with 78 additions and 14 deletions

View file

@ -299,6 +299,19 @@ public final class InBandBytestreamManager extends Manager implements Bytestream
this.ignoredBytestreamRequests.add(sessionID);
}
/**
* Use this method to clear the next incoming In-Band Bytestream request containing the given
* session ID.
* <p>
* This method should be used if you are awaiting an In-Band Bytestream request as a reply to
* another stanza (e.g. file transfer).
*
* @param sessionID to be be cleared
*/
public void removeIgnoredBytestreamRequest(String sessionID) {
this.ignoredBytestreamRequests.remove(sessionID);
}
/**
* Returns the default block size that is used for all outgoing in-band bytestreams for this
* connection.

View file

@ -216,18 +216,21 @@ public class InBandBytestreamSession implements BytestreamSession {
if (this.inputStream.isClosed && this.outputStream.isClosed) {
this.isClosed = true;
// send close request
Close close = new Close(this.byteStreamRequest.getSessionID());
close.setTo(this.remoteJID);
try {
connection.createStanzaCollectorAndSend(close).nextResultOrThrow();
}
catch (Exception e) {
// Sadly we are unable to use the IOException(Throwable) constructor because this
// constructor is only supported from Android API 9 on.
IOException ioException = new IOException();
ioException.initCause(e);
throw ioException;
// Do not send close stream IQ if on receive, otherwiese XMPPError: item-not-found - cancel
if (!in) {
// send close request
Close close = new Close(this.byteStreamRequest.getSessionID());
close.setTo(this.remoteJID);
try {
connection.createStanzaCollectorAndSend(close).nextResultOrThrow();
}
catch (Exception e) {
// Sadly we are unable to use the IOException(Throwable) constructor because this
// constructor is only supported from Android API 9 on.
IOException ioException = new IOException();
ioException.initCause(e);
throw ioException;
}
}
this.inputStream.cleanup();

View file

@ -65,11 +65,20 @@ public class FaultTolerantNegotiator extends StreamNegotiator {
@Override
public InputStream createIncomingStream(final StreamInitiation initiation) throws SmackException, XMPPErrorException, InterruptedException {
// This could be either an xep47 ibb 'open' iq or an xep65 streamhost iq
InputStream inputStream = null;
IQ initiationSet = initiateIncomingStream(connection(), initiation);
StreamNegotiator streamNegotiator = determineNegotiator(initiationSet);
return streamNegotiator.negotiateIncomingStream(initiationSet);
try {
inputStream = streamNegotiator.negotiateIncomingStream(initiationSet);
} catch (Exception ex) {
if ((streamNegotiator instanceof Socks5TransferNegotiator)
&& (secondaryNegotiator instanceof IBBTransferNegotiator)) {
inputStream = ((IBBTransferNegotiator) secondaryNegotiator).getIbbIncomingStream(initiation);
}
}
return inputStream;
}
private StreamNegotiator determineNegotiator(Stanza streamInitiation) {

View file

@ -18,13 +18,16 @@ package org.jivesoftware.smackx.filetransfer;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Logger;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamListener;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamRequest;
import org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession;
@ -46,6 +49,7 @@ import org.jxmpp.jid.Jid;
*/
public class IBBTransferNegotiator extends StreamNegotiator {
private static final Logger LOGGER = Logger.getLogger(IBBTransferNegotiator.class.getName());
private final InBandBytestreamManager manager;
/**
@ -114,7 +118,42 @@ public class IBBTransferNegotiator extends StreamNegotiator {
private ByteStreamRequest(InBandBytestreamManager manager, Open byteStreamRequest) {
super(manager, byteStreamRequest);
}
}
InputStream getIbbIncomingStream(final StreamInitiation initiation) throws InterruptedException, SmackException {
IbbBytestreamListener listener = new IbbBytestreamListener();
manager.removeIgnoredBytestreamRequest(initiation.getSessionID());
manager.addIncomingBytestreamListener(listener);
return listener.getStream();
}
private static class IbbBytestreamListener extends InBandBytestreamListener {
InputStream inputStream = null;
public InputStream getStream() throws InterruptedException, SmackException {
int wait = 50; // wait for 10 seconds
do {
Thread.sleep(200);
if (wait-- < 0) {
throw new SmackException("IBB fallback incoming stream wait timed out");
}
} while (inputStream == null);
return inputStream;
}
@Override
public void incomingBytestreamRequest(InBandBytestreamRequest request) {
try {
InBandBytestreamSession session = request.accept();
session.setCloseBothStreamsEnabled(false);
inputStream = session.getInputStream();
} catch (SmackException.NotConnectedException | InterruptedException e) {
LOGGER.warning("Error in InBand Bytestream Request: " + e.getMessage());
}
}
}
}