@@ -6,17 +6,22 @@ import { Position } from "../common";
66import { DeviceInfo , RightBar } from "../../graphics/right_bar" ;
77import { IpAddress , IPv4Packet } from "../../packets/ip" ;
88import { DeviceId , isRouter } from "../graphs/datagraph" ;
9- import { Texture } from "pixi.js" ;
10- import { MacAddress } from "../../packets/ethernet" ;
11- import { Packet } from "../packet" ;
9+ import { Texture , Ticker } from "pixi.js" ;
10+ import { EthernetFrame , MacAddress } from "../../packets/ethernet" ;
1211import { GlobalContext } from "../../context" ;
12+ import { sendRawPacket } from "../packet" ;
1313
1414export class Router extends NetworkDevice {
1515 static DEVICE_TEXTURE : Texture ;
1616
17- private packetQueueSize = 0 ;
17+ private processingPackets = false ;
18+ private processingProgress = 0 ;
19+ // Time in ms to process a single packet
20+ private timePerPacket = 250 ;
21+
22+ private packetQueue : IPv4Packet [ ] = [ ] ;
23+ // TODO: we should count this in bytes
1824 private maxQueueSize = 5 ;
19- private timePerPacket = 1000 ;
2025
2126 static getTexture ( ) {
2227 if ( ! Router . DEVICE_TEXTURE ) {
@@ -55,60 +60,90 @@ export class Router extends NetworkDevice {
5560 return DeviceType . Router ;
5661 }
5762
58- async routePacket ( datagram : IPv4Packet ) : Promise < DeviceId | null > {
59- const device = this . viewgraph . getDataGraph ( ) . getDevice ( this . id ) ;
60- if ( ! device || ! isRouter ( device ) ) {
61- return null ;
63+ receiveDatagram ( datagram : IPv4Packet ) {
64+ if ( this . ip . equals ( datagram . destinationAddress ) ) {
65+ this . handlePacket ( datagram ) ;
66+ return ;
6267 }
63- if ( this . packetQueueSize >= this . maxQueueSize ) {
68+ this . addPacketToQueue ( datagram ) ;
69+ }
70+
71+ addPacketToQueue ( datagram : IPv4Packet ) {
72+ if ( this . packetQueue . length >= this . maxQueueSize ) {
6473 console . debug ( "Packet queue full, dropping packet" ) ;
65- return null ;
74+ return ;
75+ }
76+ this . packetQueue . push ( datagram ) ;
77+ // Start packet processor if not already running
78+ if ( ! this . processingPackets ) {
79+ Ticker . shared . add ( this . processPacket , this ) ;
80+ this . processingPackets = true ;
81+ }
82+ }
83+
84+ processPacket ( ticker : Ticker ) {
85+ this . processingProgress += ticker . deltaMS ;
86+ if ( this . processingProgress < this . timePerPacket ) {
87+ return ;
88+ }
89+ this . processingProgress -= this . timePerPacket ;
90+ const datagram = this . packetQueue . pop ( ) ;
91+ const devices = this . routePacket ( datagram ) ;
92+
93+ if ( ! devices || devices . length === 0 ) {
94+ return ;
95+ }
96+ for ( const nextHopId of devices ) {
97+ // Wrap the datagram in a new frame
98+ const nextHop = this . viewgraph . getDevice ( nextHopId ) ;
99+ if ( ! nextHop ) {
100+ console . error ( "Next hop not found" ) ;
101+ continue ;
102+ }
103+ const newFrame = new EthernetFrame ( this . mac , nextHop . mac , datagram ) ;
104+ sendRawPacket ( this . viewgraph , this . id , newFrame ) ;
105+ }
106+
107+ // Stop processing packets if queue is empty
108+ if ( this . packetQueue . length === 0 ) {
109+ Ticker . shared . remove ( this . processPacket , this ) ;
110+ this . processingPackets = false ;
111+ this . processingProgress = 0 ;
112+ return ;
113+ }
114+ }
115+
116+ routePacket ( datagram : IPv4Packet ) : DeviceId [ ] {
117+ const device = this . viewgraph . getDataGraph ( ) . getDevice ( this . id ) ;
118+ if ( ! device || ! isRouter ( device ) ) {
119+ return ;
66120 }
67- this . packetQueueSize += 1 ;
68- console . debug ( "Processing packet, queue size:" , this . packetQueueSize ) ;
69- await new Promise ( ( resolve ) => setTimeout ( resolve , this . timePerPacket ) ) ;
70- this . packetQueueSize -= 1 ;
71121
72122 const result = device . routingTable . find ( ( entry ) => {
73123 if ( entry . deleted ) {
74- console . log ( "Skipping deleted entry:" , entry ) ;
124+ console . debug ( "Skipping deleted entry:" , entry ) ;
75125 return false ;
76126 }
77127 const ip = IpAddress . parse ( entry . ip ) ;
78128 const mask = IpAddress . parse ( entry . mask ) ;
79- console . log ( "Considering entry:" , entry ) ;
129+ console . debug ( "Considering entry:" , entry ) ;
80130 return datagram . destinationAddress . isInSubnet ( ip , mask ) ;
81131 } ) ;
82- console . log ( "Result:" , result ) ;
83- return result === undefined ? null : result . iface ;
84- }
85132
86- async receiveDatagram ( packet : Packet ) : Promise < DeviceId | null > {
87- const datagram = packet . rawPacket . payload ;
88- if ( ! ( datagram instanceof IPv4Packet ) ) {
89- return null ;
133+ if ( ! result ) {
134+ console . warn ( "No route found for" , datagram . destinationAddress ) ;
135+ return [ ] ;
90136 }
91- if ( this . ip . equals ( datagram . destinationAddress ) ) {
92- this . handlePacket ( datagram ) ;
93- return null ;
94- }
95- // a router changed forward datagram to destination, have to change current destination mac
96- const dstDevice = this . viewgraph . getDeviceByIP ( datagram . destinationAddress ) ;
97- if ( ! dstDevice ) {
98- console . error ( "Destination device not found" ) ;
99- return null ;
100- }
101- const path = this . viewgraph . getPathBetween ( this . id , dstDevice . id ) ;
102- let dstMac = dstDevice . mac ;
103- if ( ! path ) return null ;
104- for ( const id of path . slice ( 1 ) ) {
105- const device = this . viewgraph . getDevice ( id ) ;
106- if ( device instanceof NetworkDevice ) {
107- dstMac = device . mac ;
108- break ;
109- }
137+
138+ const devices = this . viewgraph
139+ . getDataGraph ( )
140+ . getConnectionsInInterface ( this . id , result . iface ) ;
141+
142+ if ( ! devices ) {
143+ console . error ( "Current device doesn't exist!" , this . id ) ;
144+ return [ ] ;
110145 }
111- packet . rawPacket . destination = dstMac ;
112- return this . routePacket ( datagram ) ;
146+
147+ return devices ;
113148 }
114149}
0 commit comments