1 module libsweatyballs.engine.core; 2 3 import libsweatyballs.router.core : Router; 4 import libsweatyballs.router.table; 5 import libsweatyballs.zwitch.core : Switch; 6 import libsweatyballs.zwitch.neighbor; 7 import libsweatyballs.link.core : Link; 8 import core.sync.mutex : Mutex; 9 import libsweatyballs.engine.configuration : Config; 10 import std.conv : to; 11 import gogga; 12 import core.thread : Thread, dur; 13 import libsweatyballs.router.table : Route; 14 import std.socket : Address, parseAddress; 15 import libsweatyballs.link.message.core; 16 import std.container.slist; 17 import std.range; 18 import libsweatyballs.engine.handlers : engine, advHandler, pktHandler, defaultHandler; 19 import std.datetime : Clock; 20 21 /* TODO: Import for config thing */ 22 23 /** 24 * Engine 25 * 26 * Description: TODO 27 */ 28 public final class Engine : Thread 29 { 30 /** 31 * Network components 32 */ 33 private Router router; 34 private Switch zwitch; 35 36 /** 37 * Links the router can advertise over 38 */ 39 private Link[] links; 40 private Mutex linksMutex; 41 42 /** 43 * Received packets 44 */ 45 private SList!(Packet) packetQueue; 46 private Mutex packetQueueLock; 47 48 /** 49 * 1. This must read config given to it 50 * 2. Setups links 51 * 3. Create new Router with these links 52 * 4. Spawn a Switch that handles packet in/out 53 * 5. Pass the Switch the router 54 * 6. Start the switch 55 * 7. We must then mainloop and collect statistics and handle shutdown etc 56 */ 57 this(Config config) 58 { 59 /* TODO: Add comment */ 60 super(&worker); 61 62 /* TODO: Read config */ 63 parseConfig(config); 64 65 /* Initialize locks */ 66 initMutexes(); 67 68 /* Initialize the handler's module globals */ 69 initEngine(); 70 } 71 72 /** 73 * Initializes all the mutexes 74 */ 75 private void initMutexes() 76 { 77 linksMutex = new Mutex(); 78 packetQueueLock = new Mutex(); 79 } 80 81 public Link[] getLinks() 82 { 83 Link[] copy; 84 85 linksMutex.lock(); 86 foreach(Link link; links) 87 { 88 copy ~= link; 89 } 90 linksMutex.unlock(); 91 92 return copy; 93 } 94 95 /** 96 * This function will do an import which 97 * will initialize the module, any other 98 * thread who referes to a mobule's 99 * member also inits their own copy 100 * 101 * There is however a global field 102 * `__gshared` that all code using 103 * it refers to one entity, not 104 * several static members per each 105 * module 106 * 107 * This must be set here 108 */ 109 private void initEngine() 110 { 111 engine = this; 112 } 113 114 private void initLinkHandler(Link link) 115 { 116 /* Register a handler for advertisements */ 117 link.registerHandler(&advHandler, 0); 118 119 /* Register a handler for packets */ 120 link.registerHandler(&pktHandler, 1); 121 122 /* Register default handler */ 123 link.setDefaultHandler(&defaultHandler); 124 } 125 126 private void parseConfig(Config config) 127 { 128 /* TODO: Setup the tun adapter */ 129 tun = new TUNAdapter("sweatyballs0", AdapterType.TUN); 130 131 /* TODO: Set configuration parameter */ 132 133 /* Setup links */ 134 links = createLinks(config.links); 135 setupLinks(links); 136 137 /** 138 * Setup a new Router 139 */ 140 router = new Router(this, config.routerIdentity); 141 142 143 144 145 /* Setup a new Switch */ 146 zwitch = new Switch(this); 147 148 /* Add self neighbor to any link (try the first, TODO: Atleast one link is needed) */ 149 Address address = parseAddress("::", links[0].getR2RPort()); 150 Neighbor selfNeighbor = new Neighbor(router.getIdentity().getKeys().publicKey, address, links[0]); 151 152 153 Route route = new Route(router.getIdentity().getKeys().publicKey, selfNeighbor, Clock.currTime()); 154 route.setAgeibility(false); 155 156 router.getTable().addRoute(route); 157 158 } 159 160 public Router getRouter() 161 { 162 return router; 163 } 164 165 public Switch getSwitch() 166 { 167 return zwitch; 168 } 169 170 public void newPacket(Packet packet) 171 { 172 packetQueueLock.lock(); 173 packetQueue.insertAfter(packetQueue[], packet); 174 packetQueueLock.unlock(); 175 } 176 177 private Packet checkPacket() 178 { 179 Packet received; 180 181 /* Check for packet */ 182 packetQueueLock.lock(); 183 if(!packetQueue.empty()) 184 { 185 /** 186 * Dequeue a packet 187 * 188 * Get the Range internal 189 * (use auto as this is some butchered 190 * fucking templatised shit) 191 */ 192 received = (packetQueue[]).front(); 193 (packetQueue[]).popFront(); 194 } 195 packetQueueLock.unlock(); 196 197 198 199 return received; 200 201 } 202 203 /** 204 * processPacket 205 * 206 * This method is used when a packet arrives to the engine 207 * and is used to decide what to do with the packet, this 208 * could be: 209 * 210 * 1. If the packet's payload is recognizable as a Session 211 * control command, then it will attempt to get a new 212 * Session created 213 * 2. If not a Session control message then we (as of now) 214 * drop the packet. (TODO: We could keep it but eh, use 215 * Sessions rather please) 216 */ 217 private void processPacket(Packet packet) 218 { 219 220 } 221 222 223 /** 224 * FIXME: Remove this and set it up elsewhere 225 * 226 * This function is here to setup a tun adapter which will 227 * then push shit in and out or something 228 */ 229 import libtun.adapter; 230 231 232 233 private TUNAdapter tun; 234 235 private void worker() 236 { 237 238 239 240 241 while(true) 242 { 243 byte[] poes; 244 245 tun.receive(poes); 246 gprintln("TUNRecieve: "~to!(string)(poes)); 247 248 /** 249 * FIXME: Remove this, this is just testing code 250 */ 251 router.getTable().lockTable(); 252 Route[] routes = router.getTable().getRoutes(); 253 foreach(Route route; routes) 254 { 255 zwitch.sendPacket(route.getAddress(), cast(byte[])"Hello world"); 256 } 257 router.getTable().unlockTable(); 258 259 /** 260 * Check receiveve queue 261 */ 262 Packet packet = checkPacket(); 263 if(packet) 264 { 265 processPacket(packet); 266 } 267 268 Thread.sleep(dur!("seconds")(1)); 269 } 270 } 271 272 private Link[] createLinks(string[] interfaces) 273 { 274 Link[] createdLinks; 275 276 foreach(string interfaceName; interfaces) 277 { 278 createdLinks ~= new Link(interfaceName, this); 279 } 280 281 return createdLinks; 282 } 283 284 private void setupLinks(Link[] links) 285 { 286 gprintln("Begin link initailization"); 287 foreach(Link link; links) 288 { 289 gprintln("Initializing link "~to!(string)(link)~" ..."); 290 initLinkHandler(link); 291 link.launch(); 292 } 293 gprintln("Links have been initialized"); 294 } 295 296 public void launch() 297 { 298 /* Start the engine */ 299 start(); 300 301 /* Start router */ 302 router.launch(); 303 304 /* Start switch */ 305 zwitch.launch(); 306 307 /* Start collector */ 308 /* TODO: Add me */ 309 310 gprintln("Engine has started all threads and is now going to finish and return to constructor thread control"); 311 } 312 }