New daemon communication code.

This commit is contained in:
Captain ALM 2021-03-23 18:07:47 +00:00
parent 7701457ac0
commit 12bcb4fe57
7 changed files with 361 additions and 270 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

@ -3,23 +3,32 @@ 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(msg);
public ClientResponseState SendCustomMessage(DataMessage msg) => SendCustomMessage(Messages.GetMessage(msg)));
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() { }
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];
@ -27,6 +36,11 @@ namespace MelonVPNCore
_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)
@ -34,7 +48,8 @@ namespace MelonVPNCore
IsBackground = true
};
_recvThread.Start();
} catch (Exception e)
}
catch (Exception e)
{
_stayConnected = false;
Console.WriteLine(e);
@ -48,11 +63,6 @@ namespace MelonVPNCore
}
}
public DaemonClient(Socket sockIn)
{
if (sockIn is null) throw new InvalidOperationException("Passed Socket is Null.");
}
public ClientResponseState SendCustomMessage(string msg)
{
try
@ -65,6 +75,7 @@ namespace MelonVPNCore
catch (Exception e)
{
Console.WriteLine(e);
connectionError?.Invoke(this, e);
return ClientResponseState.Error;
}
}
@ -85,8 +96,11 @@ namespace MelonVPNCore
data += Encoding.ASCII.GetString(bytes, 0, bytesRec);
if (data.IndexOf(Messages.EOF, StringComparison.CurrentCulture) > -1) break;
}
messageReceived?.Invoke(null, data);
messageReceived?.Invoke(this, data);
} catch (SocketException e)
{
Console.WriteLine(e);
connectionError?.Invoke(this, e);
} catch (Exception e)
{
Console.WriteLine(e);
@ -104,7 +118,13 @@ namespace MelonVPNCore
if (disposing)
{
_stayConnected = false;
try
{
_sock.Shutdown(SocketShutdown.Both);
} catch (SocketException e)
{
Console.WriteLine(e);
}
if (!(_recvThread is null))
{
if (_recvThread.IsAlive) _recvThread.Abort();
@ -135,7 +155,7 @@ namespace MelonVPNCore
private bool _stayListening = false;
public event EventHandler<DaemonClient> clientConnected;
public DaemonServer()
public void start()
{
try
{
@ -151,7 +171,8 @@ namespace MelonVPNCore
IsBackground = true
};
_lThread.Start();
} catch (Exception e)
}
catch (Exception e)
{
_stayListening = false;
Console.WriteLine(e);
@ -171,9 +192,8 @@ namespace MelonVPNCore
{
try
{
Socket handled = _sock.Accept();
DaemonClient dc = new DaemonClient(handled);
clientConnected?.Invoke(null,dc);
DaemonClient dc = new DaemonClient(_sock.Accept());
clientConnected?.Invoke(this,dc);
}
catch (Exception e)
{
@ -214,4 +234,96 @@ namespace MelonVPNCore
#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,23 +73,23 @@ 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)
{
@ -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,7 +29,6 @@
<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" />