Example #1
0
        public async Task Writing()
        {
            var ms    = new MemoryStream();
            var muxer = new Muxer {
                Channel = ms
            };
            var stream = new Substream {
                Muxer = muxer
            };
            var m1 = new byte[1];

            stream.AddData(new byte[] { 10 });
            Assert.IsTrue(stream.CanRead);
            Assert.IsTrue(stream.CanWrite);

            Assert.AreEqual(1, await stream.ReadAsync(m1, 0, 1));
            await stream.WriteAsync(m1, 0, 1);

            stream.WriteByte(11);
            await stream.FlushAsync();

            ms.Position = 0;
            var header = await Header.ReadAsync(ms);

            var length = await Varint.ReadVarint32Async(ms);

            var payload = new byte[length];

            ms.Read(payload, 0, length);
            Assert.AreEqual(stream.Id, header.StreamId);
            Assert.AreEqual(2, payload.Length);
            CollectionAssert.AreEqual(new byte[] { 10, 11 }, payload);
        }
Example #2
0
        public async Task Reading()
        {
            var m1     = new byte[] { 1, 2, 3, 4 };
            var m2     = new byte[m1.Length];
            var stream = new Substream();

            stream.AddData(new byte[] { 1, 2 });
            stream.AddData(new byte[] { 3, 4 });
            stream.NoMoreData();
            Assert.IsTrue(stream.CanRead);

            m2[0] = (byte)stream.ReadByte();
            Assert.AreEqual(1, stream.Read(m2, 1, 1));
            Assert.AreEqual(2, await stream.ReadAsync(m2, 2, 2));
            CollectionAssert.AreEqual(m1, m2);

            Assert.AreEqual(-1, stream.ReadByte());
            Assert.IsFalse(stream.CanRead);
        }
Example #3
0
        public async Task Reading_Delayed_Partial()
        {
            var m1     = new byte[] { 1, 2, 3, 4 };
            var m2     = new byte[m1.Length];
            var stream = new Substream();

#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            Task.Run(async() =>
            {
                await Task.Delay(100);
                stream.AddData(new byte[] { 1, 2 });
                await Task.Delay(100);
                stream.AddData(new byte[] { 3, 4 });
                await Task.Delay(100);
                stream.NoMoreData();
            });
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed

            Assert.AreEqual(4, await stream.ReadAsync(m2, 0, 5));
            CollectionAssert.AreEqual(m1, m2);
        }
Example #4
0
        public async Task Reading_Partial()
        {
            var m1     = new byte[] { 1, 2, 3, 4 };
            var m2     = new byte[m1.Length];
            var stream = new Substream();

            stream.AddData(m1);
            stream.NoMoreData();

            Assert.AreEqual(4, await stream.ReadAsync(m2, 0, 5));
            CollectionAssert.AreEqual(m1, m2);

            Assert.AreEqual(-1, stream.ReadByte());
            Assert.IsFalse(stream.CanRead);
        }
Example #5
0
        /// <summary>
        ///   Read the multiplex packets.
        /// </summary>
        /// <param name="cancel"></param>
        /// <returns></returns>
        /// <remarks>
        ///   A background task that reads and processes the multiplex packets while
        ///   the <see cref="Channel"/> is open and not <paramref name="cancel">cancelled</paramref>.
        ///   <para>
        ///   Any encountered errors will close the <see cref="Channel"/>.
        ///   </para>
        /// </remarks>
        public async Task ProcessRequestsAsync(CancellationToken cancel = default(CancellationToken))
        {
            try
            {
                while (Channel.CanRead && !cancel.IsCancellationRequested)
                {
                    // Read the packet prefix.
                    var header = await Header.ReadAsync(Channel, cancel).ConfigureAwait(false);

                    var length = await Varint.ReadVarint32Async(Channel, cancel).ConfigureAwait(false);

                    if (log.IsTraceEnabled)
                    {
                        log.TraceFormat("received '{0}', stream={1}, length={2}", header.PacketType, header.StreamId, length);
                    }

                    // Read the payload.
                    var payload = new byte[length];
                    int offset  = 0;
                    while (offset < length)
                    {
                        offset += await Channel.ReadAsync(payload, offset, length - offset, cancel).ConfigureAwait(false);
                    }

                    // Process the packet
                    Substreams.TryGetValue(header.StreamId, out Substream substream);
                    switch (header.PacketType)
                    {
                    case PacketType.NewStream:
                        if (substream != null)
                        {
                            log.Warn($"Stream {substream.Id} already exists");
                            continue;
                        }
                        substream = new Substream
                        {
                            Id    = header.StreamId,
                            Name  = Encoding.UTF8.GetString(payload),
                            Muxer = this
                        };
                        if (!Substreams.TryAdd(substream.Id, substream))
                        {
                            // Should not happen.
                            throw new Exception($"Stream {substream.Id} already exists");
                        }
                        SubstreamCreated?.Invoke(this, substream);

                        // Special hack for go-ipfs
#if true
                        if (Receiver && (substream.Id & 1) == 1)
                        {
                            log.Debug($"go-hack sending newstream {substream.Id}");
                            using (await AcquireWriteAccessAsync().ConfigureAwait(false))
                            {
                                var hdr = new Header
                                {
                                    StreamId   = substream.Id,
                                    PacketType = PacketType.NewStream
                                };
                                await hdr.WriteAsync(Channel, cancel).ConfigureAwait(false);

                                Channel.WriteByte(0);     // length
                                await Channel.FlushAsync().ConfigureAwait(false);
                            }
                        }
#endif
                        break;

                    case PacketType.MessageInitiator:
                        if (substream == null)
                        {
                            log.Warn($"Message to unknown stream #{header.StreamId}");
                            continue;
                        }
                        substream.AddData(payload);
                        break;

                    case PacketType.MessageReceiver:
                        if (substream == null)
                        {
                            log.Warn($"Message to unknown stream #{header.StreamId}");
                            continue;
                        }
                        substream.AddData(payload);
                        break;

                    case PacketType.CloseInitiator:
                    case PacketType.CloseReceiver:
                    case PacketType.ResetInitiator:
                    case PacketType.ResetReceiver:
                        if (substream == null)
                        {
                            log.Warn($"Reset of unknown stream #{header.StreamId}");
                            continue;
                        }
                        substream.NoMoreData();
                        Substreams.TryRemove(substream.Id, out Substream _);
                        SubstreamClosed?.Invoke(this, substream);
                        break;

                    default:
                        throw new InvalidDataException($"Unknown Muxer packet type '{header.PacketType}'.");
                    }
                }
            }
            catch (EndOfStreamException)
            {
                // eat it
            }
            catch (IOException)
            {
                // eat it
            }
            catch (SocketException e) when(e.SocketErrorCode == SocketError.ConnectionReset)
            {
                // eat it
            }
            catch (Exception) when(cancel.IsCancellationRequested)
            {
                // eat it
            }
            catch (Exception e)
            {
                // Log error if the channel is not closed.
                if (Channel.CanRead || Channel.CanWrite)
                {
                    log.Error("failed", e);
                }
            }

            // Some of the tests do not pass a connection.
            if (Connection != null)
            {
                Connection.Dispose();
            }
            else if (Channel != null)
            {
                Channel.Dispose();
            }

            // Dispose of all the substreams.
            var streams = Substreams.Values.ToArray();
            Substreams.Clear();
            foreach (var stream in streams)
            {
                stream.Dispose();
            }
        }