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 CustomProcessTestAsync() { await TaskEx.YieldToThreadPool(); ThreadPool.SetMaxThreads(128, 128); var cohortCount = 4; var cluster = await TestUtils.CreateCluster <int, SetBox <int> >(cohortCount).ConfigureAwait(false); var workerCount = 100; var sync = new AsyncCountdownLatch(workerCount); var tasks = Util.Generate( workerCount, value => ChannelsExtensions.Go(async() => { sync.Signal(); await sync.WaitAsync().ConfigureAwait(false); var node = cluster[value % cohortCount]; var result = await node.UserCache.ProcessAsync(0, SetAddEntryOperation <int, int> .Create(value)).ConfigureAwait(false); AssertTrue(result); })); try { await Task.WhenAll(tasks).ConfigureAwait(false); Console.WriteLine("Validating set contents"); var result = await cluster[0].UserCache.GetAsync(0).ConfigureAwait(false); AssertCollectionDeepEquals(new HashSet <int>(Enumerable.Range(0, 100)), result.Value.Set); } catch (Exception e) { Console.Error.WriteLine("Test threw " + e); throw; } }
public async Task SendAsync(DeviceAgent sender, byte[] contents) { var interval = TimeSpan.FromMilliseconds(SimulationBluetoothConstants.SEND_TICK_INTERVAL); var completionBox = new AsyncBox <bool>(); var sendEvent = new SendEvent(DateTime.Now + interval, interval, sender, completionBox, contents, 0); await ChannelsExtensions.WriteAsync(adapterEventQueueChannel, sendEvent).ConfigureAwait(false); await completionBox.GetResultAsync().ConfigureAwait(false); }
public async Task ConnectAsync(DeviceAgent sender) { var now = DateTime.Now; var connectEvent = new BeginConnectEvent(now + TimeSpan.FromMilliseconds(SimulationBluetoothConstants.BASE_HANDSHAKE_DELAY_MILLIS), sender); await ChannelsExtensions.WriteAsync(adapterEventQueueChannel, connectEvent).ConfigureAwait(false); var timeoutEvent = new TimeoutConnectEvent(now + TimeSpan.FromMilliseconds(SimulationBluetoothConstants.HANDSHAKE_TIMEOUT_MILLIS), connectEvent); await ChannelsExtensions.WriteAsync(adapterEventQueueChannel, timeoutEvent).ConfigureAwait(false); await connectEvent.ResultBox.GetResultAsync().ConfigureAwait(false); }
public async Task GiveAsync(BluetoothSocket socket) { Channel <BluetoothSocket> channel; using (await synchronization.LockAsync().ConfigureAwait(false)) { var deviceId = MacUtilities.ConvertMacToGuid(socket.RemoteDevice.Address); Console.WriteLine("INBOUND CONNECTION FROM " + deviceId + " aka " + (socket.RemoteDevice.Name ?? "[unknown]")); channel = pendingRequests.GetOrAdd(deviceId, add => ChannelFactory.Nonblocking <BluetoothSocket>()); await ChannelsExtensions.WriteAsync(channel, socket).ConfigureAwait(false); } }
public async Task <bool> TryHandshakeAsync(double minTimeoutSeconds) { try { using (await synchronization.LockAsync().ConfigureAwait(false)) { Console.WriteLine("Attempting to connect to ID " + AdapterId + " AKA " + string.Join(" ", AdapterId.ToByteArray())); bluetoothClient = new BluetoothClient(); bluetoothClient.Authenticate = false; bluetoothClient.Encrypt = false; await bluetoothClient.ConnectAsync(address, CAMPFIRE_NET_SERVICE_CLASS).ConfigureAwait(false); disconnectedChannel.SetIsClosed(false); Console.WriteLine("Connected. Their Adapter ID is " + AdapterId + " AKA " + string.Join(" ", AdapterId.ToByteArray())); ChannelsExtensions.Go(async() => { Console.WriteLine("Entered BT Reader Task"); var networkStream = bluetoothClient.GetStream(); try { while (!disconnectedChannel.IsClosed) { Console.WriteLine("Reading BT Frame"); var dataLengthBuffer = await ReadBytesAsync(networkStream, 4).ConfigureAwait(false); var dataLength = BitConverter.ToInt32(dataLengthBuffer, 0); Console.WriteLine("Got BT Frame Length: " + dataLength); var data = await ReadBytesAsync(networkStream, dataLength).ConfigureAwait(false); await inboundChannel.WriteAsync(data).ConfigureAwait(false); } } catch (Exception e) { Console.WriteLine(e); Teardown(); } }).Forget(); return(true); } } catch (Exception e) { Console.WriteLine("Failed to connect to ID " + AdapterId + " AKA " + string.Join(" ", AdapterId.ToByteArray())); Console.WriteLine(e.GetType().FullName); return(false); } }
public async Task RunAsync() { await TaskEx.YieldToThreadPool(); ThreadPool.SetMaxThreads(128, 128); var cohortCount = 4; var cluster = await TestUtils.CreateCluster <int, string>(cohortCount).ConfigureAwait(false); var workerCount = 100; var sync = new AsyncCountdownLatch(workerCount); var tasks = Util.Generate( workerCount, key => ChannelsExtensions.Go(async() => { try { Console.WriteLine("Entered thread for worker of key " + key); sync.Signal(); await sync.WaitAsync().ConfigureAwait(false); const int kReadCount = 10; for (var i = 0; i < kReadCount; i++) { var node = cluster[i % cohortCount]; var entry = await node.UserCache.GetAsync(key).ConfigureAwait(false); AssertEquals(key, entry.Key); AssertEquals(null, entry.Value); AssertFalse(entry.Exists); } } catch (Exception e) { Console.Error.WriteLine("Worker on key " + key + " threw " + e); throw; } })); try { await Task.WhenAll(tasks).ConfigureAwait(false); } catch (Exception e) { Console.Error.WriteLine("Test threw " + e); throw; } }
private async Task HandshakeAsync(double minTimeoutSeconds) { using (await synchronization.LockAsync().ConfigureAwait(false)) { var isServer = androidBluetoothAdapter.AdapterId.CompareTo(AdapterId) > 0; // Michael's laptop is always the client as windows client doesn't understand being a server. if (Name?.Contains("DESKTOP") ?? false) { isServer = true; } if (isServer) { socket = await inboundBluetoothSocketTable.TakeAsyncOrTimeout(device).ConfigureAwait(false); } else { var socketBox = new AsyncBox <BluetoothSocket>(); new Thread(() => { try { socketBox.SetResult(device.CreateInsecureRfcommSocketToServiceRecord(CampfireNetBluetoothConstants.APP_UUID)); } catch (Exception e) { socketBox.SetException(e); } }).Start(); socket = await socketBox.GetResultAsync().ConfigureAwait(false); var connectedChannel = ChannelFactory.Nonblocking <bool>(); Go(async() => { await socket.ConnectAsync().ConfigureAwait(false); await ChannelsExtensions.WriteAsync(connectedChannel, true); }).Forget(); bool isTimeout = false; await new Select { Case(ChannelFactory.Timer(TimeSpan.FromSeconds(minTimeoutSeconds)), () => { socket.Dispose(); isTimeout = true; }), Case(connectedChannel, () => { // whee! }) }.ConfigureAwait(false); if (isTimeout) { throw new TimeoutException(); } } disconnectedChannel.SetIsClosed(false); ChannelsExtensions.Go(async() => { Console.WriteLine("Entered BT Reader Task"); var networkStream = socket.InputStream; try { while (!disconnectedChannel.IsClosed) { Console.WriteLine("Reading BT Frame"); var dataLengthBuffer = await ReadBytesAsync(networkStream, 4).ConfigureAwait(false); var dataLength = BitConverter.ToInt32(dataLengthBuffer, 0); var data = await ReadBytesAsync(networkStream, dataLength).ConfigureAwait(false); await ChannelsExtensions.WriteAsync(inboundChannel, data).ConfigureAwait(false); } } catch (Exception e) { Console.WriteLine(e); Teardown(); } }).Forget(); } }
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 void OnReceive(Context context, Intent intent) { ChannelsExtensions.Write(intentChannel, intent); }
private async Task RouterTaskStart() { var inboundChannel = neighbor.InboundChannel; try { while (true) { byte[] packetData = null; bool quit = false; await new Select { Case(ChannelFactory.Timeout(TimeSpan.FromSeconds(30)), () => quit = true), Case(inboundChannel, x => packetData = x) }.ConfigureAwait(false); if (quit) { break; } var packet = serializer.ToObject(packetData); switch (packet.GetType().Name) { case nameof(HavePacket): DebugPrint("Got HAVE {0}", ((HavePacket)packet).MerkleRootHash); await ChannelsExtensions.WriteAsync(haveChannel, (HavePacket)packet).ConfigureAwait(false); break; case nameof(NeedPacket): DebugPrint("Got NEED {0}", ((NeedPacket)packet).MerkleRootHash); await ChannelsExtensions.WriteAsync(needChannel, (NeedPacket)packet).ConfigureAwait(false); break; case nameof(GivePacket): DebugPrint("Got GIVE {0}", ((GivePacket)packet).NodeHash); var p = (GivePacket)packet; Console.WriteLine($"Recieved data hash {p.NodeHash} ({p.Node.Contents.Length} '{BitConverter.ToString(p.Node.Contents)}')"); await ChannelsExtensions.WriteAsync(giveChannel, (GivePacket)packet).ConfigureAwait(false); break; case nameof(WhoisPacket): DebugPrint("Got WHOIS {0}", ((WhoisPacket)packet).IdHash.ToHexString()); await ChannelsExtensions.WriteAsync(whoisChannel, (WhoisPacket)packet).ConfigureAwait(false); break; case nameof(IdentPacket): DebugPrint("Got IDENT {0}", ((IdentPacket)packet).Id.ToHexString()); await ChannelsExtensions.WriteAsync(identChannel, (IdentPacket)packet).ConfigureAwait(false); break; case nameof(DonePacket): DebugPrint("Got DONE"); await ChannelsExtensions.WriteAsync(doneChannel, (DonePacket)packet).ConfigureAwait(false); break; default: throw new InvalidStateException(); } } } catch (NotConnectedException e) { DebugPrint("Got NotConnectedException " + e); disconnectLatchChannel.SetIsClosed(true); try { await neighbor.SendAsync(new byte[0]).ConfigureAwait(false); throw new InvalidStateException(); } catch (NotConnectedException) { } } catch (Exception e) { DebugPrint("Got Exception " + e); throw; } finally { disconnectLatchChannel.SetIsClosed(true); neighbor.Disconnect(); DebugPrint("Router loop exiting"); } }
private async Task SynchronizeLocalToRemoteAsync() { DebugPrint("Enter Local to Remote"); var localRootHash = await localMerkleTree.GetRootHashAsync().ConfigureAwait(false) ?? CampfireNetHash.ZERO_HASH_BASE64; var havePacket = new HavePacket { MerkleRootHash = localRootHash }; DebugPrint("SEND HAVE {0}", havePacket.MerkleRootHash); await neighbor.SendAsync(serializer.ToByteArray(havePacket)).ConfigureAwait(false); bool done = false; while (!done) { await new Select { ChannelsExtensions.Case(doneChannel, () => { done = true; }), ChannelsExtensions.Case(needChannel, async need => { // Console.WriteLine("RECV NEED " + need.MerkleRootHash); var node = await localMerkleTree.GetNodeAsync(need.MerkleRootHash).ConfigureAwait(false); var give = new GivePacket { NodeHash = need.MerkleRootHash, Node = node }; DebugPrint("SEND GIVE"); neighbor.SendAsync(serializer.ToByteArray(give)).Forget(); // Console.WriteLine("EMIT GIVE " + need.MerkleRootHash); }), ChannelsExtensions.Case(whoisChannel, whois => { // Ideally we send IDs one at a time. However, we are short on time so // we've gone with the simple implementation. var currentIdHash = whois.IdHash; var trustChain = new List <TrustChainNode>(); while (true) { var node = IdentityManager.LookupIdentity(currentIdHash); trustChain.Add(node); if (node.ParentId.SequenceEqual(node.ThisId)) { break; } currentIdHash = node.ParentId; } trustChain.Reverse(); DebugPrint("SEND IDENT"); var ident = new IdentPacket { Id = trustChain.Last().ThisId, TrustChain = trustChain.ToArray() }; neighbor.SendAsync(serializer.ToByteArray(ident)).Forget(); Console.WriteLine("EMIT IDENT " + ident.Id.ToHexString()); }) }.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); }
private async Task RunAsync() { var pendingBeginConnect = (BeginConnectEvent)null; while (true) { var adapterEvent = await adapterEventQueueChannel.ReadAsync(CancellationToken.None, x => true).ConfigureAwait(false); switch (adapterEvent.GetType().Name) { case nameof(BeginConnectEvent): var beginConnect = (BeginConnectEvent)adapterEvent; if (pendingBeginConnect == null) { pendingBeginConnect = beginConnect; } else { firstDisconnectChannel.SetIsClosed(false); secondDisconnectChannel.SetIsClosed(false); var pendingBeginConnectCapture = pendingBeginConnect; pendingBeginConnect = null; pendingBeginConnectCapture.ResultBox.SetResult(true); beginConnect.ResultBox.SetResult(true); } break; case nameof(TimeoutConnectEvent): var timeout = (TimeoutConnectEvent)adapterEvent; if (timeout.BeginEvent == pendingBeginConnect) { pendingBeginConnect.ResultBox.SetException(new TimeoutException()); pendingBeginConnect = null; } break; case nameof(SendEvent): var send = (SendEvent)adapterEvent; if (!GetIsConnected(send.Initiator)) { send.CompletionBox.SetException(new NotConnectedException()); break; } var connectivity = SimulationBluetoothCalculator.ComputeConnectivity(firstAgent, secondAgent); if (!connectivity.InRange) { firstDisconnectChannel.SetIsClosed(true); secondDisconnectChannel.SetIsClosed(true); send.CompletionBox.SetException(new NotConnectedException()); break; } var deltaBytesSent = (int)Math.Ceiling(connectivity.SignalQuality * send.Interval.TotalSeconds * SimulationBluetoothConstants.MAX_OUTBOUND_BYTES_PER_SECOND); var bytesSent = send.BytesSent + deltaBytesSent; if (bytesSent >= send.Payload.Length) { await ChannelsExtensions.WriteAsync(GetOtherInboundChannelInternal(send.Initiator), send.Payload).ConfigureAwait(false); send.CompletionBox.SetResult(true); break; } var nextEvent = new SendEvent(DateTime.Now + send.Interval, send.Interval, send.Initiator, send.CompletionBox, send.Payload, bytesSent); await adapterEventQueueChannel.WriteAsync(nextEvent, CancellationToken.None).ConfigureAwait(false); break; } } }