aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x.classpath2
-rw-r--r--build.xml3
-rw-r--r--lib/installer-exclude/bcpkix-jdk15on-149.jarbin0 -> 629662 bytes
-rw-r--r--lib/installer-exclude/bcprov-jdk15on-149.jar (renamed from lib/installer-exclude/bcprov-jdk15on-148.jar)bin2318161 -> 2476362 bytes
-rw-r--r--lib/installer-exclude/bcprov.manifest.mf4
-rw-r--r--lib/installer-exclude/jain-sdp.jarbin896069 -> 151866 bytes
-rw-r--r--lib/installer-exclude/libjitsi.jarbin1482741 -> 1504721 bytes
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java7
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/call/conference/BasicConferenceParticipantPanel.java7
-rw-r--r--src/net/java/sip/communicator/impl/libjitsi/libjitsi.manifest.mf15
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/AbstractCallPeerMediaHandlerJabberGTalkImpl.java189
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerGTalkImpl.java13
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java2
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java2
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/JabberAccountIDImpl.java13
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/P2PTransportManager.java2
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java4
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/DtlsFingerprintPacketExtension.java62
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java8
-rw-r--r--src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java616
-rw-r--r--src/net/java/sip/communicator/plugin/desktoputil/wizard/SecurityPanel.java2
-rw-r--r--src/net/java/sip/communicator/service/protocol/SecurityAccountRegistration.java139
-rw-r--r--src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java22
-rw-r--r--src/net/java/sip/communicator/service/protocol/media/MediaHandler.java41
-rw-r--r--src/net/java/sip/communicator/service/protocol/media/SrtpControls.java97
25 files changed, 831 insertions, 419 deletions
diff --git a/.classpath b/.classpath
index 237be5f..9a9bf4c 100755
--- a/.classpath
+++ b/.classpath
@@ -80,7 +80,7 @@
<classpathentry kind="lib" path="lib/os-specific/mac/growl4j.jar"/>
<classpathentry kind="lib" path="lib/os-specific/mac/OrangeExtensions.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/jmork-1.0.5-SNAPSHOT.jar" sourcepath="/jmork"/>
- <classpathentry kind="lib" path="lib/installer-exclude/bcprov-jdk15on-148.jar"/>
+ <classpathentry kind="lib" path="lib/installer-exclude/bcprov-jdk15on-149.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/bccontrib-1.0-SNAPSHOT.jar"/>
<classpathentry kind="lib" path="lib/installer-exclude/zrtp4j-light.jar"/>
<classpathentry kind="output" path="classes"/>
diff --git a/build.xml b/build.xml
index 96f19f8..043060e 100644
--- a/build.xml
+++ b/build.xml
@@ -1286,6 +1286,7 @@
<zipfileset dir="${dest}/net/java/sip/communicator/impl/libjitsi"
prefix="net/java/sip/communicator/impl/libjitsi"/>
+ <zipfileset src="${lib.noinst}/bcpkix-jdk15on-149.jar" prefix=""/>
<zipfileset src="${lib.noinst}/fmj.jar" prefix=""/>
<zipfileset src="${lib.noinst}/libjitsi.jar" prefix=""/>
</jar>
@@ -2517,7 +2518,7 @@ javax.swing.event, javax.swing.border"/>
<!--BUNDLE-BOUNCYCASTLE -->
<target name="bundle-bouncycastle">
- <copy file="${lib.noinst}/bcprov-jdk15on-148.jar" tofile="${bundles.dest}/bouncycastle.jar"/>
+ <copy file="${lib.noinst}/bcprov-jdk15on-149.jar" tofile="${bundles.dest}/bouncycastle.jar"/>
<copy file="${lib.noinst}/bccontrib-1.0-SNAPSHOT.jar" tofile="${bundles.dest}/bccontrib.jar"/>
</target>
diff --git a/lib/installer-exclude/bcpkix-jdk15on-149.jar b/lib/installer-exclude/bcpkix-jdk15on-149.jar
new file mode 100644
index 0000000..96d1985
--- /dev/null
+++ b/lib/installer-exclude/bcpkix-jdk15on-149.jar
Binary files differ
diff --git a/lib/installer-exclude/bcprov-jdk15on-148.jar b/lib/installer-exclude/bcprov-jdk15on-149.jar
index 3fcb136..e1d4bb3 100644
--- a/lib/installer-exclude/bcprov-jdk15on-148.jar
+++ b/lib/installer-exclude/bcprov-jdk15on-149.jar
Binary files differ
diff --git a/lib/installer-exclude/bcprov.manifest.mf b/lib/installer-exclude/bcprov.manifest.mf
index 95fd77e..402723b 100644
--- a/lib/installer-exclude/bcprov.manifest.mf
+++ b/lib/installer-exclude/bcprov.manifest.mf
@@ -361,7 +361,7 @@ Export-Package: org.bouncycastle,org.bouncycastle.asn1;uses:="org.boun
urity.auth.x500,org.bouncycastle.x509,org.bouncycastle.jce.provider,o
rg.bouncycastle.util,org.bouncycastle.asn1,javax.naming,org.bouncycas
tle.asn1.x509,org.bouncycastle.jce"
-Bundle-Version: 1.48
+Bundle-Version: 1.49
Bundle-Name: bcprov
Trusted-Library: true
Ant-Version: Apache Ant 1.6.5
@@ -371,6 +371,6 @@ Bundle-SymbolicName: bcprov
Tool: Bnd-1.30.0
Specification-Vendor: BouncyCastle.org
Extension-Name: org.bouncycastle.bcprovider
-Implementation-Version: 1.48.0
+Implementation-Version: 1.49.0
Implementation-Vendor: BouncyCastle.org
diff --git a/lib/installer-exclude/jain-sdp.jar b/lib/installer-exclude/jain-sdp.jar
index 3cda590..8f4b7a6 100644
--- a/lib/installer-exclude/jain-sdp.jar
+++ b/lib/installer-exclude/jain-sdp.jar
Binary files differ
diff --git a/lib/installer-exclude/libjitsi.jar b/lib/installer-exclude/libjitsi.jar
index c7124b2..3b3eeb1 100644
--- a/lib/installer-exclude/libjitsi.jar
+++ b/lib/installer-exclude/libjitsi.jar
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java
index 8ba3f61..49bbe47 100644
--- a/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java
@@ -843,11 +843,8 @@ public class OneToOneCallPeerPanel
SrtpControl srtpControl = evt.getSecurityController();
- if ((srtpControl.requiresSecureSignalingTransport()
- && callPeer
- .getProtocolProvider()
- .isSignalingTransportSecure())
- || !srtpControl.requiresSecureSignalingTransport())
+ if (!srtpControl.requiresSecureSignalingTransport()
+ || callPeer.getProtocolProvider().isSignalingTransportSecure())
{
if (srtpControl instanceof ZrtpControl)
{
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/conference/BasicConferenceParticipantPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/conference/BasicConferenceParticipantPanel.java
index f1876f7..744de28 100644
--- a/src/net/java/sip/communicator/impl/gui/main/call/conference/BasicConferenceParticipantPanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/call/conference/BasicConferenceParticipantPanel.java
@@ -484,10 +484,9 @@ public abstract class BasicConferenceParticipantPanel<T>
SrtpControl srtpControl = evt.getSecurityController();
- if ((srtpControl.requiresSecureSignalingTransport()
- && getCallRenderer().getCall().getProtocolProvider()
- .isSignalingTransportSecure())
- || !srtpControl.requiresSecureSignalingTransport())
+ if (!srtpControl.requiresSecureSignalingTransport()
+ || getCallRenderer().getCall().getProtocolProvider()
+ .isSignalingTransportSecure())
{
if (srtpControl instanceof ZrtpControl)
{
diff --git a/src/net/java/sip/communicator/impl/libjitsi/libjitsi.manifest.mf b/src/net/java/sip/communicator/impl/libjitsi/libjitsi.manifest.mf
index da60db3..2cf9ab5 100644
--- a/src/net/java/sip/communicator/impl/libjitsi/libjitsi.manifest.mf
+++ b/src/net/java/sip/communicator/impl/libjitsi/libjitsi.manifest.mf
@@ -48,12 +48,27 @@ Import-Package: apple.awt,
javax.xml.transform,
javax.xml.transform.dom,
javax.xml.transform.stream,
+ org.bouncycastle.asn1,
+ org.bouncycastle.asn1.cryptopro,
+ org.bouncycastle.asn1.nist,
+ org.bouncycastle.asn1.oiw,
+ org.bouncycastle.asn1.pkcs,
+ org.bouncycastle.asn1.teletrust,
+ org.bouncycastle.asn1.x500,
+ org.bouncycastle.asn1.x500.style,
+ org.bouncycastle.asn1.x509,
+ org.bouncycastle.asn1.x9,
org.bouncycastle.crypto,
org.bouncycastle.crypto.digests,
org.bouncycastle.crypto.engines,
+ org.bouncycastle.crypto.generators,
org.bouncycastle.crypto.macs,
org.bouncycastle.crypto.params,
org.bouncycastle.crypto.prng,
+ org.bouncycastle.crypto.signers,
+ org.bouncycastle.crypto.tls,
+ org.bouncycastle.crypto.util,
+ org.bouncycastle.util,
org.jitsi.bccontrib.digests,
org.jitsi.bccontrib.engines,
org.jitsi.bccontrib.macs,
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 6d2d242..7c5c690 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/AbstractCallPeerMediaHandlerJabberGTalkImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/AbstractCallPeerMediaHandlerJabberGTalkImpl.java
@@ -16,7 +16,6 @@ import net.java.sip.communicator.service.protocol.media.*;
import net.java.sip.communicator.util.*;
import org.jitsi.service.neomedia.*;
-
import org.jivesoftware.smack.packet.*;
/**
@@ -104,7 +103,8 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl
if (accountID.getAccountPropertyBoolean(
ProtocolProviderFactory.DEFAULT_ENCRYPTION,
true)
- && accountID.isEncryptionProtocolEnabled("ZRTP")
+ && accountID.isEncryptionProtocolEnabled(
+ ZrtpControl.PROTO_NAME)
&& getPeer().getCall().isSipZrtpAttribute())
{
// ZRTP
@@ -151,55 +151,33 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl
if(accountID.getAccountPropertyBoolean(
ProtocolProviderFactory.DEFAULT_ENCRYPTION,
true)
- && accountID.isEncryptionProtocolEnabled("SDES"))
+ && accountID.isEncryptionProtocolEnabled(
+ SDesControl.PROTO_NAME))
{
- Map<MediaTypeSrtpControl, SrtpControl> srtpControls
- = getSrtpControls();
- MediaTypeSrtpControl key
- = new MediaTypeSrtpControl(mediaType, SrtpControlType.SDES);
- SrtpControl control = srtpControls.get(key);
-
- if(control == null)
- {
- control
- = JabberActivator.getMediaService().createSDesControl();
- srtpControls.put(key, control);
- }
-
- SDesControl tmpSDesControl = (SDesControl) control;
+ SrtpControls srtpControls = getSrtpControls();
+ SDesControl sdesControl
+ = (SDesControl)
+ srtpControls.getOrCreate(
+ mediaType,
+ SrtpControlType.SDES);
SrtpCryptoAttribute selectedSdes
= selectSdesCryptoSuite(
isInitiator,
- tmpSDesControl,
+ sdesControl,
encryptionPacketExtension);
if(selectedSdes != null)
{
//found an SDES answer, remove all other controls
- Iterator<Map.Entry<MediaTypeSrtpControl, SrtpControl>> iter
- = srtpControls.entrySet().iterator();
-
- while (iter.hasNext())
- {
- Map.Entry<MediaTypeSrtpControl, SrtpControl> entry
- = iter.next();
- MediaTypeSrtpControl mtsc = entry.getKey();
-
- if ((mtsc.mediaType == mediaType)
- && (mtsc.srtpControlType
- != SrtpControlType.SDES))
- {
- entry.getValue().cleanup();
- iter.remove();
- }
- }
-
+ removeAndCleanupOtherSrtpControls(
+ mediaType,
+ SrtpControlType.SDES);
addAdvertisedEncryptionMethod(SrtpControlType.SDES);
}
else
{
- control.cleanup();
- srtpControls.remove(key);
+ sdesControl.cleanup();
+ srtpControls.remove(mediaType, SrtpControlType.SDES);
}
}
}
@@ -207,27 +185,12 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl
// manage it, then we must remove the unusable SDES srtpControl.
else if(isInitiator)
{
- AccountID accountID
- = getPeer().getProtocolProvider().getAccountID();
-
// SDES
- if(accountID.getAccountPropertyBoolean(
- ProtocolProviderFactory.DEFAULT_ENCRYPTION,
- true)
- && accountID.isEncryptionProtocolEnabled("SDES"))
- {
- Map<MediaTypeSrtpControl, SrtpControl> srtpControls
- = getSrtpControls();
- MediaTypeSrtpControl key
- = new MediaTypeSrtpControl(mediaType, SrtpControlType.SDES);
- SrtpControl control = srtpControls.get(key);
+ SrtpControl scontrol
+ = getSrtpControls().remove(mediaType, SrtpControlType.SDES);
- if(control != null)
- {
- control.cleanup();
- srtpControls.remove(key);
- }
- }
+ if (scontrol != null)
+ scontrol.cleanup();
}
}
@@ -283,11 +246,8 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl
for(int i = 0; i < packetExtensions.size(); ++i)
{
if(packetExtensions.get(i) instanceof ZrtpHashPacketExtension)
- {
return true;
- }
}
-
return false;
}
@@ -338,29 +298,21 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl
if(accountID.getAccountPropertyBoolean(
ProtocolProviderFactory.DEFAULT_ENCRYPTION,
true)
- && accountID.isEncryptionProtocolEnabled("ZRTP")
+ && accountID.isEncryptionProtocolEnabled(
+ ZrtpControl.PROTO_NAME)
&& peer.getCall().isSipZrtpAttribute())
{
- Map<MediaTypeSrtpControl, SrtpControl> srtpControls
- = getSrtpControls();
- MediaTypeSrtpControl key
- = new MediaTypeSrtpControl(mediaType, SrtpControlType.ZRTP);
- SrtpControl control = srtpControls.get(key);
-
- if(control == null)
- {
- control
- = JabberActivator.getMediaService().createZrtpControl();
- srtpControls.put(key, control);
- }
-
- ZrtpControl zcontrol = (ZrtpControl) control;
- int versionIndex = zcontrol.getNumberSupportedVersions();
-
- for (int i = 0; i < versionIndex; i++)
+ ZrtpControl zrtpControl
+ = (ZrtpControl)
+ getSrtpControls().getOrCreate(
+ mediaType,
+ SrtpControlType.ZRTP);
+ int numberSupportedVersions
+ = zrtpControl.getNumberSupportedVersions();
+
+ for (int i = 0; i < numberSupportedVersions; i++)
{
- String helloHash[]
- = ((ZrtpControl) control).getHelloHashSep(i);
+ String helloHash[] = zrtpControl.getHelloHashSep(i);
if ((helloHash != null) && (helloHash[1].length() > 0))
{
@@ -415,23 +367,15 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl
if (accountID.getAccountPropertyBoolean(
ProtocolProviderFactory.DEFAULT_ENCRYPTION,
true)
- && accountID.isEncryptionProtocolEnabled("SDES"))
+ && accountID.isEncryptionProtocolEnabled(
+ SDesControl.PROTO_NAME))
{
// get or create the control
- Map<MediaTypeSrtpControl, SrtpControl> srtpControls
- = getSrtpControls();
- MediaTypeSrtpControl key
- = new MediaTypeSrtpControl(mediaType, SrtpControlType.SDES);
- SrtpControl control = srtpControls.get(key);
-
- if (control == null)
- {
- control = JabberActivator.getMediaService().createSDesControl();
- srtpControls.put(key, control);
- }
-
+ SrtpControls srtpControls = getSrtpControls();
+ SDesControl sdesControl
+ = (SDesControl)
+ srtpControls.getOrCreate(mediaType, SrtpControlType.SDES);
// set the enabled ciphers suites
- SDesControl sdcontrol = (SDesControl) control;
String ciphers
= accountID.getAccountPropertyString(
ProtocolProviderFactory.SDES_CIPHER_SUITES);
@@ -442,7 +386,7 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl
JabberActivator.getResources().getSettingsString(
SDesControl.SDES_CIPHER_SUITES);
}
- sdcontrol.setEnabledCiphers(Arrays.asList(ciphers.split(",")));
+ sdesControl.setEnabledCiphers(Arrays.asList(ciphers.split(",")));
// act as initiator
if (remoteDescription == null)
@@ -457,7 +401,7 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl
localDescription.addChildExtension(localEncryption);
}
for(SrtpCryptoAttribute ca:
- sdcontrol.getInitiatorCryptoAttributes())
+ sdesControl.getInitiatorCryptoAttributes())
{
CryptoPacketExtension crypto
= new CryptoPacketExtension(ca);
@@ -479,7 +423,7 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl
{
SrtpCryptoAttribute selectedSdes = selectSdesCryptoSuite(
false,
- sdcontrol,
+ sdesControl,
remoteEncryption);
if(selectedSdes != null)
@@ -505,8 +449,8 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl
{
// none of the offered suites match, destroy the sdes
// control
- sdcontrol.cleanup();
- srtpControls.remove(key);
+ sdesControl.cleanup();
+ srtpControls.remove(mediaType, SrtpControlType.SDES);
logger.warn(
"Received unsupported sdes crypto attribute");
}
@@ -515,8 +459,8 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl
{
// peer doesn't offer any SDES attribute, destroy the sdes
// control
- sdcontrol.cleanup();
- srtpControls.remove(key);
+ sdesControl.cleanup();
+ srtpControls.remove(mediaType, SrtpControlType.SDES);
}
}
}
@@ -548,9 +492,29 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl
for(String preferredEncryptionProtocol : preferredEncryptionProtocols)
{
+ String protoName
+ = preferredEncryptionProtocol.substring(
+ ProtocolProviderFactory.ENCRYPTION_PROTOCOL.length()
+ + 1);
+
+ // 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;
+ }
+ }
// ZRTP
- if(preferredEncryptionProtocol.equals(
- ProtocolProviderFactory.ENCRYPTION_PROTOCOL + ".ZRTP"))
+ else if(ZrtpControl.PROTO_NAME.equals(protoName))
{
boolean isZRTPAddedToDescription
= setZrtpEncryptionToDescription(
@@ -564,24 +528,7 @@ public abstract class AbstractCallPeerMediaHandlerJabberGTalkImpl
false,
remoteDescription,
mediaType);
- // Stops once an encryption advertisement has been chosen.
- return;
- }
- }
- // SDES
- else if(preferredEncryptionProtocol.equals(
- ProtocolProviderFactory.ENCRYPTION_PROTOCOL + ".SDES"))
- {
- addSDESAdvertisedEncryptions(
- false,
- remoteDescription,
- mediaType);
- if(setSDesEncryptionToDescription(
- mediaType,
- localDescription,
- remoteDescription))
- {
- // Stops once an encryption advertisement has been chosen.
+ // Stop once an encryption advertisement has been chosen.
return;
}
}
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 4185a6d..6c4e190 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerGTalkImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerGTalkImpl.java
@@ -222,11 +222,11 @@ public class CallPeerMediaHandlerGTalkImpl
* @throws OperationFailedException if we fail to configure the media stream
*/
public RtpDescriptionPacketExtension generateSessionAccept(
- boolean initStream)
+ boolean initStream)
throws OperationFailedException
{
- RtpDescriptionPacketExtension description =
- new RtpDescriptionPacketExtension();
+ RtpDescriptionPacketExtension description
+ = new RtpDescriptionPacketExtension();
List<PayloadTypePacketExtension> lst = localContentMap.get("audio");
description.setNamespace(SessionIQProvider.GTALK_AUDIO_NAMESPACE);
@@ -282,11 +282,10 @@ public class CallPeerMediaHandlerGTalkImpl
continue;
// stream target
- MediaStreamTarget target = transportManager.getStreamTarget(
- mediaType);
+ MediaStreamTarget target
+ = transportManager.getStreamTarget(mediaType);
- List<RTPExtension> rtpExtensions =
- new ArrayList<RTPExtension>();
+ List<RTPExtension> rtpExtensions = new ArrayList<RTPExtension>();
MediaDirection direction = MediaDirection.SENDRECV;
boolean masterStream = false;
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 052e645..727b735 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/CallPeerMediaHandlerJabberImpl.java
@@ -918,8 +918,6 @@ public class CallPeerMediaHandlerJabberImpl
* Jitsi VideoBridge working on the server, prefer a
* transport which will route the conference through there.
*/
- CallJabberImpl call = peer.getCall();
-
if (isJitsiVideoBridge)
{
/*
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 b3f877d..2e70e48 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/IceUdpTransportManager.java
@@ -661,7 +661,7 @@ public class IceUdpTransportManager
*
* @return the {@link IceUdpTransportPacketExtension} that we
*/
- public PacketExtension createTransport(IceMediaStream stream)
+ protected PacketExtension createTransport(IceMediaStream stream)
{
IceUdpTransportPacketExtension trans
= new IceUdpTransportPacketExtension();
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/JabberAccountIDImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/JabberAccountIDImpl.java
index 9364d38..af33659 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/JabberAccountIDImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/JabberAccountIDImpl.java
@@ -32,19 +32,6 @@ public class JabberAccountIDImpl
}
/**
- * Returns the service name - the server we are logging to
- * if it is null which is not supposed to be - we return for compatibility
- * the string we used in the first release for creating AccountID
- * (Using this string is wrong, but used for compatibility for now)
- * @param accountProperties Map
- * @return String
- */
- private static String getServiceName(Map<String, String> accountProperties)
- {
- return accountProperties.get(ProtocolProviderFactory.SERVER_ADDRESS);
- }
-
- /**
* Returns the list of STUN servers that this account is currently
* configured to use.
*
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/P2PTransportManager.java b/src/net/java/sip/communicator/impl/protocol/jabber/P2PTransportManager.java
index 50f0a68..546ce99 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/P2PTransportManager.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/P2PTransportManager.java
@@ -120,7 +120,7 @@ public class P2PTransportManager
* @return the {@link GTalkTransportPacketExtension}
*/
@Override
- public PacketExtension createTransport(IceMediaStream stream)
+ protected PacketExtension createTransport(IceMediaStream stream)
{
GTalkTransportPacketExtension trans
= new GTalkTransportPacketExtension();
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java b/src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java
index 928487e..17bd9c8 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/RawUdpTransportManager.java
@@ -227,8 +227,8 @@ public class RawUdpTransportManager
MediaType mediaType,
StreamConnector connector)
{
- ColibriConferenceIQ.Channel channel = getColibriChannel(mediaType,
- false);
+ ColibriConferenceIQ.Channel channel
+ = getColibriChannel(mediaType, false);
RawUdpTransportPacketExtension ourTransport
= new RawUdpTransportPacketExtension();
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/DtlsFingerprintPacketExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/DtlsFingerprintPacketExtension.java
new file mode 100644
index 0000000..440cca4
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/DtlsFingerprintPacketExtension.java
@@ -0,0 +1,62 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.jabber.extensions.jingle;
+
+import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
+
+/**
+ *
+ * @author Lyubomir Marinov
+ */
+public class DtlsFingerprintPacketExtension
+ extends AbstractPacketExtension
+{
+ public static final String ELEMENT_NAME = "fingerprint";
+
+ private static final String HASH_ATTR_NAME = "hash";
+
+ public static final String NAMESPACE = "urn:xmpp:jingle:apps:dtls:0";
+
+ private static final String REQUIRED_ATTR_NAME = "required";
+
+ public DtlsFingerprintPacketExtension()
+ {
+ super(NAMESPACE, ELEMENT_NAME);
+ }
+
+ public String getFingerprint()
+ {
+ return getText();
+ }
+
+ public String getHash()
+ {
+ return getAttributeAsString(HASH_ATTR_NAME);
+ }
+
+ public boolean getRequired()
+ {
+ String attr = getAttributeAsString(REQUIRED_ATTR_NAME);
+
+ return (attr == null) ? false : Boolean.parseBoolean(attr);
+ }
+
+ public void setFingerprint(String fingerprint)
+ {
+ setText(fingerprint);
+ }
+
+ public void setHash(String hash)
+ {
+ setAttribute(HASH_ATTR_NAME, hash);
+ }
+
+ public void setRequired(boolean required)
+ {
+ setAttribute(REQUIRED_ATTR_NAME, Boolean.valueOf(required));
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java
index 4b36b56..583906d 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/jingle/JingleIQProvider.java
@@ -142,6 +142,14 @@ public class JingleIQProvider implements IQProvider
new DefaultPacketExtensionProvider<CoinPacketExtension>(
CoinPacketExtension.class));
+ // DTLS-SRTP
+ providerManager.addExtensionProvider(
+ DtlsFingerprintPacketExtension.ELEMENT_NAME,
+ DtlsFingerprintPacketExtension.NAMESPACE,
+ new DefaultPacketExtensionProvider
+ <DtlsFingerprintPacketExtension>(
+ DtlsFingerprintPacketExtension.class));
+
/*
* XEP-0251: Jingle Session Transfer <transfer/> and <transferred>
* providers
diff --git a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java
index 7cbd5f7..246a26b 100644
--- a/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/sip/CallPeerMediaHandlerSipImpl.java
@@ -32,12 +32,27 @@ import ch.imvs.sdes4j.srtp.*;
* both classes are only separated for reasons of readability.
*
* @author Emil Ivov
- * @author Lubomir Marinov
+ * @author Lyubomir Marinov
*/
public class CallPeerMediaHandlerSipImpl
extends CallPeerMediaHandler<CallPeerSipImpl>
{
/**
+ * The name of the SDP attribute which specifies the fingerprint and hash
+ * function which has computed it of the certificate to validate a DTLS
+ * flow.
+ */
+ private static final String DTLS_SRTP_FINGERPRINT_ATTR = "fingerprint";
+
+ private static final String DTLS_SRTP_SETUP_ACTIVE = "active";
+
+ private static final String DTLS_SRTP_SETUP_ACTPASS = "actpass";
+
+ private static final String DTLS_SRTP_SETUP_ATTR = "setup";
+
+ private static final String DTLS_SRTP_SETUP_PASSIVE = "passive";
+
+ /**
* Our class logger.
*/
private static final Logger logger
@@ -197,9 +212,7 @@ public class CallPeerMediaHandlerSipImpl
if(direction != MediaDirection.INACTIVE)
{
- boolean hadSavp = false;
-
- for (String profileName : getRtpTransports())
+ for (String proto : getRtpTransports())
{
/*
* If we start an audio-only call and re-INVITE the remote
@@ -213,7 +226,7 @@ public class CallPeerMediaHandlerSipImpl
= direction.allowsSending() ? sendQualityPreset : null;
MediaDescription md
= createMediaDescription(
- profileName,
+ proto,
getLocallySupportedFormats(
dev,
effectiveSendQualityPreset,
@@ -247,16 +260,36 @@ public class CallPeerMediaHandlerSipImpl
// do nothing in case of error.
}
- if(!hadSavp)
+ if (DtlsControl.UDP_TLS_RTP_SAVP.equals(proto)
+ || DtlsControl.UDP_TLS_RTP_SAVPF.equals(proto))
+ {
+ updateMediaDescriptionForDtls(mediaType, md, null);
+ }
+ else
{
- updateMediaDescriptionForZrtp(mediaType, md);
- updateMediaDescriptionForSDes(mediaType, md, null);
+ /*
+ * According to RFC 6189 "ZRTP: Media Path Key Agreement
+ * for Unicast Secure RTP", "ZRTP utilizes normal
+ * RTP/AVP (Audio-Visual Profile) profiles", "[t]he
+ * Secure RTP/AVP (SAVP) profile MAY be used in
+ * subsequent offer/answer exchanges after a successful
+ * ZRTP exchange has resulted in an SRTP session, or if
+ * it is known that the other endpoint supports this
+ * profile" and "[o]ther profiles MAY also be used."
+ */
+ updateMediaDescriptionForZrtp(mediaType, md, null);
+ /*
+ * According to Ingo Bauersachs, SDES "[b]asically
+ * requires SAVP per RFC."
+ */
+ if (SrtpControl.RTP_SAVP.equals(proto)
+ || SrtpControl.RTP_SAVPF.equals(proto))
+ {
+ updateMediaDescriptionForSDes(mediaType, md, null);
+ }
}
mediaDescs.add(md);
-
- if(!hadSavp && profileName.contains("SAVP"))
- hadSavp = true;
}
}
}
@@ -426,16 +459,15 @@ public class CallPeerMediaHandlerSipImpl
* or semantics of <tt>newOffer</tt>.
*/
private Vector<MediaDescription> createMediaDescriptionsForAnswer(
- SessionDescription offer)
+ SessionDescription offer)
throws OperationFailedException,
IllegalArgumentException
{
- List<MediaDescription> remoteDescriptions = SdpUtils
- .extractMediaDescriptions(offer);
-
+ List<MediaDescription> remoteDescriptions
+ = SdpUtils.extractMediaDescriptions(offer);
// prepare to generate answers to all the incoming descriptions
Vector<MediaDescription> answerDescriptions
- = new Vector<MediaDescription>( remoteDescriptions.size() );
+ = new Vector<MediaDescription>(remoteDescriptions.size());
this.setCallInfoURL(SdpUtils.getCallInfoURL(offer));
@@ -457,22 +489,26 @@ public class CallPeerMediaHandlerSipImpl
for (MediaDescription mediaDescription : remoteDescriptions)
{
- String transportProtocol;
+ String proto;
try
{
- transportProtocol = mediaDescription.getMedia().getProtocol();
+ proto = mediaDescription.getMedia().getProtocol();
}
catch (SdpParseException e)
{
throw new OperationFailedException(
- "unable to create the media description",
- OperationFailedException.ILLEGAL_ARGUMENT, e);
+ "Unable to create the media description",
+ OperationFailedException.ILLEGAL_ARGUMENT,
+ e);
}
- //ignore RTP/AVP(F) stream when RTP/SAVP(F) is mandatory
+ /*
+ * Ignore a RTP/AVP(F) stream when RTP/SAVP(F) is mandatory. At the
+ * time of this writing we support ZRTP, SDES and DTLS-SRTP.
+ */
if ((savpOption == ProtocolProviderFactory.SAVP_MANDATORY)
- && !(transportProtocol.equals("RTP/SAVP")
- || transportProtocol.equals("RTP/SAVPF")))
+ && !(proto.endsWith(SrtpControl.RTP_SAVP)
+ || proto.endsWith(SrtpControl.RTP_SAVPF)))
{
rejectedAvpOfferDueToSavpMandatory = true;
continue;
@@ -630,7 +666,7 @@ public class CallPeerMediaHandlerSipImpl
MediaDescription md
= createMediaDescription(
- transportProtocol,
+ proto,
mutuallySupportedFormats,
connector,
direction,
@@ -676,7 +712,6 @@ public class CallPeerMediaHandlerSipImpl
atLeastOneValidDescription = true;
}
-
if (!atLeastOneValidDescription)
{
if (rejectedAvpOfferDueToSavpMandatory)
@@ -699,72 +734,270 @@ public class CallPeerMediaHandlerSipImpl
}
/**
- * Updates the supplied description with zrtp hello hash if necessary.
- *
- * @param mediaType the media type.
- * @param md the description to be updated.
+ * Updates a specific local <tt>MediaDescription</tt> and the state of this
+ * instance for the purposes of DTLS-SRTP.
*
- * @return True if ZRTP is added tp the media description. False, otherwise.
+ * @param mediaType the <tt>MediaType</tt> of the media described by
+ * <tt>localMd</tt> and <tt>remoteMd</tt>
+ * @param localMd the local <tt>MediaDescription</tt> to be updated
+ * @param remoteMd the remote <tt>MediaDescription</tt>, if any, associated
+ * with <tt>localMd</tt>
+ * @return <tt>true</tt> if the specified <tt>localMd</tt> and/or the state
+ * of this instance was updated for the purposes of DTLS-SRTP or
+ * <tt>false</tt> if the specified <tt>localMd</tt> (and <tt>remoteMd</tt>)
+ * did not concern DTLS-SRTP
*/
- private boolean updateMediaDescriptionForZrtp(
- MediaType mediaType, MediaDescription md)
+ private boolean updateMediaDescriptionForDtls(
+ MediaType mediaType,
+ MediaDescription localMd,
+ MediaDescription remoteMd)
{
- MediaAwareCallPeer<?, ?, ?> peer = getPeer();
- AccountID accountID = peer.getProtocolProvider().getAccountID();
+ AccountID accountID = getPeer().getProtocolProvider().getAccountID();
+ boolean b = false;
- if(accountID.getAccountPropertyBoolean(
+ if (accountID.getAccountPropertyBoolean(
ProtocolProviderFactory.DEFAULT_ENCRYPTION,
true)
- && accountID.isEncryptionProtocolEnabled("ZRTP")
- && peer.getCall().isSipZrtpAttribute())
+ && accountID.isEncryptionProtocolEnabled(
+ DtlsControl.PROTO_NAME))
+ {
+ /*
+ * The transport protocol of the media described by localMd should
+ * be DTLS-SRTP in order to be of any concern here.
+ */
+ Media localMedia = localMd.getMedia();
+
+ if (localMedia != null)
+ {
+ String proto;
+
+ try
+ {
+ proto = localMedia.getProtocol();
+ }
+ catch (SdpParseException e)
+ {
+ /*
+ * Well, if the protocol of the Media cannot be parsed, then
+ * surely we do not want to have anything to do with it.
+ */
+ proto = null;
+ }
+
+ boolean dtls
+ = DtlsControl.UDP_TLS_RTP_SAVP.equals(proto)
+ || DtlsControl.UDP_TLS_RTP_SAVPF.equals(proto);
+ SrtpControls srtpControls = getSrtpControls();
+
+ if (dtls)
+ {
+ DtlsControl dtlsControl
+ = (DtlsControl)
+ srtpControls.getOrCreate(
+ mediaType,
+ SrtpControlType.DTLS_SRTP);
+
+ // SDP attributes
+ @SuppressWarnings("unchecked")
+ Vector<Attribute> attrs = localMd.getAttributes(true);
+
+ // setup
+ String setup
+ = (remoteMd == null)
+ ? DTLS_SRTP_SETUP_ACTPASS
+ : DTLS_SRTP_SETUP_ACTIVE;
+ Attribute setupAttr
+ = SdpUtils.createAttribute(DTLS_SRTP_SETUP_ATTR, setup);
+
+ attrs.add(setupAttr);
+
+ // fingerprint
+ String hashFunction
+ = dtlsControl.getLocalFingerprintHashFunction();
+ String fingerprint = dtlsControl.getLocalFingerprint();
+ Attribute fingerprintAttr
+ = SdpUtils.createAttribute(
+ DTLS_SRTP_FINGERPRINT_ATTR,
+ hashFunction + " " + fingerprint);
+
+ attrs.add(fingerprintAttr);
+
+ int dtlsProtocol
+ = DTLS_SRTP_SETUP_ACTIVE.equals(setup)
+ ? DtlsControl.DTLS_CLIENT_PROTOCOL
+ : DtlsControl.DTLS_SERVER_PROTOCOL;
+
+ dtlsControl.setDtlsProtocol(dtlsProtocol);
+
+ if (remoteMd != null) // answer
+ updateSrtpControlsForDtls(mediaType, localMd, remoteMd);
+
+ b = true;
+ }
+ else if (remoteMd != null) // answer
+ {
+ /*
+ * If DTLS-SRTP has been rejected as the transport protocol,
+ * then halt the operation of DTLS-SRTP.
+ */
+ SrtpControl dtlsControl
+ = srtpControls.remove(
+ mediaType,
+ SrtpControlType.DTLS_SRTP);
+
+ if (dtlsControl != null)
+ dtlsControl.cleanup();
+ }
+ }
+ }
+ return b;
+ }
+
+ /**
+ * Updates the <tt>SrtpControls</tt> of this instance in accord with a
+ * specific <tt>MediaDescription</tt> presented by a remote peer.
+ *
+ * @param mediaType the <tt>MediaType</tt> of the specified
+ * <tt>MediaDescription</tt> to be analyzed
+ * @param localMd the <tt>MediaDescription</tt> of the local peer that is
+ * the answer to the offer presented by a remote peer represented by
+ * <tt>remoteMd</tt> or <tt>null</tt> if the specified <tt>remoteMd</tt> is
+ * an answer to an offer of the local peer
+ * @param remoteMd the <tt>MediaDescription</tt> presented by a remote peer
+ * to be analyzed
+ */
+ private void updateSrtpControlsForDtls(
+ MediaType mediaType,
+ MediaDescription localMd,
+ MediaDescription remoteMd)
+ {
+ SrtpControls srtpControls = getSrtpControls();
+ DtlsControl dtlsControl
+ = (DtlsControl)
+ srtpControls.get(mediaType, SrtpControlType.DTLS_SRTP);
+
+ if (dtlsControl == null)
+ return;
+
+ Media remoteMedia = remoteMd.getMedia();
+ boolean dtls = false;
+
+ if (remoteMedia != null)
{
+ String proto;
+
try
{
- Map<MediaTypeSrtpControl, SrtpControl> srtpControls
- = getSrtpControls();
- MediaTypeSrtpControl key
- = new MediaTypeSrtpControl(mediaType, SrtpControlType.ZRTP);
- SrtpControl scontrol = srtpControls.get(key);
+ proto = remoteMedia.getProtocol();
+ }
+ catch (SdpParseException e)
+ {
+ /*
+ * Well, if the protocol of the Media cannot be parsed, then
+ * surely we do not want to have anything to do with it.
+ */
+ proto = null;
+ }
+ dtls
+ = DtlsControl.UDP_TLS_RTP_SAVP.equals(proto)
+ || DtlsControl.UDP_TLS_RTP_SAVPF.equals(proto);
+ }
+ if (dtls)
+ {
+ if (localMd == null) // answer
+ {
+ // setup
+ /*
+ * RFC 5763 requires setup:actpass from the offerer i.e. the
+ * offerer is the DTLS server and recommends setup:active to the
+ * answerer i.e the answerer is the DTLS client. If the answerer
+ * chooses setup:passive i.e. the answerer is the DTLS server,
+ * the offerer has to become the DTLS client.
+ */
+ String setup;
- if(scontrol == null)
+ try
+ {
+ setup = remoteMd.getAttribute(DTLS_SRTP_SETUP_ATTR);
+ }
+ catch (SdpParseException spe)
+ {
+ setup = null;
+ }
+ if (DTLS_SRTP_SETUP_PASSIVE.equals(setup))
{
- scontrol
- = SipActivator.getMediaService().createZrtpControl();
- srtpControls.put(key, scontrol);
+ dtlsControl.setDtlsProtocol(
+ DtlsControl.DTLS_CLIENT_PROTOCOL);
}
+ }
- ZrtpControl zcontrol = (ZrtpControl) scontrol;
- int versionIndex = zcontrol.getNumberSupportedVersions();
- boolean zrtpHashSet = false; // will become true if at least one is set
+ // fingerprint
+ @SuppressWarnings("unchecked")
+ Vector<Attribute> attrs = remoteMd.getAttributes(false);
+ Map<String, String> remoteFingerprints
+ = new LinkedHashMap<String, String>();
- for (int i = 0; i < versionIndex; i++)
+ if (attrs != null)
+ {
+ for (Attribute attr : attrs)
{
- String helloHash = zcontrol.getHelloHash(i);
+ String fingerprint;
- if ((helloHash != null) && helloHash.length() > 0)
+ try
{
- md.setAttribute(SdpUtils.ZRTP_HASH_ATTR, helloHash);
- zrtpHashSet = true;
+ if (DTLS_SRTP_FINGERPRINT_ATTR.equals(attr.getName()))
+ {
+ fingerprint = attr.getValue();
+ if (fingerprint == null)
+ continue;
+ else
+ fingerprint = fingerprint.trim();
+ }
+ else
+ {
+ continue;
+ }
+ }
+ catch (SdpParseException spe)
+ {
+ /*
+ * Whatever part of the SDP failed to parse, we would
+ * better not try to recover from it.
+ */
+ continue;
+ }
+
+ int spIndex = fingerprint.indexOf(' ');
+
+ if ((spIndex > 0) && (spIndex < fingerprint.length() - 1))
+ {
+ String hashFunction = fingerprint.substring(0, spIndex);
+
+ fingerprint = fingerprint.substring(spIndex + 1);
+ remoteFingerprints.put(hashFunction, fingerprint);
}
}
- return zrtpHashSet;
- }
- catch (SdpException ex)
- {
- logger.error("Cannot add zrtp-hash to sdp", ex);
}
+ dtlsControl.setRemoteFingerprints(remoteFingerprints);
+
+ removeAndCleanupOtherSrtpControls(
+ mediaType,
+ SrtpControlType.DTLS_SRTP);
+ }
+ else
+ {
+ srtpControls.remove(mediaType, SrtpControlType.DTLS_SRTP);
+ dtlsControl.cleanup();
}
- return false;
}
/**
- * Updates the supplied description with SDES attributes if necessary.
+ * Updates the supplied media description with SDES attributes if necessary.
*
* @param mediaType the media type.
* @param localMd the description of the local peer.
* @param remoteMd the description of the remote peer.
- *
- * @return <tt>true</tt> if SDES is added to the media description;
+ * @return <tt>true</tt> if SDES has been added to the media description;
* <tt>false</tt>, otherwise.
*/
private boolean updateMediaDescriptionForSDes(
@@ -774,29 +1007,22 @@ public class CallPeerMediaHandlerSipImpl
{
AccountID accountID = getPeer().getProtocolProvider().getAccountID();
- // check if SDES and encryption is enabled at all
+ // Check if encryption and SDES are enabled at all.
if(!accountID.getAccountPropertyBoolean(
ProtocolProviderFactory.DEFAULT_ENCRYPTION,
true)
- || !accountID.isEncryptionProtocolEnabled("SDES"))
+ || !accountID.isEncryptionProtocolEnabled(
+ SDesControl.PROTO_NAME))
{
return false;
}
// get or create the control
- Map<MediaTypeSrtpControl, SrtpControl> srtpControls = getSrtpControls();
- MediaTypeSrtpControl key
- = new MediaTypeSrtpControl(mediaType, SrtpControlType.SDES);
- SrtpControl scontrol = srtpControls.get(key);
-
- if (scontrol == null)
- {
- scontrol = SipActivator.getMediaService().createSDesControl();
- srtpControls.put(key, scontrol);
- }
-
+ SrtpControls srtpControls = getSrtpControls();
+ SDesControl sdesControl
+ = (SDesControl)
+ srtpControls.getOrCreate(mediaType, SrtpControlType.SDES);
// set the enabled ciphers suites
- SDesControl sdcontrol = (SDesControl) scontrol;
String ciphers
= accountID.getAccountPropertyString(
ProtocolProviderFactory.SDES_CIPHER_SUITES);
@@ -807,26 +1033,24 @@ public class CallPeerMediaHandlerSipImpl
= SipActivator.getResources().getSettingsString(
SDesControl.SDES_CIPHER_SUITES);
}
- sdcontrol.setEnabledCiphers(Arrays.asList(ciphers.split(",")));
+ sdesControl.setEnabledCiphers(Arrays.asList(ciphers.split(",")));
- // act as initiator
- if (remoteMd == null)
+ if (remoteMd == null) // act as initiator
{
@SuppressWarnings("unchecked")
Vector<Attribute> atts = localMd.getAttributes(true);
for (SrtpCryptoAttribute ca
- : sdcontrol.getInitiatorCryptoAttributes())
+ : sdesControl.getInitiatorCryptoAttributes())
{
atts.add(SdpUtils.createAttribute("crypto", ca.encode()));
}
return true;
}
- // act as responder
- else
+ else // act as responder
{
SrtpCryptoAttribute localAttr
- = selectSdesCryptoSuite(false, sdcontrol, remoteMd);
+ = selectSdesCryptoSuite(false, sdesControl, remoteMd);
if (localAttr != null)
{
@@ -842,16 +1066,84 @@ public class CallPeerMediaHandlerSipImpl
}
else
{
- // none of the offered suites match, destroy the sdes control
- sdcontrol.cleanup();
- srtpControls.remove(key);
+ // None of the offered suites match, destroy the SDES control.
+ sdesControl.cleanup();
+ srtpControls.remove(mediaType, SrtpControlType.SDES);
logger.warn("Received unsupported sdes crypto attribute.");
}
return false;
}
}
- private List<String> getRtpTransports() throws OperationFailedException
+ /**
+ * Updates the supplied media description with ZRTP hello hash if necessary.
+ *
+ * @param mediaType the media type.
+ * @param localMd the media description to update.
+ * @return <tt>true</tt> if ZRTP is added to the media description;
+ * <tt>false</tt>, otherwise.
+ */
+ private boolean updateMediaDescriptionForZrtp(
+ MediaType mediaType,
+ MediaDescription localMd,
+ MediaDescription remoteMd)
+ {
+ MediaAwareCallPeer<?, ?, ?> peer = getPeer();
+ AccountID accountID = peer.getProtocolProvider().getAccountID();
+ boolean b = false;
+
+ if(accountID.getAccountPropertyBoolean(
+ ProtocolProviderFactory.DEFAULT_ENCRYPTION,
+ true)
+ && accountID.isEncryptionProtocolEnabled(ZrtpControl.PROTO_NAME)
+ && peer.getCall().isSipZrtpAttribute())
+ {
+ ZrtpControl zrtpControl
+ = (ZrtpControl)
+ getSrtpControls().getOrCreate(
+ mediaType,
+ SrtpControlType.ZRTP);
+ int numberSupportedVersions
+ = zrtpControl.getNumberSupportedVersions();
+
+ try
+ {
+ for (int i = 0; i < numberSupportedVersions; i++)
+ {
+ String helloHash = zrtpControl.getHelloHash(i);
+
+ if ((helloHash != null) && helloHash.length() > 0)
+ {
+ localMd.setAttribute(
+ SdpUtils.ZRTP_HASH_ATTR,
+ helloHash);
+ /*
+ * Will return true if at least one zrtp-hash has been
+ * set.
+ */
+ b = true;
+ }
+ }
+ }
+ catch (SdpException ex)
+ {
+ logger.error("Cannot add zrtp-hash to sdp", ex);
+ }
+ }
+ return b;
+ }
+
+ /**
+ * Gets a list of (RTP) transport protocols (i.e. <tt>&lt;proto&gt;</tt>) to
+ * be announced in a SDP media description (i.e. <tt>m=</tt> line).
+ *
+ * @return a <tt>List</tt> of (RTP) transport protocols to be announced in a
+ * SDP media description
+ * @throws OperationFailedException if the value of the <tt>AccountID</tt>
+ * property {@link ProtocolProviderFactory#SAVP_OPTION} is invalid
+ */
+ private List<String> getRtpTransports()
+ throws OperationFailedException
{
AccountID accountID = getPeer().getProtocolProvider().getAccountID();
int savpOption
@@ -862,25 +1154,65 @@ public class CallPeerMediaHandlerSipImpl
ProtocolProviderFactory.SAVP_OPTION,
ProtocolProviderFactory.SAVP_OFF)
: ProtocolProviderFactory.SAVP_OFF;
- List<String> result = new ArrayList<String>(2);
+ List<String> result = new ArrayList<String>(3);
- switch (savpOption)
+ if (savpOption == ProtocolProviderFactory.SAVP_OFF)
{
- case ProtocolProviderFactory.SAVP_MANDATORY:
- result.add("RTP/SAVP");
- break;
- case ProtocolProviderFactory.SAVP_OFF:
- result.add(SdpConstants.RTP_AVP);
- break;
- case ProtocolProviderFactory.SAVP_OPTIONAL:
- result.add("RTP/SAVP");
result.add(SdpConstants.RTP_AVP);
- break;
- default:
- throw new OperationFailedException(
- "invalid value for SAVP_OPTION",
- OperationFailedException.GENERAL_ERROR);
}
+ else
+ {
+ /*
+ * List the secure transports in the result according to the order
+ * of preference of their respective encryption protocols.
+ */
+ List<String> encryptionProtocols
+ = accountID.getSortedEnabledEncryptionProtocolList();
+ int encryptionProtocolCount = encryptionProtocols.size();
+
+ for (int i = encryptionProtocolCount - 1; i >= 0; i--)
+ {
+ String encryptionProtocol = encryptionProtocols.get(i);
+ String protoName
+ = encryptionProtocol.substring(
+ ProtocolProviderFactory.ENCRYPTION_PROTOCOL.length()
+ + 1);
+ String proto;
+
+ if (DtlsControl.PROTO_NAME.equals(protoName))
+ {
+ proto = DtlsControl.UDP_TLS_RTP_SAVP;
+ }
+ else
+ {
+ /*
+ * According to Ingo Bauersachs, SDES "[b]asically requires
+ * SAVP per RFC."
+ */
+ /*
+ * According to RFC 6189 "ZRTP: Media Path Key Agreement for
+ * Unicast Secure RTP", "ZRTP utilizes normal RTP/AVP
+ * (Audio-Visual Profile) profiles", "[t]he Secure RTP/AVP
+ * (SAVP) profile MAY be used in subsequent offer/answer
+ * exchanges after a successful ZRTP exchange has resulted
+ * in an SRTP session, or if it is known that the other
+ * endpoint supports this profile" and "[o]ther profiles MAY
+ * also be used."
+ */
+ proto = SrtpControl.RTP_SAVP;
+ }
+
+ int protoIndex = result.indexOf(proto);
+
+ if (protoIndex > 0)
+ result.remove(protoIndex);
+ result.add(0, proto);
+ }
+
+ if (savpOption == ProtocolProviderFactory.SAVP_OPTIONAL)
+ result.add(SdpConstants.RTP_AVP);
+ }
+
return result;
}
@@ -1051,45 +1383,34 @@ public class CallPeerMediaHandlerSipImpl
= SdpUtils.containsAttribute(mediaDescription, "imageattr");
}
+
+ // DTLS-SRTP
+ updateSrtpControlsForDtls(mediaType, null, mediaDescription);
+
+ // SDES
// select the crypto key the peer has chosen from our proposal
- Map<MediaTypeSrtpControl, SrtpControl> srtpControls
- = getSrtpControls();
- MediaTypeSrtpControl key
- = new MediaTypeSrtpControl(mediaType, SrtpControlType.SDES);
- SrtpControl scontrol = srtpControls.get(key);
+ SrtpControls srtpControls = getSrtpControls();
+ SDesControl sdesControl
+ = (SDesControl)
+ srtpControls.get(mediaType, SrtpControlType.SDES);
- if(scontrol != null)
+ if(sdesControl != null)
{
if(selectSdesCryptoSuite(
true,
- (SDesControl) scontrol,
+ sdesControl,
mediaDescription) == null)
{
- scontrol.cleanup();
- srtpControls.remove(key);
+ sdesControl.cleanup();
+ srtpControls.remove(mediaType, SrtpControlType.SDES);
logger.warn("Received unsupported sdes crypto attribute.");
}
else
{
//found an SDES answer, remove all other controls
- Iterator<Map.Entry<MediaTypeSrtpControl, SrtpControl>> iter
- = srtpControls.entrySet().iterator();
-
- while (iter.hasNext())
- {
- Map.Entry<MediaTypeSrtpControl, SrtpControl> entry
- = iter.next();
- MediaTypeSrtpControl mtsc = entry.getKey();
-
- if ((mtsc.mediaType == mediaType)
- && (mtsc.srtpControlType
- != SrtpControlType.SDES))
- {
- entry.getValue().cleanup();
- iter.remove();
- }
- }
-
+ removeAndCleanupOtherSrtpControls(
+ mediaType,
+ SrtpControlType.SDES);
addAdvertisedEncryptionMethod(SrtpControlType.SDES);
}
}
@@ -1386,28 +1707,37 @@ public class CallPeerMediaHandlerSipImpl
.getAccountID()
.getSortedEnabledEncryptionProtocolList();
- for(int i = 0; i < preferredEncryptionProtocols.size(); ++i)
+ for(String preferredEncryptionProtocol : preferredEncryptionProtocols)
{
- // ZRTP
- if(preferredEncryptionProtocols.get(i).equals(
- ProtocolProviderFactory.ENCRYPTION_PROTOCOL + ".ZRTP"))
+ String protoName
+ = preferredEncryptionProtocol.substring(
+ ProtocolProviderFactory.ENCRYPTION_PROTOCOL.length()
+ + 1);
+
+ // DTLS-SRTP
+ if (DtlsControl.PROTO_NAME.equals(protoName))
{
- if(updateMediaDescriptionForZrtp(mediaType, localMd))
+ if(updateMediaDescriptionForDtls(mediaType, localMd, remoteMd))
{
- // Stops once an encryption advertisement has been chosen.
+ // Stop once an encryption advertisement has been chosen.
return;
}
}
// SDES
- else if(preferredEncryptionProtocols.get(i).equals(
- ProtocolProviderFactory.ENCRYPTION_PROTOCOL + ".SDES"))
+ else if(SDesControl.PROTO_NAME.equals(protoName))
{
- if(updateMediaDescriptionForSDes(
- mediaType,
- localMd,
- remoteMd))
+ if(updateMediaDescriptionForSDes(mediaType, localMd, remoteMd))
+ {
+ // Stop once an encryption advertisement has been chosen.
+ return;
+ }
+ }
+ // ZRTP
+ else if(ZrtpControl.PROTO_NAME.equals(protoName))
+ {
+ if(updateMediaDescriptionForZrtp(mediaType, localMd, remoteMd))
{
- // Stops once an encryption advertisement has been chosen.
+ // Stop once an encryption advertisement has been chosen.
return;
}
}
diff --git a/src/net/java/sip/communicator/plugin/desktoputil/wizard/SecurityPanel.java b/src/net/java/sip/communicator/plugin/desktoputil/wizard/SecurityPanel.java
index 9b39493..b838da4 100644
--- a/src/net/java/sip/communicator/plugin/desktoputil/wizard/SecurityPanel.java
+++ b/src/net/java/sip/communicator/plugin/desktoputil/wizard/SecurityPanel.java
@@ -310,7 +310,7 @@ public class SecurityPanel
pnlAdvancedSettings.add(lblEncryptionProtocolPreferences, c);
int nbEncryptionProtocols
- = SecurityAccountRegistration.ENCRYPTION_PROTOCOLS.length;
+ = SecurityAccountRegistration.ENCRYPTION_PROTOCOLS.size();
String[] encryptions = new String[nbEncryptionProtocols];
boolean[] selectedEncryptions = new boolean[nbEncryptionProtocols];
diff --git a/src/net/java/sip/communicator/service/protocol/SecurityAccountRegistration.java b/src/net/java/sip/communicator/service/protocol/SecurityAccountRegistration.java
index a66f155..e4a62ac 100644
--- a/src/net/java/sip/communicator/service/protocol/SecurityAccountRegistration.java
+++ b/src/net/java/sip/communicator/service/protocol/SecurityAccountRegistration.java
@@ -13,11 +13,12 @@ import java.util.*;
/**
* The <tt>SecurityAccountRegistration</tt> is used to determine security
- * options for different registration protocol (Jabber, SIP). Useful fot the
+ * options for different registration protocol (Jabber, SIP). Useful to the
* SecurityPanel.
*
* @author Vincent Lucas
* @author Pawel Domas
+ * @author Lyubomir Marinov
*/
public abstract class SecurityAccountRegistration
implements Serializable
@@ -25,7 +26,12 @@ public abstract class SecurityAccountRegistration
/**
* The encryption protocols managed by this SecurityPanel.
*/
- public static final String[] ENCRYPTION_PROTOCOLS = {"ZRTP", "SDES"};
+ public static final List<String> ENCRYPTION_PROTOCOLS
+ = Collections.unmodifiableList(
+ Arrays.asList(
+ ZrtpControl.PROTO_NAME,
+ SDesControl.PROTO_NAME,
+ DtlsControl.PROTO_NAME));
/**
* Enables support to encrypt calls.
@@ -33,7 +39,7 @@ public abstract class SecurityAccountRegistration
private boolean defaultEncryption = true;
/**
- * Enqbles ZRTP encryption.
+ * Enables ZRTP encryption.
*/
private boolean sipZrtpAttribute = true;
@@ -65,13 +71,13 @@ public abstract class SecurityAccountRegistration
public SecurityAccountRegistration()
{
// Sets the default values.
- this.encryptionProtocols = new HashMap<String, Integer>(1);
- this.encryptionProtocols.put("ZRTP", 0);
- this.encryptionProtocolStatus = new HashMap<String, Boolean>(1);
- this.encryptionProtocolStatus.put("ZRTP", true);
+ encryptionProtocols = new HashMap<String, Integer>(1);
+ encryptionProtocols.put("ZRTP", 0);
+ encryptionProtocolStatus = new HashMap<String, Boolean>(1);
+ encryptionProtocolStatus.put("ZRTP", true);
sdesCipherSuites
- = UtilActivator.getResources()
- .getSettingsString(SDesControl.SDES_CIPHER_SUITES);
+ = UtilActivator.getResources().getSettingsString(
+ SDesControl.SDES_CIPHER_SUITES);
}
/**
@@ -223,19 +229,13 @@ public abstract class SecurityAccountRegistration
private void addEncryptionProtocolsToProperties(
Map<String, String> properties)
{
- Map<String, Integer> encryptionProtocols
- = this.getEncryptionProtocols();
- Iterator<String> encryptionProtocolIterator
- = encryptionProtocols.keySet().iterator();
- String encryptionProtocol;
- while(encryptionProtocolIterator.hasNext())
+ for (Map.Entry<String, Integer> e : getEncryptionProtocols().entrySet())
{
- encryptionProtocol = encryptionProtocolIterator.next();
properties.put(
ProtocolProviderFactory.ENCRYPTION_PROTOCOL
+ "."
- + encryptionProtocol,
- encryptionProtocols.get(encryptionProtocol).toString());
+ + e.getKey(),
+ e.getValue().toString());
}
}
@@ -248,20 +248,14 @@ public abstract class SecurityAccountRegistration
private void addEncryptionProtocolStatusToProperties(
Map<String, String> properties)
{
- Map<String, Boolean> encryptionProtocolStatus
- = this.getEncryptionProtocolStatus();
- Iterator<String> encryptionProtocolStatusIterator
- = encryptionProtocolStatus.keySet().iterator();
- String encryptionProtocol;
- while(encryptionProtocolStatusIterator.hasNext())
+ for (Map.Entry<String,Boolean> e
+ : getEncryptionProtocolStatus().entrySet())
{
- encryptionProtocol = encryptionProtocolStatusIterator.next();
properties.put(
ProtocolProviderFactory.ENCRYPTION_PROTOCOL_STATUS
+ "."
- + encryptionProtocol,
- encryptionProtocolStatus.get(encryptionProtocol)
- .toString());
+ + e.getKey(),
+ e.getValue().toString());
}
}
@@ -278,16 +272,13 @@ public abstract class SecurityAccountRegistration
// Sets the ordered list of encryption protocols.
addEncryptionProtocolsToProperties(propertiesMap);
-
// Sets the list of encryption protocol status.
addEncryptionProtocolStatusToProperties(propertiesMap);
propertiesMap.put(ProtocolProviderFactory.DEFAULT_SIPZRTP_ATTRIBUTE,
Boolean.toString(isSipZrtpAttribute()));
-
propertiesMap.put(ProtocolProviderFactory.SAVP_OPTION,
Integer.toString(getSavpOption()));
-
propertiesMap.put(ProtocolProviderFactory.SDES_CIPHER_SUITES,
getSDesCipherSuites());
}
@@ -306,31 +297,30 @@ public abstract class SecurityAccountRegistration
encryptionProtocols = new HashMap<String, Integer>();
encryptionProtocolStatus = new HashMap<String, Boolean>();
- Map<String, Integer> srcEncryptionProtocols
- = accountID.getIntegerPropertiesByPrefix(
- ProtocolProviderFactory.ENCRYPTION_PROTOCOL, true);
- Map<String, Boolean> srcEncryptionProtocolStatus
- = accountID.getBooleanPropertiesByPrefix(
+ Map<String,Integer> srcEncryptionProtocols
+ = accountID.getIntegerPropertiesByPrefix(
+ ProtocolProviderFactory.ENCRYPTION_PROTOCOL,
+ true);
+ Map<String,Boolean> srcEncryptionProtocolStatus
+ = accountID.getBooleanPropertiesByPrefix(
ProtocolProviderFactory.ENCRYPTION_PROTOCOL_STATUS,
- true,
- false);
+ true,
+ false);
// Load stored values.
int prefixeLength
- = ProtocolProviderFactory.ENCRYPTION_PROTOCOL.length() + 1;
- String name;
- boolean enabled;
- for(String protocolPropertyName : srcEncryptionProtocols.keySet())
+ = ProtocolProviderFactory.ENCRYPTION_PROTOCOL.length() + 1;
+
+ for (Map.Entry<String,Integer> e : srcEncryptionProtocols.entrySet())
{
- name = protocolPropertyName.substring(prefixeLength);
+ String name = e.getKey().substring(prefixeLength);
if (isExistingEncryptionProtocol(name))
{
- // Copies the priority
- encryptionProtocols.put(
- name,
- srcEncryptionProtocols.get(protocolPropertyName));
- // Extracts the status
- enabled = srcEncryptionProtocolStatus.get(
- ProtocolProviderFactory.ENCRYPTION_PROTOCOL_STATUS
+ // Copy the priority
+ encryptionProtocols.put(name, e.getValue());
+ // Extract the status
+ boolean enabled
+ = srcEncryptionProtocolStatus.get(
+ ProtocolProviderFactory.ENCRYPTION_PROTOCOL_STATUS
+ "."
+ name);
encryptionProtocolStatus.put(name, enabled);
@@ -341,12 +331,10 @@ public abstract class SecurityAccountRegistration
accountID.getAccountPropertyBoolean(
ProtocolProviderFactory.DEFAULT_SIPZRTP_ATTRIBUTE,
true));
-
setSavpOption(
accountID.getAccountPropertyInt(
ProtocolProviderFactory.SAVP_OPTION,
ProtocolProviderFactory.SAVP_OFF));
-
setSDesCipherSuites(
accountID.getAccountPropertyString(
ProtocolProviderFactory.SDES_CIPHER_SUITES));
@@ -369,42 +357,37 @@ public abstract class SecurityAccountRegistration
Map<String, Integer> encryptionProtocols,
Map<String, Boolean> encryptionProtocolStatus)
{
- int nbEncryptionProtocols = ENCRYPTION_PROTOCOLS.length;
+ int nbEncryptionProtocols = ENCRYPTION_PROTOCOLS.size();
String[] encryptions = new String[nbEncryptionProtocols];
boolean[] selectedEncryptions = new boolean[nbEncryptionProtocols];
// Load stored values.
- String name;
- int index;
- Iterator<String> encryptionProtocolNames
- = encryptionProtocols.keySet().iterator();
- while(encryptionProtocolNames.hasNext())
+ for (Map.Entry<String,Integer> e : encryptionProtocols.entrySet())
{
- name = encryptionProtocolNames.next();
- index = encryptionProtocols.get(name);
+ int index = e.getValue();
+
// If the property is set.
- if(index != -1)
+ if (index != -1)
{
+ String name = e.getKey();
+
if (isExistingEncryptionProtocol(name))
{
encryptions[index] = name;
selectedEncryptions[index]
- = encryptionProtocolStatus.get(name);
+ = encryptionProtocolStatus.get(name);
}
}
}
// Load default values.
- String encryptionProtocol;
- boolean set;
int j = 0;
- for(int i = 0; i < ENCRYPTION_PROTOCOLS.length; ++i)
+ for (String encryptionProtocol : ENCRYPTION_PROTOCOLS)
{
- encryptionProtocol = ENCRYPTION_PROTOCOLS[i];
// Specify a default value only if there is no specific value set.
if(!encryptionProtocols.containsKey(encryptionProtocol))
{
- set = false;
+ boolean set = false;
// Search for the first empty element.
while(j < encryptions.length && !set)
{
@@ -418,30 +401,22 @@ public abstract class SecurityAccountRegistration
}
++j;
}
-
}
}
- return new Object[]{ encryptions, selectedEncryptions};
+ return new Object[] { encryptions, selectedEncryptions};
}
/**
- * Checks if given <tt>protocol</tt> is on supported protocols list.
+ * Checks if a specific <tt>protocol</tt> is on the list of supported
+ * (encryption) protocols.
+ *
* @param protocol the protocol name
- * @return <tt>true</tt> if encryption protocol with given protocol name is
- * supported.
+ * @return <tt>true</tt> if <tt>protocol</tt> is supported; <tt>false</tt>,
+ * otherwise
*/
private static boolean isExistingEncryptionProtocol(String protocol)
{
- for (String key : ENCRYPTION_PROTOCOLS)
- {
- if (key.equals(protocol))
- {
- return true;
- }
- }
-
- return false;
+ return ENCRYPTION_PROTOCOLS.contains(protocol);
}
-
}
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 11fcf31..9780393 100644
--- a/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java
+++ b/src/net/java/sip/communicator/service/protocol/media/CallPeerMediaHandler.java
@@ -13,8 +13,8 @@ import java.util.*;
import java.util.List;
import net.java.sip.communicator.service.protocol.*;
-
import net.java.sip.communicator.util.*;
+
import org.jitsi.service.neomedia.*;
import org.jitsi.service.neomedia.codec.*;
import org.jitsi.service.neomedia.control.*;
@@ -980,7 +980,7 @@ public abstract class CallPeerMediaHandler<T extends MediaAwareCallPeer<?,?,?>>
* @return the <tt>SrtpControl</tt>s of the <tt>MediaStream</tt>s of this
* instance
*/
- protected Map<MediaTypeSrtpControl, SrtpControl> getSrtpControls()
+ protected SrtpControls getSrtpControls()
{
return mediaHandler.getSrtpControls(this);
}
@@ -1443,6 +1443,24 @@ public abstract class CallPeerMediaHandler<T extends MediaAwareCallPeer<?,?,?>>
return mediaHandler.processKeyFrameRequest(this);
}
+ protected void removeAndCleanupOtherSrtpControls(
+ MediaType mediaType,
+ SrtpControlType srtpControlType)
+ {
+ SrtpControls srtpControls = getSrtpControls();
+
+ for (SrtpControlType i : SrtpControlType.values())
+ {
+ if (!i.equals(srtpControlType))
+ {
+ SrtpControl e = srtpControls.remove(mediaType, i);
+
+ if (e != null)
+ e.cleanup();
+ }
+ }
+ }
+
/**
* Unregisters a specific <tt>VideoListener</tt> from this instance so that
* it stops receiving notifications from it about changes in the
diff --git a/src/net/java/sip/communicator/service/protocol/media/MediaHandler.java b/src/net/java/sip/communicator/service/protocol/media/MediaHandler.java
index 62ecfa6..4b5db9e 100644
--- a/src/net/java/sip/communicator/service/protocol/media/MediaHandler.java
+++ b/src/net/java/sip/communicator/service/protocol/media/MediaHandler.java
@@ -138,8 +138,8 @@ public class MediaHandler
/**
* The <tt>SrtpControl</tt>s of the <tt>MediaStream</tt>s of this instance.
*/
- private final SortedMap<MediaTypeSrtpControl, SrtpControl> srtpControls
- = new TreeMap<MediaTypeSrtpControl, SrtpControl>();
+ private final SrtpControls srtpControls
+ = new SrtpControls();
private final SrtpListener srtpListener
= new SrtpListener()
@@ -597,19 +597,7 @@ public class MediaHandler
}
// Clean up the SRTP controls used for the associated Call.
- Iterator<Map.Entry<MediaTypeSrtpControl, SrtpControl>> iter
- = srtpControls.entrySet().iterator();
-
- while (iter.hasNext())
- {
- Map.Entry<MediaTypeSrtpControl, SrtpControl> entry = iter.next();
-
- if (entry.getKey().mediaType == mediaType)
- {
- entry.getValue().cleanup();
- iter.remove();
- }
- }
+ callPeerMediaHandler.removeAndCleanupOtherSrtpControls(mediaType, null);
}
/**
@@ -771,8 +759,8 @@ public class MediaHandler
for(SrtpControlType srtpControlType : SrtpControlType.values())
{
SrtpControl srtpControl
- = getSrtpControls(callPeerMediaHandler).get(
- new MediaTypeSrtpControl(mediaType, srtpControlType));
+ = getSrtpControls(callPeerMediaHandler)
+ .get(mediaType, srtpControlType);
if((srtpControl != null)
&& srtpControl.getSecureCommunicationStatus())
@@ -798,8 +786,7 @@ public class MediaHandler
* @return the <tt>SrtpControl</tt>s of the <tt>MediaStream</tt>s of this
* instance
*/
- Map<MediaTypeSrtpControl, SrtpControl> getSrtpControls(
- CallPeerMediaHandler<?> callPeerMediaHandler)
+ SrtpControls getSrtpControls(CallPeerMediaHandler<?> callPeerMediaHandler)
{
return srtpControls;
}
@@ -884,17 +871,7 @@ public class MediaHandler
MediaService mediaService
= ProtocolMediaActivator.getMediaService();
- /*
- * The default SrtpControlType is ZRTP. But if a SrtpControl exists
- * already, it determines the SrtpControlType.
- */
- SrtpControlType srtpControlType
- = (srtpControls.size() > 0)
- ? srtpControls.firstKey().srtpControlType
- : SrtpControlType.ZRTP;
- MediaTypeSrtpControl mediaTypeSrtpControl
- = new MediaTypeSrtpControl(mediaType, srtpControlType);
- SrtpControl srtpControl = srtpControls.get(mediaTypeSrtpControl);
+ SrtpControl srtpControl = srtpControls.findFirst(mediaType);
// If a SrtpControl does not exist yet, create a default one.
if (srtpControl == null)
@@ -905,7 +882,9 @@ public class MediaHandler
* Consequently, it needs to be linked to the srtpControls Map.
*/
stream = mediaService.createMediaStream(connector, device);
- srtpControls.put(mediaTypeSrtpControl, stream.getSrtpControl());
+ srtpControl = stream.getSrtpControl();
+ if (srtpControl != null)
+ srtpControls.set(mediaType, srtpControl);
}
else
{
diff --git a/src/net/java/sip/communicator/service/protocol/media/SrtpControls.java b/src/net/java/sip/communicator/service/protocol/media/SrtpControls.java
new file mode 100644
index 0000000..0e88007
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/media/SrtpControls.java
@@ -0,0 +1,97 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol.media;
+
+import org.jitsi.service.neomedia.*;
+
+/**
+ * Represents a sorted set of <tt>SrtpControl</tt> implementations.
+ *
+ * @author Lyubomir Marinov
+ */
+public class SrtpControls
+{
+ private static final SrtpControlType[] SORTED_SRTP_CONTROL_TYPES
+ = {
+ SrtpControlType.ZRTP,
+ SrtpControlType.DTLS_SRTP,
+ SrtpControlType.MIKEY,
+ SrtpControlType.SDES
+ };
+
+ /**
+ * The <tt>SrtpControl</tt> implementations which are the elements of this
+ * sorted set.
+ */
+ private final SrtpControl[][] elements
+ = new SrtpControl
+ [MediaType.values().length]
+ [SrtpControlType.values().length];
+
+ /**
+ * Initializes a new <tt>SrtpControls</tt> instance.
+ */
+ public SrtpControls()
+ {
+ }
+
+ public SrtpControl findFirst(MediaType mediaType)
+ {
+ SrtpControl element = null;
+
+ for (SrtpControlType srtpControlType : SORTED_SRTP_CONTROL_TYPES)
+ {
+ element = get(mediaType, srtpControlType);
+ if (element != null)
+ break;
+ }
+ return element;
+ }
+
+ public SrtpControl get(MediaType mediaType, SrtpControlType srtpControlType)
+ {
+ return elements[mediaType.ordinal()][srtpControlType.ordinal()];
+ }
+
+ public SrtpControl getOrCreate(
+ MediaType mediaType,
+ SrtpControlType srtpControlType)
+ {
+ SrtpControl[] elements = this.elements[mediaType.ordinal()];
+ int index = srtpControlType.ordinal();
+ SrtpControl element = elements[index];
+
+ if (element == null)
+ {
+ element
+ = ProtocolMediaActivator.getMediaService().createSrtpControl(
+ srtpControlType);
+ if (element != null)
+ elements[index] = element;
+ }
+ return element;
+ }
+
+ public SrtpControl remove(
+ MediaType mediaType,
+ SrtpControlType srtpControlType)
+ {
+ SrtpControl[] elements = this.elements[mediaType.ordinal()];
+ int index = srtpControlType.ordinal();
+ SrtpControl element = elements[index];
+
+ elements[index] = null;
+ return element;
+ }
+
+ public void set(MediaType mediaType, SrtpControl element)
+ {
+ SrtpControlType srtpControlType = element.getSrtpControlType();
+
+ elements[mediaType.ordinal()][srtpControlType.ordinal()] = element;
+ }
+}