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; } }
/// <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); } }
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); } }
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); } }
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); } }
/// <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); }