public void BindingRequestWithUsernameToBytesUnitTest()
        {
            Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name);

            STUNv2Message initMessage = new STUNv2Message(STUNv2MessageTypesEnum.BindingRequest);

            initMessage.AddUsernameAttribute("someusernamex");
            byte[] stunMessageBytes = initMessage.ToByteBuffer(null, false);

            Console.WriteLine(BitConverter.ToString(stunMessageBytes));

            Assert.IsTrue(stunMessageBytes.Length % 4 == 0);
        }
Exemplo n.º 2
0
        private void SendStunConnectivityChecks()
        {
            try
            {
                while (!IsClosed)
                {
                    try
                    {
                        // If one of the ICE candidates has the remote RTP socket set then the negotiation is complete and the STUN checks are to keep the connection alive.
                        if (LocalIceCandidates.Any(x => x.IsConnected == true))
                        {
                            var iceCandidate = LocalIceCandidates.First(x => x.IsConnected == true);

                            // Remote RTP endpoint gets set when the DTLS negotiation is finished.
                            if (iceCandidate.RemoteRtpEndPoint != null)
                            {
                                //logger.LogDebug("Sending STUN connectivity check to client " + iceCandidate.RemoteRtpEndPoint + ".");

                                string localUser = LocalIceUser;

                                STUNv2Message stunRequest = new STUNv2Message(STUNv2MessageTypesEnum.BindingRequest);
                                stunRequest.Header.TransactionId = Guid.NewGuid().ToByteArray().Take(12).ToArray();
                                stunRequest.AddUsernameAttribute(RemoteIceUser + ":" + localUser);
                                stunRequest.Attributes.Add(new STUNv2Attribute(STUNv2AttributeTypesEnum.Priority, new byte[] { 0x6e, 0x7f, 0x1e, 0xff }));
                                stunRequest.Attributes.Add(new STUNv2Attribute(STUNv2AttributeTypesEnum.UseCandidate, null));   // Must send this to get DTLS started.
                                byte[] stunReqBytes = stunRequest.ToByteBufferStringKey(RemoteIcePassword, true);

                                iceCandidate.LocalRtpSocket.SendTo(stunReqBytes, iceCandidate.RemoteRtpEndPoint);

                                iceCandidate.LastSTUNSendAt = DateTime.Now;
                            }

                            var secondsSinceLastResponse = DateTime.Now.Subtract(iceCandidate.LastCommunicationAt).TotalSeconds;

                            if (secondsSinceLastResponse > ICE_TIMEOUT_SECONDS)
                            {
                                logger.LogWarning("No STUN response was received on a connected ICE connection for " + secondsSinceLastResponse + "s, closing connection.");

                                iceCandidate.IsDisconnected = true;

                                if (LocalIceCandidates.Any(x => x.IsConnected == true) == false)
                                {
                                    // If there are no connected local candidates left close the peer.
                                    Close();
                                    break;
                                }
                            }
                        }
                        else
                        {
                            if (_remoteIceCandidates.Count() > 0)
                            {
                                foreach (var localIceCandidate in LocalIceCandidates.Where(x => x.IsStunLocalExchangeComplete == false && x.StunConnectionRequestAttempts < MAXIMUM_STUN_CONNECTION_ATTEMPTS))
                                {
                                    localIceCandidate.StunConnectionRequestAttempts++;

                                    // ToDo: Include srflx and relay addresses.

                                    // Only supporting UDP candidates at this stage.
                                    foreach (var remoteIceCandidate in RemoteIceCandidates.Where(x => x.Transport.ToLower() == "udp" && x.NetworkAddress.NotNullOrBlank() && x.HasConnectionError == false))
                                    {
                                        try
                                        {
                                            IPAddress remoteAddress = IPAddress.Parse(remoteIceCandidate.NetworkAddress);

                                            logger.LogDebug("Sending authenticated STUN binding request " + localIceCandidate.StunConnectionRequestAttempts + " from " + localIceCandidate.LocalRtpSocket.LocalEndPoint + " to WebRTC peer at " + remoteIceCandidate.NetworkAddress + ":" + remoteIceCandidate.Port + ".");

                                            string localUser = LocalIceUser;

                                            STUNv2Message stunRequest = new STUNv2Message(STUNv2MessageTypesEnum.BindingRequest);
                                            stunRequest.Header.TransactionId = Guid.NewGuid().ToByteArray().Take(12).ToArray();
                                            stunRequest.AddUsernameAttribute(RemoteIceUser + ":" + localUser);
                                            stunRequest.Attributes.Add(new STUNv2Attribute(STUNv2AttributeTypesEnum.Priority, new byte[] { 0x6e, 0x7f, 0x1e, 0xff }));
                                            stunRequest.Attributes.Add(new STUNv2Attribute(STUNv2AttributeTypesEnum.UseCandidate, null));   // Must send this to get DTLS started.
                                            byte[] stunReqBytes = stunRequest.ToByteBufferStringKey(RemoteIcePassword, true);

                                            localIceCandidate.LocalRtpSocket.SendTo(stunReqBytes, new IPEndPoint(IPAddress.Parse(remoteIceCandidate.NetworkAddress), remoteIceCandidate.Port));

                                            localIceCandidate.LastSTUNSendAt = DateTime.Now;
                                        }
                                        catch (System.Net.Sockets.SocketException sockExcp)
                                        {
                                            logger.LogWarning($"SocketException sending STUN request to {remoteIceCandidate.NetworkAddress}:{remoteIceCandidate.Port}, removing candidate. {sockExcp.Message}");
                                            remoteIceCandidate.HasConnectionError = true;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception excp)
                    {
                        logger.LogError("Exception SendStunConnectivityCheck ConnectivityCheck. " + excp);
                    }

                    if (!IsClosed)
                    {
                        Thread.Sleep(ESTABLISHED_STUN_BINDING_PERIOD_MILLISECONDS);
                    }
                }
            }
            catch (Exception excp)
            {
                logger.LogError("Exception SendStunConnectivityCheck. " + excp);
            }
        }