mirror of
https://github.com/pleonex/NitroDebugger.git
synced 2025-06-19 13:45:33 -04:00
Implemented session layer as raw TCP client.
* NitroDebugger/GdbClient.cs: * NitroDebugger/RSP/Presentation.cs: * NitroDebugger/NitroDebugger.csproj: Refactoring to Presentation layer * NitroDebugger.UnitTests/SessionTests.cs: Created test for Session layer (TCP socket) * NitroDebugger/RSP/Session.cs: Implemented session layer as raw TCP client.
This commit is contained in:
parent
0ca8a61353
commit
49705ea722
@ -21,6 +21,7 @@
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using NitroDebugger.RSP;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using System.Runtime.Serialization.Formatters;
|
||||
@ -31,6 +32,8 @@ namespace UnitTests
|
||||
public class SessionTests
|
||||
{
|
||||
private const int DefaultPort = 10101;
|
||||
private const int BadPort = 10102;
|
||||
|
||||
private TcpListener server;
|
||||
|
||||
[TestFixtureSetUp]
|
||||
@ -59,11 +62,119 @@ namespace UnitTests
|
||||
Assert.DoesNotThrow(() => new Session("localhost", DefaultPort));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectBadPort()
|
||||
{
|
||||
Assert.Throws<SocketException>(() => new Session("localhost", BadPort));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConnectCloseLocalhostDefaultPort()
|
||||
{
|
||||
Assert.DoesNotThrow(() => new Session("localhost", DefaultPort).Close());
|
||||
}
|
||||
|
||||
private void AcceptAndSendBytes(byte[] data)
|
||||
{
|
||||
TcpClient client = server.AcceptTcpClient();
|
||||
client.GetStream().Write(data, 0, data.Length);
|
||||
client.Close();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanSendByte()
|
||||
{
|
||||
byte expected = 0xCA;
|
||||
Session session = new Session("localhost", DefaultPort);
|
||||
session.Write(expected);
|
||||
|
||||
TcpClient client = server.AcceptTcpClient();
|
||||
int actual = client.GetStream().ReadByte();
|
||||
|
||||
Assert.AreEqual(expected, actual);
|
||||
|
||||
client.Close();
|
||||
session.Close();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanSendBytes()
|
||||
{
|
||||
byte[] expected = new byte[] { 0xCA, 0xFE };
|
||||
Session session = new Session("localhost", DefaultPort);
|
||||
session.Write(expected);
|
||||
|
||||
TcpClient client = server.AcceptTcpClient();
|
||||
byte[] actual = new byte[2];
|
||||
client.GetStream().Read(actual, 0, 2);
|
||||
|
||||
Assert.AreEqual(expected, actual);
|
||||
|
||||
client.Close();
|
||||
session.Close();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanReceiveByte()
|
||||
{
|
||||
byte expected = 0xCA;
|
||||
|
||||
Session session = new Session("localhost", DefaultPort);
|
||||
AcceptAndSendBytes(new byte[] { expected });
|
||||
|
||||
byte actual = session.ReadByte();
|
||||
session.Close();
|
||||
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReceiveEndOfStream()
|
||||
{
|
||||
Session session = new Session("localhost", DefaultPort);
|
||||
|
||||
TcpClient client = server.AcceptTcpClient();
|
||||
client.Close();
|
||||
|
||||
Assert.Throws<EndOfStreamException>(() => session.ReadByte());
|
||||
|
||||
session.Close();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanReceiveBytes()
|
||||
{
|
||||
byte[] expected = new byte[] { 0xCA, 0xFE };
|
||||
|
||||
Session session = new Session("localhost", DefaultPort);
|
||||
AcceptAndSendBytes(expected);
|
||||
|
||||
byte[] actual = session.ReadBytes();
|
||||
session.Close();
|
||||
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasDataAvailable()
|
||||
{
|
||||
Session session = new Session("localhost", DefaultPort);
|
||||
AcceptAndSendBytes(new byte[] { 0xCA, 0xFE });
|
||||
session.ReadByte();
|
||||
|
||||
Assert.IsTrue(session.DataAvailable);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasNoDataAvailable()
|
||||
{
|
||||
Session session = new Session("localhost", DefaultPort);
|
||||
AcceptAndSendBytes(new byte[] { 0xCA, 0xFE });
|
||||
session.ReadByte();
|
||||
session.ReadByte();
|
||||
|
||||
Assert.IsFalse(session.DataAvailable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,46 +28,46 @@ namespace NitroDebugger.RSP
|
||||
/// </summary>
|
||||
public class GdbClient
|
||||
{
|
||||
private Session session;
|
||||
private Presentation presentation;
|
||||
|
||||
public GdbClient(string hostname, int port)
|
||||
{
|
||||
this.session = new Session(hostname, port);
|
||||
this.presentation = new Presentation(hostname, port);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
this.session.Close();
|
||||
this.presentation.Close();
|
||||
}
|
||||
|
||||
public StopType GetHaltedReason()
|
||||
{
|
||||
session.Write("?");
|
||||
string response = session.Read();
|
||||
presentation.Write("?");
|
||||
string response = presentation.Read();
|
||||
return this.ParseStopResponse(response);
|
||||
}
|
||||
|
||||
public StopType Stop()
|
||||
{
|
||||
string response = this.session.Break();
|
||||
string response = this.presentation.Break();
|
||||
return this.ParseStopResponse(response);
|
||||
}
|
||||
|
||||
public void Continue()
|
||||
{
|
||||
this.session.Write("c");
|
||||
this.presentation.Write("c");
|
||||
}
|
||||
|
||||
public string Test()
|
||||
{
|
||||
this.session.Write("n2000800,4");
|
||||
return this.session.Read();
|
||||
this.presentation.Write("n2000800,4");
|
||||
return this.presentation.Read();
|
||||
}
|
||||
|
||||
public StopType NextStep()
|
||||
{
|
||||
this.session.Write("s");
|
||||
string response = session.Read();
|
||||
this.presentation.Write("s");
|
||||
string response = presentation.Read();
|
||||
return this.ParseStopResponse(response);
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@
|
||||
<Compile Include="GdbClient.cs" />
|
||||
<Compile Include="RSP\TargetSignals.cs" />
|
||||
<Compile Include="RSP\TcpClientAdapter.cs" />
|
||||
<Compile Include="RSP\Presentation.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
|
112
NitroDebugger/RSP/Presentation.cs
Normal file
112
NitroDebugger/RSP/Presentation.cs
Normal file
@ -0,0 +1,112 @@
|
||||
//
|
||||
// Presentation.cs
|
||||
//
|
||||
// Author:
|
||||
// Benito Palacios Sánchez <benito356@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2014 Benito Palacios Sánchez
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace NitroDebugger.RSP
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the Presentation layer.
|
||||
/// </summary>
|
||||
public class Presentation
|
||||
{
|
||||
private const int MaxWriteAttemps = 10;
|
||||
|
||||
private Session session;
|
||||
private StringBuilder buffer;
|
||||
|
||||
public Presentation(string hostname, int port)
|
||||
{
|
||||
this.session = new Session(hostname, port);
|
||||
this.buffer = new StringBuilder();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
this.session.Close();
|
||||
}
|
||||
|
||||
public string Break()
|
||||
{
|
||||
this.session.Write(0x03);
|
||||
return this.Read();
|
||||
}
|
||||
|
||||
public void Write(string message)
|
||||
{
|
||||
int count = 0;
|
||||
int response;
|
||||
|
||||
do {
|
||||
if (count == MaxWriteAttemps)
|
||||
throw new Exception("Can not send packet successfully");
|
||||
count++;
|
||||
|
||||
Packet packet = new Packet(message);
|
||||
byte[] data = packet.GetBinary();
|
||||
this.session.Write(data);
|
||||
|
||||
// Get the response
|
||||
do
|
||||
response = this.session.ReadByte();
|
||||
while (response == -1);
|
||||
|
||||
// Check the response is valid
|
||||
if (response != Packet.Ack && response != Packet.Nack)
|
||||
throw new Exception("Invalid ACK/NACK");
|
||||
|
||||
} while (response != Packet.Ack);
|
||||
}
|
||||
|
||||
public string Read()
|
||||
{
|
||||
do
|
||||
this.UpdateBuffer();
|
||||
while (buffer.Length == 0);
|
||||
|
||||
string command = null;
|
||||
|
||||
try {
|
||||
// Get packet
|
||||
Packet response = Packet.FromBinary(buffer);
|
||||
command = response.Command;
|
||||
|
||||
// Send ACK
|
||||
this.session.Write(Packet.Ack);
|
||||
} catch (FormatException ex) {
|
||||
// Error... send NACK
|
||||
this.session.Write(Packet.Nack);
|
||||
}
|
||||
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private void UpdateBuffer()
|
||||
{
|
||||
while (this.session.DataAvailable) {
|
||||
byte[] data = this.session.ReadBytes();
|
||||
buffer.AppendFormat("{0}", Encoding.ASCII.GetString(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
@ -30,17 +31,17 @@ namespace NitroDebugger.RSP
|
||||
/// </summary>
|
||||
public class Session
|
||||
{
|
||||
private const int MaxWriteAttemps = 10;
|
||||
|
||||
private ITcpClient client;
|
||||
private Stream stream;
|
||||
private StringBuilder buffer;
|
||||
|
||||
public Session(string hostname, int port)
|
||||
{
|
||||
this.client = new TcpClientAdapter(hostname, port);
|
||||
this.stream = this.client.GetStream();
|
||||
this.buffer = new StringBuilder();
|
||||
}
|
||||
|
||||
public bool DataAvailable {
|
||||
get { return this.client.DataAvailable(); }
|
||||
}
|
||||
|
||||
public void Close()
|
||||
@ -48,69 +49,37 @@ namespace NitroDebugger.RSP
|
||||
this.client.Close();
|
||||
}
|
||||
|
||||
public string Break()
|
||||
public void Write(byte data)
|
||||
{
|
||||
this.stream.WriteByte(0x03);
|
||||
return this.Read();
|
||||
this.stream.WriteByte(data);
|
||||
}
|
||||
|
||||
public void Write(string message)
|
||||
public void Write(byte[] data)
|
||||
{
|
||||
int count = 0;
|
||||
int response;
|
||||
|
||||
do {
|
||||
if (count == MaxWriteAttemps)
|
||||
throw new Exception("Can not send packet successfully");
|
||||
count++;
|
||||
|
||||
Packet packet = new Packet(message);
|
||||
byte[] data = packet.GetBinary();
|
||||
this.stream.Write(data, 0, data.Length);
|
||||
|
||||
// Get the response
|
||||
do
|
||||
response = this.stream.ReadByte();
|
||||
while (response == -1);
|
||||
|
||||
// Check the response is valid
|
||||
if (response != Packet.Ack && response != Packet.Nack)
|
||||
throw new Exception("Invalid ACK/NACK");
|
||||
|
||||
} while (response != Packet.Ack);
|
||||
this.stream.Write(data, 0, data.Length);
|
||||
}
|
||||
|
||||
public string Read()
|
||||
public byte ReadByte()
|
||||
{
|
||||
do
|
||||
this.UpdateBuffer();
|
||||
while (buffer.Length == 0);
|
||||
int result = this.stream.ReadByte();
|
||||
if (result == -1)
|
||||
throw new EndOfStreamException("No more data to read!");
|
||||
|
||||
string command = null;
|
||||
return (byte)result;
|
||||
}
|
||||
|
||||
try {
|
||||
// Get packet
|
||||
Packet response = Packet.FromBinary(buffer);
|
||||
command = response.Command;
|
||||
public byte[] ReadBytes()
|
||||
{
|
||||
List<byte> received = new List<byte>();
|
||||
|
||||
// Send ACK
|
||||
this.stream.WriteByte(Packet.Ack);
|
||||
} catch (FormatException ex) {
|
||||
// Error... send NACK
|
||||
this.stream.WriteByte(Packet.Nack);
|
||||
byte[] buffer = new byte[1024];
|
||||
while (this.DataAvailable) {
|
||||
int read = this.stream.Read(buffer, 0, buffer.Length);
|
||||
Array.Resize<byte>(ref buffer, read);
|
||||
received.AddRange(buffer);
|
||||
}
|
||||
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private void UpdateBuffer()
|
||||
{
|
||||
byte[] data = new byte[1024];
|
||||
while (this.client.DataAvailable()) {
|
||||
int read = this.stream.Read(data, 0, data.Length);
|
||||
buffer.AppendFormat("{0}", Encoding.ASCII.GetString(data, 0, read));
|
||||
}
|
||||
return received.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user