// Funktionen private static STUNMessage SendOverUDP(String IP, int Port, STUNMessage StunMessage) { IPEndPoint remoteEndpoint = new IPEndPoint(IPAddress.Parse(IP), Port); IPEndPoint localEndpoint = new IPEndPoint(IPAddress.Any, 0); UdpClient udpClient = null; // IPv4 oder IPv6 Adresse? if (remoteEndpoint.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) udpClient = new UdpClient(); else if (remoteEndpoint.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) udpClient = new UdpClient(System.Net.Sockets.AddressFamily.InterNetworkV6); // Nachricht in Byte Array wandeln Byte[] message_buffer = StunMessage.ToByteArray(); // initialen TimeOut Wert festlegen udpClient.Client.ReceiveTimeout = RTO; // Buffer für Empfang der Antwort Byte[] response_buffer = null; //Stopwatch stopwatch = new Stopwatch(); //stopwatch.Start(); // MessageType int type = (int)StunMessage.StunMessageType; // Indication? // 8.Bit(Maske 0x100) gelöscht? und 4.Bit(Maske 0x10) gesetzt? if (((type & 0x100) == 0) && ((type & 0x10) != 0)) { // Indication nur ein Sendeversuch //Console.WriteLine("Indication"); try { // Versuchen zu senden udpClient.Send(message_buffer, message_buffer.Length, remoteEndpoint); // auf Antwort warten => AUF INDICATION KOMMT KEINE ANTWORT !!! //response_buffer = udpClient.Receive(ref localEndpoint); } catch (Exception e) { Console.WriteLine(e.Message); throw e; } } else { // Request oder Response //Console.WriteLine("Request oder Response"); // RC Versuche for (int versuch = 1; versuch <= RC; versuch++) { try { // Versuchen zu senden //Console.WriteLine("Sende bei ({0} ms)", stopwatch.ElapsedMilliseconds); udpClient.Send(message_buffer, message_buffer.Length, remoteEndpoint); // auf Antwort warten response_buffer = udpClient.Receive(ref localEndpoint); // wenn Antwort erhalten springe aus Sende-Schleife break; } catch (SocketException e) { //stopwatch.Stop(); if (e.SocketErrorCode == SocketError.TimedOut) { // welcher Versuch ist gescheitert? if (versuch < RC - 1) udpClient.Client.ReceiveTimeout *= 2; // wenn vorletzter Versuch gescheitert ist => letzten Versuch mit ReceiveTimeOut = RM * RTO else if (versuch == RC - 1) udpClient.Client.ReceiveTimeout = RM * RTO; // letzter Versuch ebenfalls gescheitert else if (versuch == RC) { //stopwatch.Stop(); //Console.WriteLine("Sendevorgang nach {0} Versuchen und {1} ms abgebrochen!", RC, stopwatch.ElapsedMilliseconds); } } /* if (e.SocketErrorCode == SocketError.NetworkUnreachable) // trifft nicht ein { Console.WriteLine("unreachable"); } */ else { Console.WriteLine(e.Message); throw e; } } } } // UdpClient schließen udpClient.Close(); // Nachricht erhalten? if (response_buffer != null) { STUNMessage response = STUNMessage.Parse(response_buffer); return response; } else return null; }
private static STUNMessage SendOverTCP(String IP, int Port, STUNMessage StunMessage, IPEndPoint localEndpoint) { try { TcpClient tcpClient = new TcpClient(localEndpoint); tcpClient.Connect(IP, Port); // TimeOut Wert festlegen tcpClient.Client.ReceiveTimeout = TI; // Nachricht in Byte Array wandeln Byte[] message_buffer = StunMessage.ToByteArray(); // Netzwerkstream holen NetworkStream stream = tcpClient.GetStream(); // Message senden stream.Write(message_buffer, 0, message_buffer.Length); // zuerst Header (20 Byte) empfangen um Länge der Nachricht zu ermitteln Byte[] header = new Byte[20]; stream.Read(header, 0, 20); // Länge parsen (3. und 4. Byte im Header) Int16 msg_length = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(header, 2)); // Byte Array für Response Byte[] response = new Byte[20 + msg_length]; // Header in Response kopieren Array.Copy(header, 0, response, 0, header.Length); // Rest der Nachricht empfangen int bytesRead = stream.Read(response, 20, msg_length); // alles eingetroffen? if (bytesRead != msg_length) Console.WriteLine("Fehler beim empfangen!"); // parsen STUNMessage stunResponse = STUNMessage.Parse(response); // aufräumen //Thread.Sleep(2000); stream.Close(); tcpClient.Close(); return stunResponse; } catch (Exception e) { Console.WriteLine(e); throw e; } }
private static IPEndPoint GetPublicMapping(Socket stunSocket) { STUNMessage stunBindingRequest = new STUNMessage(StunMessageType.BindingRequest); stunBindingRequest.Create(); stunSocket.Send(stunBindingRequest.ToByteArray()); // STUN Header 20 Byte byte[] stunHeader = new byte[20]; stunSocket.Receive(stunHeader, 20, SocketFlags.None); ushort stunBodyLength = NetworkByteArray.ReadUInt16(stunHeader, 2); byte[] stunBody = new byte[stunBodyLength]; stunSocket.Receive(stunBody, stunBodyLength, SocketFlags.None); byte[] stunBindResp = new byte[20 + stunBodyLength]; Array.Copy(stunHeader, 0, stunBindResp, 0, 20); Array.Copy(stunBody, 0, stunBindResp, 20, stunBodyLength); STUNMessage stunBindingResponse = STUNMessage.Parse(stunBindResp); // contains XOR Mapped Address? for (int i = 0; i < stunBindingResponse.AttributeList.Count; i++) { if (stunBindingResponse.AttributeList[i].Type == STUNAttribute.StunAttributeType.XorMappedAddress) { XorMappedAddressAttribute xmaa = (XorMappedAddressAttribute)stunBindingResponse.AttributeList[i]; return xmaa.XorMappedAddress; } } // contains Mapped Address for (int i = 0; i < stunBindingResponse.AttributeList.Count; i++) { if (stunBindingResponse.AttributeList[i].Type == STUNAttribute.StunAttributeType.MappedAddress) { MappedAddressAttribute maa = (MappedAddressAttribute)stunBindingResponse.AttributeList[i]; return maa.MappedAddress; } } // no attribute return null; }