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 }