Compare commits

...

2 Commits

Author SHA1 Message Date
Captain ALM
12bcb4fe57 New daemon communication code. 2021-03-23 18:07:47 +00:00
Captain ALM
7701457ac0 Add the new message transmition class. 2021-03-23 12:57:51 +00:00
7 changed files with 554 additions and 245 deletions

View File

@ -197,7 +197,7 @@ public partial class MainWindow : Window
void StartupCheckMethod()
{
ClientResponseState s = Client.SendDataMessage(DataMessage.Status);
ClientResponseState s = GUISocketServer.SendDataMessage(DataMessage.Status);
Console.WriteLine(s);
Application.Invoke(delegate
{
@ -207,7 +207,7 @@ public partial class MainWindow : Window
void Refresh()
{
ClientResponseState s = Client.SendDataMessage(DataMessage.Status);
ClientResponseState s = GUISocketServer.SendDataMessage(DataMessage.Status);
switch (s)
{
case ClientResponseState.Error:
@ -364,7 +364,7 @@ public partial class MainWindow : Window
void OnStartClicked(object sender, EventArgs e)
{
ClientResponseState s = Client.SendDataMessage(DataMessage.Start);
ClientResponseState s = GUISocketServer.SendDataMessage(DataMessage.Start);
switch (s)
{
case ClientResponseState.Error:
@ -382,7 +382,7 @@ public partial class MainWindow : Window
void OnStopClicked(object sender, EventArgs e)
{
ClientResponseState s = Client.SendDataMessage(DataMessage.Stop);
ClientResponseState s = GUISocketServer.SendDataMessage(DataMessage.Stop);
switch (s)
{
case ClientResponseState.Error:
@ -417,7 +417,7 @@ public partial class MainWindow : Window
void RestartToggleBtn_Clicked(object sender, EventArgs e)
{
ClientResponseState s = (RestartMode) ? Client.SendDataMessage(DataMessage.RestartOff) : Client.SendDataMessage(DataMessage.RestartOn);
ClientResponseState s = (RestartMode) ? GUISocketServer.SendDataMessage(DataMessage.RestartOff) : GUISocketServer.SendDataMessage(DataMessage.RestartOn);
switch (s)
{
case ClientResponseState.Error:

View File

@ -7,7 +7,9 @@ namespace MelonVPNConnectedClientUpdate
{
public static void Main(string[] args)
{
Client.SendCustomMessage(Messages.GetClientListMessage(Console.ReadLine()));
GUISocketServer.oneConnect();
GUISocketServer.SendCustomMessage(Messages.GetClientListMessage(Console.ReadLine()));
GUISocketServer.oneDispose();
}
}
}

View File

@ -1,41 +0,0 @@
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace MelonVPNCore
{
public static class Client
{
public static ClientResponseState SendDataMessage(DataMessage msg) => SendDataMessage(msg, false);
public static ClientResponseState SendDataMessage(DataMessage msg, bool IsSendingFromDaemon) => SendCustomMessage(Messages.GetMessage(msg), IsSendingFromDaemon);
public static ClientResponseState SendCustomMessage(string msg) => SendCustomMessage(msg, false);
public static ClientResponseState SendCustomMessage(string msg, bool IsSendingFromDaemon)
{
IPHostEntry host = Dns.GetHostEntry("localhost");
IPAddress ipAddress = host.AddressList[0];
IPEndPoint remoteEndPoint = new IPEndPoint(ipAddress, IsSendingFromDaemon ? 22036 : 22035);
try
{
if (msg == Messages.EOF || msg == "") return ClientResponseState.Blank;
Socket client = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
client.Connect(remoteEndPoint);
client.ReceiveTimeout = 5000;
client.SendTimeout = 5000;
byte[] bytes = Encoding.ASCII.GetBytes(msg);
client.Send(bytes);
client.Close();
return ClientResponseState.Sent;
}
catch (Exception e)
{
Console.WriteLine(e);
return ClientResponseState.Error;
}
}
}
}

View File

@ -0,0 +1,329 @@
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Collections.Generic;
namespace MelonVPNCore
{
public class DaemonClient : IDisposable
{
public ClientResponseState SendDataMessage(DataMessage msg) => SendCustomMessage(Messages.GetMessage(msg));
private Socket _sock;
public static int timeout = 5000;
private Thread _recvThread;
private bool _stayConnected = false;
public event EventHandler<String> messageReceived;
public event EventHandler<Exception> connectionError;
public DaemonClient() { }
public DaemonClient(Socket sockIn)
{
if (sockIn is null) throw new ArgumentNullException(nameof(sockIn));
}
public void start()
{
try
{
if (_sock is null)
{
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);
}
else
{
_stayConnected = true;
}
_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 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);
connectionError?.Invoke(this, 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(this, data);
} catch (SocketException e)
{
Console.WriteLine(e);
connectionError?.Invoke(this, e);
} 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;
try
{
_sock.Shutdown(SocketShutdown.Both);
} catch (SocketException e)
{
Console.WriteLine(e);
}
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<DaemonClient> clientConnected;
public void start()
{
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
{
DaemonClient dc = new DaemonClient(_sock.Accept());
clientConnected?.Invoke(this,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
}
public class DaemonClientMultiplexor : IDisposable
{
public ClientResponseState SendDataMessage(DataMessage msg) => SendCustomMessage(Messages.GetMessage(msg));
private List<DaemonClient> plexed = new List<DaemonClient>();
private object slockplexed = new object();
private object slockcon = new object();
private object slockrecv = new object();
public event EventHandler<String> clientMessageReceived;
public event EventHandler<DaemonClient> clientConnectComplete;
public bool startClients = true;
public bool disconnectErroredClients = true;
public DaemonClientMultiplexor(DaemonServer dsIn)
{
if (dsIn is null) throw new ArgumentNullException(nameof(dsIn));
dsIn.clientConnected += DsIn_ClientConnected;
}
void DsIn_ClientConnected(object sender, DaemonClient e)
{
lock (slockplexed) plexed.Add(e);
e.messageReceived += E_MessageReceived;
e.connectionError += E_ConnectionError;
if (startClients) e.start();
lock(slockcon) clientConnectComplete?.Invoke(this, e);
}
void E_MessageReceived(object sender, string e)
{
lock(slockrecv) clientMessageReceived?.Invoke(this, e);
}
void E_ConnectionError(object sender, Exception e)
{
if(disconnectErroredClients) ((DaemonClient)sender).Dispose();
}
public ClientResponseState SendCustomMessage(string msg)
{
var toret = ClientResponseState.Sent;
lock (slockplexed) {
foreach (DaemonClient c in plexed)
{
try
{
if (c.SendCustomMessage(msg) != ClientResponseState.Sent) toret = ClientResponseState.Error;
} catch (Exception e)
{
Console.WriteLine(e);
}
}
}
return toret;
}
public void disconnectAllClients()
{
lock (slockplexed) foreach (DaemonClient c in plexed) c.Dispose();
lock (slockplexed) plexed.Clear();
}
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
lock(slockplexed) foreach (DaemonClient c in plexed) c.Dispose();
lock (slockplexed) plexed.Clear();
}
plexed = null;
slockcon = null;
slockrecv = null;
slockplexed = 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
}
}

View File

@ -15,50 +15,55 @@ namespace MelonVPNCore
private static bool isRestarting = false;
private static int startingTime = 3000;
private static int restartDelay = 250;
private static DaemonServer _srv;
private static DaemonClientMultiplexor _mlt;
private static string lastClientUpdate = Messages.EOF;
public static void StartServer()
{
IPHostEntry host = Dns.GetHostEntry("localhost");
IPAddress ipAddress = host.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 22035);
try
{
Socket listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(localEndPoint);
listener.Listen(32);
string lastClientUpdate = Messages.EOF;
while (true)
{
Socket handler = listener.Accept();
string data = null;
byte[] bytes = null;
while (true)
{
bytes = new byte[1024];
int bytesRec = handler.Receive(bytes);
data += Encoding.ASCII.GetString(bytes, 0, bytesRec);
if (data.IndexOf(Messages.EOF, StringComparison.CurrentCulture) > -1) break;
_srv = new DaemonServer();
_mlt = new DaemonClientMultiplexor(_srv);
_mlt.clientMessageReceived += clientMessageReceived;
_srv.start();
}
public static bool isProcessOnline(Process p)
{
if (p == null)
{
return false;
}
else
{
if (p.HasExited)
{
return false;
}
else
{
return true;
}
}
}
static void clientMessageReceived(object sender, string data)
{
try
{
if (data.StartsWith(Messages.ClientListStartMsg, StringComparison.CurrentCulture) && shouldBeRunning)
{
lastClientUpdate = data;
Client.SendCustomMessage(lastClientUpdate, true);
_mlt.SendCustomMessage(lastClientUpdate);
}
else if (data == Messages.RestartOnMsg)
{
shouldRestart = true;
Client.SendDataMessage(DataMessage.RestartOn, true);
_mlt.SendDataMessage(DataMessage.RestartOn);
}
else if (data == Messages.RestartOffMsg)
{
shouldRestart = false;
Client.SendDataMessage(DataMessage.RestartOff, true);
_mlt.SendDataMessage(DataMessage.RestartOff);
}
else if (data == Messages.StatusMsg)
{
@ -68,27 +73,27 @@ namespace MelonVPNCore
if (isRestarting)
{
Console.WriteLine("Sending response: restarting");
Client.SendDataMessage(DataMessage.Restarting, true);
Client.SendCustomMessage(lastClientUpdate, true);
_mlt.SendDataMessage(DataMessage.Restarting);
_mlt.SendCustomMessage(lastClientUpdate);
}
else
{
Console.WriteLine("Sending response: online");
Client.SendDataMessage(DataMessage.Online, true);
Client.SendCustomMessage(lastClientUpdate, true);
_mlt.SendDataMessage(DataMessage.Online);
_mlt.SendCustomMessage(lastClientUpdate);
}
}
else
{
Console.WriteLine("Sending response: offline");
Client.SendDataMessage(DataMessage.Offline, true);
Client.SendCustomMessage(Messages.ClientListEmptyMsg, true);
_mlt.SendDataMessage(DataMessage.Offline);
_mlt.SendCustomMessage(Messages.ClientListEmptyMsg);
}
Client.SendDataMessage((shouldRestart) ? DataMessage.RestartOn : DataMessage.RestartOff);
_mlt.SendDataMessage((shouldRestart) ? DataMessage.RestartOn : DataMessage.RestartOff);
}
else if (data == Messages.StartMsg)
{
if (! isProcessOnline(currentVpnProcess))
if (!isProcessOnline(currentVpnProcess))
{
shouldBeRunning = true;
Console.WriteLine("Starting VPN");
@ -96,11 +101,11 @@ namespace MelonVPNCore
{
Console.WriteLine("Starting embedded process");
Console.WriteLine("Sending starting reply");
Client.SendDataMessage(DataMessage.Starting, true);
_mlt.SendDataMessage(DataMessage.Starting);
if (StartEProcess(true))
{
Console.WriteLine("Sending online reply");
Client.SendDataMessage(DataMessage.Online, true);
_mlt.SendDataMessage(DataMessage.Online);
currentVpnProcess.EnableRaisingEvents = true;
}
else { throw new InvalidOperationException("Client crashed!"); }
@ -112,8 +117,8 @@ namespace MelonVPNCore
Console.WriteLine("It looked like this: " + e);
currentVpnProcess.Dispose();
currentVpnProcess = null;
Client.SendDataMessage(DataMessage.Error, true);
Client.SendCustomMessage(Messages.ClientListEmptyMsg, true);
_mlt.SendDataMessage(DataMessage.Error);
_mlt.SendCustomMessage(Messages.ClientListEmptyMsg);
}
}
else
@ -140,8 +145,8 @@ namespace MelonVPNCore
Console.WriteLine("There was an error. But I fixed it.");
Console.WriteLine("It looked like this: " + e);
currentVpnProcess = null;
Client.SendDataMessage(DataMessage.Error, true);
Client.SendCustomMessage(Messages.ClientListEmptyMsg, true);
_mlt.SendDataMessage(DataMessage.Error);
_mlt.SendCustomMessage(Messages.ClientListEmptyMsg);
haderr = true;
}
}
@ -152,16 +157,13 @@ namespace MelonVPNCore
if (!haderr)
{
Console.WriteLine("Sending offline reply");
Client.SendDataMessage(DataMessage.Offline, true);
Client.SendCustomMessage(Messages.ClientListEmptyMsg, true);
_mlt.SendDataMessage(DataMessage.Offline);
_mlt.SendCustomMessage(Messages.ClientListEmptyMsg);
}
}
Client.SendDataMessage(DataMessage.Blank, true);
_mlt.SendDataMessage(DataMessage.Blank);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
}
catch (Exception e)
{
@ -169,24 +171,6 @@ namespace MelonVPNCore
}
}
public static bool isProcessOnline(Process p)
{
if (p == null)
{
return false;
}
else
{
if (p.HasExited)
{
return false;
}
else
{
return true;
}
}
}
static void CurrentVpnProcess_Exited(object sender, EventArgs e)
{
@ -199,11 +183,11 @@ namespace MelonVPNCore
while (shouldRestart && shouldBeRunning)
{
Console.WriteLine("Sending restarting reply");
Client.SendDataMessage(DataMessage.Restarting, true);
_mlt.SendDataMessage(DataMessage.Restarting);
if (StartEProcess(false))
{
Console.WriteLine("Sending online reply");
Client.SendDataMessage(DataMessage.Online, true);
_mlt.SendDataMessage(DataMessage.Online);
currentVpnProcess.EnableRaisingEvents = true;
imonline = true;
break;
@ -220,8 +204,8 @@ namespace MelonVPNCore
{
shouldBeRunning = false;
Console.WriteLine("Sending offline reply");
Client.SendDataMessage(DataMessage.Offline, true);
Client.SendCustomMessage(Messages.ClientListEmptyMsg, true);
_mlt.SendDataMessage(DataMessage.Offline);
_mlt.SendCustomMessage(Messages.ClientListEmptyMsg);
}
}

View File

@ -2,41 +2,76 @@
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace MelonVPNCore
{
public static class GUISocketServer
{
public static ClientResponseState SendDataMessage(DataMessage msg) => SendCustomMessage(Messages.GetMessage(msg));
public static int reconnectTimeout = 2000;
public static DaemonClient client;
public static event EventHandler<ClientResponseState> Receive;
public static event EventHandler<ConnectedClient[]> ClientListUpdate;
private static bool waitfcl = false;
private static bool exec = true;
public static void StartServer()
{
IPHostEntry host = Dns.GetHostEntry("localhost");
IPAddress ipAddress = host.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 22036);
while (exec)
{
try
{
Socket listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(localEndPoint);
listener.Listen(32);
while (true)
client = new DaemonClient();
client.connectionError += Client_ConnectionError;
client.messageReceived += Client_MessageReceived;
waitfcl = true;
client.start();
while (waitfcl) Thread.Sleep(reconnectTimeout);
client.connectionError -= Client_ConnectionError;
client.messageReceived -= Client_MessageReceived;
client.Dispose();
}
catch (InvalidOperationException e)
{
Socket handler = listener.Accept();
string data = "";
byte[] bytes = null;
while (true)
{
bytes = new byte[1024];
int bytesRec = handler.Receive(bytes);
data += Encoding.ASCII.GetString(bytes, 0, bytesRec);
if (data.IndexOf(Messages.EOF, StringComparison.CurrentCulture) > -1) break;
Console.WriteLine(e);
}
Thread.Sleep(reconnectTimeout);
}
Console.WriteLine("GUISocketServer has reached the end.");
}
public static void oneConnect()
{
try
{
client = new DaemonClient();
client.messageReceived += Client_MessageReceived;
waitfcl = true;
client.start();
}
catch (InvalidOperationException e)
{
Console.WriteLine(e);
}
}
public static void oneDispose()
{
client.messageReceived -= Client_MessageReceived;
client.Dispose();
}
static void Client_ConnectionError(object sender, Exception e)
{
waitfcl = false;
}
static void Client_MessageReceived(object sender, string data)
{
try
{
ClientResponseState ret = ClientResponseState.None;
if (data == Messages.OnlineMsg) ret = ClientResponseState.Online;
if (data == Messages.OfflineMsg) ret = ClientResponseState.Offline;
@ -54,18 +89,18 @@ namespace MelonVPNCore
ConnectedClient[] clients = ClientListParser.Parse(jsonData);
ClientListUpdate?.Invoke(null, clients);
}
handler.Shutdown(SocketShutdown.Both);
handler.Close();
Receive?.Invoke(null, ret);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.WriteLine("GUI socket server reached the end");
}
public static ClientResponseState SendCustomMessage(string msg)
{
var toret = client?.SendCustomMessage(msg);
return (toret.HasValue) ? toret.Value : ClientResponseState.Error;
}
}
}

View File

@ -29,12 +29,12 @@
<Compile Include="DaemonSocketServer.cs" />
<Compile Include="ThreadWrapper.cs" />
<Compile Include="Messages.cs" />
<Compile Include="Client.cs" />
<Compile Include="DataMessage.cs" />
<Compile Include="ClientResponseState.cs" />
<Compile Include="GUISocketServer.cs" />
<Compile Include="ClientListParser.cs" />
<Compile Include="ConnectedClient.cs" />
<Compile Include="DaemonMessaging.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="System" />