Skip to content

Commit 990a970

Browse files
committed
fix: various fixes for tunnel startup to work
Fixes various problems that prevented tunnel startup from succeeding and prevented clients from connecting to the RPC server. Added a new temporary package Vpn.DebugClient to help control the system service component until the UI is ready. Adds utility PS1 scripts for adding the debug binary to a new system service and managing/hotswapping it.
1 parent 7b0e421 commit 990a970

16 files changed

+593
-83
lines changed

Coder.Desktop.sln

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio Version 17
4-
VisualStudioVersion = 17.12.35707.178 d17.12
4+
VisualStudioVersion = 17.12.35707.178
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vpn", "Vpn\Vpn.csproj", "{B342F896-C721-4AA5-A0F6-0BFA8EBAFACB}"
77
EndProject
@@ -21,6 +21,8 @@ Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "Package", "Package\Package.
2121
EndProject
2222
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "App\App.csproj", "{800C7E2D-0D86-4554-9903-B879DA6FA2CE}"
2323
EndProject
24+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vpn.DebugClient", "Vpn.DebugClient\Vpn.DebugClient.csproj", "{1BBFDF88-B25F-4C07-99C2-30DA384DB730}"
25+
EndProject
2426
Global
2527
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2628
Debug|Any CPU = Debug|Any CPU
@@ -185,6 +187,22 @@ Global
185187
{800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Release|x64.Build.0 = Release|x64
186188
{800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Release|x86.ActiveCfg = Release|x86
187189
{800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Release|x86.Build.0 = Release|x86
190+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
191+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Debug|Any CPU.Build.0 = Debug|Any CPU
192+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Debug|ARM64.ActiveCfg = Debug|Any CPU
193+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Debug|ARM64.Build.0 = Debug|Any CPU
194+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Debug|x64.ActiveCfg = Debug|Any CPU
195+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Debug|x64.Build.0 = Debug|Any CPU
196+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Debug|x86.ActiveCfg = Debug|Any CPU
197+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Debug|x86.Build.0 = Debug|Any CPU
198+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Release|Any CPU.ActiveCfg = Release|Any CPU
199+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Release|Any CPU.Build.0 = Release|Any CPU
200+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Release|ARM64.ActiveCfg = Release|Any CPU
201+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Release|ARM64.Build.0 = Release|Any CPU
202+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Release|x64.ActiveCfg = Release|Any CPU
203+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Release|x64.Build.0 = Release|Any CPU
204+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Release|x86.ActiveCfg = Release|Any CPU
205+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Release|x86.Build.0 = Release|Any CPU
188206
EndGlobalSection
189207
GlobalSection(SolutionProperties) = preSolution
190208
HideSolutionNode = FALSE

Vpn.DebugClient/Program.cs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
using System.IO.Pipes;
2+
using Coder.Desktop.Vpn.Proto;
3+
4+
namespace Coder.Desktop.Vpn.DebugClient;
5+
6+
public static class Program
7+
{
8+
private static Speaker<ClientMessage, ServiceMessage>? _speaker;
9+
10+
private static string? _coderUrl;
11+
private static string? _apiToken;
12+
13+
public static void Main()
14+
{
15+
Console.WriteLine("Type 'exit' to exit the program");
16+
Console.WriteLine("Type 'connect' to connect to the service");
17+
Console.WriteLine("Type 'disconnect' to disconnect from the service");
18+
Console.WriteLine("Type 'configure' to set the parameters");
19+
Console.WriteLine("Type 'start' to send a start command with the current parameters");
20+
Console.WriteLine("Type 'stop' to send a stop command");
21+
while (true)
22+
{
23+
Console.Write("> ");
24+
var input = Console.ReadLine()?.Trim();
25+
try
26+
{
27+
switch (input)
28+
{
29+
case "exit":
30+
return;
31+
case "connect":
32+
Connect();
33+
break;
34+
case "disconnect":
35+
Disconnect();
36+
break;
37+
case "configure":
38+
Configure();
39+
break;
40+
case "start":
41+
Start();
42+
break;
43+
case "stop":
44+
Stop();
45+
break;
46+
}
47+
}
48+
catch (Exception ex)
49+
{
50+
Console.WriteLine($"Error: {ex}");
51+
}
52+
}
53+
}
54+
55+
private static void Connect()
56+
{
57+
var client = new NamedPipeClientStream(".", "Coder.Desktop.Vpn", PipeDirection.InOut, PipeOptions.Asynchronous);
58+
client.Connect();
59+
Console.WriteLine("Connected to named pipe.");
60+
61+
_speaker = new Speaker<ClientMessage, ServiceMessage>(client);
62+
_speaker.Receive += message => { Console.WriteLine($"Received({message.Message.MsgCase}: {message.Message}"); };
63+
_speaker.Error += exception =>
64+
{
65+
Console.WriteLine($"Error: {exception}");
66+
Disconnect();
67+
};
68+
_speaker.StartAsync().Wait();
69+
Console.WriteLine("Speaker started.");
70+
}
71+
72+
private static void Disconnect()
73+
{
74+
_speaker?.DisposeAsync().AsTask().Wait();
75+
_speaker = null;
76+
Console.WriteLine("Disconnected from named pipe");
77+
}
78+
79+
private static void Configure()
80+
{
81+
Console.Write("Coder URL: ");
82+
_coderUrl = Console.ReadLine()?.Trim();
83+
Console.Write("API Token: ");
84+
_apiToken = Console.ReadLine()?.Trim();
85+
}
86+
87+
private static void Start()
88+
{
89+
if (_speaker is null)
90+
{
91+
Console.WriteLine("Not connected to Coder.Desktop.Vpn.");
92+
return;
93+
}
94+
95+
var message = new ClientMessage
96+
{
97+
Start = new StartRequest
98+
{
99+
CoderUrl = _coderUrl,
100+
ApiToken = _apiToken,
101+
},
102+
};
103+
Console.WriteLine("Sending start message...");
104+
var sendTask = _speaker.SendRequestAwaitReply(message).AsTask();
105+
Console.WriteLine("Start message sent, awaiting reply.");
106+
sendTask.Wait();
107+
Console.WriteLine($"Received reply: {sendTask.Result.Message}");
108+
}
109+
110+
private static void Stop()
111+
{
112+
if (_speaker is null)
113+
{
114+
Console.WriteLine("Not connected to Coder.Desktop.Vpn.");
115+
return;
116+
}
117+
118+
var message = new ClientMessage
119+
{
120+
Stop = new StopRequest(),
121+
};
122+
Console.WriteLine("Sending stop message...");
123+
var sendTask = _speaker.SendRequestAwaitReply(message);
124+
Console.WriteLine("Stop message sent, awaiting reply.");
125+
var reply = sendTask.AsTask().Result;
126+
Console.WriteLine($"Received reply: {reply.Message}");
127+
}
128+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<RootNamespace>Coder.Desktop.Vpn.DebugClient</RootNamespace>
5+
<OutputType>Exe</OutputType>
6+
<TargetFramework>net8.0</TargetFramework>
7+
<ImplicitUsings>enable</ImplicitUsings>
8+
<Nullable>enable</Nullable>
9+
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<ProjectReference Include="..\Vpn\Vpn.csproj"/>
14+
<ProjectReference Include="..\Vpn.Proto\Vpn.Proto.csproj"/>
15+
</ItemGroup>
16+
17+
</Project>

Vpn.DebugClient/packages.lock.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"version": 1,
3+
"dependencies": {
4+
"net8.0": {
5+
"Google.Protobuf": {
6+
"type": "Transitive",
7+
"resolved": "3.29.1",
8+
"contentHash": "kDFLP72bPu4GwquVN7HtFnfqxhQs4CLbUEyOc/0yV48HB0Pxf7tDK7zIx6ifaQwGp+RSoLY1sz1CXqoAEAu+AQ=="
9+
},
10+
"System.IO.Pipelines": {
11+
"type": "Transitive",
12+
"resolved": "9.0.0",
13+
"contentHash": "eA3cinogwaNB4jdjQHOP3Z3EuyiDII7MT35jgtnsA4vkn0LUrrSHsU0nzHTzFzmaFYeKV7MYyMxOocFzsBHpTw=="
14+
},
15+
"vpn": {
16+
"type": "Project",
17+
"dependencies": {
18+
"System.IO.Pipelines": "[9.0.0, )",
19+
"Vpn.Proto": "[1.0.0, )"
20+
}
21+
},
22+
"vpn.proto": {
23+
"type": "Project",
24+
"dependencies": {
25+
"Google.Protobuf": "[3.29.1, )"
26+
}
27+
}
28+
}
29+
}
30+
}

Vpn.Service/Create-Service.ps1

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Elevate to administrator
2+
if (-not ([Security.Principal.WindowsPrincipal]([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
3+
Write-Host "Elevating script to run as administrator..."
4+
Start-Process powershell.exe -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$($MyInvocation.MyCommand.Path)`"" -Verb RunAs
5+
exit
6+
}
7+
8+
$name = "Coder Desktop (Debug)"
9+
$binaryPath = Join-Path -Path $PSScriptRoot -ChildPath "bin/Debug/net8.0-windows/Vpn.Service.exe"
10+
11+
try {
12+
Write-Host "Creating service..."
13+
New-Service -Name $name -BinaryPathName "`"$binaryPath`"" -DisplayName $name -StartupType Automatic
14+
15+
$sddl = & sc.exe sdshow $name
16+
if (-not $sddl) {
17+
throw "Failed to retrieve security descriptor for service '$name'"
18+
}
19+
Write-Host "Current security descriptor: '$sddl'"
20+
$sddl = $sddl.Trim() -replace "D:", "D:(A;;RPWP;;;WD)" # allow everyone to start, stop, pause, and query the service
21+
Write-Host "Setting security descriptor: '$sddl'"
22+
& sc.exe sdset $name $sddl
23+
24+
Write-Host "Starting service..."
25+
Start-Service -Name $name
26+
27+
if ((Get-Service -Name $name -ErrorAction Stop).Status -ne "Running") {
28+
throw "Service '$name' is not running"
29+
}
30+
Write-Host "Service '$name' created and started successfully"
31+
} catch {
32+
Write-Host $_ -ForegroundColor Red
33+
Write-Host "Press Return to exit..."
34+
Read-Host
35+
}

Vpn.Service/Delete-Service.ps1

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Elevate to administrator
2+
if (-not ([Security.Principal.WindowsPrincipal]([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
3+
Write-Host "Elevating script to run as administrator..."
4+
Start-Process powershell.exe -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$($MyInvocation.MyCommand.Path)`"" -Verb RunAs
5+
exit
6+
}
7+
8+
$name = "Coder Desktop (Debug)"
9+
10+
try {
11+
Stop-Service -Name $name -Force -ErrorAction SilentlyContinue
12+
sc.exe delete $name
13+
Write-Host "Service '$name' deleted"
14+
} catch {
15+
Write-Host $_ -ForegroundColor Red
16+
Write-Host "Press Return to exit..."
17+
Read-Host
18+
}

Vpn.Service/Downloader.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public class AuthenticodeDownloadValidator : IDownloadValidator
4242
{
4343
private readonly string _expectedName;
4444

45+
// ReSharper disable once ConvertToPrimaryConstructor
4546
public AuthenticodeDownloadValidator(string expectedName)
4647
{
4748
_expectedName = expectedName;
@@ -79,6 +80,7 @@ public class AssemblyVersionDownloadValidator : IDownloadValidator
7980
{
8081
private readonly string _expectedAssemblyVersion;
8182

83+
// ReSharper disable once ConvertToPrimaryConstructor
8284
public AssemblyVersionDownloadValidator(string expectedAssemblyVersion)
8385
{
8486
_expectedAssemblyVersion = expectedAssemblyVersion;

0 commit comments

Comments
 (0)