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 newRouteEntry.creationTime = route.getCreationTime().toISOString(); 90 91 /* Add to list of RouteEntry-s */ 92 entries ~= newRouteEntry; 93 } 94 95 /* Set entries */ 96 advMsg.routes = entries; 97 98 return advMsg; 99 } 100 101 102 /** 103 * Send an IPv6 Multicast advertisement via link-local 104 * 105 * Sends to `ff02::1%<interface>:6666` 106 * 107 * TODO: Advertise self (we should insert our own route too perhaps or just do it here (eaiser)) 108 * 109 * TODO: We should split advertisements up, depending on the number, into seperate 110 * advertisements 111 */ 112 private void advertise(Link link) 113 { 114 /** 115 * Advertise a set of routes over a link to all neighbors 116 * on said link 117 * 118 * TODO: Shard these (batch them) 119 */ 120 router.getTable().lockTable(); 121 Route[] routes = router.getTable().getRoutes(); 122 router.getTable().unlockTable(); 123 advertiseRoute(link, routes); 124 } 125 126 /** 127 * Advertises the given `routes` on the given `link` 128 */ 129 private void advertiseRoute(Link link, Route[] routes) 130 { 131 /** 132 * Construct the Advertisement message for the given Link and 133 * set of routes 134 */ 135 Advertisement advMsg = makeAdvertisement(link, routes); 136 137 /** 138 * Construct a LinkMessage with type=ADVERTISEMENT and 139 * the encoded message above 140 * 141 * Set the public key to ours 142 * Set the signature (TODO) 143 * Set neighbor port 144 */ 145 LinkMessage linkMsg = new LinkMessage(); 146 linkMsg.type = LinkMessageType.ADVERTISEMENT; 147 linkMsg.payload = array(toProtobuf(advMsg)); 148 linkMsg.publicKey = router.getIdentity().getKeys().publicKey; 149 linkMsg.neighborPort = to!(string)(link.getR2RPort()); 150 // linkMsg.signature = 151 152 /* Encode the LinkMessage */ 153 byte[] messageBytes = cast(byte[])array(toProtobuf(linkMsg)); 154 ulong stats = mcastSock.sendTo(messageBytes, parseAddress("ff02::1%"~link.getInterface(), 6666)); 155 gprintln("Status"~to!(string)(stats)); 156 } 157 }