1
0
mirror of https://github.com/livingcomputermuseum/IFS.git synced 2026-04-09 14:23:16 +00:00

Basics completed (still rough). No testing done (awaiting running Alto.)

This commit is contained in:
Josh Dersch
2015-10-15 16:47:45 -07:00
parent 16557b9110
commit 3c6c88381e
11 changed files with 336 additions and 46 deletions

View File

@@ -25,7 +25,7 @@ namespace IFS
_inputWriteEvent = new AutoResetEvent(false);
_inputQueue = new MemoryStream(65536);
_inputQueue = new Queue<byte>(65536);
// TODO: init IDs, etc. based on RFC PUP
_start_pos = _recv_pos = _send_pos = rfcPup.ID;
@@ -161,13 +161,15 @@ namespace IFS
_outputAckEvent.Set();
}
/*
public void Mark(byte type);
public void Interrupt();
public void Abort(int code, string message);
public void Error(int code, string message);
public void End();
public void End();
*/
// TODO:
// Events for:
@@ -235,10 +237,11 @@ namespace IFS
case PupType.RFC:
{
BSPChannel newChannel = new BSPChannel(p);
_activeChannels.Add(newChannel.ClientPort.Socket);
_activeChannels.Add(newChannel.ClientPort.Socket, newChannel);
return newChannel;
}
break;
case PupType.Data:
case PupType.AData:
@@ -253,11 +256,13 @@ namespace IFS
break;
case PupType.Ack:
BSPChannel channel = FindChannelForPup(p);
{
BSPChannel channel = FindChannelForPup(p);
if (channel != null)
{
channel.Ack(p);
if (channel != null)
{
channel.Ack(p);
}
}
break;
@@ -267,7 +272,7 @@ namespace IFS
if (channel != null)
{
channel.EndReply();
//channel.EndReply();
}
}
break;

64
PUP/BreathOfLife.cs Normal file
View File

@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IFS
{
/// <summary>
/// Implements the BreathOfLife services.
/// It spins up a worker thread that wakes up every few seconds and broadcasts
/// a BreathOfLife packet.
/// </summary>
public class BreathOfLife
{
public BreathOfLife()
{
}
/*
ushort[] _bolPacket =
{
0,0,
0022574, 0100000, 0040437, 0102000, 0034431, 0164000,
0061005, 0102460, 0024567, 0034572, 0061006, 0024565, 0034570, 0061006,
0024564, 0034566, 0061006, 0020565, 0034565, 0061005, 0125220, 0046573,
0020576, 0061004, 0123400, 0030551, 0041211, 0004416, 0000000, 0001000,
0000026, 0000244, 0000000, 0000000, 0000000, 0000000, 0000004, 0000000,
0000000, 0000020, 0177777, 0055210, 0025400, 0107000, 0045400, 0041411,
0020547, 0041207, 0020544, 0061004, 0006531, 0034517, 0030544, 0051606,
0020510, 0041605, 0042526, 0102460, 0041601, 0020530, 0061004, 0021601,
0101014, 0000414, 0061020, 0014737, 0000773, 0014517, 0000754, 0020517,
0061004, 0030402, 0002402, 0000000, 0000732, 0034514, 0162414, 0000746,
0021001, 0024511, 0106414, 0000742, 0021003, 0163400, 0035005, 0024501,
0106415, 0175014, 0000733, 0021000, 0042465, 0034457, 0056445, 0055775,
0055776, 0101300, 0041400, 0020467, 0041401, 0020432, 0041402, 0121400,
0041403, 0021006, 0041411, 0021007, 0041412, 0021010, 0041413, 0021011,
0041406, 0021012, 0041407, 0021013, 0041410, 0015414, 0006427, 0012434,
0006426, 0020421, 0024437, 0134000, 0030417, 0002422, 0177035, 0000026,
0000415, 0000427, 0000567, 0000607, 0000777, 0177751, 0177641, 0177600,
0000225, 0177624, 0001013, 0000764, 0000431, 0000712, 0000634, 0000735,
0000611, 0000567, 0000564, 0000566, 0000036, 0000002, 0000003, 0000015,
0000030, 0000377, 0001000, 0177764, 0000436, 0054731, 0050750, 0020753,
0040745, 0102460, 0040737, 0020762, 0061004, 0020734, 0105304, 0000406,
0020743, 0101014, 0014741, 0000772, 0002712, 0034754, 0167700, 0116415,
0024752, 0021001, 0106414, 0000754, 0021000, 0024703, 0106414, 0000750,
0021003, 0163400, 0024736, 0106405, 0000404, 0121400, 0101404, 0000740,
0044714, 0021005, 0042732, 0024664, 0122405, 0000404, 0101405, 0004404,
0000727, 0010656, 0034654, 0024403, 0120500, 0101404, 0000777, 0040662,
0040664, 0040664, 0102520, 0061004, 0020655, 0101015, 0000776, 0106415,
0001400, 0014634, 0000761, 0020673, 0061004, 0000400, 0061005, 0102000,
0143000, 0034672, 0024667, 0166400, 0061005, 0004670, 0020663, 0034664,
0164000, 0147000, 0061005, 0024762, 0132414, 0133000, 0020636, 0034416,
0101015, 0156415, 0131001, 0000754, 0024643, 0044625, 0101015, 0000750,
0014623, 0004644, 0020634, 0061004, 0002000, 0176764, 0001401, 0041002
}; */
}
}

View File

@@ -33,6 +33,18 @@ namespace IFS
_localHost = new HostAddress(1, 34);
}
public string AddressLookup(HostAddress address)
{
// TODO: actually look things up
return "Alto";
}
public HostAddress NameLookup(string hostName)
{
// TODO: actually look things up
return new HostAddress(1, 0x80);
}
public static DirectoryServices Instance
{
get { return _instance; }

View File

@@ -6,6 +6,9 @@ using System.Threading.Tasks;
using IFS.Transport;
using PcapDotNet.Packets;
using PcapDotNet.Packets.Ethernet;
using IFS.Logging;
using PcapDotNet.Base;
namespace IFS
{
@@ -22,9 +25,7 @@ namespace IFS
/// </summary>
private Dispatcher()
{
_dispatchMap = new Dictionary<uint, PUPProtocolEntry>();
_packetInterface = new Ethernet(iface, OnPacketReceived);
_dispatchMap = new Dictionary<uint, PUPProtocolEntry>();
}
/// <summary>
@@ -35,6 +36,13 @@ namespace IFS
get { return _instance; }
}
public void RegisterInterface(EthernetInterface i)
{
// TODO: support multiple interfaces (for gateway routing, for example.)
// Also, this should not be ethernet-specific.
_packetInterface = new Ethernet(i, OnPacketReceived);
}
/// <summary>
/// Registers a new protocol with the dispatcher
/// </summary>
@@ -45,7 +53,7 @@ namespace IFS
if (_dispatchMap.ContainsKey(entry.Socket))
{
throw new InvalidOperationException(
String.Format("Socket {0} has already been registered for protocol {1}", impl.Socket, _dispatchMap[impl.Socket].FriendlyName));
String.Format("Socket {0} has already been registered for protocol {1}", entry.Socket, _dispatchMap[entry.Socket].FriendlyName));
}
_dispatchMap[entry.Socket] = entry;
@@ -53,7 +61,41 @@ namespace IFS
public void SendPup(PUP p)
{
// TODO: Write PUP to ethernet
//
// Write PUP to ethernet:
// Get destination network & host address from PUP and route to correct ethernet address.
// For now, no actual routing (Gateway not implemented yet), everthing is on the same 'net.
// Just look up host address and find the MAC of the host to send it to.
// TODO: this translation should be at the Interface level, not here (we shouldn't be doing
// ethernet-specific things here -- at the moment it doesn't matter since we're only speaking
// ethernet, but this should be fixed.)
//
if (_pupToEthernetMap.ContainsKey(p.DestinationPort.Host))
{
MacAddress destinationMac = _pupToEthernetMap[p.SourcePort.Host];
// Build the outgoing packet; place the source/dest addresses, type field and the PUP data.
EthernetLayer ethernetLayer = new EthernetLayer
{
Source = (MacAddress)_packetInterface.GetDeviceAddress(),
Destination = destinationMac,
EtherType = (EthernetType)512, // PUP type (TODO: move to constant)
};
PayloadLayer payloadLayer = new PayloadLayer
{
Data = new Datagram(p.RawData),
};
PacketBuilder builder = new PacketBuilder(ethernetLayer, payloadLayer);
_packetInterface.SendPacket(builder.Build(DateTime.Now));
}
else
{
// Log error, this should not happen.
Log.Write(LogLevel.Error, String.Format("PUP destination address {0} is unknown.", p.DestinationPort.Host));
}
}
@@ -65,19 +107,64 @@ namespace IFS
{
PUP pup = new PUP(p.Ethernet.Payload.ToMemoryStream());
if (_dispatchMap.ContainsKey(pup.DestinationPort.Socket))
//
// Check the network -- if this is not network zero (coming from a host that doesn't yet know what
// network it's on) or the network we're on, we will ignore it (for now...). Once we implement
// Gateway services we will handle these appropriately.
//
if (pup.SourcePort.Network == 0 || pup.SourcePort.Network == DirectoryServices.Instance.LocalHostAddress.Network)
{
PUPProtocolEntry entry = _dispatchMap[pup.DestinationPort.Socket];
entry.ProtocolImplementation.RecvData(pup);
UpdateMACTable(pup, p);
if (_dispatchMap.ContainsKey(pup.DestinationPort.Socket))
{
PUPProtocolEntry entry = _dispatchMap[pup.DestinationPort.Socket];
entry.ProtocolImplementation.RecvData(pup);
}
else
{
// Not a protocol we handle; TODO: log it.
Log.Write(LogLevel.UnhandledProtocol | LogLevel.DroppedPacket, String.Format("Unhandled PUP protocol, socket {0}, dropped packet.", pup.DestinationPort.Socket));
}
}
else
{
// Not a protocol we handle; TODO: log it.
// Not for our network; eventually we will look into routing...
Log.Write(LogLevel.DroppedPacket, String.Format("PUP is for network {0}, dropping.", pup.SourcePort.Network));
}
}
else
{
// Not a PUP, Discard the packet.
// Not a PUP, Discard the packet. We will not log this to keep noise down.
//Log.Write(LogLevel.DroppedPacket, "Not a PUP. Dropping.");
}
}
private void UpdateMACTable(PUP p, Packet e)
{
//
// See if we already have this entry.
//
if (_pupToEthernetMap.ContainsKey(p.SourcePort.Host))
{
//
// We do; ensure that the mac addresses match -- if not we have a duplicate
// PUP id on the network.
//
if (_pupToEthernetMap[p.SourcePort.Host] != e.Ethernet.Source)
{
Log.Write(LogLevel.DuplicateHostNumber,
String.Format("Duplicate host number {0} for MAC {1} (currently mapped to MAC {2})",
p.SourcePort.Host,
e.Ethernet.Source,
_pupToEthernetMap[p.SourcePort.Host]));
}
}
else
{
// Add a mapping in both directions
_pupToEthernetMap.Add(p.SourcePort.Host, e.Ethernet.Source);
_ethernetToPupMap.Add(e.Ethernet.Source, p.SourcePort.Host);
}
}
@@ -91,6 +178,12 @@ namespace IFS
/// </summary>
private Dictionary<UInt32, PUPProtocolEntry> _dispatchMap;
/// <summary>
/// PUP<->Ethernet address map
/// </summary>
private Dictionary<byte, MacAddress> _pupToEthernetMap;
private Dictionary<MacAddress, byte> _ethernetToPupMap;
private static Dispatcher _instance = new Dispatcher();
}
}

View File

@@ -1,4 +1,5 @@
using System;
using IFS.Transport;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -10,6 +11,20 @@ namespace IFS
{
static void Main(string[] args)
{
Logging.Log.Level = Logging.LogLevel.All;
List<EthernetInterface> ifaces = EthernetInterface.EnumerateDevices();
Console.WriteLine("available interfaces are:");
foreach(EthernetInterface i in ifaces)
{
Console.WriteLine(String.Format("{0} - address {1}", i.Name, i.MacAddress));
}
// TODO: MAKE THIS CONFIGURABLE.
Dispatcher.Instance.RegisterInterface(ifaces[1]);
// Set up protocols:
// Connectionless
@@ -19,5 +34,10 @@ namespace IFS
// RTP/BSP based:
Dispatcher.Instance.RegisterProtocol(new PUPProtocolEntry("CopyDisk", 0x15 /* 25B */, ConnectionType.BSP, new CopyDiskServer()));
while (true)
{
System.Threading.Thread.Sleep(100);
}
}
}
}

View File

@@ -32,18 +32,36 @@
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="PcapDotNet.Base">
<HintPath>..\Ethernet\pcap\PcapDotNet.Base.dll</HintPath>
<HintPath>pcap\PcapDotNet.Base.dll</HintPath>
</Reference>
<Reference Include="PcapDotNet.Core">
<HintPath>..\Ethernet\pcap\PcapDotNet.Core.dll</HintPath>
<HintPath>pcap\PcapDotNet.Core.dll</HintPath>
</Reference>
<Reference Include="PcapDotNet.Core.Extensions">
<HintPath>..\Ethernet\pcap\PcapDotNet.Core.Extensions.dll</HintPath>
<HintPath>pcap\PcapDotNet.Core.Extensions.dll</HintPath>
</Reference>
<Reference Include="PcapDotNet.Packets">
<HintPath>..\Ethernet\pcap\PcapDotNet.Packets.dll</HintPath>
<HintPath>pcap\PcapDotNet.Packets.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -55,11 +73,13 @@
</ItemGroup>
<ItemGroup>
<Compile Include="BCPLString.cs" />
<Compile Include="BreathOfLife.cs" />
<Compile Include="BSPManager.cs" />
<Compile Include="CopyDiskServer.cs" />
<Compile Include="DirectoryServices.cs" />
<Compile Include="EchoProtocol.cs" />
<Compile Include="Entrypoint.cs" />
<Compile Include="Logging\Log.cs" />
<Compile Include="MiscServicesProtocol.cs" />
<Compile Include="Transport\Ethernet.cs" />
<Compile Include="PUPProtocolBase.cs" />

View File

@@ -8,13 +8,19 @@ EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5C0BBE4B-76AB-4AC1-8691-F19D8D282DCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5C0BBE4B-76AB-4AC1-8691-F19D8D282DCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5C0BBE4B-76AB-4AC1-8691-F19D8D282DCB}.Debug|x64.ActiveCfg = Debug|x64
{5C0BBE4B-76AB-4AC1-8691-F19D8D282DCB}.Debug|x64.Build.0 = Debug|x64
{5C0BBE4B-76AB-4AC1-8691-F19D8D282DCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5C0BBE4B-76AB-4AC1-8691-F19D8D282DCB}.Release|Any CPU.Build.0 = Release|Any CPU
{5C0BBE4B-76AB-4AC1-8691-F19D8D282DCB}.Release|x64.ActiveCfg = Release|x64
{5C0BBE4B-76AB-4AC1-8691-F19D8D282DCB}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

48
PUP/Logging/Log.cs Normal file
View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IFS.Logging
{
[Flags]
public enum LogLevel
{
None = 0,
Normal = 1,
Warning = 2,
Error = 4,
DroppedPacket = 8,
InvalidPacket = 0x10,
UnhandledProtocol = 0x20,
DuplicateHostNumber = 0x40,
All = 0x7fffffff,
}
public static class Log
{
static Log()
{
_level = LogLevel.None;
}
public static LogLevel Level
{
get { return _level; }
set { _level = value; }
}
public static void Write(LogLevel level, string message)
{
if ((level & _level) != 0)
{
// My log has something to tell you...
Console.WriteLine("{0}: {1} - {2}", DateTime.Now, level, message);
}
}
private static LogLevel _level;
}
}

View File

@@ -1,4 +1,5 @@
using System;
using IFS.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -48,7 +49,7 @@ namespace IFS
break;
default:
// Unhandled, TODO: log it
Log.Write(LogLevel.UnhandledProtocol, String.Format("Unhandled misc. protocol {0}", p.Type));
break;
}
}
@@ -144,7 +145,7 @@ namespace IFS
// and see if we have a match.
//
PUPPort lookupAddress = new PUPPort(p.Contents, 0);
string hostName = DirectoryServices.Instance.AddressLookup(lookupAddress);
string hostName = DirectoryServices.Instance.AddressLookup(new HostAddress(lookupAddress.Network, lookupAddress.Host));
if (!String.IsNullOrEmpty(hostName))
{

View File

@@ -5,20 +5,36 @@ using System.Text;
using System.Threading.Tasks;
using PcapDotNet.Core;
using PcapDotNet.Core.Extensions;
using PcapDotNet.Packets;
using PcapDotNet.Packets.Ethernet;
namespace IFS.Transport
{
public struct EthernetInterface
{
public EthernetInterface(string name, string description)
public EthernetInterface(string name, string description, MacAddress macAddress)
{
Name = name;
Description = description;
MacAddress = macAddress;
}
public string Name;
public string Description;
public static List<EthernetInterface> EnumerateDevices()
{
List<EthernetInterface> interfaces = new List<EthernetInterface>();
foreach (LivePacketDevice device in LivePacketDevice.AllLocalMachine)
{
interfaces.Add(new EthernetInterface(device.Name, device.Description, device.GetMacAddress()));
}
return interfaces;
}
public string Name;
public string Description;
public MacAddress MacAddress;
}
/// <summary>
@@ -30,23 +46,14 @@ namespace IFS.Transport
{
AttachInterface(iface);
_callback = callback;
}
public static List<EthernetInterface> EnumerateDevices()
{
List<EthernetInterface> interfaces = new List<EthernetInterface>();
foreach(LivePacketDevice device in LivePacketDevice.AllLocalMachine)
{
interfaces.Add(new EthernetInterface(device.Name, device.Description));
}
return interfaces;
Open(false, int.MaxValue);
BeginReceive();
}
public void Open(bool promiscuous, int timeout)
{
_communicator = _interface.Open(0xffff, promiscuous ? PacketDeviceOpenAttributes.Promiscuous : PacketDeviceOpenAttributes.None, timeout);
_communicator = _interface.Open(0xffff, promiscuous ? PacketDeviceOpenAttributes.Promiscuous : PacketDeviceOpenAttributes.None, timeout);
}
/// <summary>
@@ -57,9 +64,19 @@ namespace IFS.Transport
_communicator.ReceivePackets(-1, ReceiveCallback);
}
public void SendPacket(Packet p)
{
_communicator.SendPacket(p);
}
public object GetDeviceAddress()
{
return (object)_interface.GetMacAddress();
}
private void ReceiveCallback(Packet p)
{
_callback(p);
{
_callback(p);
}
private void AttachInterface(EthernetInterface iface)
@@ -69,7 +86,7 @@ namespace IFS.Transport
// Find the specified device by name
foreach (LivePacketDevice device in LivePacketDevice.AllLocalMachine)
{
if (device.Name == iface.Name)
if (device.Name == iface.Name && device.GetMacAddress() == iface.MacAddress)
{
_interface = device;
break;

View File

@@ -1,4 +1,5 @@
using System;
using PcapDotNet.Packets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -10,7 +11,10 @@ namespace IFS.Transport
/// PacketInterface provides an abstraction over a transport (Ethernet, IP, Carrier Pigeon)
/// which can provide raw packets.
/// </summary>
interface IPacketInterface
public interface IPacketInterface
{
void SendPacket(Packet p);
object GetDeviceAddress();
}
}