1 module libsweatyballs.router.advertiser; 2 3 import core.thread : Thread, dur; 4 import libsweatyballs.router.core : Router; 5 import libsweatyballs.link.core : Link; 6 import std.socket; 7 import gogga; 8 import std.conv : to; 9 import bmessage; 10 import libsweatyballs.link.message.core; 11 import google.protobuf; 12 import std.array : array; 13 import libsweatyballs.router.table : Route; 14 15 public final class Advertiser : Thread 16 { 17 private Router router; 18 private Socket mcastSock; 19 20 this(Router router) 21 { 22 /* Set the thread's worker function */ 23 super(&worker); 24 25 this.router = router; 26 27 /* Setup socket */ 28 setupSocket(); 29 } 30 31 private void setupSocket() 32 { 33 /* TODO: Error handling */ 34 mcastSock = new Socket(AddressFamily.INET6, SocketType.DGRAM, ProtocolType.UDP); 35 36 37 } 38 39 private void worker() 40 { 41 /* TODO: Implement me */ 42 while(true) 43 { 44 /* Cycle through each link and advertise on them */ 45 Link[] links = router.getEngine().getLinks(); 46 foreach(Link link; links) 47 { 48 gprintln("Sending advertisement on "~to!(string)(link)~" ..."); 49 advertise(link); 50 } 51 52 sleep(dur!("seconds")(2)); 53 } 54 } 55 56 public void launch() 57 { 58 start(); 59 } 60 61 public void shutdown() 62 { 63 /* TODO: Implement me */ 64 65 /* Close the multicast socket */ 66 mcastSock.close(); 67 } 68 69 /** 70 * TODO: Move this elsehwre 71 * 72 * Given a publicKey, nexthop this generates the advertisement message 73 */ 74 private link.Advertisement makeAdvertisement(Link link, Route[] routes) 75 { 76 /* The advertisement message */ 77 Advertisement advMsg = new Advertisement(); 78 79 /** 80 * Construct RouteEntry's 81 */ 82 RouteEntry[] entries; 83 foreach(Route route; routes) 84 { 85 /* Copy Route's data to a new RouteEntry */ 86 RouteEntry newRouteEntry = new RouteEntry(); 87 newRouteEntry.address = route.getAddress(); 88 newRouteEntry.metric = route.getMetric(); 89 90 /* Add to list of RouteEntry-s */ 91 entries ~= newRouteEntry; 92 } 93 94 /* Set entries */ 95 advMsg.routes = entries; 96 97 return advMsg; 98 } 99 100 101 /** 102 * Send an IPv6 Multicast advertisement via link-local 103 * 104 * Sends to `ff02::1%<interface>:6666` 105 * 106 * TODO: Advertise self (we should insert our own route too perhaps or just do it here (eaiser)) 107 * 108 * TODO: We should split advertisements up, depending on the number, into seperate 109 * advertisements 110 */ 111 private void advertise(Link link) 112 { 113 /** 114 * Advertise a set of routes over a link to all neighbors 115 * on said link 116 * 117 * TODO: Shard these (batch them) 118 */ 119 Route[] routes = router.getTable().getRoutes(); 120 advertiseRoute(link, routes); 121 } 122 123 /** 124 * Advertises the given `routes` on the given `link` 125 */ 126 private void advertiseRoute(Link link, Route[] routes) 127 { 128 /** 129 * Construct the Advertisement message for the given Link and 130 * set of routes 131 */ 132 Advertisement advMsg = makeAdvertisement(link, routes); 133 134 /** 135 * Construct a LinkMessage with type=ADVERTISEMENT and 136 * the encoded message above 137 * 138 * Set the public key to ours 139 * Set the signature (TODO) 140 * Set neighbor port 141 */ 142 LinkMessage linkMsg = new LinkMessage(); 143 linkMsg.type = LinkMessageType.ADVERTISEMENT; 144 linkMsg.payload = array(toProtobuf(advMsg)); 145 linkMsg.publicKey = router.getIdentity().getKeys().publicKey; 146 linkMsg.neighborPort = to!(string)(link.getR2RPort()); 147 // linkMsg.signature = 148 149 /* Encode the LinkMessage */ 150 byte[] messageBytes = cast(byte[])array(toProtobuf(linkMsg)); 151 ulong stats = mcastSock.sendTo(messageBytes, parseAddress("ff02::1%"~link.getInterface(), 6666)); 152 gprintln("Status"~to!(string)(stats)); 153 } 154 }