Skip to content

Commit 4c6d2bd

Browse files
authoredJan 31, 2025··
fix: various fixes for tunnel startup to work (#14)
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. Start and stop operations from a client now reliably work, although there are various TODOs around the service codebase still. Closes #2
1 parent 7f716c8 commit 4c6d2bd

19 files changed

+744
-124
lines changed
 

‎Coder.Desktop.sln

+18
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoderSdk", "CoderSdk\CoderS
1919
EndProject
2020
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "App\App.csproj", "{800C7E2D-0D86-4554-9903-B879DA6FA2CE}"
2121
EndProject
22+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vpn.DebugClient", "Vpn.DebugClient\Vpn.DebugClient.csproj", "{1BBFDF88-B25F-4C07-99C2-30DA384DB730}"
23+
EndProject
2224
Global
2325
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2426
Debug|Any CPU = Debug|Any CPU
@@ -167,6 +169,22 @@ Global
167169
{800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Release|x86.ActiveCfg = Release|x86
168170
{800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Release|x86.Build.0 = Release|x86
169171
{800C7E2D-0D86-4554-9903-B879DA6FA2CE}.Release|x86.Deploy.0 = Release|x86
172+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
173+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Debug|Any CPU.Build.0 = Debug|Any CPU
174+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Debug|ARM64.ActiveCfg = Debug|Any CPU
175+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Debug|ARM64.Build.0 = Debug|Any CPU
176+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Debug|x64.ActiveCfg = Debug|Any CPU
177+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Debug|x64.Build.0 = Debug|Any CPU
178+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Debug|x86.ActiveCfg = Debug|Any CPU
179+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Debug|x86.Build.0 = Debug|Any CPU
180+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Release|Any CPU.ActiveCfg = Release|Any CPU
181+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Release|Any CPU.Build.0 = Release|Any CPU
182+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Release|ARM64.ActiveCfg = Release|Any CPU
183+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Release|ARM64.Build.0 = Release|Any CPU
184+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Release|x64.ActiveCfg = Release|Any CPU
185+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Release|x64.Build.0 = Release|Any CPU
186+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Release|x86.ActiveCfg = Release|Any CPU
187+
{1BBFDF88-B25F-4C07-99C2-30DA384DB730}.Release|x86.Build.0 = Release|Any CPU
170188
EndGlobalSection
171189
GlobalSection(SolutionProperties) = preSolution
172190
HideSolutionNode = FALSE

‎Coder.Desktop.sln.DotSettings

+2-19
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
</HasMember>
3131
</And>
3232
</TypePattern.Match>
33-
33+
3434
<Entry DisplayName="Fields">
3535
<Entry.Match>
3636
<And>
@@ -144,10 +144,6 @@
144144
<Kind Is="Delegate" />
145145
</And>
146146
</Entry.Match>
147-
148-
<Entry.SortBy>
149-
<Name />
150-
</Entry.SortBy>
151147
</Entry>
152148

153149
<Entry DisplayName="Public Enums" Priority="100">
@@ -157,10 +153,6 @@
157153
<Kind Is="Enum" />
158154
</And>
159155
</Entry.Match>
160-
161-
<Entry.SortBy>
162-
<Name />
163-
</Entry.SortBy>
164156
</Entry>
165157

166158
<Entry DisplayName="Static Fields and Constants">
@@ -193,21 +185,12 @@
193185
</Not>
194186
</And>
195187
</Entry.Match>
196-
197-
<Entry.SortBy>
198-
<Readonly />
199-
<Name />
200-
</Entry.SortBy>
201188
</Entry>
202189

203190
<Entry DisplayName="Events">
204191
<Entry.Match>
205192
<Kind Is="Event" />
206193
</Entry.Match>
207-
208-
<Entry.SortBy>
209-
<Name />
210-
</Entry.SortBy>
211194
</Entry>
212195

213196
<Entry DisplayName="Constructors">
@@ -256,4 +239,4 @@
256239
<s:Boolean x:Key="/Default/UserDictionary/Words/=codervpn/@EntryIndexedValue">True</s:Boolean>
257240
<s:Boolean x:Key="/Default/UserDictionary/Words/=hkey/@EntryIndexedValue">True</s:Boolean>
258241
<s:Boolean x:Key="/Default/UserDictionary/Words/=replyable/@EntryIndexedValue">True</s:Boolean>
259-
<s:Boolean x:Key="/Default/UserDictionary/Words/=serdes/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
242+
<s:Boolean x:Key="/Default/UserDictionary/Words/=serdes/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

‎Tests.Vpn.Service/packages.lock.json

+45
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,48 @@
383383
"Microsoft.Extensions.Primitives": "5.0.1"
384384
}
385385
},
386+
"Serilog": {
387+
"type": "Transitive",
388+
"resolved": "4.2.0",
389+
"contentHash": "gmoWVOvKgbME8TYR+gwMf7osROiWAURterc6Rt2dQyX7wtjZYpqFiA/pY6ztjGQKKV62GGCyOcmtP1UKMHgSmA=="
390+
},
391+
"Serilog.Extensions.Hosting": {
392+
"type": "Transitive",
393+
"resolved": "9.0.0",
394+
"contentHash": "u2TRxuxbjvTAldQn7uaAwePkWxTHIqlgjelekBtilAGL5sYyF3+65NWctN4UrwwGLsDC7c3Vz3HnOlu+PcoxXg==",
395+
"dependencies": {
396+
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0",
397+
"Microsoft.Extensions.Hosting.Abstractions": "9.0.0",
398+
"Microsoft.Extensions.Logging.Abstractions": "9.0.0",
399+
"Serilog": "4.2.0",
400+
"Serilog.Extensions.Logging": "9.0.0"
401+
}
402+
},
403+
"Serilog.Extensions.Logging": {
404+
"type": "Transitive",
405+
"resolved": "9.0.0",
406+
"contentHash": "NwSSYqPJeKNzl5AuXVHpGbr6PkZJFlNa14CdIebVjK3k/76kYj/mz5kiTRNVSsSaxM8kAIa1kpy/qyT9E4npRQ==",
407+
"dependencies": {
408+
"Microsoft.Extensions.Logging": "9.0.0",
409+
"Serilog": "4.2.0"
410+
}
411+
},
412+
"Serilog.Sinks.Console": {
413+
"type": "Transitive",
414+
"resolved": "6.0.0",
415+
"contentHash": "fQGWqVMClCP2yEyTXPIinSr5c+CBGUvBybPxjAGcf7ctDhadFhrQw03Mv8rJ07/wR5PDfFjewf2LimvXCDzpbA==",
416+
"dependencies": {
417+
"Serilog": "4.0.0"
418+
}
419+
},
420+
"Serilog.Sinks.File": {
421+
"type": "Transitive",
422+
"resolved": "6.0.0",
423+
"contentHash": "lxjg89Y8gJMmFxVkbZ+qDgjl+T4yC5F7WSLTvA+5q0R04tfKVLRL/EHpYoJ/MEQd2EeCKDuylBIVnAYMotmh2A==",
424+
"dependencies": {
425+
"Serilog": "4.0.0"
426+
}
427+
},
386428
"System.Diagnostics.DiagnosticSource": {
387429
"type": "Transitive",
388430
"resolved": "9.0.1",
@@ -450,6 +492,9 @@
450492
"Microsoft.Extensions.Options.DataAnnotations": "[9.0.1, )",
451493
"Microsoft.Security.Extensions": "[1.3.0, )",
452494
"Semver": "[3.0.0, )",
495+
"Serilog.Extensions.Hosting": "[9.0.0, )",
496+
"Serilog.Sinks.Console": "[6.0.0, )",
497+
"Serilog.Sinks.File": "[6.0.0, )",
453498
"Vpn": "[1.0.0, )"
454499
}
455500
}

‎Vpn.DebugClient/Program.cs

+128
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+
}
+17
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

+30
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.3",
8+
"contentHash": "t7nZFFUFwigCwZ+nIXHDLweXvwIpsOXi+P7J7smPT/QjI3EKxnCzTQOhBqyEh6XEzc/pNH+bCFOOSjatrPt6Tw=="
9+
},
10+
"System.IO.Pipelines": {
11+
"type": "Transitive",
12+
"resolved": "9.0.1",
13+
"contentHash": "uXf5o8eV/gtzDQY4lGROLFMWQvcViKcF8o4Q6KpIOjloAQXrnscQSu6gTxYJMHuNJnh7szIF9AzkaEq+zDLoEg=="
14+
},
15+
"vpn": {
16+
"type": "Project",
17+
"dependencies": {
18+
"System.IO.Pipelines": "[9.0.1, )",
19+
"Vpn.Proto": "[1.0.0, )"
20+
}
21+
},
22+
"vpn.proto": {
23+
"type": "Project",
24+
"dependencies": {
25+
"Google.Protobuf": "[3.29.3, )"
26+
}
27+
}
28+
}
29+
}
30+
}

‎Vpn.Service/Create-Service.ps1

+35
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

+18
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+
}

0 commit comments

Comments
 (0)
Please sign in to comment.