internal static void Reply(IPeerDiscoveryTransport net, IPeerDiscoveryMessage msg, Guid streamId, Action <BinaryWriter> cb) { byte[] buffer = new byte[1024]; using (var str = new MemoryStream(buffer)) using (var writer = new BinaryWriter(str)) { cb.Invoke(writer); writer.Flush(); net.Reply(msg, streamId, new ArraySegment <byte>(buffer, 0, (int)str.Position)); } }
private void SendReceive(ITransportBuilder transportBuilder, bool useMultiThread) { using (var cts = new CancellationTokenSource(Utils.TestTimeoutMs)) { const int lastId = 50; const int guidsPerTransport = 3; // Make a few transports in the same broadcast domain. var transports = new IPeerDiscoveryTransport[5]; // Associate a few stream IDs to each transport. int streamsNum = guidsPerTransport * transports.Length; var streams = new Guid[streamsNum]; // Keep track of the messages received by each transport. var lastIdFromGuid = new Dictionary <Guid, int> [transports.Length]; var lastMessageReceived = new Dictionary <Guid, ManualResetEvent> [transports.Length]; for (int transportIdx = 0; transportIdx < transports.Length; ++transportIdx) { // Initialize transport and associated data. lastMessageReceived[transportIdx] = new Dictionary <Guid, ManualResetEvent>(); lastIdFromGuid[transportIdx] = new Dictionary <Guid, int>(); for (int guidIdx = 0; guidIdx < guidsPerTransport; ++guidIdx) { var streamId = Guid.NewGuid(); streams[transportIdx * guidsPerTransport + guidIdx] = streamId; lastMessageReceived[transportIdx][streamId] = new ManualResetEvent(false); } transports[transportIdx] = transportBuilder.MakeTransport(transportIdx + 1); // Handle received messages. // Note: must copy into local variable or the lambda will capture the wrong value. int captureTransportIdx = transportIdx; transports[transportIdx].Message += (IPeerDiscoveryTransport _, IPeerDiscoveryMessage message) => { // Check that messages are received in send order. lastIdFromGuid[captureTransportIdx].TryGetValue(message.StreamId, out int lastReceivedId); int currentId = BitConverter.ToInt32(message.Contents); Assert.True(currentId > lastReceivedId); // Notify that the last message hasn't been dropped. if (currentId == lastId) { lastMessageReceived[captureTransportIdx][message.StreamId].Set(); } }; transports[transportIdx].Start(); } try { // Send a sequence of messages from every transport for every stream. var sendTasks = new List <Task>(); for (int transportIdx = 0; transportIdx < transports.Length; ++transportIdx) { for (int guidIdx = 0; guidIdx < guidsPerTransport; ++guidIdx) { var guid = streams[transportIdx * guidsPerTransport + guidIdx]; var transport = transports[transportIdx]; Action sendMessages = () => { for (int msgIdx = 1; msgIdx <= lastId; ++msgIdx) { byte[] bytes = BitConverter.GetBytes(msgIdx); transport.Broadcast(guid, bytes); } }; if (useMultiThread) { sendTasks.Add(Task.Run(sendMessages)); } else { sendMessages(); } } } // Wait until all messages have been sent. Task.WaitAll(sendTasks.ToArray(), cts.Token); // The last message has been received for every stream by every transport. var allHandles = new List <WaitHandle>(streamsNum); foreach (var transportEvents in lastMessageReceived) { foreach (var ev in transportEvents.Values) { allHandles.Add(ev); } } // Workaround to WaitHandle.WaitAll not taking a CancellationToken. Task.Run(() => WaitHandle.WaitAll(allHandles.ToArray())).Wait(cts.Token); } finally { Exception anyException = null; foreach (var transport in transports) { try { transport.Stop(); } catch (Exception e) { anyException = e; } } if (anyException != null) { throw anyException; } } } }
internal Server(IPeerDiscoveryTransport net) { proto_ = new Proto(net); proto_.OnClientQuery = OnClientQuery; timer_ = new Timer(OnServerTimerExpired, null, Timeout.Infinite, Timeout.Infinite); }
// Receiving private void OnMessage(IPeerDiscoveryTransport net, IPeerDiscoveryMessage msg) { Debug.Assert(net == transport_); Dispatch(msg); }
internal Proto(IPeerDiscoveryTransport net) { transport_ = net; Start(); }