protected void ProcessCall(ProcessState state)
		{
			MemoryStream messageStream = null;
			MemoryStream replyStream = null;

			MessageState message = null;
			try
			{
				messageStream = state.message.Item;

				if (asyncMessageHandler != null)
				{
					message = new MessageState
					{
						CommandId = state.commandId,
						Message = messageStream,
						Length = state.messageLength,
						ClientIP = state.remoteEndpoint
					};

					asyncMessageHandler.BeginHandleMessage(message, (asyncResult) =>
					{
						try
						{
							MemoryStream reply = asyncMessageHandler.EndHandleMessage(asyncResult);
							CompleteProcessCall(state, reply); //not APM
						}
						catch (Exception exc)
						{
							if (log.IsErrorEnabled)
								log.Error(exc);
						}
					});

					return; //very important
				}

				if (AsynMessageHandler != null)
				{
					replyStream = AsynMessageHandler.Invoke((int)state.commandId, messageStream, state.remoteEndpoint.Address);
				}
				else if (MessageHandler != null)
				{
					replyStream = MessageHandler.HandleMessage((int)state.commandId, messageStream, state.messageLength);
				}
			}
			catch (Exception ex)
			{
				try
				{
					string endPoint = state.socket.RemoteEndPoint.ToString();

					if (log.IsErrorEnabled)
						log.ErrorFormat("Socket Server Exception handling message from {0}: {1}.", endPoint, ex);
					replyStream = null;
				}
				catch (ObjectDisposedException) { }
			}
			finally
			{
				if (message != null)
				{
					message.Message = null;
					message.Length = 0;
				}
				bufferPool.ReleaseItem(state.message);
				state.message = null;
			}

			CompleteProcessCall(state, replyStream);
		}
		/// <summary>
		/// Begins the handling of a complete message from a stream. All references 
		/// to <see cref="MessageState.Message"/> must be released by the end of this method.
		/// </summary>
		/// <param name="message">The complete message that is to be handled.</param>
		/// <param name="callback">The delegate to call when complete.</param>
		/// <returns>Returns an <see cref="IAsyncResult"/>.</returns>
		/// <remarks>
		///		<para>
		///		All implementors must release any references to <see cref="MessageState.Message"/>
		///		by the time that <see cref="BeginHandleMessage"/> returns.
		///		</para>
		/// </remarks>
		public IAsyncResult BeginHandleMessage(MessageState message, AsyncCallback callback)
		{
			SocketHandlerAsyncResult result = new SocketHandlerAsyncResult(null, callback);
			//don't use callback directly, use result.Complete();
			callback = null;
			const bool wasSyncronous = true;
			//VERY IMPORTANT! don't hold any references to message or it's properties after leaving this method
			try
			{
				SocketCommand command = SocketCommand.Unknown;
				RelayMessage relayMessage = null;
				List<RelayMessage> relayMessages = null;

                try
                {
                    command = (SocketCommand)message.CommandId;
                }
                catch
                {
                    if (RelayNode.log.IsErrorEnabled)
                        RelayNode.log.ErrorFormat("Unrecognized commandID {0} sent to Relay Service via socket transport", message.CommandId);
                    result.CompleteOperation(wasSyncronous);
                    return result;
                }

				switch (command)
				{
					case SocketCommand.Unknown:
                        if (RelayNode.log.IsErrorEnabled)
                            RelayNode.log.Error("SocketCommand.Unknown received");
						result.CompleteOperation(wasSyncronous);
						return result;						
					case SocketCommand.HandleOneWayMessage:
					case SocketCommand.HandleSyncMessage:
						relayMessage = RelayMessageFormatter.ReadRelayMessage(message.Message);
						relayMessage.ResultOutcome = RelayOutcome.Received;
						_dataHandler.BeginHandleMessage(relayMessage, null, async => {
							try
							{
								_dataHandler.EndHandleMessage(async);
								if (command == SocketCommand.HandleSyncMessage)
								{
									result.ReplyMessage = relayMessage;
								}
							}
							catch (Exception exc)
							{
								result.Exception = exc;
							}
							finally
							{
								result.CompleteOperation(async.CompletedSynchronously);
							}
						});
						break;
					case SocketCommand.HandleOneWayMessages:
					case SocketCommand.HandleSyncMessages:
						relayMessages = RelayMessageFormatter.ReadRelayMessageList(message.Message, msg => msg.ResultOutcome = RelayOutcome.Received);
						_dataHandler.BeginHandleMessages(relayMessages, null, async =>
							{
								try
								{
									_dataHandler.EndHandleMessages(async);
									if (command == SocketCommand.HandleSyncMessages)
									{
										result.ReplyMessages = relayMessages;
									}
								}
								catch (Exception exc)
								{
									result.Exception = exc;
								}
								finally
								{
									result.CompleteOperation(async.CompletedSynchronously);
								}
							});
						break;
					case SocketCommand.GetRuntimeInfo:
						_enqueueGetComponentRuntimeInfo(result);
						break;
					default:
                        if (RelayNode.log.IsErrorEnabled)
                            RelayNode.log.ErrorFormat("Unhandled command {0} sent to Relay Service via socket transport", command);
						result.CompleteOperation(wasSyncronous);
						return result;
				}
			}
			catch (Exception exc)
			{
				result.Exception = exc;
				result.CompleteOperation(wasSyncronous);
			}
			
			return result;
		}