diff --git a/MelonVPNCore/DaemonMessaging.cs b/MelonVPNCore/DaemonMessaging.cs new file mode 100644 index 0000000..0ab3b31 --- /dev/null +++ b/MelonVPNCore/DaemonMessaging.cs @@ -0,0 +1,217 @@ +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 + + } +} diff --git a/MelonVPNCore/MelonVPNCore.csproj b/MelonVPNCore/MelonVPNCore.csproj index d970afb..82c59fb 100644 --- a/MelonVPNCore/MelonVPNCore.csproj +++ b/MelonVPNCore/MelonVPNCore.csproj @@ -35,6 +35,7 @@ +