diff --git a/PVHelpers/INetEndPoint.cs b/PVHelpers/INetEndPoint.cs
new file mode 100644
index 0000000..33556c8
--- /dev/null
+++ b/PVHelpers/INetEndPoint.cs
@@ -0,0 +1,11 @@
+using System.Net;
+
+namespace PVHelpers
+{
+ public interface INetEndPoint
+ {
+ public IPEndPoint EndPoint { get; }
+ public IPAddress Address { get; }
+ public Int32 Port { get; }
+ }
+}
diff --git a/PVHelpers/NetEndPointFromHostname.cs b/PVHelpers/NetEndPointFromHostname.cs
new file mode 100644
index 0000000..c91d741
--- /dev/null
+++ b/PVHelpers/NetEndPointFromHostname.cs
@@ -0,0 +1,20 @@
+using System.Net;
+
+namespace PVHelpers
+{
+ public class NetEndPointFromHostname(String hostname, Int32 port) : INetEndPoint
+ {
+ public String Hostname { get; } = hostname;
+ public IPEndPoint EndPoint => new(this.Address, this.Port);
+
+ public IPAddress Address
+ {
+ get
+ {
+ IPHostEntry entry = Dns.GetHostEntry(this.Hostname);
+ return entry.AddressList[0];
+ }
+ }
+ public Int32 Port { get; } = port;
+ }
+}
diff --git a/PVHelpers/NetEndPointFromIP.cs b/PVHelpers/NetEndPointFromIP.cs
new file mode 100644
index 0000000..fae087e
--- /dev/null
+++ b/PVHelpers/NetEndPointFromIP.cs
@@ -0,0 +1,18 @@
+using System.Net;
+
+namespace PVHelpers
+{
+ public class NetEndPointFromIP : INetEndPoint
+ {
+ public IPEndPoint EndPoint { get; }
+ public IPAddress Address => this.EndPoint.Address;
+ public Int32 Port => this.EndPoint.Port;
+
+ public NetEndPointFromIP(IPEndPoint endpoint)
+ {
+ this.EndPoint = endpoint;
+ }
+
+ public NetEndPointFromIP(IPAddress address, Int32 port) : this(new(address, port)) { }
+ }
+}
diff --git a/PVHelpers/PVHelpers.csproj b/PVHelpers/PVHelpers.csproj
new file mode 100644
index 0000000..b760144
--- /dev/null
+++ b/PVHelpers/PVHelpers.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net10.0
+ enable
+ enable
+
+
+
diff --git a/PVabel2026.slnx b/PVabel2026.slnx
index 55050b0..bb5fa7a 100644
--- a/PVabel2026.slnx
+++ b/PVabel2026.slnx
@@ -3,5 +3,7 @@
+
+
diff --git a/RemoteFrameBuffer/Client/IRemoteFrameBufferClientStreamProvider.cs b/RemoteFrameBuffer/Client/IRemoteFrameBufferClientStreamProvider.cs
new file mode 100644
index 0000000..a7c1d3a
--- /dev/null
+++ b/RemoteFrameBuffer/Client/IRemoteFrameBufferClientStreamProvider.cs
@@ -0,0 +1,7 @@
+namespace RemoteFrameBuffer.Client
+{
+ public interface IRemoteFrameBufferClientStreamProvider
+ {
+ public Stream GetRemoteFrameBufferClientStream();
+ }
+}
diff --git a/RemoteFrameBuffer/Client/IRemoteFramebufferClientProtocolFactory.cs b/RemoteFrameBuffer/Client/IRemoteFramebufferClientProtocolFactory.cs
new file mode 100644
index 0000000..c1aadde
--- /dev/null
+++ b/RemoteFrameBuffer/Client/IRemoteFramebufferClientProtocolFactory.cs
@@ -0,0 +1,7 @@
+namespace RemoteFrameBuffer.Client
+{
+ public interface IRemoteFramebufferClientProtocolFactory
+ {
+ public abstract RemoteFrameBufferClientProtocol Construct(Stream s);
+ }
+}
diff --git a/RemoteFrameBuffer/Client/RemoteFrameBufferClientProtocol.cs b/RemoteFrameBuffer/Client/RemoteFrameBufferClientProtocol.cs
new file mode 100644
index 0000000..d0f3b13
--- /dev/null
+++ b/RemoteFrameBuffer/Client/RemoteFrameBufferClientProtocol.cs
@@ -0,0 +1,18 @@
+using RemoteFrameBuffer.Common;
+
+namespace RemoteFrameBuffer.Client
+{
+ public abstract class RemoteFrameBufferClientProtocol
+ {
+ protected readonly Stream vncStream;
+ public abstract RfbProtoVersion Version { get; }
+
+ public RemoteFrameBufferClientProtocol(Stream s)
+ {
+ this.vncStream = s;
+ }
+
+ public abstract void Handshake();
+ public abstract void Initialization();
+ }
+}
diff --git a/RemoteFrameBuffer/Client/RemoteFrameBufferClientProtocolFactory.cs b/RemoteFrameBuffer/Client/RemoteFrameBufferClientProtocolFactory.cs
new file mode 100644
index 0000000..a120ba0
--- /dev/null
+++ b/RemoteFrameBuffer/Client/RemoteFrameBufferClientProtocolFactory.cs
@@ -0,0 +1,10 @@
+namespace RemoteFrameBuffer.Client
+{
+ public class RemoteFrameBufferClientProtocolFactory : IRemoteFramebufferClientProtocolFactory where T : RemoteFrameBufferClientProtocol
+ {
+ public RemoteFrameBufferClientProtocol Construct(Stream s)
+ {
+ return (RemoteFrameBufferClientProtocol)Activator.CreateInstance(typeof(T), s)!;
+ }
+ }
+}
diff --git a/RemoteFrameBuffer/Client/RemoteFrameBufferClientProtocol_3_3.cs b/RemoteFrameBuffer/Client/RemoteFrameBufferClientProtocol_3_3.cs
new file mode 100644
index 0000000..eba03ce
--- /dev/null
+++ b/RemoteFrameBuffer/Client/RemoteFrameBufferClientProtocol_3_3.cs
@@ -0,0 +1,22 @@
+using RemoteFrameBuffer.Common;
+
+namespace RemoteFrameBuffer.Client
+{
+ public class RemoteFrameBufferClientProtocol_3_3 : RemoteFrameBufferClientProtocol
+ {
+ public override RfbProtoVersion Version => new(3, 3);
+
+ public RemoteFrameBufferClientProtocol_3_3(Stream s) : base(s)
+ {
+ }
+
+ public override void Handshake()
+ {
+ }
+
+ public override void Initialization()
+ {
+
+ }
+ }
+}
diff --git a/RemoteFrameBuffer/Client/RemoteFrameBufferTcpClientStreamProvider.cs b/RemoteFrameBuffer/Client/RemoteFrameBufferTcpClientStreamProvider.cs
new file mode 100644
index 0000000..5914b7b
--- /dev/null
+++ b/RemoteFrameBuffer/Client/RemoteFrameBufferTcpClientStreamProvider.cs
@@ -0,0 +1,29 @@
+using PVHelpers;
+using System.Net;
+using System.Net.Sockets;
+
+namespace RemoteFrameBuffer.Client
+{
+ public class RemoteFrameBufferTcpClientStreamProvider : IRemoteFrameBufferClientStreamProvider
+ {
+ private readonly INetEndPoint remoteEndPoint;
+ private readonly IPEndPoint localEndPoint;
+
+ public RemoteFrameBufferTcpClientStreamProvider(INetEndPoint remoteEndPoint, IPEndPoint? localEndPoint)
+ {
+ this.remoteEndPoint = remoteEndPoint;
+ this.localEndPoint = localEndPoint ?? new(IPAddress.Any, 0);
+ }
+
+ public Stream GetRemoteFrameBufferClientStream()
+ {
+ TcpClient tcpClient = new TcpClient(this.localEndPoint);
+ tcpClient.Connect(this.remoteEndPoint.EndPoint);
+ return tcpClient.GetStream();
+ }
+
+ public RemoteFrameBufferTcpClientStreamProvider(String hostname, Int16 port, IPEndPoint? localEndPoint = null) : this(new NetEndPointFromHostname(hostname, port), localEndPoint) { }
+ public RemoteFrameBufferTcpClientStreamProvider(IPAddress address, Int32 port, IPEndPoint? localEndPoint = null) : this(new NetEndPointFromIP(address, port), localEndPoint) { }
+ public RemoteFrameBufferTcpClientStreamProvider(IPEndPoint remoteEndPoint, IPEndPoint? localEndPoint = null) : this(new NetEndPointFromIP(remoteEndPoint), localEndPoint) { }
+ }
+}
diff --git a/RemoteFrameBuffer/Client/RemoteFramebufferClient.cs b/RemoteFrameBuffer/Client/RemoteFramebufferClient.cs
new file mode 100644
index 0000000..0e108e9
--- /dev/null
+++ b/RemoteFrameBuffer/Client/RemoteFramebufferClient.cs
@@ -0,0 +1,110 @@
+using RemoteFrameBuffer.Client;
+using RemoteFrameBuffer.Common;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace RemoteFrameBuffer
+{
+ public partial class RemoteFramebufferClient
+ {
+ private static Dictionary _protocolHandlers;
+
+ private readonly IRemoteFrameBufferClientStreamProvider _socketProvider;
+ private Task? backgroundWorker;
+ private CancellationTokenSource cancellationTokenSource = new();
+
+ static RemoteFramebufferClient()
+ {
+ _protocolHandlers = new() {
+ { new RfbProtoVersion(3, 3), new RemoteFrameBufferClientProtocolFactory() },
+ };
+ }
+
+ public RemoteFramebufferClient(IRemoteFrameBufferClientStreamProvider socketProvider)
+ {
+ this._socketProvider = socketProvider;
+ }
+
+ public void Start()
+ {
+ if (this.backgroundWorker == null)
+ {
+ Console.Error.WriteLine("VNC client starting");
+ this.backgroundWorker = new Task(this.Worker, this.cancellationTokenSource.Token);
+ this.backgroundWorker.ContinueWith(this.WorkerStopped);
+ this.backgroundWorker.Start();
+ }
+ }
+
+ public void Stop()
+ {
+ if (this.backgroundWorker != null)
+ {
+ this.cancellationTokenSource.Cancel();
+ this.backgroundWorker.Wait();
+ }
+ }
+
+ private void Worker()
+ {
+ Int32 failcount = 0;
+ while (!this.cancellationTokenSource.Token.IsCancellationRequested)
+ {
+ Console.Error.WriteLine("Attempting to connect");
+ Stream s = this._socketProvider.GetRemoteFrameBufferClientStream();
+ using (s)
+ {
+ Byte[] buf = new Byte[12];
+ CancellationTokenSource readTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
+ CancellationTokenSource readTokenSource = CancellationTokenSource.CreateLinkedTokenSource(this.cancellationTokenSource.Token, readTimeout.Token);
+ try
+ {
+ s.ReadExactlyAsync(buf, 0, buf.Length, readTokenSource.Token).AsTask().Wait();
+ } catch (AggregateException e)// TODO: go through InnerExceptions and only throw if we are left with unhandled ones
+ {
+ if (e.InnerException is TaskCanceledException)
+ {
+ if (failcount++ >= 5)
+ {
+ break;
+ }
+ Task.Delay(1000).Wait();
+ continue;
+ } else
+ {
+ throw new Exception("Something broke. Yeah, I know, very useful message.", e);
+ }
+ }
+ failcount = 0;
+ String protover = Encoding.ASCII.GetString(buf);
+ Console.Error.Write($"Server protocol: {protover}");
+ Match m = _rfbVersionRegex().Match(protover);
+ if (!m.Success)
+ {
+ throw new Exception("Cannot parse protocol version");
+ }
+ RfbProtoVersion serverVersion = new(Int16.Parse(m.Groups["major"].Value), Int16.Parse(m.Groups["minor"].Value));
+ RfbProtoVersion maxProto = _protocolHandlers.Keys.Where((ph) => ph <= serverVersion).Max();
+ RemoteFrameBufferClientProtocol proto = _protocolHandlers[maxProto].Construct(s);
+ Console.Error.WriteLine($"Using client protocol {proto.Version.Major}.{proto.Version.Minor}");
+ proto.Handshake();
+ proto.Initialization();
+ }
+
+ }
+ }
+
+ private void WorkerStopped(Task t)
+ {
+ Console.Error.WriteLine("VNC client exited");
+ this.backgroundWorker = null;
+ if (!this.cancellationTokenSource.TryReset())
+ {
+ this.cancellationTokenSource = new();
+ }
+ }
+
+ [GeneratedRegex(@"^RFB (?'major'\d{3}).(?'minor'\d{3})$")]
+ private static partial Regex _rfbVersionRegex();
+ }
+}
diff --git a/RemoteFrameBuffer/Common/RfbProtoVersion.cs b/RemoteFrameBuffer/Common/RfbProtoVersion.cs
new file mode 100644
index 0000000..92f6585
--- /dev/null
+++ b/RemoteFrameBuffer/Common/RfbProtoVersion.cs
@@ -0,0 +1,40 @@
+namespace RemoteFrameBuffer.Common
+{
+ public struct RfbProtoVersion(Int16 major, Int16 minor)
+ {
+ public Int16 Major = major;
+ public Int16 Minor = minor;
+
+
+ public static Boolean operator ==(RfbProtoVersion a, RfbProtoVersion b)
+ {
+ return (a.Major == b.Major) && (a.Minor == b.Minor);
+ }
+ public static Boolean operator !=(RfbProtoVersion a, RfbProtoVersion b)
+ {
+ return !(a == b);
+ }
+ public static Boolean operator <(RfbProtoVersion a, RfbProtoVersion b)
+ {
+ if (a.Major == b.Major)
+ {
+ return a.Minor < b.Minor;
+ } else
+ {
+ return a.Major < b.Major;
+ }
+ }
+ public static Boolean operator >(RfbProtoVersion a, RfbProtoVersion b)
+ {
+ return b < a;
+ }
+ public static Boolean operator <=(RfbProtoVersion a, RfbProtoVersion b)
+ {
+ return b < a;
+ }
+ public static Boolean operator >=(RfbProtoVersion a, RfbProtoVersion b)
+ {
+ return a < b;
+ }
+ }
+}
diff --git a/RemoteFrameBuffer/RemoteFrameBuffer.csproj b/RemoteFrameBuffer/RemoteFrameBuffer.csproj
new file mode 100644
index 0000000..0bb265e
--- /dev/null
+++ b/RemoteFrameBuffer/RemoteFrameBuffer.csproj
@@ -0,0 +1,13 @@
+
+
+
+ net10.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/YetAnotherDummy/Program.cs b/YetAnotherDummy/Program.cs
index 002baad..5ed75f1 100644
--- a/YetAnotherDummy/Program.cs
+++ b/YetAnotherDummy/Program.cs
@@ -1,247 +1,13 @@
// See https://aka.ms/new-console-template for more information
+using RemoteFrameBuffer;
+using RemoteFrameBuffer.Client;
using System.Net;
-using System.Net.Sockets;
-using System.Numerics;
-using System.Text;
-using System.Text.RegularExpressions;
-using static RemoteFrameBufferClientProtocol;
IPAddress tessia = new([192,168,16,253]);
-IRemoteFrameBufferClientStreamProvider tessia6001vnc = new IRemoteFrameBufferClientStreamProvider.RemoteFrameBufferTcpClientStreamProvider(tessia, 5901);
+IRemoteFrameBufferClientStreamProvider tessia6001vnc = new RemoteFrameBufferTcpClientStreamProvider(tessia, 5901);
RemoteFramebufferClient client = new(tessia6001vnc);
client.Start();
Console.ReadLine();
client.Stop();
-
-public interface INetEndPoint
-{
- public IPEndPoint EndPoint { get; }
- public IPAddress Address { get; }
- public Int32 Port { get; }
-
- public class NetEndPointFromIP : INetEndPoint
- {
- public IPEndPoint EndPoint { get; }
- public IPAddress Address => this.EndPoint.Address;
- public Int32 Port => this.EndPoint.Port;
-
- public NetEndPointFromIP(IPEndPoint endpoint)
- {
- this.EndPoint = endpoint;
- }
-
- public NetEndPointFromIP(IPAddress address, Int32 port) : this(new(address, port)) { }
- }
-
- public class NetEndPointFromHostname(String hostname, Int32 port) : INetEndPoint
- {
- public String Hostname { get; } = hostname;
- public IPEndPoint EndPoint => new(this.Address, this.Port);
-
- public IPAddress Address {
- get
- {
- IPHostEntry entry = Dns.GetHostEntry(this.Hostname);
- return entry.AddressList[0];
- }
- }
- public Int32 Port { get; } = port;
- }
-}
-
-public interface IRemoteFrameBufferClientStreamProvider
-{
- public Stream GetRemoteFrameBufferClientStream();
-
- public class RemoteFrameBufferTcpClientStreamProvider : IRemoteFrameBufferClientStreamProvider
- {
- private readonly INetEndPoint remoteEndPoint;
- private readonly IPEndPoint localEndPoint;
-
- public RemoteFrameBufferTcpClientStreamProvider(INetEndPoint remoteEndPoint, IPEndPoint? localEndPoint)
- {
- this.remoteEndPoint = remoteEndPoint;
- this.localEndPoint = localEndPoint ?? new(IPAddress.Any, 0);
- }
-
- public Stream GetRemoteFrameBufferClientStream()
- {
- TcpClient tcpClient = new TcpClient(this.localEndPoint);
- tcpClient.Connect(this.remoteEndPoint.EndPoint);
- return tcpClient.GetStream();
- }
-
- public RemoteFrameBufferTcpClientStreamProvider(String hostname, Int16 port, IPEndPoint? localEndPoint = null) : this(new INetEndPoint.NetEndPointFromHostname(hostname, port), localEndPoint) { }
- public RemoteFrameBufferTcpClientStreamProvider(IPAddress address, Int32 port, IPEndPoint? localEndPoint = null) : this(new INetEndPoint.NetEndPointFromIP(address, port), localEndPoint) { }
- public RemoteFrameBufferTcpClientStreamProvider(IPEndPoint remoteEndPoint, IPEndPoint? localEndPoint = null) : this(new INetEndPoint.NetEndPointFromIP(remoteEndPoint), localEndPoint) { }
- }
-}
-
-public partial class RemoteFramebufferClient
-{
- private static Dictionary _protocolHandlers;
-
- private readonly IRemoteFrameBufferClientStreamProvider _socketProvider;
- private Task? backgroundWorker;
- private CancellationTokenSource cancellationTokenSource = new();
-
- static RemoteFramebufferClient() {
- _protocolHandlers = new() {
- { new RfbProtoVersion(3, 3), new RemoteFrameBufferClientProtocolFactory() },
- };
- }
-
- public RemoteFramebufferClient(IRemoteFrameBufferClientStreamProvider socketProvider)
- {
- this._socketProvider = socketProvider;
- }
-
- public void Start()
- {
- if (this.backgroundWorker == null)
- {
- Console.Error.WriteLine("VNC client starting");
- this.backgroundWorker = new Task(this.Worker, this.cancellationTokenSource.Token);
- this.backgroundWorker.ContinueWith(this.WorkerStopped);
- this.backgroundWorker.Start();
- }
- }
-
- public void Stop()
- {
- if (this.backgroundWorker != null)
- {
- this.cancellationTokenSource.Cancel();
- this.backgroundWorker.Wait();
- }
- }
-
- private void Worker()
- {
- Int32 failcount = 0;
- while (!this.cancellationTokenSource.Token.IsCancellationRequested)
- {
- Console.Error.WriteLine("Attempting to connect");
- Stream s = this._socketProvider.GetRemoteFrameBufferClientStream();
- using (s)
- {
- Byte[] buf = new Byte[12];
- CancellationTokenSource readTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
- CancellationTokenSource readTokenSource = CancellationTokenSource.CreateLinkedTokenSource(this.cancellationTokenSource.Token, readTimeout.Token);
- try
- {
- s.ReadExactlyAsync(buf, 0, buf.Length, readTokenSource.Token).AsTask().Wait();
- }catch (AggregateException e)// TODO: go through InnerExceptions and only throw if we are left with unhandled ones
- {
- if (e.InnerException is TaskCanceledException)
- {
- if (failcount++ >= 5)
- {
- break;
- }
- Task.Delay(1000).Wait();
- continue;
- }else
- {
- throw new Exception("Something broke. Yeah, I know, very useful message.", e);
- }
- }
- failcount = 0;
- String protover = Encoding.ASCII.GetString(buf);
- Console.Error.Write($"Server protocol: {protover}");
- Match m = _rfbVersionRegex().Match(protover);
- if (!m.Success)
- {
- throw new Exception("Cannot parse protocol version");
- }
- RfbProtoVersion serverVersion = new(Int16.Parse(m.Groups["major"].Value), Int16.Parse(m.Groups["minor"].Value));
- RfbProtoVersion maxProto = _protocolHandlers.Keys.Where((ph) => ph <= serverVersion).Max();
- RemoteFrameBufferClientProtocol proto = _protocolHandlers[maxProto].Construct(s);
- Console.Error.WriteLine($"Using client protocol {proto.Version.Major}.{proto.Version.Minor}");
- }
-
- }
- }
-
- private void WorkerStopped(Task t)
- {
- Console.Error.WriteLine("VNC client exited");
- this.backgroundWorker = null;
- if (!this.cancellationTokenSource.TryReset())
- {
- this.cancellationTokenSource = new();
- }
- }
-
- [GeneratedRegex(@"^RFB (?'major'\d{3}).(?'minor'\d{3})$")]
- private static partial Regex _rfbVersionRegex();
-}
-public struct RfbProtoVersion(Int16 major, Int16 minor)
-{
- public Int16 Major = major;
- public Int16 Minor = minor;
-
-
- public static Boolean operator ==(RfbProtoVersion a, RfbProtoVersion b)
- {
- return (a.Major == b.Major) && (a.Minor == b.Minor);
- }
- public static Boolean operator !=(RfbProtoVersion a, RfbProtoVersion b)
- {
- return !(a == b);
- }
- public static Boolean operator <(RfbProtoVersion a, RfbProtoVersion b)
- {
- if (a.Major == b.Major)
- {
- return a.Minor < b.Minor;
- } else
- {
- return a.Major < b.Major;
- }
- }
- public static Boolean operator >(RfbProtoVersion a, RfbProtoVersion b)
- {
- return b < a;
- }
- public static Boolean operator <=(RfbProtoVersion a, RfbProtoVersion b)
- {
- return b < a;
- }
- public static Boolean operator >=(RfbProtoVersion a, RfbProtoVersion b)
- {
- return a < b;
- }
-}
-public abstract class RemoteFrameBufferClientProtocol
-{
- protected readonly Stream vncStream;
- public abstract RfbProtoVersion Version { get; }
-
- public RemoteFrameBufferClientProtocol(Stream s)
- {
- this.vncStream = s;
- }
-
- public interface IRemoteFramebufferClientProtocolFactory {
- public abstract RemoteFrameBufferClientProtocol Construct(Stream s);
- }
- public class RemoteFrameBufferClientProtocolFactory : IRemoteFramebufferClientProtocolFactory where T : RemoteFrameBufferClientProtocol
- {
- public RemoteFrameBufferClientProtocol Construct(Stream s)
- {
- return (RemoteFrameBufferClientProtocol)Activator.CreateInstance(typeof(T), s)!;
- }
- }
-
- public class RemoteFrameBufferClientProtocol_3_3 : RemoteFrameBufferClientProtocol
- {
- public override RfbProtoVersion Version => new(3,3);
-
- public RemoteFrameBufferClientProtocol_3_3(Stream s) : base(s)
- {
- }
- }
-}
\ No newline at end of file
diff --git a/YetAnotherDummy/YetAnotherDummy.csproj b/YetAnotherDummy/YetAnotherDummy.csproj
index ed9781c..5dd89bf 100644
--- a/YetAnotherDummy/YetAnotherDummy.csproj
+++ b/YetAnotherDummy/YetAnotherDummy.csproj
@@ -7,4 +7,8 @@
enable
+
+
+
+