Ejemplo n.º 1
0
        private async Task SynchronizationLoopTaskStart()
        {
            var isGreater = bluetoothAdapter.AdapterId.CompareTo(neighbor.AdapterId) > 0;
            var rateLimit = ChannelFactory.Timer(1000); //5000, 3000);

            try {
                while (true)
                {
                    if (isGreater)
                    {
                        await SynchronizeRemoteToLocalAsync().ConfigureAwait(false);
                        await SynchronizeLocalToRemoteAsync().ConfigureAwait(false);
                    }
                    else
                    {
                        await SynchronizeLocalToRemoteAsync().ConfigureAwait(false);
                        await SynchronizeRemoteToLocalAsync().ConfigureAwait(false);
                    }
                    await ChannelsExtensions.ReadAsync(rateLimit).ConfigureAwait(false);
                }
            } catch (NotConnectedException e) {
                DebugPrint("Got NotConnectedException " + e);
            } catch (Exception e) {
                DebugPrint("Got Exception " + e);
                throw;
            } finally {
                DebugPrint("Sync loop exiting");
                disconnectLatchChannel.SetIsClosed(true);
                neighbor.Disconnect();
            }
        }
Ejemplo n.º 2
0
        public async Task DiscoverAsync()
        {
            var rateLimit = ChannelFactory.Timer(1000); // 5000, 5000);
            var connectedNeighborContextsByAdapterId = new ConcurrentDictionary <Guid, NeighborConnectionContext>();

            while (true)
            {
                Debug("Starting discovery round!");
                var discoveryStartTime = DateTime.Now;
                var neighbors          = await bluetoothAdapter.DiscoverAsync().ConfigureAwait(false);

                var discoveryDurationSeconds = Math.Max(10, 3 * (DateTime.Now - discoveryStartTime).TotalSeconds);
                try {
                    var neighborsToConnectTo = new List <IBluetoothNeighbor>();
                    foreach (var neighbor in neighbors)
                    {
                        if (neighbor.IsConnected)
                        {
                            Debug("Connection Candidate: {0} already connected.", neighbor.AdapterId);
                            continue;
                        }

                        if (connectedNeighborContextsByAdapterId.ContainsKey(neighbor.AdapterId))
                        {
                            Debug("Connection Candidate: {0} already has connected context.", neighbor.AdapterId);
                            continue;
                        }

                        Debug("Connection Candidate: {0} looks like a go.", neighbor.AdapterId);
                        neighborsToConnectTo.Add(neighbor);
                    }
                    await Task.WhenAll(
                        neighborsToConnectTo.Select(neighbor => ChannelsExtensions.Go(async() => {
                        Debug("Attempt to connect to: {0}", neighbor.AdapterId);
                        var connected = await neighbor.TryHandshakeAsync(discoveryDurationSeconds).ConfigureAwait(false);
                        if (!connected)
                        {
                            Debug("Failed to connect to: {0}", neighbor.AdapterId);
                            return;
                        }
                        Debug("Successfully connected to: {0}", neighbor.AdapterId);

                        //                           Console.WriteLine("Discovered neighbor: " + neighbor.AdapterId);
                        var remoteMerkleTree  = merkleTreeFactory.CreateForNeighbor(neighbor.AdapterId.ToString("N"));
                        var connectionContext = new NeighborConnectionContext(identity, bluetoothAdapter, neighbor, broadcastMessageSerializer, localMerkleTree, remoteMerkleTree);
                        connectedNeighborContextsByAdapterId.AddOrThrow(neighbor.AdapterId, connectionContext);
                        connectionContext.BroadcastReceived += HandleBroadcastReceived;
                        connectionContext.Start(() => {
                            Debug("Connection Context Torn Down: {0}", neighbor.AdapterId);

                            connectionContext.BroadcastReceived -= HandleBroadcastReceived;
                            connectedNeighborContextsByAdapterId.RemoveOrThrow(neighbor.AdapterId);
                            neighbor.Disconnect();
                        });
                    }))
                        )
                    .ConfigureAwait(false);
                } catch (Exception e) {
                    Debug("Discovery threw!");
                    Debug(e.ToString());
                }
                Debug("Ending discovery round!");
                await ChannelsExtensions.ReadAsync(rateLimit).ConfigureAwait(false);
            }
        }
Ejemplo n.º 3
0
        private async Task SynchronizeRemoteToLocalAsync()
        {
            DebugPrint("Enter Remote to Local");
            var have = await ChannelsExtensions.ReadAsync(haveChannel).ConfigureAwait(false);

            DebugPrint("Have is {0}", have.MerkleRootHash);
            var isRemoteRootSyncedLocally = await IsRemoteObjectHeldLocally(have.MerkleRootHash).ConfigureAwait(false);

            DebugPrint("IRRSL {0}", isRemoteRootSyncedLocally);

            if (!isRemoteRootSyncedLocally)
            {
                var nodesToImport = new List <Tuple <string, MerkleNode> >();
                var neededHashes  = new LinkedList <string>();
                neededHashes.AddLast(have.MerkleRootHash);

                while (neededHashes.Count != 0)
                {
                    var hashesReadLocally = new HashSet <string>();
                    foreach (var hash in neededHashes)
                    {
                        var localNode = await localMerkleTree.GetNodeAsync(hash).ConfigureAwait(false);

                        if (localNode != null)
                        {
                            nodesToImport.Add(Tuple.Create(hash, localNode));
                            hashesReadLocally.Add(hash);
                            continue;
                        }

                        var need = new NeedPacket {
                            MerkleRootHash = hash
                        };
                        DebugPrint("SEND NEED {0}", need.MerkleRootHash);
                        neighbor.SendAsync(serializer.ToByteArray(need)).Forget();
                    }

                    Console.WriteLine($"Found {neededHashes.Count} messages to sync");
                    foreach (var i in Enumerable.Range(0, neededHashes.Count))
                    {
                        var hash = neededHashes.First();
                        neededHashes.RemoveFirst();

                        if (hashesReadLocally.Contains(hash))
                        {
                            continue;
                        }

                        var give = await ChannelsExtensions.ReadAsync(giveChannel).ConfigureAwait(false);

                        Console.WriteLine($"Got hash {give.NodeHash}");
                        nodesToImport.Add(Tuple.Create(give.NodeHash, give.Node));

                        if (!await IsRemoteObjectHeldLocally(give.Node.LeftHash).ConfigureAwait(false))
                        {
                            neededHashes.AddLast(give.Node.LeftHash);
                        }

                        if (!await IsRemoteObjectHeldLocally(give.Node.RightHash).ConfigureAwait(false))
                        {
                            neededHashes.AddLast(give.Node.RightHash);
                        }
                    }
                }

                var broadcastMessagesByNodeHash = nodesToImport.Where(n => n.Item2.TypeTag == MerkleNodeTypeTag.Data)
                                                  .ToDictionary(
                    n => n.Item1,
                    n => broadcastMessageSerializer.Deserialize(n.Item2.Contents)
                    );
                Console.WriteLine($"Need to add {broadcastMessagesByNodeHash.Count} hashes that we don't have");

                var neededSourceIdHashes = broadcastMessagesByNodeHash.Select(kvp => kvp.Value.SourceIdHash)
                                           .GroupBy(sourceIdHash => sourceIdHash.ToHexString())
                                           .Select(g => new { Bytes = g.First(), Hex = g.Key })
                                           .Where(pair => !IdentityManager.IsKnownIdentity(pair.Bytes))
                                           .ToList();

                foreach (var neededSourceId in neededSourceIdHashes)
                {
                    var whois = new WhoisPacket {
                        IdHash = neededSourceId.Bytes
                    };
                    DebugPrint("SEND WHOIS {0}", neededSourceId.Hex);
                    neighbor.SendAsync(serializer.ToByteArray(whois)).Forget();
                }

                foreach (var i in Enumerable.Range(0, neededSourceIdHashes.Count))
                {
                    var ident = await ChannelsExtensions.ReadAsync(identChannel).ConfigureAwait(false);

                    Identity.ValidateAndAdd(ident.TrustChain);
                }

                foreach (var neededSourceId in neededSourceIdHashes)
                {
                    if (!IdentityManager.IsKnownIdentity(neededSourceId.Bytes))
                    {
                        throw new InvalidStateException();
                    }
                }

                foreach (var tuple in nodesToImport)
                {
                    var node = tuple.Item2;
                    if (node.Descendents == 0 && await localMerkleTree.GetNodeAsync(tuple.Item1).ConfigureAwait(false) == null)
                    {
                        var isDataNode = node.TypeTag == MerkleNodeTypeTag.Data;
                        BroadcastMessageDto message = isDataNode ? broadcastMessageSerializer.Deserialize(node.Contents) : null;

                        var sender = IdentityManager.LookupIdentity(message.SourceIdHash);
                        if (message.DestinationIdHash.All(val => val == 0))
                        {
                            if ((sender.HeldPermissions & Permission.Broadcast) == 0)
                            {
                                Console.WriteLine("Sender does not have broadcast permissions. Malicious peer!");
                                throw new InvalidStateException();
                            }
                        }
                        else
                        {
                            if ((sender.HeldPermissions & Permission.Unicast) == 0)
                            {
                                Console.WriteLine("Sender does not have unicast permissions. Malicious peer!");
                                throw new InvalidStateException();
                            }
                        }
                    }
                }

                await remoteMerkleTree.ImportAsync(have.MerkleRootHash, nodesToImport).ConfigureAwait(false);

                Console.WriteLine($"Currently have {nodesToImport.Count} nodes to import still");

                foreach (var tuple in nodesToImport)
                {
                    var node = tuple.Item2;
                    if (node.Descendents == 0 && await localMerkleTree.GetNodeAsync(tuple.Item1).ConfigureAwait(false) == null)
                    {
                        var isDataNode = node.TypeTag == MerkleNodeTypeTag.Data;
                        BroadcastMessageDto message = isDataNode ? broadcastMessageSerializer.Deserialize(node.Contents) : null;

                        Console.WriteLine("Got data node");

                        var insertionResult = await localMerkleTree.TryInsertAsync(tuple.Item2).ConfigureAwait(false);

                        if (insertionResult.Item1 && isDataNode)
                        {
                            byte[] decryptedPayload;
                            Console.WriteLine("Got a message");
                            if (identity.TryDecodePayload(message, out decryptedPayload))
                            {
                                BroadcastReceived?.Invoke(new MessageReceivedEventArgs(neighbor, new BroadcastMessage {
                                    SourceId         = IdentityHash.GetFlyweight(message.SourceIdHash),
                                    DestinationId    = IdentityHash.GetFlyweight(message.DestinationIdHash),
                                    DecryptedPayload = decryptedPayload,
                                    Dto = message
                                }));
                            }
                        }
                    }
                }
            }

            DebugPrint("SEND DONE");
            await neighbor.SendAsync(serializer.ToByteArray(new DonePacket())).ConfigureAwait(false);
        }