1
0
mirror of https://github.com/livingcomputermuseum/IFS.git synced 2026-01-29 21:30:54 +00:00
Files
livingcomputermuseum.IFS/PUP/DirectoryServices.cs

275 lines
9.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Threading.Tasks;
namespace IFS
{
public class HostAddress
{
public HostAddress(byte network, byte host)
{
Network = network;
Host = host;
}
public byte Network;
public byte Host;
/// <summary>
/// Non-existent address
/// </summary>
public static HostAddress Empty = new HostAddress(0, 0);
}
/// <summary>
/// Provides a basic database used by the Misc. Services to do name lookup and whatnot.
///
/// </summary>
public class DirectoryServices
{
private DirectoryServices()
{
// Get our host address; for now just hardcode it.
// TODO: need to define config files, etc.
_localHost = new HostAddress(1, 1);
// Load in hosts table from hosts file.
LoadHostTable();
Logging.Log.Write(Logging.LogLevel.Normal, "Directory services initialized.");
}
public string AddressLookup(HostAddress address)
{
//
// First look up the network. If specified network is Zero,
// we will assume our network number.
//
byte network = address.Network;
if (network == 0)
{
network = _localHost.Network;
}
if (_hostAddressTable.ContainsKey(network))
{
//
// We have entries for this network, see if the host is specified.
//
if (_hostAddressTable[network].ContainsKey(address.Host))
{
return _hostAddressTable[network][address.Host];
}
}
// Not found.
return null;
}
public HostAddress NameLookup(string hostName)
{
if (_hostNameTable.ContainsKey(hostName.ToLowerInvariant()))
{
return _hostNameTable[hostName.ToLowerInvariant()];
}
return null;
}
public static DirectoryServices Instance
{
get { return _instance; }
}
public HostAddress LocalHostAddress
{
get { return _localHost; }
}
public byte LocalNetwork
{
get { return _localHost.Network; }
}
public byte LocalHost
{
get { return _localHost.Host; }
}
private void LoadHostTable()
{
_hostAddressTable = new Dictionary<byte, Dictionary<byte, string>>();
_hostNameTable = new Dictionary<string, HostAddress>();
// TODO: do not hardcode path like this.
using (StreamReader sr = new StreamReader("Conf\\hosts.txt"))
{
int lineNumber = 0;
while (!sr.EndOfStream)
{
lineNumber++;
//
// A line is either:
// '#' followed by comment to EOL
// <inter-network name> <hostname>
// Any whitespace is ignored
//
// Format for Inter-Network name expressions is either:
// network#host# (to specify hosts on another network)
// or
// host# (to specify hosts on our network)
//
string line = sr.ReadLine().Trim().ToLowerInvariant();
if (line.StartsWith("#") || String.IsNullOrWhiteSpace(line))
{
// Comment or empty, just ignore
continue;
}
// Tokenize on whitespace
string[] tokens = line.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
// We need at least two tokens (inter-network name and one hostname)
if (tokens.Length < 2)
{
// Log warning and continue.
Logging.Log.Write(Logging.LogLevel.Warning,
String.Format("hosts.txt line {0}: Invalid syntax.", lineNumber));
continue;
}
// First token should be an inter-network name, which should end with '#'.
if (!tokens[0].EndsWith("#"))
{
// Log warning and continue.
Logging.Log.Write(Logging.LogLevel.Warning,
String.Format("hosts.txt line {0}: Improperly formed inter-network name '{1}'.", lineNumber, tokens[0]));
continue;
}
// tokenize on '#'
string[] networkTokens = tokens[0].Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries);
HostAddress host = new HostAddress(0, 0);
// 1 token means a local name, 2 means on other network, anything else is illegal
if (networkTokens.Length == 1)
{
try
{
host.Host = Convert.ToByte(networkTokens[0], 8);
host.Network = _localHost.Network;
}
catch
{
// Log warning and continue.
Logging.Log.Write(Logging.LogLevel.Warning,
String.Format("hosts.txt line {0}: Invalid host number in inter-network address '{1}'.", lineNumber, tokens[0]));
continue;
}
}
else if (networkTokens.Length == 2)
{
try
{
host.Network = Convert.ToByte(networkTokens[0], 8);
host.Host = Convert.ToByte(networkTokens[1], 8);
}
catch
{
// Log warning and continue.
Logging.Log.Write(Logging.LogLevel.Warning,
String.Format("hosts.txt line {0}: Invalid host or network number in inter-network address '{1}'.", lineNumber, tokens[0]));
continue;
}
}
else
{
// Log warning and continue.
Logging.Log.Write(Logging.LogLevel.Warning,
String.Format("hosts.txt line {0}: Improperly formed inter-network name '{1}'.", lineNumber, tokens[0]));
continue;
}
// Hash the host by one or more names
for (int i=1;i<tokens.Length;i++)
{
string hostName = tokens[i];
// Add to name table
if (_hostNameTable.ContainsKey(hostName))
{
// Duplicate name entry! Skip this line.
Logging.Log.Write(Logging.LogLevel.Warning,
String.Format("hosts.txt line {0}: Duplicate hostname '{1}'.", lineNumber, hostName));
break;
}
_hostNameTable.Add(hostName, host);
// Add to address table:
// - See if network has entry
Dictionary<byte, string> networkTable = null;
if (_hostAddressTable.ContainsKey(host.Network))
{
networkTable = _hostAddressTable[host.Network];
}
else
{
// No entry for this network yet, add it now
networkTable = new Dictionary<byte, string>();
_hostAddressTable.Add(host.Network, networkTable);
}
// Add to network table
if (networkTable.ContainsKey(host.Host))
{
// Duplicate host entry! Skip this line.
Logging.Log.Write(Logging.LogLevel.Warning,
String.Format("hosts.txt line {0}: Duplicate host ID '{1}'.", lineNumber, host.Host));
break;
}
networkTable.Add(host.Host, hostName);
}
}
}
}
/// <summary>
/// Points to us.
/// </summary>
private HostAddress _localHost;
/// <summary>
/// Hash table for address resolution; outer hash finds the dictionary
/// for a given network, inner hash finds names for hosts.
/// </summary>
private Dictionary<byte, Dictionary<byte, string>> _hostAddressTable;
/// <summary>
/// Hash table for name resolution.
/// </summary>
private Dictionary<string, HostAddress> _hostNameTable;
private static DirectoryServices _instance = new DirectoryServices();
}
}