Explorar el Código

Add name info store plus filesystem implementation

Billy Barrow hace 2 años
padre
commit
41ee13f1fd

+ 2 - 2
README.md

@@ -3,9 +3,9 @@
 A system for finding application peers and resolving names over mesh-like networks
 
 TODO:
-- Build propogation mechanism
-- Add propogation rate limit
 - Create a NameInfoStore, along with a FilesystemNameInfoStore and maybe a memory one too
+- Add `SYNC` request with `DOMAINS` response for quickly getting a new server peer up to date on domain information
+- Add propogation rate limit
 - Verify CertifiedNameInfo against system trust
 - Server class should implement (or inherit) a "Service" class, with another implementation being "DaemonClient" when a Riddle Daemon is implemented
 - Build tooling for generating and propogating NameInfo.

+ 4 - 3
src/infra/server/server.vala

@@ -2,12 +2,13 @@ using Riddle;
 
 public static int main(string[] args) {
 
-    if(args.length != 3) {
-        printerr("Please specify address and port only\n");
+    if(args.length != 4) {
+        printerr("Please specify address, port, and store location only\n");
         return -1;
     }
 
-    var server = new Server(args[1], (uint16)int.parse(args[2]));
+    var store = new FilesystemNameInfoStore(args[3]);
+    var server = new Server(args[1], (uint16)int.parse(args[2]), store);
 
     var loop = new MainLoop();
     //  server.run.begin((obj, res) => {

+ 4 - 3
src/lib/Client.vala

@@ -76,8 +76,9 @@ namespace Riddle {
             return responses.where(r => r.message_type == MessageType.OK).count();
         }
 
-        public int propogate(NameInfo info) {
-            var msg = new Message(MessageType.PROPOGATE, new string[] { info.name, "10" }, new string[] { info.get_encoded() });
+        public int propogate(NameInfo info, string? idempotency_token = null) {
+            var token = idempotency_token ?? GLib.Uuid.string_random();
+            var msg = new Message(MessageType.PROPOGATE, new string[] { info.name, "10", token }, new string[] { info.get_encoded() });
             var responses = raw_request(msg, servers, 10000, MessageType.OK);
             return responses.where(r => r.message_type == MessageType.OK).count();
         }
@@ -133,7 +134,7 @@ namespace Riddle {
 
         }
 
-        private bool server_equals(InetSocketAddress a1, InetSocketAddress a2) {
+        internal static bool server_equals(InetSocketAddress a1, InetSocketAddress a2) {
             return (a1.address.equal(a2.address) && a1.port == a2.port);
         }
 

+ 55 - 0
src/lib/FilesystemNameInfoStore.vala

@@ -0,0 +1,55 @@
+
+namespace Riddle {
+
+    public class FilesystemNameInfoStore : NameInfoStore {
+
+        private string path;
+
+        public FilesystemNameInfoStore(string store_path) {
+            path = store_path;
+        }
+
+        public override bool has_name (string name) {
+            return get_name_file(name).query_exists ();
+        }
+        public override NameInfo? get_name (string name) {
+            var file = get_name_file (name);
+            NameInfo info = null;
+            try {
+                var name_stream = new DataInputStream (file.read ());
+                var data = name_stream.read_line();
+                name_stream.close();
+
+                if(name.has_suffix (".rns")) {
+                    info = new DecentralisedNameInfo.from_string (data);
+                }
+                else {
+                    info = new CertifiedNameInfo.from_string (data);
+                }
+            }
+            catch(Error e) {
+                warning(@"Error while reading name from filesystem store: $(e.message)");
+            }
+
+            return info;
+        }
+        public override void save_name (NameInfo name_info) {
+            var file = get_name_file (name_info.name);
+            try {
+                var name_stream = new DataOutputStream (file.replace (null, false, FileCreateFlags.REPLACE_DESTINATION));
+                var data = name_info.get_encoded();
+                name_stream.put_string (@"$data\n");
+                name_stream.close();
+            }
+            catch(Error e) {
+                warning(@"Error while writing name to filesystem store: $(e.message)");
+            }
+        }
+
+        private File get_name_file(string name) {
+            return File.new_for_path (@"$path/$name.nameinfo");
+        }
+
+    }
+
+}

+ 20 - 0
src/lib/NameInfoStore.vala

@@ -0,0 +1,20 @@
+
+namespace Riddle {
+
+    public abstract class NameInfoStore : Object {
+
+        public abstract bool has_name(string name);
+        public abstract NameInfo? get_name(string name);
+        public abstract void save_name(NameInfo name_info);
+
+        public virtual bool is_outdated(string name, DateTime effective) {
+            if(!has_name(name)) {
+                return true;
+            }
+            var current_info = get_name(name);
+            return current_info.effective.difference(effective) < 0;
+        }
+
+    }
+
+}

+ 39 - 23
src/lib/Server.vala

@@ -11,15 +11,17 @@ namespace Riddle {
         private SocketService service;
         private Gee.HashMap<string, Invercargill.Sequence<Registration>> registrations = new Gee.HashMap<string, Invercargill.Sequence<Registration>>();
         private Gee.HashMap<string, RiddleEnvelope> riddles = new Gee.HashMap<string, RiddleEnvelope>();
-        private Gee.HashMap<string, NameInfo> names = new Gee.HashMap<string, NameInfo>();
+        private NameInfoStore names;
         private Client client;
 
-        private AsyncQueue<Gossip> gossip = new AsyncQueue<Gossip>();
+        private Fifo<Gossip> gossip = new Fifo<Gossip>();
+        private Gee.HashSet<string> gossip_idempotency_tokens = new Gee.HashSet<string>();
         private Thread<bool> gossip_thread;
         private uint16 port;
         
         
-        public Server(string address, uint16 port) throws Error {
+        public Server(string address, uint16 port, NameInfoStore name_store) throws Error {
+            this.names = name_store;
             this.port = port;
             var add = new InetAddress.from_string(address);
             service = new SocketService ();
@@ -64,14 +66,15 @@ namespace Riddle {
         }
 
         private bool spread_gossip() {
-            while (true) {
+            foreach (var goss in gossip) {
                 // What's the goss?
-                var goss = gossip.pop();
                 var members = get_group_registrations(goss.group).select<InetSocketAddress>(r => r.address);
+
                 print("Spreading gossip!\n");
                 client.raw_request(goss.message, members, 30000);
                 Thread.usleep(GOSSIP_INTERVAL_US);
             }
+            return true;
         }
 
         private Message service_message(Message msg, InetSocketAddress origin) throws Error {
@@ -122,6 +125,7 @@ namespace Riddle {
         private Message handle_propogate(Message msg) throws Error {
             var name = msg.arguments[0];
             var ttl = int.parse(msg.arguments[1]);
+            var token = msg.arguments[2];
             var encoded_name_info = msg.items[0];
 
             try {
@@ -151,7 +155,7 @@ namespace Riddle {
 
             if(ttl > 0) {
                 msg.arguments[1] = (ttl - 1).to_string();
-                gossip_to(RIDDLE_SERVER_GROUP, msg);
+                gossip_to(RIDDLE_SERVER_GROUP, msg, token);
             }
 
             return new Message(MessageType.OK, new string[0], new string[0]);
@@ -189,7 +193,7 @@ namespace Riddle {
             
             var to_forward = riddle_envelope.forward(port);
             if(to_forward != null) {
-                gossip_to(riddle_envelope.group_name, to_forward.to_message());
+                gossip_to(riddle_envelope.group_name, to_forward.to_message(), riddle_envelope.identifier);
             }
 
             // Pass to application to solve then compact when done.
@@ -265,18 +269,18 @@ namespace Riddle {
 
         private bool add_name_info_if_latest(NameInfo info) {
             lock(names) {
-                if(names.has_key(info.name) && names[info.name].effective.difference(info.effective) > 0) {
+                if(!names.is_outdated(info.name, info.effective)) {
                     return false;
                 }
-                names.set(info.name, info);
+                names.save_name(info);
             }
             return true;
         }
 
         private NameInfo? get_name_info(string name) {
             lock(names) {
-                if(names.has_key(name)) {
-                    return names[name];
+                if(names.has_name(name)) {
+                    return names.get_name(name);
                 }
             }
             return null;
@@ -291,20 +295,32 @@ namespace Riddle {
             return null;
         }
 
-        private void gossip_to(string group, Message message) {
-            var g = new Gossip() {
-                message = message,
-                group = group
-            };
-            gossip.push(g);
+        private void gossip_to(string group, Message message, string token) {
+            lock(gossip) {
+                if(gossip_idempotency_tokens.contains(token)){
+                    return;
+                }
+                var g = new Gossip() {
+                    message = message,
+                    group = group,
+                };
+                gossip.push(g);
+                gossip_idempotency_tokens.add(token);
+            }
         }
 
-        private void gossip_next(string group, Message message) {
-            var g = new Gossip() {
-                message = message,
-                group = group
-            };
-            gossip.push_front(g);
+        private void gossip_next(string group, Message message, string token) {
+            lock(gossip) {
+                if(gossip_idempotency_tokens.contains(token)){
+                    return;
+                }
+                var g = new Gossip() {
+                    message = message,
+                    group = group
+                };
+                gossip.push_start(g);
+                gossip_idempotency_tokens.add(token);
+            }
         }
 
     }

+ 2 - 0
src/lib/meson.build

@@ -31,6 +31,8 @@ sources += files('PeerDiscoverer.vala')
 sources += files('KnownHostDiscoverer.vala')
 sources += files('LanDiscoverer.vala')
 sources += files('RequestManager.vala')
+sources += files('NameInfoStore.vala')
+sources += files('FilesystemNameInfoStore.vala')