mirror of
https://github.com/livingcomputermuseum/IFS.git
synced 2026-03-08 03:49:22 +00:00
Implemented BreathOfLife, begun EFTP.
This commit is contained in:
@@ -636,8 +636,6 @@ namespace IFS.BSP
|
||||
}
|
||||
|
||||
// Nope. Request another ACK.
|
||||
// TODO: should probably error out of this if the client never becomes ready again...
|
||||
RequestClientStats();
|
||||
}
|
||||
|
||||
//
|
||||
@@ -671,6 +669,7 @@ namespace IFS.BSP
|
||||
Log.Write(LogType.Error, LogComponent.BSP, "Client lost more than a window of data, BSP connection is broken. Aborting.");
|
||||
SendAbort("Fatal BSP synchronization error.");
|
||||
BSPManager.DestroyChannel(this);
|
||||
_outputWindowLock.ExitUpgradeableReadLock();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -684,8 +683,9 @@ namespace IFS.BSP
|
||||
_outputWindow.RemoveRange(0, _outputWindowIndex);
|
||||
_outputWindowIndex = 0;
|
||||
_outputWindowLock.ExitWriteLock();
|
||||
_outputReadyEvent.Set();
|
||||
break;
|
||||
_outputReadyEvent.Set();
|
||||
|
||||
// Note: we don't break from the loop here; there may still be PUPs left in _outputWindow that need to be sent.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -720,6 +720,10 @@ namespace IFS.BSP
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Waits for an ACK from the client, "pinging" the client periodically. Will retry a number of times, if no
|
||||
/// ACK is received the channel is shut down.
|
||||
/// </summary>
|
||||
private void WaitForAck()
|
||||
{
|
||||
//
|
||||
|
||||
24
PUP/Boot/BootServer.cs
Normal file
24
PUP/Boot/BootServer.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IFS.Boot
|
||||
{
|
||||
public class BootServerProtocol : PUPProtocolBase
|
||||
{
|
||||
public BootServerProtocol()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by dispatcher to send incoming data destined for this protocol
|
||||
/// </summary>
|
||||
/// <param name="p"></param>
|
||||
public override void RecvData(PUP p)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
95
PUP/Boot/BreathOfLife.cs
Normal file
95
PUP/Boot/BreathOfLife.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using IFS.Logging;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
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()
|
||||
{
|
||||
Log.Write(LogType.Verbose, LogComponent.BreathOfLife, "Breath Of Life service starting. Broadcast interval is {0} milliseconds.", _bolPacketDelay);
|
||||
_bolThread = new Thread(BreathOfLifeThread);
|
||||
_bolThread.Start();
|
||||
}
|
||||
|
||||
private void BreathOfLifeThread()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
//
|
||||
// Send BOL
|
||||
//
|
||||
PUPProtocolDispatcher.Instance.Send(_bolPacket, DirectoryServices.Instance.LocalHost, _bolAddress, _bolPacketType);
|
||||
|
||||
Log.Write(LogType.Verbose, LogComponent.BreathOfLife, "Breath Of Life packet sent.");
|
||||
|
||||
//
|
||||
// Go to sleep.
|
||||
//
|
||||
Thread.Sleep(_bolPacketDelay);
|
||||
|
||||
//
|
||||
// That's it. Go home, do it again.
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Thread _bolThread;
|
||||
|
||||
private const ushort _bolPacketType = 0x182; // 602B
|
||||
private const byte _bolAddress = 0xff; // 377B (boot address)
|
||||
|
||||
private const int _bolPacketDelay = 5000; // 5 seconds
|
||||
|
||||
/// <summary>
|
||||
/// The gold-standard BOL packet, containing the Alto ethernet bootstrap code.
|
||||
/// Note that this does not contain padding for the ethernet header, the dispatcher adds those two words.
|
||||
/// </summary>
|
||||
private byte[] _bolPacket =
|
||||
{
|
||||
0x25, 0x7c, 0x80, 0x00, 0x41, 0x1f, 0x84, 0x00, 0x39, 0x19, 0xe8, 0x00,
|
||||
0x62, 0x05, 0x85, 0x30, 0x29, 0x77, 0x39, 0x7a, 0x62, 0x06, 0x29, 0x75, 0x39, 0x78, 0x62, 0x06,
|
||||
0x29, 0x74, 0x39, 0x76, 0x62, 0x06, 0x21, 0x75, 0x39, 0x75, 0x62, 0x05, 0xaa, 0x90, 0x4d, 0x7b,
|
||||
0x21, 0x7e, 0x62, 0x04, 0xa7, 0x00, 0x31, 0x69, 0x42, 0x89, 0x09, 0x0e, 0x00, 0x00, 0x02, 0x00,
|
||||
0x00, 0x16, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0x5a, 0x88, 0x2b, 0x00, 0x8e, 0x00, 0x4b, 0x00, 0x43, 0x09,
|
||||
0x21, 0x67, 0x42, 0x87, 0x21, 0x64, 0x62, 0x04, 0x0d, 0x59, 0x39, 0x4f, 0x31, 0x64, 0x53, 0x86,
|
||||
0x21, 0x48, 0x43, 0x85, 0x45, 0x56, 0x85, 0x30, 0x43, 0x81, 0x21, 0x58, 0x62, 0x04, 0x23, 0x81,
|
||||
0x82, 0x0c, 0x01, 0x0c, 0x62, 0x10, 0x19, 0xdf, 0x01, 0xfb, 0x19, 0x4f, 0x01, 0xec, 0x21, 0x4f,
|
||||
0x62, 0x04, 0x31, 0x02, 0x05, 0x02, 0x00, 0x00, 0x01, 0xda, 0x39, 0x4c, 0xe5, 0x0c, 0x01, 0xe6,
|
||||
0x22, 0x01, 0x29, 0x49, 0x8d, 0x0c, 0x01, 0xe2, 0x22, 0x03, 0xe7, 0x00, 0x3a, 0x05, 0x29, 0x41,
|
||||
0x8d, 0x0d, 0xfa, 0x0c, 0x01, 0xdb, 0x22, 0x00, 0x45, 0x35, 0x39, 0x2f, 0x5d, 0x25, 0x5b, 0xfd,
|
||||
0x5b, 0xfe, 0x82, 0xc0, 0x43, 0x00, 0x21, 0x37, 0x43, 0x01, 0x21, 0x1a, 0x43, 0x02, 0xa3, 0x00,
|
||||
0x43, 0x03, 0x22, 0x06, 0x43, 0x09, 0x22, 0x07, 0x43, 0x0a, 0x22, 0x08, 0x43, 0x0b, 0x22, 0x09,
|
||||
0x43, 0x06, 0x22, 0x0a, 0x43, 0x07, 0x22, 0x0b, 0x43, 0x08, 0x1b, 0x0c, 0x0d, 0x17, 0x15, 0x1c,
|
||||
0x0d, 0x16, 0x21, 0x11, 0x29, 0x1f, 0xb8, 0x00, 0x31, 0x0f, 0x05, 0x12, 0xfe, 0x1d, 0x00, 0x16,
|
||||
0x01, 0x0d, 0x01, 0x17, 0x01, 0x77, 0x01, 0x87, 0x01, 0xff, 0xff, 0xe9, 0xff, 0xa1, 0xff, 0x80,
|
||||
0x00, 0x95, 0xff, 0x94, 0x02, 0x0b, 0x01, 0xf4, 0x01, 0x19, 0x01, 0xca, 0x01, 0x9c, 0x01, 0xdd,
|
||||
0x01, 0x89, 0x01, 0x77, 0x01, 0x74, 0x01, 0x76, 0x00, 0x1e, 0x00, 0x02, 0x00, 0x03, 0x00, 0x0d,
|
||||
0x00, 0x18, 0x00, 0xff, 0x02, 0x00, 0xff, 0xf4, 0x01, 0x1e, 0x59, 0xd9, 0x51, 0xe8, 0x21, 0xeb,
|
||||
0x41, 0xe5, 0x85, 0x30, 0x41, 0xdf, 0x21, 0xf2, 0x62, 0x04, 0x21, 0xdc, 0x8a, 0xc4, 0x01, 0x06,
|
||||
0x21, 0xe3, 0x82, 0x0c, 0x19, 0xe1, 0x01, 0xfa, 0x05, 0xca, 0x39, 0xec, 0xef, 0xc0, 0x9d, 0x0d,
|
||||
0x29, 0xea, 0x22, 0x01, 0x8d, 0x0c, 0x01, 0xec, 0x22, 0x00, 0x29, 0xc3, 0x8d, 0x0c, 0x01, 0xe8,
|
||||
0x22, 0x03, 0xe7, 0x00, 0x29, 0xde, 0x8d, 0x05, 0x01, 0x04, 0xa3, 0x00, 0x83, 0x04, 0x01, 0xe0,
|
||||
0x49, 0xcc, 0x22, 0x05, 0x45, 0xda, 0x29, 0xb4, 0xa5, 0x05, 0x01, 0x04, 0x83, 0x05, 0x09, 0x04,
|
||||
0x01, 0xd7, 0x11, 0xae, 0x39, 0xac, 0x29, 0x03, 0xa1, 0x40, 0x83, 0x04, 0x01, 0xff, 0x41, 0xb2,
|
||||
0x41, 0xb4, 0x41, 0xb4, 0x85, 0x50, 0x62, 0x04, 0x21, 0xad, 0x82, 0x0d, 0x01, 0xfe, 0x8d, 0x0d,
|
||||
0x03, 0x00, 0x19, 0x9c, 0x01, 0xf1, 0x21, 0xbb, 0x62, 0x04, 0x01, 0x00, 0x62, 0x05, 0x84, 0x00,
|
||||
0xc6, 0x00, 0x39, 0xba, 0x29, 0xb7, 0xed, 0x00, 0x62, 0x05, 0x09, 0xb8, 0x21, 0xb3, 0x39, 0xb4,
|
||||
0xe8, 0x00, 0xce, 0x00, 0x62, 0x05, 0x29, 0xf2, 0xb5, 0x0c, 0xb6, 0x00, 0x21, 0x9e, 0x39, 0x0e,
|
||||
0x82, 0x0d, 0xdd, 0x0d, 0xb2, 0x01, 0x01, 0xec, 0x29, 0xa3, 0x49, 0x95, 0x82, 0x0d, 0x01, 0xe8,
|
||||
0x19, 0x93, 0x09, 0xa4, 0x21, 0x9c, 0x62, 0x04, 0x04, 0x00, 0xfd, 0xf4, 0x03, 0x01, 0x42, 0x02,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
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
|
||||
}; */
|
||||
}
|
||||
}
|
||||
37
PUP/EFTP/EFTPServer.cs
Normal file
37
PUP/EFTP/EFTPServer.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using IFS.BSP;
|
||||
using IFS.Logging;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.IO;
|
||||
|
||||
namespace IFS.EFTP
|
||||
{
|
||||
/// <summary>
|
||||
/// EFTP: It's like a really limited version of BSP.
|
||||
/// This is not a standalone server like FTP but provides routines for sending / receiving data
|
||||
/// via FTP, so that actual servers (Boot, Printing, etc.) can serve their clients.
|
||||
/// </summary>
|
||||
public class EFTPServer : PUPProtocolBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Called by dispatcher to send incoming data destined for this protocol.
|
||||
/// </summary>
|
||||
/// <param name="p"></param>
|
||||
public override void RecvData(PUP p)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class EFTPWorker
|
||||
{
|
||||
public EFTPWorker(BSPChannel channel)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using IFS.CopyDisk;
|
||||
using IFS.Boot;
|
||||
using IFS.CopyDisk;
|
||||
using IFS.FTP;
|
||||
using IFS.Transport;
|
||||
using System;
|
||||
@@ -27,13 +28,18 @@ namespace IFS
|
||||
PUPProtocolDispatcher.Instance.RegisterProtocol(new PUPProtocolEntry("Gateway Information", 2, ConnectionType.Connectionless, new GatewayInformationProtocol()));
|
||||
PUPProtocolDispatcher.Instance.RegisterProtocol(new PUPProtocolEntry("Misc Services", 0x4, ConnectionType.Connectionless, new MiscServicesProtocol()));
|
||||
PUPProtocolDispatcher.Instance.RegisterProtocol(new PUPProtocolEntry("Echo", 0x5, ConnectionType.Connectionless, new EchoProtocol()));
|
||||
PUPProtocolDispatcher.Instance.RegisterProtocol(new PUPProtocolEntry("Boot", 0x10, ConnectionType.Connectionless, new BootServerProtocol()));
|
||||
|
||||
// RTP/BSP based:
|
||||
PUPProtocolDispatcher.Instance.RegisterProtocol(new PUPProtocolEntry("CopyDisk", 0x15 /* 25B */, ConnectionType.BSP, new CopyDiskServer()));
|
||||
PUPProtocolDispatcher.Instance.RegisterProtocol(new PUPProtocolEntry("FTP", 0x3, ConnectionType.BSP, new FTPServer()));
|
||||
|
||||
// Breath Of Life
|
||||
BreathOfLife breathOfLifeServer = new BreathOfLife();
|
||||
|
||||
|
||||
// TODO: MAKE THIS CONFIGURABLE.
|
||||
PUPProtocolDispatcher.Instance.RegisterInterface(ifaces[2]);
|
||||
PUPProtocolDispatcher.Instance.RegisterInterface(ifaces[2]);
|
||||
|
||||
while (true)
|
||||
{
|
||||
|
||||
@@ -73,7 +73,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BCPLString.cs" />
|
||||
<Compile Include="BreathOfLife.cs" />
|
||||
<Compile Include="Boot\BootServer.cs" />
|
||||
<Compile Include="Boot\BreathOfLife.cs" />
|
||||
<Compile Include="BSP\BSPChannel.cs" />
|
||||
<Compile Include="BSP\BSPManager.cs" />
|
||||
<Compile Include="Configuration.cs" />
|
||||
@@ -81,6 +82,7 @@
|
||||
<Compile Include="CopyDisk\DiabloPack.cs" />
|
||||
<Compile Include="DirectoryServices.cs" />
|
||||
<Compile Include="EchoProtocol.cs" />
|
||||
<Compile Include="EFTP\EFTPServer.cs" />
|
||||
<Compile Include="Entrypoint.cs" />
|
||||
<Compile Include="FTP\FTPServer.cs" />
|
||||
<Compile Include="FTP\PropertyList.cs" />
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace IFS.Logging
|
||||
DirectoryServices = 0x20,
|
||||
PUP = 0x40,
|
||||
FTP = 0x80,
|
||||
BreathOfLife = 0x100,
|
||||
|
||||
All = 0x7fffffff
|
||||
}
|
||||
|
||||
@@ -76,7 +76,11 @@ namespace IFS
|
||||
|
||||
case PupType.NameLookupRequest:
|
||||
SendNameLookupReply(p);
|
||||
break;
|
||||
break;
|
||||
|
||||
case PupType.SendBootFileRequest:
|
||||
SendBootFile(p);
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.Write(LogComponent.MiscServices, String.Format("Unhandled misc. protocol {0}", p.Type));
|
||||
@@ -107,9 +111,7 @@ namespace IFS
|
||||
}
|
||||
|
||||
private void SendAltoTimeReply(PUP p)
|
||||
{
|
||||
|
||||
|
||||
{
|
||||
// So the Alto epoch is 1/1/1901. For the time being to keep things simple we're assuming
|
||||
// GMT and no DST at all. TODO: make this take into account our TZ, etc.
|
||||
//
|
||||
@@ -134,8 +136,6 @@ namespace IFS
|
||||
|
||||
UInt32 altoTime = (UInt32)timeSinceAltoEpoch.TotalSeconds;
|
||||
|
||||
|
||||
|
||||
// Build the response data
|
||||
AltoTime time = new AltoTime();
|
||||
time.DateTime = altoTime;
|
||||
@@ -237,5 +237,18 @@ namespace IFS
|
||||
PUPProtocolDispatcher.Instance.SendPup(errorReply);
|
||||
}
|
||||
}
|
||||
|
||||
private void SendBootFile(PUP p)
|
||||
{
|
||||
//
|
||||
// The request PUP contains the file number in the lower-order 16-bits of the pup ID.
|
||||
// Assuming the number is a valid bootfile, we start sending it to the client's port via EFTP.
|
||||
//
|
||||
uint fileNumber = p.ID & 0xffff;
|
||||
|
||||
Log.Write(LogType.Verbose, LogComponent.MiscServices, "Boot file request is for file {0}.", fileNumber);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,12 @@ namespace IFS
|
||||
InterruptReply = 21,
|
||||
AMark = 22,
|
||||
|
||||
// EFTP types
|
||||
EFTPData = 24,
|
||||
EFTPAck = 25,
|
||||
EFTPEnd = 26,
|
||||
EFTPAbort = 27,
|
||||
|
||||
// Misc. Services types
|
||||
StringTimeRequest = 128,
|
||||
StringTimeReply = 129,
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace IFS
|
||||
{
|
||||
Connectionless, /* echo, name resolution, etc. */
|
||||
BSP, /* FTP, Telnet, CopyDisk, etc. */
|
||||
EFTP, /* EFTP-based (boot, printing) */
|
||||
}
|
||||
|
||||
public struct PUPProtocolEntry
|
||||
@@ -33,7 +34,7 @@ namespace IFS
|
||||
public UInt32 Socket;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the type of connection (connectionless or BSP-based)
|
||||
/// Indicates the type of connection (connectionless, BSP-based or EFTP)
|
||||
/// </summary>
|
||||
public ConnectionType ConnectionType;
|
||||
|
||||
|
||||
@@ -37,7 +37,9 @@ namespace IFS
|
||||
{
|
||||
// TODO: support multiple interfaces (for gateway routing, for example.)
|
||||
// Also, this should not be ethernet-specific.
|
||||
_pupPacketInterface = new Ethernet(i);
|
||||
Ethernet enet = new Ethernet(i);
|
||||
_pupPacketInterface = enet as IPupPacketInterface;
|
||||
_rawPacketInterface = enet as IRawPacketInterface;
|
||||
|
||||
_pupPacketInterface.RegisterReceiveCallback(OnPupReceived);
|
||||
}
|
||||
@@ -63,6 +65,14 @@ namespace IFS
|
||||
_pupPacketInterface.Send(p);
|
||||
}
|
||||
|
||||
public void Send(byte[] data, byte source, byte destination, ushort frameType)
|
||||
{
|
||||
if (_rawPacketInterface != null)
|
||||
{
|
||||
_rawPacketInterface.Send(data, source, destination, frameType);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPupReceived(PUP pup)
|
||||
{
|
||||
//
|
||||
@@ -117,6 +127,11 @@ namespace IFS
|
||||
/// </summary>
|
||||
private IPupPacketInterface _pupPacketInterface;
|
||||
|
||||
/// <summary>
|
||||
/// Our interface to a facility that can transmit raw Ethernet frames
|
||||
/// </summary>
|
||||
private IRawPacketInterface _rawPacketInterface;
|
||||
|
||||
/// <summary>
|
||||
/// Map from socket to protocol implementation
|
||||
/// </summary>
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace IFS.Transport
|
||||
/// <summary>
|
||||
/// Defines interface "to the metal" (raw ethernet frames) which may wrap the underlying transport (for example, winpcap)
|
||||
/// </summary>
|
||||
public class Ethernet : IPupPacketInterface
|
||||
public class Ethernet : IPupPacketInterface, IRawPacketInterface
|
||||
{
|
||||
public Ethernet(EthernetInterface iface)
|
||||
{
|
||||
@@ -63,7 +63,6 @@ namespace IFS.Transport
|
||||
BeginReceive();
|
||||
}
|
||||
|
||||
|
||||
public void Send(PUP p)
|
||||
{
|
||||
//
|
||||
@@ -125,6 +124,75 @@ namespace IFS.Transport
|
||||
}
|
||||
}
|
||||
|
||||
public void Send(byte[] data, byte source, byte destination, ushort frameType)
|
||||
{
|
||||
// Build the outgoing data; this is:
|
||||
// 1st word: length of data following
|
||||
// 2nd word: 3mbit destination / source bytes
|
||||
// 3rd word: frame type (PUP)
|
||||
byte[] encapsulatedFrame = new byte[6 + data.Length];
|
||||
|
||||
// 3mbit Packet length
|
||||
encapsulatedFrame[0] = (byte)((data.Length / 2 + 2) >> 8);
|
||||
encapsulatedFrame[1] = (byte)(data.Length / 2 + 2);
|
||||
|
||||
// addressing
|
||||
encapsulatedFrame[2] = destination;
|
||||
encapsulatedFrame[3] = source;
|
||||
|
||||
// frame type
|
||||
encapsulatedFrame[4] = (byte)(frameType >> 8);
|
||||
encapsulatedFrame[5] = (byte)frameType;
|
||||
|
||||
// Actual data
|
||||
data.CopyTo(encapsulatedFrame, 6);
|
||||
|
||||
// Byte swap
|
||||
encapsulatedFrame = ByteSwap(encapsulatedFrame);
|
||||
|
||||
MacAddress destinationMac;
|
||||
if (destination != 0xff)
|
||||
{
|
||||
if (_pupToEthernetMap.ContainsKey(destination))
|
||||
{
|
||||
//
|
||||
// Use the existing map.
|
||||
//
|
||||
destinationMac = _pupToEthernetMap[destination];
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Nothing mapped for this PUP, do our best with it.
|
||||
//
|
||||
destinationMac = new MacAddress((UInt48)(_10mbitMACPrefix | destination));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 3mbit broadcast becomes 10mbit broadcast
|
||||
destinationMac = new MacAddress(_10mbitBroadcast);
|
||||
}
|
||||
|
||||
// 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)_3mbitFrameType,
|
||||
};
|
||||
|
||||
PayloadLayer payloadLayer = new PayloadLayer
|
||||
{
|
||||
Data = new Datagram(encapsulatedFrame),
|
||||
};
|
||||
|
||||
PacketBuilder builder = new PacketBuilder(ethernetLayer, payloadLayer);
|
||||
|
||||
// Send it over the 'net!
|
||||
_communicator.SendPacket(builder.Build(DateTime.Now));
|
||||
}
|
||||
|
||||
private void ReceiveCallback(Packet p)
|
||||
{
|
||||
//
|
||||
@@ -292,5 +360,12 @@ namespace IFS.Transport
|
||||
// The type used for 3mbit frames encapsulated in 10mb frames
|
||||
private readonly int _3mbitFrameType = 0xbeef; // easy to identify, ostensibly unused by anything of any import
|
||||
|
||||
// 5 byte prefix for 3mbit->10mbit addresses when sending raw frames; this is the convention ContrAlto uses.
|
||||
// TODO: this should be configurable.
|
||||
private UInt48 _10mbitMACPrefix = 0x0000aa010200; // 00-00-AA is the Xerox vendor code, used just to be cute.
|
||||
|
||||
// 10mbit broadcast address
|
||||
private UInt48 _10mbitBroadcast = (UInt48)0xffffffffffff;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,4 +20,17 @@ namespace IFS.Transport
|
||||
|
||||
void RegisterReceiveCallback(HandlePup callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IPupPacketInterface provides an abstraction over a transport (Ethernet, IP, Carrier Pigeon)
|
||||
/// which can provide encapsulation for raw Ethernet frames.
|
||||
///
|
||||
/// For the time being, this exists only to provide support for BreathOfLife packets (the only non-PUP
|
||||
/// Ethernet Packet the IFS suite deals with). This only requires being able to send packets, so no
|
||||
/// receive is implemented.
|
||||
/// </summary>
|
||||
public interface IRawPacketInterface
|
||||
{
|
||||
void Send(byte[] data, byte source, byte destination, ushort frameType);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user