Example #1
0
        /// <summary>
        /// Process a reception conforming to rev 00 of the WebSocket spec
        /// </summary>
        /// <param name="agent"></param>
        /// <param name="socket"></param>
        /// <param name="remoteEndPoint"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        private string HandleWebSocketReceive_00(WSAgent agent, Socket socket, IPEndPoint remoteEndPoint, SocketAsyncEventArgs args)
        {
            if (agent == null)
            {
                // m_log.Debug("Sending handshake response to " + remoteEndPoint);
                byte[] byteRequest = new byte[args.BytesTransferred];
                Buffer.BlockCopy(args.Buffer, args.Offset, byteRequest, 0, args.BytesTransferred);

                // create the controlling agent for this new stream
                agent = new WSAgent(m_server, m_throttle, m_throttleRates, UUID.Random(), UUID.Random(), socket, false);
                m_clients.Add(agent.ID, remoteEndPoint, agent);

                // there are some fields in the header that we must extract the values of
                string requestString = Encoding.UTF8.GetString(byteRequest, 0, byteRequest.GetLength(0));
                int    originIndex   = requestString.IndexOf("Origin: ");
                if (originIndex > 0)
                {
                    // if the client specified an origin, we must echo it back in the response
                    originIndex += 8;
                    int originEnd = requestString.IndexOf('\r', originIndex);
                    if (originEnd > 0)
                    {
                        m_webSocketOrigin = requestString.Substring(originIndex, originEnd - originIndex);
                    }
                }

                // This is an initial handshake
                // Process the header and send the response
                byte[] response = BuildHandshake(byteRequest);
                SendMessageFinal(socket, response);

                // tell those who care that we are connected
                WebSocketClientConnectedEventHandler handler = Connected;
                if (handler != null)
                {
                    handler(agent);
                }

                return(null);
            }

            // It is not the initial handshake so extract data from the header
            // and find the application data therein.
            int start = args.Offset;
            int end   = start + args.BytesTransferred;

            if (args.Buffer[start] == 0 && args.Buffer[end - 1] == 0xff)
            {
                // we know about the spec rev0 character padding
                string dataString = Encoding.UTF8.GetString(args.Buffer, start + 1, end - start - 2);
                return(dataString);
            }
            else
            {
                m_log.Warn("Received message not conforming to rev 00 of the WebSocket specification");
            }
            return(null);
        }
Example #2
0
        /// <summary>
        /// The WebSockets spec has been evolving. This routine processes data framing
        /// for verions 03 of the spec.
        /// </summary>
        /// <param name="agent"></param>
        /// <param name="socket"></param>
        /// <param name="remoteEndPoint"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        private string HandleWebSocketReceive_03(WSAgent agent, Socket socket, IPEndPoint remoteEndPoint, SocketAsyncEventArgs args)
        {
            if (agent == null)
            {
                // m_log.Debug("Sending handshake response to " + remoteEndPoint);
                byte[] byteRequest = new byte[args.BytesTransferred];
                Buffer.BlockCopy(args.Buffer, args.Offset, byteRequest, 0, args.BytesTransferred);

                // create the controlling agent for this new stream
                agent = new WSAgent(m_server, m_throttle, m_throttleRates, UUID.Random(), UUID.Random(), socket, false);
                m_clients.Add(agent.ID, remoteEndPoint, agent);

                // there are some fields in the header that we must extract the values of
                string requestString = Encoding.UTF8.GetString(byteRequest, 0, byteRequest.GetLength(0));
                int    originIndex   = requestString.IndexOf("Origin: ");
                if (originIndex > 0)
                {
                    // if the client specified an origin, we must echo it back in the response
                    originIndex += 8;
                    int originEnd = requestString.IndexOf('\r', originIndex);
                    if (originEnd > 0)
                    {
                        m_webSocketOrigin = requestString.Substring(originIndex, originEnd - originIndex);
                    }
                }

                // This is an initial handshake
                // Process the header and send the response
                byte[] response = BuildHandshake(byteRequest);
                SendMessageFinal(socket, response);

                // tell those who care that we are connected
                WebSocketClientConnectedEventHandler handler = Connected;
                if (handler != null)
                {
                    handler(agent);
                }

                return(null);
            }

            // It is not the initial handshake so extract data from the header
            // and find the application data therein.
            int start = args.Offset;
            int end   = start + args.BytesTransferred;

            bool headerMore = false;
            int  headerOp   = 0;
            int  headerLen  = 0;

            try {
                headerMore = (args.Buffer[start] & 0x80) != 0;
                headerOp   = args.Buffer[start] & 0x0f;
                headerLen  = args.Buffer[start + 1] & 0x7f;
                if (headerLen == 0x7e)
                {
                    headerLen = (args.Buffer[start + 2] << 8) + args.Buffer[start + 3];
                    start    += 2;
                }
                else
                {
                    if (headerLen == 0x7f)
                    {
                        headerLen = args.Buffer[start + 2] << 24
                                    + args.Buffer[start + 3] << 16
                                    + args.Buffer[start + 4] << 8
                                    + args.Buffer[start + 5];
                        start += 4;
                    }
                }
                start += 2;
            }
            catch (Exception e) {
                // failure decoding the header (probably short)
                m_log.Warn("HandleWebSocketReceive: Failure parsing message header: " + e.ToString());
                return(null);
            }
            if ((end - start) < headerLen)
            {
                // didn't receive enough data
                m_log.Warn("HandleWebSocketReceive: received less data than specified in length. Ignoring.");
                return(null);
            }

            // Opcode of '1' says 'close'
            if (headerOp == 1)
            {
                m_log.Warn("HandleWebSocketReceive: polite request to close connection");
                // TODO:
                return(null);
            }

            // Opcode of '2' says 'ping'
            if (headerOp == 2)
            {
                byte[] pingResponse = GeneratePingResponse();
                SendMessageFinal(socket, pingResponse);
                // The standard is undecided on whether a control message can also
                // include data. Here we presume not.
                return(null);
            }
            // TODO: someday do our own pings so we'll need to process pongs

            // if specified, remember the form of the data being received
            if (headerOp == 4)
            {
                agent.ReadingBinary = false;
            }
            if (headerOp == 5)
            {
                agent.ReadingBinary = true;
            }

            if (!agent.ReadingData)
            {
                // not yet reading data so initialize new buffers
                agent.ReadingData = true;
                agent.DataString  = new StringBuilder();
                agent.DataBinary  = null;
            }

            if (agent.ReadingBinary)
            {
                // If binary, build up a buffer of the binary data
                int doffset = 0;
                if (agent.DataBinary == null)
                {
                    agent.DataBinary = new byte[headerLen];
                }
                else
                {
                    byte[] temp = agent.DataBinary;
                    doffset          = temp.Length;
                    agent.DataBinary = new byte[doffset + headerLen];
                    Buffer.BlockCopy(temp, 0, agent.DataBinary, 0, doffset);
                }
                Buffer.BlockCopy(args.Buffer, start, agent.DataBinary, doffset, headerLen);
            }
            else
            {
                // if just text, get the UTF8 characters into our growing string
                agent.DataString.Append(Encoding.UTF8.GetString(args.Buffer, start, headerLen));
            }

            if (!headerMore)
            {
                // end of any fragmentation. no longer reading data
                agent.ReadingData = false;
                return(agent.DataString.ToString());
                // Note the race condition here for the binary data.
                // Binary is not handled correctly as it can be immediately overwritten
                // by the next message.
            }
            // if this is part of a fragmented message, don't return any data this time
            return(null);
        }