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; private final onNewNeigborTrigger:SignalTrigger = Signal.trigger(); private final routingTable:Map = 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(response.toID,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; } var fullCost = cost+interf.getBaseRoutingCost(); if (this.routingTable.exists(toID)){ if (this.routingTable[toID].cost > fullCost){ Log.info("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.info("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; } }