route jingle message inits

This commit is contained in:
Daniel Gultsch 2020-04-02 16:29:33 +02:00
parent a4acfb2a19
commit 385692ea28
10 changed files with 151 additions and 97 deletions

View file

@ -39,7 +39,8 @@ public abstract class AbstractGenerator {
Namespace.JINGLE_TRANSPORT_ICE_UDP, Namespace.JINGLE_TRANSPORT_ICE_UDP,
Namespace.JINGLE_FEATURE_AUDIO, Namespace.JINGLE_FEATURE_AUDIO,
Namespace.JINGLE_FEATURE_VIDEO, Namespace.JINGLE_FEATURE_VIDEO,
Namespace.JINGLE_APP_RTP, Namespace.JINGLE_APPS_RTP,
Namespace.JINGLE_APPS_DTLS,
"http://jabber.org/protocol/muc", "http://jabber.org/protocol/muc",
"jabber:x:conference", "jabber:x:conference",

View file

@ -6,6 +6,7 @@ import android.util.Pair;
import java.net.URL; import java.net.URL;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -50,6 +51,8 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss", Locale.ENGLISH); private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss", Locale.ENGLISH);
private static final List<String> JINGLE_MESSAGE_ELEMENT_NAMES = Arrays.asList("accept", "propose", "proceed", "reject", "retract");
public MessageParser(XmppConnectionService service) { public MessageParser(XmppConnectionService service) {
super(service); super(service);
} }
@ -809,6 +812,13 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
} }
} }
} }
if (!isTypeGroupChat) {
for (Element child : packet.getChildren()) {
if (Namespace.JINGLE_MESSAGE.equals(child.getNamespace()) && JINGLE_MESSAGE_ELEMENT_NAMES.contains(child.getName())) {
mXmppConnectionService.getJingleConnectionManager().deliverMessage(account, packet.getTo(), packet.getFrom(), child);
}
}
}
} }
Element received = packet.findChild("received", "urn:xmpp:chat-markers:0"); Element received = packet.findChild("received", "urn:xmpp:chat-markers:0");

View file

@ -27,19 +27,21 @@ public final class Namespace {
public static final String BOOKMARKS = "storage:bookmarks"; public static final String BOOKMARKS = "storage:bookmarks";
public static final String SYNCHRONIZATION = "im.quicksy.synchronization:0"; public static final String SYNCHRONIZATION = "im.quicksy.synchronization:0";
public static final String AVATAR_CONVERSION = "urn:xmpp:pep-vcard-conversion:0"; public static final String AVATAR_CONVERSION = "urn:xmpp:pep-vcard-conversion:0";
public static final String JINGLE = "urn:xmpp:jingle:1";
public static final String JINGLE_MESSAGE = "urn:xmpp:jingle-message:0";
public static final String JINGLE_ENCRYPTED_TRANSPORT = "urn:xmpp:jingle:jet:0";
public static final String JINGLE_ENCRYPTED_TRANSPORT_OMEMO = "urn:xmpp:jingle:jet-omemo:0";
public static final String JINGLE_TRANSPORTS_S5B = "urn:xmpp:jingle:transports:s5b:1"; public static final String JINGLE_TRANSPORTS_S5B = "urn:xmpp:jingle:transports:s5b:1";
public static final String JINGLE_TRANSPORTS_IBB = "urn:xmpp:jingle:transports:ibb:1"; public static final String JINGLE_TRANSPORTS_IBB = "urn:xmpp:jingle:transports:ibb:1";
public static final String JINGLE_TRANSPORT_ICE_UDP = "urn:xmpp:jingle:transports:ice-udp:1"; public static final String JINGLE_TRANSPORT_ICE_UDP = "urn:xmpp:jingle:transports:ice-udp:1";
public static final String JINGLE_APP_RTP = "urn:xmpp:jingle:apps:rtp:1"; public static final String JINGLE_APPS_RTP = "urn:xmpp:jingle:apps:rtp:1";
public static final String JINGLE_APPS_DTLS = "urn:xmpp:jingle:apps:dtls:0";
public static final String JINGLE_FEATURE_AUDIO = "urn:xmpp:jingle:apps:rtp:audio"; public static final String JINGLE_FEATURE_AUDIO = "urn:xmpp:jingle:apps:rtp:audio";
public static final String JINGLE_FEATURE_VIDEO = "urn:xmpp:jingle:apps:rtp:video"; public static final String JINGLE_FEATURE_VIDEO = "urn:xmpp:jingle:apps:rtp:video";
public static final String IBB = "http://jabber.org/protocol/ibb"; public static final String IBB = "http://jabber.org/protocol/ibb";
public static final String PING = "urn:xmpp:ping"; public static final String PING = "urn:xmpp:ping";
public static final String PUSH = "urn:xmpp:push:0"; public static final String PUSH = "urn:xmpp:push:0";
public static final String COMMANDS = "http://jabber.org/protocol/commands"; public static final String COMMANDS = "http://jabber.org/protocol/commands";
public static final String JINGLE = "urn:xmpp:jingle:1";
public static final String JINGLE_ENCRYPTED_TRANSPORT = "urn:xmpp:jingle:jet:0";
public static final String JINGLE_ENCRYPTED_TRANSPORT_OMEMO = "urn:xmpp:jingle:jet-omemo:0";
public static final String MUC_USER = "http://jabber.org/protocol/muc#user"; public static final String MUC_USER = "http://jabber.org/protocol/muc#user";
public static final String BOOKMARKS2 = "urn:xmpp:bookmarks:0"; public static final String BOOKMARKS2 = "urn:xmpp:bookmarks:0";
public static final String BOOKMARKS2_COMPAT = BOOKMARKS2 + "#compat"; public static final String BOOKMARKS2_COMPAT = BOOKMARKS2 + "#compat";

View file

@ -30,14 +30,14 @@ public abstract class AbstractJingleConnection {
public static class Id { public static class Id {
public final Account account; public final Account account;
public final Jid counterPart; public final Jid with;
public final String sessionId; public final String sessionId;
private Id(final Account account, final Jid counterPart, final String sessionId) { private Id(final Account account, final Jid with, final String sessionId) {
Preconditions.checkNotNull(counterPart); Preconditions.checkNotNull(with);
Preconditions.checkArgument(counterPart.isFullJid()); Preconditions.checkArgument(with.isFullJid());
this.account = account; this.account = account;
this.counterPart = counterPart; this.with = with;
this.sessionId = sessionId; this.sessionId = sessionId;
} }
@ -45,6 +45,10 @@ public abstract class AbstractJingleConnection {
return new Id(account, jinglePacket.getFrom(), jinglePacket.getSessionId()); return new Id(account, jinglePacket.getFrom(), jinglePacket.getSessionId());
} }
public static Id of(Account account, Jid with, final String sessionId) {
return new Id(account, with, sessionId);
}
public static Id of(Message message) { public static Id of(Message message) {
return new Id( return new Id(
message.getConversation().getAccount(), message.getConversation().getAccount(),
@ -59,13 +63,13 @@ public abstract class AbstractJingleConnection {
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
Id id = (Id) o; Id id = (Id) o;
return Objects.equal(account.getJid(), id.account.getJid()) && return Objects.equal(account.getJid(), id.account.getJid()) &&
Objects.equal(counterPart, id.counterPart) && Objects.equal(with, id.with) &&
Objects.equal(sessionId, id.sessionId); Objects.equal(sessionId, id.sessionId);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hashCode(account.getJid(), counterPart, sessionId); return Objects.hashCode(account.getJid(), with, sessionId);
} }
} }
} }

View file

@ -22,6 +22,7 @@ import eu.siacs.conversations.xmpp.jingle.stanzas.Content;
import eu.siacs.conversations.xmpp.jingle.stanzas.FileTransferDescription; import eu.siacs.conversations.xmpp.jingle.stanzas.FileTransferDescription;
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket; import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
import eu.siacs.conversations.xmpp.stanzas.IqPacket; import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
import rocks.xmpp.addr.Jid; import rocks.xmpp.addr.Jid;
public class JingleConnectionManager extends AbstractConnectionManager { public class JingleConnectionManager extends AbstractConnectionManager {
@ -35,13 +36,16 @@ public class JingleConnectionManager extends AbstractConnectionManager {
public void deliverPacket(final Account account, final JinglePacket packet) { public void deliverPacket(final Account account, final JinglePacket packet) {
final AbstractJingleConnection.Id id = AbstractJingleConnection.Id.of(account, packet); final AbstractJingleConnection.Id id = AbstractJingleConnection.Id.of(account, packet);
if (packet.getAction() == JinglePacket.Action.SESSION_INITIATE) { //TODO check that id doesn't exist yet final AbstractJingleConnection existingJingleConnection = connections.get(id);
if (existingJingleConnection != null) {
existingJingleConnection.deliverPacket(packet);
} else if (packet.getAction() == JinglePacket.Action.SESSION_INITIATE) {
final Content content = packet.getJingleContent(); final Content content = packet.getJingleContent();
final String descriptionNamespace = content == null ? null : content.getDescriptionNamespace(); final String descriptionNamespace = content == null ? null : content.getDescriptionNamespace();
final AbstractJingleConnection connection; final AbstractJingleConnection connection;
if (FileTransferDescription.NAMESPACES.contains(descriptionNamespace)) { if (FileTransferDescription.NAMESPACES.contains(descriptionNamespace)) {
connection = new JingleFileTransferConnection(this, id); connection = new JingleFileTransferConnection(this, id);
} else if (Namespace.JINGLE_APP_RTP.equals(descriptionNamespace)) { } else if (Namespace.JINGLE_APPS_RTP.equals(descriptionNamespace)) {
connection = new JingleRtpConnection(this, id); connection = new JingleRtpConnection(this, id);
} else { } else {
//TODO return feature-not-implemented //TODO return feature-not-implemented
@ -49,21 +53,52 @@ public class JingleConnectionManager extends AbstractConnectionManager {
} }
connections.put(id, connection); connections.put(id, connection);
connection.deliverPacket(packet); connection.deliverPacket(packet);
} else {
final AbstractJingleConnection abstractJingleConnection = connections.get(id);
if (abstractJingleConnection != null) {
abstractJingleConnection.deliverPacket(packet);
} else { } else {
Log.d(Config.LOGTAG, "unable to route jingle packet: " + packet); Log.d(Config.LOGTAG, "unable to route jingle packet: " + packet);
IqPacket response = packet.generateResponse(IqPacket.TYPE.ERROR); final IqPacket response = packet.generateResponse(IqPacket.TYPE.ERROR);
Element error = response.addChild("error"); final Element error = response.addChild("error");
error.setAttribute("type", "cancel"); error.setAttribute("type", "cancel");
error.addChild("item-not-found", error.addChild("item-not-found", "urn:ietf:params:xml:ns:xmpp-stanzas");
"urn:ietf:params:xml:ns:xmpp-stanzas");
error.addChild("unknown-session", "urn:xmpp:jingle:errors:1"); error.addChild("unknown-session", "urn:xmpp:jingle:errors:1");
account.getXmppConnection().sendIqPacket(response, null); account.getXmppConnection().sendIqPacket(response, null);
} }
} }
public void deliverMessage(final Account account, final Jid to, final Jid from, final Element message) {
Preconditions.checkArgument(Namespace.JINGLE_MESSAGE.equals(message.getNamespace()));
final String sessionId = message.getAttribute("id");
if (sessionId == null) {
return;
}
final Jid with;
if (account.getJid().asBareJid().equals(from.asBareJid())) {
with = to;
} else {
with = from;
}
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": received jingle message from " + from + " with=" + with + " " + message);
final AbstractJingleConnection.Id id = AbstractJingleConnection.Id.of(account, with, sessionId);
final AbstractJingleConnection existingJingleConnection = connections.get(id);
if (existingJingleConnection != null) {
if (existingJingleConnection instanceof JingleRtpConnection) {
((JingleRtpConnection) existingJingleConnection).deliveryMessage(to, from, message);
} else {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": " + existingJingleConnection.getClass().getName() + " does not support jingle messages");
}
} else if ("propose".equals(message.getName())) {
final Element description = message.findChild("description");
final String namespace = description == null ? null : description.getNamespace();
if (Namespace.JINGLE_APPS_RTP.equals(namespace)) {
final JingleRtpConnection rtpConnection = new JingleRtpConnection(this, id);
this.connections.put(id, rtpConnection);
rtpConnection.deliveryMessage(to, from, message);
} else {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": unable to react to proposed " + namespace + " session");
}
} else {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": retrieved out of order jingle message");
}
} }
public void startJingleFileTransfer(final Message message) { public void startJingleFileTransfer(final Message message) {

View file

@ -4,11 +4,7 @@ import android.util.Base64;
import android.util.Log; import android.util.Log;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -351,7 +347,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
this.message.setTransferable(this); this.message.setTransferable(this);
this.mStatus = Transferable.STATUS_UPLOADING; this.mStatus = Transferable.STATUS_UPLOADING;
this.initiator = this.id.account.getJid(); this.initiator = this.id.account.getJid();
this.responder = this.id.counterPart; this.responder = this.id.with;
this.transportId = JingleConnectionManager.nextRandomId(); this.transportId = JingleConnectionManager.nextRandomId();
this.setupDescription(remoteVersion); this.setupDescription(remoteVersion);
if (this.initialTransport == IbbTransportInfo.class) { if (this.initialTransport == IbbTransportInfo.class) {
@ -416,7 +412,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
} }
private List<String> getRemoteFeatures() { private List<String> getRemoteFeatures() {
final Jid jid = this.id.counterPart; final Jid jid = this.id.with;
String resource = jid != null ? jid.getResource() : null; String resource = jid != null ? jid.getResource() : null;
if (resource != null) { if (resource != null) {
Presence presence = this.id.account.getRoster().getContact(jid).getPresences().getPresences().get(resource); Presence presence = this.id.account.getRoster().getContact(jid).getPresences().getPresences().get(resource);
@ -428,14 +424,15 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
} }
private void init(JinglePacket packet) { //should move to deliverPacket private void init(JinglePacket packet) { //should move to deliverPacket
//TODO if not 'OFFERED' reply with out-of-order
this.mJingleStatus = JINGLE_STATUS_INITIATED; this.mJingleStatus = JINGLE_STATUS_INITIATED;
final Conversation conversation = this.xmppConnectionService.findOrCreateConversation(id.account, id.counterPart.asBareJid(), false, false); final Conversation conversation = this.xmppConnectionService.findOrCreateConversation(id.account, id.with.asBareJid(), false, false);
this.message = new Message(conversation, "", Message.ENCRYPTION_NONE); this.message = new Message(conversation, "", Message.ENCRYPTION_NONE);
this.message.setStatus(Message.STATUS_RECEIVED); this.message.setStatus(Message.STATUS_RECEIVED);
this.mStatus = Transferable.STATUS_OFFER; this.mStatus = Transferable.STATUS_OFFER;
this.message.setTransferable(this); this.message.setTransferable(this);
this.message.setCounterpart(this.id.counterPart); this.message.setCounterpart(this.id.with);
this.initiator = this.id.counterPart; this.initiator = this.id.with;
this.responder = this.id.account.getJid(); this.responder = this.id.account.getJid();
final Content content = packet.getJingleContent(); final Content content = packet.getJingleContent();
final GenericTransportInfo transportInfo = content.getTransport(); final GenericTransportInfo transportInfo = content.getTransport();
@ -527,11 +524,11 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
respondToIq(packet, true); respondToIq(packet, true);
if (id.account.getRoster().getContact(id.counterPart).showInContactList() if (id.account.getRoster().getContact(id.with).showInContactList()
&& jingleConnectionManager.hasStoragePermission() && jingleConnectionManager.hasStoragePermission()
&& size < this.jingleConnectionManager.getAutoAcceptFileSize() && size < this.jingleConnectionManager.getAutoAcceptFileSize()
&& xmppConnectionService.isDataSaverDisabled()) { && xmppConnectionService.isDataSaverDisabled()) {
Log.d(Config.LOGTAG, "auto accepting file from " + id.counterPart); Log.d(Config.LOGTAG, "auto accepting file from " + id.with);
this.acceptedAutomatically = true; this.acceptedAutomatically = true;
this.sendAccept(); this.sendAccept();
} else { } else {
@ -697,7 +694,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
private JinglePacket bootstrapPacket(JinglePacket.Action action) { private JinglePacket bootstrapPacket(JinglePacket.Action action) {
final JinglePacket packet = new JinglePacket(action, this.id.sessionId); final JinglePacket packet = new JinglePacket(action, this.id.sessionId);
packet.setTo(id.counterPart); packet.setTo(id.with);
return packet; return packet;
} }
@ -837,7 +834,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
activation.query("http://jabber.org/protocol/bytestreams") activation.query("http://jabber.org/protocol/bytestreams")
.setAttribute("sid", sid); .setAttribute("sid", sid);
activation.query().addChild("activate") activation.query().addChild("activate")
.setContent(this.id.counterPart.toEscapedString()); .setContent(this.id.with.toEscapedString());
xmppConnectionService.sendIqPacket(this.id.account, activation, (account, response) -> { xmppConnectionService.sendIqPacket(this.id.account, activation, (account, response) -> {
if (response.getType() != IqPacket.TYPE.RESULT) { if (response.getType() != IqPacket.TYPE.RESULT) {
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": " + response.toString()); Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": " + response.toString());

View file

@ -65,7 +65,7 @@ public class JingleInBandTransport extends JingleTransport {
JingleInBandTransport(final JingleFileTransferConnection connection, final String sid, final int blockSize) { JingleInBandTransport(final JingleFileTransferConnection connection, final String sid, final int blockSize) {
this.connection = connection; this.connection = connection;
this.account = connection.getId().account; this.account = connection.getId().account;
this.counterpart = connection.getId().counterPart; this.counterpart = connection.getId().with;
this.blockSize = blockSize; this.blockSize = blockSize;
this.sessionId = sid; this.sessionId = sid;
} }

View file

@ -3,7 +3,9 @@ package eu.siacs.conversations.xmpp.jingle;
import android.util.Log; import android.util.Log;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket; import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
import rocks.xmpp.addr.Jid;
public class JingleRtpConnection extends AbstractJingleConnection { public class JingleRtpConnection extends AbstractJingleConnection {
@ -16,4 +18,8 @@ public class JingleRtpConnection extends AbstractJingleConnection {
void deliverPacket(final JinglePacket jinglePacket) { void deliverPacket(final JinglePacket jinglePacket) {
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": packet delivered to JingleRtpConnection"); Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": packet delivered to JingleRtpConnection");
} }
void deliveryMessage(final Jid to, Jid from, Element message) {
Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": delivered message to JingleRtpConnection " + message);
}
} }

View file

@ -23,7 +23,6 @@ import eu.siacs.conversations.services.AbstractConnectionManager;
import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.SocksSocketFactory; import eu.siacs.conversations.utils.SocksSocketFactory;
import eu.siacs.conversations.utils.WakeLockHelper; import eu.siacs.conversations.utils.WakeLockHelper;
import eu.siacs.conversations.xmpp.jingle.stanzas.Content;
import eu.siacs.conversations.xmpp.jingle.stanzas.FileTransferDescription; import eu.siacs.conversations.xmpp.jingle.stanzas.FileTransferDescription;
public class JingleSocks5Transport extends JingleTransport { public class JingleSocks5Transport extends JingleTransport {
@ -61,9 +60,9 @@ public class JingleSocks5Transport extends JingleTransport {
} }
if (candidate.isOurs()) { if (candidate.isOurs()) {
destBuilder.append(this.account.getJid()); destBuilder.append(this.account.getJid());
destBuilder.append(this.connection.getId().counterPart); destBuilder.append(this.connection.getId().with);
} else { } else {
destBuilder.append(this.connection.getId().counterPart); destBuilder.append(this.connection.getId().with);
destBuilder.append(this.account.getJid()); destBuilder.append(this.account.getJid());
} }
messageDigest.reset(); messageDigest.reset();

View file

@ -14,8 +14,8 @@ public class RtpDescription extends GenericDescription {
public static RtpDescription upgrade(final Element element) { public static RtpDescription upgrade(final Element element) {
Preconditions.checkArgument("description".equals(element.getName()), "Name of provided element is not description"); Preconditions.checkArgument("description".equals(element.getName()), "Name of provided element is not description");
Preconditions.checkArgument(Namespace.JINGLE_APP_RTP.equals(element.getNamespace()), "Element does not match the jingle rtp namespace"); Preconditions.checkArgument(Namespace.JINGLE_APPS_RTP.equals(element.getNamespace()), "Element does not match the jingle rtp namespace");
final RtpDescription description = new RtpDescription("description", Namespace.JINGLE_APP_RTP); final RtpDescription description = new RtpDescription("description", Namespace.JINGLE_APPS_RTP);
description.setAttributes(element.getAttributes()); description.setAttributes(element.getAttributes());
description.setChildren(element.getChildren()); description.setChildren(element.getChildren());
return description; return description;