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

            STUNMessage initMessage = new STUNMessage(STUNMessageTypesEnum.BindingRequest);
            initMessage.AddUsernameAttribute("someusername");
            byte[] stunMessageBytes = initMessage.ToByteBuffer();

            Console.WriteLine(BitConverter.ToString(stunMessageBytes));
        }
        public static STUNMessage ParseSTUNMessage(byte[] buffer, int bufferLength)
        {
            if (buffer != null && buffer.Length > 0 && buffer.Length >= bufferLength)
            {
                STUNMessage stunMessage = new STUNMessage();
                stunMessage.Header = STUNHeader.ParseSTUNHeader(buffer);

                if (stunMessage.Header.MessageLength > 0)
                {
                    stunMessage.Attributes = STUNAttribute.ParseMessageAttributes(buffer, STUNHeader.STUN_HEADER_LENGTH, bufferLength);
                }

                return stunMessage;
            }

            return null;
        }
        private void ListenForXMPPServerMedia(UdpClient localSocket)
        {
            try
            {
                logger.Debug("Commencing listen for media from XMPP server on local socket " + m_localSIPEndPoint + ".");
                bool stunResponseSent = false;

                IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
                byte[] buffer = localSocket.Receive(ref remoteEndPoint);
                while (buffer != null && buffer.Length > 0 && !m_exit)
                {
                    //if (!stunResponseSent && buffer[0] >> 0xef == 0)
                    if (!stunResponseSent)
                    {
                        //logger.Debug(buffer.Length + " bytes read on media socket from " + remoteEndPoint.ToString() + ", byte[0]=" + buffer[0].ToString() + ".");

                        STUNMessage stunMessage = STUNMessage.ParseSTUNMessage(buffer, buffer.Length);

                        logger.Debug("STUN message received " + stunMessage.Header.MessageType + ".");

                        if (stunMessage.Header.MessageType == STUNMessageTypesEnum.BindingRequest)
                        {
                            logger.Debug("Sending STUN response to " + remoteEndPoint + ".");
                            stunResponseSent = true;
                            STUNMessage stunResponse = new STUNMessage();
                            stunResponse.Header.MessageType = STUNMessageTypesEnum.BindingResponse;
                            stunResponse.Header.TransactionId = stunMessage.Header.TransactionId;
                            stunResponse.AddUsernameAttribute(Encoding.UTF8.GetString(stunMessage.Attributes[0].Value));
                            byte[] stunRespBytes = stunResponse.ToByteBuffer();
                            m_xmppMediaSocket.Send(stunRespBytes, stunRespBytes.Length, remoteEndPoint);
                        }
                        else
                        {
                            //if (stunMessage.Attributes.Count > 0)
                            //{
                            //    foreach (STUNAttribute stunAttribute in stunMessage.Attributes)
                            //    {
                            //        Console.WriteLine(" " + stunAttribute.AttributeType + "=" + stunAttribute.Value + ".");
                            //    }
                            //}
                        }
                    }

                    if (buffer.Length > 100)
                    {
                        m_sipMediaSocket.Send(buffer, buffer.Length, m_sipPhoneRTPEndPoint);
                    }

                    buffer = localSocket.Receive(ref remoteEndPoint);
                }
            }
            catch (SocketException)
            { }
            catch (Exception excp)
            {
                logger.Error("Exception ListenForXMPPServerMedia. " + excp.Message);
            }
            finally
            {
                logger.Debug("Shutting down listen for SIP phone media on local socket " + m_localSIPEndPoint + ".");
            }
        }
        private void Answered(SDP xmppSDP)
        {
            //Console.WriteLine("Yay call answered.");
            //Console.WriteLine(sdp.ToString());
            m_xmppServerEndPoint = SDP.GetSDPRTPEndPoint(xmppSDP.ToString());
            logger.Debug("Sending STUN binding request to " + m_xmppServerEndPoint + ".");
            STUNMessage initMessage = new STUNMessage(STUNMessageTypesEnum.BindingRequest);
            initMessage.AddUsernameAttribute(xmppSDP.IceUfrag + m_localSTUNUFrag);
            byte[] stunMessageBytes = initMessage.ToByteBuffer();
            m_xmppMediaSocket.Send(stunMessageBytes, stunMessageBytes.Length, m_xmppServerEndPoint);

            m_uas.Answer("application/sdp", GetSDPForSIPResponse().ToString(), null, SIPDialogueTransferModesEnum.NotAllowed);
        }
        /// <summary>
        /// Event handler for an answer on an outgoing Google Voice call.
        /// </summary>
        /// <param name="xmppSDP">The SDP packet received from the Google Voice gateway.</param>
        private void XMPPAnswered(SDP xmppSDP)
        {
            StatusMessage("Google Voice call answered.");

            IPEndPoint remoteSDPEndPoint = SDP.GetSDPRTPEndPoint(xmppSDP.ToString());
            _rtpManager.SetRemoteRTPEndPoints(remoteSDPEndPoint, null);

            // Google Voice require that a STUN exchange occurs on the RTP socket before the RTP packet can flow.
            // This code block sends a STUN binding request to the Google Voice gateway.
            STUNMessage initMessage = new STUNMessage(STUNMessageTypesEnum.BindingRequest);
            initMessage.AddUsernameAttribute(xmppSDP.IceUfrag + m_localSTUNUFrag);
            byte[] stunMessageBytes = initMessage.ToByteBuffer();
            _rtpManager.SendRTPRaw(stunMessageBytes, stunMessageBytes.Length);
        }
 private void FireSTUNSecondaryResponseOutTraceEvent(IPEndPoint localEndPoint, IPEndPoint toEndPoint, STUNMessage stunMessage)
 {
     try
     {
         if (STUNSecondaryResponseOutTraceEvent != null)
         {
             STUNSecondaryResponseOutTraceEvent(localEndPoint, toEndPoint, stunMessage);
         }
     }
     catch (Exception excp)
     {
         logger.Error("Exception FireSTUNSecondaryResponseOutTraceEvent. " + excp.Message);
     }
 }
 private void FireSTUNPrimaryRequestInTraceEvent(IPEndPoint localEndPoint, IPEndPoint fromEndPoint, STUNMessage stunMessage)
 {
     try
     {
         if (STUNPrimaryRequestInTraceEvent != null)
         {
             STUNPrimaryRequestInTraceEvent(localEndPoint, fromEndPoint, stunMessage);
         }
     }
     catch (Exception excp)
     {
         logger.Error("Exception FireSTUNPrimaryRequestInTraceEvent. " + excp.Message);
     }
 }
        private STUNMessage GetResponse(IPEndPoint receivedEndPoint, STUNMessage stunRequest, bool primary)
        {
            if (stunRequest.Header.MessageType == STUNMessageTypesEnum.BindingRequest)
            {
                STUNMessage stunResponse = new STUNMessage();
                stunResponse.Header.MessageType = STUNMessageTypesEnum.BindingResponse;
                stunResponse.Header.TransactionId = stunRequest.Header.TransactionId;

                // Add MappedAddress attribute to indicate the socket the request was received from.
                STUNAddressAttribute mappedAddressAtt = new STUNAddressAttribute(STUNAttributeTypesEnum.MappedAddress, receivedEndPoint.Port, receivedEndPoint.Address);
                stunResponse.Attributes.Add(mappedAddressAtt);

                // Add SourceAddress attribute to indicate the socket used to send the response.
                if (primary)
                {
                    STUNAddressAttribute sourceAddressAtt = new STUNAddressAttribute(STUNAttributeTypesEnum.SourceAddress, m_primaryEndPoint.Port, m_primaryEndPoint.Address);
                    stunResponse.Attributes.Add(sourceAddressAtt);
                }
                else
                {
                    STUNAddressAttribute sourceAddressAtt = new STUNAddressAttribute(STUNAttributeTypesEnum.SourceAddress, m_secondaryEndPoint.Port, m_secondaryEndPoint.Address);
                    stunResponse.Attributes.Add(sourceAddressAtt);
                }

                // Add ChangedAddress attribute to inidcate the servers alternative socket.
                if (primary)
                {
                    STUNAddressAttribute changedAddressAtt = new STUNAddressAttribute(STUNAttributeTypesEnum.ChangedAddress, m_secondaryEndPoint.Port, m_secondaryEndPoint.Address);
                    stunResponse.Attributes.Add(changedAddressAtt);
                }
                else
                {
                    STUNAddressAttribute changedAddressAtt = new STUNAddressAttribute(STUNAttributeTypesEnum.ChangedAddress, m_primaryEndPoint.Port, m_primaryEndPoint.Address);
                    stunResponse.Attributes.Add(changedAddressAtt);
                }

                //Console.WriteLine(stunResponse.ToString());

                //byte[] stunResponseBuffer = stunResponse.ToByteBuffer();

                return stunResponse;
            }

            return null;
        }
        private void RTPPacketReceived(UDPListener listener, IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, byte[] buffer)
        {
            if ((buffer[0] == 0x0 || buffer[0] == 0x1) && buffer.Length >= 20)
            {
                // Probably a STUN request.
                STUNMessage stunMessage = STUNMessage.ParseSTUNMessage(buffer, buffer.Length);

                if (stunMessage != null)
                {
                    logger.Debug("STUN message received on RTP channel " + stunMessage.Header.MessageType + ".");

                    if (stunMessage.Header.MessageType == STUNMessageTypesEnum.BindingRequest)
                    {
                        logger.Debug("RTP channel sending STUN response to " + remoteEndPoint + ".");
                        STUNMessage stunResponse = new STUNMessage();
                        stunResponse.Header.MessageType = STUNMessageTypesEnum.BindingResponse;
                        stunResponse.Header.TransactionId = stunMessage.Header.TransactionId;
                        stunResponse.AddUsernameAttribute(Encoding.UTF8.GetString(stunMessage.Attributes[0].Value));
                        byte[] stunRespBytes = stunResponse.ToByteBuffer();
                        SendRaw(remoteEndPoint, stunRespBytes, stunRespBytes.Length);
                    }
                }
            }
            else
            {
                logger.Debug("RTP packet received from " + remoteEndPoint + ".");

                if (SampleReceived != null)
                {
                    var rtpHeader = new RTPHeader(buffer);

                    SampleReceived(buffer, rtpHeader.Length);
                }
            }
        }
        public static IPAddress GetPublicIPAddress(string stunServer)
        {
            try
            {
                logger.Debug("STUNClient attempting to determine public IP from " + stunServer + ".");

                using (UdpClient udpClient = new UdpClient(stunServer, m_defaultSTUNPort))
                {
                        STUNMessage initMessage = new STUNMessage(STUNMessageTypesEnum.BindingRequest);
                        byte[] stunMessageBytes = initMessage.ToByteBuffer();
                        udpClient.Send(stunMessageBytes, stunMessageBytes.Length);

                        IPAddress publicIPAddress = null;
                        ManualResetEvent gotResponseMRE = new ManualResetEvent(false);

                        udpClient.BeginReceive((ar) =>
                        {
                            try
                            {
                                IPEndPoint stunResponseEndPoint = null;
                                byte[] stunResponseBuffer = udpClient.EndReceive(ar, ref stunResponseEndPoint);

                                if (stunResponseBuffer != null && stunResponseBuffer.Length > 0)
                                {
                                    logger.Debug("STUNClient Response to initial STUN message received from " + stunResponseEndPoint + ".");
                                    STUNMessage stunResponse = STUNMessage.ParseSTUNMessage(stunResponseBuffer, stunResponseBuffer.Length);

                                    if (stunResponse.Attributes.Count > 0)
                                    {
                                        foreach (STUNAttribute stunAttribute in stunResponse.Attributes)
                                        {
                                            if (stunAttribute.AttributeType == STUNAttributeTypesEnum.MappedAddress)
                                            {
                                                publicIPAddress = ((STUNAddressAttribute)stunAttribute).Address;
                                                logger.Debug("STUNClient Public IP=" + publicIPAddress.ToString() + ".");
                                            }
                                        }
                                    }
                                }

                                gotResponseMRE.Set();
                            }
                            catch (Exception recvExcp)
                            {
                                logger.Warn("Exception STUNClient Receive. " + recvExcp.Message);
                            }
                        }, null);

                        if (gotResponseMRE.WaitOne(STUN_SERVER_RESPONSE_TIMEOUT * 1000))
                        {
                            return publicIPAddress;
                        }
                        else
                        {
                            logger.Warn("STUNClient server response timedout after " + STUN_SERVER_RESPONSE_TIMEOUT + "s.");
                            return null;
                        }
                    }
            }
            catch (Exception excp)
            {
                logger.Error("Exception STUNClient GetPublicIPAddress. " + excp.Message);
                return null;
                //throw;
            }
        }
Exemple #11
0
        /// <summary>
        /// Used to get the public IP address and port as seen by the STUN server.
        /// </summary>
        /// <param name="stunServer">A server to send STUN requests to.</param>
        /// <param name="port">The port to use for the request. Defaults to 3478.</param>
        /// <returns>The public IP address and port of the client.</returns>
        public static IPEndPoint GetPublicIPEndPoint(string stunServer, int port = DEFAULT_STUN_PORT)
        {
            try
            {
                logger.LogDebug("STUNClient attempting to determine public IP from " + stunServer + ".");

                using (UdpClient udpClient = new UdpClient(stunServer, port))
                {
                    STUNMessage initMessage      = new STUNMessage(STUNMessageTypesEnum.BindingRequest);
                    byte[]      stunMessageBytes = initMessage.ToByteBuffer(null, false);
                    udpClient.Send(stunMessageBytes, stunMessageBytes.Length);

                    IPEndPoint       publicEndPoint = null;
                    ManualResetEvent gotResponseMRE = new ManualResetEvent(initialState: false);

                    udpClient.BeginReceive((ar) =>
                    {
                        try
                        {
                            IPEndPoint stunResponseEndPoint = null;
                            byte[] stunResponseBuffer       = udpClient.EndReceive(ar, ref stunResponseEndPoint);

                            if (stunResponseBuffer != null && stunResponseBuffer.Length > 0)
                            {
                                logger.LogDebug("STUNClient Response to initial STUN message received from " +
                                                stunResponseEndPoint + ".");
                                STUNMessage stunResponse =
                                    STUNMessage.ParseSTUNMessage(stunResponseBuffer, stunResponseBuffer.Length);

                                if (stunResponse.Attributes.Count > 0)
                                {
                                    foreach (STUNAttribute stunAttribute in stunResponse.Attributes)
                                    {
                                        if (stunAttribute.AttributeType == STUNAttributeTypesEnum.MappedAddress)
                                        {
                                            STUNAddressAttribute stunAddress = (STUNAddressAttribute)stunAttribute;
                                            publicEndPoint = new IPEndPoint(stunAddress.Address, stunAddress.Port);
                                            logger.LogDebug(
                                                $"STUNClient Public IP={publicEndPoint.Address} Port={publicEndPoint.Port}.");
                                        }
                                    }
                                }
                            }

                            gotResponseMRE.Set();
                        }
                        catch (Exception recvExcp)
                        {
                            logger.LogWarning("Exception STUNClient Receive. " + recvExcp.Message);
                        }
                    }, state: null);

                    if (gotResponseMRE.WaitOne(STUN_SERVER_RESPONSE_TIMEOUT * 1000))
                    {
                        return(publicEndPoint);
                    }
                    else
                    {
                        logger.LogWarning("STUNClient server response timed out after " + STUN_SERVER_RESPONSE_TIMEOUT +
                                          "s.");
                        return(null);
                    }
                }
            }
            catch (Exception excp)
            {
                logger.LogError("Exception STUNClient GetPublicIPAddress. " + excp.Message);
                return(null);
            }
        }
Exemple #12
0
        public void STUNPrimaryReceived(IPEndPoint localEndPoint, IPEndPoint receivedEndPoint, byte[] buffer,
                                        int bufferLength)
        {
            try
            {
                //Console.WriteLine("\n=> received from " + IPSocketAddress.GetSocketString(receivedEndPoint) + " on " + IPSocketAddress.GetSocketString(receivedOnEndPoint));
                //Console.WriteLine(Utility.PrintBuffer(buffer));

                STUNMessage stunRequest = STUNMessage.ParseSTUNMessage(buffer, bufferLength);
                //Console.WriteLine(stunRequest.ToString());

                FireSTUNPrimaryRequestInTraceEvent(localEndPoint, receivedEndPoint, stunRequest);

                STUNMessage stunResponse       = GetResponse(receivedEndPoint, stunRequest, true);
                byte[]      stunResponseBuffer = stunResponse.ToByteBuffer(null, false);

                bool changeAddress = false;
                bool changePort    = false;
                foreach (STUNAttribute attr in stunRequest.Attributes)
                {
                    if (attr.AttributeType == STUNAttributeTypesEnum.ChangeRequest)
                    {
                        STUNChangeRequestAttribute changeReqAttr = (STUNChangeRequestAttribute)attr;
                        changeAddress = changeReqAttr.ChangeAddress;
                        changePort    = changeReqAttr.ChangePort;
                        break;
                    }
                }

                if (!changeAddress)
                {
                    if (!changePort)
                    {
                        //Console.WriteLine("<= sending to " + IPSocketAddress.GetSocketString(receivedEndPoint) + " from " + IPSocketAddress.GetSocketString(m_primaryEndPoint));
                        m_primarySend(receivedEndPoint, stunResponseBuffer);

                        FireSTUNPrimaryResponseOutTraceEvent(m_primaryEndPoint, receivedEndPoint, stunResponse);
                    }
                    else
                    {
                        //Console.WriteLine("<= sending to " + IPSocketAddress.GetSocketString(receivedEndPoint) + " from " + IPSocketAddress.GetSocketString(m_primaryDiffPortEndPoint));
                        m_primaryDiffPortSocket.Send(stunResponseBuffer, stunResponseBuffer.Length, receivedEndPoint);

                        FireSTUNPrimaryResponseOutTraceEvent(m_primaryDiffPortEndPoint, receivedEndPoint, stunResponse);
                    }
                }
                else
                {
                    if (!changePort)
                    {
                        //Console.WriteLine("<= sending to " + IPSocketAddress.GetSocketString(receivedEndPoint) + " from " + IPSocketAddress.GetSocketString(m_secondaryEndPoint));
                        m_secondarySend(receivedEndPoint, stunResponseBuffer);

                        FireSTUNSecondaryResponseOutTraceEvent(m_secondaryEndPoint, receivedEndPoint, stunResponse);
                    }
                    else
                    {
                        //Console.WriteLine("<= sending to " + IPSocketAddress.GetSocketString(receivedEndPoint) + " from " + IPSocketAddress.GetSocketString(m_secondaryDiffPortEndPoint));
                        m_secondaryDiffPortSocket.Send(stunResponseBuffer, stunResponseBuffer.Length, receivedEndPoint);

                        FireSTUNSecondaryResponseOutTraceEvent(m_secondaryDiffPortEndPoint, receivedEndPoint,
                                                               stunResponse);
                    }
                }
            }
            catch (Exception excp)
            {
                logger.LogDebug("Exception STUNPrimaryReceived. " + excp.Message);
            }
        }
Exemple #13
0
 private void FireSTUNSecondaryResponseOutTraceEvent(IPEndPoint localEndPoint, IPEndPoint toEndPoint, STUNMessage stunMessage)
 {
     try
     {
         if (STUNSecondaryResponseOutTraceEvent != null)
         {
             STUNSecondaryResponseOutTraceEvent(localEndPoint, toEndPoint, stunMessage);
         }
     }
     catch (Exception excp)
     {
         logger.LogError("Exception FireSTUNSecondaryResponseOutTraceEvent. " + excp.Message);
     }
 }
Exemple #14
0
 private void FireSTUNPrimaryRequestInTraceEvent(IPEndPoint localEndPoint, IPEndPoint fromEndPoint, STUNMessage stunMessage)
 {
     try
     {
         if (STUNPrimaryRequestInTraceEvent != null)
         {
             STUNPrimaryRequestInTraceEvent(localEndPoint, fromEndPoint, stunMessage);
         }
     }
     catch (Exception excp)
     {
         logger.LogError("Exception FireSTUNPrimaryRequestInTraceEvent. " + excp.Message);
     }
 }
Exemple #15
0
        /// <summary>
        /// Handler for a STUN response received in response to an ICE server connectivity check.
        /// Note that no STUN requests are expected to be received from an ICE server during the initial
        /// connection to an ICE server. Requests will only arrive if a TURN relay is used and data
        /// indications arrive but this will be at a later stage.
        /// </summary>
        /// <param name="stunResponse">The STUN response received.</param>
        /// <param name="remoteEndPoint">The remote end point the STUN response was received from.</param>
        /// <returns>True if the STUN response resulted in new ICE candidates being available (which
        /// will be either a "server reflexive" or "relay" candidate.</returns>
        internal bool GotStunResponse(STUNMessage stunResponse, IPEndPoint remoteEndPoint)
        {
            bool candidatesAvailable = false;

            string txID = Encoding.ASCII.GetString(stunResponse.Header.TransactionId);

            // Ignore responses to old requests on the assumption they are retransmits.
            if (TransactionID == txID)
            {
                // The STUN response is for a check sent to an ICE server.
                LastResponseReceivedAt  = DateTime.Now;
                OutstandingRequestsSent = 0;

                if (stunResponse.Header.MessageType == STUNMessageTypesEnum.AllocateSuccessResponse)
                {
                    ErrorResponseCount = 0;

                    // If the relay end point is set then this connection check has already been completed.
                    if (RelayEndPoint == null)
                    {
                        logger.LogDebug($"TURN allocate success response received for ICE server check to {_uri}.");

                        var mappedAddrAttr = stunResponse.Attributes.Where(x => x.AttributeType == STUNAttributeTypesEnum.XORMappedAddress).FirstOrDefault();

                        if (mappedAddrAttr != null)
                        {
                            ServerReflexiveEndPoint = (mappedAddrAttr as STUNXORAddressAttribute).GetIPEndPoint();
                        }

                        var mappedRelayAddrAttr = stunResponse.Attributes.Where(x => x.AttributeType == STUNAttributeTypesEnum.XORRelayedAddress).FirstOrDefault();

                        if (mappedRelayAddrAttr != null)
                        {
                            RelayEndPoint = (mappedRelayAddrAttr as STUNXORAddressAttribute).GetIPEndPoint();
                        }

                        candidatesAvailable = true;
                    }
                }
                else if (stunResponse.Header.MessageType == STUNMessageTypesEnum.AllocateErrorResponse)
                {
                    ErrorResponseCount++;

                    if (stunResponse.Attributes.Any(x => x.AttributeType == STUNAttributeTypesEnum.ErrorCode))
                    {
                        var errCodeAttribute = stunResponse.Attributes.First(x => x.AttributeType == STUNAttributeTypesEnum.ErrorCode) as STUNErrorCodeAttribute;

                        if (errCodeAttribute.ErrorCode == STUN_UNAUTHORISED_ERROR_CODE)
                        {
                            // Set the authentication properties authenticate.
                            var nonceAttribute = stunResponse.Attributes.FirstOrDefault(x => x.AttributeType == STUNAttributeTypesEnum.Nonce);
                            Nonce = nonceAttribute?.Value;

                            var realmAttribute = stunResponse.Attributes.FirstOrDefault(x => x.AttributeType == STUNAttributeTypesEnum.Realm);
                            Realm = realmAttribute?.Value;

                            // Set a new transaction ID.
                            GenerateNewTransactionID();
                        }
                        else
                        {
                            logger.LogWarning($"ICE session received an error response for an Allocate request to {_uri}, error {errCodeAttribute.ErrorCode} {errCodeAttribute.ReasonPhrase}.");
                        }
                    }
                }
                else if (stunResponse.Header.MessageType == STUNMessageTypesEnum.BindingSuccessResponse)
                {
                    ErrorResponseCount = 0;

                    // If the server reflexive end point is set then this connection check has already been completed.
                    if (ServerReflexiveEndPoint == null)
                    {
                        logger.LogDebug($"STUN binding success response received for ICE server check to {_uri}.");

                        var mappedAddrAttr = stunResponse.Attributes.Where(x => x.AttributeType == STUNAttributeTypesEnum.XORMappedAddress).FirstOrDefault();

                        if (mappedAddrAttr != null)
                        {
                            ServerReflexiveEndPoint = (mappedAddrAttr as STUNXORAddressAttribute).GetIPEndPoint();
                            candidatesAvailable     = true;
                        }
                    }
                }
                else if (stunResponse.Header.MessageType == STUNMessageTypesEnum.BindingErrorResponse)
                {
                    ErrorResponseCount++;

                    logger.LogWarning($"STUN binding error response received for ICE server check to {_uri}.");
                    // The STUN response is for a check sent to an ICE server.
                    Error = SocketError.ConnectionRefused;
                }
                else
                {
                    logger.LogWarning($"An unrecognised STUN {stunResponse.Header.MessageType} response for an ICE server check was received from {remoteEndPoint}.");
                    ErrorResponseCount++;
                }
            }

            return(candidatesAvailable);
        }