mirror of
https://github.com/openziti/desktop-edge-win.git
synced 2026-10-12 15:58:34 +00:00
252 lines
11 KiB
C#
252 lines
11 KiB
C#
using System;
|
|
using System.Threading.Tasks;
|
|
using System.IO;
|
|
using System.IO.Pipes;
|
|
using System.Security.Principal;
|
|
using System.Security.AccessControl;
|
|
|
|
using Newtonsoft.Json;
|
|
using NLog;
|
|
|
|
using ZitiDesktopEdge.DataStructures;
|
|
|
|
namespace ZitiDesktopEdge.Server {
|
|
public class IPCServer {
|
|
public const string PipeName = @"OpenZiti\ziti-monitor\ipc";
|
|
public const string EventPipeName = @"OpenZiti\ziti-monitor\events";
|
|
|
|
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
|
private static int BUFFER_SIZE = 16 * 1024;
|
|
|
|
private JsonSerializer serializer = new JsonSerializer() { Formatting = Formatting.None };
|
|
private string ipcPipeName;
|
|
private string eventPipeName;
|
|
|
|
public delegate Task OnClientAsync(StreamWriter writer);
|
|
|
|
public delegate string CaptureLogsDelegate();
|
|
public CaptureLogsDelegate CaptureLogs { get; set; }
|
|
|
|
public delegate void SetLogLevelDelegate(string level);
|
|
public SetLogLevelDelegate SetLogLevel { get; set; }
|
|
|
|
public delegate void SetReleaseStreamDelegate(string stream);
|
|
public SetReleaseStreamDelegate SetReleaseStream { get; set; }
|
|
|
|
public delegate StatusCheck DoUpdateCheckDelegate();
|
|
public DoUpdateCheckDelegate DoUpdateCheck { get; set; }
|
|
|
|
public delegate SvcResponse TriggerUpdateDelegate();
|
|
public TriggerUpdateDelegate TriggerUpdate { get; set; }
|
|
|
|
public IPCServer() {
|
|
ipcPipeName = PipeName;
|
|
eventPipeName = EventPipeName;
|
|
}
|
|
|
|
async public Task startIpcServerAsync(OnClientAsync onClient) {
|
|
int idx = 0;
|
|
|
|
// Allow AuthenticatedUserSid read and write access to the pipe.
|
|
PipeSecurity pipeSecurity = new PipeSecurity();
|
|
var id = new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null);
|
|
pipeSecurity.SetAccessRule(new PipeAccessRule(id, PipeAccessRights.CreateNewInstance | PipeAccessRights.ReadWrite, AccessControlType.Allow));
|
|
|
|
while (true) {
|
|
try {
|
|
var ipcPipeServer = new NamedPipeServerStream(
|
|
ipcPipeName,
|
|
PipeDirection.InOut,
|
|
NamedPipeServerStream.MaxAllowedServerInstances,
|
|
PipeTransmissionMode.Byte,
|
|
PipeOptions.Asynchronous | PipeOptions.WriteThrough,
|
|
BUFFER_SIZE,
|
|
BUFFER_SIZE,
|
|
pipeSecurity);
|
|
|
|
await ipcPipeServer.WaitForConnectionAsync();
|
|
Logger.Debug("Total ipc clients now at: {0}", ++idx);
|
|
_ = Task.Run(async () => {
|
|
try {
|
|
await handleIpcClientAsync(ipcPipeServer, onClient);
|
|
} catch(Exception icpe) {
|
|
Logger.Error(icpe, "Unexpected erorr in handleIpcClientAsync");
|
|
}
|
|
idx--;
|
|
Logger.Debug("Total ipc clients now at: {0}", idx);
|
|
});
|
|
} catch (Exception pe) {
|
|
Logger.Error(pe, "Unexpected erorr when connecting a client pipe.");
|
|
}
|
|
}
|
|
}
|
|
|
|
async public Task startEventsServerAsync(OnClientAsync onClient) {
|
|
int idx = 0;
|
|
|
|
// Allow AuthenticatedUserSid read and write access to the pipe.
|
|
PipeSecurity pipeSecurity = new PipeSecurity();
|
|
var id = new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null);
|
|
pipeSecurity.SetAccessRule(new PipeAccessRule(id, PipeAccessRights.CreateNewInstance | PipeAccessRights.ReadWrite, AccessControlType.Allow));
|
|
|
|
while (true) {
|
|
try {
|
|
var eventPipeServer = new NamedPipeServerStream(
|
|
eventPipeName,
|
|
PipeDirection.InOut,
|
|
NamedPipeServerStream.MaxAllowedServerInstances,
|
|
PipeTransmissionMode.Byte,
|
|
PipeOptions.Asynchronous | PipeOptions.WriteThrough,
|
|
BUFFER_SIZE,
|
|
BUFFER_SIZE,
|
|
pipeSecurity);
|
|
|
|
await eventPipeServer.WaitForConnectionAsync();
|
|
Logger.Debug("Total event clients now at: {0}", ++idx);
|
|
_ = Task.Run(async () => {
|
|
try {
|
|
await handleEventClientAsync(eventPipeServer, onClient);
|
|
} catch (Exception icpe) {
|
|
Logger.Error(icpe, "Unexpected erorr in handleEventClientAsync");
|
|
}
|
|
idx--;
|
|
Logger.Debug("Total event clients now at: {0}", idx);
|
|
});
|
|
} catch (Exception pe) {
|
|
Logger.Error(pe, "Unexpected erorr when connecting a client pipe.");
|
|
}
|
|
}
|
|
}
|
|
|
|
async public Task handleIpcClientAsync(NamedPipeServerStream ss, OnClientAsync onClient) {
|
|
using (ss) {
|
|
try {
|
|
StreamReader reader = new StreamReader(ss);
|
|
StreamWriter writer = new StreamWriter(ss);
|
|
|
|
string line = await reader.ReadLineAsync();
|
|
|
|
while (line != null) {
|
|
await processMessageAsync(line, writer);
|
|
line = await reader.ReadLineAsync();
|
|
}
|
|
|
|
Logger.Debug("handleIpcClientAsync is complete");
|
|
} catch (Exception e) {
|
|
Logger.Error(e, "Unexpected erorr when reading from or writing to a client pipe.");
|
|
}
|
|
}
|
|
}
|
|
|
|
async public Task handleEventClientAsync(NamedPipeServerStream ss, OnClientAsync onClient) {
|
|
using (ss) {
|
|
|
|
StreamWriter writer = new StreamWriter(ss);
|
|
EventHandler eh = async (object sender, EventArgs e) => {
|
|
await writer.WriteLineAsync(sender.ToString());
|
|
await writer.FlushAsync();
|
|
};
|
|
|
|
await onClient(writer);
|
|
|
|
EventRegistry.MyEvent += eh;
|
|
try {
|
|
StreamReader reader = new StreamReader(ss);
|
|
|
|
string line = await reader.ReadLineAsync();
|
|
while (line != null) {
|
|
await processMessageAsync(line, writer);
|
|
line = await reader.ReadLineAsync();
|
|
}
|
|
|
|
Logger.Debug("handleEventClientAsync is complete");
|
|
} catch (Exception e) {
|
|
Logger.Error(e, "Unexpected erorr when reading from or writing to a client pipe.");
|
|
}
|
|
EventRegistry.MyEvent -= eh;
|
|
}
|
|
}
|
|
|
|
async public Task processMessageAsync(string json, StreamWriter writer) {
|
|
Logger.Debug("message received: {0}", json);
|
|
var r = new SvcResponse();
|
|
var rr = new MonitorServiceStatusEvent();
|
|
try {
|
|
ActionEvent ae = serializer.Deserialize<ActionEvent>(new JsonTextReader(new StringReader(json)));
|
|
Logger.Debug("Op: {0}", ae.Op);
|
|
switch (ae.Op.ToLower()) {
|
|
case "stop":
|
|
if (ae.Action == "Force") {
|
|
// attempt to forcefully find the process and terminate it...
|
|
Logger.Warn("User has requested a FORCEFUL termination of the service. It must be stuck. Current status: {0}", ServiceActions.ServiceStatus());
|
|
var procs = System.Diagnostics.Process.GetProcessesByName("ziti-tunnel");
|
|
if (procs == null || procs.Length == 0) {
|
|
Logger.Error("Process not found! Cannot terminate!");
|
|
rr.Code = -20;
|
|
rr.Error = "Process not found! Cannot terminate!";
|
|
rr.Message = "Could not terminate the service forcefully";
|
|
break;
|
|
}
|
|
|
|
foreach(var p in procs) {
|
|
Logger.Warn("Forcefully terminating process: {0}", p.Id);
|
|
p.Kill();
|
|
}
|
|
rr.Message = "Service has been terminated";
|
|
rr.Status = ServiceActions.ServiceStatus();
|
|
r = rr;
|
|
} else {
|
|
r.Message = ServiceActions.StopService();
|
|
}
|
|
break;
|
|
case "start":
|
|
r.Message = ServiceActions.StartService();
|
|
break;
|
|
case "status":
|
|
rr.Status = ServiceActions.ServiceStatus();
|
|
r = rr;
|
|
break;
|
|
case "capturelogs":
|
|
try {
|
|
string results = CaptureLogs();
|
|
r.Message = results;
|
|
} catch (Exception ex) {
|
|
string err = string.Format("UNKNOWN ERROR : {0}", ex.Message);
|
|
Logger.Error(ex, err);
|
|
r.Code = -5;
|
|
r.Message = "FAILURE";
|
|
r.Error = err;
|
|
}
|
|
break;
|
|
case "setreleasestream":
|
|
SetReleaseStream(ae.Action);
|
|
break;
|
|
case "setloglevel":
|
|
SetLogLevel(ae.Action);
|
|
break;
|
|
case "doupdatecheck":
|
|
r = DoUpdateCheck();
|
|
break;
|
|
case "triggerupdate":
|
|
r = TriggerUpdate();
|
|
break;
|
|
default:
|
|
r.Message = "FAILURE";
|
|
r.Code = -3;
|
|
r.Error = string.Format("UNKNOWN ACTION received: {0}", ae.Op);
|
|
Logger.Error(r.Message);
|
|
break;
|
|
}
|
|
} catch (Exception e) {
|
|
Logger.Error(e, "Unexpected erorr in processMessage!");
|
|
r.Message = "FAILURE";
|
|
r.Code = -2;
|
|
r.Error = e.Message + ":" + e?.InnerException?.Message;
|
|
}
|
|
Logger.Debug("Returning status: {0}", r.Message);
|
|
await writer.WriteLineAsync(JsonConvert.SerializeObject(r));
|
|
await writer.FlushAsync();
|
|
}
|
|
}
|
|
}
|