示例#1
0
        /// <summary>
        /// Begins an asynchronous receive
        /// </summary>
        /// <param name="Buffer">Buffer to store received data</param>
        /// <param name="ReadCallBack">Method to call on receiving data</param>
        /// <param name="StateObject">State object to be passed to ReadCallBack</param>
        /// <returns>AsyncResult for the asynchronous operation</returns>
        public IAsyncResult BeginReceive(int BufferLength, AsyncCallback ReadCallBack, object StateObject)
        {
            try
            {
                if (recvBuffer == null || recvBuffer.IsDisposed)
                {
                    recvBuffer = bufferPool.GetBuffer(BufferLength);
                }
                else if (recvBuffer.Size < BufferLength)
                {
                    recvBuffer.Dispose();
                    recvBuffer = bufferPool.GetBuffer(BufferLength);
                }

                lock (syncSocket)
                {
                    return(socket.BeginReceive(recvBuffer.GetSegments(), SocketFlags.None, ReadCallBack, StateObject));
                }
            }
            catch (Exception ex)
            {
                Diags.LogSocketException(ex);
                return(null);
            }
        }
示例#2
0
        /// <summary>
        ///     relays the input clientStream to the server at the specified host name and port with the given httpCmd and headers
        ///     as prefix
        ///     Usefull for websocket requests
        ///     Asynchronous Programming Model, which does not throw exceptions when the socket is closed
        /// </summary>
        /// <param name="clientStream"></param>
        /// <param name="serverStream"></param>
        /// <param name="bufferSize"></param>
        /// <param name="onDataSend"></param>
        /// <param name="onDataReceive"></param>
        /// <param name="cancellationTokenSource"></param>
        /// <param name="exceptionFunc"></param>
        /// <returns></returns>
        internal static async Task SendRawApm(Stream clientStream, Stream serverStream,
                                              IBufferPool bufferPool, int bufferSize,
                                              Action <byte[], int, int> onDataSend, Action <byte[], int, int> onDataReceive,
                                              CancellationTokenSource cancellationTokenSource,
                                              ExceptionHandler exceptionFunc)
        {
            var taskCompletionSource = new TaskCompletionSource <bool>();

            cancellationTokenSource.Token.Register(() => taskCompletionSource.TrySetResult(true));

            // Now async relay all server=>client & client=>server data
            var clientBuffer = bufferPool.GetBuffer(bufferSize);
            var serverBuffer = bufferPool.GetBuffer(bufferSize);

            try
            {
                beginRead(clientStream, serverStream, clientBuffer, onDataSend, cancellationTokenSource, exceptionFunc);
                beginRead(serverStream, clientStream, serverBuffer, onDataReceive, cancellationTokenSource,
                          exceptionFunc);
                await taskCompletionSource.Task;
            }
            finally
            {
                bufferPool.ReturnBuffer(clientBuffer);
                bufferPool.ReturnBuffer(serverBuffer);
            }
        }
 public CopyStream(ICustomStreamReader reader, ICustomStreamWriter writer, IBufferPool bufferPool, int bufferSize)
 {
     this.reader = reader;
     this.writer = writer;
     BufferSize  = bufferSize;
     buffer      = bufferPool.GetBuffer(bufferSize);
 }
        /// <summary>
        ///     Copy streams asynchronously
        /// </summary>
        /// <param name="input"></param>
        /// <param name="output"></param>
        /// <param name="onCopy"></param>
        /// <param name="bufferPool"></param>
        /// <param name="bufferSize"></param>
        /// <param name="cancellationToken"></param>
        internal static async Task CopyToAsync(this Stream input, Stream output, Action <byte[], int, int> onCopy,
                                               IBufferPool bufferPool, int bufferSize, CancellationToken cancellationToken)
        {
            var buffer = bufferPool.GetBuffer(bufferSize);

            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    // cancellation is not working on Socket ReadAsync
                    // https://github.com/dotnet/corefx/issues/15033
                    int num = await input.ReadAsync(buffer, 0, buffer.Length, CancellationToken.None)
                              .withCancellation(cancellationToken);

                    int bytesRead;
                    if ((bytesRead = num) != 0 && !cancellationToken.IsCancellationRequested)
                    {
                        await output.WriteAsync(buffer, 0, bytesRead, CancellationToken.None);

                        onCopy?.Invoke(buffer, 0, bytesRead);
                    }
                    else
                    {
                        break;
                    }
                }
            }
            finally
            {
                bufferPool.ReturnBuffer(buffer);
            }
        }
        /// <summary>
        ///     Determines whether the stream starts with the given string.
        /// </summary>
        /// <returns>
        ///     1: when starts with the given string, 0: when valid HTTP method, -1: otherwise
        /// </returns>
        private static async Task <int> startsWith(ICustomStreamReader clientStreamReader, IBufferPool bufferPool, string expectedStart, CancellationToken cancellationToken = default)
        {
            const int lengthToCheck = 10;

            byte[] buffer = null;
            try
            {
                if (bufferPool.BufferSize < lengthToCheck)
                {
                    throw new Exception($"Buffer is too small. Minimum size is {lengthToCheck} bytes");
                }

                buffer = bufferPool.GetBuffer(bufferPool.BufferSize);

                bool isExpected = true;
                int  i          = 0;
                while (i < lengthToCheck)
                {
                    int peeked = await clientStreamReader.PeekBytesAsync(buffer, i, i, lengthToCheck - i, cancellationToken);

                    if (peeked <= 0)
                    {
                        return(-1);
                    }

                    peeked += i;

                    while (i < peeked)
                    {
                        int b = buffer[i];

                        if (b == ' ' && i > 2)
                        {
                            return(isExpected ? 1 : 0);
                        }
                        else
                        {
                            char ch = (char)b;
                            if (ch < 'A' || ch > 'z' || (ch > 'Z' && ch < 'a')) // ASCII letter
                            {
                                return(-1);
                            }
                            else if (i >= expectedStart.Length || ch != expectedStart[i])
                            {
                                isExpected = false;
                            }
                        }

                        i++;
                    }
                }

                // only letters
                return(0);
            }
            finally
            {
                bufferPool.ReturnBuffer(buffer);
            }
        }
示例#6
0
        /// <summary>
        /// Writes a byte to the current position in the stream and advances the position within the stream by one byte.
        /// </summary>
        /// <param name="value">The byte to write to the stream.</param>
        public override void WriteByte(byte value)
        {
            if (closedWrite)
            {
                return;
            }

            var buffer = bufferPool.GetBuffer();

            try
            {
                buffer[0] = value;
                OnDataWrite(buffer, 0, 1);
                baseStream.Write(buffer, 0, 1);
            }
            catch
            {
                closedWrite = true;
                if (!isNetworkStream)
                {
                    throw;
                }
            }
            finally
            {
                bufferPool.ReturnBuffer(buffer);
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="CustomBufferedStream"/> class.
 /// </summary>
 /// <param name="baseStream">The base stream.</param>
 /// <param name="bufferPool">Bufferpool.</param>
 /// <param name="leaveOpen"><see langword="true" /> to leave the stream open after disposing the <see cref="T:CustomBufferedStream" /> object; otherwise, <see langword="false" />.</param>
 public CustomBufferedStream(Stream baseStream, IBufferPool bufferPool, bool leaveOpen = false)
 {
     BaseStream      = baseStream;
     this.leaveOpen  = leaveOpen;
     streamBuffer    = bufferPool.GetBuffer();
     this.bufferPool = bufferPool;
 }
示例#8
0
 public CopyStream(ICustomStreamReader reader, ICustomStreamWriter writer, IBufferPool bufferPool)
 {
     this.reader     = reader;
     this.writer     = writer;
     buffer          = bufferPool.GetBuffer();
     this.bufferPool = bufferPool;
 }
示例#9
0
 /// <summary>
 /// Initializes a new instance of the <see cref="CustomBufferedStream"/> class.
 /// </summary>
 /// <param name="baseStream">The base stream.</param>
 /// <param name="bufferPool">Bufferpool.</param>
 /// <param name="bufferSize">Size of the buffer.</param>
 /// <param name="leaveOpen"><see langword="true" /> to leave the stream open after disposing the <see cref="T:CustomBufferedStream" /> object; otherwise, <see langword="false" />.</param>
 public CustomBufferedStream(Stream baseStream, IBufferPool bufferPool, int bufferSize, bool leaveOpen = false)
 {
     this.baseStream = baseStream;
     BufferSize      = bufferSize;
     this.leaveOpen  = leaveOpen;
     streamBuffer    = bufferPool.GetBuffer(bufferSize);
     this.bufferPool = bufferPool;
 }
示例#10
0
        private Task writeAsyncInternal(string value, bool addNewLine, CancellationToken cancellationToken)
        {
            int newLineChars = addNewLine ? newLine.Length : 0;
            int charCount    = value.Length;

            if (charCount < BufferSize - newLineChars)
            {
                value.CopyTo(0, charBuffer, 0, charCount);

                var buffer = bufferPool.GetBuffer(BufferSize);
                try
                {
                    int idx = encoder.GetBytes(charBuffer, 0, charCount, buffer, 0, true);
                    if (newLineChars > 0)
                    {
                        Buffer.BlockCopy(newLine, 0, buffer, idx, newLineChars);
                        idx += newLineChars;
                    }

                    return(stream.WriteAsync(buffer, 0, idx, cancellationToken));
                }
                finally
                {
                    bufferPool.ReturnBuffer(buffer);
                }
            }
            else
            {
                var charBuffer = new char[charCount];
                value.CopyTo(0, charBuffer, 0, charCount);

                var buffer = new byte[charCount + newLineChars + 1];
                int idx    = encoder.GetBytes(charBuffer, 0, charCount, buffer, 0, true);
                if (newLineChars > 0)
                {
                    Buffer.BlockCopy(newLine, 0, buffer, idx, newLineChars);
                    idx += newLineChars;
                }

                return(stream.WriteAsync(buffer, 0, idx, cancellationToken));
            }
        }
示例#11
0
        /// <summary>
        /// Initializes a new instance of the <see cref="HttpStream"/> class.
        /// </summary>
        /// <param name="baseStream">The base stream.</param>
        /// <param name="bufferPool">Bufferpool.</param>
        /// <param name="leaveOpen"><see langword="true" /> to leave the stream open after disposing the <see cref="T:CustomBufferedStream" /> object; otherwise, <see langword="false" />.</param>
        internal HttpStream(Stream baseStream, IBufferPool bufferPool, bool leaveOpen = false)
        {
            if (baseStream is NetworkStream)
            {
                swallowException = true;
            }

            this.baseStream = baseStream;
            this.leaveOpen  = leaveOpen;
            streamBuffer    = bufferPool.GetBuffer();
            this.bufferPool = bufferPool;
        }
示例#12
0
        /// <summary>
        /// Initializes a new instance of the <see cref="HttpStream"/> class.
        /// </summary>
        /// <param name="baseStream">The base stream.</param>
        /// <param name="bufferPool">Bufferpool.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="leaveOpen"><see langword="true" /> to leave the stream open after disposing the <see cref="T:CustomBufferedStream" /> object; otherwise, <see langword="false" />.</param>
        internal HttpStream(Stream baseStream, IBufferPool bufferPool, CancellationToken cancellationToken, bool leaveOpen = false)
        {
            if (baseStream is NetworkStream)
            {
                isNetworkStream = true;
            }

            this.baseStream        = baseStream;
            this.leaveOpen         = leaveOpen;
            streamBuffer           = bufferPool.GetBuffer();
            this.bufferPool        = bufferPool;
            this.cancellationToken = cancellationToken;
        }
示例#13
0
        /// <summary>
        ///     Gets the HTTP method from the stream.
        /// </summary>
        public static async ValueTask <KnownMethod> GetMethod(IPeekStream httpReader, IBufferPool bufferPool, CancellationToken cancellationToken = default)
        {
            const int lengthToCheck = 20;

            if (bufferPool.BufferSize < lengthToCheck)
            {
                throw new Exception($"Buffer is too small. Minimum size is {lengthToCheck} bytes");
            }

            byte[] buffer = bufferPool.GetBuffer(bufferPool.BufferSize);
            try
            {
                int i = 0;
                while (i < lengthToCheck)
                {
                    int peeked = await httpReader.PeekBytesAsync(buffer, i, i, lengthToCheck - i, cancellationToken);

                    if (peeked <= 0)
                    {
                        return(KnownMethod.Invalid);
                    }

                    peeked += i;

                    while (i < peeked)
                    {
                        int b = buffer[i];

                        if (b == ' ' && i > 2)
                        {
                            return(getKnownMethod(buffer.AsSpan(0, i)));
                        }

                        char ch = (char)b;
                        if ((ch < 'A' || ch > 'z' || (ch > 'Z' && ch < 'a')) && (ch != '-')) // ASCII letter
                        {
                            return(KnownMethod.Invalid);
                        }

                        i++;
                    }
                }

                // only letters, but no space (or shorter than 3 characters)
                return(KnownMethod.Invalid);
            }
            finally
            {
                bufferPool.ReturnBuffer(buffer);
            }
        }
示例#14
0
        private async Task writeAsyncInternal(string value, bool addNewLine, CancellationToken cancellationToken)
        {
            int newLineChars = addNewLine ? newLine.Length : 0;
            int charCount    = value.Length;

            if (charCount < bufferPool.BufferSize - newLineChars)
            {
                var buffer = bufferPool.GetBuffer();
                try
                {
                    int idx = encoding.GetBytes(value, 0, charCount, buffer, 0);
                    if (newLineChars > 0)
                    {
                        Buffer.BlockCopy(newLine, 0, buffer, idx, newLineChars);
                        idx += newLineChars;
                    }

                    await stream.WriteAsync(buffer, 0, idx, cancellationToken);
                }
                finally
                {
                    bufferPool.ReturnBuffer(buffer);
                }
            }
            else
            {
                var buffer = new byte[charCount + newLineChars + 1];
                int idx    = encoding.GetBytes(value, 0, charCount, buffer, 0);
                if (newLineChars > 0)
                {
                    Buffer.BlockCopy(newLine, 0, buffer, idx, newLineChars);
                    idx += newLineChars;
                }

                await stream.WriteAsync(buffer, 0, idx, cancellationToken);
            }
        }
示例#15
0
        /// <summary>
        ///     Determines whether the stream starts with the given string.
        /// </summary>
        /// <param name="clientStreamReader">The client stream reader.</param>
        /// <param name="expectedStart">The expected start.</param>
        /// <returns>
        ///     1: when starts with the given string, 0: when valid HTTP method, -1: otherwise
        /// </returns>
        private static async Task <int> startsWith(ICustomStreamReader clientStreamReader, IBufferPool bufferPool, int bufferSize, string expectedStart, CancellationToken cancellationToken = default)
        {
            int       iRet          = -1;
            const int lengthToCheck = 10;

            byte[] buffer = null;
            try
            {
                buffer = bufferPool.GetBuffer(Math.Max(bufferSize, lengthToCheck));

                int peeked = await clientStreamReader.PeekBytesAsync(buffer, 0, 0, lengthToCheck, cancellationToken);

                if (peeked > 0)
                {
                    bool isExpected = true;

                    for (int i = 0; i < lengthToCheck; i++)
                    {
                        int b = buffer[i];

                        if (b == ' ' && i > 2)
                        {
                            return(isExpected ? 1 : 0);
                        }
                        else
                        {
                            char ch = (char)b;
                            if (!char.IsLetter(ch))
                            {
                                return(-1);
                            }
                            else if (i >= expectedStart.Length || ch != expectedStart[i])
                            {
                                isExpected = false;
                            }
                        }
                    }

                    // only letters
                    iRet = isExpected ? 1 : 0;
                }
            }
            finally
            {
                bufferPool.ReturnBuffer(buffer);
                buffer = null;
            }
            return(iRet);
        }
示例#16
0
        /// <summary>
        /// Writes a byte to the current position in the stream and advances the position within the stream by one byte.
        /// </summary>
        /// <param name="value">The byte to write to the stream.</param>
        public override void WriteByte(byte value)
        {
            var buffer = bufferPool.GetBuffer(BufferSize);

            try
            {
                buffer[0] = value;
                OnDataWrite(buffer, 0, 1);
                baseStream.Write(buffer, 0, 1);
            }
            finally
            {
                bufferPool.ReturnBuffer(buffer);
            }
        }
        public async Task Finish()
        {
            if (bytesRemaining != -1)
            {
                var buffer = bufferPool.GetBuffer(baseStream.BufferSize);
                try
                {
                    int res = await ReadAsync(buffer, 0, buffer.Length);

                    if (res != 0)
                    {
                        throw new Exception("Data received after stream end");
                    }
                }
                finally
                {
                    bufferPool.ReturnBuffer(buffer);
                }
            }
        }