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(); } }
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); } }
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); }