mirror of
https://github.com/ZuneDev/MicrosoftIris.git
synced 2026-07-27 13:13:29 -07:00
Implement new System.Net.Sockets debugger
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Iris.Debug.Data;
|
||||
|
||||
public class DebuggerMessageFrame
|
||||
{
|
||||
public DebuggerMessageFrame() { }
|
||||
|
||||
public DebuggerMessageFrame(long transactionId, DebuggerMessageType type, byte[] data)
|
||||
{
|
||||
TransactionId = transactionId;
|
||||
Type = type;
|
||||
Data = data;
|
||||
}
|
||||
|
||||
public DebuggerMessageFrame(long transactionId, DebuggerMessageType type, string message, Encoding encoding = null)
|
||||
: this(transactionId, type, (encoding ?? Encoding.UTF8).GetBytes(message))
|
||||
{
|
||||
}
|
||||
|
||||
public DebuggerMessageFrame(byte[] bytes)
|
||||
{
|
||||
TransactionId = BitConverter.ToInt64(bytes, 0);
|
||||
Type = (DebuggerMessageType)BitConverter.ToInt32(bytes, sizeof(long));
|
||||
Data = bytes.AsSpan(sizeof(long) + sizeof(DebuggerMessageType)).ToArray();
|
||||
}
|
||||
|
||||
public long TransactionId { get; set; }
|
||||
|
||||
public DebuggerMessageType Type { get; set; }
|
||||
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public byte[] ToBytes()
|
||||
{
|
||||
byte[] bytes = new byte[Data.Length + sizeof(DebuggerMessageType) + sizeof(long)];
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
var span = bytes.AsSpan();
|
||||
BitConverter.TryWriteBytes(span, TransactionId);
|
||||
BitConverter.TryWriteBytes(span[sizeof(long)..], (int)Type);
|
||||
#else
|
||||
var idBytes = BitConverter.GetBytes(TransactionId);
|
||||
idBytes.CopyTo(bytes, 0);
|
||||
|
||||
var typeBytes = BitConverter.GetBytes((int)Type);
|
||||
typeBytes.CopyTo(bytes, sizeof(long));
|
||||
#endif
|
||||
|
||||
Data.CopyTo(bytes, sizeof(long) + sizeof(DebuggerMessageType));
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public string GetDataAsString(Encoding encoding = null) => (encoding ?? Encoding.UTF8).GetString(Data);
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
using System.Runtime.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Microsoft.Iris.Debug;
|
||||
|
||||
@@ -7,9 +11,34 @@ namespace Microsoft.Iris.Debug;
|
||||
/// </summary>
|
||||
public static class DebugRemoting
|
||||
{
|
||||
public const string DEFAULT_TCP_CLIENT_URI = ">tcp://127.0.0.1:5555,@tcp://127.0.0.1:55556";
|
||||
public const string DEFAULT_TCP_CLIENT_URI = ">tcp://127.0.0.1:5555,@tcp://127.0.0.1:5556";
|
||||
public const string DEFAULT_TCP_SERVER_URI = "@tcp://127.0.0.1:5555,>tcp://127.0.0.1:5556";
|
||||
|
||||
public const string DEFAULT_TCP_SERVER_URI = "@tcp://127.0.0.1:5555,>tcp://127.0.0.1:55556";
|
||||
public static readonly Uri DEFAULT_TCP_URI = new("tcp://127.0.0.1:5555");
|
||||
|
||||
internal static IFormatter CreateBsonFormatter() => new BsonFormatter(new StreamingContext(StreamingContextStates.Remoting));
|
||||
|
||||
internal static Data.DebuggerMessageFrame ReceiveDebuggerMessage(Socket socket)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] sizeBuffer = new byte[sizeof(int)];
|
||||
int bytesReceived = socket.Receive(sizeBuffer);
|
||||
|
||||
// Reached end of stream, no bytes to recieve
|
||||
if (bytesReceived == 0)
|
||||
return null;
|
||||
|
||||
int frameLength = BitConverter.ToInt32(sizeBuffer, 0);
|
||||
|
||||
byte[] frameBytes = new byte[frameLength];
|
||||
socket.Receive(frameBytes, frameLength, SocketFlags.None);
|
||||
|
||||
return new(frameBytes);
|
||||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ public interface IDebuggerClient
|
||||
/// <summary>
|
||||
/// The URI the client is connected to.
|
||||
/// </summary>
|
||||
string ConnectionUri { get; }
|
||||
Uri ConnectionUri { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when the UIX interpreter steps forward.
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Microsoft.Iris.Debug;
|
||||
using Microsoft.Iris.Debug.Data;
|
||||
using NetMQ;
|
||||
using NetMQ.Sockets;
|
||||
@@ -16,14 +15,14 @@ public class ZmqDebuggerClient : IDebuggerClient, IDisposable
|
||||
private readonly PairSocket _socket;
|
||||
private readonly IFormatter _formatter;
|
||||
|
||||
public string ConnectionUri { get; }
|
||||
public Uri ConnectionUri { get; }
|
||||
|
||||
public event EventHandler<InterpreterEntry> InterpreterStep;
|
||||
public event Action<string> DispatcherStep;
|
||||
|
||||
public ZmqDebuggerClient(string connectionUri)
|
||||
{
|
||||
ConnectionUri = connectionUri ?? DebugRemoting.DEFAULT_TCP_CLIENT_URI;
|
||||
ConnectionUri = new(connectionUri ?? DebugRemoting.DEFAULT_TCP_CLIENT_URI);
|
||||
|
||||
_socket = new(connectionUri);
|
||||
_formatter = DebugRemoting.CreateBsonFormatter();
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
using Microsoft.Iris.Debug.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Iris.Debug.SystemNet;
|
||||
|
||||
public class NetDebuggerClient : IDebuggerClient, IDisposable
|
||||
{
|
||||
public Uri ConnectionUri { get; }
|
||||
|
||||
private readonly Socket _socket;
|
||||
private readonly Queue<byte[]> _queue;
|
||||
private readonly IFormatter _formatter;
|
||||
|
||||
public event EventHandler<InterpreterEntry> InterpreterStep;
|
||||
public event Action<string> DispatcherStep;
|
||||
|
||||
public NetDebuggerClient(string connectionUri) : this(new Uri(connectionUri))
|
||||
{
|
||||
}
|
||||
|
||||
public NetDebuggerClient(Uri connectionUri)
|
||||
{
|
||||
ConnectionUri = connectionUri ?? DebugRemoting.DEFAULT_TCP_URI;
|
||||
_socket = new(SocketType.Stream, ProtocolType.Tcp);
|
||||
_formatter = DebugRemoting.CreateBsonFormatter();
|
||||
|
||||
System.Threading.Thread connectThread = new(ConnectLoop);
|
||||
connectThread.Start();
|
||||
}
|
||||
|
||||
public void Dispose() => _socket.Dispose();
|
||||
|
||||
private void QueueDebuggerMessage(DebuggerMessageFrame frame)
|
||||
{
|
||||
_queue.Enqueue(frame.ToBytes());
|
||||
}
|
||||
|
||||
private void MessageRecieveLoop()
|
||||
{
|
||||
while (_socket.Connected)
|
||||
{
|
||||
DebuggerMessageFrame frame;
|
||||
while ((frame = DebugRemoting.ReceiveDebuggerMessage(_socket)) == null)
|
||||
if (!_socket.Connected) return;
|
||||
|
||||
switch (frame.Type)
|
||||
{
|
||||
case DebuggerMessageType.InterpreterOpCode:
|
||||
{
|
||||
using MemoryStream stream = new(frame.Data);
|
||||
var entry = (InterpreterEntry)_formatter.Deserialize(stream);
|
||||
InterpreterStep?.Invoke(this, entry);
|
||||
}
|
||||
break;
|
||||
|
||||
case DebuggerMessageType.DispatcherStep:
|
||||
string message = frame.GetDataAsString();
|
||||
DispatcherStep?.Invoke(message);
|
||||
break;
|
||||
|
||||
default:
|
||||
Trace.WriteLine(TraceCategory.MarkupDebug, "Recieved unknown debugger message of type '{0}'.", frame.Type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ConnectLoop()
|
||||
{
|
||||
while (!_socket.Connected)
|
||||
{
|
||||
try
|
||||
{
|
||||
var endpoint = new IPEndPoint(IPAddress.Parse(ConnectionUri.Host), ConnectionUri.Port);
|
||||
_socket.Connect(endpoint);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
System.Threading.Thread receiveThread = new(MessageRecieveLoop);
|
||||
receiveThread.Start();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
using Microsoft.Iris.Debug.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Iris.Debug.SystemNet;
|
||||
|
||||
internal class NetDebuggerServer : IDebuggerServer, IDisposable
|
||||
{
|
||||
public static IDebuggerServer Current { get; private set; }
|
||||
|
||||
public Uri ConnectionUri { get; }
|
||||
|
||||
private readonly Queue<byte[]> _outQueue = new();
|
||||
private readonly TcpListener _listener;
|
||||
private readonly IFormatter _formatter;
|
||||
private Socket _socket;
|
||||
|
||||
public NetDebuggerServer(string connectionUri) : this(new Uri(connectionUri))
|
||||
{
|
||||
}
|
||||
|
||||
public NetDebuggerServer(Uri connectionUri)
|
||||
{
|
||||
ConnectionUri = connectionUri ?? DebugRemoting.DEFAULT_TCP_URI;
|
||||
|
||||
_listener = TcpListener.Create(connectionUri.Port);
|
||||
_listener.Start();
|
||||
|
||||
_formatter = DebugRemoting.CreateBsonFormatter();
|
||||
|
||||
System.Threading.Thread connectThread = new(ConnectLoop);
|
||||
connectThread.Start();
|
||||
|
||||
Current = this;
|
||||
}
|
||||
|
||||
public void LogInterpreterOpCode(object context, InterpreterEntry entry)
|
||||
{
|
||||
using MemoryStream entryStream = new();
|
||||
_formatter.Serialize(entryStream, entry);
|
||||
|
||||
QueueDebuggerMessage(new(0, DebuggerMessageType.InterpreterOpCode, entryStream.ToArray()));
|
||||
}
|
||||
|
||||
public void LogDispatcher(string message)
|
||||
{
|
||||
QueueDebuggerMessage(new(0, DebuggerMessageType.DispatcherStep, message));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_listener.Stop();
|
||||
_socket?.Dispose();
|
||||
}
|
||||
|
||||
private void QueueDebuggerMessage(DebuggerMessageFrame frame)
|
||||
{
|
||||
_outQueue.Enqueue(frame.ToBytes());
|
||||
}
|
||||
|
||||
private void MessageRecieveLoop()
|
||||
{
|
||||
while (_socket.Connected)
|
||||
{
|
||||
DebuggerMessageFrame frame;
|
||||
while ((frame = DebugRemoting.ReceiveDebuggerMessage(_socket)) == null)
|
||||
;
|
||||
|
||||
switch (frame.Type)
|
||||
{
|
||||
default:
|
||||
Trace.WriteLine(TraceCategory.MarkupDebug, "Recieved unknown debugger message of type '{0}'.", frame.Type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MessageSendLoop()
|
||||
{
|
||||
while (_socket.Connected)
|
||||
{
|
||||
while (_outQueue.Count == 0) ;
|
||||
|
||||
var frameBytes = _outQueue.Dequeue();
|
||||
_socket.Send(BitConverter.GetBytes(frameBytes.Length));
|
||||
_socket.Send(frameBytes);
|
||||
}
|
||||
}
|
||||
|
||||
private void ConnectLoop()
|
||||
{
|
||||
while (!_listener.Pending()) ;
|
||||
|
||||
_socket = _listener.AcceptSocket();
|
||||
|
||||
System.Threading.Thread receiveThread = new(MessageRecieveLoop);
|
||||
System.Threading.Thread sendThread = new(MessageSendLoop);
|
||||
receiveThread.Start();
|
||||
sendThread.Start();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user