confused screaming
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
namespace RemoteFrameBuffer.Client
|
||||
{
|
||||
public interface IRemoteFrameBufferClientStreamProvider
|
||||
{
|
||||
public Stream GetRemoteFrameBufferClientStream();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace RemoteFrameBuffer.Client
|
||||
{
|
||||
public interface IRemoteFramebufferClientProtocolFactory
|
||||
{
|
||||
public abstract RemoteFrameBufferClientProtocol Construct(Stream s);
|
||||
}
|
||||
}
|
||||
18
RemoteFrameBuffer/Client/RemoteFrameBufferClientProtocol.cs
Normal file
18
RemoteFrameBuffer/Client/RemoteFrameBufferClientProtocol.cs
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace RemoteFrameBuffer.Client
|
||||
{
|
||||
public class RemoteFrameBufferClientProtocolFactory<T> : IRemoteFramebufferClientProtocolFactory where T : RemoteFrameBufferClientProtocol
|
||||
{
|
||||
public RemoteFrameBufferClientProtocol Construct(Stream s)
|
||||
{
|
||||
return (RemoteFrameBufferClientProtocol)Activator.CreateInstance(typeof(T), s)!;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) { }
|
||||
}
|
||||
}
|
||||
110
RemoteFrameBuffer/Client/RemoteFramebufferClient.cs
Normal file
110
RemoteFrameBuffer/Client/RemoteFramebufferClient.cs
Normal file
@@ -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<RfbProtoVersion, IRemoteFramebufferClientProtocolFactory> _protocolHandlers;
|
||||
|
||||
private readonly IRemoteFrameBufferClientStreamProvider _socketProvider;
|
||||
private Task? backgroundWorker;
|
||||
private CancellationTokenSource cancellationTokenSource = new();
|
||||
|
||||
static RemoteFramebufferClient()
|
||||
{
|
||||
_protocolHandlers = new() {
|
||||
{ new RfbProtoVersion(3, 3), new RemoteFrameBufferClientProtocolFactory<RemoteFrameBufferClientProtocol_3_3>() },
|
||||
};
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user