Search in sources :

Example 1 with IceUdpTransportInfo

use of eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo in project Conversations by siacs.

the class RtpContentMap method modifiedCredentials.

public RtpContentMap modifiedCredentials(IceUdpTransportInfo.Credentials credentials, final IceUdpTransportInfo.Setup setup) {
    final ImmutableMap.Builder<String, DescriptionTransport> contentMapBuilder = new ImmutableMap.Builder<>();
    for (final Map.Entry<String, DescriptionTransport> content : contents.entrySet()) {
        final RtpDescription rtpDescription = content.getValue().description;
        IceUdpTransportInfo transportInfo = content.getValue().transport;
        final IceUdpTransportInfo modifiedTransportInfo = transportInfo.modifyCredentials(credentials, setup);
        contentMapBuilder.put(content.getKey(), new DescriptionTransport(rtpDescription, modifiedTransportInfo));
    }
    return new RtpContentMap(this.group, contentMapBuilder.build());
}
Also used : IceUdpTransportInfo(eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo) OmemoVerifiedIceUdpTransportInfo(eu.siacs.conversations.xmpp.jingle.stanzas.OmemoVerifiedIceUdpTransportInfo) ImmutableMap(com.google.common.collect.ImmutableMap) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) RtpDescription(eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription)

Example 2 with IceUdpTransportInfo

use of eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo in project Conversations by siacs.

the class SessionDescription method of.

public static SessionDescription of(final RtpContentMap contentMap) {
    final SessionDescriptionBuilder sessionDescriptionBuilder = new SessionDescriptionBuilder();
    final ArrayListMultimap<String, String> attributeMap = ArrayListMultimap.create();
    final ImmutableList.Builder<Media> mediaListBuilder = new ImmutableList.Builder<>();
    final Group group = contentMap.group;
    if (group != null) {
        final String semantics = group.getSemantics();
        checkNoWhitespace(semantics, "group semantics value must not contain any whitespace");
        attributeMap.put("group", group.getSemantics() + " " + Joiner.on(' ').join(group.getIdentificationTags()));
    }
    attributeMap.put("msid-semantic", " WMS my-media-stream");
    for (final Map.Entry<String, RtpContentMap.DescriptionTransport> entry : contentMap.contents.entrySet()) {
        final String name = entry.getKey();
        RtpContentMap.DescriptionTransport descriptionTransport = entry.getValue();
        RtpDescription description = descriptionTransport.description;
        IceUdpTransportInfo transport = descriptionTransport.transport;
        final ArrayListMultimap<String, String> mediaAttributes = ArrayListMultimap.create();
        final String ufrag = transport.getAttribute("ufrag");
        final String pwd = transport.getAttribute("pwd");
        if (Strings.isNullOrEmpty(ufrag)) {
            throw new IllegalArgumentException("Transport element is missing required ufrag attribute");
        }
        checkNoWhitespace(ufrag, "ufrag value must not contain any whitespaces");
        mediaAttributes.put("ice-ufrag", ufrag);
        if (Strings.isNullOrEmpty(pwd)) {
            throw new IllegalArgumentException("Transport element is missing required pwd attribute");
        }
        checkNoWhitespace(pwd, "pwd value must not contain any whitespaces");
        mediaAttributes.put("ice-pwd", pwd);
        mediaAttributes.put("ice-options", HARDCODED_ICE_OPTIONS);
        final IceUdpTransportInfo.Fingerprint fingerprint = transport.getFingerprint();
        if (fingerprint != null) {
            mediaAttributes.put("fingerprint", fingerprint.getHash() + " " + fingerprint.getContent());
            final IceUdpTransportInfo.Setup setup = fingerprint.getSetup();
            if (setup != null) {
                mediaAttributes.put("setup", setup.toString().toLowerCase(Locale.ROOT));
            }
        }
        final ImmutableList.Builder<Integer> formatBuilder = new ImmutableList.Builder<>();
        for (RtpDescription.PayloadType payloadType : description.getPayloadTypes()) {
            final String id = payloadType.getId();
            if (Strings.isNullOrEmpty(id)) {
                throw new IllegalArgumentException("Payload type is missing id");
            }
            if (!isInt(id)) {
                throw new IllegalArgumentException("Payload id is not numeric");
            }
            formatBuilder.add(payloadType.getIntId());
            mediaAttributes.put("rtpmap", payloadType.toSdpAttribute());
            final List<RtpDescription.Parameter> parameters = payloadType.getParameters();
            if (parameters.size() == 1) {
                mediaAttributes.put("fmtp", RtpDescription.Parameter.toSdpString(id, parameters.get(0)));
            } else if (parameters.size() > 0) {
                mediaAttributes.put("fmtp", RtpDescription.Parameter.toSdpString(id, parameters));
            }
            for (RtpDescription.FeedbackNegotiation feedbackNegotiation : payloadType.getFeedbackNegotiations()) {
                final String type = feedbackNegotiation.getType();
                final String subtype = feedbackNegotiation.getSubType();
                if (Strings.isNullOrEmpty(type)) {
                    throw new IllegalArgumentException("a feedback for payload-type " + id + " negotiation is missing type");
                }
                checkNoWhitespace(type, "feedback negotiation type must not contain whitespace");
                mediaAttributes.put("rtcp-fb", id + " " + type + (Strings.isNullOrEmpty(subtype) ? "" : " " + subtype));
            }
            for (RtpDescription.FeedbackNegotiationTrrInt feedbackNegotiationTrrInt : payloadType.feedbackNegotiationTrrInts()) {
                mediaAttributes.put("rtcp-fb", id + " trr-int " + feedbackNegotiationTrrInt.getValue());
            }
        }
        for (RtpDescription.FeedbackNegotiation feedbackNegotiation : description.getFeedbackNegotiations()) {
            final String type = feedbackNegotiation.getType();
            final String subtype = feedbackNegotiation.getSubType();
            if (Strings.isNullOrEmpty(type)) {
                throw new IllegalArgumentException("a feedback negotiation is missing type");
            }
            checkNoWhitespace(type, "feedback negotiation type must not contain whitespace");
            mediaAttributes.put("rtcp-fb", "* " + type + (Strings.isNullOrEmpty(subtype) ? "" : " " + subtype));
        }
        for (final RtpDescription.FeedbackNegotiationTrrInt feedbackNegotiationTrrInt : description.feedbackNegotiationTrrInts()) {
            mediaAttributes.put("rtcp-fb", "* trr-int " + feedbackNegotiationTrrInt.getValue());
        }
        for (final RtpDescription.RtpHeaderExtension extension : description.getHeaderExtensions()) {
            final String id = extension.getId();
            final String uri = extension.getUri();
            if (Strings.isNullOrEmpty(id)) {
                throw new IllegalArgumentException("A header extension is missing id");
            }
            checkNoWhitespace(id, "header extension id must not contain whitespace");
            if (Strings.isNullOrEmpty(uri)) {
                throw new IllegalArgumentException("A header extension is missing uri");
            }
            checkNoWhitespace(uri, "feedback negotiation uri must not contain whitespace");
            mediaAttributes.put("extmap", id + " " + uri);
        }
        if (description.hasChild("extmap-allow-mixed", Namespace.JINGLE_RTP_HEADER_EXTENSIONS)) {
            mediaAttributes.put("extmap-allow-mixed", "");
        }
        for (final RtpDescription.SourceGroup sourceGroup : description.getSourceGroups()) {
            final String semantics = sourceGroup.getSemantics();
            final List<String> groups = sourceGroup.getSsrcs();
            if (Strings.isNullOrEmpty(semantics)) {
                throw new IllegalArgumentException("A SSRC group is missing semantics attribute");
            }
            checkNoWhitespace(semantics, "source group semantics must not contain whitespace");
            if (groups.size() == 0) {
                throw new IllegalArgumentException("A SSRC group is missing SSRC ids");
            }
            mediaAttributes.put("ssrc-group", String.format("%s %s", semantics, Joiner.on(' ').join(groups)));
        }
        for (final RtpDescription.Source source : description.getSources()) {
            for (final RtpDescription.Source.Parameter parameter : source.getParameters()) {
                final String id = source.getSsrcId();
                final String parameterName = parameter.getParameterName();
                final String parameterValue = parameter.getParameterValue();
                if (Strings.isNullOrEmpty(id)) {
                    throw new IllegalArgumentException("A source specific media attribute is missing the id");
                }
                checkNoWhitespace(id, "A source specific media attributes must not contain whitespaces");
                if (Strings.isNullOrEmpty(parameterName)) {
                    throw new IllegalArgumentException("A source specific media attribute is missing its name");
                }
                if (Strings.isNullOrEmpty(parameterValue)) {
                    throw new IllegalArgumentException("A source specific media attribute is missing its value");
                }
                mediaAttributes.put("ssrc", id + " " + parameterName + ":" + parameterValue);
            }
        }
        mediaAttributes.put("mid", name);
        // random additional attributes
        mediaAttributes.put("rtcp", "9 IN IP4 0.0.0.0");
        mediaAttributes.put("sendrecv", "");
        if (description.hasChild("rtcp-mux", Namespace.JINGLE_APPS_RTP)) {
            mediaAttributes.put("rtcp-mux", "");
        }
        final MediaBuilder mediaBuilder = new MediaBuilder();
        mediaBuilder.setMedia(description.getMedia().toString().toLowerCase(Locale.ROOT));
        mediaBuilder.setConnectionData(HARDCODED_CONNECTION);
        mediaBuilder.setPort(HARDCODED_MEDIA_PORT);
        mediaBuilder.setProtocol(HARDCODED_MEDIA_PROTOCOL);
        mediaBuilder.setAttributes(mediaAttributes);
        mediaBuilder.setFormats(formatBuilder.build());
        mediaListBuilder.add(mediaBuilder.createMedia());
    }
    sessionDescriptionBuilder.setVersion(0);
    sessionDescriptionBuilder.setName("-");
    sessionDescriptionBuilder.setMedia(mediaListBuilder.build());
    sessionDescriptionBuilder.setAttributes(attributeMap);
    return sessionDescriptionBuilder.createSessionDescription();
}
Also used : Group(eu.siacs.conversations.xmpp.jingle.stanzas.Group) ImmutableList(com.google.common.collect.ImmutableList) RtpDescription(eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription) IceUdpTransportInfo(eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo) Map(java.util.Map)

Example 3 with IceUdpTransportInfo

use of eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo in project Conversations by siacs.

the class JingleRtpConnection method processCandidate.

private void processCandidate(final Map.Entry<String, RtpContentMap.DescriptionTransport> content) {
    final RtpContentMap rtpContentMap = getRemoteContentMap();
    final List<String> indices = toIdentificationTags(rtpContentMap);
    // aka content name
    final String sdpMid = content.getKey();
    final IceUdpTransportInfo transport = content.getValue().transport;
    final IceUdpTransportInfo.Credentials credentials = transport.getCredentials();
    for (final IceUdpTransportInfo.Candidate candidate : transport.getCandidates()) {
        final String sdp;
        try {
            sdp = candidate.toSdpAttribute(credentials.ufrag);
        } catch (final IllegalArgumentException e) {
            Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": ignoring invalid ICE candidate " + e.getMessage());
            continue;
        }
        final int mLineIndex = indices.indexOf(sdpMid);
        if (mLineIndex < 0) {
            Log.w(Config.LOGTAG, "mLineIndex not found for " + sdpMid + ". available indices " + indices);
        }
        final IceCandidate iceCandidate = new IceCandidate(sdpMid, mLineIndex, sdp);
        Log.d(Config.LOGTAG, "received candidate: " + iceCandidate);
        this.webRTCWrapper.addIceCandidate(iceCandidate);
    }
}
Also used : IceUdpTransportInfo(eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo) IceCandidate(org.webrtc.IceCandidate)

Example 4 with IceUdpTransportInfo

use of eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo in project Conversations by siacs.

the class AxolotlService method decrypt.

private OmemoVerifiedPayload<IceUdpTransportInfo> decrypt(final OmemoVerifiedIceUdpTransportInfo verifiedIceUdpTransportInfo, final Jid from, ImmutableList.Builder<ListenableFuture<XmppAxolotlSession>> pepVerificationFutures) throws CryptoFailedException {
    final IceUdpTransportInfo transportInfo = new IceUdpTransportInfo();
    transportInfo.setAttributes(verifiedIceUdpTransportInfo.getAttributes());
    final OmemoVerification omemoVerification = new OmemoVerification();
    for (final Element child : verifiedIceUdpTransportInfo.getChildren()) {
        if ("fingerprint".equals(child.getName()) && Namespace.OMEMO_DTLS_SRTP_VERIFICATION.equals(child.getNamespace())) {
            final Element fingerprint = new Element("fingerprint", Namespace.JINGLE_APPS_DTLS);
            fingerprint.setAttribute("setup", child.getAttribute("setup"));
            fingerprint.setAttribute("hash", child.getAttribute("hash"));
            final Element encrypted = child.findChildEnsureSingle(XmppAxolotlMessage.CONTAINERTAG, AxolotlService.PEP_PREFIX);
            final XmppAxolotlMessage xmppAxolotlMessage = XmppAxolotlMessage.fromElement(encrypted, from.asBareJid());
            final XmppAxolotlSession session = getReceivingSession(xmppAxolotlMessage);
            final XmppAxolotlMessage.XmppAxolotlPlaintextMessage plaintext = xmppAxolotlMessage.decrypt(session, getOwnDeviceId());
            final Integer preKeyId = session.getPreKeyIdAndReset();
            if (preKeyId != null) {
                postponedSessions.add(session);
            }
            if (session.isFresh()) {
                pepVerificationFutures.add(putFreshSession(session));
            } else if (Config.REQUIRE_RTP_VERIFICATION) {
                pepVerificationFutures.add(Futures.immediateFuture(session));
            }
            fingerprint.setContent(plaintext.getPlaintext());
            omemoVerification.setDeviceId(session.getRemoteAddress().getDeviceId());
            omemoVerification.setSessionFingerprint(plaintext.getFingerprint());
            transportInfo.addChild(fingerprint);
        } else {
            transportInfo.addChild(child);
        }
    }
    return new OmemoVerifiedPayload<>(omemoVerification, transportInfo);
}
Also used : OmemoVerification(eu.siacs.conversations.xmpp.jingle.OmemoVerification) IceUdpTransportInfo(eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo) OmemoVerifiedIceUdpTransportInfo(eu.siacs.conversations.xmpp.jingle.stanzas.OmemoVerifiedIceUdpTransportInfo) Element(eu.siacs.conversations.xml.Element)

Example 5 with IceUdpTransportInfo

use of eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo in project Conversations by siacs.

the class AxolotlService method decrypt.

public ListenableFuture<OmemoVerifiedPayload<RtpContentMap>> decrypt(OmemoVerifiedRtpContentMap omemoVerifiedRtpContentMap, final Jid from) {
    final ImmutableMap.Builder<String, RtpContentMap.DescriptionTransport> descriptionTransportBuilder = new ImmutableMap.Builder<>();
    final OmemoVerification omemoVerification = new OmemoVerification();
    final ImmutableList.Builder<ListenableFuture<XmppAxolotlSession>> pepVerificationFutures = new ImmutableList.Builder<>();
    for (final Map.Entry<String, RtpContentMap.DescriptionTransport> content : omemoVerifiedRtpContentMap.contents.entrySet()) {
        final RtpContentMap.DescriptionTransport descriptionTransport = content.getValue();
        final OmemoVerifiedPayload<IceUdpTransportInfo> decryptedTransport;
        try {
            decryptedTransport = decrypt((OmemoVerifiedIceUdpTransportInfo) descriptionTransport.transport, from, pepVerificationFutures);
        } catch (CryptoFailedException e) {
            return Futures.immediateFailedFuture(e);
        }
        omemoVerification.setOrEnsureEqual(decryptedTransport);
        descriptionTransportBuilder.put(content.getKey(), new RtpContentMap.DescriptionTransport(descriptionTransport.description, decryptedTransport.payload));
    }
    processPostponed();
    final ImmutableList<ListenableFuture<XmppAxolotlSession>> sessionFutures = pepVerificationFutures.build();
    return Futures.transform(Futures.allAsList(sessionFutures), sessions -> {
        if (Config.REQUIRE_RTP_VERIFICATION) {
            for (XmppAxolotlSession session : sessions) {
                requireVerification(session);
            }
        }
        return new OmemoVerifiedPayload<>(omemoVerification, new RtpContentMap(omemoVerifiedRtpContentMap.group, descriptionTransportBuilder.build()));
    }, MoreExecutors.directExecutor());
}
Also used : OmemoVerification(eu.siacs.conversations.xmpp.jingle.OmemoVerification) IceUdpTransportInfo(eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo) OmemoVerifiedIceUdpTransportInfo(eu.siacs.conversations.xmpp.jingle.stanzas.OmemoVerifiedIceUdpTransportInfo) ImmutableList(com.google.common.collect.ImmutableList) SessionBuilder(org.whispersystems.libsignal.SessionBuilder) OmemoVerifiedIceUdpTransportInfo(eu.siacs.conversations.xmpp.jingle.stanzas.OmemoVerifiedIceUdpTransportInfo) OmemoVerifiedRtpContentMap(eu.siacs.conversations.xmpp.jingle.OmemoVerifiedRtpContentMap) RtpContentMap(eu.siacs.conversations.xmpp.jingle.RtpContentMap) ImmutableMap(com.google.common.collect.ImmutableMap) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) OmemoVerifiedRtpContentMap(eu.siacs.conversations.xmpp.jingle.OmemoVerifiedRtpContentMap) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) HashMap(java.util.HashMap) RtpContentMap(eu.siacs.conversations.xmpp.jingle.RtpContentMap)

Aggregations

IceUdpTransportInfo (eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo)7 OmemoVerifiedIceUdpTransportInfo (eu.siacs.conversations.xmpp.jingle.stanzas.OmemoVerifiedIceUdpTransportInfo)5 Map (java.util.Map)4 ImmutableMap (com.google.common.collect.ImmutableMap)3 ImmutableList (com.google.common.collect.ImmutableList)2 OmemoVerification (eu.siacs.conversations.xmpp.jingle.OmemoVerification)2 RtpDescription (eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription)2 ListenableFuture (com.google.common.util.concurrent.ListenableFuture)1 Element (eu.siacs.conversations.xml.Element)1 OmemoVerifiedRtpContentMap (eu.siacs.conversations.xmpp.jingle.OmemoVerifiedRtpContentMap)1 RtpContentMap (eu.siacs.conversations.xmpp.jingle.RtpContentMap)1 Group (eu.siacs.conversations.xmpp.jingle.stanzas.Group)1 HashMap (java.util.HashMap)1 IceCandidate (org.webrtc.IceCandidate)1 SessionBuilder (org.whispersystems.libsignal.SessionBuilder)1