mirror of
https://github.com/vanitasvitae/Smack.git
synced 2025-09-15 03:59:38 +02:00
Add Fault-tolerant for incoming IbbByteStream fallback
This commit is contained in:
parent
fb2a9b2167
commit
d5edbc7a30
4 changed files with 78 additions and 14 deletions
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue