using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; namespace MelonVPNCore { public class DaemonClient : IDisposable { public ClientResponseState SendDataMessage(DataMessage msg) => SendCustomMessage(msg); public ClientResponseState SendCustomMessage(DataMessage msg) => SendCustomMessage(Messages.GetMessage(msg))); private Socket _sock; public static int timeout = 5000; private Thread _recvThread; private bool _stayConnected = false; public event EventHandler messageReceived; public DaemonClient() { try { IPHostEntry host = Dns.GetHostEntry("localhost"); IPAddress ipAddress = host.AddressList[0]; IPEndPoint remoteEndPoint = new IPEndPoint(ipAddress, DaemonServer.port); _sock = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp); _stayConnected = true; _sock.Connect(remoteEndPoint); _sock.ReceiveTimeout = timeout; _sock.SendTimeout = timeout; _recvThread = new Thread(recvThreader) { IsBackground = true }; _recvThread.Start(); } catch (Exception e) { _stayConnected = false; Console.WriteLine(e); _sock = null; if (! (_recvThread is null)) { if (_recvThread.IsAlive) _recvThread.Abort(); _recvThread = null; } throw new InvalidOperationException("Daemon Client Init Failed."); } } public DaemonClient(Socket sockIn) { if (sockIn is null) throw new InvalidOperationException("Passed Socket is Null."); } public ClientResponseState SendCustomMessage(string msg) { try { if (msg == Messages.EOF || msg == "") return ClientResponseState.Blank; byte[] bytes = Encoding.ASCII.GetBytes(msg); _sock.Send(bytes); return ClientResponseState.Sent; } catch (Exception e) { Console.WriteLine(e); return ClientResponseState.Error; } } public void recvThreader() { while (_stayConnected) { try { string data = null; byte[] bytes = null; while (_stayConnected) { bytes = new byte[1024]; int bytesRec = _sock.Receive(bytes); data += Encoding.ASCII.GetString(bytes, 0, bytesRec); if (data.IndexOf(Messages.EOF, StringComparison.CurrentCulture) > -1) break; } messageReceived?.Invoke(null, data); } catch (Exception e) { Console.WriteLine(e); } } } #region IDisposable Support private bool disposedValue = false; // To detect redundant calls protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { _stayConnected = false; _sock.Shutdown(SocketShutdown.Both); if (!(_recvThread is null)) { if (_recvThread.IsAlive) _recvThread.Abort(); _recvThread = null; } _sock.Close(); } _sock = null; _recvThread = null; disposedValue = true; } } // This code added to correctly implement the disposable pattern. public void Dispose() { // Do not change this code. Put cleanup code in Dispose(bool disposing) above. Dispose(true); } #endregion } public class DaemonServer : IDisposable { public static int port = 22037; private Socket _sock; private Thread _lThread; private bool _stayListening = false; public event EventHandler clientConnected; public DaemonServer() { try { IPHostEntry host = Dns.GetHostEntry("localhost"); IPAddress ipAddress = host.AddressList[0]; IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port); _sock = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp); _stayListening = true; _sock.Bind(localEndPoint); _sock.Listen(64); _lThread = new Thread(lThreader) { IsBackground = true }; _lThread.Start(); } catch (Exception e) { _stayListening = false; Console.WriteLine(e); _sock = null; if (!(_lThread is null)) { if (_lThread.IsAlive) _lThread.Abort(); _lThread = null; } throw new InvalidOperationException("Daemon Server Init Failed."); } } public void lThreader() { while (_stayListening) { try { Socket handled = _sock.Accept(); DaemonClient dc = new DaemonClient(handled); clientConnected?.Invoke(null,dc); } catch (Exception e) { Console.WriteLine(e); } } } #region IDisposable Support private bool disposedValue = false; // To detect redundant calls protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { _stayListening = false; if (!(_lThread is null)) { if (_lThread.IsAlive) _lThread.Abort(); _lThread = null; } _sock.Close(); } _sock = null; _lThread = null; disposedValue = true; } } // This code added to correctly implement the disposable pattern. public void Dispose() { // Do not change this code. Put cleanup code in Dispose(bool disposing) above. Dispose(true); } #endregion } }