1 module libsweatyballs.router.table; 2 3 import std.socket : Address; 4 import core.sync.mutex : Mutex; 5 import std.conv : to; 6 import std.string : cmp; 7 import std.datetime.stopwatch : StopWatch; 8 import std.datetime : Duration; 9 import gogga; 10 import libsweatyballs.zwitch.neighbor; 11 import std.datetime; 12 13 /** 14 * Route 15 * 16 * Description: TODO 17 */ 18 public final class Route 19 { 20 // We must know our self-route and add it too somewhere 21 //private __gshared Identity d; 22 private string address; 23 private Neighbor nexthop; 24 private uint metric; 25 26 /** 27 * TODO: Set these and add a loop watcher to 28 * the table 29 */ 30 private long timeout; 31 32 /* TODO: Either guarantee fast updates or don't expire ourself AT ALL */ 33 private bool ageibility = true; 34 35 private SysTime creationTime; 36 37 this(string address, Neighbor nexthop, SysTime creationTime, long timeout = 100, uint metric = 64) 38 { 39 this.address = address; 40 this.nexthop = nexthop; 41 this.timeout = timeout; 42 this.metric = metric; 43 44 this.creationTime = creationTime; 45 } 46 47 public void updateCreationTime(SysTime creationTime) 48 { 49 this.creationTime = creationTime; 50 } 51 52 public string getAddress() 53 { 54 return address; 55 } 56 57 public SysTime getCreationTime() 58 { 59 return creationTime; 60 } 61 62 public Neighbor getNexthop() 63 { 64 return nexthop; 65 } 66 67 public uint getMetric() 68 { 69 return metric; 70 } 71 72 public void setAgeibility(bool age) 73 { 74 ageibility = age; 75 } 76 77 public override string toString() 78 { 79 return "Route (To: "~address~", Via: "~to!(string)(nexthop)~", Metric: "~to!(string)(metric)~", Age: "~to!(string)(getAge())~")"; 80 } 81 82 public long getAge() 83 { 84 /* Get the current time */ 85 SysTime currentTime = Clock.currTime(); 86 87 return currentTime.toUnixTime() - creationTime.toUnixTime(); 88 } 89 90 public bool isExpired() 91 { 92 return (getAge()) > timeout; 93 } 94 95 public override bool opEquals(Object other) 96 { 97 Route otherRoute = cast(Route)other; 98 99 /* TODO: Add other comparators such as next hops */ 100 101 return cmp(otherRoute.getAddress(), this.getAddress()) == 0 && 102 otherRoute.getNexthop() == this.getNexthop() && 103 otherRoute.getMetric() == this.getMetric(); 104 } 105 } 106 107 /** 108 * Table 109 * 110 * Description: TODO 111 */ 112 public final class Table 113 { 114 /** 115 * Routes 116 */ 117 private Route[] routes; 118 private Mutex routeLock; 119 120 this() 121 { 122 /* Initialize locks */ 123 initMutexes(); 124 } 125 126 public void lockTable() 127 { 128 routeLock.lock(); 129 } 130 131 public void unlockTable() 132 { 133 routeLock.unlock(); 134 } 135 136 /** 137 * Initialize the mutexes 138 */ 139 private void initMutexes() 140 { 141 routeLock = new Mutex(); 142 } 143 144 /** 145 * Get routes 146 * 147 * unsafe, must lock 148 */ 149 public Route[] getRoutes() 150 { 151 return routes; 152 } 153 154 /** 155 * Add a route 156 * 157 * unsafe, must lock 158 */ 159 public void addRoute(Route route) 160 { 161 /* Add the route (only if it doesn't already exist) */ 162 foreach(Route cRoute; routes) 163 { 164 /* FIXME: Make sure nexthop matches as well */ 165 if(cRoute == route) 166 { 167 goto no_add_route; 168 } 169 } 170 171 routes ~= route; 172 173 no_add_route: 174 } 175 176 public Route lookup(string address) 177 { 178 /* The matched route (if any) */ 179 Route match; 180 181 /* Add the route (only if it doesn't already exist) */ 182 foreach(Route route; routes) 183 { 184 /* FIXME: Make sure nexthop matches as well */ 185 if(cmp(route.getAddress(), address) == 0) 186 { 187 match = route; 188 } 189 } 190 191 return match; 192 } 193 194 /** 195 * Remove a route 196 */ 197 public void removeRoute(Route route) 198 { 199 /* New routing table */ 200 Route[] newRoutes; 201 202 /* Add the route (only if it doesn't already exist) */ 203 foreach(Route cRoute; routes) 204 { 205 /* FIXME: Make sure nexthop matches as well */ 206 if(cRoute != route) 207 { 208 newRoutes ~= cRoute; 209 } 210 } 211 212 routes = newRoutes; 213 } 214 }