Example #1
0
        void ToggleObjectsByMetadataGroup(NetContext <MetadataCategoryGroupToggle> ctx)
        {
            var group   = ctx.Data.Value.groupKey;
            var filter  = ctx.Data.Value.filterKey;
            var visible = ctx.Data.Value.visible;

            if (!m_DisabledGroups.ContainsKey(group))
            {
                m_DisabledGroups.Add(group, new List <string>());
            }

            if (visible)
            {
                m_DisabledGroups[group].Remove(filter);
            }
            else
            {
                m_DisabledGroups[group].Add(filter);
            }

            if (GetFilterData(group, filter, out var ids))
            {
                m_ToggleGameObjectOutput.Send(new ToggleGameObject(ids.Select(x => (x, visible ? 1 : -1)).ToList()));
            }
        }
Example #2
0
        protected override int ProcessIncoming(NetContext context, Connection connection, Stream incomingBuffer)
        {
            int len = FindHeadersLength(incomingBuffer);
            if (len <= 0) return 0;

            incomingBuffer.Position = 0;
            int extraConsumed;
            if (len < NetContext.BufferSize)
            {
                byte[] buffer = null;
                try
                {
                    buffer = context.GetBuffer();
                    NetContext.Fill(incomingBuffer, buffer, len);
                    using (var ms = new MemoryStream(buffer, 0, len))
                    {
                        extraConsumed = ProcessHeadersAndUpgrade(context, connection, ms, incomingBuffer, len);
                    }
                }
                finally
                {
                    context.Recycle(buffer);
                }
            }
            else
            {
                using (var ss = new SubStream(incomingBuffer, len))
                {
                    extraConsumed = ProcessHeadersAndUpgrade(context, connection, ss, incomingBuffer, len);
                }
            }
            if (extraConsumed < 0) return 0; // means: wasn't usable (yet)

            return len + extraConsumed;
        }
        protected override int ProcessHeadersAndUpgrade(NetContext context, Connection connection, Stream input, Stream additionalData, int additionalOffset)
        {
            string requestLine;
            var    headers = ParseHeaders(input, out requestLine);

            if (!string.Equals(headers["Upgrade"], "WebSocket", StringComparison.InvariantCultureIgnoreCase) ||
                !string.Equals(headers["Connection"], "Upgrade", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new InvalidOperationException();
            }

            lock (this)
            {
                var protocol = new WebSocketsProcessor_Hixie76_00.Client(expectedSecurityResponse);
                expectedSecurityResponse = null; // use once only
                connection.SetProtocol(protocol);
                if (pending != null)
                {
                    while (pending.Count != 0)
                    {
                        connection.Send(context, pending.Dequeue());
                    }
                }
            }
            return(0);
        }
        protected override int ProcessHeadersAndUpgrade(NetContext context, Connection connection, Stream input, Stream additionalData, int additionalOffset)
        {
            string requestLine;
            var    headers = ParseHeaders(input, out requestLine);

            if (!string.Equals(headers["Upgrade"], "WebSocket", StringComparison.InvariantCultureIgnoreCase) ||
                !string.Equals(headers["Connection"], "Upgrade", StringComparison.InvariantCultureIgnoreCase) ||
                headers["Sec-WebSocket-Accept"] != expected)
            {
                throw new InvalidOperationException();
            }

            lock (this)
            {
                AddMatchingExtensions(headers, connection, context.Extensions);
                var protocol = new WebSocketsProcessor_RFC6455_13(true);
                connection.SetProtocol(protocol);
                if (pending != null)
                {
                    while (pending.Count != 0)
                    {
                        connection.Send(context, pending.Dequeue());
                    }
                }
            }
            return(0);
        }
        private INetContext GetContext()
        {
            INetContext ctx = new NetContext();

            ctx.Services.Register <TestService>();
            return(ctx);
        }
 void IMessageProcessor.Received(NetContext context, Connection connection, object message)
 {
     string s;
     byte[] b;
     if((s = message as string) != null) OnReceive((WebSocketConnection)connection, s);
     else if ((b = message as byte[]) != null) OnReceive((WebSocketConnection)connection, b);
 }
            protected internal override void CompleteHandshake(NetContext context, Connection connection, System.IO.Stream input, string requestLine, System.Collections.Specialized.StringDictionary headers, byte[] body)
            {
                keys = Tuple.Create(headers["Sec-WebSocket-Key1"], headers["Sec-WebSocket-Key2"]);
                var builder = new StringBuilder(
                    "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
                    + "Upgrade: WebSocket\r\n"
                    + "Connection: Upgrade\r\n");
                var conn = (WebSocketConnection)connection;

                if (!string.IsNullOrEmpty(conn.Host))
                { // we should add the origin/location, but that depends on what we have available to us
                    builder.Append("Sec-WebSocket-Origin: ").Append(conn.Origin).Append("\r\n");
                    if (!string.IsNullOrEmpty(conn.RequestLine))
                    {
                        Match match;
                        if ((match = Regex.Match(conn.RequestLine, @"GET ([^\s]+) HTTP")).Success)
                        {
                            builder.Append("Sec-WebSocket-Location: ").Append("ws://").Append(conn.Host).Append(match.Groups[1].Value).Append("\r\n");
                        }
                    }
                }
                if (!string.IsNullOrEmpty(conn.Protocol))
                {
                    builder.Append("Sec-WebSocket-Protocol: ").Append(conn.Protocol).Append("\r\n");
                }
                builder.Append("\r\n");
                SendControl(context, new StringFrame(builder.ToString(), Encoding.ASCII, false));
                connection.PromptToSend(context);
            }
 protected IFrame Pop(NetContext context)
 {
     lock (this)
     {
         return(ProtocolProcessor.GetFrame(context, ref holder));
     }
 }
Example #9
0
 public Message(NetContext context, Connection connection, object value)
 {
     this.context = context;
     this.connection = connection;
     this.value = value;
     isHandled = false;
 }
Example #10
0
        private INetContext CreateContext()
        {
            INetContext ctx = new NetContext();

            ctx.ApplicationName = Guid.NewGuid().ToString();
            ctx.IPAddress       = "localhost";
            ctx.MaxConnections  = 10;
            ctx.Port            = 1111;
            ctx.Serializer.AddReaderWriter <TestData>(
                new DataWriter(ctx.Serializer, typeof(TestData)),
                new DataReader(ctx.Serializer, typeof(TestData)));

            ctx.Services.Register <Svc1>();
            ctx.Services.Register <Svc2>();
            ctx.Services.Register <Svc3>();
            ctx.Services.Register <Svc4>();

            ctx.Packets.Register <Pck4>();
            ctx.Packets.Register <Pck3>();
            ctx.Packets.Register <Pck2>();
            ctx.Packets.Register <Pck1>();

            ctx.LockContext();
            return(ctx);
        }
Example #11
0
        public static void Send(this Chunk chunk, NetContext context)
        {
            NetPack netPack = context.GetNetBlock((int)NetMessageType.Chunk, Chunk.c_minimumSize);

            chunk.ToNetBlock(netPack);
            context.Send(netPack);
        }
Example #12
0
        void OnSpatialDataChanged(NetContext <SpatialDataChanged> ctx)
        {
            var added   = ctx.Data.Added.Select(x => x.Id).ToList();
            var removed = ctx.Data.Removed.Select(x => x.Id).ToList();

            m_UpdateStreamingOutput.Send(new UpdateStreaming(added, removed));
        }
Example #13
0
        public void CompressFrame()
        {
            var handler = new TcpHandler();
            var ctx     = new NetContext(delegate { }, handler);

            IExtensionFactory factory = new PerFrameDeflate(0, false);
            var extn  = factory.CreateExtension("deflate-frame");
            var data  = Encoding.UTF8.GetBytes("Hello");
            var frame = new WebSocketsFrame
            {
                OpCode        = WebSocketsFrame.OpCodes.Text,
                Payload       = new MemoryStream(data),
                PayloadLength = data.Length,
                Reserved1     = false
            };
            var connection = new WebSocketConnection(new IPEndPoint(IPAddress.Loopback, 20000));
            var encoded    = extn.ApplyOutgoing(ctx, connection, frame).Single();
            var ms         = new MemoryStream();

            encoded.Payload.CopyTo(ms);
            string hex = BitConverter.ToString(ms.GetBuffer(), 0, (int)ms.Length);

            Assert.AreEqual("F2-48-CD-C9-C9-07-00", hex);

            // unrelated decoder
            extn = PerFrameDeflate.Default.CreateExtension("deflate-frame");
            var decoded = extn.ApplyIncoming(ctx, connection, frame).Single();

            ms = new MemoryStream();
            decoded.Payload.Position = 0;
            decoded.Payload.CopyTo(ms);
            string s = Encoding.UTF8.GetString(ms.GetBuffer(), 0, (int)ms.Length);

            Assert.AreEqual("Hello", s);
        }
        void OnGameObjectCreated(NetContext <GameObjectCreated> ctx)
        {
            var gameObject = ctx.Data.GameObject;

            if (!gameObject.TryGetComponent <Metadata>(out var metadata))
            {
                return;
            }

            m_GameObjects.Add(gameObject);

            bool setHighlight = false;

            foreach (var groupKey in m_Settings.Safelist)
            {
                if (metadata.GetParameters().TryGetValue(groupKey, out Metadata.Parameter category))
                {
                    if (string.IsNullOrEmpty(category.value))
                    {
                        continue;
                    }

                    // check categories
                    if (!m_FilterGroups.ContainsKey(groupKey))
                    {
                        m_FilterGroups[groupKey] = new Dictionary <string, FilterData>();
                        m_MetadataGroupsChangedOutput.Broadcast(new MetadataGroupsChanged(m_FilterGroups.Keys.OrderBy(e => e).ToList()));
                    }

                    var dicFilterData = m_FilterGroups[groupKey];
                    if (!dicFilterData.ContainsKey(category.value))
                    {
                        dicFilterData[category.value] = new FilterData();
                        m_MetadataCategoriesChangedOutput.Broadcast(new MetadataCategoriesChanged(groupKey, dicFilterData.Keys.OrderBy(e => e).ToList()));
                    }

                    // set filters
                    if (!GetFilterData(groupKey, category.value, out var filterData))
                    {
                        return;
                    }

                    filterData.Instances.Add(gameObject);

                    if (!filterData.Visible)
                    {
                        gameObject.SetActive(false);
                    }

                    if (m_HighlightedFilterData == filterData)
                    {
                        setHighlight = true;
                    }
                }
            }
            if (m_HighlightedFilterData != null)
            {
                gameObject.SetLayerRecursively(setHighlight ? k_SelectedLayer : k_OtherLayer);
            }
        }
Example #15
0
        void UpdateVisibility(NetContext <UpdateVisibility> ctx)
        {
            foreach (var guid in ctx.Data.ShownInstances)
            {
                if (m_IdToGameObjects.TryGetValue(guid, out var obj))
                {
                    obj.SetActive(!m_Settings.DisplayOnlyBoundingBoxes);
                }
                if (m_IdToBoxes.TryGetValue(guid, out var box))
                {
                    box.gameObject.SetActive(m_Settings.DisplayOnlyBoundingBoxes || obj == null);
                }
            }

            foreach (var guid in ctx.Data.HiddenInstances)
            {
                if (m_IdToBoxes.TryGetValue(guid, out var box))
                {
                    box.gameObject.SetActive(false);
                }
                if (m_IdToGameObjects.TryGetValue(guid, out var obj))
                {
                    obj.SetActive(false);
                }
            }
        }
Example #16
0
 public Message(NetContext context, Connection connection, object value)
 {
     this.context    = context;
     this.connection = connection;
     this.value      = value;
     isHandled       = false;
 }
        protected override void InitializeClientHandshake(NetContext context, Connection conn)
        {
            var connection = (WebSocketConnection) conn;
            if (string.IsNullOrEmpty(connection.Host)) throw new InvalidOperationException("Host must be specified");
            if (string.IsNullOrEmpty(connection.RequestLine)) throw new InvalidOperationException("RequestLine must be specified");

            string key1 = CreateRandomKey(), key2 = CreateRandomKey();
            byte[] key3 = new byte[8];
            NetContext.GetRandomBytes(key3);

            StringBuilder req = new StringBuilder(connection.RequestLine).Append("\r\n" +
                                    "Upgrade: WebSocket\r\n" + // note casing!
                                    "Connection: Upgrade\r\n" +
                                    "Sec-WebSocket-Key1: ").Append(key1).Append("\r\n" +
                                    "Sec-WebSocket-Key2: ").Append(key2).Append("\r\n" +
                                    "Host: ").Append(connection.Host).Append("\r\n");
            if (!string.IsNullOrEmpty(connection.Origin))
                req.Append("Origin: ").Append(connection.Origin).Append("\r\n");
            if (!string.IsNullOrEmpty(connection.Protocol))
                req.Append("Sec-WebSocket-Protocol: ").Append(connection.Protocol).Append("\r\n");
            req.Append("\r\n");




            expectedSecurityResponse = WebSocketsProcessor_Hixie76_00.ComputeKey(key1, key2, key3);
            EnqueueFrame(context, new StringFrame(req.ToString(), Encoding.ASCII, false));
            EnqueueFrame(context, new BinaryFrame(key3));
            connection.PromptToSend(context);
        }
        void OnEntryDataChanged(NetContext <EntryDataChanged> ctx)
        {
            m_AssetCountData.NbAdded   += ctx.Data.Added.Count;
            m_AssetCountData.NbChanged += ctx.Data.Changed.Count;
            m_AssetCountData.NbRemoved += ctx.Data.Removed.Count;

            m_AssetCountChangedOutput.Broadcast(new AssetCountChanged(m_AssetCountData));
        }
Example #19
0
        void OnSpatialDataChanged(NetContext <SpatialDataChanged> ctx)
        {
            var added = ctx.Data.Delta.Added.Select(x => x.Id).Count();

            //var removed = ctx.Data.Delta.Removed.Select(x => x.Id).ToList();

            PerformanceTests.s_InstanceCount = added;
        }
 void IMessageProcessor.StartProcessor(NetContext context, string configuration)
 {
     if (Interlocked.CompareExchange(ref processorContext, context, null) != null)
     {
         throw new InvalidOperationException("Processor already has a context");
     }
     OnStartup(configuration);
 }
        void OnSpatialDataChanged(NetContext <SpatialDataChanged> ctx)
        {
            m_InstanceCountData.NbAdded   += ctx.Data.Added.Count;
            m_InstanceCountData.NbChanged += ctx.Data.Changed.Count;
            m_InstanceCountData.NbRemoved += ctx.Data.Removed.Count;

            m_InstanceCountChangedOutput.Broadcast(new InstanceCountChanged(m_InstanceCountData));
        }
Example #22
0
        public void DeflateRoundTrip()
        {
            var handler = new TcpHandler();
            var ctx     = new NetContext(delegate { }, handler);

            var extn = PerFrameDeflate.Default.CreateExtension("deflate-frame");
            var conn = new WebSocketConnection(new IPEndPoint(IPAddress.Loopback, 20000));

            string[] messages =
            {
                "This extension uses one reserved bit to indicate whether DEFLATE is applied to the frame or not.  We call this \"COMP\" bit.",
                "Hello",
                "This extension operates only on data frames, and only on the \"Application data\" therein (it does not affect the \"Extension data\" portion of the \"Payload data\").",
                "world",                                                                                                                                                                                                         "Hello",
                "To send a frame with DEFLATE applied, an endpoint MUST use the following algorithm.",
                "world",
                "Apply DEFLATE [RFC1951] to all the octets in the \"Application data\" part of the frame.  Multiple blocks MAY be used.  Any type of block MAY be used.  Both block with \"BFINAL\" set to 0 and 1 MAY be used.",
                "If the resulting data does not end with an empty block with no compression (\"BTYPE\" set to 0), append an empty block with no compression to the tail.",
                "Remove 4 octets (that are 0x00 0x00 0xff 0xff) from the tail.",
                "Hello",
                "Build a frame by putting the resulting octets in the \"Application data\" part instead of the original octets.  The payload length field of the frame MUST be the sum of the size of the \"Extension data\" part and these resulting octets.  \"COMP\" bit MUST be set to 1."
            };

            var frames = Array.ConvertAll(messages, CreateFrame);

            int initialSize = frames.Sum(x => x.PayloadLength);

            Assert.IsTrue(frames.All(x => !x.Reserved1), "no COMP initially");
            var munged = frames.SelectMany(f => extn.ApplyOutgoing(ctx, conn, f)).ToArray();

            Assert.AreEqual(frames.Length, munged.Length, "compress: 1 in, 1 out");

            Assert.IsTrue(frames.Any(x => x.Reserved1), "some COMP after compress");
            Assert.IsTrue(frames.Any(x => !x.Reserved1), "some non-COMP after compress");

            for (int i = 0; i < munged.Length; i++)
            {
                var ms = new MemoryStream();
                munged[i].Payload.Position = 0;
                munged[i].Payload.CopyTo(ms);
                ms.Position       = 0;
                munged[i].Payload = new MemoryStream(ms.ToArray()); // read-only, deliberately
            }
            int mungedSize = frames.Sum(x => x.PayloadLength);

            var unmunged = munged.SelectMany(f => extn.ApplyIncoming(ctx, conn, f)).ToArray();

            Assert.AreEqual(unmunged.Length, unmunged.Length, "inflate: 1 in, 1 out");
            Assert.IsTrue(unmunged.All(x => !x.Reserved1), "no COMP after inflate");

            int unmungedSize = unmunged.Sum(x => x.PayloadLength);

            Console.WriteLine("Uncompressed: {0} bytes; compressed: {1} bytes; inflated {2} bytes", initialSize, mungedSize, unmungedSize);

            string[] finalMessages = Array.ConvertAll(unmunged, ReadFrameMessage);

            Assert.IsTrue(finalMessages.SequenceEqual(messages), "Equal messages");
        }
 protected void Buffer(NetContext context, byte[] buffer, int offset, int count)
 {
     if (incoming == null)
     {
         incoming = new BufferStream(context, context.Handler.MaxIncomingQuota);
     }
     incoming.Position = incoming.Length;
     incoming.Write(buffer, offset, count);
 }
        void OnGameObjectCreated(NetContext <GameObjectCreated> ctx)
        {
            m_GameObjectCountData.NbAdded++;

            m_StreamingProgressedOutput.Broadcast(new StreamingProgressed(
                                                      m_GameObjectCountData.NbAdded - m_GameObjectCountData.NbRemoved,
                                                      m_InstanceCountData.NbAdded - m_InstanceCountData.NbRemoved));

            m_GameObjectCountChangedOutput.Broadcast(new GameObjectCountChanged(m_InstanceCountData));
        }
        protected void SendData(NetContext context, IFrame frame)
        {
            lock(this)
            {
                ProtocolProcessor.AddFrame(context, ref dataQueue, frame);
#if VERBOSE
                Debug.WriteLine("pushed (data): " + frame);
#endif
            }
        }
        protected void SendData(NetContext context, IFrame frame)
        {
            lock (this)
            {
                ProtocolProcessor.AddFrame(context, ref dataQueue, frame);
#if VERBOSE
                Debug.WriteLine("pushed (data): " + frame);
#endif
            }
        }
Example #27
0
        protected INetContext CreateContext()
        {
            INetContext ctx = new NetContext();

            ctx.ApplicationName = "TestApp";
            ctx.IPAddress       = "localhost";
            ctx.Port            = Common.Port;
            ctx.MaxConnections  = 10;
            return(ctx);
        }
Example #28
0
        public virtual INetContext GetContext(string ip, int port)
        {
            INetContext ret = new NetContext();

            ret.Services.Register <TService>();

            ret.IPAddress = "localhost";
            ret.Port      = port;
            return(ret);
        }
 void CancelStreamingOfHiddenInstances(NetContext <UpdateStreaming> ctx)
 {
     foreach (var entryId in ctx.Data.RemovedInstances)
     {
         if (m_LoadingInstances.TryGetValue(entryId, out var state))
         {
             state.Stream.Cancel();
         }
     }
 }
Example #30
0
        public static void Main(string[] args)
        {
            // Set up timestamps in debug output
            DebugStream = new TimeStampWriter(DebugStream, "HH:mm:ss.fff");

            Padding p = new AbsolutePadding(2, 2, 1, 1);

            Console.CursorVisible = false;
            Console.Title         = "Tofvesson Enterprises"; // Set console title

            // Start with the networking context
            ContextManager manager    = new ContextManager();
            NetContext     networking = new NetContext(manager);

            if (CheckIsNewUser())
            {
                manager.LoadContext(new IntroContext(manager, () => manager.LoadContext(networking)));
            }
            else
            {
                manager.LoadContext(networking);
            }

            // Start input listener loop. Graphics happen here too (triggered by keystrokes)
            ConsoleController.KeyEvent info = new ConsoleController.KeyEvent(default(ConsoleKeyInfo))
            {
                ValidEvent = false
            };
            bool first = true;

            do
            {
                if (first)
                {
                    first = false;
                }
                else
                {
                    info = controller.ReadKey();
                }

                bool b = manager.Update(info), haskey = false;
                while (b)
                {
                    System.Threading.Thread.Sleep(25);
                    haskey = _kbhit() != 0;
                    if (haskey)
                    {
                        info = controller.ReadKey(false);
                    }
                    b = manager.Update(info, haskey);
                    controller.Draw();
                }
            } while ((!info.ValidEvent || info.Event.Key != ConsoleKey.Escape) && !controller.ShouldExit);
        }
Example #31
0
        }                                                              // doesn't need to be 100% accurate

        void IFrame.Write(NetContext context, Connection connection, Stream stream)
        {
            //Debug.WriteLine("write:" + this);
            byte[] buffer = null;
            try
            {
                buffer = context.GetBuffer();
                int offset = 0;
                buffer[offset++] = (byte)(((int)flags & 240) | ((int)OpCode & 15));
                if (PayloadLength > ushort.MaxValue)
                { // write as a 64-bit length
                    buffer[offset++] = (byte)((Mask.HasValue ? 128 : 0) | 127);
                    buffer[offset++] = 0;
                    buffer[offset++] = 0;
                    buffer[offset++] = 0;
                    buffer[offset++] = 0;
                    buffer[offset++] = (byte)(PayloadLength >> 24);
                    buffer[offset++] = (byte)(PayloadLength >> 16);
                    buffer[offset++] = (byte)(PayloadLength >> 8);
                    buffer[offset++] = (byte)(PayloadLength);
                }
                else if (PayloadLength > 125)
                { // write as a 16-bit length
                    buffer[offset++] = (byte)((Mask.HasValue ? 128 : 0) | 126);
                    buffer[offset++] = (byte)(PayloadLength >> 8);
                    buffer[offset++] = (byte)(PayloadLength);
                }
                else
                { // write in the header
                    buffer[offset++] = (byte)((Mask.HasValue ? 128 : 0) | PayloadLength);
                }
                if (Mask.HasValue)
                {
                    int mask = Mask.Value;
                    buffer[offset++] = (byte)(mask >> 24);
                    buffer[offset++] = (byte)(mask >> 16);
                    buffer[offset++] = (byte)(mask >> 8);
                    buffer[offset++] = (byte)(mask);
                }
                stream.Write(buffer, 0, offset);

                if (PayloadLength != 0)
                {
                    int totalRead = WebSocketsProcessor_RFC6455_13.Copy(Payload, stream, buffer, Mask, PayloadLength);
                    if (totalRead != PayloadLength)
                    {
                        throw new EndOfStreamException("Wrong payload length sent");
                    }
                }
            }
            finally
            {
                context.Recycle(buffer);
            }
        }
Example #32
0
 protected override void Send(NetContext context, Connection connection, object message)
 {
     lock (this)
     {
         if (pending == null)
         {
             pending = new Queue <object>();
         }
         pending.Enqueue(message);
     }
 }
Example #33
0
        public override bool Resource(NetContext context, string targetKey)
        {
            if (targetKey.EndsWith("UMC.js") || targetKey.EndsWith("Page.js"))
            {
                context.Output.WriteLine("UMC.UI.Config({'posurl': '/UMC/' + (UMC.cookie('device') || UMC.cookie('device', UMC.uuid()))}); ");


                return(true);
            }
            return(base.Resource(context, targetKey));
        }
        protected override int ProcessIncoming(NetContext context, Connection connection, System.IO.Stream incoming)
        {
            if (incoming.Length < 2) return 0; // can't read that; start/end markers take at least 2 bytes

            switch(incoming.ReadByte())
            {
                case 0x00:
                    var ws = (WebSocketConnection) connection;
                    if(!ws.AllowIncomingDataFrames) throw new InvalidOperationException("Data frames disabled");
                    // data frame is 0x00 [data] 0xFF
                    int len = 0, cur;
                    while((cur = incoming.ReadByte()) != 0xFF && cur >= 0)
                    {
                        len++;
                    }
                    if(cur < 0) throw new EndOfStreamException();

                    incoming.Position = 1;
                    string value;
                    if (len == 0) value = "";
                    else if (len <= NetContext.BufferSize)
                    {
                        byte[] buffer = null;
                        try
                        {
                            buffer = context.GetBuffer();
                            NetContext.Fill(incoming, buffer, len);
                            value = Encoding.UTF8.GetString(buffer, 0, len);
                        } finally
                        {
                            context.Recycle(buffer);
                        }
                    } else
                    {
                        var buffer = new byte[len];
                        NetContext.Fill(incoming, buffer, len);
                        value = Encoding.UTF8.GetString(buffer, 0, len);
                    }
                    context.Handler.OnReceived(connection, value);
                    return len + 2;
                case 0xFF:
                    // shutdown is 0xFF 0x00
                    if(incoming.ReadByte() == 0x00)
                    {
                        GracefulShutdown(context, connection);
                        return 2;
                    } else
                    {
                        throw new InvalidOperationException("protocol fail");
                    }
                default:
                    throw new InvalidOperationException("protocol fail");
            }
        }
 protected override void GracefulShutdown(NetContext context, Connection connection)
 {
     connection.DisableRead();
     var ws = (WebSocketConnection) connection;
     if(ws.HasSentClose)
     {
         ws.HasSentClose = true;
         SendData(context, new BinaryFrame(new byte[] {0xFF, 0x00}, true));
     }
     SendShutdown(context);
     connection.PromptToSend(context);
 }
        public INetContext GetContext(string Name, int Port)
        {
            INetContext ctx = new NetContext();

            ctx.IPAddress = Name;
            ctx.Port      = Port;

            ctx.Services.Register <TestDistributedService>();
            ctx.Packets.Register <TestPacket>();

            return(ctx);
        }
        void OnReleaseUnityResource(NetContext <ReleaseUnityResource> ctx)
        {
            var resourceId = ctx.Data.ResourceId;
            var resource   = m_LoadedResources[resourceId];

            --resource.Count;

            foreach (var dependency in resource.Dependencies)
            {
                --m_LoadedResources[dependency].Count;
            }
        }
        protected void SendData(NetContext context, IList<IFrame> batch)
        {
            lock (this)
            {
                foreach (var frame in batch)
                {
                    ProtocolProcessor.AddFrame(context, ref dataQueue, frame);
#if VERBOSE
                    Debug.WriteLine("pushed (data): " + frame);
#endif
                }
            }
        }
        IFrame IProtocolProcessor.GetOutboundFrame(NetContext context)
        {            
            lock(this)
            {
                var result = ProtocolProcessor.GetFrame(context, ref controlQueue);
                if(result != null)
                {
#if VERBOSE
                    Debug.WriteLine("popped (control): " + result);   
#endif
                }
                else
                {
                    result = ProtocolProcessor.GetFrame(context, ref dataQueue);
                    if (result != null)
                    {
#if VERBOSE
                        Debug.WriteLine("popped (data): " + result);
#endif
                    }
                }
                return result;
            }            
        }
        internal static string ComputeReply(NetContext context, string webSocketKey)
        {
            //To prove that the handshake was received, the server has to take two
            //pieces of information and combine them to form a response.  The first
            //piece of information comes from the |Sec-WebSocket-Key| header field
            //in the client handshake:

            //     Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

            //For this header field, the server has to take the value (as present
            //in the header field, e.g., the base64-encoded [RFC4648] version minus
            //any leading and trailing whitespace) and concatenate this with the
            //Globally Unique Identifier (GUID, [RFC4122]) "258EAFA5-E914-47DA-
            //95CA-C5AB0DC85B11" in string form, which is unlikely to be used by
            //network endpoints that do not understand the WebSocket Protocol.  A
            //SHA-1 hash (160 bits) [FIPS.180-3], base64-encoded (see Section 4 of
            //[RFC4648]), of this concatenation is then returned in the server's
            //handshake.
            if (string.IsNullOrEmpty(webSocketKey) || webSocketKey.Length != 24) throw new ArgumentException("webSocketKey");
            
            const string WebSocketKeySuffix = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
            byte[] buffer = null;
            try
            {
                buffer = context.GetBuffer();
                int offset = Encoding.ASCII.GetBytes(webSocketKey, 0, webSocketKey.Length, buffer, 0);
                int len = offset + Encoding.ASCII.GetBytes(WebSocketKeySuffix, 0, WebSocketKeySuffix.Length, buffer, offset);
                using(var sha = SHA1.Create())
                {
                    return Convert.ToBase64String(sha.ComputeHash(buffer, 0, len));
                }
            }
            finally
            {
                context.Recycle(buffer);
            }
        }
 protected override void InitializeClientHandshake(NetContext context, Connection connection)
 {
     throw new System.NotImplementedException();
 }
        private static IEnumerable<WebSocketsFrame> ApplyExtensions(NetContext context, Connection connection, WebSocketsFrame frame, bool inbound)
        {
            var wsc = connection as WebSocketConnection;
            var extn = wsc == null ? null : wsc.Extensions;

            IEnumerable<WebSocketsFrame> frames = Enumerable.Repeat(frame, 1);

            if (extn != null && extn.Length != 0)
            {
                for (int i = 0; i < extn.Length; i++)
                {
                    var actualExtension = extn[i];
                    if (inbound)
                    {
                        frames = frames.SelectMany(x => actualExtension.ApplyIncoming(context, wsc, x));
                    }
                    else
                    {
                        frames = frames.SelectMany(x => actualExtension.ApplyOutgoing(context, wsc, x));
                    }
                }
            }
            return frames;
        }
        protected internal override void CompleteHandshake(NetContext context, Connection connection, Stream input, string requestLine, StringDictionary headers, byte[] body)
        {


            string key = headers["Sec-WebSocket-Key"];
            if(key != null) key = key.Trim();
            string response = ComputeReply(context, key);

            var builder = new StringBuilder(
                              "HTTP/1.1 101 Switching Protocols\r\n"
                            + "Upgrade: websocket\r\n"
                            + "Connection: Upgrade\r\n"
                            + "Sec-WebSocket-Accept: ").Append(response).Append("\r\n");

            var wc = connection as WebSocketConnection;
            var extn = wc == null ? null : wc.Extensions;
            if (extn != null)
            {
                List<string> extnHeaders = null;
                for (int i = 0; i < extn.Length; i++)
                {
                    string extnHeader = extn[i].GetResponseHeader();
                    if (!string.IsNullOrEmpty(extnHeader))
                    {
                        if (extnHeaders == null) extnHeaders = new List<string>();
                        extnHeaders.Add(extnHeader);
                    }
                }
                if (extnHeaders != null)
                {
                    builder.Append("Sec-WebSocket-Extensions: ").Append(extnHeaders[0]);
                    for (int i = 1; i < extnHeaders.Count; i++)
                        builder.Append(", ").Append(extnHeaders[i]);
                    builder.Append("\r\n");
                }
            }

            builder.Append("\r\n");
            SendControl(context, new StringFrame(builder.ToString(), Encoding.ASCII));
            connection.PromptToSend(context);
        }
 private void Process(NetContext context, Connection connection, Stream stream, WebSocketsFrame.OpCodes opCode)
 {
     using (stream)
     {
         switch (opCode)
         {
             case WebSocketsFrame.OpCodes.Text:
                 string s;
                 if (stream == null || stream.Length == 0) s = "";
                 else
                 {
                     stream.Position = 0;
                     using (var reader = new StreamReader(stream, Encoding.UTF8))
                     {
                         s = reader.ReadToEnd();
                     }
                 }
                 context.Handler.OnReceived(connection, s);
                 break;
             case WebSocketsFrame.OpCodes.Binary:
                 byte[] blob;
                 int len;
                 if (stream == null || (len = ((int)stream.Length - (int)stream.Position)) == 0) blob = new byte[0]; 
                 else
                 {
                     blob = new byte[len];
                     byte[] buffer = null;
                     try
                     {
                         buffer = context.GetBuffer();
                         int offset = 0, read;
                         stream.Position = 0;
                         while((read = stream.Read(buffer, offset, Math.Min(len, buffer.Length))) > 0)
                         {
                             offset += read;
                             len -= read;
                         }
                         if(len != 0) throw new EndOfStreamException();
                     } finally
                     {
                         context.Recycle(buffer);
                     }
                 }
                 context.Handler.OnReceived(connection, blob);
                 break;
             default:
                 throw new InvalidOperationException();
         }
     }
 }
        public override void Send(NetContext context, Connection connection, object message)
        {
            if(message == null) throw new ArgumentNullException("message");

            string s;
            WebSocketConnection wsConnection;
            WebSocketsFrame frame;

            var encoding = Encoding.UTF8;
            if ((s = message as string) != null && (wsConnection = connection as WebSocketConnection) != null
                && wsConnection.MaxCharactersPerFrame > 0 && s.Length > wsConnection.MaxCharactersPerFrame)
            {
                int remaining = s.Length, charIndex = 0;
                bool isFirst = true;
                char[] charBuffer = s.ToCharArray();
                var batch = new List<IFrame>();
                while(remaining > 0)
                {
                    int charCount = Math.Min(remaining, wsConnection.MaxCharactersPerFrame);
                    var buffer = encoding.GetBytes(charBuffer, charIndex, charCount);
                    //Debug.WriteLine("> " + new string(charBuffer, charIndex, charCount));
                    remaining -= charCount;
                    charIndex += charCount;

                    frame = new WebSocketsFrame();
                    frame.OpCode = isFirst ? WebSocketsFrame.OpCodes.Text : WebSocketsFrame.OpCodes.Continuation;
                    isFirst = false;
                    frame.Payload = new BufferStream(context, context.Handler.MaxOutgoingQuota);
                    frame.Payload.Write(buffer, 0, buffer.Length);
                    frame.PayloadLength = buffer.Length;
                    frame.Mask = IsClient ? (int?)CreateMask() : null;
                    frame.Payload.Position = 0;
                    frame.IsFinal = remaining <= 0;
                    foreach (var final in ApplyExtensions(context, connection, frame, false))
                    {
                        batch.Add(final);
                    }                    
                }
                SendData(context, batch);
                return;
            }            


            byte[] blob;
            frame = new WebSocketsFrame();
            frame.Payload = new BufferStream(context, context.Handler.MaxOutgoingQuota);
            if(s != null)
            {
                frame.OpCode = WebSocketsFrame.OpCodes.Text;
                var buffer = encoding.GetBytes(s);
                //Debug.WriteLine("> " + s);
                frame.Payload.Write(buffer, 0, buffer.Length);
                frame.PayloadLength = buffer.Length;
            }
            else if ((blob = message as byte[]) != null)
            {
                frame.OpCode = WebSocketsFrame.OpCodes.Binary;
                frame.Payload.Write(blob, 0, blob.Length);
                frame.PayloadLength = blob.Length;
            }
            else
            {
                throw new NotSupportedException(message.ToString());
            }
            frame.Mask = IsClient ? (int?)CreateMask() : null;
            frame.Payload.Position = 0;
            frame.IsFinal = true;

            foreach(var final in ApplyExtensions(context, connection, frame, false))
            {
                SendData(context, final);
            }
        }
 protected override void Send(NetContext context, Connection connection, object message)
 {
     lock (this)
     {
         if (pending == null) pending = new Queue<object>();
         pending.Enqueue(message);
     }
 }
 protected override void Write(NetContext context, Connection connection, Stream stream)
 {
     stream.WriteByte(0x00);
     base.Write(context, connection, stream);
     stream.WriteByte(0xFF);
 }
            protected override int ProcessIncoming(NetContext context, Connection connection, Stream incoming)
            {
                if (expectedResponse != null)
                {
                    if (incoming.Length < expectedResponse.Length) return 0; // not enough to check the response

                    byte[] actual = new byte[expectedResponse.Length];
                    NetContext.Fill(incoming, actual, actual.Length);
                    for (int i = 0; i < actual.Length; i++)
                    {
                        if (actual[i] != expectedResponse[i]) throw new InvalidOperationException("Incorrect Hixie76 respoonse");
                    }
                    expectedResponse = null; // all verified now
                    return actual.Length; // the amount we processed

                }
                return base.ProcessIncoming(context, connection, incoming);
            } 
Example #49
0
            IEnumerable<WebSocketsFrame> IExtension.ApplyOutgoing(NetContext context, WebSocketConnection connection, WebSocketsFrame frame)
            {
                if (!frame.IsControlFrame && frame.PayloadLength > parent.compressMessagesLargerThanBytes)
                {
                    if (frame.Reserved1)
                    {
                        throw new InvalidOperationException("Reserved1 flag is already set; extension conflict?");
                    }

                    int headerBytes = 0;
                    if (outbound == null)
                    {
                        outbound = new ZStream();
                        const int BITS = 12; // 4096 byte outbound buffer (instead of full 32k=15)
                        outbound.deflateInit(zlibConst.Z_BEST_COMPRESSION, BITS);
                        headerBytes = 2;
                    }
                    BufferStream tmp = null;
                    var payload = frame.Payload;
                    payload.Position = 0;
                    byte[] inBuffer = null, outBuffer = null;
                    try
                    {
                        inBuffer = context.GetBuffer();
                        outBuffer = context.GetBuffer();
                        tmp = new BufferStream(context, 0);

                        outbound.next_out = outBuffer;
                        outbound.next_in = inBuffer;

                        int remaining = frame.PayloadLength;
                        while (remaining > 0)
                        {
                            int readCount = payload.Read(inBuffer, 0, inBuffer.Length);
                            if (readCount <= 0) break;
                            remaining -= readCount;

                            outbound.next_in_index = 0;
                            outbound.avail_in = readCount;

                            do
                            {
                                outbound.next_out_index = 0;
                                outbound.avail_out = outBuffer.Length;
                                long priorOut = outbound.total_out;
                                int err = outbound.deflate(remaining == 0 ? zlibConst.Z_SYNC_FLUSH : zlibConst.Z_NO_FLUSH);
                                if (err != zlibConst.Z_OK && err != zlibConst.Z_STREAM_END)
                                    throw new ZStreamException("deflating: " + outbound.msg);

                                int outCount = (int)(outbound.total_out - priorOut);
                                if (outCount > 0)
                                {
                                    if (headerBytes == 0)
                                    {
                                        tmp.Write(outBuffer, 0, outCount);
                                    }
                                    else
                                    {
                                        if (outCount < headerBytes)
                                        {
                                            throw new InvalidOperationException("Failed to write entire header");
                                        }
                                        // check the generated header meets our expectations
                                        // CMF is very specific - CM must be 8, and CINFO must be <=7 (for 32k window)
                                        if ((outBuffer[0] & 15) != 8)
                                        {
                                            throw new InvalidOperationException("Zlib CM header was incorrect");
                                        }
                                        if ((outBuffer[0] & 128) != 0) // if msb set, is > 7 - invalid
                                        {
                                            throw new InvalidOperationException("Zlib CINFO header was incorrect");
                                        }

                                        // FLG is less important; FCHECK is irrelevent, FLEVEL doesn't matter; but
                                        // FDICT must be zero, to ensure that we aren't expecting a an initialization dictionary
                                        if ((outBuffer[1] & 32) != 0)
                                        {
                                            throw new InvalidOperationException("Zlib FLG.FDICT header was set (must not be)");
                                        }

                                        // skip the header, and write anything else
                                        outCount -= headerBytes;
                                        if (outCount > 0)
                                        {
                                            tmp.Write(outBuffer, headerBytes, outCount);
                                        }
                                        headerBytes = 0; // all written now
                                    }
                                }
                            } while (outbound.avail_in > 0 || outbound.avail_out == 0);
                        }
                        if (remaining != 0) throw new EndOfStreamException();
                        if (headerBytes != 0) throw new InvalidOperationException("Zlib header was not written");

                        // verify the last 4 bytes, then drop them
                        tmp.Position = tmp.Length - 4;
                        NetContext.Fill(tmp, outBuffer, 4);
                        if (!(outBuffer[0] == 0x00 && outBuffer[1] == 0x00 && outBuffer[2] == 0xFF && outBuffer[3] == 0xFF))
                        {
                            throw new InvalidOperationException("expectation failed: 0000FFFF in the tail");
                        }

                        if (parent.disableContextTakeover && tmp.Length >= frame.PayloadLength)
                        { // compressing it didn't do anything useful; since we're going to discard
                          // the compression context, we might as well stick with the original data
                            payload.Position = 0;
                            payload = null; // so that it doesn't get disposed
                        }
                        else
                        {
                            // set our final output
                            tmp.Position = 0;
                            tmp.SetLength(tmp.Length - 4);
                            long bytesSaved = frame.PayloadLength - tmp.Length;
                            frame.Payload = tmp;
                            frame.PayloadLength = (int)tmp.Length;
                            frame.Reserved1 = true;
                            tmp = payload as BufferStream;
                            parent.RegisterOutboundBytesSaved(bytesSaved);
                        }
                    }
#if DEBUG
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex);
                        throw;
                    }
#endif
                    finally
                    {
                        if (outbound != null)
                        {
                            outbound.next_out = null;
                            outbound.next_in = null;
                        }
                        if (tmp != null) tmp.Dispose();
                        if (inBuffer != null) context.Recycle(inBuffer);
                        if (outBuffer != null) context.Recycle(outBuffer);
                        if (parent.disableContextTakeover) ClearContext(false, true);
                    }
                }
                yield return frame;
            }
 protected internal override void CompleteHandshake(NetContext context, Connection connection, Stream input, string requestLine, System.Collections.Specialized.StringDictionary headers, byte[] body)
 {
     throw new NotSupportedException();
 }
            protected override int ProcessIncoming(NetContext context, Connection connection, Stream incoming)
            {
                if (keys != null) // handshake is not yet complete
                {
                    if (incoming.Length < 8) return 0; // need 8 bytes to finish the handshake

                    var key3 = new byte[8];
                    NetContext.Fill(incoming, key3, 8);

                    // now that we're on a different protocol, send the server's response to the client's challenge
                    var securityCheck = ComputeKey(keys.Item1, keys.Item2, key3);
                    keys = null; // wipe
                    SendControl(context, new BinaryFrame(securityCheck));
                    connection.PromptToSend(context);
                    return 8;
                }
                return base.ProcessIncoming(context, connection, incoming);
            }
 public override void Send(NetContext context, Connection connection, object message)
 {
     SendData(context, new HixieFrame((string)message));
 }
        protected override int ProcessIncoming(NetContext context, Connection connection, Stream incoming)
        {
            if (incoming.Length < 2) return 0; // can't read that; frame takes at minimum two bytes

            

            byte[] buffer = null;
            try
            {
                buffer = context.GetBuffer();
                int read;
                // read as much as possible up to 14 bytes; that gives us space for 2 bytes frame header, 8 bytes length, and 4 bytes mask
                read = NetContext.TryFill(incoming, buffer, 14);

                int headerLength;
                var frame = WebSocketsFrame.TryParseFrameHeader(buffer, read, out headerLength);

                if (frame == null) return 0;
                int payloadLen = frame.PayloadLength;

#if VERBOSE
                Debug.WriteLine("Parsed header from: " + BitConverter.ToString(buffer, 0, headerLength));
#endif

                if (incoming.Length < headerLength + payloadLen) return 0; // not enough data to read the payload

                if (payloadLen != 0)
                {
                    Stream payload = null;
                    try
                    {
                        payload = new BufferStream(context, context.Handler.MaxIncomingQuota);
                        if (read != headerLength) incoming.Position -= (read - headerLength); // we got it wrong...

                        Copy(incoming, payload, buffer, frame.Mask, payloadLen);

                        if (payloadLen != payload.Length)
                        {
                            throw new InvalidOperationException("I munged the data");
                        }
                        frame.Payload = payload;
                        payload = null;
                    }
                    finally
                    {
                        if (payload != null) payload.Dispose();
                    }
                }
                foreach (var final in ApplyExtensions(context, connection, frame, true))
                {
                    ProcessFrame(context, connection, final);
                }
                return headerLength + payloadLen;
            }
            finally
            {
                context.Recycle(buffer);
            }
        }
        private void ProcessFrame(NetContext context, Connection connection, WebSocketsFrame frame)
        {
            if(IsClient)
            {
                if(frame.Mask.HasValue) throw new InvalidOperationException("Clients only expect unmasked frames");
            } else
            {
                if (!frame.Mask.HasValue) throw new InvalidOperationException("Servers only expect masked frames");
            }
            var ws = (WebSocketConnection) connection;
            if(frame.IsControlFrame)
            {
                if(!frame.IsFinal) throw new InvalidOperationException("control frames cannot be fragmented");
                switch(frame.OpCode)
                {
                    case WebSocketsFrame.OpCodes.Close:
                        // respond with a closing handshake
                        GracefulShutdown(context, connection);
                        break;
                    case WebSocketsFrame.OpCodes.Pong:
                        // could add some reaction here
                        break;
                    case WebSocketsFrame.OpCodes.Ping:
                        // send a "pong" with the same payload
                        var pong = new WebSocketsFrame();
                        if (IsClient) pong.Mask = CreateMask();
                        pong.OpCode = WebSocketsFrame.OpCodes.Binary;
                        pong.PayloadLength = frame.PayloadLength;
                        if(frame.Payload != null)
                        {
                            var ms = new MemoryStream((int)frame.Payload.Length);
                            byte[] buffer = null;
                            try
                            {
                                buffer = context.GetBuffer();
                                Copy(frame.Payload, ms, buffer, null, frame.PayloadLength);
                            } finally
                            {
                                context.Recycle(buffer);
                            }
                            pong.Payload = ms;
                        }
                        SendControl(context, pong);
                        connection.PromptToSend(context);
                        break;
                    default:
                        throw new InvalidOperationException();
                }
            }
            else
            {
                if (!ws.AllowIncomingDataFrames) throw new InvalidOperationException("Data frames disabled");

                int pendingCount = FrameCount;
                if (frame.OpCode == WebSocketsFrame.OpCodes.Continuation)
                {
                    if(pendingCount == 0) throw new InvalidOperationException("Continuation of nothing");
                }
                else  if (pendingCount != 0)
                {
                    throw new InvalidOperationException("Should be a continuation");
                }
                if (!frame.IsFinal)
                {
                    Push(context, frame);
                }
                else
                {
                    if(pendingCount == 0)
                    {
                        Process(context, connection, frame.Payload, frame.OpCode);
                    } else
                    {
                        throw new NotImplementedException();
                    }
                }

            }
            if (frame.OpCode == WebSocketsFrame.OpCodes.Close)
            {
                Debug.WriteLine("Sent close frame: " + connection);
            }
        }
 protected override void GracefulShutdown(NetContext context, Connection connection)
 {
     connection.DisableRead();
     var ws = (WebSocketConnection) connection;
     if(!ws.HasSentClose)
     {
         ws.HasSentClose = true;
         var close = new WebSocketsFrame();
         if (IsClient) close.Mask = CreateMask();
         close.OpCode = WebSocketsFrame.OpCodes.Close;
         close.PayloadLength = 0;
         SendControl(context, close);
     }
     SendShutdown(context);
     connection.PromptToSend(context);
 }
 protected internal override void CompleteHandshake(NetContext context, Connection connection, System.IO.Stream input, string requestLine, System.Collections.Specialized.StringDictionary headers, byte[] body)
 {
     keys = Tuple.Create(headers["Sec-WebSocket-Key1"], headers["Sec-WebSocket-Key2"]);
     var builder = new StringBuilder(
         "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
         + "Upgrade: WebSocket\r\n"
         + "Connection: Upgrade\r\n");
     var conn = (WebSocketConnection)connection;
     if (!string.IsNullOrEmpty(conn.Host))
     { // we should add the origin/location, but that depends on what we have available to us
         builder.Append("Sec-WebSocket-Origin: ").Append(conn.Origin).Append("\r\n");
         if (!string.IsNullOrEmpty(conn.RequestLine))
         {
             Match match;
             if ((match = Regex.Match(conn.RequestLine, @"GET ([^\s]+) HTTP")).Success)
             {
                 builder.Append("Sec-WebSocket-Location: ").Append("ws://").Append(conn.Host).Append(match.Groups[1].Value).Append("\r\n");
             }
         }
     }
     if (!string.IsNullOrEmpty(conn.Protocol))
         builder.Append("Sec-WebSocket-Protocol: ").Append(conn.Protocol).Append("\r\n");
     builder.Append("\r\n");
     SendControl(context, new StringFrame(builder.ToString(), Encoding.ASCII, false));
     connection.PromptToSend(context);
 }
        protected override void InitializeClientHandshake(NetContext context, Connection conn)
        {
            var connection = (WebSocketConnection) conn;
            byte[] nonce = new byte[16];
            NetContext.GetRandomBytes(nonce);
            var outgoing = Convert.ToBase64String(nonce);
            expected = WebSocketsProcessor_RFC6455_13.ComputeReply(context, outgoing);

            if(string.IsNullOrEmpty(connection.Host)) throw new InvalidOperationException("Host must be specified");
            if (string.IsNullOrEmpty(connection.RequestLine)) throw new InvalidOperationException("RequestLine must be specified");
            
            StringBuilder req = new StringBuilder(connection.RequestLine).Append("\r\n" +
                                    "Upgrade: websocket\r\n" +
                                    "Connection: Upgrade\r\n" +
                                    "Sec-WebSocket-Version: 13\r\n" +
                                    "Sec-WebSocket-Key: ").Append(outgoing).Append("\r\n" +
                                    "Host: ").Append(connection.Host).Append("\r\n");
            if (!string.IsNullOrEmpty(connection.Origin))
                req.Append("Origin: ").Append(connection.Origin).Append("\r\n");
            if (!string.IsNullOrEmpty(connection.Protocol))
                req.Append("Sec-WebSocket-Protocol: ").Append(connection.Protocol).Append("\r\n");
            var extnArray = context.Extensions;
            if (extnArray != null && extnArray.Length != 0)
            {
                List<string> extnHeaders = null;
                for (int i = 0; i < extnArray.Length; i++)
                {
                    var extn = extnArray[i] as IExtensionFactory;
                    if (extn != null)
                    {
                        string extnHeader = extn.GetRequestHeader();
                        if (!string.IsNullOrEmpty(extnHeader))
                        {
                            if (extnHeaders == null) extnHeaders = new List<string>();
                            extnHeaders.Add(extnHeader);
                        }
                    }
                }
                if (extnHeaders != null)
                {
                    req.Append("Sec-WebSocket-Extensions: ").Append(extnHeaders[0]);
                    for (int i = 1; i < extnHeaders.Count; i++)
                        req.Append(", ").Append(extnHeaders[i]);
                    req.Append("\r\n");
                }
            }

            req.Append("\r\n");
            EnqueueFrame(context, new StringFrame(req.ToString(), Encoding.ASCII));
            connection.PromptToSend(context);
        }
Example #58
0
 void IFrame.Write(NetContext context, Connection connection, System.IO.Stream stream)
 {
     connection.Shutdown(context);
 }
Example #59
0
            IEnumerable<WebSocketsFrame> IExtension.ApplyIncoming(NetContext context, WebSocketConnection connection, WebSocketsFrame frame)
            {
                if (frame.Reserved1 && !frame.IsControlFrame)
                {
                    BufferStream tmp = null;
                    var payload = frame.Payload;
                    payload.Position = 0;
                    byte[] inBuffer = null, outBuffer = null;

                    try
                    {
                        outBuffer = context.GetBuffer();
                        inBuffer = context.GetBuffer();
                        tmp = new BufferStream(context, 0);

                        if (inbound == null)
                        {
                            inbound = new ZStream();
                            inbound.inflateInit();

                            // fake a zlib header with:
                            // CMF:
                            //   CM = 8 (deflate)
                            //   CINFO = 7 (32k window)
                            // FLG:
                            //   FCHECK: 26 (checksum of other bits)
                            //   FDICT: 0 (no dictionary)
                            //   FLEVEL: 3 (maximum)
                            inBuffer[0] = 120;
                            inBuffer[1] = 218;
                            inbound.next_in = inBuffer;
                            int chk = Inflate(tmp, outBuffer, 2);
                            if (chk != 0) throw new InvalidOperationException("Spoofed zlib header suggested data");
                        }   
                        
                        inbound.next_in = inBuffer;
                        int remaining = frame.PayloadLength;
                        //bool first = true;
                        while (remaining > 0)
                        {
                            int readCount = payload.Read(inBuffer, 0, inBuffer.Length);
                            if (readCount <= 0) break;
                            remaining -= readCount;

                            //if (first)
                            //{   // kill the BFINAL flag from the first block, if set; we don't want zlib
                            //    // trying to verify the ADLER checksum; unfortunately, a frame can contain
                            //    // multiple blocks, and a *later* block could have BFINAL set. That sucks.
                            //    inBuffer[0] &= 254;
                            //    first = false;
                            //}
                            Inflate(tmp, outBuffer, readCount);                          
                        }
                        if (remaining != 0) throw new EndOfStreamException();

                        // spoof the missing 4 bytes from the tail
                        inBuffer[0] = inBuffer[1] = 0x00;
                        inBuffer[2] = inBuffer[3] = 0xFF;
                        Inflate(tmp, outBuffer, 4);

                        // set our final output
                        tmp.Position = 0;
                        frame.Payload = tmp;
                        long bytesSaved = tmp.Length - frame.PayloadLength;
                        frame.PayloadLength = (int)tmp.Length;
                        frame.Reserved1 = false;
                        tmp = payload as BufferStream;
                        parent.RegisterInboundBytesSaved(bytesSaved);
                    }
#if DEBUG
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex);
                        throw;
                    }
#endif
                    finally
                    {
                        if (inbound != null)
                        {
                            inbound.next_out = null;
                            inbound.next_in = null;
                        }
                        if (tmp != null) tmp.Dispose();
                        if (inBuffer != null) context.Recycle(inBuffer);
                        if (outBuffer != null) context.Recycle(outBuffer);
                        if (parent.disableContextTakeover) ClearContext(true, false);
                    }

                }
                yield return frame;
            }
        protected override int ProcessHeadersAndUpgrade(NetContext context, Connection connection, Stream input, Stream additionalData, int additionalOffset)
        {
            string requestLine;
            var headers = ParseHeaders(input, out requestLine);
            if (!string.Equals(headers["Upgrade"], "WebSocket", StringComparison.InvariantCultureIgnoreCase)
                || !string.Equals(headers["Connection"], "Upgrade", StringComparison.InvariantCultureIgnoreCase)
                || headers["Sec-WebSocket-Accept"] != expected)
            {
                throw new InvalidOperationException();
            }

            lock (this)
            {
                AddMatchingExtensions(headers, connection, context.Extensions);
                var protocol = new WebSocketsProcessor_RFC6455_13(true);
                connection.SetProtocol(protocol);
                if (pending != null)
                {
                    while (pending.Count != 0)
                    {
                        connection.Send(context, pending.Dequeue());
                    }
                }
            }
            return 0;
        }