respond with busy if there is anthor rtp session

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/generator/MessageGenerator.java          | 10 
src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java               |  1 
src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java | 99 
3 files changed, 74 insertions(+), 36 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/generator/MessageGenerator.java 🔗

@@ -255,4 +255,14 @@ public class MessageGenerator extends AbstractGenerator {
 		propose.addChild("description", Namespace.JINGLE_APPS_RTP);
 		return packet;
 	}
+
+	public MessagePacket sessionReject(final Jid with, final String sessionId) {
+		final MessagePacket packet = new MessagePacket();
+		packet.setType(MessagePacket.TYPE_CHAT); //we want to carbon copy those
+		packet.setTo(with);
+		final Element propose = packet.addChild("reject", Namespace.JINGLE_MESSAGE);
+		propose.setAttribute("id", sessionId);
+		propose.addChild("description", Namespace.JINGLE_APPS_RTP);
+		return packet;
+	}
 }

src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java 🔗

@@ -18,12 +18,14 @@ import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.entities.Transferable;
 import eu.siacs.conversations.services.AbstractConnectionManager;
 import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.ui.util.Attachment;
 import eu.siacs.conversations.xml.Element;
 import eu.siacs.conversations.xml.Namespace;
 import eu.siacs.conversations.xmpp.OnIqPacketReceived;
 import eu.siacs.conversations.xmpp.jingle.stanzas.Content;
 import eu.siacs.conversations.xmpp.jingle.stanzas.FileTransferDescription;
 import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
+import eu.siacs.conversations.xmpp.jingle.stanzas.Reason;
 import eu.siacs.conversations.xmpp.stanzas.IqPacket;
 import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
 import rocks.xmpp.addr.Jid;
@@ -38,7 +40,14 @@ public class JingleConnectionManager extends AbstractConnectionManager {
         super(service);
     }
 
+    static String nextRandomId() {
+        final byte[] id = new byte[16];
+        new SecureRandom().nextBytes(id);
+        return Base64.encodeToString(id, Base64.NO_WRAP | Base64.NO_PADDING);
+    }
+
     public void deliverPacket(final Account account, final JinglePacket packet) {
+        //TODO check that sessionId is not null
         final AbstractJingleConnection.Id id = AbstractJingleConnection.Id.of(account, packet);
         final AbstractJingleConnection existingJingleConnection = connections.get(id);
         if (existingJingleConnection != null) {
@@ -50,7 +59,15 @@ public class JingleConnectionManager extends AbstractConnectionManager {
             final AbstractJingleConnection connection;
             if (FileTransferDescription.NAMESPACES.contains(descriptionNamespace)) {
                 connection = new JingleFileTransferConnection(this, id, from);
-            } else if (Namespace.JINGLE_APPS_RTP.equals(descriptionNamespace)) {
+            } else if (Namespace.JINGLE_APPS_RTP.equals(descriptionNamespace)) { //and not using Tor
+                if (isBusy()) {
+                    mXmppConnectionService.sendIqPacket(account, packet.generateResponse(IqPacket.TYPE.RESULT), null);
+                    final JinglePacket sessionTermination = new JinglePacket(JinglePacket.Action.SESSION_TERMINATE, id.sessionId);
+                    sessionTermination.setTo(id.with);
+                    sessionTermination.setReason(Reason.BUSY, null);
+                    mXmppConnectionService.sendIqPacket(account, sessionTermination, null);
+                    return;
+                }
                 connection = new JingleRtpConnection(this, id, from);
             } else {
                 respondWithJingleError(account, packet, "unsupported-info", "feature-not-implemented", "cancel");
@@ -65,6 +82,17 @@ public class JingleConnectionManager extends AbstractConnectionManager {
         }
     }
 
+    private boolean isBusy() {
+        for (AbstractJingleConnection connection : this.connections.values()) {
+            if (connection instanceof JingleRtpConnection) {
+                return true;
+            }
+        }
+        synchronized (this.rtpSessionProposals) {
+            return this.rtpSessionProposals.containsValue(DeviceDiscoveryState.DISCOVERED) || this.rtpSessionProposals.containsValue(DeviceDiscoveryState.SEARCHING);
+        }
+    }
+
     public void respondWithJingleError(final Account account, final IqPacket original, String jingleCondition, String condition, String conditionType) {
         final IqPacket response = original.generateResponse(IqPacket.TYPE.ERROR);
         final Element error = response.addChild("error");
@@ -109,21 +137,30 @@ public class JingleConnectionManager extends AbstractConnectionManager {
             } else {
                 Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": " + existingJingleConnection.getClass().getName() + " does not support jingle messages");
             }
-        } else if ("propose".equals(message.getName())) {
+            return;
+        }
+        if (carbonCopy) {
+            Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": ignore jingle message from self");
+            return;
+        }
+
+        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, with);
-                this.connections.put(id, rtpConnection);
-                rtpConnection.deliveryMessage(from, message);
+            if (Namespace.JINGLE_APPS_RTP.equals(namespace)) { //and not using Tor
+                if (isBusy()) {
+                    final MessagePacket reject = mXmppConnectionService.getMessageGenerator().sessionReject(from, sessionId);
+                    mXmppConnectionService.sendMessagePacket(account, reject);
+                } else {
+                    final JingleRtpConnection rtpConnection = new JingleRtpConnection(this, id, with);
+                    this.connections.put(id, rtpConnection);
+                    rtpConnection.deliveryMessage(from, message);
+                }
             } else {
                 Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": unable to react to proposed " + namespace + " session");
             }
         } else if ("proceed".equals(message.getName())) {
-            if (carbonCopy) {
-                Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": ignore carbon copied proceed");
-                return;
-            }
+
             final RtpSessionProposal proposal = new RtpSessionProposal(account, with.asBareJid(), sessionId);
             synchronized (rtpSessionProposals) {
                 if (rtpSessionProposals.remove(proposal) != null) {
@@ -136,10 +173,6 @@ public class JingleConnectionManager extends AbstractConnectionManager {
                 }
             }
         } else if ("reject".equals(message.getName())) {
-            if (carbonCopy) {
-                Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": ignore carbon copied reject");
-                return;
-            }
             final RtpSessionProposal proposal = new RtpSessionProposal(account, with.asBareJid(), sessionId);
             synchronized (rtpSessionProposals) {
                 if (rtpSessionProposals.remove(proposal) != null) {
@@ -268,12 +301,6 @@ public class JingleConnectionManager extends AbstractConnectionManager {
         }
     }
 
-    static String nextRandomId() {
-        final byte[] id = new byte[16];
-        new SecureRandom().nextBytes(id);
-        return Base64.encodeToString(id, Base64.NO_WRAP | Base64.NO_PADDING);
-    }
-
     public void deliverIbbPacket(Account account, IqPacket packet) {
         final String sid;
         final Element payload;
@@ -372,10 +399,25 @@ public class JingleConnectionManager extends AbstractConnectionManager {
         }
     }
 
+    public enum DeviceDiscoveryState {
+        SEARCHING, DISCOVERED, FAILED;
+
+        public RtpEndUserState toEndUserState() {
+            switch (this) {
+                case SEARCHING:
+                    return RtpEndUserState.FINDING_DEVICE;
+                case DISCOVERED:
+                    return RtpEndUserState.RINGING;
+                default:
+                    return RtpEndUserState.CONNECTIVITY_ERROR;
+            }
+        }
+    }
+
     public static class RtpSessionProposal {
-        private final Account account;
         public final Jid with;
         public final String sessionId;
+        private final Account account;
 
         private RtpSessionProposal(Account account, Jid with, String sessionId) {
             this.account = account;
@@ -402,19 +444,4 @@ public class JingleConnectionManager extends AbstractConnectionManager {
             return Objects.hashCode(account.getJid(), with, sessionId);
         }
     }
-
-    public enum DeviceDiscoveryState {
-        SEARCHING, DISCOVERED, FAILED;
-
-        public RtpEndUserState toEndUserState() {
-            switch (this) {
-                case SEARCHING:
-                    return RtpEndUserState.FINDING_DEVICE;
-                case DISCOVERED:
-                    return RtpEndUserState.RINGING;
-                default:
-                    return RtpEndUserState.CONNECTIVITY_ERROR;
-            }
-        }
-    }
 }