コード例 #1
0
ファイル: Program.cs プロジェクト: Yitzchok/sipsorcery
        /// <summary>
        /// Hands the socket handle to the DTLS context and waits for the handshake to complete.
        /// </summary>
        /// <param name="webRtcSession">The WebRTC session to perform the DTLS handshake on.</param>
        private static bool DoDtlsHandshake(RTCPeerConnection pc, SIPSorceryMedia.DtlsHandshake dtls, bool isClient, byte[] sdpFingerprint)
        {
            logger.LogDebug("DoDtlsHandshake started.");

            if (!File.Exists(DTLS_CERTIFICATE_PATH))
            {
                throw new ApplicationException($"The DTLS certificate file could not be found at {DTLS_CERTIFICATE_PATH}.");
            }
            else if (!File.Exists(DTLS_KEY_PATH))
            {
                throw new ApplicationException($"The DTLS key file could not be found at {DTLS_KEY_PATH}.");
            }

            int  res = 0;
            bool fingerprintMatch = false;

            if (isClient)
            {
                logger.LogDebug($"DTLS client handshake starting to {pc.AudioDestinationEndPoint}.");

                // For the DTLS handshake to work connect must be called on the socket so openssl knows where to send.
                var rtpSocket = pc.GetRtpChannel(SDPMediaTypesEnum.audio).RtpSocket;
                rtpSocket.Connect(pc.AudioDestinationEndPoint);

                byte[] fingerprint = null;
                var    peerEP      = pc.AudioDestinationEndPoint;
                res = dtls.DoHandshakeAsClient((ulong)rtpSocket.Handle, (short)peerEP.AddressFamily.GetHashCode(), peerEP.Address.GetAddressBytes(), (ushort)peerEP.Port, ref fingerprint);
                if (fingerprint != null)
                {
                    logger.LogDebug($"DTLS server fingerprint {ByteBufferInfo.HexStr(fingerprint)}.");
                    fingerprintMatch = sdpFingerprint.SequenceEqual(fingerprint);
                }
            }
            else
            {
                byte[] fingerprint = null;
                res = dtls.DoHandshakeAsServer((ulong)pc.GetRtpChannel(SDPMediaTypesEnum.audio).RtpSocket.Handle, ref fingerprint);
                if (fingerprint != null)
                {
                    logger.LogDebug($"DTLS client fingerprint {ByteBufferInfo.HexStr(fingerprint)}.");
                    fingerprintMatch = sdpFingerprint.SequenceEqual(fingerprint);
                }
            }

            logger.LogDebug("DtlsContext initialisation result=" + res);

            if (dtls.IsHandshakeComplete())
            {
                logger.LogDebug("DTLS negotiation complete.");

                if (!fingerprintMatch)
                {
                    logger.LogWarning("DTLS fingerprint mismatch.");
                    return(false);
                }
                else
                {
                    var srtpSendContext    = new SIPSorceryMedia.Srtp(dtls, isClient);
                    var srtpReceiveContext = new SIPSorceryMedia.Srtp(dtls, !isClient);

                    pc.SetSecurityContext(
                        srtpSendContext.ProtectRTP,
                        srtpReceiveContext.UnprotectRTP,
                        srtpSendContext.ProtectRTCP,
                        srtpReceiveContext.UnprotectRTCP);

                    return(true);
                }
            }
            else
            {
                return(false);
            }
        }
コード例 #2
0
ファイル: Program.cs プロジェクト: Yitzchok/sipsorcery
        private static RTCPeerConnection Createpc(WebSocketContext context)
        {
            RTCConfiguration pcConfiguration = new RTCConfiguration
            {
                certificates = new List <RTCCertificate>
                {
                    new RTCCertificate
                    {
                        X_CertificatePath = DTLS_CERTIFICATE_PATH,
                        X_KeyPath         = DTLS_KEY_PATH,
                        X_Fingerprint     = DTLS_CERTIFICATE_FINGERPRINT
                    }
                },
                X_RemoteSignallingAddress = context.UserEndPoint.Address,
                iceServers = new List <RTCIceServer> {
                    new RTCIceServer
                    {
                        urls           = SIPSORCERY_STUN_SERVER,
                        username       = SIPSORCERY_STUN_SERVER_USERNAME,
                        credential     = SIPSORCERY_STUN_SERVER_PASSWORD,
                        credentialType = RTCIceCredentialType.password
                    }
                },
                iceTransportPolicy = RTCIceTransportPolicy.relay
            };

            var pc = new RTCPeerConnection(pcConfiguration);

#if DTLS_IS_ENABLED
            SIPSorceryMedia.DtlsHandshake dtls = new SIPSorceryMedia.DtlsHandshake(DTLS_CERTIFICATE_PATH, DTLS_KEY_PATH);
            dtls.Debug = true;
#endif

            // Add inactive audio and video tracks.
            MediaStreamTrack audioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPMediaFormat> {
                new SDPMediaFormat(SDPMediaFormatsEnum.PCMU)
            }, MediaStreamStatusEnum.RecvOnly);
            pc.addTrack(audioTrack);
            MediaStreamTrack videoTrack = new MediaStreamTrack(SDPMediaTypesEnum.video, false, new List <SDPMediaFormat> {
                new SDPMediaFormat(SDPMediaFormatsEnum.VP8)
            }, MediaStreamStatusEnum.Inactive);
            pc.addTrack(videoTrack);

            pc.onicecandidateerror     += (candidate, error) => logger.LogWarning($"Error adding remote ICE candidate. {error} {candidate}");
            pc.onconnectionstatechange += (state) => logger.LogDebug($"Peer connection state change to {state}.");
            pc.OnReceiveReport         += (type, rtcp) => logger.LogDebug($"RTCP {type} report received.");
            pc.OnRtcpBye += (reason) => logger.LogDebug($"RTCP BYE receive, reason: {(string.IsNullOrWhiteSpace(reason) ? "<none>" : reason)}.");

            pc.onicecandidate += (candidate) =>
            {
                if (pc.signalingState == RTCSignalingState.have_local_offer ||
                    pc.signalingState == RTCSignalingState.have_remote_offer)
                {
                    context.WebSocket.Send($"candidate:{candidate}");
                }
            };

            // Peer ICE connection state changes are for ICE events such as the STUN checks completing.
            pc.oniceconnectionstatechange += (state) =>
            {
                logger.LogDebug($"ICE connection state change to {state}.");

                if (state == RTCIceConnectionState.connected)
                {
                    logger.LogInformation($"ICE connected to remote end point {pc.AudioDestinationEndPoint}.");

                    if (pc.RemotePeerDtlsFingerprint == null)
                    {
                        logger.LogWarning("DTLS handshake cannot proceed, no fingerprint was available for the remote peer.");
                        pc.Close("No DTLS fingerprint.");
                    }
                    else
                    {
#if DTLS_IS_ENABLED
                        if (pc.IceRole == IceRolesEnum.active)
                        {
                            logger.LogDebug("Starting DLS handshake as client task.");
                            _ = Task.Run(() =>
                            {
                                bool handshakedResult = DoDtlsHandshake(pc, dtls, true, pc.RemotePeerDtlsFingerprint);
                                logger.LogDebug($"DTLS handshake result {handshakedResult}.");
                            });
                        }
                        else
                        {
                            logger.LogDebug("Starting DLS handshake as server task.");
                            _ = Task.Run(() =>
                            {
                                bool handshakedResult = DoDtlsHandshake(pc, dtls, false, pc.RemotePeerDtlsFingerprint);
                                logger.LogDebug($"DTLS handshake result {handshakedResult}.");
                            });
                        }
#endif
                    }
                }
            };

            return(pc);
        }