Commit 913cb59e authored by Brickner_cp's avatar Brickner_cp

--no commit message

--no commit message
parent 3840c47a
...@@ -8,7 +8,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; ...@@ -8,7 +8,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace PcapDotNet.Core.Test namespace PcapDotNet.Core.Test
{ {
/// <summary> /// <summary>
/// Summary description for PcapLibTests /// Summary description for LivePacketDeviceTests
/// </summary> /// </summary>
[TestClass] [TestClass]
public class LivePacketDeviceTests public class LivePacketDeviceTests
...@@ -147,49 +147,6 @@ namespace PcapDotNet.Core.Test ...@@ -147,49 +147,6 @@ namespace PcapDotNet.Core.Test
PacketCommunicatorReceiveResult.BreakLoop, NumPacketsToSend / 2, 0, 0.02); PacketCommunicatorReceiveResult.BreakLoop, NumPacketsToSend / 2, 0, 0.02);
} }
[TestMethod]
public void DumpPacketsTest()
{
const string SourceMac = "11:22:33:44:55:66";
const string DestinationMac = "77:88:99:AA:BB:CC";
string dumpFilename = Path.GetTempPath() + @"dump.pcap";
const int NumPackets = 10;
Packet expectedPacket = MoreRandom.BuildRandomPacket(SourceMac, DestinationMac, 24);
using (PacketCommunicator communicator = OpenLiveDevice())
{
using (PacketDumpFile dumpFile = communicator.OpenDump(dumpFilename))
{
for (int i = 0; i != NumPackets; ++i)
{
dumpFile.Dump(expectedPacket);
dumpFile.Flush();
}
}
}
using (PacketCommunicator communicator = new OfflinePacketDevice(dumpFilename).Open())
{
communicator.SetFilter("ether src " + SourceMac + " and ether dst " + DestinationMac);
PacketCommunicatorReceiveResult result;
Packet actualPacket;
for (int i = 0; i != NumPackets; ++i)
{
result = communicator.GetPacket(out actualPacket);
Assert.AreEqual(PacketCommunicatorReceiveResult.Ok, result);
Assert.AreEqual(expectedPacket, actualPacket);
MoreAssert.IsInRange(expectedPacket.Timestamp.AddSeconds(-0.05), expectedPacket.Timestamp.AddSeconds(0.05),
actualPacket.Timestamp);
}
result = communicator.GetPacket(out actualPacket);
Assert.AreEqual(PacketCommunicatorReceiveResult.Eof, result);
Assert.IsNull(actualPacket);
}
}
[TestMethod] [TestMethod]
public void GetNextStatisticsTest() public void GetNextStatisticsTest()
{ {
...@@ -256,6 +213,39 @@ namespace PcapDotNet.Core.Test ...@@ -256,6 +213,39 @@ namespace PcapDotNet.Core.Test
PacketCommunicatorReceiveResult.BreakLoop, NumStatisticsToGather / 2, NumPacketsToSend, NumStatisticsToGather / 2, NumStatisticsToGather / 2 + 0.02); PacketCommunicatorReceiveResult.BreakLoop, NumStatisticsToGather / 2, NumPacketsToSend, NumStatisticsToGather / 2, NumStatisticsToGather / 2 + 0.02);
} }
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void GetStatisticsOnCaptureModeErrorTest()
{
using (PacketCommunicator communicator = OpenLiveDevice())
{
PacketSampleStatistics statistics;
communicator.GetNextStatistics(out statistics);
}
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void GetPacketOnStatisticsModeErrorTest()
{
using (PacketCommunicator communicator = OpenLiveDevice())
{
communicator.Mode = PacketCommunicatorMode.Statistics;
Packet packet;
communicator.GetPacket(out packet);
}
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void SetInvalidModeErrorTest()
{
using (PacketCommunicator communicator = OpenLiveDevice())
{
communicator.Mode = (PacketCommunicatorMode)(-99);
}
}
private void TestGetStatistics(string sourceMac, string destinationMac, int numPacketsToSend, int numStatisticsToGather, int numStatisticsToBreakLoop, double secondsToWait, int packetSize, private void TestGetStatistics(string sourceMac, string destinationMac, int numPacketsToSend, int numStatisticsToGather, int numStatisticsToBreakLoop, double secondsToWait, int packetSize,
PacketCommunicatorReceiveResult expectedResult, int expectedNumStatistics, int expectedNumPackets, double expectedMinSeconds, double expectedMaxSeconds) PacketCommunicatorReceiveResult expectedResult, int expectedNumStatistics, int expectedNumPackets, double expectedMinSeconds, double expectedMaxSeconds)
{ {
......
...@@ -5,6 +5,20 @@ namespace PcapDotNet.Core.Test ...@@ -5,6 +5,20 @@ namespace PcapDotNet.Core.Test
{ {
internal static class MoreAssert internal static class MoreAssert
{ {
public static void IsBigger<T>(T expectedMinimum, T actual) where T : IComparable<T>
{
if (expectedMinimum.CompareTo(actual) >= 0)
throw new AssertFailedException("Assert.IsBigger failed. Expected minimum: <" + expectedMinimum +
"> Actual: <" + actual + ">.");
}
public static void IsSmaller<T>(T expectedMaximum, T actual) where T : IComparable<T>
{
if (expectedMaximum.CompareTo(actual) <= 0)
throw new AssertFailedException("Assert.IsSmaller failed. Expected maximum: <" + expectedMaximum +
"> Actual: <" + actual + ">.");
}
public static void IsBiggerOrEqual<T>(T expectedMinimum, T actual) where T : IComparable<T> public static void IsBiggerOrEqual<T>(T expectedMinimum, T actual) where T : IComparable<T>
{ {
if (expectedMinimum.CompareTo(actual) > 0) if (expectedMinimum.CompareTo(actual) > 0)
......
...@@ -23,6 +23,11 @@ namespace PcapDotNet.Core.Test ...@@ -23,6 +23,11 @@ namespace PcapDotNet.Core.Test
return BuildRandomPacket(DateTime.Now, sourceMac, destinationMac, packetSize); return BuildRandomPacket(DateTime.Now, sourceMac, destinationMac, packetSize);
} }
public static Packet BuildRandomPacket(int packetSize)
{
return BuildRandomPacket(DateTime.Now, GetRandomMacAddress().ToString(), GetRandomMacAddress().ToString(), packetSize);
}
private static Datagram GetRandomDatagram(int length) private static Datagram GetRandomDatagram(int length)
{ {
byte[] buffer = new byte[length]; byte[] buffer = new byte[length];
...@@ -30,6 +35,13 @@ namespace PcapDotNet.Core.Test ...@@ -30,6 +35,13 @@ namespace PcapDotNet.Core.Test
return new Datagram(buffer); return new Datagram(buffer);
} }
private static MacAddress GetRandomMacAddress()
{
byte[] buffer = new byte[6];
_random.NextBytes(buffer);
return new MacAddress(buffer, 0);
}
private static readonly Random _random = new Random(); private static readonly Random _random = new Random();
} }
} }
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Packets;
namespace PcapDotNet.Core.Test
{
/// <summary>
/// Summary description for OfflinePacketDeviceTests
/// </summary>
[TestClass]
public class OfflinePacketDeviceTests
{
public OfflinePacketDeviceTests()
{
//
// TODO: Add constructor logic here
//
}
private TestContext testContextInstance;
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}
#region Additional test attributes
//
// You can use the following additional attributes as you write your tests:
//
// Use ClassInitialize to run code before running the first test in the class
// [ClassInitialize()]
// public static void MyClassInitialize(TestContext testContext) { }
//
// Use ClassCleanup to run code after all tests in a class have run
// [ClassCleanup()]
// public static void MyClassCleanup() { }
//
// Use TestInitialize to run code before running each test
// [TestInitialize()]
// public void MyTestInitialize() { }
//
// Use TestCleanup to run code after each test has run
// [TestCleanup()]
// public void MyTestCleanup() { }
//
#endregion
[TestMethod]
public void DumpPacketsTest()
{
const string SourceMac = "11:22:33:44:55:66";
const string DestinationMac = "77:88:99:AA:BB:CC";
const int NumPackets = 10;
Packet expectedPacket = MoreRandom.BuildRandomPacket(SourceMac, DestinationMac, 24);
using (PacketCommunicator communicator = OpenOfflineDevice(NumPackets, expectedPacket))
{
communicator.SetFilter("ether src " + SourceMac + " and ether dst " + DestinationMac);
PacketCommunicatorReceiveResult result;
Packet actualPacket;
for (int i = 0; i != NumPackets; ++i)
{
result = communicator.GetPacket(out actualPacket);
Assert.AreEqual(PacketCommunicatorReceiveResult.Ok, result);
Assert.AreEqual(expectedPacket, actualPacket);
MoreAssert.IsInRange(expectedPacket.Timestamp.AddSeconds(-0.05), expectedPacket.Timestamp.AddSeconds(0.05),
actualPacket.Timestamp);
}
result = communicator.GetPacket(out actualPacket);
Assert.AreEqual(PacketCommunicatorReceiveResult.Eof, result);
Assert.IsNull(actualPacket);
}
}
[TestMethod]
public void SetNonBlockTest()
{
const int NumPackets = 10;
Packet packet = MoreRandom.BuildRandomPacket(24);
using (PacketCommunicator communicator = OpenOfflineDevice(NumPackets, packet))
{
Assert.AreEqual(false, communicator.NonBlocking);
communicator.NonBlocking = false;
Assert.AreEqual(false, communicator.NonBlocking);
communicator.NonBlocking = true;
Assert.AreEqual(false, communicator.NonBlocking);
}
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void GetTotalStatisticsTest()
{
const int NumPackets = 10;
Packet packet = MoreRandom.BuildRandomPacket(24);
using (PacketCommunicator communicator = OpenOfflineDevice(NumPackets, packet))
{
Assert.IsNotNull(communicator.TotalStatistics);
}
}
[TestMethod]
[ExpectedException(typeof(InvalidOperationException))]
public void OpenInvalidFileTest()
{
using (PacketCommunicator communicator = new OfflinePacketDevice("myinvalidfile").Open())
{
}
}
public static PacketCommunicator OpenOfflineDevice(int numPackets, Packet packet)
{
string dumpFilename = Path.GetTempPath() + @"dump.pcap";
PacketCommunicator communicator;
using (communicator = LivePacketDeviceTests.OpenLiveDevice())
{
using (PacketDumpFile dumpFile = communicator.OpenDump(dumpFilename))
{
int lastPosition = 0;
for (int i = 0; i != numPackets; ++i)
{
dumpFile.Dump(packet);
MoreAssert.IsBigger(lastPosition, dumpFile.Position);
lastPosition = dumpFile.Position;
dumpFile.Flush();
}
}
}
communicator = new OfflinePacketDevice(dumpFilename).Open();
try
{
Assert.AreEqual(DataLinkKind.Ethernet, communicator.DataLink.Kind);
Assert.AreEqual("EN10MB (Ethernet)", communicator.DataLink.ToString());
Assert.AreEqual(communicator.DataLink, new PcapDataLink(communicator.DataLink.Name));
Assert.IsTrue(communicator.IsFileSystemByteOrder);
Assert.AreEqual(PacketCommunicatorMode.Capture, communicator.Mode);
Assert.IsFalse(communicator.NonBlocking);
Assert.AreEqual(PacketDevice.DefaultSnapshotLength, communicator.SnapshotLength);
return communicator;
}
catch (Exception)
{
communicator.Dispose();
throw;
}
}
}
}
\ No newline at end of file
...@@ -6,7 +6,7 @@ using Packets; ...@@ -6,7 +6,7 @@ using Packets;
namespace PcapDotNet.Core.Test namespace PcapDotNet.Core.Test
{ {
/// <summary> /// <summary>
/// Summary description for PcapLibTests /// Summary description for PacketSendQueueTests
/// </summary> /// </summary>
[TestClass] [TestClass]
public class PacketSendQueueTests public class PacketSendQueueTests
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
<Compile Include="LivePacketDeviceTests.cs" /> <Compile Include="LivePacketDeviceTests.cs" />
<Compile Include="MoreRandom.cs" /> <Compile Include="MoreRandom.cs" />
<Compile Include="PacketSendQueueTests.cs" /> <Compile Include="PacketSendQueueTests.cs" />
<Compile Include="OfflinePacketDeviceTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PcapLibTests.cs" /> <Compile Include="PcapLibTests.cs" />
</ItemGroup> </ItemGroup>
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "MarshalingServices.h" #include "MarshalingServices.h"
#include "Pcap.h" #include "Pcap.h"
#include "OnlinePacketCommunicator.h"
using namespace System; using namespace System;
using namespace System::Collections::Generic; using namespace System::Collections::Generic;
...@@ -81,7 +82,7 @@ PacketCommunicator^ LivePacketDevice::Open(int snapshotLength, PacketDeviceOpenF ...@@ -81,7 +82,7 @@ PacketCommunicator^ LivePacketDevice::Open(int snapshotLength, PacketDeviceOpenF
netmask = Addresses[0]->Netmask; netmask = Addresses[0]->Netmask;
// Open the device // Open the device
return gcnew PacketCommunicator(deviceName.c_str(), snapshotLength, flags, readTimeout, NULL, netmask); return gcnew OnlinePacketCommunicator(deviceName.c_str(), snapshotLength, flags, readTimeout, NULL, netmask);
} }
// Private Methods // Private Methods
......
#include "OfflinePacketCommunicator.h"
using namespace System;
using namespace PcapDotNet::Core;
PacketTotalStatistics^ OfflinePacketCommunicator::TotalStatistics::get()
{
throw gcnew InvalidOperationException("Can't get TotalStatistics for offline devices");
}
OfflinePacketCommunicator::OfflinePacketCommunicator(const char* source, int snapshotLength, PacketDeviceOpenFlags flags, int readTimeout, pcap_rmtauth* auth)
: PacketCommunicator(source, snapshotLength, flags, readTimeout, auth, nullptr)
{
}
#pragma once
#include "PacketCommunicator.h"
#include "PcapDeclarations.h"
namespace PcapDotNet { namespace Core
{
public ref class OfflinePacketCommunicator : PacketCommunicator
{
public:
virtual property PacketTotalStatistics^ TotalStatistics
{
PacketTotalStatistics^ get() override;
}
internal:
OfflinePacketCommunicator(const char* source, int snapshotLength, PacketDeviceOpenFlags flags, int readTimeout, pcap_rmtauth* auth);
};
}}
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "Pcap.h" #include "Pcap.h"
#include "MarshalingServices.h" #include "MarshalingServices.h"
#include "OfflinePacketCommunicator.h"
using namespace System; using namespace System;
using namespace System::Collections::Generic; using namespace System::Collections::Generic;
...@@ -53,5 +54,5 @@ PacketCommunicator^ OfflinePacketDevice::Open(int snapshotLength, PacketDeviceOp ...@@ -53,5 +54,5 @@ PacketCommunicator^ OfflinePacketDevice::Open(int snapshotLength, PacketDeviceOp
throw gcnew InvalidOperationException("Error creating a source string from filename " + _filename + " Error: " + gcnew String(errbuf)); throw gcnew InvalidOperationException("Error creating a source string from filename " + _filename + " Error: " + gcnew String(errbuf));
} }
return gcnew PacketCommunicator(source, snapshotLength, flags, readTimeout, NULL, nullptr); return gcnew OfflinePacketCommunicator(source, snapshotLength, flags, readTimeout, NULL);
} }
#include "OnlinePacketCommunicator.h"
#include "Pcap.h"
using namespace PcapDotNet::Core;
OnlinePacketCommunicator::OnlinePacketCommunicator(const char* source, int snapshotLength, PacketDeviceOpenFlags flags, int readTimeout, pcap_rmtauth* auth, SocketAddress^ netmask)
: PacketCommunicator(source, snapshotLength, flags, readTimeout, auth, netmask)
{
}
PacketTotalStatistics^ OnlinePacketCommunicator::TotalStatistics::get()
{
int statisticsSize;
pcap_stat* statistics = pcap_stats_ex(_pcapDescriptor, &statisticsSize);
if (statistics == NULL)
throw BuildInvalidOperation("Failed getting total statistics");
unsigned int packetsReceived = statistics->ps_recv;
unsigned int packetsDroppedByDriver = statistics->ps_drop;
unsigned int packetsDroppedByInterface = statistics->ps_ifdrop;
unsigned int packetsCaptured = (statisticsSize >= 16
? *(reinterpret_cast<int*>(statistics) + 3)
: 0);
return gcnew PacketTotalStatistics(packetsReceived, packetsDroppedByDriver, packetsDroppedByInterface, packetsCaptured);
}
#pragma once
#include "PacketCommunicator.h"
namespace PcapDotNet { namespace Core
{
public ref class OnlinePacketCommunicator : PacketCommunicator
{
public:
virtual property PacketTotalStatistics^ TotalStatistics
{
PacketTotalStatistics^ get() override;
}
internal:
OnlinePacketCommunicator(const char* source, int snapshotLength, PacketDeviceOpenFlags flags, int readTimeout, pcap_rmtauth* auth,
SocketAddress^ netmask);
};
}}
\ No newline at end of file
...@@ -13,8 +13,6 @@ using namespace System::Collections::Generic; ...@@ -13,8 +13,6 @@ using namespace System::Collections::Generic;
using namespace Packets; using namespace Packets;
using namespace PcapDotNet::Core; using namespace PcapDotNet::Core;
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
PacketCommunicator::PacketCommunicator(const char* source, int snapshotLength, PacketDeviceOpenFlags flags, int readTimeout, pcap_rmtauth *auth, SocketAddress^ netmask) PacketCommunicator::PacketCommunicator(const char* source, int snapshotLength, PacketDeviceOpenFlags flags, int readTimeout, pcap_rmtauth *auth, SocketAddress^ netmask)
{ {
// Open the device // Open the device
...@@ -91,23 +89,6 @@ int PacketCommunicator::FileMinorVersion::get() ...@@ -91,23 +89,6 @@ int PacketCommunicator::FileMinorVersion::get()
return pcap_minor_version(_pcapDescriptor); return pcap_minor_version(_pcapDescriptor);
} }
PacketTotalStatistics^ PacketCommunicator::TotalStatistics::get()
{
int statisticsSize;
pcap_stat* statistics = pcap_stats_ex(_pcapDescriptor, &statisticsSize);
if (statistics == NULL)
throw BuildInvalidOperation("Failed getting total statistics");
unsigned int packetsReceived = statistics->ps_recv;
unsigned int packetsDroppedByDriver = statistics->ps_drop;
unsigned int packetsDroppedByInterface = statistics->ps_ifdrop;
unsigned int packetsCaptured = (statisticsSize >= 16
? *(reinterpret_cast<int*>(statistics) + 3)
: 0);
return gcnew PacketTotalStatistics(packetsReceived, packetsDroppedByDriver, packetsDroppedByInterface, packetsCaptured);
}
PacketCommunicatorMode PacketCommunicator::Mode::get() PacketCommunicatorMode PacketCommunicator::Mode::get()
{ {
return _mode; return _mode;
......
...@@ -28,12 +28,9 @@ namespace PcapDotNet { namespace Core ...@@ -28,12 +28,9 @@ namespace PcapDotNet { namespace Core
KernelDump = 0x10 // Kernel dump working mode. KernelDump = 0x10 // Kernel dump working mode.
}; };
public ref class PacketCommunicator : System::IDisposable public ref class PacketCommunicator abstract : System::IDisposable
{ {
public: public:
PacketCommunicator(const char* source, int snapshotLength, PacketDeviceOpenFlags flags, int readTimeout, pcap_rmtauth *auth,
SocketAddress^ netmask);
property PcapDataLink DataLink property PcapDataLink DataLink
{ {
PcapDataLink get(); PcapDataLink get();
...@@ -65,9 +62,9 @@ namespace PcapDotNet { namespace Core ...@@ -65,9 +62,9 @@ namespace PcapDotNet { namespace Core
int get(); int get();
} }
property PacketTotalStatistics^ TotalStatistics virtual property PacketTotalStatistics^ TotalStatistics
{ {
PacketTotalStatistics^ get(); PacketTotalStatistics^ get() = 0;
} }
property PacketCommunicatorMode Mode property PacketCommunicatorMode Mode
...@@ -104,6 +101,13 @@ namespace PcapDotNet { namespace Core ...@@ -104,6 +101,13 @@ namespace PcapDotNet { namespace Core
~PacketCommunicator(); ~PacketCommunicator();
internal:
PacketCommunicator(const char* source, int snapshotLength, PacketDeviceOpenFlags flags, int readTimeout, pcap_rmtauth* auth,
SocketAddress^ netmask);
protected:
System::InvalidOperationException^ BuildInvalidOperation(System::String^ errorMessage);
private: private:
static Packets::Packet^ CreatePacket(const pcap_pkthdr& packetHeader, const unsigned char* packetData, Packets::IDataLink^ dataLink); static Packets::Packet^ CreatePacket(const pcap_pkthdr& packetHeader, const unsigned char* packetData, Packets::IDataLink^ dataLink);
static PacketSampleStatistics^ PacketCommunicator::CreateStatistics(const pcap_pkthdr& packetHeader, const unsigned char* packetData); static PacketSampleStatistics^ PacketCommunicator::CreateStatistics(const pcap_pkthdr& packetHeader, const unsigned char* packetData);
...@@ -120,8 +124,6 @@ namespace PcapDotNet { namespace Core ...@@ -120,8 +124,6 @@ namespace PcapDotNet { namespace Core
System::String^ get(); System::String^ get();
} }
System::InvalidOperationException^ BuildInvalidOperation(System::String^ errorMessage);
ref class PacketHandler ref class PacketHandler
{ {
public: public:
...@@ -150,8 +152,10 @@ namespace PcapDotNet { namespace Core ...@@ -150,8 +152,10 @@ namespace PcapDotNet { namespace Core
HandleStatistics^ _callBack; HandleStatistics^ _callBack;
}; };
private: protected:
pcap_t* _pcapDescriptor; pcap_t* _pcapDescriptor;
private:
IpV4SocketAddress^ _ipV4Netmask; IpV4SocketAddress^ _ipV4Netmask;
PacketCommunicatorMode _mode; PacketCommunicatorMode _mode;
}; };
......
...@@ -187,7 +187,7 @@ ...@@ -187,7 +187,7 @@
/> />
<ProjectReference <ProjectReference
ReferencedProjectIdentifier="{8A184AF5-E46C-482C-81A3-76D8CE290104}" ReferencedProjectIdentifier="{8A184AF5-E46C-482C-81A3-76D8CE290104}"
RelativePathToProject=".\BPacket\BPacket.csproj" RelativePathToProject=".\BPacket\Packets.csproj"
/> />
</References> </References>
<Files> <Files>
...@@ -243,6 +243,14 @@ ...@@ -243,6 +243,14 @@
RelativePath=".\MarshalingServices.h" RelativePath=".\MarshalingServices.h"
> >
</File> </File>
<File
RelativePath=".\OfflinePacketCommunicator.cpp"
>
</File>
<File
RelativePath=".\OfflinePacketCommunicator.h"
>
</File>
<File <File
RelativePath=".\OfflinePacketDevice.cpp" RelativePath=".\OfflinePacketDevice.cpp"
> >
...@@ -251,6 +259,14 @@ ...@@ -251,6 +259,14 @@
RelativePath=".\OfflinePacketDevice.h" RelativePath=".\OfflinePacketDevice.h"
> >
</File> </File>
<File
RelativePath=".\OnlinePacketCommunicator.cpp"
>
</File>
<File
RelativePath=".\OnlinePacketCommunicator.h"
>
</File>
<File <File
RelativePath=".\PacketCommunicator.cpp" RelativePath=".\PacketCommunicator.cpp"
> >
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment