From 60233503648a82075cc4188042bca0a0ab686915 Mon Sep 17 00:00:00 2001 From: vanitasvitae Date: Wed, 21 Jun 2017 14:11:42 +0200 Subject: [PATCH] Progress --- .../IncomingJingleFileOffer.java | 71 ++++++++++---- .../JingleFileTransferManager.java | 1 + .../JingleFileTransferSession.java | 18 ---- .../OutgoingJingleFileOffer.java | 98 ++++++------------- .../jingle_filetransfer/SendingThread.java | 82 ++++++++++++++++ .../smackx/jingle/JingleSession.java | 14 +-- .../jingle/JingleTransportMethodManager.java | 2 +- .../smackx/jingle/JingleUtil.java | 10 +- .../JingleTransportInitiationCallback.java | 16 +++ .../transports/JingleTransportNegotiator.java | 16 +++ 10 files changed, 212 insertions(+), 116 deletions(-) create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/SendingThread.java diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/IncomingJingleFileOffer.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/IncomingJingleFileOffer.java index e15fe552e..46e8311be 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/IncomingJingleFileOffer.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/IncomingJingleFileOffer.java @@ -29,7 +29,6 @@ import org.jivesoftware.smackx.jingle.Role; import org.jivesoftware.smackx.jingle.element.Jingle; import org.jivesoftware.smackx.jingle.element.JingleContent; import org.jivesoftware.smackx.jingle.element.JingleContentTransport; -import org.jivesoftware.smackx.jingle.transports.JingleTransportManager; import org.jivesoftware.smackx.jingle_filetransfer.callback.IncomingFileOfferCallback; import org.jivesoftware.smackx.jingle_filetransfer.element.JingleFileTransfer; @@ -40,6 +39,18 @@ import org.jxmpp.jid.FullJid; */ public class IncomingJingleFileOffer extends JingleFileTransferSession implements IncomingFileOfferCallback { private static final Logger LOGGER = Logger.getLogger(IncomingJingleFileOffer.class.getName()); + private Jingle pendingSessionInitiate = null; + + public enum State { + fresh, + pending, + sent_transport_replace, + active, + terminated, + ; + } + + private State state; public IncomingJingleFileOffer(XMPPConnection connection, FullJid initiator, String sid) { super(connection, initiator, connection.getUser().asFullJidOrThrow(), Role.responder, sid, Type.offer); @@ -50,9 +61,10 @@ public class IncomingJingleFileOffer extends JingleFileTransferSession implement } @Override - public IQ handleSessionInitiate(Jingle initiate) { + public IQ handleSessionInitiate(Jingle initiate) throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException { + JingleTransportMethodManager tm = JingleTransportMethodManager.getInstanceFor(connection); - if (getState() != State.fresh) { + if (state != State.fresh) { //Out of order (initiate after accept) return jutil.createErrorOutOfOrder(initiate); } @@ -61,29 +73,53 @@ public class IncomingJingleFileOffer extends JingleFileTransferSession implement this.creator = content.getCreator(); this.file = (JingleFileTransfer) content.getDescription(); this.name = content.getName(); - this.transport = content.getJingleTransports().get(0); + this.transport = content.getJingleTransport(); + this.transportManager = tm.getTransportManager(initiate); + + if (transportManager == null) { + //Fallback + pendingSessionInitiate = initiate; + transportManager = tm.getBestAvailableTransportManager(); + + if (transportManager == null) { + jutil.sendSessionTerminateUnsupportedTransports(initiate.getInitiator(), initiate.getSid()); + state = State.terminated; + return jutil.createAck(initiate); + } + + transport = transportManager.createTransport(); + jutil.sendTransportReplace(initiate.getFrom().asFullJidOrThrow(), initiate.getInitiator(), + initiate.getSid(), creator, name, transport); + state = State.sent_transport_replace; + return jutil.createAck(initiate); + } JingleFileTransferManager.getInstanceFor(connection).notifyIncomingFileOffer(initiate, this); - setState(State.pending); + state = State.pending; return jutil.createAck(initiate); } @Override - public void acceptIncomingFileOffer(Jingle request, File target) { - FullJid recipient = request.getInitiator(); - String sid = request.getSid(); - JingleContent content = request.getContents().get(0); + public IQ handleTransportAccept(Jingle transportAccept) { - //Get TransportManager - JingleTransportManager transportManager = JingleTransportMethodManager.getInstanceFor(connection) - .getTransportManager(request); + if (state != State.sent_transport_replace) { + return jutil.createErrorOutOfOrder(transportAccept); + } + + JingleFileTransferManager.getInstanceFor(connection).notifyIncomingFileOffer(pendingSessionInitiate, this); + transport = transportAccept.getContents().get(0).getJingleTransport(); + state = State.pending; + return jutil.createAck(transportAccept); + } + + @Override + public void acceptIncomingFileOffer(Jingle request, File target) { if (transportManager == null) { //Unsupported transport LOGGER.log(Level.WARNING, "Unsupported Transport method."); - setState(State.terminated); try { - jutil.sendSessionTerminateUnsupportedTransports(recipient, sid); + jutil.sendSessionTerminateUnsupportedTransports(request.getFrom().asFullJidOrThrow(), sid); } catch (InterruptedException | SmackException.NoResponseException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) { LOGGER.log(Level.SEVERE, "Could not send session-terminate: " + e, e); } @@ -92,9 +128,8 @@ public class IncomingJingleFileOffer extends JingleFileTransferSession implement JingleContentTransport transport = transportManager.createTransport(request); try { - jutil.sendSessionAccept(recipient, sid, content.getCreator(), content.getName(), content.getSenders(), - content.getDescription(), transport); - setState(State.active); + jutil.sendSessionAccept(getInitiator(), sid, creator, name, JingleContent.Senders.initiator, file, transport); + state = State.active; } catch (SmackException.NotConnectedException | SmackException.NoResponseException | XMPPException.XMPPErrorException | InterruptedException e) { LOGGER.log(Level.SEVERE, "Could not send session-accept: " + e, e); } @@ -102,7 +137,7 @@ public class IncomingJingleFileOffer extends JingleFileTransferSession implement @Override public void declineIncomingFileOffer(Jingle request) { - setState(State.terminated); + state = State.terminated; try { jutil.sendSessionTerminateDecline(request.getInitiator(), request.getSid()); } catch (SmackException.NotConnectedException | SmackException.NoResponseException | XMPPException.XMPPErrorException | InterruptedException e) { diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java index 568f5cee6..07274ef19 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferManager.java @@ -77,6 +77,7 @@ public final class JingleFileTransferManager extends Manager implements JingleHa } JingleManager.getInstanceFor(connection()).registerJingleSessionHandler(fullJid, sid, handler); + return handler.handleJingleSessionRequest(jingle); } diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferSession.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferSession.java index e46809706..5ccdeebd6 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferSession.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/JingleFileTransferSession.java @@ -38,14 +38,6 @@ public abstract class JingleFileTransferSession extends JingleSession { ; } - public enum State { - fresh, - pending, - active, - terminated, - ; - } - protected final XMPPConnection connection; protected final JingleUtil jutil; @@ -56,12 +48,10 @@ public abstract class JingleFileTransferSession extends JingleSession { protected JingleTransportManager transportManager; private final Type type; - private State state; public JingleFileTransferSession(XMPPConnection connection, FullJid initiator, FullJid responder, Role role, String sid, Type type) { super(initiator, responder, role, sid); this.type = type; - this.state = State.fresh; this.connection = connection; this.jutil = new JingleUtil(connection); } @@ -70,14 +60,6 @@ public abstract class JingleFileTransferSession extends JingleSession { return type; } - public State getState() { - return state; - } - - public void setState(State state) { - this.state = state; - } - public boolean isOffer() { return this.type == Type.offer; } diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/OutgoingJingleFileOffer.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/OutgoingJingleFileOffer.java index af104b087..514b1b47c 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/OutgoingJingleFileOffer.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/OutgoingJingleFileOffer.java @@ -17,10 +17,6 @@ package org.jivesoftware.smackx.jingle_filetransfer; import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.util.logging.Level; import java.util.logging.Logger; @@ -47,12 +43,23 @@ public class OutgoingJingleFileOffer extends JingleFileTransferSession { private static final Logger LOGGER = Logger.getLogger(OutgoingJingleFileOffer.class.getName()); + public enum State { + fresh, + pending, + sent_transport_replace, + active, + terminated, + ; + } + private Thread sendingThread; private File source; + private State state; public OutgoingJingleFileOffer(XMPPConnection connection, FullJid responder, String sid) { super(connection, connection.getUser().asFullJidOrThrow(), responder, Role.initiator, sid, Type.offer); + state = State.fresh; } public OutgoingJingleFileOffer(XMPPConnection connection, FullJid recipient) { @@ -60,7 +67,7 @@ public class OutgoingJingleFileOffer extends JingleFileTransferSession { } public void sendFile(JingleFileTransfer file, JingleContent.Creator creator, String name) throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException { - if (getState() == State.fresh) { + if (state == State.fresh) { transportManager = JingleTransportMethodManager.getInstanceFor(connection) .getBestAvailableTransportManager(); @@ -71,20 +78,28 @@ public class OutgoingJingleFileOffer extends JingleFileTransferSession { transport = transportManager.createTransport(); jutil.sendSessionInitiateFileOffer(getResponder(), getSessionId(), creator, name, file, transport); + state = State.pending; } } @Override - public IQ handleSessionAccept(Jingle sessionAccept) { - setState(State.active); - - transportManager.initiateOutgoingSession(transport, new JingleTransportInitiationCallback() { - @Override - public void onSessionInitiated(final BytestreamSession session) { - sendingThread = new SendingThread(session, source); - sendingThread.run(); - } - }); + public IQ handleSessionAccept(Jingle sessionAccept) throws SmackException.NotConnectedException, InterruptedException { + // Out of order? + if (state != State.pending) { + LOGGER.log(Level.WARNING, "Out of order!"); + jutil.sendErrorOutOfOrder(sessionAccept); + } + // Legal + else { + state = State.active; + transportManager.initiateOutgoingSession(transport, new JingleTransportInitiationCallback() { + @Override + public void onSessionInitiated(final BytestreamSession session) { + sendingThread = new SendingThread(session, source); + sendingThread.run(); + } + }); + } return jutil.createAck(sessionAccept); } @@ -96,7 +111,7 @@ public class OutgoingJingleFileOffer extends JingleFileTransferSession { sendingThread.interrupt(); } - setState(State.terminated); + state = State.terminated; return jutil.createAck(sessionTerminate); } @@ -115,55 +130,4 @@ public class OutgoingJingleFileOffer extends JingleFileTransferSession { return jutil.createAck(transportReplace); } - - private static class SendingThread extends Thread { - - private final BytestreamSession session; - private final File source; - - public SendingThread(BytestreamSession session, File source) { - this.session = session; - this.source = source; - } - - @Override - public void run() { - InputStream inputStream; - OutputStream outputStream; - - try { - inputStream = new FileInputStream(source); - outputStream = session.getOutputStream(); - - byte[] filebuf = new byte[(int) source.length()]; - int r = inputStream.read(filebuf); - - if (r < 0) { - throw new IOException("Read returned -1"); - } - - outputStream.write(filebuf); - } - catch (IOException e) { - LOGGER.log(Level.SEVERE, "Could not send file: " + e, e); - } - finally { - try { - session.close(); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Could not close session.", e); - } - } - } - - @Override - public void interrupt() { - try { - session.close(); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Could not close session.", e); - } - super.interrupt(); - } - } } diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/SendingThread.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/SendingThread.java new file mode 100644 index 000000000..441c140a6 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jingle_filetransfer/SendingThread.java @@ -0,0 +1,82 @@ +/** + * + * 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_filetransfer; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.jivesoftware.smackx.bytestreams.BytestreamSession; + +/** + * Created by vanitas on 21.06.17. + */ +public class SendingThread extends Thread { + private static final Logger LOGGER = Logger.getLogger(SendingThread.class.getName()); + + private final BytestreamSession session; + private final File source; + + public SendingThread(BytestreamSession session, File source) { + this.session = session; + this.source = source; + } + + @Override + public void run() { + InputStream inputStream; + OutputStream outputStream; + + try { + inputStream = new FileInputStream(source); + outputStream = session.getOutputStream(); + + byte[] filebuf = new byte[(int) source.length()]; + int r = inputStream.read(filebuf); + + if (r < 0) { + throw new IOException("Read returned -1"); + } + + outputStream.write(filebuf); + } + catch (IOException e) { + LOGGER.log(Level.SEVERE, "Could not send file: " + e, e); + } + finally { + try { + session.close(); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Could not close session.", e); + } + } + } + + @Override + public void interrupt() { + try { + session.close(); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Could not close session.", e); + } + super.interrupt(); + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSession.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSession.java index 473621a00..efaa52493 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSession.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleSession.java @@ -91,6 +91,7 @@ public abstract class JingleSession implements JingleSessionHandler { @Override public IQ handleJingleSessionRequest(Jingle jingle) { + try { switch (jingle.getAction()) { case content_accept: return handleContentAccept(jingle); @@ -121,17 +122,16 @@ public abstract class JingleSession implements JingleSessionHandler { case session_terminate: return handleSessionTerminate(jingle); case transport_replace: - try { - return handleTransportReplace(jingle); - } catch (InterruptedException | SmackException.NoResponseException | SmackException.NotConnectedException | XMPPException.XMPPErrorException e) { - e.printStackTrace(); - } + return handleTransportReplace(jingle); default: return IQ.createResultIQ(jingle); } + } catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) { + return null; //TODO: + } } - protected IQ handleSessionInitiate(Jingle sessionInitiate) { + protected IQ handleSessionInitiate(Jingle sessionInitiate) throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException { return IQ.createResultIQ(sessionInitiate); } @@ -143,7 +143,7 @@ public abstract class JingleSession implements JingleSessionHandler { return IQ.createResultIQ(sessionInfo); } - protected IQ handleSessionAccept(Jingle sessionAccept) { + protected IQ handleSessionAccept(Jingle sessionAccept) throws SmackException.NotConnectedException, InterruptedException { return IQ.createResultIQ(sessionAccept); } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportMethodManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportMethodManager.java index c46ff1974..72dc03279 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportMethodManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleTransportMethodManager.java @@ -70,7 +70,7 @@ public final class JingleTransportMethodManager extends Manager { return null; } - JingleContentTransport transport = content.getJingleTransports().get(0); + JingleContentTransport transport = content.getJingleTransport(); if (transport == null) { return null; } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleUtil.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleUtil.java index fa2e15e34..994bdcff7 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleUtil.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/JingleUtil.java @@ -60,7 +60,7 @@ public class JingleUtil { .setName(contentName) .setSenders(contentSenders) .setDescription(description) - .addTransport(transport); + .setTransport(transport); Jingle jingle = jb.addJingleContent(cb.build()).build(); jingle.setFrom(connection.getUser()); @@ -126,7 +126,7 @@ public class JingleUtil { .setName(contentName) .setSenders(contentSenders) .setDescription(description) - .addTransport(transport); + .setTransport(transport); Jingle jingle = jb.addJingleContent(cb.build()).build(); jingle.setTo(recipient); @@ -364,7 +364,7 @@ public class JingleUtil { .setAction(JingleAction.transport_replace); JingleContent.Builder cb = JingleContent.getBuilder(); - cb.setName(contentName).setCreator(contentCreator).addTransport(transport); + cb.setName(contentName).setCreator(contentCreator).setTransport(transport); Jingle jingle = jb.addJingleContent(cb.build()).build(); jingle.setTo(recipient); @@ -391,7 +391,7 @@ public class JingleUtil { .setSessionId(sessionId); JingleContent.Builder cb = JingleContent.getBuilder(); - cb.setCreator(contentCreator).setName(contentName).addTransport(transport); + cb.setCreator(contentCreator).setName(contentName).setTransport(transport); Jingle jingle = jb.addJingleContent(cb.build()).build(); jingle.setTo(recipient); @@ -418,7 +418,7 @@ public class JingleUtil { .setSessionId(sessionId); JingleContent.Builder cb = JingleContent.getBuilder(); - cb.setCreator(contentCreator).setName(contentName).addTransport(transport); + cb.setCreator(contentCreator).setName(contentName).setTransport(transport); Jingle jingle = jb.addJingleContent(cb.build()).build(); jingle.setTo(recipient); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportInitiationCallback.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportInitiationCallback.java index 964cf2fd0..3db3f91ea 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportInitiationCallback.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportInitiationCallback.java @@ -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; import org.jivesoftware.smackx.bytestreams.BytestreamSession; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportNegotiator.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportNegotiator.java index 9d6146cfc..797897b92 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportNegotiator.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transports/JingleTransportNegotiator.java @@ -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; /**