1 module libsweatyballs.engine.handlers;
2 
3 import libsweatyballs.link.unit;
4 import libsweatyballs.link.message.core;
5 import libsweatyballs.engine.core;
6 import gogga;
7 import google.protobuf;
8 import std.string : cmp;
9 import std.conv : to;
10 import libsweatyballs.router.table : Route;
11 import std.socket : Address;
12 import libsweatyballs.zwitch.neighbor : Neighbor;
13 import libsweatyballs.link.core : Link;
14 import std.datetime : SysTime;
15 
16 public __gshared Engine engine;
17 
18 public void advHandler(LinkUnit unit)
19 {
20     /**
21     * Message details
22     *
23     * 1. Public key of Link Neighbor
24     * 2. Signature of Link Neighbor
25     * 3. Neighbor port of LinkNeighbor
26     * 4. Message type (also from LinkUnit address)
27     * 5. Payload
28     */
29     link.LinkMessage message = unit.getMessage();
30     link.LinkMessageType mType = message.type;
31     Address sender = unit.getSender();
32     string identity = message.publicKey;
33     ushort neighborPort = to!(ushort)(message.neighborPort);
34     ubyte[] msgPayload = message.payload;
35 
36 
37     Address neighborAddress = Link.getNeighborIPAddress(sender, neighborPort);
38     Neighbor neighbor = new Neighbor(identity, neighborAddress, unit.getLink());
39 
40     Advertisement advMsg = fromProtobuf!(link.Advertisement)(msgPayload);
41 
42     /* Get the routes being advertised */
43     RouteEntry[] routes = advMsg.routes;
44 
45     /* TODO: Do router2router verification here */
46 
47     /* Add each route to the routing table */
48     foreach(RouteEntry route; routes)
49     {
50         uint metric = route.metric;
51         SysTime routeCreationTime = SysTime.fromISOString(route.creationTime);
52 
53         /**
54         * Create a new route with `nexthop` as the nexthop address
55         * Also set its metric to whatever it is +64
56         */
57         Route newRoute = new Route(route.address, neighbor, routeCreationTime, 100, metric+64);
58 
59         engine.getRouter().getTable().lockTable();
60        
61         /**
62         * TODO: Found it, only install routes if their updated metric on arrival is lesser than current route
63         * TODO: Search for existing route
64         * TODO: This might make above constraints nmeaningless, or well atleast the one above me (outer one not me thinks)
65         */
66         Route possibleExistingRoute = engine.getRouter().getTable().lookup(route.address);
67 
68         /* If no route exists then add it */
69         if(!possibleExistingRoute)
70         {
71             engine.getRouter().getTable().addRoute(newRoute);
72         }
73         /* If a route exists only install it if current one has higher metric than advertised one */
74         else
75         {
76             /**
77             * If the route is already installed then simply update the creationTime field
78             */
79             if(possibleExistingRoute == newRoute)
80             {
81                 /* TODO: Even more reason to lock the table */
82                 possibleExistingRoute.updateCreationTime(routeCreationTime);
83             }
84             /**
85             * If the routes are not the same then go and check the metric to see if it is better
86             * and only install it if so
87             *
88             * TODO: Lock WHOLE table when doing these things (the below code is not logically safe)
89             */
90             else if(possibleExistingRoute.getMetric() > newRoute.getMetric())
91             {
92                 /* Remove the old one (higher metric than advertised route) */
93                 engine.getRouter().getTable().removeRoute(possibleExistingRoute);
94 
95                 /* Install the advertised route (lower metric than currently installed route) */
96                 engine.getRouter().getTable().addRoute(newRoute);
97             }
98             else
99             {
100                 /* TODO: Nothing needs to be done here */
101             }
102         }
103 
104         engine.getRouter().getTable().unlockTable();
105     }
106 }
107 
108 public void pktHandler(LinkUnit unit)
109 {
110     /**
111     * Message details
112     *
113     * 1. Public key of Link Neighbor
114     * 2. Signature of Link Neighbor
115     * 3. Neighbor port of LinkNeighbor
116     * 4. Message type (also from LinkUnit address)
117     * 5. Payload
118     */
119     link.LinkMessage message = unit.getMessage();
120     link.LinkMessageType mType = message.type;
121     Address sender = unit.getSender();
122     string identity = message.publicKey;
123     ushort neighborPort = to!(ushort)(message.neighborPort);
124     ubyte[] msgPayload = message.payload;
125 
126 
127     Address neighborAddress = Link.getNeighborIPAddress(sender, neighborPort);
128     Neighbor neighbor = new Neighbor(identity, neighborAddress, unit.getLink());
129 
130     gprintln("pktHandler!!!!!!!!!! "~unit.toString());
131 
132 
133     gprintln("Woohoo! PACKET received!", DebugType.WARNING);
134 
135     try
136     {
137 
138         /* TODO: Now check if destined to me, if so THEN attempt decrypt */
139         link.Packet packet = fromProtobuf!(link.Packet)(msgPayload);
140         gprintln("Payload (encrypted): "~to!(string)(packet.payload));
141 
142         /* Attempt decrypting with my key */
143         import crypto.rsa;
144         import std.string : cmp;
145 
146         /* TODO: Make sure decryotion passes, maybe add a PayloadBytes thing to use that */
147         ubyte[] decryptedPayload = RSA.decrypt(engine.getRouter().getIdentity().getKeys().privateKey, packet.payload);
148         gprintln("Payload (decrypted): "~cast(string)(decryptedPayload));
149 
150         /* Now see if it is destined to us */
151 
152         /* If it is destined to us (TODO: Accept it) */
153         if(cmp(packet.toKey, engine.getRouter().getIdentity().getKeys().publicKey) == 0)
154         {
155             gprintln("PACKET IS ACCEPTED TO ME", DebugType.WARNING);
156 
157             bool stat = engine.getSwitch().isNeighbour(packet.fromKey) !is null;
158             gprintln("WasPacketFromNeighbor: "~to!(string)(stat), DebugType.WARNING);
159 
160             /* Deliver this to the engine */
161             engine.newPacket(packet);
162         }
163         /* If it is not destined to me then forward it */
164         else
165         {
166             engine.getSwitch().forward(packet);
167             gprintln("PACKET IS FORWRDED", DebugType.WARNING);
168         }
169     
170     }
171     catch(ProtobufException)
172     {
173         gprintln("Failed to deserialize protobuff bytes", DebugType.ERROR);
174     }
175 }
176 
177 public void defaultHandler(LinkUnit unit)
178 {
179     gprintln("Unknown mesage type!!!!!!!!!! "~unit.toString());
180 }