diff --git a/PUP/BSPManager.cs b/PUP/BSPManager.cs
index 3e976b1..557fb9f 100644
--- a/PUP/BSPManager.cs
+++ b/PUP/BSPManager.cs
@@ -18,7 +18,7 @@ namespace IFS
public class BSPChannel
{
- public BSPChannel(PUP rfcPup)
+ public BSPChannel(PUP rfcPup, UInt32 socketID)
{
_inputLock = new ReaderWriterLockSlim();
_outputLock = new ReaderWriterLockSlim();
@@ -30,6 +30,13 @@ namespace IFS
// TODO: init IDs, etc. based on RFC PUP
_start_pos = _recv_pos = _send_pos = rfcPup.ID;
+ // Set up socket addresses.
+ // The client sends the connection port it prefers to use
+ // in the RFC pup.
+ _clientConnectionPort = new PUPPort(rfcPup.Contents, 0);
+
+ // We create our connection port using a unique socket address.
+ _serverConnectionPort = new PUPPort(DirectoryServices.Instance.LocalHostAddress, socketID);
}
public PUPPort ClientPort
@@ -152,6 +159,10 @@ namespace IFS
}
+ ///
+ /// Invoked when the client sends an ACK
+ ///
+ ///
public void Ack(PUP ackPUP)
{
// Update receiving end stats (max PUPs, etc.)
@@ -216,7 +227,14 @@ namespace IFS
{
static BSPManager()
{
-
+ //
+ // Initialize the socket ID counter; we start with a
+ // number beyond the range of well-defined sockets.
+ // For each new BSP channel that gets opened, we will
+ // increment this counter to ensure that each channel gets
+ // a unique ID. (Well, until we wrap around...)
+ //
+ _nextSocketID = _startingSocketID;
}
@@ -235,9 +253,14 @@ namespace IFS
switch (type)
{
case PupType.RFC:
- {
- BSPChannel newChannel = new BSPChannel(p);
- _activeChannels.Add(newChannel.ClientPort.Socket, newChannel);
+ {
+ BSPChannel newChannel = new BSPChannel(p, GetNextSocketID());
+ _activeChannels.Add(newChannel.ServerPort.Socket, newChannel);
+
+ // Send RFC response to complete the rendezvous.
+ PUP rfcResponse = new PUP(PupType.RFC, p.ID, newChannel.ClientPort, newChannel.ServerPort, newChannel.ServerPort.ToArray());
+
+ Dispatcher.Instance.SendPup(rfcResponse);
return newChannel;
}
@@ -301,6 +324,33 @@ namespace IFS
return null;
}
+ private static UInt32 GetNextSocketID()
+ {
+ UInt32 next = _nextSocketID;
+
+ _nextSocketID++;
+
+ //
+ // Handle the wrap around case (which we're very unlikely to
+ // ever hit, but why not do the right thing).
+ // Start over at the initial ID. This is very unlikely to
+ // collide with any pending channels.
+ //
+ if(_nextSocketID < _startingSocketID)
+ {
+ _nextSocketID = _startingSocketID;
+ }
+
+ return next;
+ }
+
+
+ ///
+ /// Map from socket address to BSP channel
+ ///
private static Dictionary _activeChannels;
+
+ private static UInt32 _nextSocketID;
+ private static readonly UInt32 _startingSocketID = 0x1000;
}
}
diff --git a/PUP/Dispatcher.cs b/PUP/Dispatcher.cs
index 4b29e42..a2b6b5c 100644
--- a/PUP/Dispatcher.cs
+++ b/PUP/Dispatcher.cs
@@ -5,16 +5,11 @@ using System.Text;
using System.Threading.Tasks;
using IFS.Transport;
-using PcapDotNet.Packets;
-using PcapDotNet.Packets.Ethernet;
using IFS.Logging;
using PcapDotNet.Base;
namespace IFS
-{
-
-
-
+{
///
/// Dispatches incoming PUPs to the right protocol handler; sends outgoing PUPs over the network.
///
@@ -40,11 +35,13 @@ namespace IFS
{
// TODO: support multiple interfaces (for gateway routing, for example.)
// Also, this should not be ethernet-specific.
- _packetInterface = new Ethernet(i, OnPacketReceived);
+ _pupPacketInterface = new Ethernet(i);
+
+ _pupPacketInterface.RegisterReceiveCallback(OnPupReceived);
}
///
- /// Registers a new protocol with the dispatcher
+ /// Registers a new protocol with the dispatcher.
///
///
///
@@ -61,129 +58,36 @@ namespace IFS
public void SendPup(PUP p)
{
- //
- // 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))
+ _pupPacketInterface.Send(p);
+ }
+
+ private void OnPupReceived(PUP pup)
+ {
+ //
+ // Forward PUP on to registered endpoints.
+ //
+ if (_dispatchMap.ContainsKey(pup.DestinationPort.Socket))
{
- 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));
+ PUPProtocolEntry entry = _dispatchMap[pup.DestinationPort.Socket];
+ entry.ProtocolImplementation.RecvData(pup);
}
else
{
- // Log error, this should not happen.
- Log.Write(LogLevel.Error, String.Format("PUP destination address {0} is unknown.", p.DestinationPort.Host));
- }
-
+ // Not a protocol we handle; log it.
+ Log.Write(LogLevel.UnhandledProtocol | LogLevel.DroppedPacket, String.Format("Unhandled PUP protocol, socket {0}, dropped packet.", pup.DestinationPort.Socket));
+ }
}
-
- private void OnPacketReceived(Packet p)
- {
- // filter out PUPs, discard all other packets. Forward PUP on to registered endpoints.
- //
- if ((int)p.Ethernet.EtherType == 512) // 512 = pup type
- {
- PUP pup = new PUP(p.Ethernet.Payload.ToMemoryStream());
-
- //
- // 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)
- {
- 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 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. 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);
- }
- }
-
+
///
- /// Our interface to some kind of network
+ /// Our interface to a facility that can transmit/receive PUPs
///
- private IPacketInterface _packetInterface;
+ private IPupPacketInterface _pupPacketInterface;
///
/// Map from socket to protocol implementation
///
private Dictionary _dispatchMap;
- ///
- /// PUP<->Ethernet address map
- ///
- private Dictionary _pupToEthernetMap;
- private Dictionary _ethernetToPupMap;
-
private static Dispatcher _instance = new Dispatcher();
}
}
diff --git a/PUP/Transport/Ethernet.cs b/PUP/Transport/Ethernet.cs
index 151e4c1..9a10278 100644
--- a/PUP/Transport/Ethernet.cs
+++ b/PUP/Transport/Ethernet.cs
@@ -4,10 +4,12 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using PcapDotNet.Base;
using PcapDotNet.Core;
using PcapDotNet.Core.Extensions;
using PcapDotNet.Packets;
using PcapDotNet.Packets.Ethernet;
+using IFS.Logging;
namespace IFS.Transport
{
@@ -40,43 +42,95 @@ namespace IFS.Transport
///
/// Defines interface "to the metal" (raw ethernet frames) which may wrap the underlying transport (for example, winpcap)
///
- public class Ethernet : IPacketInterface
+ public class Ethernet : IPupPacketInterface
{
- public Ethernet(EthernetInterface iface, HandlePacket callback)
+ public Ethernet(EthernetInterface iface)
{
AttachInterface(iface);
+
+ // Set up maps
+ _pupToEthernetMap = new Dictionary(256);
+ _ethernetToPupMap = new Dictionary(256);
+ }
+
+ public void RegisterReceiveCallback(HandlePup callback)
+ {
_callback = callback;
- Open(false, int.MaxValue);
+ // Now that we have a callback we can start receiving stuff.
+ Open(false /* not promiscuous */, int.MaxValue);
BeginReceive();
}
+
- public void Open(bool promiscuous, int timeout)
+ public void Send(PUP p)
{
- _communicator = _interface.Open(0xffff, promiscuous ? PacketDeviceOpenAttributes.Promiscuous : PacketDeviceOpenAttributes.None, timeout);
- }
+ //
+ // 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), everything is on the same 'net.
+ // Just look up host address and find the MAC of the host to send it to.
+ //
+ if (_pupToEthernetMap.ContainsKey(p.DestinationPort.Host))
+ {
+ MacAddress destinationMac = _pupToEthernetMap[p.SourcePort.Host];
- ///
- /// Begin receiving packets, forever.
- ///
- public void BeginReceive()
- {
- _communicator.ReceivePackets(-1, ReceiveCallback);
- }
+ // Build the outgoing packet; place the source/dest addresses, type field and the PUP data.
+ EthernetLayer ethernetLayer = new EthernetLayer
+ {
+ Source = _interface.GetMacAddress(),
+ Destination = destinationMac,
+ EtherType = (EthernetType)_pupFrameType,
+ };
- public void SendPacket(Packet p)
- {
- _communicator.SendPacket(p);
- }
+ PayloadLayer payloadLayer = new PayloadLayer
+ {
+ Data = new Datagram(p.RawData),
+ };
- public object GetDeviceAddress()
- {
- return (object)_interface.GetMacAddress();
+ PacketBuilder builder = new PacketBuilder(ethernetLayer, payloadLayer);
+
+ // Send it over the 'net!
+ _communicator.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));
+ }
}
private void ReceiveCallback(Packet p)
- {
- _callback(p);
+ {
+ //
+ // Filter out PUPs, forward them on.
+ //
+ if ((int)p.Ethernet.EtherType == _pupFrameType)
+ {
+ PUP pup = new PUP(p.Ethernet.Payload.ToMemoryStream());
+
+ //
+ // 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 (at a higher, as-yet-unimplemented level between this
+ // and the Dispatcher).
+ //
+ if (pup.SourcePort.Network == 0 || pup.SourcePort.Network == DirectoryServices.Instance.LocalHostAddress.Network)
+ {
+ UpdateMACTable(pup, p);
+ _callback(pup);
+ }
+ else
+ {
+ // Not for our network.
+ Log.Write(LogLevel.DroppedPacket, String.Format("PUP is for network {0}, dropping.", pup.SourcePort.Network));
+ }
+ }
+ else
+ {
+ // Not a PUP, Discard the packet. We will not log this, so as to keep noise down.
+ //Log.Write(LogLevel.DroppedPacket, "Not a PUP. Dropping.");
+ }
}
private void AttachInterface(EthernetInterface iface)
@@ -99,9 +153,59 @@ namespace IFS.Transport
}
}
+ private void Open(bool promiscuous, int timeout)
+ {
+ _communicator = _interface.Open(0xffff, promiscuous ? PacketDeviceOpenAttributes.Promiscuous : PacketDeviceOpenAttributes.None, timeout);
+ }
+
+ ///
+ /// Begin receiving packets, forever.
+ ///
+ private void BeginReceive()
+ {
+ _communicator.ReceivePackets(-1, ReceiveCallback);
+ }
+
+ 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 host id on the network.
+ //
+ if (_pupToEthernetMap[p.SourcePort.Host] != e.Ethernet.Source)
+ {
+ Log.Write(LogLevel.DuplicateHostNumber,
+ String.Format("Duplicate host ID {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);
+ }
+ }
+
+ ///
+ /// PUP<->Ethernet address map
+ ///
+ private Dictionary _pupToEthernetMap;
+ private Dictionary _ethernetToPupMap;
+
private LivePacketDevice _interface;
private PacketCommunicator _communicator;
- private HandlePacket _callback;
+ private HandlePup _callback;
+
+ // Constants
+ private const ushort _pupFrameType = 512;
}
}
diff --git a/PUP/Transport/PacketInterface.cs b/PUP/Transport/PacketInterface.cs
index 183dc03..dd638bf 100644
--- a/PUP/Transport/PacketInterface.cs
+++ b/PUP/Transport/PacketInterface.cs
@@ -7,14 +7,17 @@ using System.Threading.Tasks;
namespace IFS.Transport
{
- ///
- /// PacketInterface provides an abstraction over a transport (Ethernet, IP, Carrier Pigeon)
- /// which can provide raw packets.
- ///
- public interface IPacketInterface
- {
- void SendPacket(Packet p);
- object GetDeviceAddress();
+ public delegate void HandlePup(PUP pup);
+
+ ///
+ /// IPupPacketInterface provides an abstraction over a transport (Ethernet, IP, Carrier Pigeon)
+ /// which can provide encapsulation for PUPs.
+ ///
+ public interface IPupPacketInterface
+ {
+ void Send(PUP p);
+
+ void RegisterReceiveCallback(HandlePup callback);
}
}