public static void Receive_Callback(IAsyncResult result) { StunSession session = (StunSession)result.AsyncState; Socket socket = session.TcpSocket; int read = socket.EndReceive(result); if (read > 0) { session.Position += read; // if we have at least 4 bytes we can check the length if (session.Position > 3) { // extract length and compare with buffer position, we may have a full message byte[] lengthBytes = new byte[2]; Array.Copy(session.SocketBuffer, 2, lengthBytes, 0, 2); if (BitConverter.IsLittleEndian) { Array.Reverse(lengthBytes); } ushort length = BitConverter.ToUInt16(lengthBytes, 0); if (length + 20 == session.Position) { StunMessage message = new StunMessage(session.SocketBuffer); // TODO: work out how to process message :) // we're now on a secondary thread in a static method, with no access to the "server" } else { session.TcpSocket.BeginReceive(session.SocketBuffer, session.Position, session.SocketBuffer.Length - session.Position, SocketFlags.None, new AsyncCallback(Receive_Callback), session); } } } else { socket.Close(); } }
public void Start() { TcpListener tcpServer = new TcpListener(IPAddress.Parse(options.ListenAddress), options.TcpPort); UdpClient udpClient = new UdpClient(new IPEndPoint(IPAddress.Parse(options.ListenAddress), options.UdpPort)); Task[] tasks = new Task[2]; // UDP receive, TCP accept List <StunSession> sessions = new List <StunSession>(); // TODO: this is taken from an console app I used for UDP testing, refactor // Task t = Task.Run(async () => // { while (true) { // TODO: need to add logic to manage tasks for when UDP and/or TCP requests come in // if the tasks are not already outstanding (i.e. awaiting from a previous loop) then // add, otherwise just check for completion // if task is already outstanding there is nothing to do but check if it's complete if (tasks[0] == null) { tasks[0] = udpClient.ReceiveAsync(); } if (tasks[1] == null) { tasks[2] = tcpServer.AcceptSocketAsync(); } // check for any new connections int task = Task.WaitAny(tasks, 5); if (task == 0) { // UDP client sent a request UdpReceiveResult result = ((Task <UdpReceiveResult>)tasks[0]).Result; // done with the task so null it ready for next loop iteration tasks[0] = null; // TODO: store this somewhere for future reference IPEndPoint remoteEndpoint = result.RemoteEndPoint; // TODO: add some validation of magic number, 32-bit alignment etc. byte[] buffer = result.Buffer; StunMessage message = new StunMessage(buffer); // process the message ProcessMessage(message); } else if (task == 1) { // accepting a connection - create a new session object and start tracking StunSession session = new StunSession(); sessions.Add(session); session.TcpSocket = ((Task <Socket>)tasks[1]).Result; // done with the task so null it ready for next loop iteration tasks[1] = null; // add task to receive TCP packet // tcpReceiveTasks.Add(session.TcpSocket.ReceiveAsync(session.SocketBuffer, SocketFlags.None)); session.TcpSocket.BeginReceive(session.SocketBuffer, session.Position, session.SocketBuffer.Length - session.Position, SocketFlags.None, new AsyncCallback(Receive_Callback), session); } } // }); // Console.WriteLine("Press any key to quit it"); // Console.ReadKey(); }