Esempio n. 1
0
        /// <summary>
        ///		Unpack request/notification message array header.
        /// </summary>
        /// <param name="context">Context information.</param>
        /// <returns>
        ///		<c>true</c>, if the pipeline is finished;
        ///		<c>false</c>, the pipeline is interruppted because extra data is needed.
        /// </returns>
        internal bool UnpackRequestHeader(ServerRequestContext context)
        {
            Contract.Assert(context != null);

            if (context.RootUnpacker == null)
            {
                context.UnpackingBuffer = new ByteArraySegmentStream(context.ReceivedData);
                context.RootUnpacker    = Unpacker.Create(context.UnpackingBuffer, false);
                Interlocked.Increment(ref this._processing);
                context.RenewSessionId();
                if (this._manager.Server.Configuration.ReceiveTimeout != null)
                {
                    context.Timeout += this.OnReceiveTimeout;
                    context.StartWatchTimeout(this._manager.Server.Configuration.ReceiveTimeout.Value);
                }

                if (MsgPackRpcServerProtocolsTrace.ShouldTrace(MsgPackRpcServerProtocolsTrace.NewSession))
                {
                    MsgPackRpcServerProtocolsTrace.TraceEvent(
                        MsgPackRpcServerProtocolsTrace.NewSession,
                        "New session is created. {{ \"SessionID\" : {0} }}",
                        context.SessionId
                        );
                }
            }

            if (!context.ReadFromRootUnpacker())
            {
                MsgPackRpcServerProtocolsTrace.TraceEvent(
                    MsgPackRpcServerProtocolsTrace.NeedRequestHeader,
                    "Array header is needed. {{ \"SessionID\" : {0} }}",
                    context.SessionId
                    );
                return(false);
            }

            if (!context.RootUnpacker.IsArrayHeader)
            {
                this.HandleDeserializationError(context, "Invalid request/notify message stream. Message must be array.", () => context.UnpackingBuffer.ToArray());
                return(true);
            }

            if (context.RootUnpacker.ItemsCount != 3 && context.RootUnpacker.ItemsCount != 4)
            {
                this.HandleDeserializationError(
                    context,
                    String.Format(
                        CultureInfo.CurrentCulture,
                        "Invalid request/notify message stream. Message must be valid size array. Actual size is {0}.",
                        context.RootUnpacker.ItemsCount
                        ),
                    () => context.UnpackingBuffer.ToArray()
                    );
                return(true);
            }

            context.HeaderUnpacker = context.RootUnpacker.ReadSubtree();
            context.NextProcess    = UnpackMessageType;
            return(context.NextProcess(context));
        }
Esempio n. 2
0
        /// <summary>
        ///		Unpack array elements of Arguments part on request/notification message.
        /// </summary>
        /// <param name="context">Context information.</param>
        /// <returns>
        ///		<c>true</c>, if the pipeline is finished;
        ///		<c>false</c>, the pipeline is interruppted because extra data is needed.
        /// </returns>
        private bool UnpackArguments(ServerRequestContext context)
        {
            Contract.Assert(context != null);

            while (context.UnpackedArgumentsCount < context.ArgumentsCount)
            {
                if (!context.ReadFromArgumentsBufferUnpacker())
                {
                    MsgPackRpcServerProtocolsTrace.TraceEvent(
                        MsgPackRpcServerProtocolsTrace.NeedArgumentsElement,
                        "Arguments array element is needed. {0}/{1}  {{ \"SessionID\" : {2} }}",
                        context.UnpackedArgumentsCount,
                        context.ArgumentsCount,
                        context.SessionId
                        );
                    return(false);
                }

                context.ArgumentsBufferPacker.Pack(context.ArgumentsBufferUnpacker.LastReadData);
                context.UnpackedArgumentsCount++;
            }

            context.ArgumentsBuffer.Position = 0;
            context.ArgumentsUnpacker        = Unpacker.Create(context.ArgumentsBuffer, false);
            context.NextProcess = this.Dispatch;
            return(context.NextProcess(context));
        }
Esempio n. 3
0
        /// <summary>
        ///		Unpack Method Name part on request/notification message.
        /// </summary>
        /// <param name="context">Context information.</param>
        /// <returns>
        ///		<c>true</c>, if the pipeline is finished;
        ///		<c>false</c>, the pipeline is interruppted because extra data is needed.
        /// </returns>
        private bool UnpackMethodName(ServerRequestContext context)
        {
            Contract.Assert(context != null);

            if (!context.ReadFromHeaderUnpacker())
            {
                MsgPackRpcServerProtocolsTrace.TraceEvent(
                    MsgPackRpcServerProtocolsTrace.NeedMethodName,
                    "Method Name is needed. {{ \"SessionID\" : {0} }}",
                    context.SessionId
                    );
                return(false);
            }

            try
            {
                context.MethodName = context.HeaderUnpacker.LastReadData.AsString();
            }
            catch (InvalidOperationException)
            {
                this.HandleDeserializationError(
                    context,
                    "Invalid request/notify message stream. Method name must be UTF-8 string.",
                    () => context.UnpackingBuffer.ToArray()
                    );
                return(true);
            }

            context.NextProcess = this.UnpackArgumentsHeader;
            return(context.NextProcess(context));
        }
Esempio n. 4
0
        /// <summary>
        ///		Unpack Message ID part on request message.
        /// </summary>
        /// <param name="context">Context information.</param>
        /// <returns>
        ///		<c>true</c>, if the pipeline is finished;
        ///		<c>false</c>, the pipeline is interruppted because extra data is needed.
        /// </returns>
        private bool UnpackMessageId(ServerRequestContext context)
        {
            Contract.Assert(context != null);

            if (!context.ReadFromHeaderUnpacker())
            {
                MsgPackRpcServerProtocolsTrace.TraceEvent(
                    MsgPackRpcServerProtocolsTrace.NeedMessageId,
                    "Message ID is needed. {{ \"SessionID\" : {0} }}",
                    context.SessionId
                    );
                return(false);
            }

            try
            {
                context.MessageId = unchecked (( int )context.HeaderUnpacker.LastReadData.AsUInt32());
            }
            catch (InvalidOperationException)
            {
                this.HandleDeserializationError(
                    context,
                    "Invalid request message stream. ID must be UInt32 compatible integer.",
                    () => context.UnpackingBuffer.ToArray()
                    );
                return(true);
            }

            context.NextProcess = this.UnpackMethodName;
            return(context.NextProcess(context));
        }
Esempio n. 5
0
        /// <summary>
        ///		Unpack Message Type part on request/notification message.
        /// </summary>
        /// <param name="context">Context information.</param>
        /// <returns>
        ///		<c>true</c>, if the pipeline is finished;
        ///		<c>false</c>, the pipeline is interruppted because extra data is needed.
        /// </returns>
        private bool UnpackMessageType(ServerRequestContext context)
        {
            Contract.Assert(context != null);

            if (!context.ReadFromHeaderUnpacker())
            {
                MsgPackRpcServerProtocolsTrace.TraceEvent(
                    MsgPackRpcServerProtocolsTrace.NeedMessageType,
                    "Message Type is needed. {{ \"SessionID\" : {0} }}",
                    context.SessionId
                    );
                return(false);
            }

            int numericType;

            try
            {
                numericType = context.HeaderUnpacker.LastReadData.AsInt32();
            }
            catch (InvalidOperationException)
            {
                this.HandleDeserializationError(context, "Invalid request/notify message stream. Message Type must be Int32 compatible integer.", () => context.UnpackingBuffer.ToArray());
                return(true);
            }

            MessageType type = ( MessageType )numericType;

            context.MessageType = type;

            switch (type)
            {
            case MessageType.Request:
            {
                context.NextProcess = this.UnpackMessageId;
                break;
            }

            case MessageType.Notification:
            {
                context.NextProcess = this.UnpackMethodName;
                break;
            }

            default:
            {
                this.HandleDeserializationError(
                    context,
                    String.Format(CultureInfo.CurrentCulture, "Unknown message type '{0:x8}'", numericType),
                    () => context.UnpackingBuffer.ToArray()
                    );
                return(true);
            }
            }

            return(context.NextProcess(context));
        }
Esempio n. 6
0
        /// <summary>
        ///		Unpack array header of Arguments part on request/notification message.
        /// </summary>
        /// <param name="context">Context information.</param>
        /// <returns>
        ///		<c>true</c>, if the pipeline is finished;
        ///		<c>false</c>, the pipeline is interruppted because extra data is needed.
        /// </returns>
        private bool UnpackArgumentsHeader(ServerRequestContext context)
        {
            Contract.Assert(context != null);

            if (!context.ReadFromHeaderUnpacker())
            {
                MsgPackRpcServerProtocolsTrace.TraceEvent(
                    MsgPackRpcServerProtocolsTrace.NeedArgumentsArrayHeader,
                    "Arguments array header is needed. {{ \"SessionID\" : {0} }}",
                    context.SessionId
                    );
                return(false);
            }

            if (!context.HeaderUnpacker.IsArrayHeader)
            {
                this.HandleDeserializationError(
                    context,
                    "Invalid request/notify message stream. Arguments must be array.",
                    () => context.UnpackingBuffer.ToArray()
                    );
                return(true);
            }

            // TODO: Avoid actual unpacking to improve performance.
            context.ArgumentsBufferUnpacker = context.HeaderUnpacker.ReadSubtree();

            if (Int32.MaxValue < context.ArgumentsBufferUnpacker.ItemsCount)
            {
                this.HandleDeserializationError(
                    context,
                    RpcError.MessageTooLargeError,
                    "Too many arguments.",
                    context.ArgumentsBufferUnpacker.ItemsCount.ToString("#,0", CultureInfo.CurrentCulture),
                    () => context.UnpackingBuffer.ToArray()
                    );
                return(true);
            }

            context.ArgumentsCount        = unchecked (( int )(context.ArgumentsBufferUnpacker.ItemsCount));
            context.ArgumentsBufferPacker = Packer.Create(context.ArgumentsBuffer, false);
            context.ArgumentsBufferPacker.PackArrayHeader(context.ArgumentsCount);
            context.UnpackedArgumentsCount = 0;
            context.NextProcess            = this.UnpackArguments;
            return(context.NextProcess(context));
        }
Esempio n. 7
0
        /// <summary>
        ///		Dispatch request/notification message via the <see cref="MsgPack.Rpc.Server.Dispatch.Dispatcher"/>.
        /// </summary>
        /// <param name="context">Context information.</param>
        /// <returns>
        ///		<c>true</c>, if the pipeline is finished;
        ///		<c>false</c>, the pipeline is interruppted because extra data is needed.
        /// </returns>
        private bool Dispatch(ServerRequestContext context)
        {
            Contract.Assert(context != null);

            context.StopWatchTimeout();
            context.Timeout -= this.OnReceiveTimeout;

            context.ClearBuffers();

            var isNotification = context.MessageType == MessageType.Notification;

            try
            {
                this._dispatcher.Dispatch(
                    this,
                    context
                    );
            }
            finally
            {
                context.ClearDispatchContext();

                if (isNotification)
                {
                    this.OnSessionFinished();
                }
            }

            context.NextProcess = this.UnpackRequestHeader;

            if (context.UnpackingBuffer.Length > 0)
            {
                // Subsequent request is already arrived.
                return(context.NextProcess(context));
            }
            else
            {
                // Try receive subsequent.
                return(true);
            }
        }
		/// <summary>
		///		Dispatch request/notification message via the <see cref="MsgPack.Rpc.Server.Dispatch.Dispatcher"/>.
		/// </summary>
		/// <param name="context">Context information.</param>
		/// <returns>
		///		<c>true</c>, if the pipeline is finished;
		///		<c>false</c>, the pipeline is interruppted because extra data is needed.
		/// </returns>
		private bool Dispatch( ServerRequestContext context )
		{
			Contract.Assert( context != null );

			context.StopWatchTimeout();
			context.Timeout -= this.OnReceiveTimeout;

			context.ClearBuffers();

			var isNotification = context.MessageType == MessageType.Notification;
			try
			{
				this._dispatcher.Dispatch(
					this,
					context
				);
			}
			finally
			{
				context.ClearDispatchContext();

				if ( isNotification )
				{
					this.OnSessionFinished();
				}
			}

			context.NextProcess = this.UnpackRequestHeader;

			if ( context.UnpackingBuffer.Length > 0 )
			{
				// Subsequent request is already arrived.
				return context.NextProcess( context );
			}
			else
			{
				// Try receive subsequent.
				return true;
			}
		}
		/// <summary>
		///		Unpack request/notification message array header.
		/// </summary>
		/// <param name="context">Context information.</param>
		/// <returns>
		///		<c>true</c>, if the pipeline is finished;
		///		<c>false</c>, the pipeline is interruppted because extra data is needed.
		/// </returns>
		internal bool UnpackRequestHeader( ServerRequestContext context )
		{
			Contract.Assert( context != null );

			if ( context.RootUnpacker == null )
			{
				context.UnpackingBuffer = new ByteArraySegmentStream( context.ReceivedData );
				context.RootUnpacker = Unpacker.Create( context.UnpackingBuffer, false );
				Interlocked.Increment( ref this._processing );
				context.RenewSessionId();
				if ( this._manager.Server.Configuration.ReceiveTimeout != null )
				{
					context.Timeout += this.OnReceiveTimeout;
					context.StartWatchTimeout( this._manager.Server.Configuration.ReceiveTimeout.Value );
				}

				if ( MsgPackRpcServerProtocolsTrace.ShouldTrace( MsgPackRpcServerProtocolsTrace.NewSession ) )
				{
					MsgPackRpcServerProtocolsTrace.TraceEvent(
						MsgPackRpcServerProtocolsTrace.NewSession,
						"New session is created. {{ \"SessionID\" : {0} }}",
						context.SessionId
					);
				}
			}

			if ( !context.ReadFromRootUnpacker() )
			{
				MsgPackRpcServerProtocolsTrace.TraceEvent( 
					MsgPackRpcServerProtocolsTrace.NeedRequestHeader,
					"Array header is needed. {{ \"SessionID\" : {0} }}", 
					context.SessionId 
				);
				return false;
			}

			if ( !context.RootUnpacker.IsArrayHeader )
			{
				this.HandleDeserializationError( context, "Invalid request/notify message stream. Message must be array.", () => context.UnpackingBuffer.ToArray() );
				return true;
			}

			if ( context.RootUnpacker.ItemsCount != 3 && context.RootUnpacker.ItemsCount != 4 )
			{
				this.HandleDeserializationError(
					context,
					String.Format(
						CultureInfo.CurrentCulture,
						"Invalid request/notify message stream. Message must be valid size array. Actual size is {0}.",
						context.RootUnpacker.ItemsCount
					),
					() => context.UnpackingBuffer.ToArray()
				);
				return true;
			}

			context.HeaderUnpacker = context.RootUnpacker.ReadSubtree();
			context.NextProcess = UnpackMessageType;
			return context.NextProcess( context );
		}
		/// <summary>
		///		Unpack array elements of Arguments part on request/notification message.
		/// </summary>
		/// <param name="context">Context information.</param>
		/// <returns>
		///		<c>true</c>, if the pipeline is finished;
		///		<c>false</c>, the pipeline is interruppted because extra data is needed.
		/// </returns>
		private bool UnpackArguments( ServerRequestContext context )
		{
			Contract.Assert( context != null );
			
			while ( context.UnpackedArgumentsCount < context.ArgumentsCount )
			{
				if ( !context.ReadFromArgumentsBufferUnpacker() )
				{
					MsgPackRpcServerProtocolsTrace.TraceEvent( 
						MsgPackRpcServerProtocolsTrace.NeedArgumentsElement,
						"Arguments array element is needed. {0}/{1}  {{ \"SessionID\" : {2} }}",
						context.UnpackedArgumentsCount, 
						context.ArgumentsCount, 
						context.SessionId 
					);
					return false;
				}

				context.ArgumentsBufferPacker.Pack( context.ArgumentsBufferUnpacker.LastReadData );
				context.UnpackedArgumentsCount++;
			}

			context.ArgumentsBuffer.Position = 0;
			context.ArgumentsUnpacker = Unpacker.Create( context.ArgumentsBuffer, false );
			context.NextProcess = this.Dispatch;
			return context.NextProcess( context );
		}
		/// <summary>
		///		Unpack array header of Arguments part on request/notification message.
		/// </summary>
		/// <param name="context">Context information.</param>
		/// <returns>
		///		<c>true</c>, if the pipeline is finished;
		///		<c>false</c>, the pipeline is interruppted because extra data is needed.
		/// </returns>
		private bool UnpackArgumentsHeader( ServerRequestContext context )
		{
			Contract.Assert( context != null );

			if ( !context.ReadFromHeaderUnpacker() )
			{
				MsgPackRpcServerProtocolsTrace.TraceEvent( 
					MsgPackRpcServerProtocolsTrace.NeedArgumentsArrayHeader,
					"Arguments array header is needed. {{ \"SessionID\" : {0} }}",
					context.SessionId 
				);
				return false;
			}

			if ( !context.HeaderUnpacker.IsArrayHeader )
			{
				this.HandleDeserializationError(
					context,
					"Invalid request/notify message stream. Arguments must be array.",
					() => context.UnpackingBuffer.ToArray()
				);
				return true;
			}

			// TODO: Avoid actual unpacking to improve performance.
			context.ArgumentsBufferUnpacker = context.HeaderUnpacker.ReadSubtree();

			if ( Int32.MaxValue < context.ArgumentsBufferUnpacker.ItemsCount )
			{
				this.HandleDeserializationError(
					context,
					RpcError.MessageTooLargeError,
					"Too many arguments.",
					context.ArgumentsBufferUnpacker.ItemsCount.ToString( "#,0", CultureInfo.CurrentCulture ),
					() => context.UnpackingBuffer.ToArray()
				);
				return true;
			}

			context.ArgumentsCount = unchecked( ( int )( context.ArgumentsBufferUnpacker.ItemsCount ) );
			context.ArgumentsBufferPacker = Packer.Create( context.ArgumentsBuffer, false );
			context.ArgumentsBufferPacker.PackArrayHeader( context.ArgumentsCount );
			context.UnpackedArgumentsCount = 0;
			context.NextProcess = this.UnpackArguments;
			return context.NextProcess( context );
		}
		/// <summary>
		///		Unpack Method Name part on request/notification message.
		/// </summary>
		/// <param name="context">Context information.</param>
		/// <returns>
		///		<c>true</c>, if the pipeline is finished;
		///		<c>false</c>, the pipeline is interruppted because extra data is needed.
		/// </returns>
		private bool UnpackMethodName( ServerRequestContext context )
		{
			Contract.Assert( context != null );

			if ( !context.ReadFromHeaderUnpacker() )
			{
				MsgPackRpcServerProtocolsTrace.TraceEvent( 
					MsgPackRpcServerProtocolsTrace.NeedMethodName,
					"Method Name is needed. {{ \"SessionID\" : {0} }}",
					context.SessionId 
				);
				return false;
			}

			try
			{
				context.MethodName = context.HeaderUnpacker.LastReadData.AsString();
			}
			catch ( InvalidOperationException )
			{
				this.HandleDeserializationError(
					context,
					"Invalid request/notify message stream. Method name must be UTF-8 string.",
					() => context.UnpackingBuffer.ToArray()
				);
				return true;
			}

			context.NextProcess = this.UnpackArgumentsHeader;
			return context.NextProcess( context );
		}
		/// <summary>
		///		Unpack Message ID part on request message.
		/// </summary>
		/// <param name="context">Context information.</param>
		/// <returns>
		///		<c>true</c>, if the pipeline is finished;
		///		<c>false</c>, the pipeline is interruppted because extra data is needed.
		/// </returns>
		private bool UnpackMessageId( ServerRequestContext context )
		{
			Contract.Assert( context != null );

			if ( !context.ReadFromHeaderUnpacker() )
			{
				MsgPackRpcServerProtocolsTrace.TraceEvent( 
					MsgPackRpcServerProtocolsTrace.NeedMessageId,
					"Message ID is needed. {{ \"SessionID\" : {0} }}", 
					context.SessionId 
				);
				return false;
			}

			try
			{
				context.MessageId = unchecked( ( int )context.HeaderUnpacker.LastReadData.AsUInt32() );
			}
			catch ( InvalidOperationException )
			{
				this.HandleDeserializationError(
					context,
					"Invalid request message stream. ID must be UInt32 compatible integer.",
					() => context.UnpackingBuffer.ToArray()
				);
				return true;
			}

			context.NextProcess = this.UnpackMethodName;
			return context.NextProcess( context );
		}
		/// <summary>
		///		Unpack Message Type part on request/notification message.
		/// </summary>
		/// <param name="context">Context information.</param>
		/// <returns>
		///		<c>true</c>, if the pipeline is finished;
		///		<c>false</c>, the pipeline is interruppted because extra data is needed.
		/// </returns>
		private bool UnpackMessageType( ServerRequestContext context )
		{
			Contract.Assert( context != null );
			
			if ( !context.ReadFromHeaderUnpacker() )
			{
				MsgPackRpcServerProtocolsTrace.TraceEvent( 
					MsgPackRpcServerProtocolsTrace.NeedMessageType,
					"Message Type is needed. {{ \"SessionID\" : {0} }}",
					context.SessionId 
				);
				return false;
			}

			int numericType;
			try
			{
				numericType = context.HeaderUnpacker.LastReadData.AsInt32();
			}
			catch ( InvalidOperationException )
			{
				this.HandleDeserializationError( context, "Invalid request/notify message stream. Message Type must be Int32 compatible integer.", () => context.UnpackingBuffer.ToArray() );
				return true;
			}

			MessageType type = ( MessageType )numericType;
			context.MessageType = type;

			switch ( type )
			{
				case MessageType.Request:
				{
					context.NextProcess = this.UnpackMessageId;
					break;
				}
				case MessageType.Notification:
				{
					context.NextProcess = this.UnpackMethodName;
					break;
				}
				default:
				{
					this.HandleDeserializationError(
						context,
						String.Format( CultureInfo.CurrentCulture, "Unknown message type '{0:x8}'", numericType ),
						() => context.UnpackingBuffer.ToArray()
					);
					return true;
				}
			}

			return context.NextProcess( context );
		}