mirror of
https://github.com/vanitasvitae/Smack.git
synced 2025-09-10 17:49:38 +02:00
Rewrote Jingle code
This commit is contained in:
parent
a6b27f62d2
commit
df69c8a81c
25 changed files with 571 additions and 780 deletions
|
@ -585,7 +585,7 @@ public final class Socks5BytestreamManager extends Manager implements Bytestream
|
|||
* @param proxies a list of SOCKS5 proxy JIDs
|
||||
* @return a list of stream hosts containing the IP address an the port
|
||||
*/
|
||||
public List<StreamHost> determineStreamHostInfos(List<Jid> proxies) {
|
||||
private List<StreamHost> determineStreamHostInfos(List<Jid> proxies) {
|
||||
XMPPConnection connection = connection();
|
||||
List<StreamHost> streamHosts = new ArrayList<StreamHost>();
|
||||
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* 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;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.jivesoftware.smack.Manager;
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||
import org.jivesoftware.smackx.jingle.element.Jingle;
|
||||
import org.jivesoftware.smackx.jingle.element.JingleContentTransport;
|
||||
import org.jivesoftware.smackx.jingle.provider.JingleContentTransportProvider;
|
||||
import org.jxmpp.jid.Jid;
|
||||
|
||||
/**
|
||||
* Interface with methods that JingleContentTransportManagers must implement.
|
||||
*/
|
||||
public abstract class AbstractJingleContentTransportManager<D extends JingleContentTransport> extends Manager {
|
||||
|
||||
public AbstractJingleContentTransportManager(XMPPConnection connection) {
|
||||
super(connection);
|
||||
JingleTransportManager.getInstanceFor(connection).registerJingleContentTransportManager(this);
|
||||
JingleContentProviderManager.addJingleContentTransportProvider(getNamespace(), createJingleContentTransportProvider());
|
||||
ServiceDiscoveryManager.getInstanceFor(connection).addFeature(getNamespace());
|
||||
}
|
||||
|
||||
protected abstract JingleContentTransportProvider<D> createJingleContentTransportProvider();
|
||||
|
||||
public abstract String getNamespace();
|
||||
|
||||
public abstract void acceptInputStream(Jingle jingle, JingleTransportInputStreamCallback callback);
|
||||
|
||||
public abstract OutputStream createOutputStream(Jingle jingle);
|
||||
|
||||
public abstract D createJingleContentTransport(Jid remote) throws XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package org.jivesoftware.smackx.jingle;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jivesoftware.smack.Manager;
|
||||
import org.jivesoftware.smack.SmackException;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.XMPPException;
|
||||
import org.jivesoftware.smackx.bytestreams.BytestreamListener;
|
||||
import org.jivesoftware.smackx.bytestreams.BytestreamSession;
|
||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||
import org.jivesoftware.smackx.jingle.element.Jingle;
|
||||
import org.jivesoftware.smackx.jingle.element.JingleContentDescription;
|
||||
import org.jivesoftware.smackx.jingle.element.JingleContentTransport;
|
||||
import org.jivesoftware.smackx.jingle.provider.JingleContentTransportProvider;
|
||||
import org.jxmpp.jid.FullJid;
|
||||
|
||||
/**
|
||||
* Created by vanitas on 09.06.17.
|
||||
*/
|
||||
public abstract class JingleBytestreamManager<D extends JingleContentTransport>
|
||||
extends Manager {
|
||||
|
||||
public JingleBytestreamManager(XMPPConnection connection) {
|
||||
super(connection);
|
||||
JingleTransportManager.getInstanceFor(connection).registerJingleContentTransportManager(this);
|
||||
JingleContentProviderManager.addJingleContentTransportProvider(getNamespace(), createJingleContentTransportProvider());
|
||||
ServiceDiscoveryManager.getInstanceFor(connection).addFeature(getNamespace());
|
||||
}
|
||||
|
||||
protected abstract JingleContentTransportProvider<D> createJingleContentTransportProvider();
|
||||
|
||||
public abstract String getNamespace();
|
||||
|
||||
public Jingle createSessionInitiate(FullJid targetJID, JingleContentDescription application) throws XMPPException, IOException, InterruptedException, SmackException {
|
||||
return createSessionInitiate(targetJID, application, JingleTransportManager.generateRandomId());
|
||||
}
|
||||
|
||||
public abstract Jingle createSessionInitiate(FullJid targetJID, JingleContentDescription application, String sessionId) throws XMPPException, IOException, InterruptedException, SmackException;
|
||||
|
||||
public abstract Jingle createSessionAccept(Jingle request);
|
||||
|
||||
public abstract BytestreamSession outgoingInitiatedSession(Jingle jingle) throws Exception;
|
||||
|
||||
public abstract void setIncomingRespondedSessionListener(Jingle jingle, BytestreamListener listener);
|
||||
|
||||
}
|
|
@ -21,6 +21,6 @@ import org.jivesoftware.smackx.jingle.element.Jingle;
|
|||
|
||||
public interface JingleHandler {
|
||||
|
||||
IQ handleJingleRequest(Jingle jingle);
|
||||
IQ handleJingleSessionInitiate(Jingle jingle);
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
*/
|
||||
package org.jivesoftware.smackx.jingle;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
@ -54,7 +53,7 @@ public final class JingleManager extends Manager {
|
|||
}
|
||||
|
||||
private final Map<String, JingleHandler> descriptionHandlers = new ConcurrentHashMap<>();
|
||||
private final Map<FullJidAndSessionId, JingleSession> jingleSessions = new ConcurrentHashMap<>();
|
||||
private final Map<FullJidAndSessionId, JingleSessionHandler> jingleSessionHandlers = new ConcurrentHashMap<>();
|
||||
|
||||
private JingleManager(final XMPPConnection connection) {
|
||||
super(connection);
|
||||
|
@ -71,16 +70,16 @@ public final class JingleManager extends Manager {
|
|||
assert (from != null);
|
||||
FullJid fullFrom = from.asFullJidOrThrow();
|
||||
FullJidAndSessionId fullJidAndSessionId = new FullJidAndSessionId(fullFrom, jingle.getSid());
|
||||
JingleSession jingleSession = jingleSessions.get(fullJidAndSessionId);
|
||||
JingleSessionHandler jingleSessionHandler = jingleSessionHandlers.get(fullJidAndSessionId);
|
||||
|
||||
if (jingleSession == null) {
|
||||
if (jingleSessionHandler == null) {
|
||||
// Handle unknown session (XEP-0166 §10)
|
||||
XMPPError.Builder errorBuilder = XMPPError.getBuilder();
|
||||
errorBuilder.setCondition(XMPPError.Condition.item_not_found)
|
||||
.addExtension(JingleError.UNKNOWN_SESSION);
|
||||
return IQ.createErrorResponse(jingle, errorBuilder);
|
||||
}
|
||||
return jingleSession.handleRequest(jingle);
|
||||
return jingleSessionHandler.handleJingleSessionRequest(jingle, jingle.getSid());
|
||||
}
|
||||
|
||||
if (jingle.getContents().size() > 1) {
|
||||
|
@ -104,33 +103,41 @@ public final class JingleManager extends Manager {
|
|||
return response;
|
||||
}
|
||||
|
||||
return jingleDescriptionHandler.handleJingleRequest(jingle);
|
||||
return jingleDescriptionHandler.handleJingleSessionInitiate(jingle);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void registerJingleSession(JingleSession session) {
|
||||
FullJidAndSessionId jidAndSid = new FullJidAndSessionId(session.getRemote(), session.getSid());
|
||||
jingleSessions.put(jidAndSid, session);
|
||||
public void registerJingleSessionHandler(FullJid jid, String sessionId, JingleSessionHandler sessionHandler) {
|
||||
jingleSessionHandlers.put(new FullJidAndSessionId(jid, sessionId), sessionHandler);
|
||||
}
|
||||
|
||||
public void unregisterJingleSession(JingleSession session) {
|
||||
jingleSessions.values().removeAll(Collections.singleton(session));
|
||||
public void unregisterJingleSession(FullJid jid, String sessionId) {
|
||||
jingleSessionHandlers.remove(new FullJidAndSessionId(jid, sessionId));
|
||||
}
|
||||
|
||||
public JingleHandler registerDescriptionHandler(String namespace, JingleHandler handler) {
|
||||
return descriptionHandlers.put(namespace, handler);
|
||||
}
|
||||
|
||||
private static final class FullJidAndSessionId {
|
||||
public static final class FullJidAndSessionId {
|
||||
final FullJid fullJid;
|
||||
final String sessionId;
|
||||
|
||||
private FullJidAndSessionId(FullJid fullJid, String sessionId) {
|
||||
public FullJidAndSessionId(FullJid fullJid, String sessionId) {
|
||||
this.fullJid = fullJid;
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
|
||||
public FullJid getFullJid() {
|
||||
return fullJid;
|
||||
}
|
||||
|
||||
|
||||
public String getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = 31 * fullJid.hashCode();
|
||||
|
|
|
@ -1,247 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.packet.XMPPError;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smackx.jingle.element.Jingle;
|
||||
import org.jivesoftware.smackx.jingle.element.JingleAction;
|
||||
import org.jivesoftware.smackx.jingle.element.JingleContent;
|
||||
import org.jivesoftware.smackx.jingle.element.JingleError;
|
||||
import org.jivesoftware.smackx.jingle.element.JingleReason;
|
||||
import org.jxmpp.jid.FullJid;
|
||||
|
||||
/**
|
||||
* JingleSession.
|
||||
*/
|
||||
public abstract class JingleSession {
|
||||
|
||||
public enum State {
|
||||
fresh,
|
||||
pending,
|
||||
accepted,
|
||||
terminated,
|
||||
}
|
||||
|
||||
protected final XMPPConnection connection;
|
||||
protected final FullJid initiator;
|
||||
protected final FullJid responder;
|
||||
protected final FullJid ourJid;
|
||||
protected final FullJid remote;
|
||||
protected final String sid;
|
||||
protected State sessionState;
|
||||
protected List<JingleContent> contents;
|
||||
|
||||
public JingleSession(XMPPConnection connection, FullJid remote, FullJid initiator, FullJid responder, String sid) {
|
||||
this.connection = connection;
|
||||
this.ourJid = connection.getUser();
|
||||
this.remote = remote;
|
||||
this.initiator = initiator;
|
||||
this.responder = responder;
|
||||
this.sid = sid;
|
||||
this.sessionState = State.fresh;
|
||||
}
|
||||
|
||||
public JingleSession(XMPPConnection connection, FullJid remote, FullJid initiator, FullJid responder) {
|
||||
this(connection, remote, initiator, responder, StringUtils.randomString(24));
|
||||
}
|
||||
|
||||
public JingleSession(XMPPConnection connection, Jingle initiate) {
|
||||
if (initiate.getAction() != JingleAction.session_initiate) {
|
||||
throw new AssertionError("Session cannot be created without session-initiate");
|
||||
}
|
||||
this.connection = connection;
|
||||
this.ourJid = connection.getUser();
|
||||
this.remote = initiate.getFrom().asFullJidIfPossible();
|
||||
this.initiator = initiate.getInitiator();
|
||||
this.responder = initiate.getResponder();
|
||||
this.sid = initiate.getSid();
|
||||
this.sessionState = State.fresh;
|
||||
}
|
||||
|
||||
public FullJid getInitiator() {
|
||||
return initiator;
|
||||
}
|
||||
|
||||
public FullJid getResponder() {
|
||||
return responder;
|
||||
}
|
||||
|
||||
public FullJid getRemote() {
|
||||
return remote;
|
||||
}
|
||||
|
||||
public FullJid getOurJid() {
|
||||
return ourJid;
|
||||
}
|
||||
|
||||
public String getSid() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
public State getSessionState() {
|
||||
return sessionState;
|
||||
}
|
||||
|
||||
public IQ handleRequest(Jingle jingle) {
|
||||
switch (jingle.getAction()) {
|
||||
case session_initiate:
|
||||
// Did we already get another session-initiate?
|
||||
if (sessionState != State.fresh) {
|
||||
return outOfOrder(jingle);
|
||||
}
|
||||
|
||||
//Keep local copy of contents
|
||||
contents = jingle.getContents();
|
||||
|
||||
onSessionInitiate(jingle);
|
||||
|
||||
return IQ.createResultIQ(jingle);
|
||||
|
||||
case session_accept:
|
||||
if (sessionState != State.pending) {
|
||||
return outOfOrder(jingle);
|
||||
}
|
||||
|
||||
onAccept(jingle);
|
||||
|
||||
return IQ.createResultIQ(jingle);
|
||||
|
||||
case session_terminate:
|
||||
|
||||
onTerminate(jingle);
|
||||
|
||||
return IQ.createResultIQ(jingle);
|
||||
|
||||
case content_add:
|
||||
//TODO: Inform listeners
|
||||
return IQ.createResultIQ(jingle);
|
||||
|
||||
default: return IQ.createResultIQ(jingle);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void onSessionInitiate(Jingle jingle);
|
||||
|
||||
public abstract void onAccept(Jingle jingle);
|
||||
|
||||
public abstract void onTerminate(Jingle jingle);
|
||||
|
||||
public IQ initiate(List<JingleContent> contents) {
|
||||
Jingle.Builder b = Jingle.getBuilder();
|
||||
b.setInitiator(initiator)
|
||||
.setAction(JingleAction.session_initiate)
|
||||
.setSessionId(sid);
|
||||
for (JingleContent c : contents) {
|
||||
b.addJingleContent(c);
|
||||
}
|
||||
|
||||
Jingle j = b.build();
|
||||
j.setTo(remote);
|
||||
j.setFrom(ourJid);
|
||||
this.sessionState = State.pending;
|
||||
return j;
|
||||
}
|
||||
|
||||
public IQ accept(Jingle jingle) {
|
||||
Jingle.Builder b = Jingle.getBuilder();
|
||||
b.setResponder(ourJid)
|
||||
.setAction(JingleAction.session_accept)
|
||||
.setSessionId(sid);
|
||||
for (JingleContent c : jingle.getContents()) {
|
||||
b.addJingleContent(c);
|
||||
}
|
||||
|
||||
Jingle j = b.build();
|
||||
j.setTo(remote);
|
||||
j.setFrom(ourJid);
|
||||
this.sessionState = State.accepted;
|
||||
return j;
|
||||
}
|
||||
|
||||
public IQ terminate(JingleReason.Reason reason) {
|
||||
Jingle.Builder b = Jingle.getBuilder();
|
||||
b.setAction(JingleAction.session_terminate)
|
||||
.setSessionId(sid)
|
||||
.setReason(reason);
|
||||
Jingle j = b.build();
|
||||
j.setTo(remote);
|
||||
j.setFrom(ourJid);
|
||||
this.sessionState = State.terminated;
|
||||
return b.build();
|
||||
}
|
||||
|
||||
public IQ terminateFormally() {
|
||||
return terminate(JingleReason.Reason.decline);
|
||||
}
|
||||
|
||||
//TODO Fix
|
||||
public IQ terminateAlternativeSession(String alternative) {
|
||||
Jingle.Builder b = Jingle.getBuilder();
|
||||
b.setAction(JingleAction.session_terminate)
|
||||
.setSessionId(sid)
|
||||
.setReason(JingleReason.Reason.alternative_session); //Set alt. sessionId
|
||||
Jingle j = b.build();
|
||||
j.setTo(remote);
|
||||
j.setFrom(ourJid);
|
||||
this.sessionState = State.terminated;
|
||||
return j;
|
||||
}
|
||||
|
||||
public IQ terminateSuccessfully() {
|
||||
return terminate(JingleReason.Reason.success);
|
||||
}
|
||||
|
||||
public IQ terminateBusy() {
|
||||
return terminate(JingleReason.Reason.busy);
|
||||
}
|
||||
|
||||
public IQ terminateUnsupportedTransports() {
|
||||
return terminate(JingleReason.Reason.unsupported_transports);
|
||||
}
|
||||
|
||||
public IQ terminateFailedTransport() {
|
||||
return terminate(JingleReason.Reason.failed_transport);
|
||||
}
|
||||
|
||||
public IQ terminateUnsupportedApplications() {
|
||||
return terminate(JingleReason.Reason.unsupported_applications);
|
||||
}
|
||||
|
||||
public IQ terminateFailedApplication() {
|
||||
return terminate(JingleReason.Reason.failed_application);
|
||||
}
|
||||
|
||||
public IQ terminateIncompatibleParameters() {
|
||||
return terminate(JingleReason.Reason.incompatible_parameters);
|
||||
}
|
||||
|
||||
public IQ unknownInitiator(Jingle jingle) {
|
||||
return IQ.createErrorResponse(jingle, XMPPError.Condition.service_unavailable);
|
||||
}
|
||||
|
||||
public IQ outOfOrder(Jingle jingle) {
|
||||
XMPPError.Builder b = XMPPError.getBuilder();
|
||||
b.setCondition(XMPPError.Condition.unexpected_request);
|
||||
b.addExtension(JingleError.OUT_OF_ORDER);
|
||||
return IQ.createErrorResponse(jingle, b);
|
||||
}
|
||||
}
|
|
@ -16,12 +16,15 @@
|
|||
*/
|
||||
package org.jivesoftware.smackx.jingle;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import org.jivesoftware.smack.Manager;
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smackx.jingle.element.Jingle;
|
||||
import org.jivesoftware.smackx.jingle.exception.UnsupportedJingleTransportException;
|
||||
|
||||
/**
|
||||
|
@ -31,7 +34,7 @@ public final class JingleTransportManager extends Manager {
|
|||
|
||||
public static final WeakHashMap<XMPPConnection, JingleTransportManager> INSTANCES = new WeakHashMap<>();
|
||||
|
||||
private final HashMap<String, AbstractJingleContentTransportManager<?>> contentTransportManagers = new HashMap<>();
|
||||
private final HashMap<String, JingleBytestreamManager<?>> contentTransportManagers = new HashMap<>();
|
||||
|
||||
private JingleTransportManager(XMPPConnection connection) {
|
||||
super(connection);
|
||||
|
@ -46,22 +49,30 @@ public final class JingleTransportManager extends Manager {
|
|||
return manager;
|
||||
}
|
||||
|
||||
public AbstractJingleContentTransportManager<?> getJingleContentTransportManager(String namespace) throws UnsupportedJingleTransportException {
|
||||
AbstractJingleContentTransportManager<?> manager = contentTransportManagers.get(namespace);
|
||||
public JingleBytestreamManager<?> getJingleContentTransportManager(String namespace) throws UnsupportedJingleTransportException {
|
||||
JingleBytestreamManager<?> manager = contentTransportManagers.get(namespace);
|
||||
if (manager == null) {
|
||||
throw new UnsupportedJingleTransportException("Cannot find registered JingleContentTransportManager for " + namespace);
|
||||
}
|
||||
return manager;
|
||||
}
|
||||
|
||||
public void registerJingleContentTransportManager(AbstractJingleContentTransportManager<?> manager) {
|
||||
public JingleBytestreamManager<?> getJingleContentTransportManager(Jingle jingle) throws UnsupportedJingleTransportException {
|
||||
return getJingleContentTransportManager(jingle.getContents().get(0).getJingleTransports().get(0).getNamespace());
|
||||
}
|
||||
|
||||
public void registerJingleContentTransportManager(JingleBytestreamManager<?> manager) {
|
||||
contentTransportManagers.put(manager.getNamespace(), manager);
|
||||
}
|
||||
|
||||
public void unregisterJingleContentTransportManager(AbstractJingleContentTransportManager<?> manager) {
|
||||
public void unregisterJingleContentTransportManager(JingleBytestreamManager<?> manager) {
|
||||
contentTransportManagers.remove(manager.getNamespace());
|
||||
}
|
||||
|
||||
public Collection<JingleBytestreamManager<?>> getAvailableJingleBytestreamManagers() {
|
||||
return Collections.unmodifiableCollection(contentTransportManagers.values());
|
||||
}
|
||||
|
||||
public static String generateRandomId() {
|
||||
return StringUtils.randomString(24);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package org.jivesoftware.smackx.jingle;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.jivesoftware.smackx.jingle.element.Jingle;
|
||||
|
||||
/**
|
||||
* Created by vanitas on 09.06.17.
|
||||
*/
|
||||
public class PendingJingleSession {
|
||||
|
||||
public PendingJingleSession(Jingle initiation, File file) {
|
||||
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue