diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/AbstractCallPeerMediaHandlerJabberGTalkImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/AbstractCallPeerMediaHandlerJabberGTalkImpl.java index 7c5c69024..832dda2e9 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/AbstractCallPeerMediaHandlerJabberGTalkImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/AbstractCallPeerMediaHandlerJabberGTalkImpl.java @@ -6,8 +6,6 @@ */ package net.java.sip.communicator.impl.protocol.jabber; -import ch.imvs.sdes4j.srtp.*; - import java.util.*; import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*; @@ -18,11 +16,14 @@ import org.jitsi.service.neomedia.*; import org.jivesoftware.smack.packet.*; +import ch.imvs.sdes4j.srtp.*; + /** * An implementation of the CallPeerMediaHandler abstract class for the * common part of Jabber and Gtalk protocols. * * @author Vincent Lucas + * @author Lyubomir Marinov */ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl > @@ -84,7 +85,7 @@ public void setLocalInputEvtAware(boolean enable) * contains the PAYLOAD-TYPE and (more important here) the ENCRYPTION. * @param mediaType The type of media (AUDIO or VIDEO). */ - protected void addZRTPAdvertisedEncryptions( + protected void addZrtpAdvertisedEncryptions( boolean isInitiator, RtpDescriptionPacketExtension description, MediaType mediaType) @@ -131,7 +132,7 @@ && getPeer().getCall().isSipZrtpAttribute()) * contains the PAYLOAD-TYPE and (more important here) the ENCRYPTION. * @param mediaType The type of media (AUDIO or VIDEO). */ - protected void addSDESAdvertisedEncryptions( + protected void addSDesAdvertisedEncryptions( boolean isInitiator, RtpDescriptionPacketExtension description, MediaType mediaType) @@ -380,7 +381,7 @@ protected boolean setSDesEncryptionToDescription( = accountID.getAccountPropertyString( ProtocolProviderFactory.SDES_CIPHER_SUITES); - if (ciphers == null) + if (ciphers == null) { ciphers = JabberActivator.getResources().getSettingsString( @@ -475,8 +476,8 @@ protected boolean setSDesEncryptionToDescription( * @param localDescription The element containing the media DESCRIPTION and * its encryption. * @param remoteDescription The element containing the media DESCRIPTION and - * its encryption for the remote peer. Null, if the local peer is the - * initiator of the call. + * its encryption for the remote peer; null if the local peer is + * the initiator of the call. */ protected void setAndAddPreferredEncryptionProtocol( MediaType mediaType, @@ -497,41 +498,71 @@ protected void setAndAddPreferredEncryptionProtocol( ProtocolProviderFactory.ENCRYPTION_PROTOCOL.length() + 1); - // SDES - if(SDesControl.PROTO_NAME.equals(protoName)) + if (setAndAddPreferredEncryptionProtocol( + protoName, + mediaType, + localDescription, + remoteDescription)) + { + // Stop once an encryption advertisement has been chosen. + return; + } + } + } + + /** + * Selects a specific encryption protocol if it is the preferred (only used + * by the callee). + * + * @param protoName the name of the encryption protocol which is to be + * selected + * @param mediaType The type of media (AUDIO or VIDEO). + * @param localDescription The element containing the media DESCRIPTION and + * its encryption. + * @param remoteDescription The element containing the media DESCRIPTION and + * its encryption for the remote peer; null if the local peer is + * the initiator of the call. + * @return true if the specified encryption protocol has been + * selected; false, otherwise + */ + protected boolean setAndAddPreferredEncryptionProtocol( + String protoName, + MediaType mediaType, + RtpDescriptionPacketExtension localDescription, + RtpDescriptionPacketExtension remoteDescription) + { + // SDES + if(SDesControl.PROTO_NAME.equals(protoName)) + { + addSDesAdvertisedEncryptions( + false, + remoteDescription, + mediaType); + if(setSDesEncryptionToDescription( + mediaType, + localDescription, + remoteDescription)) + { + // Stop once an encryption advertisement has been chosen. + return true; + } + } + // ZRTP + else if(ZrtpControl.PROTO_NAME.equals(protoName)) + { + if(setZrtpEncryptionToDescription( + mediaType, + localDescription, + remoteDescription)) { - addSDESAdvertisedEncryptions( + addZrtpAdvertisedEncryptions( false, remoteDescription, mediaType); - if(setSDesEncryptionToDescription( - mediaType, - localDescription, - remoteDescription)) - { - // Stop once an encryption advertisement has been chosen. - return; - } - } - // ZRTP - else if(ZrtpControl.PROTO_NAME.equals(protoName)) - { - boolean isZRTPAddedToDescription - = setZrtpEncryptionToDescription( - mediaType, - localDescription, - remoteDescription); - - if(isZRTPAddedToDescription) - { - addZRTPAdvertisedEncryptions( - false, - remoteDescription, - mediaType); - // Stop once an encryption advertisement has been chosen. - return; - } + // Stop once an encryption advertisement has been chosen. + return true; } } + return false; } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java index b15f0fb23..726d12fe9 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerJabberImpl.java @@ -979,7 +979,7 @@ public void processTransportInfo(JingleIQ jingleIQ) } getMediaHandler().processTransportInfo( - jingleIQ.getContentList()); + jingleIQ.getContentList()); } catch (OperationFailedException ofe) { diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerGTalkImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerGTalkImpl.java index 6c4e190d3..1007f9784 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerGTalkImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerGTalkImpl.java @@ -362,8 +362,8 @@ public void processAnswer(RtpDescriptionPacketExtension answer) if(format == null) continue; - addZRTPAdvertisedEncryptions(true, answer, mediaType); - addSDESAdvertisedEncryptions(true, answer, mediaType); + addZrtpAdvertisedEncryptions(true, answer, mediaType); + addSDesAdvertisedEncryptions(true, answer, mediaType); // stream connector StreamConnector connector @@ -521,7 +521,6 @@ public RtpDescriptionPacketExtension createDescription() mediaType, description, null); - //ZRTP setZrtpEncryptionToDescription( mediaType, diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java index 727b735bf..31d0e4b7f 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java @@ -267,6 +267,8 @@ && isRTPTranslationEnabled(mediaType))) RtpDescriptionPacketExtension description = JingleUtils.getRtpDescription(content); + // DTLS-SRTP + setDtlsEncryptionToContent(mediaType, content, null); //SDES // It is important to set SDES before ZRTP in order to make GTALK // application able to work with SDES. @@ -320,13 +322,13 @@ private ContentPacketExtension createContentForOffer( { ContentPacketExtension content = JingleUtils.createDescription( - ContentPacketExtension.CreatorEnum.initiator, - supportedFormats.get(0).getMediaType().toString(), - JingleUtils.getSenders(direction, !getPeer().isInitiator()), - supportedFormats, - supportedExtensions, - getDynamicPayloadTypes(), - getRtpExtensionsRegistry()); + ContentPacketExtension.CreatorEnum.initiator, + supportedFormats.get(0).getMediaType().toString(), + JingleUtils.getSenders(direction, !getPeer().isInitiator()), + supportedFormats, + supportedExtensions, + getDynamicPayloadTypes(), + getRtpExtensionsRegistry()); this.localContentMap.put(content.getName(), content); return content; @@ -390,6 +392,8 @@ && isRTPTranslationEnabled(mediaType))) RtpDescriptionPacketExtension description = JingleUtils.getRtpDescription(content); + // DTLS-SRTP + setDtlsEncryptionToContent(mediaType, content, null); //SDES // It is important to set SDES before ZRTP in order to make // GTALK application able to work with SDES. @@ -542,11 +546,10 @@ public Iterable generateSessionAccept() //user answered an incoming call so we go through whatever content //entries we are initializing and init their corresponding streams - // First parse content so we know how may streams, - // and what type of content we have - Map contents - = new HashMap(); + // First parse content so we know how many streams and what type of + // content we have + Map contents + = new HashMap(); for(ContentPacketExtension ourContent : sessAccept) { @@ -1065,7 +1068,6 @@ private List harvestCandidates( throws OperationFailedException { long startCandidateHarvestTime = System.currentTimeMillis(); - TransportManagerJabberImpl transportManager = getTransportManager(); if (remote == null) @@ -1090,11 +1092,19 @@ private List harvestCandidates( } long stopCandidateHarvestTime = System.currentTimeMillis(); - long candidateHarvestTime - = stopCandidateHarvestTime - startCandidateHarvestTime; + if (logger.isInfoEnabled()) - logger.info("End candidate harvest within " - + candidateHarvestTime + " ms"); + { + long candidateHarvestTime + = stopCandidateHarvestTime - startCandidateHarvestTime; + + logger.info( + "End candidate harvest within " + candidateHarvestTime + + " ms"); + } + + setDtlsEncryptionToTransports(local); + /* * TODO Ideally, we wouldn't wrap up that quickly. We need to revisit * this. @@ -1220,7 +1230,7 @@ public void processAnswer(List answer) RtpDescriptionPacketExtension description = JingleUtils.getRtpDescription(content); MediaType mediaType - = MediaType.parseString( description.getMedia() ); + = MediaType.parseString(description.getMedia()); if(answer.size() > 1) { @@ -1408,8 +1418,9 @@ private void processContent( logger); } - addZRTPAdvertisedEncryptions(true, description, mediaType); - addSDESAdvertisedEncryptions(true, description, mediaType); + addZrtpAdvertisedEncryptions(true, description, mediaType); + addSDesAdvertisedEncryptions(true, description, mediaType); + addDtlsAdvertisedEncryptions(true, content, mediaType); StreamConnector connector = transportManager.getStreamConnector(mediaType); @@ -1573,7 +1584,9 @@ public void processOffer(List offer) // intersect the MediaFormats of our device with remote ones List mutuallySupportedFormats - = intersectFormats(remoteFormats, getLocallySupportedFormats(dev)); + = intersectFormats( + remoteFormats, + getLocallySupportedFormats(dev)); // check whether we will be exchanging any RTP extensions. List offeredRTPExtensions @@ -1649,14 +1662,14 @@ public void processOffer(List offer) getDynamicPayloadTypes(), getRtpExtensionsRegistry()); - RtpDescriptionPacketExtension localDescription = - JingleUtils.getRtpDescription(ourContent); - - // Sets ZRTP or SDES, depending on the preferences for this account. + /* + * Sets ZRTP, SDES or DTLS-SRTP depending on the preferences for + * this account. + */ setAndAddPreferredEncryptionProtocol( mediaType, - localDescription, - description); + ourContent, + content); // Got a content which has inputevt. It means that the peer requests // a desktop sharing session so tell it we support inputevt. @@ -2163,4 +2176,343 @@ public void setLocallyOnHold(boolean locallyOnHold) } } + /** + * Detects and adds DTLS-SRTP available encryption method present in the + * content (description) given in parameter. + * + * @param isInitiator true if the local call instance is the + * initiator of the call; false, otherwise. + * @param content The CONTENT element of the JINGLE element which contains + * the TRANSPORT element + * @param mediaType The type of media (AUDIO or VIDEO). + */ + private boolean addDtlsAdvertisedEncryptions( + boolean isInitiator, + ContentPacketExtension content, + MediaType mediaType) + { + IceUdpTransportPacketExtension remoteTransport + = content.getFirstChildOfType(IceUdpTransportPacketExtension.class); + SrtpControls srtpControls = getSrtpControls(); + boolean b = false; + + if (remoteTransport != null) + { + List remoteFingerpintPEs + = remoteTransport.getChildExtensionsOfType( + DtlsFingerprintPacketExtension.class); + + if (!remoteFingerpintPEs.isEmpty()) + { + AccountID accountID + = getPeer().getProtocolProvider().getAccountID(); + + if (accountID.getAccountPropertyBoolean( + ProtocolProviderFactory.DEFAULT_ENCRYPTION, + true) + && accountID.isEncryptionProtocolEnabled( + DtlsControl.PROTO_NAME)) + { + Map remoteFingerprints + = new LinkedHashMap(); + + for (DtlsFingerprintPacketExtension remoteFingerprintPE + : remoteFingerpintPEs) + { + String remoteFingerprint + = remoteFingerprintPE.getFingerprint(); + String remoteHash = remoteFingerprintPE.getHash(); + + remoteFingerprints.put( + remoteHash, + remoteFingerprint); + } + + DtlsControl dtlsControl; + int dtlsProtocol; + + if (isInitiator) + { + dtlsControl + = (DtlsControl) + srtpControls.get( + mediaType, + SrtpControlType.DTLS_SRTP); + dtlsProtocol = DtlsControl.DTLS_SERVER_PROTOCOL; + } + else + { + dtlsControl + = (DtlsControl) + srtpControls.getOrCreate( + mediaType, + SrtpControlType.DTLS_SRTP); + dtlsProtocol = DtlsControl.DTLS_CLIENT_PROTOCOL; + } + if (dtlsControl != null) + { + dtlsControl.setDtlsProtocol(dtlsProtocol); + dtlsControl.setRemoteFingerprints(remoteFingerprints); + removeAndCleanupOtherSrtpControls( + mediaType, + SrtpControlType.DTLS_SRTP); + addAdvertisedEncryptionMethod( + SrtpControlType.DTLS_SRTP); + b = true; + } + } + } + } + /* + * If they haven't advertised DTLS-SRTP in their (media) description, + * then DTLS-SRTP shouldn't be functioning as far as we're concerned. + */ + if (!b) + { + SrtpControl dtlsControl + = srtpControls.get(mediaType, SrtpControlType.DTLS_SRTP); + + if (dtlsControl != null) + { + srtpControls.remove(mediaType, SrtpControlType.DTLS_SRTP); + dtlsControl.cleanup(); + } + } + return b; + } + + /** + * Selects the preferred encryption protocol (only used by the callee). + * + * @param mediaType The type of media (AUDIO or VIDEO). + * @param localContent The element containing the media DESCRIPTION and + * its encryption. + * @param remoteContent The element containing the media DESCRIPTION and + * its encryption for the remote peer; null if the local peer is + * the initiator of the call. + */ + private void setAndAddPreferredEncryptionProtocol( + MediaType mediaType, + ContentPacketExtension localContent, + ContentPacketExtension remoteContent) + { + List preferredEncryptionProtocols + = getPeer() + .getProtocolProvider() + .getAccountID() + .getSortedEnabledEncryptionProtocolList(); + + for (String preferredEncryptionProtocol : preferredEncryptionProtocols) + { + String protoName + = preferredEncryptionProtocol.substring( + ProtocolProviderFactory.ENCRYPTION_PROTOCOL.length() + + 1); + + // DTLS-SRTP + if (DtlsControl.PROTO_NAME.equals(protoName)) + { + addDtlsAdvertisedEncryptions( + false, + remoteContent, + mediaType); + if (setDtlsEncryptionToContent( + mediaType, + localContent, + remoteContent)) + { + // Stop once an encryption advertisement has been chosen. + return; + } + } + else + { + RtpDescriptionPacketExtension localDescription + = (localContent == null) + ? null + : JingleUtils.getRtpDescription(localContent); + RtpDescriptionPacketExtension remoteDescription + = (remoteContent == null) + ? null + : JingleUtils.getRtpDescription(remoteContent); + + if (setAndAddPreferredEncryptionProtocol( + protoName, + mediaType, + localDescription, + remoteDescription)) + { + // Stop once an encryption advertisement has been chosen. + return; + } + } + } + } + + /** + * Sets DTLS-SRTP element(s) to the TRANSPORT element of the CONTENT for a + * given media. + * + * @param mediaType The type of media we are modifying the CONTENT to + * integrate the DTLS-SRTP element(s). + * @param localContent The element containing the media CONTENT and its + * TRANSPORT. + * @param remoteContent The element containing the media CONTENT and its + * TRANSPORT for the remote peer. Null, if the local peer is the initiator + * of the call. + * @return true if any DTLS-SRTP element has been added to the + * specified localContent; false, otherwise. + */ + private boolean setDtlsEncryptionToContent( + MediaType mediaType, + ContentPacketExtension localContent, + ContentPacketExtension remoteContent) + { + CallPeerJabberImpl peer = getPeer(); + ProtocolProviderServiceJabberImpl protocolProvider + = peer.getProtocolProvider(); + AccountID accountID = protocolProvider.getAccountID(); + SrtpControls srtpControls = getSrtpControls(); + boolean b = false; + + if (accountID.getAccountPropertyBoolean( + ProtocolProviderFactory.DEFAULT_ENCRYPTION, + true) + && accountID.isEncryptionProtocolEnabled( + DtlsControl.PROTO_NAME)) + { + boolean addFingerprintToLocalTransport; + + if (remoteContent == null) // initiator + { + addFingerprintToLocalTransport + = protocolProvider.isFeatureSupported( + peer.getAddress(), + ProtocolProviderServiceJabberImpl + .URN_XMPP_JINGLE_DTLS_SRTP); + } + else // responder + { + addFingerprintToLocalTransport + = addDtlsAdvertisedEncryptions( + false, + remoteContent, + mediaType); + } + if (addFingerprintToLocalTransport) + { + DtlsControl dtlsControl + = (DtlsControl) + srtpControls.getOrCreate( + mediaType, + SrtpControlType.DTLS_SRTP); + + if (dtlsControl != null) + { + int dtlsProtocol + = (remoteContent == null) + ? DtlsControl.DTLS_SERVER_PROTOCOL + : DtlsControl.DTLS_CLIENT_PROTOCOL; + + dtlsControl.setDtlsProtocol(dtlsProtocol); + b = true; + + setDtlsEncryptionToTransport(mediaType, localContent); + } + } + } + /* + * If we haven't advertised DTLS-SRTP in our (media) description, then + * DTLS-SRTP shouldn't be functioning as far as we're concerned. + */ + if (!b) + { + SrtpControl dtlsControl + = srtpControls.get(mediaType, SrtpControlType.DTLS_SRTP); + + if (dtlsControl != null) + { + srtpControls.remove(mediaType, SrtpControlType.DTLS_SRTP); + dtlsControl.cleanup(); + } + } + return b; + } + + /** + * Sets DTLS-SRTP element(s) to the TRANSPORT element of the CONTENT for a + * given media. + * + * @param mediaType The type of media we are modifying the CONTENT to + * integrate the DTLS-SRTP element(s). + * @param localContent The element containing the media CONTENT and its + * TRANSPORT. + */ + private void setDtlsEncryptionToTransport( + MediaType mediaType, + ContentPacketExtension localContent) + { + SrtpControls srtpControls = getSrtpControls(); + DtlsControl dtlsControl + = (DtlsControl) + srtpControls.get( + mediaType, + SrtpControlType.DTLS_SRTP); + + if (dtlsControl != null) + { + IceUdpTransportPacketExtension localTransport + = localContent.getFirstChildOfType( + IceUdpTransportPacketExtension.class); + + if (localTransport != null) + { + String localFingerprint = dtlsControl.getLocalFingerprint(); + String localFingerprintHashFunction + = dtlsControl.getLocalFingerprintHashFunction(); + + { + DtlsFingerprintPacketExtension localFingerprintPE + = localTransport.getFirstChildOfType( + DtlsFingerprintPacketExtension.class); + + if (localFingerprintPE == null) + { + localFingerprintPE + = new DtlsFingerprintPacketExtension(); + localTransport.addChildExtension( + localFingerprintPE); + } + localFingerprintPE.setFingerprint(localFingerprint); + localFingerprintPE.setHash( + localFingerprintHashFunction); + } + } + } + } + + /** + * Sets DTLS-SRTP element(s) to the TRANSPORT element of a specified list of + * CONTENT elements. + * + * @param localContents The elements containing the media CONTENT elements + * and their respective TRANSPORT elements. + */ + private void setDtlsEncryptionToTransports( + List localContents) + { + for (ContentPacketExtension localContent : localContents) + { + RtpDescriptionPacketExtension description + = JingleUtils.getRtpDescription(localContent); + + if (description != null) + { + MediaType mediaType = JingleUtils.getMediaType(localContent); + + if (mediaType != null) + setDtlsEncryptionToTransport(mediaType, localContent); + } + } + } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ContactJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ContactJabberImpl.java index afe59a2a6..96cf9daec 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/ContactJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/ContactJabberImpl.java @@ -14,8 +14,6 @@ import net.java.sip.communicator.service.protocol.jabberconstants.*; import org.jivesoftware.smack.*; -import org.jivesoftware.smack.packet.*; -import org.jivesoftware.smack.util.*; /** * The Jabber implementation of the service.protocol.Contact interface. diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java b/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java index 2e70e4879..024d7f23e 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java @@ -583,17 +583,18 @@ public void startCandidateHarvest( transportInfoContent.addChildExtension( createTransport(stream)); - /* We send each media content in separate transport-info. - * It is absolutely not mandatory (we can simply send all - * content in one transport-info) but the XMPP Jingle client - * Empathy (via telepathy-gabble), which is present on many - * Linux distributions and N900 mobile phone, has a bug when - * it receives more than one content in transport-info. + /* + * We send each media content in separate transport-info. It is + * absolutely not mandatory (we can simply send all content in + * one transport-info) but the XMPP Jingle client Empathy (via + * telepathy-gabble), which is present on many Linux + * distributions and N900 mobile phone, has a bug when it + * receives more than one content in transport-info. * - * The related bug has been fixed in mainstream but the - * Linux distributions have not updated their packages yet. - * That's why we made this modification to be fully - * interoperable with Empathy right now. + * The related bug has been fixed in mainstream but the Linux + * distributions have not updated their packages yet. That's why + * we made this modification to be fully interoperable with + * Empathy right now. * * In the future, we will get back to the original behavior: * sending all content in one transport-info. @@ -1160,7 +1161,8 @@ public void propertyChange(PropertyChangeEvent evt) transport.removeCandidate(candidate); Collection childExtensions - = transport.getChildExtensions(); + = transport.getChildExtensionsOfType( + CandidatePacketExtension.class); if ((childExtensions == null) || childExtensions.isEmpty()) { diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java index a43e44fb1..bd8dd88b7 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java @@ -33,9 +33,10 @@ import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.service.protocol.jabberconstants.*; import net.java.sip.communicator.util.*; - import net.java.sip.communicator.util.Logger; + import org.jitsi.service.configuration.*; +import org.jitsi.service.neomedia.*; import org.jitsi.util.*; import org.jivesoftware.smack.*; import org.jivesoftware.smack.packet.*; @@ -124,6 +125,13 @@ public class ProtocolProviderServiceJabberImpl */ public static final String URN_XMPP_JINGLE_COIN = "urn:xmpp:coin"; + /** + * Jingle's Discovery Info URN for "XEP-0320: Use of DTLS-SRTP in + * Jingle Sessions". + */ + public static final String URN_XMPP_JINGLE_DTLS_SRTP + = "urn:xmpp:jingle:apps:dtls:0"; + /** * Discovery Info URN for classic RFC3264-style Offer/Answer negotiation * with no support for Trickle ICE and low tolerance to transport/payload @@ -1889,6 +1897,16 @@ private void addJingleFeatures() // XEP-0251: Jingle Session Transfer supportedFeatures.add(URN_XMPP_JINGLE_TRANSFER_0); + + // XEP-0320: Use of DTLS-SRTP in Jingle Sessions + if (accountID.getAccountPropertyBoolean( + ProtocolProviderFactory.DEFAULT_ENCRYPTION, + true) + && accountID.isEncryptionProtocolEnabled( + DtlsControl.PROTO_NAME)) + { + supportedFeatures.add(URN_XMPP_JINGLE_DTLS_SRTP); + } } /** diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/AbstractPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/AbstractPacketExtension.java index 2f76151ff..4577c3a9f 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/AbstractPacketExtension.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/AbstractPacketExtension.java @@ -51,7 +51,7 @@ public abstract class AbstractPacketExtension /** * A list of extensions registered with this element. */ - private List childExtensions + private final List childExtensions = new ArrayList(); /** diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/IceUdpTransportPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/IceUdpTransportPacketExtension.java index 73fa1d62b..f09fcaf7d 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/IceUdpTransportPacketExtension.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/IceUdpTransportPacketExtension.java @@ -18,7 +18,8 @@ * @author Emil Ivov * @author Lyubomir Marinov */ -public class IceUdpTransportPacketExtension extends AbstractPacketExtension +public class IceUdpTransportPacketExtension + extends AbstractPacketExtension { /** * The name of the "transport" element. @@ -128,24 +129,22 @@ public String getUfrag() @Override public List getChildExtensions() { + List childExtensions + = new ArrayList(); + List superChildExtensions + = super.getChildExtensions(); + + childExtensions.addAll(superChildExtensions); + synchronized (candidateList) { - if(candidateList.size() > 0) - { - return candidateList; - } + if (candidateList.size() > 0) + childExtensions.addAll(candidateList); else if (remoteCandidate != null) - { - List list - = new ArrayList(); - list.add(remoteCandidate); - - return list; - } + childExtensions.add(remoteCandidate); } - //there are apparently no child elements. - return null; + return childExtensions; } /** @@ -191,7 +190,7 @@ public List getCandidateList() { synchronized(candidateList) { - return new ArrayList(this.candidateList); + return new ArrayList(candidateList); } } @@ -221,7 +220,7 @@ public RemoteCandidatePacketExtension getRemoteCandidate() * CandidatePacketExtension}, a {@link RemoteCandidatePacketExtension} or * something else and then adds it as such. * - * @param childExtension the extension we'd like to add here. + * @param childExtension the extension we'd like to add here. */ @Override public void addChildExtension(PacketExtension childExtension) @@ -232,5 +231,8 @@ public void addChildExtension(PacketExtension childExtension) else if(childExtension instanceof CandidatePacketExtension) addCandidate((CandidatePacketExtension) childExtension); + + else if (childExtension instanceof DtlsFingerprintPacketExtension) + super.addChildExtension(childExtension); } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/RawUdpTransportPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/RawUdpTransportPacketExtension.java index 0fd8e7594..8ee3e7760 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/RawUdpTransportPacketExtension.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/RawUdpTransportPacketExtension.java @@ -47,6 +47,7 @@ public RawUdpTransportPacketExtension() @Override public List getChildExtensions() { - return getCandidateList(); + // TODO Auto-generated method stub + return super.getChildExtensions(); } } diff --git a/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java b/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java index 9780393c5..b256fe8be 100644 --- a/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java +++ b/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java @@ -1443,6 +1443,17 @@ public boolean processKeyFrameRequest() return mediaHandler.processKeyFrameRequest(this); } + /** + * Removes from this instance and cleans up the SrtpControl which + * are not of a specific SrtpControlType. + * + * @param mediaType the MediaType of the SrtpControl to be + * examined + * @param srtpControlType the SrtpControlType of the + * SrtpControls to not be removed from this instance and cleaned + * up. If null, all SrtpControls are removed from this + * instance and cleaned up + */ protected void removeAndCleanupOtherSrtpControls( MediaType mediaType, SrtpControlType srtpControlType)