예제 #1
0
        /// <summary>
        /// Processes the packet within the context. Returns true whether the packet was processed or throttled.
        /// </summary>
        /// <param name="channel">The through which the packet is coming/going out.</param>
        /// <param name="context">The packet context for this operation.</param>
        /// <returns>True whether the packet was processed or throttled, false otherwise.</returns>
        public static ProcessingState Process(Emitter.Connection channel, ProcessingContext context)
        {
            var buffer = context.Buffer;

            if (buffer == null)
            {
                return(ProcessingState.Failure);
            }

            // Get the buffer pointer
            var pBuffer = buffer.AsBytePointer();
            var offset  = 0;
            var length  = buffer.Length;

            // Decode the frame
            var queue = new Queue <BufferSegment>();
            int index; bool isFinal; BufferSegment decoded;

            do
            {
                //var trace = (context.Buffer.ViewAsHybi13 == "(Invalid: Hybi13)" ? context.Buffer.ViewAsBytes : context.Buffer.ViewAsHybi13);
                var result = DecodeFrame(context, pBuffer, length, out index, out isFinal, out decoded);
                //Console.WriteLine(trace + " -> " + result);
                if (result != ProcessingState.Success)
                {
                    return(result);
                }

                pBuffer += index;
                offset  += index;
                length  -= index;

                queue.Enqueue(decoded);
            } while (!isFinal);

            // Merge the queue
            decoded = queue.Dequeue();
            while (queue.Count > 0)
            {
                decoded = decoded.Join(queue.Dequeue());
            }

            // Throttle the rest
            if (offset < buffer.Length)
            {
                context.Throttle(offset);
            }

            // Swap the buffer
            context.SwitchBuffer(decoded);

            NetTrace.WriteLine("Hybi13 frame decoded", channel, NetTraceCategory.WebSocket);
            return(ProcessingState.Success);
        }
예제 #2
0
        /// <summary>
        /// Processes the packet within the context. Returns true whether the packet was processed or throttled.
        /// </summary>
        /// <param name="channel">The through which the packet is coming/going out.</param>
        /// <param name="context">The packet context for this operation.</param>
        /// <returns>True whether the packet was processed or throttled, false otherwise.</returns>
        public static ProcessingState Process(Emitter.Connection channel, ProcessingContext context)
        {
            // Get the buffer
            if (context.Buffer == null || context.Buffer.Length < PacketHeader.TotalSize)
            {
                return(ProcessingState.Failure);
            }

            // Check for 'MSH' prefix
            var pBuffer = context.Buffer.AsBytePointer();

            if (*(pBuffer) != 'M' ||
                *(pBuffer + 1) != 'S' ||
                *(pBuffer + 2) != 'H')
            {
                return(ProcessingState.Failure);
            }

            // Get the type of the mesh frame
            var type = (char)(*(pBuffer + 3));

            if (type != 'F' && type != 'C')
            {
                return(ProcessingState.Failure);
            }

            // Must be a TCP channel
            var tcpChannel = channel as Connection;

            if (tcpChannel == null)
            {
                return(ProcessingState.Failure);
            }

            // Get the packet length
            int length = PeekPacketLength(pBuffer + 4);

            if (length < 0 || length > context.MaxMemory)
            {
                return(ProcessingState.Failure);
            }

            // Check whether we have all the bytes
            if (context.Buffer.Length < length + PacketHeader.TotalSize)
            {
                return(ProcessingState.InsufficientData);
            }

            // There might be several packets in the same segment. We need to specify
            // that one is decoded and forward only that one to the next decoder.
            // However, we must not discard the segment completely as we might loose data!
            context.Throttle(PacketHeader.TotalSize + length);
            context.SwitchBuffer(
                context.Buffer.Split(PacketHeader.TotalSize)
                );

            // Decompress with Snappy
            if (Decode.Snappy(channel, context) != ProcessingState.Success)
            {
                return(ProcessingState.Failure);
            }

            try
            {
                // Update the last seen, if we have a mesh identifier
                var server = Service.Mesh.Members.Get(tcpChannel.MeshIdentifier);
                if (server != null)
                {
                    server.LastTouchUtc = Timer.UtcNow;
                }

                // Something went wrong?
                if (context.Buffer == null)
                {
                    return(ProcessingState.Stop);
                }

                switch (type)
                {
                // This represents a mesh 'Command' type including commands that need to establish mesh
                // handshake between the nodes in the cluster. In that case, we don't have an ID set
                // on the connection and must let everything pass.
                case 'C':

                    // Acquire a command packet and the reader
                    using (var reader = PacketReaderPool.Default.Acquire(context.Buffer))
                        using (var packet = Create((MeshEventType)reader.PeekByte()))
                        {
                            // Deserialize the packet
                            packet.Read(reader);

                            // Process the command and exit
                            MeshHandler.Process(channel as Connection, packet);
                            break;
                        }

                // This represents a mesh 'Frame', which is a simple array segment forwarded to a set
                // of handlers, in the way in which the Fabric is done as well.
                case 'F':

                    // Process the frame and exit
                    Service.Mesh.OnFrame(server, context.Buffer);
                    break;

                // We've received some weird data
                default:
                    Service.Logger.Log("Mesh: Unknown frame type '" + type + "'");
                    break;
                }
            }
            catch (Exception ex)
            {
                Service.Logger.Log(ex);
            }

            // We're done here, stop the processing. The buffer will be freed right after
            // we've returned here, in the ProcessingContext's code.
            return(ProcessingState.Stop);
        }
예제 #3
0
        /// <summary>
        /// Processes the packet within the context. Returns true whether the packet was processed or throttled.
        /// </summary>
        /// <param name="channel">The through which the packet is coming/going out.</param>
        /// <param name="context">The packet context for this operation.</param>
        /// <returns>True whether the packet was processed or throttled, false otherwise.</returns>
        public static ProcessingState Process(Emitter.Connection channel, ProcessingContext context)
        {
            // Get the buffer
            var buffer = context.Buffer;

            if (buffer == null)
            {
                return(ProcessingState.Failure);
            }

            // Check if it looks like an http request but only with a single byte
            var pBuffer = buffer.AsBytePointer();
            var length  = context.Buffer.Length;
            var first   = (char)*pBuffer;

            if (length == 1 &&
                (first == 'P' ||
                 first == 'G' ||
                 first == 'H' ||
                 first == 'D' ||
                 first == 'O' ||
                 first == 'T' ||
                 first == 'C'))
            {
                return(ProcessingState.InsufficientData);
            }

            // Check if we can handle it
            if (!CanHandle(buffer))
            {
                return(ProcessingState.Failure);
            }

            // Acquire a HTTP context and save it in the session
            HttpContext httpContext = HttpContextPool.Default.Acquire(channel);

            context.Session = httpContext;

            // Make sure we have HTTP timeout set
            if (channel.Timeout != httpContext.ScriptTimeout)
            {
                channel.Timeout = httpContext.ScriptTimeout;
            }

            // Check if we have a http request
            if (buffer.Length < 14) // "GET / HTTP/1.1".Length;
            {
                return(ProcessingState.InsufficientData);
            }

            // Parse http request
            var errorOccured     = false;
            var insufficientData = false;
            var bytesParsed      = httpContext.ParseRequest(context.Buffer.AsBytePointer(), length,
                                                            out errorOccured, out insufficientData);

            // If there was en error during the parse, fail it
            if (errorOccured)
            {
                return(ProcessingState.Failure);
            }

            // Parsing of http headers was not complete, need to read more bytes
            if (insufficientData)
            {
                return(ProcessingState.InsufficientData);
            }

            // Trace HTTP request
            var request = httpContext.Request;

            NetTrace.WriteLine(request.HttpVerb.ToString().ToUpper() + " " + request.Path, channel, NetTraceCategory.Http);

            // Attempt to read the body
            if (buffer.Length < bytesParsed + request.ContentLength)
            {
                return(ProcessingState.InsufficientData);
            }

            // We got enough data, map the read data to the request
            if (request.ContentLength > 0)
            {
                // Switch to the current buffer, release the old one
                context.Throttle(bytesParsed + request.ContentLength);
                context.SwitchBuffer(
                    buffer.Split(bytesParsed)
                    );

                // Parse the body to the request
                request.Body = context.Buffer.AsArray();
            }
            else
            {
                // Make a special case for draft websockets, as they send a body with a
                // GET request. Bastards!
                if (bytesParsed + 8 <= buffer.Length &&
                    request.ContainsHeader("Sec-WebSocket-Key1"))
                {
                    // Get the 8 bytes of websocket challenge
                    context.Throttle(bytesParsed + 8);
                    context.SwitchBuffer(
                        buffer.Split(bytesParsed)
                        );

                    // Parse the body to the request
                    request.Body = context.Buffer.AsArray();
                }
                else
                {
                    // Switch to the current buffer, release the old one
                    context.Throttle(bytesParsed);
                    context.SwitchBuffer(null);
                }
            }

            // Redirect to the various built-in handlers
            context.Redirect(
                Handle.WebSocketUpgrade,
                Handle.Http
                );

            return(ProcessingState.Success);
        }
예제 #4
0
        /// <summary>
        /// Processes the packet within the context. Returns true whether the packet was processed or throttled.
        /// </summary>
        /// <param name="channel">The through which the packet is coming/going out.</param>
        /// <param name="context">The packet context for this operation.</param>
        /// <returns>True whether the packet was processed or throttled, false otherwise.</returns>
        public static ProcessingState Process(Emitter.Connection channel, ProcessingContext context)
        {
            // Get the buffer
            var buffer = context.Buffer;

            if (buffer == null)
            {
                return(ProcessingState.Failure);
            }

            // Get the info
            var pBuffer = buffer.AsBytePointer();
            int length  = buffer.Length;

            // To close the connection cleanly, a frame consisting of just a 0xFF
            // byte followed by a 0x00 byte is sent from one peer to ask that the
            // other peer close the connection.
            if (*pBuffer == 0xFF && *(pBuffer + 1) == 0x00)
            {
                // Trace a websocket event
                NetTrace.WriteLine("Draft76 connection termination requested", channel, NetTraceCategory.WebSocket);

                length = 0;
                channel.Close();
                return(ProcessingState.Stop);
            }

            if (*pBuffer != Start)
            {
                throw new WebSocketException("WebSocket frame is invalid.");
            }

            // Search for the next end byte
            int endIndex = -1;

            for (int i = 0; i < length; ++i)
            {
                if (*(pBuffer + i) == End)
                {
                    endIndex = i;
                    break;
                }
            }

            if (endIndex == -1)
            {
                // Trace a websocket event
                NetTrace.WriteLine("Draft76 frame is not complete", channel, NetTraceCategory.WebSocket);
                return(ProcessingState.InsufficientData);
            }

            if (endIndex > MaxSize)
            {
                throw new WebSocketException("WebSocket frame is too large.");
            }

            // Throttle the rest
            context.Throttle(endIndex + 1);

            // Decode the body
            var decoded = context.BufferWrite(buffer.Array, buffer.Offset + 1, endIndex - 1);

            context.SwitchBuffer(decoded);

            // Trace a websocket event
            NetTrace.WriteLine("Draft76 frame decoded", channel, NetTraceCategory.WebSocket);
            return(ProcessingState.Success);
        }