golang.zx2c4.com/wireguard/windows@v0.5.4-0.20230123132234-dcc0eb72a04b/embeddable-dll-service/csharp/DemoUI/MainWindow.cs (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
     4   */
     5  
     6  using System;
     7  using System.Text;
     8  using System.Threading.Tasks;
     9  using System.IO;
    10  using System.Windows.Forms;
    11  using System.Threading;
    12  using System.IO.Pipes;
    13  using System.Diagnostics;
    14  using System.Net.Sockets;
    15  using System.Security.AccessControl;
    16  
    17  namespace DemoUI
    18  {
    19      public partial class MainWindow : Form
    20      {
    21          private static readonly string userDirectory = Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), "Config"); //TODO: put in Program Files in real code.
    22          private static readonly string configFile = Path.Combine(userDirectory, "demobox.conf");
    23          private static readonly string logFile = Path.Combine(userDirectory, "log.bin");
    24  
    25          private Tunnel.Ringlogger log;
    26          private Thread logPrintingThread, transferUpdateThread;
    27          private volatile bool threadsRunning;
    28          private bool connected;
    29  
    30          public MainWindow()
    31          {
    32              makeConfigDirectory();
    33              InitializeComponent();
    34              Application.ApplicationExit += Application_ApplicationExit;
    35              try { File.Delete(logFile); } catch { }
    36              log = new Tunnel.Ringlogger(logFile, "GUI");
    37              logPrintingThread = new Thread(new ThreadStart(tailLog));
    38              transferUpdateThread = new Thread(new ThreadStart(tailTransfer));
    39          }
    40  
    41          private void makeConfigDirectory()
    42          {
    43              var ds = new DirectorySecurity();
    44              ds.SetSecurityDescriptorSddlForm("O:BAG:BAD:PAI(A;OICI;FA;;;BA)(A;OICI;FA;;;SY)");
    45              FileSystemAclExtensions.CreateDirectory(ds, userDirectory);
    46          }
    47  
    48          private void tailLog()
    49          {
    50              var cursor = Tunnel.Ringlogger.CursorAll;
    51              while (threadsRunning)
    52              {
    53                  var lines = log.FollowFromCursor(ref cursor);
    54                  foreach (var line in lines)
    55                      logBox.Invoke(new Action<string>(logBox.AppendText), new object[] { line + "\r\n" });
    56                  try
    57                  {
    58                      Thread.Sleep(300);
    59                  }
    60                  catch
    61                  {
    62                      break;
    63                  }
    64              }
    65          }
    66  
    67          private void tailTransfer()
    68          {
    69              Tunnel.Driver.Adapter adapter = null;
    70              while (threadsRunning)
    71              {
    72                  if (adapter == null)
    73                  {
    74                      while (threadsRunning)
    75                      {
    76                          try
    77                          {
    78                              adapter = Tunnel.Service.GetAdapter(configFile);
    79                              break;
    80                          }
    81                          catch
    82                          {
    83                              try
    84                              {
    85                                  Thread.Sleep(1000);
    86                              }
    87                              catch { }
    88                          }
    89                      }
    90                  }
    91                  if (adapter == null)
    92                      continue;
    93                  try
    94                  {
    95                      ulong rx = 0, tx = 0;
    96                      var config = adapter.GetConfiguration();
    97                      foreach (var peer in config.Peers)
    98                      {
    99                          rx += peer.RxBytes;
   100                          tx += peer.TxBytes;
   101                      }
   102                      Invoke(new Action<ulong, ulong>(updateTransferTitle), new object[] { rx, tx });
   103                      Thread.Sleep(1000);
   104                  }
   105                  catch { adapter = null; }
   106              }
   107          }
   108  
   109          private void Application_ApplicationExit(object sender, EventArgs e)
   110          {
   111              Tunnel.Service.Remove(configFile, true);
   112              try { File.Delete(logFile); } catch { }
   113              try { File.Delete(configFile); } catch { }
   114          }
   115  
   116          private void MainWindow_Load(object sender, EventArgs e)
   117          {
   118              threadsRunning = true;
   119              logPrintingThread.Start();
   120              transferUpdateThread.Start();
   121          }
   122  
   123          private void MainWindow_FormClosing(object sender, FormClosingEventArgs e)
   124          {
   125              threadsRunning = false;
   126              logPrintingThread.Interrupt();
   127              transferUpdateThread.Interrupt();
   128              try { logPrintingThread.Join(); } catch { }
   129              try { transferUpdateThread.Join(); } catch { }
   130          }
   131  
   132          private static string formatBytes(ulong bytes)
   133          {
   134              decimal d = bytes;
   135              string selectedUnit = null;
   136              foreach (string unit in new string[] { "B", "KiB", "MiB", "GiB", "TiB" })
   137              {
   138                  selectedUnit = unit;
   139                  if (d < 1024)
   140                      break;
   141                  d /= 1024;
   142              }
   143              return string.Format("{0:0.##} {1}", d, selectedUnit);
   144          }
   145  
   146          private void updateTransferTitle(ulong rx, ulong tx)
   147          {
   148              var titleBase = Text;
   149              var idx = titleBase.IndexOf(" - ");
   150              if (idx != -1)
   151                  titleBase = titleBase.Substring(0, idx);
   152              if (rx == 0 && tx == 0)
   153                  Text = titleBase;
   154              else
   155                  Text = string.Format("{0} - rx: {1}, tx: {2}", titleBase, formatBytes(rx), formatBytes(tx));
   156          }
   157  
   158          private async Task<string> generateNewConfig()
   159          {
   160              log.Write("Generating keys");
   161              var keys = Tunnel.Keypair.Generate();
   162              log.Write("Exchanging keys with demo server");
   163              var client = new TcpClient();
   164              await client.ConnectAsync("demo.wireguard.com", 42912);
   165              var stream = client.GetStream();
   166              var reader = new StreamReader(stream, Encoding.UTF8);
   167              var pubKeyBytes = Encoding.UTF8.GetBytes(keys.Public + "\n");
   168              await stream.WriteAsync(pubKeyBytes, 0, pubKeyBytes.Length);
   169              await stream.FlushAsync();
   170              var ret = (await reader.ReadLineAsync()).Split(':');
   171              client.Close();
   172              var status = ret.Length >= 1 ? ret[0] : "";
   173              var serverPubkey = ret.Length >= 2 ? ret[1] : "";
   174              var serverPort = ret.Length >= 3 ? ret[2] : "";
   175              var internalIP = ret.Length >= 4 ? ret[3] : "";
   176              if (status != "OK")
   177                  throw new InvalidOperationException(string.Format("Server status is {0}", status));
   178              return string.Format("[Interface]\nPrivateKey = {0}\nAddress = {1}/24\nDNS = 8.8.8.8, 8.8.4.4\n\n[Peer]\nPublicKey = {2}\nEndpoint = demo.wireguard.com:{3}\nAllowedIPs = 0.0.0.0/0\n", keys.Private, internalIP, serverPubkey, serverPort);
   179          }
   180  
   181          private async void connectButton_Click(object sender, EventArgs e)
   182          {
   183              if (connected)
   184              {
   185                  connectButton.Enabled = false;
   186                  await Task.Run(() =>
   187                  {
   188                      Tunnel.Service.Remove(configFile, true);
   189                      try { File.Delete(configFile); } catch { }
   190                  });
   191                  updateTransferTitle(0, 0);
   192                  connectButton.Text = "&Connect";
   193                  connectButton.Enabled = true;
   194                  connected = false;
   195                  return;
   196              }
   197  
   198              connectButton.Enabled = false;
   199              try
   200              {
   201                  var config = await generateNewConfig();
   202                  await File.WriteAllBytesAsync(configFile, Encoding.UTF8.GetBytes(config));
   203                  await Task.Run(() => Tunnel.Service.Add(configFile, true));
   204                  connected = true;
   205                  connectButton.Text = "&Disconnect";
   206              }
   207              catch (Exception ex)
   208              {
   209                  log.Write(ex.Message);
   210                  try { File.Delete(configFile); } catch { }
   211              }
   212              connectButton.Enabled = true;
   213          }
   214      }
   215  }