idk routing stuff i guess
This commit is contained in:
17
src/kernel/net/INetworkInterface.hx
Normal file
17
src/kernel/net/INetworkInterface.hx
Normal file
@@ -0,0 +1,17 @@
|
||||
package kernel.net;
|
||||
|
||||
using tink.CoreApi;
|
||||
|
||||
/**
|
||||
A object that is able to send and receive messages.
|
||||
**/
|
||||
interface INetworkInterface {
|
||||
public function listen(chan: Int):Void;
|
||||
public function close(chan: Int):Void;
|
||||
public function isListening(chan: Int): Bool;
|
||||
public function closeAll(): Void;
|
||||
public function send(chan: Int,replyChan: Int,payload: Any):Void;
|
||||
public function name():String;
|
||||
public function getBaseRoutingCost():Int;
|
||||
public var onMessage (default, null): Signal<Package>;
|
||||
}
|
||||
47
src/kernel/net/Loopback.hx
Normal file
47
src/kernel/net/Loopback.hx
Normal file
@@ -0,0 +1,47 @@
|
||||
package kernel.net;
|
||||
|
||||
using tink.CoreApi;
|
||||
|
||||
/**
|
||||
Virtual network interface that handle
|
||||
**/
|
||||
class Loopback implements INetworkInterface {
|
||||
public static final instance:Loopback = new Loopback();
|
||||
|
||||
public var onMessage(default, null):Signal<Package>;
|
||||
|
||||
private final onMessageTrigger: SignalTrigger<Package> = Signal.trigger();
|
||||
private var openChans: Array<Int> = [];
|
||||
|
||||
private function new() {
|
||||
this.onMessage = onMessageTrigger.asSignal();
|
||||
}
|
||||
|
||||
public function listen(chan:Int) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public function close(chan:Int) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public function isListening(chan:Int):Bool {
|
||||
return this.openChans.contains(chan);
|
||||
}
|
||||
|
||||
public function closeAll() {
|
||||
this.openChans = [];
|
||||
}
|
||||
|
||||
public function send(chan:Int, replyChan:Int, payload:Any) {
|
||||
this.onMessageTrigger.trigger(payload);
|
||||
}
|
||||
|
||||
public function name():String {
|
||||
return "loopback";
|
||||
}
|
||||
|
||||
public function getBaseRoutingCost():Int {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,6 @@ using tink.CoreApi;
|
||||
import kernel.net.Package.NetworkID;
|
||||
import kernel.peripherals.Peripherals.Peripheral;
|
||||
import kernel.Log;
|
||||
import kernel.KernelEvents;
|
||||
import haxe.Exception;
|
||||
import kernel.Timer;
|
||||
import cc.OS;
|
||||
|
||||
@@ -18,145 +16,53 @@ using util.Extender.LambdaExtender;
|
||||
Used to send and recceive packages.
|
||||
**/
|
||||
class Net {
|
||||
/**
|
||||
Depends on: KernelEvents
|
||||
**/
|
||||
public static var instance:Net;
|
||||
public static inline final BRODCAST_PORT:Int = 65533;
|
||||
public static inline final MESSAGE_TIMEOUT:Int = 3;
|
||||
|
||||
public final onNewNeigbor:Signal<Int>;
|
||||
|
||||
public final networkID:NetworkID = OS.getComputerID();
|
||||
private final responseBus:Map<Int, Callback<Package>> = new Map();
|
||||
private final protoHandlers:Map<String, Callback<Package>> = new Map();
|
||||
private var allModems:Array<kernel.peripherals.Modem>;
|
||||
private final routingTable:Map<NetworkID, kernel.peripherals.Modem> = new Map();
|
||||
private final onNewNeigborTrigger:SignalTrigger<NetworkID> = Signal.trigger();
|
||||
private var interfaces:Array<INetworkInterface>;
|
||||
|
||||
@:allow(kernel.Init)
|
||||
private function new() {
|
||||
onNewNeigbor = onNewNeigborTrigger.asSignal();
|
||||
KernelEvents.instance.onModemMessage.handle(params -> {
|
||||
var pack:Package = {
|
||||
fromID: params.replyChannel,
|
||||
toID: params.channel,
|
||||
msgID: params.message.msgID,
|
||||
type: params.message.type,
|
||||
data: params.message.data,
|
||||
};
|
||||
this.interfaces = [for (e in Peripheral.instance.getModems()) e ]; // TODO: is this the way to do it?
|
||||
this.interfaces.push(Loopback.instance);
|
||||
|
||||
handelIncomming(pack, params.addr);
|
||||
});
|
||||
|
||||
allModems = Peripheral.instance.getModems();
|
||||
|
||||
open();
|
||||
discoverNeighbors();
|
||||
for (interf in interfaces){
|
||||
interf.onMessage.handle(pack -> handle(pack,interf));
|
||||
interf.listen(networkID);
|
||||
interf.listen(BRODCAST_PORT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Called when a new package comes in.
|
||||
**/
|
||||
private function handelIncomming(pack:Package, ?addr:String) {
|
||||
private function handle(pack:Package,interf: INetworkInterface) {
|
||||
switch pack.type {
|
||||
case Data(_):
|
||||
routeToProto(pack);
|
||||
case DataNoResponse(_):
|
||||
case Data(_) | DataNoResponse(_):
|
||||
// Let a local proccess handle it
|
||||
routeToProto(pack);
|
||||
case Response:
|
||||
// Got a response to a send message. Invoke the callback
|
||||
if (responseBus.exists(pack.msgID)) {
|
||||
responseBus[pack.msgID].invoke(pack);
|
||||
}
|
||||
case RouteDiscover(_) | RouteDiscoverResponse(_):
|
||||
handleRouteDiscover(pack, addr);
|
||||
// Delegate to Routing
|
||||
Routing.instance.handleRoutePackage(pack,interf);
|
||||
}
|
||||
}
|
||||
|
||||
private function newRoutDiscoverPackage():Package {
|
||||
var pack:Package = {
|
||||
type: RouteDiscover(getAllNeighbors()),
|
||||
toID: BRODCAST_PORT,
|
||||
msgID: generateMessageID(),
|
||||
fromID: networkID,
|
||||
data: null,
|
||||
}
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
/**
|
||||
Send out discover packages on all modems.
|
||||
**/
|
||||
private function discoverNeighbors() {
|
||||
for (modem in allModems) {
|
||||
var pack = newRoutDiscoverPackage();
|
||||
|
||||
modem.transmit(BRODCAST_PORT, networkID, pack);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Handle incomming packages that involve route discovery.
|
||||
**/
|
||||
private function handleRouteDiscover(pack:Package, addr:String) {
|
||||
addRoute(pack.fromID, addr);
|
||||
|
||||
var forward = getAllNeighbors().filter(i -> i == pack.fromID);
|
||||
|
||||
switch pack.type{
|
||||
case RouteDiscoverResponse(reachableIDs):
|
||||
for (id in reachableIDs) {
|
||||
addRoute(id, addr);
|
||||
}
|
||||
return; // Dont respond to a response
|
||||
case RouteDiscover(reachableIDs):
|
||||
for (id in reachableIDs) {
|
||||
addRoute(id, addr);
|
||||
}
|
||||
default:
|
||||
throw new Error("Expcted RouteDiscover or RouteDiscoverResponse type");
|
||||
}
|
||||
|
||||
// Respond to peer
|
||||
var response:Package = {
|
||||
toID: pack.fromID,
|
||||
fromID: networkID,
|
||||
msgID: pack.msgID,
|
||||
type: RouteDiscoverResponse(forward),
|
||||
data: null
|
||||
}
|
||||
|
||||
for (reponseModem in allModems.filter(m -> m.addr == addr)) {
|
||||
reponseModem.transmit(pack.fromID, networkID, response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Called when a route to a client has been disoverd.
|
||||
Its posible to be called multiple times with the same id but different addr.
|
||||
**/
|
||||
private function addRoute(toID:Int, addr:String) {
|
||||
Log.info("Added new route to " + toID + " via " + addr);
|
||||
routingTable.set(toID, allModems.find(item -> item.addr == addr));
|
||||
this.onNewNeigborTrigger.trigger(toID);
|
||||
}
|
||||
|
||||
public function getAllNeighbors():Array<Int> {
|
||||
return routingTable.mapi((index, item) -> index);
|
||||
}
|
||||
|
||||
private function generateMessageID():Int {
|
||||
return Std.random(2147483647); // TODO: better uniqe number
|
||||
}
|
||||
|
||||
/**
|
||||
Open all wireless and wired modem.
|
||||
**/
|
||||
private function open() {
|
||||
for (m in allModems) {
|
||||
m.open(networkID);
|
||||
m.open(BRODCAST_PORT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Send a message. Dont care if its reaches its destination nor it has a response.
|
||||
**/
|
||||
@@ -207,17 +113,8 @@ class Net {
|
||||
Just send the package to the right modem.
|
||||
**/
|
||||
private function sendRaw(pack:Package) {
|
||||
if (pack.toID == networkID) {
|
||||
// Loopback
|
||||
handelIncomming(pack);
|
||||
} else {
|
||||
if (routingTable.exists(pack.toID)) {
|
||||
routingTable[pack.toID].transmit(pack.toID, pack.fromID, pack);
|
||||
} else {
|
||||
// Route not found
|
||||
// TODO: forward package or report not reachable
|
||||
}
|
||||
}
|
||||
|
||||
Routing.instance.getIterfaceToId(pack.toID).send(pack.toID,pack.fromID,pack);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,8 +6,8 @@ enum PackageTypes {
|
||||
Data(proto:String);
|
||||
DataNoResponse(proto:String);
|
||||
Response;
|
||||
RouteDiscover(reachableIDs: Array<NetworkID>);
|
||||
RouteDiscoverResponse(reachableIDs: Array<NetworkID>);
|
||||
RouteDiscover(reachableIDs: Array<{id:NetworkID,cost:Int}>);
|
||||
RouteDiscoverResponse(reachableIDs: Array<{id:NetworkID,cost:Int}>);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
135
src/kernel/net/Routing.hx
Normal file
135
src/kernel/net/Routing.hx
Normal file
@@ -0,0 +1,135 @@
|
||||
package kernel.net;
|
||||
|
||||
import kernel.peripherals.Peripherals.Peripheral;
|
||||
import kernel.net.INetworkInterface;
|
||||
|
||||
using tink.CoreApi;
|
||||
|
||||
import kernel.net.Package.NetworkID;
|
||||
|
||||
@:structInit typedef Route = {
|
||||
interf:INetworkInterface,
|
||||
cost:Int
|
||||
}
|
||||
|
||||
/**
|
||||
Manages network routing.
|
||||
**/
|
||||
class Routing {
|
||||
/**
|
||||
Depends on: Peripheral
|
||||
**/
|
||||
public static var instance:Routing;
|
||||
|
||||
public final onNewNeigbor:Signal<Int>;
|
||||
|
||||
private final onNewNeigborTrigger:SignalTrigger<NetworkID> = Signal.trigger();
|
||||
private final routingTable:Map<NetworkID, Route> = new Map();
|
||||
|
||||
@:allow(kernel.Init)
|
||||
private function new() {
|
||||
this.onNewNeigbor = this.onNewNeigborTrigger.asSignal();
|
||||
}
|
||||
|
||||
@:allow(kernel.Init)
|
||||
private function init() {
|
||||
routingTable.set(Net.instance.networkID,{interf: Loopback.instance,cost:0});
|
||||
for (modem in Peripheral.instance.getModems()) {
|
||||
modem.send(Net.BRODCAST_PORT, Net.instance.networkID, newRoutDiscoverPackage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Handle incomming packages that involve route discovery.
|
||||
**/
|
||||
public function handleRoutePackage(pack:Package, interf:INetworkInterface):Void {
|
||||
addPossibleRoute(pack.fromID,interf,0);
|
||||
|
||||
var shouldRespond: Bool = switch pack.type {
|
||||
case RouteDiscoverResponse(routes):
|
||||
for (route in routes) {
|
||||
addPossibleRoute(route.id,interf,route.cost);
|
||||
}
|
||||
false;
|
||||
case RouteDiscover(routes):
|
||||
for (route in routes) {
|
||||
addPossibleRoute(route.id,interf,route.cost);
|
||||
}
|
||||
true;
|
||||
default:
|
||||
Log.error("Expected RouteDiscover or RouteDiscoverResponse type");
|
||||
false;
|
||||
};
|
||||
|
||||
if (!shouldRespond){
|
||||
return;
|
||||
}
|
||||
|
||||
// Respond to peer
|
||||
var response:Package = {
|
||||
toID: pack.fromID,
|
||||
fromID: Net.instance.networkID,
|
||||
msgID: null,
|
||||
type: RouteDiscoverResponse(genRouteList()),
|
||||
data: null
|
||||
}
|
||||
|
||||
interf.send(pack.fromID,Net.instance.networkID,response);
|
||||
}
|
||||
|
||||
private function genRouteList(): Array<{id:NetworkID,cost:Int}> {
|
||||
var routes: Array<{id:NetworkID,cost:Int}> = [];
|
||||
for (k => v in this.routingTable){
|
||||
routes.push({
|
||||
id: k,
|
||||
cost: v.cost
|
||||
});
|
||||
}
|
||||
return routes;
|
||||
}
|
||||
|
||||
private function newRoutDiscoverPackage():Package {
|
||||
var pack:Package = {
|
||||
type: RouteDiscover(genRouteList()),
|
||||
toID: Net.BRODCAST_PORT,
|
||||
msgID: null,
|
||||
fromID: Net.instance.networkID,
|
||||
data: null,
|
||||
}
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
/**
|
||||
Called when a route to a client has been disoverd.
|
||||
Its possible to be called multiple times with the same id but different addr.
|
||||
**/
|
||||
private function addPossibleRoute(toID:Int, interf:INetworkInterface, cost:Int) {
|
||||
if (toID == Net.instance.networkID){
|
||||
return;
|
||||
}
|
||||
|
||||
Log.debug("a");
|
||||
|
||||
var fullCost = cost+interf.getBaseRoutingCost();
|
||||
|
||||
if (this.routingTable.exists(toID)){
|
||||
if (this.routingTable[toID].cost > fullCost){
|
||||
Log.debug("Better route: " + toID + " -> " + interf.name() + ":$"+fullCost);
|
||||
this.routingTable[toID] = {interf:interf,cost:cost + interf.getBaseRoutingCost()};
|
||||
}
|
||||
}else{
|
||||
this.routingTable[toID] = {interf:interf,cost:cost + interf.getBaseRoutingCost()};
|
||||
Log.debug("New route: " + toID + " -> " + interf.name() + ":$"+fullCost);
|
||||
this.onNewNeigborTrigger.trigger(toID);
|
||||
}
|
||||
}
|
||||
|
||||
public function getIterfaceToId(networkID:NetworkID):INetworkInterface {
|
||||
if (networkID == Net.instance.networkID) {
|
||||
return Loopback.instance;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user