A game about forced loneliness, made by TACStudios
1/*--------------------------------------------------------------------------------------------- 2 * Copyright (c) Microsoft Corporation. All rights reserved. 3 * Licensed under the MIT License. See License.txt in the project root for license information. 4 *--------------------------------------------------------------------------------------------*/ 5using System; 6using System.Net; 7using System.Net.Sockets; 8using System.Threading; 9 10namespace Microsoft.Unity.VisualStudio.Editor.Messaging 11{ 12 internal class TcpClient 13 { 14 private const int ConnectOrReadTimeoutMilliseconds = 5000; 15 16 private class State 17 { 18 public System.Net.Sockets.TcpClient TcpClient; 19 public NetworkStream NetworkStream; 20 public byte[] Buffer; 21 public Action<byte[]> OnBufferAvailable; 22 } 23 24 public static void Queue(IPAddress address, int port, int bufferSize, Action<byte[]> onBufferAvailable) 25 { 26 var client = new System.Net.Sockets.TcpClient(); 27 var state = new State {OnBufferAvailable = onBufferAvailable, TcpClient = client, Buffer = new byte[bufferSize]}; 28 29 try 30 { 31 ThreadPool.QueueUserWorkItem(_ => 32 { 33 var handle = client.BeginConnect(address, port, OnClientConnected, state); 34 if (!handle.AsyncWaitHandle.WaitOne(ConnectOrReadTimeoutMilliseconds)) 35 Cleanup(state); 36 }); 37 } 38 catch (Exception) 39 { 40 Cleanup(state); 41 } 42 } 43 44 private static void OnClientConnected(IAsyncResult result) 45 { 46 var state = (State)result.AsyncState; 47 48 try 49 { 50 state.TcpClient.EndConnect(result); 51 state.NetworkStream = state.TcpClient.GetStream(); 52 var handle = state.NetworkStream.BeginRead(state.Buffer, 0, state.Buffer.Length, OnEndRead, state); 53 if (!handle.AsyncWaitHandle.WaitOne(ConnectOrReadTimeoutMilliseconds)) 54 Cleanup(state); 55 } 56 catch (Exception) 57 { 58 Cleanup(state); 59 } 60 } 61 62 private static void OnEndRead(IAsyncResult result) 63 { 64 var state = (State)result.AsyncState; 65 66 try 67 { 68 var count = state.NetworkStream.EndRead(result); 69 if (count == state.Buffer.Length) 70 state.OnBufferAvailable?.Invoke(state.Buffer); 71 } 72 catch (Exception) 73 { 74 // Ignore and cleanup 75 } 76 finally 77 { 78 Cleanup(state); 79 } 80 } 81 82 private static void Cleanup(State state) 83 { 84 state.NetworkStream?.Dispose(); 85 state.TcpClient?.Close(); 86 87 state.NetworkStream = null; 88 state.TcpClient = null; 89 state.Buffer = null; 90 state.OnBufferAvailable = null; 91 } 92 } 93}