778 lines
26 KiB
C#
778 lines
26 KiB
C#
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Microsoft Research, Cambridge
|
|
* author: Yaron Weinsberg, Richard Black
|
|
*/
|
|
|
|
// #define DEBUG_CORE
|
|
|
|
using NetStack.Common;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Diagnostics;
|
|
using System.Threading;
|
|
|
|
using System.Net.IP;
|
|
using Drivers.Net;
|
|
using NetStack.NetDrivers;
|
|
using NetStack.Protocols;
|
|
|
|
using Microsoft.Singularity;
|
|
|
|
namespace NetStack.Runtime
|
|
{
|
|
/**
|
|
* This is the heart of the networking stack.
|
|
* - A single thread inside the core handles
|
|
* packet reception, Qos demultiplexing and
|
|
* later on multiplexing on a specific protocol queue.
|
|
* - The thread also handles user send & receive in order
|
|
* to avoid reentrancy deadlocks etc.
|
|
* - The Runtime uses an asynchronous IO in order to
|
|
* avoid locking and denial of service.
|
|
* - The Core's thread, never invokes user's callbacks
|
|
* directly, the user can poll for a message or get
|
|
* his thread to sleep, waiting for a new message event.
|
|
*/
|
|
public class Core : INetModule
|
|
{
|
|
private bool activated = false;
|
|
|
|
#if THREAD_POOL
|
|
private const int workerThreads = 16;
|
|
private const int maxWorkItems = workerThreads * 128;
|
|
private NetStackThreadPool! threadPool;
|
|
#endif
|
|
|
|
// the single core object
|
|
protected static Core! instance = new Core();
|
|
|
|
// disable default lazy creation (beforefieldinit)
|
|
static Core() {}
|
|
|
|
private Core()
|
|
{
|
|
worker = null;
|
|
stopped = false;
|
|
protocols = new SortedList();
|
|
packetTypes = new PacketTypes();
|
|
adapters = new ArrayList();
|
|
adapterNextId = 0;
|
|
theDispatcher = new Dispatcher();
|
|
muxTable = new ArrayList();
|
|
sessions = new SessionsTable();
|
|
outboundPacketsEvent = new AutoResetEvent(false);
|
|
inboundPacketsEvent = new AutoResetEvent(false);
|
|
#if THREAD_POOL
|
|
threadPool =
|
|
new NetStackThreadPool(workerThreads, maxWorkItems);
|
|
#endif
|
|
|
|
base();
|
|
// NB The demux is initialized when the first adapter is
|
|
// registered as it depends on the Core Instance being
|
|
// valid and it's not within this constructor.
|
|
// theDemux = null;
|
|
}
|
|
|
|
// get the single core instance
|
|
public static Core! Instance()
|
|
{
|
|
return instance;
|
|
}
|
|
|
|
#if THREAD_POOL
|
|
public NetStackThreadPool! ThreadPool {
|
|
get { return threadPool; }
|
|
}
|
|
#endif
|
|
|
|
[ System.Diagnostics.Conditional("DEBUG_CORE") ]
|
|
private static void DebugPrint(string format, params object[] args)
|
|
{
|
|
DebugStub.Print("Core: {0}",
|
|
__arglist(String.Format(format, args))
|
|
);
|
|
}
|
|
|
|
// create a session of a specific protocol
|
|
public Session CreateSession(string protocolName)
|
|
{
|
|
IProtocol p = GetProtocolByName(protocolName);
|
|
if (p == null) {
|
|
return null;
|
|
}
|
|
return (p.CreateSession());
|
|
}
|
|
|
|
// register a new session in the runtime
|
|
// notice that multiple user threads can register new
|
|
// sessions (multiple writers).
|
|
// In the Meanwhile the internal thread can scan the
|
|
// sessions in order to HandleOutgoingSessions
|
|
internal void RegisterSession(IProtocol! p, Session s)
|
|
{
|
|
lock (sessions.SyncRoot)
|
|
{
|
|
if (!sessions.Contains(p)) {
|
|
ArrayList l = new ArrayList();
|
|
l.Add(s);
|
|
sessions[p] = l;
|
|
}
|
|
else {
|
|
ArrayList l = (ArrayList!)sessions[p];
|
|
lock (l.SyncRoot) {
|
|
if (!l.Contains(s)) {
|
|
l.Add(s);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Deregister a session
|
|
internal void DeregisterSession(IProtocol! p, Session s)
|
|
{
|
|
lock (sessions.SyncRoot) {
|
|
if (!sessions.Contains(p))
|
|
Core.Panic("Error: Can't deregister a session for an unknown protocol!");
|
|
else {
|
|
ArrayList l = (ArrayList!)sessions[p];
|
|
lock (l.SyncRoot) {
|
|
l.Remove(s);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static int FindFreePort(ArrayList sessions)
|
|
{
|
|
const int PortMin = 1024;
|
|
const int PortMax = 65535;
|
|
|
|
if (sessions == null || sessions.Count == 0)
|
|
return PortMin;
|
|
|
|
int lastPort = PortMin;
|
|
foreach (Session! s in sessions) {
|
|
if (s.LocalPort - 1 > lastPort)
|
|
return s.LocalPort - 1;
|
|
if (lastPort > PortMin)
|
|
lastPort = s.LocalPort;
|
|
}
|
|
lastPort++;
|
|
if (lastPort > PortMax)
|
|
return -1;
|
|
return lastPort;
|
|
}
|
|
|
|
internal bool ChangeSessionLocalPort(Session! s, int newPort)
|
|
{
|
|
ArrayList tcpSessions = Core.Instance().GetSessions(s.Protocol);
|
|
|
|
// If no sessions registered yet, just do it...
|
|
if (tcpSessions == null) {
|
|
if (newPort == 0) {
|
|
newPort = FindFreePort(tcpSessions);
|
|
}
|
|
|
|
s.SetLocalPort((ushort) newPort);
|
|
return true;
|
|
}
|
|
|
|
// Take care to acquire the global sessions lock before the
|
|
// more specific lock for the TCP sessions list
|
|
lock (sessions.SyncRoot) {
|
|
lock (tcpSessions.SyncRoot) {
|
|
if (newPort == 0) {
|
|
// Find FreePort
|
|
newPort = FindFreePort(tcpSessions);
|
|
}
|
|
|
|
if (newPort < 0)
|
|
return false;
|
|
|
|
// Deregister session
|
|
Core.Instance().DeregisterSession(s.Protocol, s);
|
|
|
|
// Reregister session
|
|
s.SetLocalPort((ushort) newPort);
|
|
Core.Instance().RegisterSession(s.Protocol, s);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal ArrayList GetSessions(IProtocol! protocol)
|
|
{
|
|
return (ArrayList)sessions[protocol];
|
|
}
|
|
|
|
public int GetSessionCount(IProtocol! protocol)
|
|
{
|
|
ArrayList tmp = (ArrayList)sessions[protocol];
|
|
if (tmp != null) return tmp.Count;
|
|
return 0;
|
|
}
|
|
|
|
private bool HandleSessionsOutboundQueue(Session! s)
|
|
{
|
|
DebugPrint("HandleSession {0} paused = {1} queued {2}\n",
|
|
s.Uid, s.OutQueuePaused, s.outQueue.Count);
|
|
|
|
// Session may be paused if waiting on reception
|
|
// event, e.g. ARP response triggered by first
|
|
// outbound packet.
|
|
if (s.OutQueuePaused == true) {
|
|
return false;
|
|
}
|
|
|
|
NetPacket packet = s.GetPacket(s.outQueue, false, 0);
|
|
if (packet == null) {
|
|
return false;
|
|
}
|
|
|
|
if (packet.Mux == null)
|
|
packet.Mux = s.BoundMux;
|
|
s.Protocol.OnProtocolSend(packet);
|
|
|
|
// NOTE Special case; if this is a TCP session
|
|
// and we just transmitted the very last packet it will
|
|
// ever send, help out with the shutdown process by
|
|
// signalling this session closed.
|
|
TcpSession tcpS = s as TcpSession;
|
|
|
|
if ((tcpS != null) &&
|
|
(tcpS.stateContext == TCPFSM.CLOSED) &&
|
|
(tcpS.outQueue.Count == 0))
|
|
{
|
|
// That was the very last TCP frame for this session
|
|
tcpS.closedEvent.Set();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool IsAnyMuxBackLogged()
|
|
{
|
|
foreach (Multiplexer! m in this.muxTable) {
|
|
if (m.IsBackLogged) {
|
|
DebugPrint("BackLogged\n");
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private int GetMaxOutgoingPackets()
|
|
{
|
|
int n = ((Multiplexer!)this.muxTable[0]).FreeBufferSpace;
|
|
for (int i = 1; i < this.muxTable.Count; i++) {
|
|
n = Math.Min(n,
|
|
((Multiplexer!)this.muxTable[i]).FreeBufferSpace);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
static Random picker = new Random();
|
|
|
|
// handle outgoing queues...
|
|
// we handle outgoing queues of user sessions in two cases:
|
|
// 1. periodically using a timer
|
|
// 2. after handling received packets
|
|
internal NetStatus HandleOutgoingQueues(Dispatcher.CallbackArgs unused)
|
|
{
|
|
lock (sessions.SyncRoot)
|
|
{
|
|
DebugPrint("++++ OUTGOING QUEUE PASS ++++\n");
|
|
int todo = GetMaxOutgoingPackets();
|
|
|
|
DebugPrint("Driving Sessions (mux avail = {0})\n",
|
|
GetMaxOutgoingPackets());
|
|
|
|
DebugPrint("Mux max packets = {0}\n", todo);
|
|
bool morePackets = true;
|
|
while (todo > 0 && morePackets) {
|
|
morePackets = false;
|
|
|
|
// TODO: Shuffle order
|
|
// sessions are visited for some concept of
|
|
// fairness. This probably requires
|
|
// redesigning The protocol session storage
|
|
// because it's currently a hashtable and
|
|
// this does not give a particularly
|
|
// effective means to shuffle / rotate
|
|
// entries.
|
|
|
|
foreach (IProtocol! p in sessions.Keys) {
|
|
ArrayList! x = (ArrayList!)sessions[p];
|
|
int limit = x.Count;
|
|
int offset = picker.Next(x.Count);
|
|
for (int i = 0; i < limit; i++) {
|
|
Session! s = (Session!)x[(i + offset) % limit];
|
|
if (HandleSessionsOutboundQueue(s)) {
|
|
if (--todo == 0)
|
|
goto DoneDrivingQueues;
|
|
morePackets |= true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// To be really drive the outbound queue
|
|
// todo = GetMaxOutgoingPackets();
|
|
}
|
|
|
|
DoneDrivingQueues:
|
|
DebugPrint("Driving Mux (mux avail = {0})\n",
|
|
GetMaxOutgoingPackets());
|
|
|
|
for (int i = this.muxTable.Count - 1; i >= 0; i--) {
|
|
Multiplexer! m = (Multiplexer!)this.muxTable[i];
|
|
m.PushSendBuffer();
|
|
}
|
|
|
|
DebugPrint("Done Driving Mux (mux avail = {0})\n",
|
|
GetMaxOutgoingPackets());
|
|
|
|
DebugPrint("---- OUTGOING QUEUE PASS ----\n");
|
|
|
|
if (morePackets) {
|
|
// Make sure we wake up again
|
|
SignalOutboundPackets();
|
|
}
|
|
}
|
|
|
|
return NetStatus.Code.RT_OK;
|
|
}
|
|
|
|
// INetModule interface
|
|
// ---------------------
|
|
// get the module's name
|
|
public string ModuleName { get { return "Core"; } }
|
|
|
|
// get the modules version
|
|
public ushort ModuleVersion { get { return 0x01; } } // 0.1
|
|
|
|
public bool Initialize(ProtocolParams args)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// start module activity, module specific.
|
|
// it is called by the runtime
|
|
public bool StartModule()
|
|
{
|
|
if (stopped) {
|
|
worker.Start();
|
|
stopped = false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// stop module activity, module specific.
|
|
// it is called by the runtime
|
|
public bool StopModule()
|
|
{
|
|
if (!stopped) {
|
|
// Signal stop to dispatcher since worker thread
|
|
// is running dispatcher.
|
|
theDispatcher.Stop();
|
|
worker.Join();
|
|
stopped = true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// destroy module, free unmanaged resources if any.
|
|
// it is called by the runtime
|
|
public bool DestroyModule()
|
|
{
|
|
StopModule();
|
|
return true;
|
|
}
|
|
|
|
// ------------------------------------------------------
|
|
// Core's data
|
|
// ------------------------------------------------------
|
|
|
|
// Sorted List of adapters <adapter, adapterDetails>
|
|
private ArrayList! adapters;
|
|
|
|
// Id number of next adapter added
|
|
private int adapterNextId;
|
|
|
|
// the protocol list
|
|
private SortedList! protocols;
|
|
|
|
// the packet types list
|
|
public PacketTypes packetTypes;
|
|
|
|
// out internal thread
|
|
protected Thread worker;
|
|
|
|
// should the thread stop?
|
|
protected bool stopped;
|
|
|
|
// the dispatcher instance, implements the event driven logic
|
|
protected Dispatcher! theDispatcher;
|
|
internal Dispatcher! TheDispatcher { get { return theDispatcher; } }
|
|
|
|
// the demux object, intercepts packets as they come and
|
|
// classifies them into flows
|
|
protected DeMultiplexer theDemux;
|
|
internal DeMultiplexer! TheDemux { get { return theDemux; } }
|
|
|
|
private ArrayList muxTable;
|
|
|
|
// the runtime active sessions
|
|
protected SessionsTable sessions;
|
|
internal SessionsTable Sessions { get { return sessions; } }
|
|
|
|
// This event is used to signal that there are outbound packets
|
|
private AutoResetEvent outboundPacketsEvent;
|
|
private AutoResetEvent inboundPacketsEvent;
|
|
|
|
// ------------------------------------------------------
|
|
// Core specific methods
|
|
// ------------------------------------------------------
|
|
|
|
internal class AdapterArgs : Dispatcher.CallbackArgs
|
|
{
|
|
internal IAdapter adapter;
|
|
internal string deviceName;
|
|
internal int fwQueueSize;
|
|
|
|
internal AdapterArgs(IAdapter theAdapter,
|
|
string theDeviceName,
|
|
int theQueueSize)
|
|
{
|
|
adapter = theAdapter;
|
|
deviceName = theDeviceName;
|
|
fwQueueSize = theQueueSize;
|
|
}
|
|
}
|
|
|
|
private NetStatus RegisterAdapterInternal(Dispatcher.CallbackArgs args)
|
|
{
|
|
AdapterArgs aa = (AdapterArgs!)args;
|
|
|
|
if (theDemux == null) {
|
|
theDemux = new DeMultiplexer();
|
|
}
|
|
|
|
Core.Log("Registering {0}", aa.deviceName);
|
|
adapters.Add(new AdapterInfo(aa.adapter, aa.deviceName));
|
|
|
|
Multiplexer mux = new Multiplexer(new Queue(aa.fwQueueSize),
|
|
aa.adapter);
|
|
muxTable.Add(mux);
|
|
|
|
theDispatcher.AddCallback(
|
|
new Dispatcher.Callback(mux.OnAdapterSendComplete),
|
|
null, aa.adapter.GetWriteHandle()
|
|
);
|
|
|
|
theDispatcher.AddCallback(
|
|
new Dispatcher.Callback(theDemux.OnAdapterReceive),
|
|
new DemuxAdapterArgs(aa.adapter), aa.adapter.GetReadHandle()
|
|
);
|
|
|
|
Core.Log("Registered adapter: {0}", aa.deviceName);
|
|
|
|
return NetStatus.Code.RT_OK;
|
|
}
|
|
|
|
private NetStatus
|
|
DeregisterAdapterInternal(Dispatcher.CallbackArgs args)
|
|
{
|
|
AdapterArgs aa = (AdapterArgs!)args;
|
|
IAdapter ad = aa.adapter;
|
|
|
|
// XXX IP specific hack - should be replaced by a
|
|
// message to each module or some such.
|
|
IPModule ip = (IPModule)protocols["IP"];
|
|
if (ip != null) {
|
|
ip.HostConfiguration.Bindings.Flush(ad);
|
|
}
|
|
|
|
theDispatcher.RemoveCallback(ad.GetReadHandle());
|
|
theDispatcher.RemoveCallback(ad.GetWriteHandle());
|
|
|
|
foreach (AdapterInfo! ai in adapters) {
|
|
if (ai.Adapter == ad) {
|
|
adapters.Remove(ad);
|
|
break;
|
|
}
|
|
}
|
|
|
|
foreach (Multiplexer! m in muxTable) {
|
|
if (m.Adapter == ad) {
|
|
muxTable.Remove(m);
|
|
}
|
|
}
|
|
|
|
Core.Log("Deregistered adapter: {0}", aa.deviceName);
|
|
|
|
return NetStatus.Code.RT_OK;
|
|
}
|
|
|
|
public void RegisterAdapter(IAdapter ad,
|
|
string nsName,
|
|
int fwQueueSize)
|
|
{
|
|
theDispatcher.AddCallback(
|
|
new Dispatcher.Callback(this.RegisterAdapterInternal),
|
|
new AdapterArgs(ad, nsName, fwQueueSize)
|
|
);
|
|
}
|
|
|
|
public void DeregisterAdapter(IAdapter ad)
|
|
{
|
|
theDispatcher.AddCallback(
|
|
new Dispatcher.Callback(this.DeregisterAdapterInternal),
|
|
new AdapterArgs(ad, null, 0)
|
|
);
|
|
}
|
|
|
|
public IAdapter GetAdapterByDeviceName(string deviceName)
|
|
{
|
|
foreach (AdapterInfo! ai in adapters) {
|
|
if (ai.DeviceName == deviceName) {
|
|
return ai.Adapter;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get collection of AdapterInfo instances associated
|
|
/// with adapters.
|
|
/// </summary>
|
|
public ICollection! GetAdapterInfoCollection()
|
|
{
|
|
return adapters;
|
|
}
|
|
|
|
// return the mux for the given adapter
|
|
internal Multiplexer GetMuxForAdapter(IAdapter ad)
|
|
{
|
|
foreach (Multiplexer! m in muxTable) {
|
|
if (m.Adapter == ad) {
|
|
return m;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public bool RegisterProtocol(IProtocol! protocol)
|
|
{
|
|
try {
|
|
protocols[protocol.ModuleName] = protocol;
|
|
return true;
|
|
}
|
|
catch (ArgumentException)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public bool DeregisterProtocol(IProtocol! protocol)
|
|
{
|
|
IProtocol found = protocols[protocol.ModuleName] as IProtocol;
|
|
if (found == protocol) {
|
|
protocols.Remove(protocol.ModuleName);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// get a protocol reference identified by name
|
|
public IProtocol GetProtocolByName(string protocolName)
|
|
{
|
|
if (protocolName == null)
|
|
return null;
|
|
return protocols[protocolName] as IProtocol;
|
|
}
|
|
|
|
/**
|
|
* Dispatch an incoming packets
|
|
* this method actually drives the
|
|
* packet through the stack's modules.
|
|
*/
|
|
private NetStatus DispatchPacket(NetPacket! pkt)
|
|
{
|
|
// look at the ethernet headers...
|
|
EthernetAddress src, dst;
|
|
ushort prot = 0;
|
|
|
|
if (EthernetFormat.Read(pkt, out src, out dst, out prot)) {
|
|
IProtocol protocol = packetTypes.GetHandler(prot);
|
|
if (protocol != null) {
|
|
NetStatus res = protocol.OnProtocolReceive(pkt);
|
|
if (res == NetStatus.Code.PROTOCOL_PROCESSING) {
|
|
return NetStatus.Code.RT_OK;
|
|
}
|
|
if (res == NetStatus.Code.PROTOCOL_PANIC) {
|
|
Panic(String.Format("Protocol {0} panicked!!!",
|
|
protocol.ModuleName));
|
|
|
|
// if the protocol has finished with the packet, return it!
|
|
}
|
|
}
|
|
}
|
|
|
|
// no handler, return the packet
|
|
theDemux.TakeFreePacket(pkt);
|
|
return NetStatus.Code.RT_DROP_NO_HANDLER;
|
|
}
|
|
|
|
// get the protocol interface from an ID
|
|
// (ignore packet level protocols)
|
|
internal IProtocol GetProtocolFromID(byte prot)
|
|
{
|
|
IProtocol p = null;
|
|
|
|
// checkout the protocol list for this one
|
|
foreach (string retProtName in protocols.Keys) {
|
|
p = (IProtocol!)protocols[retProtName];
|
|
ushort pID = p.GetProtocolID();
|
|
if (EthernetFormat.IsEthernetProtocol(pID))
|
|
continue;
|
|
if (prot == (byte)pID)
|
|
break;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
public static void Panic(string reason)
|
|
{
|
|
Core.Log("NetStack Panic: {0}", reason);
|
|
DebugStub.Break();
|
|
#if !SINGULARITY
|
|
Environment.Exit(1);
|
|
#endif
|
|
}
|
|
|
|
public static void Panic(string format, params object[] args)
|
|
{
|
|
Core.Panic(String.Format(format, args));
|
|
}
|
|
|
|
public static void Log(string message)
|
|
{
|
|
DebugStub.Print("NetStack: {0}\n", __arglist(message));
|
|
}
|
|
|
|
public static void Log(string format, params object[] args)
|
|
{
|
|
Core.Log(String.Format(format, args));
|
|
}
|
|
|
|
public static void LogData(byte []! Data)
|
|
{
|
|
LogData(Data, 0, Data.Length);
|
|
}
|
|
|
|
public static void LogData(byte []! data, int offset, int length)
|
|
{
|
|
length = Math.Min(length, data.Length);
|
|
|
|
for (int i = offset; i < length; i += 16) {
|
|
DebugStub.Print("{0:x4} ", __arglist(i));
|
|
int n = Math.Min(16, length - i) + i;
|
|
for (int j = i; j < n; j++)
|
|
DebugStub.Print("{0:x2} ", __arglist(data[j]));
|
|
for (int j = n; j != i + 16; j++)
|
|
DebugStub.Print(" ");
|
|
DebugStub.Print(" ");
|
|
for (int j = i; j < n; j++) {
|
|
char c = '.';
|
|
if (data[j] > 31 && data[j] < 128)
|
|
c = (char)data[j];
|
|
DebugStub.Print("{0}", __arglist(c));
|
|
}
|
|
DebugStub.Print("\n");
|
|
}
|
|
}
|
|
|
|
// the core's activation routine, beware...
|
|
// (this is a go/no-go method)
|
|
public void Activate()
|
|
{
|
|
Core.Log("NetStack Core Runtime Active...");
|
|
|
|
// since all the protocols are initialized
|
|
// start them up (start module)
|
|
foreach (string protName in protocols.Keys) {
|
|
IProtocol protocol = (IProtocol!)protocols[protName];
|
|
if (protocol.StartModule() == false) {
|
|
Core.Panic("Module {0} failed to start, exit.",
|
|
protocol.ModuleName);
|
|
}
|
|
}
|
|
|
|
// register a callback to handle outgoing queues
|
|
theDispatcher.AddCallback(
|
|
new Dispatcher.Callback(this.HandleOutgoingQueues),
|
|
null, outboundPacketsEvent
|
|
);
|
|
|
|
// register a callback to handle incoming queue
|
|
theDispatcher.AddCallback(
|
|
new Dispatcher.Callback(this.HandleIncomingQueue),
|
|
null, inboundPacketsEvent
|
|
);
|
|
|
|
// create the worker
|
|
// now, pass control to the dispatcher...
|
|
worker = new Thread(new ThreadStart(theDispatcher.Execute));
|
|
worker.Start();
|
|
activated = true;
|
|
}
|
|
|
|
public void ProvisionDemux(int freePacketCount, int packetSize)
|
|
{
|
|
if (activated == true)
|
|
Core.Panic("Cannot provision demux after Core.Activate()");
|
|
theDemux = new DeMultiplexer();
|
|
}
|
|
|
|
private NetStatus HandleIncomingQueue(Dispatcher.CallbackArgs unused)
|
|
{
|
|
const int PacketsToHandleBeforeYield = 25;
|
|
|
|
int n = PacketsToHandleBeforeYield;
|
|
while (n-- > 0 && theDemux.PacketsReady) {
|
|
NetPacket p = theDemux.GetReceivedPacket();
|
|
if (p == null) {
|
|
break;
|
|
}
|
|
DispatchPacket(p);
|
|
}
|
|
if (theDemux.PacketsReady) {
|
|
SignalInboundPackets();
|
|
}
|
|
return NetStatus.Code.RT_OK;
|
|
}
|
|
|
|
// Call this to indicate that outbound packets are waiting
|
|
public void SignalOutboundPackets()
|
|
{
|
|
outboundPacketsEvent.Set();
|
|
}
|
|
|
|
// Call this to indicate that outbound packets are waiting
|
|
public void SignalInboundPackets()
|
|
{
|
|
inboundPacketsEvent.Set();
|
|
}
|
|
}
|
|
}
|