예제 #1
0
        /// <summary>
        /// Reads headers from a stream into the given frame.
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="headerCount"></param>
        /// <param name="frame"></param>
        private static void ReadHeadersFromStream(Stream stream, ushort headerCount, GdsFrame frame)
        {
            BinaryReader reader = new BinaryReader(stream);

            for (int i = 0; i < headerCount; i++)
            {
                ushort keyLength   = (ushort)IPAddress.NetworkToHostOrder((short)reader.ReadUInt16());
                ushort valueLength = (ushort)IPAddress.NetworkToHostOrder((short)reader.ReadUInt16());

                byte[] key = reader.ReadBytes(keyLength);

                if (key.Length != keyLength)
                {
                    throw new EndOfStreamException();
                }

                byte[] value = reader.ReadBytes(valueLength);

                if (value.Length != valueLength)
                {
                    throw new EndOfStreamException();
                }

                frame.Headers[HeaderEncoding.GetString(key)] = value;
            }
        }
예제 #2
0
        public void TestPing()
        {
            ObjectPool <byte[]> pool = new ObjectPool <byte[]>(() => { return(new byte[1024]); });

            Random rand = new Random(this.GetHashCode() ^ DateTime.Now.Millisecond);

            uint streamId = (uint)rand.Next(0, (int)(Math.Pow(2, 24) - 1));

            GdsFrame frame = GdsFrame.NewPingFrame(streamId);

            Assert.AreEqual(true, frame.IsComplete);
            Assert.AreEqual(GdsFrame.GdsFrameType.Ping, frame.Type);
            Assert.AreEqual(streamId, frame.StreamId);

            MemoryStream stream = new MemoryStream();

            frame.Write(stream);

            Assert.AreEqual(4, stream.Position);

            stream.Position = 0;

            GdsFrame readFrame = GdsFrame.ParseFrame(stream, pool);

            Assert.AreEqual(true, readFrame.IsComplete);
            Assert.AreEqual(GdsFrame.GdsFrameType.Ping, readFrame.Type);
            Assert.AreEqual(streamId, readFrame.StreamId);
        }
        public ChunkedBuffer ToBuffer(GdsFrame frame)
        {
            ObjectPool <byte[]> pool = new ObjectPool <byte[]>(() => { return(new byte[1024]); });

            ChunkedBuffer buffer = new ChunkedBuffer(pool);

            frame.Write(buffer.Stream);
            return(buffer);
        }
예제 #4
0
        public void TestFullCompressed()
        {
            ObjectPool <byte[]> pool = new ObjectPool <byte[]>(() => { return(new byte[1024]); });

            Random rand = new Random(this.GetHashCode() ^ DateTime.Now.Millisecond);

            uint streamId = (uint)rand.Next(0, (int)(Math.Pow(2, 24) - 1));

            string header1Key = "the first key";

            byte[] header1Value = new byte[rand.Next(32, 1024 * 64)];
            rand.NextBytes(header1Value);

            string header2Key = "the second key";

            byte[] header2Value = new byte[rand.Next(32, 1024 * 64)];
            rand.NextBytes(header2Value);

            byte[] bodyBuffer = new byte[rand.Next(1024, 1024 * 64)];
            rand.NextBytes(bodyBuffer);
            ChunkedBuffer body = new ChunkedBuffer(pool);

            body.OfferRaw(bodyBuffer, 0, bodyBuffer.Length);

            GdsFrame frame = GdsFrame.NewContentFrame(streamId, new Dictionary <string, byte[]>()
            {
                { header1Key, header1Value },
                { header2Key, header2Value }
            }, true, body, true);

            Assert.AreEqual(true, frame.IsComplete);
            Assert.AreEqual(GdsFrame.GdsFrameType.Full, frame.Type);
            Assert.AreEqual(streamId, frame.StreamId);
            Assert.AreEqual(2, frame.Headers.Count);

            MemoryStream stream = new MemoryStream();

            frame.Write(stream);

            stream.Position = 0;

            GdsFrame readFrame = GdsFrame.ParseFrame(stream, pool);

            Assert.AreEqual(true, readFrame.IsComplete);
            Assert.AreEqual(GdsFrame.GdsFrameType.Full, readFrame.Type);
            Assert.AreEqual(streamId, readFrame.StreamId);
            Assert.AreEqual(2, readFrame.Headers.Count);

            byte[] readBodyBuffer = new byte[readFrame.Body.AvailableBytesToRead];
            readFrame.Body.Read(readBodyBuffer, 0, readBodyBuffer.Length);

            AssertEquals(bodyBuffer, readBodyBuffer);

            frame.Dispose();
            readFrame.Dispose();
        }
            /// <summary>
            /// Updates the given chunked frame with a new frame.
            /// </summary>
            /// <param name="frame"></param>
            private static void UpdateChunk(ref GdsFrame chunkedFrame, GdsFrame frame, ISockNetChannel channel)
            {
                if (chunkedFrame == null)
                {
                    chunkedFrame = frame;  // set initial frame
                }
                else
                {
                    if (frame.Type == GdsFrame.GdsFrameType.Ping || frame.Type == GdsFrame.GdsFrameType.Pong || frame.Type == GdsFrame.GdsFrameType.Close)
                    {
                        chunkedFrame = frame;
                    }

                    GdsFrame.GdsFrameType type = chunkedFrame.Type;

                    ChunkedBuffer body = null;

                    if (frame.Type == GdsFrame.GdsFrameType.BodyOnly || frame.Type == GdsFrame.GdsFrameType.Full)
                    {
                        if (type == GdsFrame.GdsFrameType.HeadersOnly)
                        {
                            type = GdsFrame.GdsFrameType.Full;
                        }

                        body = new ChunkedBuffer(channel.BufferPool);
                        chunkedFrame.Body.DrainToStreamSync(body.Stream).Close();
                        frame.Body.DrainToStreamSync(body.Stream).Close();
                    }

                    Dictionary <string, byte[]> headers = null;

                    if (frame.Type == GdsFrame.GdsFrameType.HeadersOnly || frame.Type == GdsFrame.GdsFrameType.Full)
                    {
                        if (type == GdsFrame.GdsFrameType.BodyOnly)
                        {
                            type = GdsFrame.GdsFrameType.Full;
                        }

                        headers = new Dictionary <string, byte[]>(StringComparer.OrdinalIgnoreCase);
                        foreach (KeyValuePair <string, byte[]> kvp in chunkedFrame.Headers)
                        {
                            headers[kvp.Key] = kvp.Value;
                        }
                        foreach (KeyValuePair <string, byte[]> kvp in frame.Headers)
                        {
                            headers[kvp.Key] = kvp.Value;
                        }
                    }

                    chunkedFrame.Dispose();
                    frame.Dispose();

                    chunkedFrame = GdsFrame.NewContentFrame(frame.StreamId, headers, false, body, frame.IsComplete);
                }
            }
예제 #6
0
        public void TestHeaderOnlyNotCompressed()
        {
            ObjectPool <byte[]> pool = new ObjectPool <byte[]>(() => { return(new byte[1024]); });

            Random rand = new Random(this.GetHashCode() ^ DateTime.Now.Millisecond);

            uint streamId = (uint)rand.Next(0, (int)(Math.Pow(2, 24) - 1));

            string header1Key = "the first key";

            byte[] header1Value = new byte[rand.Next(32, 1024 * 64)];
            rand.NextBytes(header1Value);

            string header2Key = "the second key";

            byte[] header2Value = new byte[rand.Next(32, 1024 * 64)];
            rand.NextBytes(header2Value);

            GdsFrame frame = GdsFrame.NewContentFrame(streamId, new Dictionary <string, byte[]>()
            {
                { header1Key, header1Value },
                { header2Key, header2Value }
            },
                                                      false, null, true);

            Assert.AreEqual(true, frame.IsComplete);
            Assert.AreEqual(GdsFrame.GdsFrameType.HeadersOnly, frame.Type);
            Assert.AreEqual(streamId, frame.StreamId);
            Assert.AreEqual(2, frame.Headers.Count);

            MemoryStream stream = new MemoryStream();

            frame.Write(stream);

            Assert.AreEqual(
                4           // frame definition
                + 2         // header definition
                + (4 * 2)   // header sizes for two headers
                + header1Key.Length + header1Value.Length + header2Key.Length + header2Value.Length
                , stream.Position);

            stream.Position = 0;

            GdsFrame readFrame = GdsFrame.ParseFrame(stream, pool);

            Assert.AreEqual(true, readFrame.IsComplete);
            Assert.AreEqual(GdsFrame.GdsFrameType.HeadersOnly, readFrame.Type);
            Assert.AreEqual(streamId, readFrame.StreamId);
            Assert.AreEqual(2, readFrame.Headers.Count);

            AssertEquals(header1Value, readFrame.Headers[header1Key]);
            AssertEquals(header2Value, readFrame.Headers[header2Key]);
        }
            /// <summary>
            /// Handles an incomming raw Gds message.
            /// </summary>
            /// <param name="channel"></param>
            /// <param name="obj"></param>
            public void HandleIncoming(ISockNetChannel channel, ref object obj)
            {
                if (!(obj is ChunkedBuffer))
                {
                    return;
                }

                ChunkedBuffer stream           = (ChunkedBuffer)obj;
                long          startingPosition = stream.ReadPosition;

                try
                {
                    GdsFrame frame = GdsFrame.ParseFrame(stream.Stream, channel.BufferPool);

                    if (combineChunks)
                    {
                        if (frame.IsComplete)
                        {
                            UpdateChunk(ref chunkedFrame, frame, channel);

                            obj          = chunkedFrame;
                            chunkedFrame = null;
                        }
                        else
                        {
                            UpdateChunk(ref chunkedFrame, frame, channel);
                        }
                    }
                    else
                    {
                        obj = frame;
                    }

                    if (SockNetLogger.DebugEnabled)
                    {
                        SockNetLogger.Log(SockNetLogger.LogLevel.DEBUG, this, "Received Gds message. Body Size: {0}, Type: {1}, IsComplete: {2}", frame.Body.AvailableBytesToRead, Enum.GetName(typeof(GdsFrame.GdsFrameType), frame.Type), frame.IsComplete);
                    }
                }
                catch (EndOfStreamException)
                {
                    // frame isn't done
                    stream.ReadPosition = startingPosition;
                }
                catch (ArgumentOutOfRangeException)
                {
                    // frame isn't done
                    stream.ReadPosition = startingPosition;
                }
                catch (Exception e)
                {
                    SockNetLogger.Log(SockNetLogger.LogLevel.ERROR, this, "Unable to parse Gds message", e);
                }
            }
예제 #8
0
        public void TestBodyOnly()
        {
            ObjectPool <byte[]> pool = new ObjectPool <byte[]>(() => { return(new byte[1024]); });

            Random rand = new Random(this.GetHashCode() ^ DateTime.Now.Millisecond);

            uint streamId = (uint)rand.Next(0, (int)(Math.Pow(2, 24) - 1));

            byte[] bodyBuffer = new byte[rand.Next(1024, 1024 * 64)];
            rand.NextBytes(bodyBuffer);
            ChunkedBuffer body = new ChunkedBuffer(pool);

            body.OfferRaw(bodyBuffer, 0, bodyBuffer.Length);

            GdsFrame frame = GdsFrame.NewContentFrame(streamId, null, false, body, true);

            Assert.AreEqual(true, frame.IsComplete);
            Assert.AreEqual(GdsFrame.GdsFrameType.BodyOnly, frame.Type);
            Assert.AreEqual(streamId, frame.StreamId);
            Assert.AreEqual(0, frame.Headers.Count);

            MemoryStream stream = new MemoryStream();

            frame.Write(stream);

            Assert.AreEqual(
                4           // frame definition
                + 4         // body definition
                + bodyBuffer.Length
                , stream.Position);

            stream.Position = 0;

            GdsFrame readFrame = GdsFrame.ParseFrame(stream, pool);

            Assert.AreEqual(true, readFrame.IsComplete);
            Assert.AreEqual(GdsFrame.GdsFrameType.BodyOnly, readFrame.Type);
            Assert.AreEqual(streamId, readFrame.StreamId);
            Assert.AreEqual(0, readFrame.Headers.Count);

            byte[] readBodyBuffer = new byte[readFrame.Body.AvailableBytesToRead];
            readFrame.Body.Read(readBodyBuffer, 0, readBodyBuffer.Length);

            AssertEquals(bodyBuffer, readBodyBuffer);

            frame.Dispose();
            readFrame.Dispose();
        }
            /// <summary>
            /// Handles an outgoing HttpRequest and converts it to a raw buffer.
            /// </summary>
            /// <param name="channel"></param>
            /// <param name="obj"></param>
            public void HandleOutgoing(ISockNetChannel channel, ref object obj)
            {
                if (!(obj is GdsFrame))
                {
                    return;
                }

                GdsFrame      gdsFrame = (GdsFrame)obj;
                ChunkedBuffer buffer   = new ChunkedBuffer(channel.BufferPool);

                gdsFrame.Write(buffer.Stream);

                gdsFrame.Dispose();

                obj = buffer;
            }
        public void TestSimpleSslContent()
        {
            ObjectPool <byte[]> pool = new ObjectPool <byte[]>(() => { return(new byte[1024]); });

            GdsEchoServer server = new GdsEchoServer(pool);

            try
            {
                server.Start(true);

                BlockingCollection <object> blockingCollection = new BlockingCollection <object>();

                ClientSockNetChannel client = (ClientSockNetChannel)SockNetClient.Create(server.Endpoint, ClientSockNetChannel.DefaultNoDelay, ClientSockNetChannel.DefaultTtl, pool)
                                              .AddModule(new GdsSockNetChannelModule(true));

                client.ConnectWithTLS((object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => { return(true); })
                .WaitForValue(TimeSpan.FromSeconds(5));

                object currentObject;

                client.Pipe.AddIncomingLast <GdsFrame>((ISockNetChannel sockNetClient, ref GdsFrame data) => { blockingCollection.Add(data); });

                ChunkedBuffer body = new ChunkedBuffer(pool);
                body.OfferRaw(Encoding.UTF8.GetBytes("some test"), 0, Encoding.UTF8.GetByteCount("some test"));

                client.Send(GdsFrame.NewContentFrame(1, null, false, body, true));

                Assert.IsTrue(blockingCollection.TryTake(out currentObject, 5000));
                Assert.IsTrue(currentObject is GdsFrame);

                Assert.AreEqual("some test", ((GdsFrame)currentObject).Body.ToString(Encoding.UTF8));

                Console.WriteLine("Got response: \n" + ((GdsFrame)currentObject).Body);

                client.Disconnect().WaitForValue(TimeSpan.FromSeconds(5));
            }
            finally
            {
                server.Stop();
            }
        }
예제 #11
0
        public void TestCompression()
        {
            Random rand = new Random(this.GetHashCode() ^ DateTime.Now.Millisecond);

            uint streamId = (uint)rand.Next(0, (int)(Math.Pow(2, 24) - 1));

            // deflate works great on text - it is horrible with random byte arrays
            string header1Key = "Some key";

            byte[] header1Value = Encoding.UTF8.GetBytes("Well here is a great value for some key. We're really great at making keys and value.");

            string header2Key = "Another key";

            byte[] header2Value = Encoding.UTF8.GetBytes("Yet another great value for another key. This is just getting absurd.");

            GdsFrame frame = GdsFrame.NewContentFrame(streamId, new Dictionary <string, byte[]>()
            {
                { header1Key, header1Value },
                { header2Key, header2Value }
            },
                                                      true, null, true);

            Assert.AreEqual(true, frame.IsComplete);
            Assert.AreEqual(GdsFrame.GdsFrameType.HeadersOnly, frame.Type);
            Assert.AreEqual(streamId, frame.StreamId);
            Assert.AreEqual(2, frame.Headers.Count);

            MemoryStream stream = new MemoryStream();

            frame.Write(stream);

            int uncompressedSize = (4         // frame definition
                                    + 2       // header definition
                                    + (4 * 2) // header sizes for two headers
                                    + header1Key.Length + header1Value.Length + header2Key.Length + header2Value.Length);

            Console.WriteLine("Compressed: " + stream.Position + ", Uncompressed: " + uncompressedSize);

            Assert.IsTrue(stream.Position < uncompressedSize);
        }
예제 #12
0
        /// <summary>
        /// Creates a new content frame where the frame is a headers only, body only, or a full frame.
        /// </summary>
        /// <param name="streamId"></param>
        /// <param name="headers"></param>
        /// <param name="areHeadersCompressed"></param>
        /// <param name="body"></param>
        /// <param name="isComplete"></param>
        /// <returns></returns>
        public static GdsFrame NewContentFrame(uint streamId, Dictionary <string, byte[]> headers = null, bool areHeadersCompressed = false, ChunkedBuffer body = null, bool isComplete = true)
        {
            GdsFrameType type = GdsFrameType.Full;

            if (body == null)
            {
                type = GdsFrameType.HeadersOnly;
            }
            else if (headers == null)
            {
                type = GdsFrameType.BodyOnly;
            }

            GdsFrame frame = new GdsFrame(null)
            {
                IsComplete           = isComplete,
                Type                 = type,
                StreamId             = streamId,
                AreHeadersCompressed = areHeadersCompressed
            };

            if (headers != null)
            {
                foreach (KeyValuePair <string, byte[]> kvp in headers)
                {
                    frame.Headers[kvp.Key] = kvp.Value;
                }
            }

            if (body != null)
            {
                frame.Body = body;
            }

            return(frame);
        }
        public void TestChunks()
        {
            ObjectPool <byte[]> pool = new ObjectPool <byte[]>(() => { return(new byte[1024]); });

            DummySockNetChannel channel = new DummySockNetChannel()
            {
                State      = null,
                IsActive   = true,
                BufferPool = pool
            };

            channel.Pipe = new SockNetChannelPipe(channel);

            GdsSockNetChannelModule module = new GdsSockNetChannelModule(true);

            channel.AddModule(module);
            channel.Connect();

            uint streamId = 1;

            ChunkedBuffer body = new ChunkedBuffer(pool);

            body.OfferRaw(Encoding.UTF8.GetBytes("This "), 0, Encoding.UTF8.GetByteCount("This "));

            GdsFrame chunk1 = GdsFrame.NewContentFrame(streamId, new Dictionary <string, byte[]>()
            {
                { "test1", new byte[] { 1 } },
                { "test", new byte[] { 1 } },
            },
                                                       false, body, false);
            ChunkedBuffer buffer          = ToBuffer(chunk1);
            object        receiveResponse = buffer;

            channel.Receive(ref receiveResponse);
            buffer.Close();

            Assert.IsTrue(receiveResponse is ChunkedBuffer);

            body = new ChunkedBuffer(pool);
            body.OfferRaw(Encoding.UTF8.GetBytes("is "), 0, Encoding.UTF8.GetByteCount("is "));

            GdsFrame chunk2 = GdsFrame.NewContentFrame(streamId, new Dictionary <string, byte[]>()
            {
                { "test2", new byte[] { 2 } },
                { "test", new byte[] { 2 } },
            },
                                                       false, body, false);

            buffer          = ToBuffer(chunk2);
            receiveResponse = buffer;
            channel.Receive(ref receiveResponse);
            buffer.Close();

            Assert.IsTrue(receiveResponse is ChunkedBuffer);

            body = new ChunkedBuffer(pool);
            body.OfferRaw(Encoding.UTF8.GetBytes("awesome!"), 0, Encoding.UTF8.GetByteCount("awesome!"));

            GdsFrame chunk3 = GdsFrame.NewContentFrame(streamId, new Dictionary <string, byte[]>()
            {
                { "test3", new byte[] { 3 } },
                { "test", new byte[] { 3 } },
            },
                                                       false, body, true);

            buffer          = ToBuffer(chunk3);
            receiveResponse = buffer;
            channel.Receive(ref receiveResponse);
            buffer.Close();

            Assert.IsTrue(receiveResponse is GdsFrame);
            Assert.AreEqual("This is awesome!", ((GdsFrame)receiveResponse).Body.ToString(Encoding.UTF8));
            Assert.AreEqual(1, ((GdsFrame)receiveResponse).Headers["test1"][0]);
            Assert.AreEqual(2, ((GdsFrame)receiveResponse).Headers["test2"][0]);
            Assert.AreEqual(3, ((GdsFrame)receiveResponse).Headers["test3"][0]);
            Assert.AreEqual(3, ((GdsFrame)receiveResponse).Headers["test"][0]);

            body.Dispose();
            chunk1.Dispose();
            chunk2.Dispose();
            chunk3.Dispose();

            Console.WriteLine("Pool stats: " + pool.ObjectsInPool + "/" + pool.TotalNumberOfObjects);
        }
예제 #14
0
        /// <summary>
        /// Parses a frame from a stream.
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static GdsFrame ParseFrame(Stream stream, ObjectPool <byte[]> bufferPool)
        {
            GdsFrame frame = new GdsFrame(bufferPool);

            BinaryReader reader = new BinaryReader(stream);

            uint frameDefinition = (uint)IPAddress.NetworkToHostOrder((int)reader.ReadUInt32());

            if (!Enum.IsDefined(typeof(GdsFrameType), (byte)((frameDefinition & (uint)TypeMask) >> TypeShift)))
            {
                throw new ArgumentException("Invalid type: " + (GdsFrameType)(byte)((frameDefinition & (uint)TypeMask) >> TypeShift));
            }

            frame.IsComplete = ((frameDefinition & IsCompleteMask) >> IsCompleteShift) == 1;
            frame.Type       = (GdsFrameType)(byte)((frameDefinition & (uint)TypeMask) >> TypeShift);
            frame.StreamId   = (frameDefinition & (uint)StreamIdMask) >> StreamIdShift;

            // parse the headers
            if (frame.Type == GdsFrameType.Full || frame.Type == GdsFrameType.HeadersOnly)
            {
                ushort headersDefinition = (ushort)IPAddress.NetworkToHostOrder((short)reader.ReadUInt16());

                frame.AreHeadersCompressed = ((headersDefinition & (ushort)HeadersIsCompressedMask) >> HeadersIsCompressedShift) == 1;
                ushort count = (ushort)((headersDefinition & HeadersLengthMask) >> HeadersLengthShift);

                if (frame.AreHeadersCompressed)
                {
                    long movePosition = stream.Position;

                    using (DeflateStream compressedHeaderStream = new DeflateStream(stream, CompressionMode.Decompress, true))
                    {
                        ReadHeadersFromStream(compressedHeaderStream, count, frame);

                        movePosition += compressedHeaderStream.TotalIn;
                    }

                    stream.Position = movePosition; // we need to fix the position since the DeflateStream buffers the base stream
                }
                else
                {
                    ReadHeadersFromStream(stream, count, frame);
                }
            }

            // read the body
            if (frame.Type == GdsFrameType.Full || frame.Type == GdsFrameType.BodyOnly)
            {
                uint length = (uint)IPAddress.NetworkToHostOrder((int)reader.ReadUInt32());

                frame.Body = new ChunkedBuffer(bufferPool);

                PooledObject <byte[]> buffer = bufferPool.Borrow();
                int count = 0;

                while ((count = reader.Read(buffer.Value, 0, buffer.Value.Length)) > 0)
                {
                    frame.Body.OfferChunk(buffer, 0, count);

                    buffer = bufferPool.Borrow();
                }

                if (count < 1)
                {
                    buffer.Return();
                }

                if (frame.Body.AvailableBytesToRead != length)
                {
                    throw new EndOfStreamException();
                }
            }

            return(frame);
        }