Пример #1
0
        /// <summary>
        /// Copies the input stream to the output stream with intermediate size labels.
        /// </summary>
        /// <param name="inputStream">The source stream.</param>
        /// <param name="outputStream">The destination stream.</param>
        /// <param name="writer">The writer created on destination stream.</param>
        /// <param name="intermediateBuffer">The intermediate buffer.</param>
        public static void WriteLabelledStream(Stream inputStream, GenuineChunkedStream outputStream, BinaryWriter writer, byte[] intermediateBuffer)
        {
            if (inputStream.CanSeek)
            {
                writer.Write((byte)MessageCoder.COMMAND_MAGIC_CODE);
                writer.Write((int)inputStream.Length);
                writer.Write((byte)1);
                outputStream.WriteStream(inputStream);
                return;
            }

            for ( ; ;)
            {
                int bytesRead = inputStream.Read(intermediateBuffer, 0, intermediateBuffer.Length);
                writer.Write((byte)MessageCoder.COMMAND_MAGIC_CODE);
                writer.Write((int)bytesRead);
                writer.Write((byte)(bytesRead < intermediateBuffer.Length? 1 : 0));
                writer.BaseStream.Write(intermediateBuffer, 0, bytesRead);

                if (bytesRead < intermediateBuffer.Length)
                {
                    return;
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Returns a stream containing version of the using protocol and type of the connection being established.
        /// </summary>
        /// <param name="protocolVersion">The version of the protocol.</param>
        /// <param name="genuineConnectionType">Type of the connection.</param>
        /// <param name="connectionId">The identifier of the connection.</param>
        /// <returns>BinaryWriter containing a stream with serialized data.</returns>
        public static BinaryWriter SerializeConnectionHeader(byte protocolVersion, GenuineConnectionType genuineConnectionType, string connectionId)
        {
            GenuineChunkedStream stream       = new GenuineChunkedStream(false);
            BinaryWriter         binaryWriter = new BinaryWriter(stream);

            binaryWriter.Write((byte)protocolVersion);
            binaryWriter.Write((byte)genuineConnectionType);
            binaryWriter.Write((string)connectionId);

            return(binaryWriter);
        }
        /// <summary>
        /// Sends the content of the log to the remote host.
        /// </summary>
        /// <param name="stream">The stream containing a request or a response.</param>
        /// <param name="sender">The remote host that sent this request.</param>
        /// <returns>The response.</returns>
        public Stream HandleMessage(Stream stream, HostInformation sender)
        {
            if (_stopped)
                return Stream.Null;

            int expectedSize = 640000;

            // copy to an intermediate stream
            GenuineChunkedStream intermediateStream = new GenuineChunkedStream(true);
            GenuineUtility.CopyStreamToStream(this._memoryWritingStream, intermediateStream, expectedSize);

            // and send it as one chunk
            return intermediateStream;
        }
        /// <summary>
        /// Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>A new object that is a copy of this instance.</returns>
        public object Clone()
        {
            if (this._disposed)
            {
                throw new ObjectDisposedException("GenuineChunkedStream");
            }
            if (this._releaseOnReadMode)
            {
                throw new InvalidOperationException();
            }

            GenuineChunkedStream copy = new GenuineChunkedStream(false);

            copy._chunksAndStreams  = this._chunksAndStreams;
            copy._currentWriteBlock = this._currentWriteBlock;
            copy._length            = this._length;
            copy._writePosition     = this._writePosition;

            // prevents buffers from being returned to Buffer Pool
            this._cloned = true;
            copy._cloned = true;

            return(copy);
        }
        /// <summary>
        /// Encrypts the message data and put a result into the specified output stream.
        /// </summary>
        /// <param name="input">The stream containing the serialized message.</param>
        /// <param name="output">The result stream with the data being sent to the remote host.</param>
        public override void Encrypt(Stream input, GenuineChunkedStream output)
        {
            // write session established flag
            output.WriteByte(1);

            // serialize messages into separate stream
            this.SspiSecurityContext.EncryptMessage(input, output, this.KeyProvider_SspiClient.RequiredFeatures);
        }
        /// <summary>
        /// Invokes the target or dispatches the response according to message content.
        /// Throws the exception on any errors.
        /// </summary>
        /// <param name="message">The message being processed.</param>
        public void HandleMessage_Final(Message message)
        {
            // get the specified transport user
            ITransportUser iTransportUser = null;
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;
            if (message.SecuritySessionParameters.RemoteTransportUser.Length > 0)
                iTransportUser = this._transportUsers[message.SecuritySessionParameters.RemoteTransportUser] as ITransportUser;

            if (iTransportUser == null)
                iTransportUser = this.DefaultTransportUser;

            // direct the response to the response handler
            if (message.ReplyToId > 0)
            {
                IResponseProcessor iResponseProcessor = GenuineReceivingHandler._responseHandlers[message.ReplyToId] as IResponseProcessor;

                // check whether it's OK
                if (iResponseProcessor == null)
                {
            #if TRIAL
            #else
                    GenuineReceivingHandler._responseHandlers.Remove(message.ReplyToId);
            #endif

                    return ;
                }

                if (! iResponseProcessor.IsExpired(GenuineUtility.TickCount))
                    iResponseProcessor.ProcessRespose(message);

            #if TRIAL
            #else
                if (iResponseProcessor.IsExpired(GenuineUtility.TickCount))
                    GenuineReceivingHandler._responseHandlers.Remove(message.ReplyToId);
            #endif

                return ;
            }

            //			if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Security] > 0 )
            //				binaryLogWriter.WriteEvent(LogCategory.MessageProcessing, "GenuineReceivingHandler.HandleMessage_Final",
            //					LogMessageType.MessageDispatched, null, message, message.Recipient, null,
            //					GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
            //					null, message.SecuritySessionParameters.Name, -1, 0, 0, 0, null, null, null, null,
            //					"The message is dispatched.");

            // dispatch it
            switch (message.GenuineMessageType)
            {
                case GenuineMessageType.Ordinary:
                    // dispatch the message to the sink
                    iTransportUser.HandleMessage(message);
                    break;

                case GenuineMessageType.TrueBroadcast:
                case GenuineMessageType.BroadcastEngine:
                    // get the string
                    BinaryFormatter binaryFormatter = new BinaryFormatter();
                    IMessage iMessage = null;

                    try
                    {
                        iMessage = (IMessage) binaryFormatter.Deserialize(message.Stream);
                        IMethodReturnMessage ret = null;

                        if (message.DestinationMarshalByRef is string)
                        {
                            // message come via true multicast channel to the specific court
                            MarshalByRefObject receiver, sender;

                            // get the court info
                            CourtCollection.Find( (string) message.DestinationMarshalByRef,
                                out receiver, out sender);

                            if (receiver == null)
                            {
                                // message to the unregistered court has been received
                                this.ITransportContext.IGenuineEventProvider.Fire(new GenuineEventArgs(GenuineEventType.BroadcastUnknownCourtReceived, null,
                                    message.Sender, message.DestinationMarshalByRef));

                                // LOG: put down the log record
                                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0 )
                                {
                                    binaryLogWriter.WriteEvent(LogCategory.BroadcastEngine, "GenuineReceivingHanlder.HandleMessage_Final",
                                        LogMessageType.MessageRequestInvoking, GenuineExceptions.Get_Debugging_GeneralWarning("No objects are associated with the \"{0}\" court.", (string) message.DestinationMarshalByRef),
                                        message, message.Sender, null,
                                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                        null, null, -1, 0, 0, 0, null, null, null, null,
                                        "The message is ignored because no objects are associated with the \"{0}\" court.", (string) message.DestinationMarshalByRef);
                                }

                                return ;
                            }

                            if (message.ITransportHeaders[Message.TransportHeadersBroadcastSendGuid] is string
                                && UniqueCallTracer.Instance.WasGuidRegistered( RemotingServices.GetObjectUri(receiver) + (string) message.ITransportHeaders[Message.TransportHeadersBroadcastSendGuid]))
                            {
                                // LOG: put down the log record
                                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0 )
                                {
                                    binaryLogWriter.WriteEvent(LogCategory.BroadcastEngine, "GenuineReceivingHanlder.HandleMessage_Final",
                                        LogMessageType.MessageRequestInvoking, GenuineExceptions.Get_Broadcast_CallHasAlreadyBeenMade(),
                                        message, message.Sender, null,
                                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                        null, null, -1, 0, 0, 0, null, null, null, null,
                                        "This message is ignored because this call has been already processed.");
                                }

                                // this call has been already processed
                                ret = new ReturnMessage(GenuineExceptions.Get_Broadcast_CallHasAlreadyBeenMade(), (IMethodCallMessage) iMessage);
                            }
                            else
                            {
                                // perform the call
                                try
                                {
                                    // LOG: put down the log record
                                    if ( binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0 )
                                    {
                                        binaryLogWriter.WriteEvent(LogCategory.BroadcastEngine, "GenuineReceivingHanlder.HandleMessage_Final",
                                            LogMessageType.MessageRequestInvoking, null,
                                            message, message.Sender, null,
                                            GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                            null, null, -1, 0, 0, 0, null, null, null, null,
                                            "The multicast message is being invoked on court \"{0}\".", (string) message.DestinationMarshalByRef);
                                    }

                                    ret = RemotingServices.ExecuteMessage(receiver, (IMethodCallMessage) iMessage);
                                }
                                catch(Exception ex)
                                {
                                    // LOG: put down the log record
                                    if ( binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0 )
                                    {
                                        binaryLogWriter.WriteEvent(LogCategory.BroadcastEngine, "GenuineReceivingHanlder.HandleMessage_Final",
                                            LogMessageType.MessageRequestInvoking, ex,
                                            message, message.Sender, null,
                                            GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                            null, null, -1, 0, 0, 0, null, null, null, null,
                                            "An exception occurred while the message was being processed. The exception is dispatched back.");
                                    }

                                    ret = new ReturnMessage(ex, (IMethodCallMessage) iMessage);
                                }
                            }

            //							if (sender != null)
            //								message.Sender = this.ITransportContext.KnownHosts[GenuineUtility.FetchChannelUriFromMbr(sender)];

                            // set correct remote guid
                            ITransportContext iTransportContext = this.ITransportContext;
                            if (sender != null)
                            {
                                string uri;
                                GenuineUtility.FetchChannelUriFromMbr(sender, out uri, out iTransportContext);
                                if (uri == null || iTransportContext == null)
                                    iTransportContext = this.ITransportContext;
                                else
                                    message.Sender = iTransportContext.KnownHosts[uri];
                            }

                            Message reply = CreateResponseToBroadcastMessage(message, ret, binaryFormatter);
                            reply.DestinationMarshalByRef = GenuineUtility.FetchDotNetUriFromMbr(receiver);

                            // LOG: put down the log record
                            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0 )
                                this.PutDownRecordAboutResponseCreation(binaryLogWriter, reply, ret, "The response to the \"true\" broadcast message has been created.");

                            iTransportContext.ConnectionManager.Send(reply);
                        }
                        else
                        {
                            MarshalByRefObject marshalByRefObject = null;

                            if ((message.DestinationMarshalByRef is MarshalByRefObject))
                                marshalByRefObject = (MarshalByRefObject) message.DestinationMarshalByRef;
                            else
                            {
                                Exception exception = GenuineExceptions.Get_Debugging_GeneralWarning("Can't process the object with type {0}", message.DestinationMarshalByRef == null ? "<null!>" : message.DestinationMarshalByRef.GetType().ToString());

                                if (binaryLogWriter != null)
                                {
                                    binaryLogWriter.WriteImplementationWarningEvent("GenuineReceivingHandler.HandleMessage_Final",
                                        LogMessageType.CriticalError, exception,
                                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                        "The response with the {0} type cannot be processed.", message.DestinationMarshalByRef.GetType());
                                }

                                throw exception;
                            }

                            if (message.ITransportHeaders[Message.TransportHeadersBroadcastSendGuid] is string
                                && UniqueCallTracer.Instance.WasGuidRegistered( RemotingServices.GetObjectUri( marshalByRefObject ) + (string) message.ITransportHeaders[Message.TransportHeadersBroadcastSendGuid]))
                            {
                                Exception exception = GenuineExceptions.Get_Broadcast_CallHasAlreadyBeenMade();

                                // LOG: put down the log record
                                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0 )
                                {
                                    binaryLogWriter.WriteEvent(LogCategory.BroadcastEngine, "GenuineReceivingHanlder.HandleMessage_Final",
                                        LogMessageType.MessageRequestInvoking, exception,
                                        message, message.Sender, null,
                                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                        null, null, -1, 0, 0, 0, null, null, null, null,
                                        "This message is ignored because this call has been already processed.");
                                }

                                ret = new ReturnMessage(exception, (IMethodCallMessage) iMessage);
                            }
                            else
                            {
                                // LOG: put down the log record
                                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0 )
                                {
                                    binaryLogWriter.WriteEvent(LogCategory.BroadcastEngine, "GenuineReceivingHanlder.HandleMessage_Final",
                                        LogMessageType.MessageRequestInvoking, null,
                                        message, message.Sender, null,
                                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                        null, null, -1, 0, 0, 0, null, null, null, null,
                                        "The usual broadcast message is being invoked.");
                                }

                                ret = RemotingServices.ExecuteMessage(marshalByRefObject, (IMethodCallMessage) iMessage);
                            }

                            Message reply = CreateResponseToBroadcastMessage(message, ret, binaryFormatter);

                            // LOG: put down the log record
                            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0 )
                                this.PutDownRecordAboutResponseCreation(binaryLogWriter, reply, ret, "The response to the usual broadcast invocation has been created.");

                            reply.ITransportHeaders[Message.TransportHeadersMbrUriName] = message.ITransportHeaders[Message.TransportHeadersMbrUriName];
                            this.ITransportContext.ConnectionManager.Send(reply);
                        }
                    }
                    catch(Exception ex)
                    {
                        try
                        {
                            // LOG: put down the log record
                            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0 )
                            {
                                binaryLogWriter.WriteEvent(LogCategory.BroadcastEngine, "GenuineReceivingHanlder.HandleMessage_Final",
                                    LogMessageType.MessageRequestInvoking, ex,
                                    message, message.Sender, null,
                                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                    null, null, -1, 0, 0, 0, null, null, null, null,
                                    "An exception occurred while the usual broadcast message was being processed. The exception is dispatched back.");
                            }

                            ReturnMessage returnMessage = new ReturnMessage(ex, (IMethodCallMessage) iMessage);
                            Message reply = CreateResponseToBroadcastMessage(message, returnMessage, binaryFormatter);

                            // LOG: put down the log record
                            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0 )
                                this.PutDownRecordAboutResponseCreation(binaryLogWriter, reply, returnMessage, "The response to the usual broadcast invocation has been created.");

                            this.ITransportContext.ConnectionManager.Send(reply);
                        }
                        catch(Exception internalException)
                        {
                            // it's a destiny not to reply to this message

                            // LOG: put down the log record
                            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0 )
                            {
                                binaryLogWriter.WriteEvent(LogCategory.BroadcastEngine, "GenuineReceivingHanlder.HandleMessage_Final",
                                    LogMessageType.MessageRequestInvoking, internalException,
                                    message, message.Sender, null,
                                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                    null, null, -1, 0, 0, 0, null, null, null, null,
                                    "An exception occurred again while the previous exception was being serialized. This request is ignored.");
                            }
                        }
                    }
                    break;

                case GenuineMessageType.ExternalStreamConsumer:
                    // direct the response to response handler
                    if (message.ReplyToId > 0)
                    {
                        IResponseProcessor iResponseProcessor = GenuineReceivingHandler._responseHandlers[message.ReplyToId] as IResponseProcessor;
                        if (! iResponseProcessor.IsExpired(GenuineUtility.TickCount))
                            iResponseProcessor.ProcessRespose(message);

            #if TRIAL
            #else
                        if (iResponseProcessor.IsExpired(GenuineUtility.TickCount))
                            GenuineReceivingHandler._responseHandlers.Remove(message.ReplyToId);
            #endif

                        break;
                    }

                    string entryName = message.DestinationMarshalByRef as string;
                    if (entryName != null)
                    {
                        if (message.IsOneWay)
                        {
                            this.ITransportContext.DirectExchangeManager.HandleRequest(message);
                            return ;
                        }

                        Stream response = null;
                        Message reply;
                        try
                        {
                            // LOG: put down the log record
                            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.DXM] > 0 )
                            {
                                binaryLogWriter.WriteEvent(LogCategory.BroadcastEngine, "GenuineReceivingHanlder.HandleMessage_Final",
                                    LogMessageType.MessageRequestInvoking, null,
                                    message, message.Sender, null,
                                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                    null, null, -1, 0, 0, 0, null, null, null, null,
                                    "The DXM message is being dispatched to the \"{0}\" entry.", entryName);
                            }

                            response = this.ITransportContext.DirectExchangeManager.HandleRequest(message);
                            if (response == null)
                                response = Stream.Null;
                            reply = new Message(message, new TransportHeaders(), response);

                            // LOG: put down the log record
                            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.MessageProcessing] > 0 )
                            {
                                if (this.ITransportContext.BinaryLogWriter[LogCategory.MessageProcessing] > 1)
                                {
                                    // make a copy of the source stream
                                    GenuineChunkedStream copy = new GenuineChunkedStream(false);
                                    GenuineUtility.CopyStreamToStream(reply.Stream, copy);
                                    reply.Stream = copy;
                                }

                                binaryLogWriter.WriteMessageCreatedEvent("AsyncSinkStackResponseProcessor.ProcessRespose",
                                    LogMessageType.MessageCreated, null, reply, false, reply.Recipient,
                                    this.ITransportContext.BinaryLogWriter[LogCategory.MessageProcessing] > 1 ? reply.Stream : null,
                                    entryName, entryName,
                                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, -1, -1, null, -1, null,
                                    "A response to DXM request has been created.");

                                message.ITransportHeaders[Message.TransportHeadersInvocationTarget] = entryName;
                                message.ITransportHeaders[Message.TransportHeadersMethodName] = entryName;

                                binaryLogWriter.WriteEvent(LogCategory.MessageProcessing, "AsyncSinkStackResponseProcessor.ProcessRespose",
                                    LogMessageType.MessageRequestInvoked, null, reply, reply.Recipient, null,
                                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, -1,
                                    GenuineUtility.TickCount, 0, message.SeqNo, null, null, null, null,
                                    "The DXM invocation has been completed.");
                            }

                            message.ITransportContext.ConnectionManager.Send(reply);
                        }
                        catch(Exception ex)
                        {
                            // LOG: put down the log record
                            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.DXM] > 0 )
                            {
                                binaryLogWriter.WriteEvent(LogCategory.BroadcastEngine, "GenuineReceivingHanlder.HandleMessage_Final",
                                    LogMessageType.MessageRequestInvoking, ex,
                                    message, message.Sender, null,
                                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                    null, null, -1, 0, 0, 0, null, null, null, null,
                                    "The invocation of the DXM message directed to the \"{0}\" entry has resulted in exception.", entryName);
                            }

                            // return this exception as a result
                            BinaryFormatter binaryFormatter2 = new BinaryFormatter();
                            GenuineChunkedStream serializedException = new GenuineChunkedStream(false);
                            binaryFormatter2.Serialize(serializedException, ex);

                            reply = new Message(message, new TransportHeaders(), serializedException);
                            reply.ContainsSerializedException = true;

                            // LOG: put down the log record
                            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0 )
                            {
                                string invocationTarget = entryName;
                                string methodName = null;
                                object service = this.ITransportContext.DirectExchangeManager.GetServerService(entryName);
                                if (service != null)
                                    methodName = service.GetType().FullName;

                                binaryLogWriter.WriteMessageCreatedEvent("GenuineReceivingHanlder.HandleMessage_Final",
                                    LogMessageType.MessageCreated, null, reply, false, reply.Recipient,
                                    this.ITransportContext.BinaryLogWriter[LogCategory.MessageProcessing] > 1 ? reply.Stream : null,
                                    invocationTarget, methodName,
                                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, -1, -1, null, -1, null,
                                    "The response to DXM message directed to the \"{0}\" court has been created.", entryName);

                                reply.ITransportHeaders[Message.TransportHeadersInvocationTarget] = invocationTarget;
                                reply.ITransportHeaders[Message.TransportHeadersMethodName] = methodName;
                            }

                            this.ITransportContext.ConnectionManager.Send(reply);
                        }
                    }
                    break;

                default:
                    // LOG:
                    if ( binaryLogWriter != null && binaryLogWriter[LogCategory.MessageProcessing] > 0 )
                        binaryLogWriter.WriteEvent(LogCategory.MessageProcessing, "GenuineReceivingHandler.HandleMessage_Final",
                            LogMessageType.MessageDispatched, GenuineExceptions.Get_Debugging_GeneralWarning("Unknown message type."),
                            message, message.Sender,
                            null,
                            GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, message.SecuritySessionParameters.Name,
                            -1, 0, 0, 0, null, null, null, null,
                            "A message has an unknown type and can not be processed. Type: {0}", (int) message.GenuineMessageType);
                    break;
            }
        }
        /// <summary>
        /// Encrypts the stream under current security conditions.
        /// </summary>
        /// <param name="messageStream">Data to be encrypted.</param>
        /// <param name="outputStream">Stream to write encrypted content to.</param>
        /// <param name="sspiFeatureFlags">Requested features.</param>
        public void EncryptMessage(Stream messageStream, GenuineChunkedStream outputStream, SspiFeatureFlags sspiFeatureFlags)
        {
            // get package sizes
            lock(_secPkgContext_SizesLock)
            {
                if (! _secPkgContext_SizesInitialized)
                {
                    SspiApi.QueryContextSizes(this._phContext, ref this._secPkgContext_Sizes);
                    _secPkgContext_SizesInitialized = true;
                }
            }

            byte[] chunk = null;
            int position = 0;
            BinaryWriter outputWriter = new BinaryWriter(outputStream);

            if ( (sspiFeatureFlags & SspiFeatureFlags.Encryption) != 0)
                // it'll write signature automatically as well as encrypt content
                SspiApi.EncryptMessage(this._phContext, messageStream, outputWriter, ref this._secPkgContext_Sizes);
            else if ( (sspiFeatureFlags & SspiFeatureFlags.Signing) != 0)
            {
                // remember position to write signature size later
                outputStream.WriteInt32AndRememberItsLocation(0, out chunk, out position);
                long currentLength = outputStream.Length;

                // anyway will have to read this into buffer
                byte[] contentBuffer = new byte[(int) messageStream.Length];
                GenuineUtility.ReadDataFromStream(messageStream, contentBuffer, 0, contentBuffer.Length);

                // write signature
                SspiApi.MakeSignature(this._phContext, contentBuffer, outputWriter, ref this._secPkgContext_Sizes);

                // update signature size
                MessageCoder.WriteInt32(chunk, position, (int) (outputStream.Length - currentLength) );

                // write the content
                outputWriter.Write( (int) contentBuffer.Length );
                outputWriter.Write( contentBuffer, 0, contentBuffer.Length);
            }
            else
            {
                // just copy the source content
                //outputWriter.Write( (int) messageStream.Length );
                GenuineUtility.CopyStreamToStream(messageStream, outputStream);
            }
        }
            /// <summary>
            /// Reads messages from the connection and processes them synchronously.
            /// </summary>
            public void ReceiveSynchronously()
            {
                try
                {
                    for ( ; ; )
                    {
                        if (! this.SharedMemoryConnection.IsValid)
                            return ;

                        using (Stream stream = this.SharedMemoryConnection.LowLevel_ReadSync(GenuineUtility.GetTimeout(this.SharedMemoryConnection._closeAfterInactivity)))
                        {
                            // receive the message
                            GenuineChunkedStream theMessage = new GenuineChunkedStream(true);
                            GenuineUtility.CopyStreamToStream(stream, theMessage);

                            // a message was successfully received
                            this.SharedMemoryConnection.Renew();
                            if (theMessage.Length == 0)
                            {
                                // LOG:
                                BinaryLogWriter binaryLogWriter = this.SharedMemoryConnectionManager.ITransportContext.BinaryLogWriter;
                                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                                {
                                    binaryLogWriter.WriteEvent(LogCategory.Connection, "SharedMemoryConnectionManager.ReceiveSynchronously",
                                        LogMessageType.ConnectionPingReceived, null, null, null, null,
                                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                        null, null, this.SharedMemoryConnection.DbgConnectionId, 0, 0, 0, null, null, null, null,
                                        "A message with zero size is treated as ping.");
                                }

                                continue;
                            }

                            this.SharedMemoryConnectionManager.ITransportContext.IIncomingStreamHandler.HandleMessage(theMessage, this.SharedMemoryConnection.Remote, GenuineConnectionType.Persistent, null, this.SharedMemoryConnection.DbgConnectionId, false, null, this.SharedMemoryConnection.ConnectionLevelSecurity, null);
                            this.SharedMemoryConnection.Renew();
                        }
                    }
                }
                catch(Exception ex)
                {
                    this.SharedMemoryConnectionManager.ConnectionFailed(ex, this.SharedMemoryConnection);
                }
            }
        /// <summary>
        /// Sends a message to the remote host.
        /// </summary>
        /// <param name="message">The message to be sent.</param>
        public void Send(Message message)
        {
            #if TRIAL
            _messagesBeingSent[message.MessageId] = message;
            #endif

            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            try
            {
                using (new ReaderAutoLocker(this._disposeLock))
                {
                    if (this._disposed)
                        throw OperationException.WrapException(this._disposeReason);
                }

                SecuritySession session = null;

                if (this._disposed)
                    throw OperationException.WrapException(this._disposeReason);

                // get the security session descriptor
                if (message.SecuritySessionParameters == null)
                {
                    SecuritySessionParameters securitySessionParameters = SecuritySessionServices.GetCurrentSecurityContext();
                    if (securitySessionParameters == null)
                        securitySessionParameters = message.Recipient.SecuritySessionParameters;
                    if (securitySessionParameters == null)
                        securitySessionParameters = this.ITransportContext.SecuritySessionParameters;
                    if (securitySessionParameters == null)
                        securitySessionParameters = SecuritySessionServices.DefaultSecuritySession;
                    message.SecuritySessionParameters = securitySessionParameters;
                }

                // LOG:
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.MessageProcessing] > 0 )
                    binaryLogWriter.WriteSecuritySessionParametersEvent("ConnectionManager.Send",
                        LogMessageType.SecuritySessionParametersAssembled, null, message, message.Recipient,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                        message.SecuritySessionParameters,
                        "Security Session Parameters have been assembled.");

                // determine the type of sending
                message.IsSynchronous = (message.SecuritySessionParameters.Attributes & SecuritySessionAttributes.ForceSync) != 0 ||
                    (message.IsSynchronous && (message.SecuritySessionParameters.Attributes & SecuritySessionAttributes.ForceAsync) == 0);

                // the time until invocation times out
                if (! message.FinishTime_Initialized)
                {
                    TimeSpan messageTimeout = message.SecuritySessionParameters.Timeout;
                    if (messageTimeout == TimeSpan.MinValue)
                        messageTimeout = (TimeSpan) this.ITransportContext.IParameterProvider[GenuineParameter.InvocationTimeout];
                    message.FinishTime = GenuineUtility.GetTimeout(messageTimeout);

                    message.FinishTime_Initialized = true;
                }

                // checks whether the message has been already processed by Security Session
                if (message.SerializedContent == null)
                {
                    session = message.Recipient.GetSecuritySession(message.SecuritySessionParameters.Name, this.ITransportContext.IKeyStore);
                    if (! session.IsEstablished)
                    {
                        if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Security] > 0 )
                            binaryLogWriter.WriteEvent(LogCategory.Security, "ConnectionManager.Send",
                                LogMessageType.SecuritySessionHasNotBeenEstablishedYet, null, message, message.Recipient, null,
                                GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                session, session.Name, -1, 0, 0, 0, null, null, null, null,
                                "The requested Security Session is not established.");

                        session.InitiateEstablishingSecuritySession(message.SecuritySessionParameters);

                        // if it's a sync sending, then wait until security session will be established
                        if ( message.IsSynchronous )
                        {
                            int timeSpanToWait = GenuineUtility.GetMillisecondsLeft(message.FinishTime);
                            if (timeSpanToWait <= 0)
                                throw GenuineExceptions.Get_Send_ServerDidNotReply();

                            // wait until Security Session will be established or a failure will be detected
                            int firedEvent = 0;
                            if (message.CancelSending != null)
                                firedEvent = WaitHandle.WaitAny(new WaitHandle[] { session.IsEstablishedEvent, session.Failed, message.CancelSending }, timeSpanToWait, false);
                            else
                                firedEvent = WaitHandle.WaitAny(new WaitHandle[] { session.IsEstablishedEvent, session.Failed }, timeSpanToWait, false);

                            if (firedEvent == WaitHandle.WaitTimeout)
                                throw GenuineExceptions.Get_Send_ServerDidNotReply();

                            // analyze the problem, if any
                            Exception exception = session.ReasonOfFailure;
                            if (firedEvent == 1)
                            {
                                if (exception != null)
                                    throw OperationException.WrapException(exception);
                                else
                                    throw GenuineExceptions.Get_Security_ContextWasNotEstablished(session.Name);
                            }

                            // if the message has been cancelled, let the sender to understand the reason
                            if (firedEvent == 2)
                                return ;
                        }
                        else if (! session.IsEstablished)
                        {
                            // it's async and SS still isn't established
                            session.PutMessageToAwaitingQueue(message);
                            return;
                        }
                    }
                }

                // if serialization is necessary
                if (message.SerializedContent == null)
                {
                    // serialize the message
                    GenuineChunkedStream serializedMessageStream = new GenuineChunkedStream(false);
                    MessageCoder.Serialize(serializedMessageStream, message, (message.SecuritySessionParameters.Attributes & SecuritySessionAttributes.EnableCompression) != 0);

                    // save the name of the Security Session
                    GenuineChunkedStream resultStream = new GenuineChunkedStream(false);
                    BinaryWriter writer = new BinaryWriter(resultStream);
                    writer.Write(message.SecuritySessionParameters.Name);
                    session.Encrypt(serializedMessageStream, resultStream);
                    message.SerializedContent = resultStream;

                    // LOG: put down the log record
                    if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Security] > 0 )
                    {
                        binaryLogWriter.WriteEvent(LogCategory.Security, "ConnectionManager.Send",
                            LogMessageType.SecuritySessionApplied, null, message, message.Recipient,
                            binaryLogWriter[LogCategory.Security] > 1 ? message.SerializedContent : null,
                            GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, session,
                            session.Name, -1, 0, 0, 0, null, null, null, null,
                            "The message has been processed by the established Security Session.");
                    }
                }

            #if TRIAL
                if (message.MessageId > 3005)
                    throw GenuineExceptions.Get_Channel_TrialConditionExceeded("The maximum number of messages restriction has been exceeded. You can not send more than 3000 messages using TRIAL version.");
            #endif

                message.Sender = this.Local;
                this.InternalSend(message);
            }
            catch(Exception ex)
            {
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Security] > 0 )
                    binaryLogWriter.WriteEvent(LogCategory.MessageProcessing, "ConnectionManager.Send",
                        LogMessageType.Error, ex, message, message.Recipient, null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                        null, null, -1, 0, 0, 0, null, null, null, null,
                        "An exception occurred while processing the message.");

                throw;
            }
        }
        /// <summary>
        /// Initiates or continues establishing of the Security Session.
        /// </summary>
        /// <param name="input">A null reference or an incoming stream.</param>
        /// <param name="connectionLevel">Indicates whether the Security Session operates on connection level.</param>
        /// <returns>A stream containing data for sending to the remote host or a null reference if Security Session is established.</returns>
        public override GenuineChunkedStream EstablishSession(Stream input, bool connectionLevel)
        {
            // a dance is over
            if (this.IsEstablished)
                return null;

            GenuineChunkedStream outputStream = null;
            BinaryFormatter binaryFormatter = new BinaryFormatter();

            // skip the status flag
            if (connectionLevel)
            {
                if (input != null)
                    input.ReadByte();

                outputStream = new GenuineChunkedStream(false);
            }
            else
                outputStream = this.CreateOutputStream();

            lock (this)
            {
                // write session is being established flag
                BinaryWriter binaryWriter = new BinaryWriter(outputStream);
                binaryWriter.Write((bool) false);

                // remote host sent nothing, send a RSA public key
                if (input == null || input == Stream.Null)
                {
                    // serialize RSA public key
                    RSAParameters rsaParameters = this._rsaCryptoServiceProviderDecryptor.ExportParameters(false);
                    binaryFormatter.Serialize(outputStream, rsaParameters);
                    binaryFormatter.Serialize(outputStream, this._localInstanceGuid);

                    return outputStream;
                }

                // deserialize incoming data
                Rijndael rijndael = null;
                object receivedObject = binaryFormatter.Deserialize(input);

                // RSA public key has been received
                if (receivedObject is RSAParameters)
                {
                    this._remoteInstanceGuid = (string) binaryFormatter.Deserialize(input);
                    if (string.Compare(this._remoteInstanceGuid, this._localInstanceGuid, false) > 0)
                        return this.EstablishSession(Stream.Null, connectionLevel);

                    if (this.RijndaelKey == null)
                    {
                        // create Rijndael key
                        rijndael = Rijndael.Create();
                        this.RijndaelKey = rijndael.Key;
                    }

                    // encrypt it with public rsa key
                    RSAParameters rsaParameters = (RSAParameters) receivedObject;
                    RSACryptoServiceProvider rsaCryptoServiceProvider;
             					try
             					{
             						// try the usual way, and if fails, use the patch in the catch block
             						rsaCryptoServiceProvider = new RSACryptoServiceProvider();
             					}
             					catch
             					{
             						CspParameters CSPParam = new CspParameters();
             						CSPParam.Flags = CspProviderFlags.UseMachineKeyStore;
             						rsaCryptoServiceProvider = new RSACryptoServiceProvider(CSPParam);
             					}
                    rsaCryptoServiceProvider.ImportParameters(rsaParameters);

                    // serialize
                    byte[] encryptedContent = RSAUtility.Encrypt(rsaCryptoServiceProvider, this.RijndaelKey);
                    binaryFormatter.Serialize(outputStream, encryptedContent);

                    return outputStream;
                }

                // Rijndael key has been received
                if (receivedObject is byte[])
                {
                    // first of all, retrieve it
                    byte[] receivedRijndaelKey = RSAUtility.Decrypt(this._rsaCryptoServiceProviderDecryptor, (byte[]) receivedObject);

                    // accept received key
                    this.RijndaelKey = receivedRijndaelKey;

                    // confirm that the session has been established
                    binaryFormatter.Serialize(outputStream, "OK");
                    this.SessionEstablished();
                    return outputStream;
                }

                // a confirmation received that the session is established
                if (receivedObject is string)
                {
                    this.SessionEstablished();
                    return null;
                }
            }

            throw GenuineExceptions.Get_Receive_IncorrectData();
        }
        /// <summary>
        /// Accepts an incoming connection.
        /// </summary>
        /// <param name="url">The name of the share.</param>
        /// <param name="localUri">URI of the local host.</param>
        /// <param name="protocolVersion">The version of the protocol supported by the remote host.</param>
        /// <param name="remoteUri">Uri of the remote host.</param>
        /// <param name="remoteHostUniqueIdentifier">The unique identifier of the HostInformation used by the remote host.</param>
        /// <returns>The established connection.</returns>
        private SharedMemoryConnection LowLevel_AcceptConnection_1(string url, string localUri, byte protocolVersion, out string remoteUri, out int remoteHostUniqueIdentifier)
        {
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            using (new ReaderAutoLocker(this._disposeLock))
            {
                if (this._disposed)
                    throw OperationException.WrapException(this._disposeReason);
            }

            remoteUri = null;
            Stream inputStream = null;
            Stream outputStream = null;
            remoteHostUniqueIdentifier = 0;

            // the maximum time during which the connection must be established
            int timeout = GenuineUtility.GetTimeout((TimeSpan) this.ITransportContext.IParameterProvider[GenuineParameter.ConnectTimeout]);

            // open the client's share
            SharedMemoryConnection sharedMemoryConnection = new SharedMemoryConnection(this.ITransportContext, url, false, true);

            // LOG:
            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
            {
                binaryLogWriter.WriteConnectionParameterEvent(LogCategory.Connection, "SharedMemoryConnectionManager.LowLevel_AcceptConnection",
                    LogMessageType.ConnectionParameters, null, null, this.ITransportContext.IParameterProvider,
                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, sharedMemoryConnection.DbgConnectionId,
                    "The connection is being established to \"{0}\".", url);
            }

            // get the connection-level Security Session
            string connectionLevelSSName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForPersistentConnections] as string;
            SecuritySession securitySession = null;
            if (connectionLevelSSName != null)
                securitySession = this.ITransportContext.IKeyStore.GetKey(connectionLevelSSName).CreateSecuritySession(connectionLevelSSName, null);

            // establish it
            if (securitySession != null && ! securitySession.IsEstablished)
            {
                for ( ; ; )
                {
                    inputStream = Stream.Null;

                    try
                    {
                        // prepare streams
                        inputStream = sharedMemoryConnection.LowLevel_ReadSync(timeout);
                        outputStream = securitySession.EstablishSession(inputStream, true);

                        if (outputStream == null)
                            break;

                        // send a packet to the remote host
                        sharedMemoryConnection.LowLevel_SendSync(outputStream, timeout);
                        if (securitySession.IsEstablished)
                            break;
                    }
                    finally
                    {
                        if (inputStream != null)
                            inputStream.Close();
                        if (outputStream != null)
                            outputStream.Close();
                    }
                }
            }

            sharedMemoryConnection.ConnectionLevelSecurity = securitySession;
            HostInformation remote = null;

            // read remote info
            using (Stream remoteUriStream = sharedMemoryConnection.LowLevel_ReadSync(timeout))
            {
                BinaryReader binaryReader = new BinaryReader(remoteUriStream);
                remoteUri = binaryReader.ReadString();

                remote = this.ITransportContext.KnownHosts[remoteUri];
                if (protocolVersion > 0)
                    remoteHostUniqueIdentifier = binaryReader.ReadInt32();
            }

            // now send connection info through the established connection
            using (GenuineChunkedStream serializedLocalInfo = new GenuineChunkedStream(false))
            {
                // serialize local info
                BinaryWriter binaryWriter = new BinaryWriter(serializedLocalInfo);
                binaryWriter.Write((string) localUri);

                if (protocolVersion > 0)
                    binaryWriter.Write((int) remote.LocalHostUniqueIdentifier);

                // and send it
                sharedMemoryConnection.LowLevel_SendSync(serializedLocalInfo, timeout);
            }

            // LOG:
            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
            {
                binaryLogWriter.WriteEvent(LogCategory.Connection, "SharedMemoryConnectionManager.LowLevel_AcceptConnection_1",
                    LogMessageType.ConnectionEstablished, null, null, remote, null,
                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                    securitySession, connectionLevelSSName,
                    sharedMemoryConnection.DbgConnectionId, (int) GenuineConnectionType.Persistent, 0, 0, this.GetType().Name, null, null, null,
                    "The connection to the remote host has been established.");
            }

            return sharedMemoryConnection;
        }
Пример #12
0
        /// <summary>
        /// Serializes a message to the GenuineChunkedStream stream.
        /// </summary>
        /// <param name="stream">Stream to serialize the message to.</param>
        /// <param name="message">The message being serialized.</param>
        /// <param name="compress">Indicates whether content should be compressed.</param>
        public static void Serialize(GenuineChunkedStream stream, Message message, bool compress)
        {
            // write a mark whether the content will be compressed
            BinaryWriter binaryWriter = new BinaryWriter(stream);
            binaryWriter.Write((bool) compress);

            // gather messages into a separate stream if compression is required
            GenuineChunkedStream usedStream = stream;
            if (compress)
                usedStream = new GenuineChunkedStream(false);
            binaryWriter = new BinaryWriter(usedStream);

            // all simple values
            binaryWriter.Write((byte) message.GenuineMessageType);
            binaryWriter.Write(message.MessageId);
            binaryWriter.Write(message.ReplyToId);
            //			binaryWriter.Write(message.Recipient.Uri);
            binaryWriter.Write((bool) message.IsOneWay);

            // set DestinationMarshalByRef if it is specified in headers
            object broadcastObjRefOrCourt = message.ITransportHeaders[Message.TransportHeadersBroadcastObjRefOrCourt];
            if (broadcastObjRefOrCourt != null)
                message.DestinationMarshalByRef = broadcastObjRefOrCourt;

            // objref if it exists
            if (message.DestinationMarshalByRef != null)
            {
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                binaryWriter.Write( true );
                binaryFormatter.Serialize(binaryWriter.BaseStream, message.DestinationMarshalByRef);
            }
            else
                binaryWriter.Write( false );

            // Security Session parameters
            binaryWriter.Write((Int16) message.SecuritySessionParameters.Attributes);
            binaryWriter.Write(message.SecuritySessionParameters.RemoteTransportUser);

            // now headers
            foreach (DictionaryEntry entry in message.ITransportHeaders)
            {
                string key = entry.Key as string;
                if (key == null || key == "__" || key == Message.TransportHeadersBroadcastObjRefOrCourt
                    || entry.Value == null || key == Message.TransportHeadersGenuineMessageType)
                    continue;

                string val = entry.Value.ToString();

                // now write these strings
                binaryWriter.Write(key);
                binaryWriter.Write(val);
            }

            // headers end tag
            binaryWriter.Write("__");

            // and finally the content
            usedStream.WriteStream(message.Stream);

            // compress the content
            if (compress)
            {
                GZipOutputStream compressingStream = new GZipOutputStream(new NonClosableStream(stream));
                GenuineUtility.CopyStreamToStream(usedStream, compressingStream);
                compressingStream.Finish();
            }
        }
Пример #13
0
        /// <summary>
        /// Returns a stream containing version of the using protocol and type of the connection being established.
        /// </summary>
        /// <param name="protocolVersion">The version of the protocol.</param>
        /// <param name="genuineConnectionType">Type of the connection.</param>
        /// <param name="connectionId">The identifier of the connection.</param>
        /// <returns>BinaryWriter containing a stream with serialized data.</returns>
        public static BinaryWriter SerializeConnectionHeader(byte protocolVersion, GenuineConnectionType genuineConnectionType, string connectionId)
        {
            GenuineChunkedStream stream = new GenuineChunkedStream(false);
            BinaryWriter binaryWriter = new BinaryWriter(stream);
            binaryWriter.Write((byte) protocolVersion);
            binaryWriter.Write((byte) genuineConnectionType);
            binaryWriter.Write((string) connectionId);

            return binaryWriter;
        }
        /// <summary>
        /// Sends the response to the remote host.
        /// </summary>
        /// <param name="httpContext">The http context.</param>
        /// <param name="listener">True if it's a listener.</param>
        /// <param name="httpServerConnection">The connection containing CLSS.</param>
        /// <param name="applyClss">Indicates whether it is necessary to apply Connection Level Security Session.</param>
        /// <param name="content">The content being sent to the remote host.</param>
        /// <param name="httpServerConnectionForDebugging">The connection that will be mentioned in the debug records.</param>
        public void LowLevel_SendStream(HttpContext httpContext, bool listener, HttpServerConnection httpServerConnection, bool applyClss, ref Stream content, HttpServerConnection httpServerConnectionForDebugging)
        {
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            try
            {
                if (applyClss)
                {
                    // detect clss
                    SecuritySession clss = null;
                    if (httpServerConnection != null && listener && httpServerConnection.Listener_SecuritySession != null && httpServerConnection.Listener_SecuritySession.IsEstablished)
                        clss = httpServerConnection.Listener_SecuritySession;
                    if (httpServerConnection != null && ! listener && httpServerConnection.Sender_SecuritySession != null && httpServerConnection.Sender_SecuritySession.IsEstablished)
                        clss = httpServerConnection.Sender_SecuritySession;

                    // apply clss
                    if (clss != null)
                    {
                        GenuineChunkedStream encryptedContent = new GenuineChunkedStream(false);
                        clss.Encrypt(content, encryptedContent);
                        content = encryptedContent;
                    }
                }

            #if DEBUG
                Debug.Assert(content.CanSeek);
                Debug.Assert(content.Length >= 0);
            #endif

                // prepare the response
                HttpResponse response = httpContext.Response;
                response.ContentType = "application/octet-stream";
                response.StatusCode = 200;
                response.StatusDescription = "OK";
                int contentLength = (int) content.Length;
                response.AppendHeader("Content-Length", contentLength.ToString() );

                // write the response
                Stream responseStream = response.OutputStream;
                GenuineUtility.CopyStreamToStream(content, responseStream, contentLength);
                this.ITransportContext.ConnectionManager.IncreaseBytesSent(contentLength);

            #if DEBUG
                // the content must end up here
                Debug.Assert(content.ReadByte() == -1);
            #endif

                // LOG:
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0 )
                {
                    bool writeContent = binaryLogWriter[LogCategory.LowLevelTransport] > 1;
                    GenuineChunkedStream copiedContent = null;
                    if (writeContent)
                    {
                        copiedContent = new GenuineChunkedStream(false);
                        GenuineUtility.CopyStreamToStream(content, copiedContent);
                    }

                    binaryLogWriter.WriteTransportContentEvent(LogCategory.LowLevelTransport, "HttpServerConnectionManager.LowLevel_SendStream",
                        LogMessageType.LowLevelTransport_AsyncSendingInitiating, null, null, httpServerConnectionForDebugging.Remote,
                        copiedContent,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, httpServerConnectionForDebugging.DbgConnectionId,
                        (int) content.Length, null, null, null,
                        "Response is sent back to the client. Buffer: {0}; BufferOutput: {1}; Charset: {2}; ContentEncoding: {3}; ContentType: {4}; IsClientConnected: {5}; StatusCode: {6}; StatusDescription: {7}; SuppressContent: {8}; Content-Length: {9}. Connection: {10}.",
                        response.Buffer, response.BufferOutput, response.Charset,
                        response.ContentEncoding, response.ContentType, response.IsClientConnected,
                        response.StatusCode, response.StatusDescription, response.SuppressContent,
                        contentLength, listener ? "LISTENER" : "SENDER");
                }
            }
            catch(Exception ex)
            {
                // LOG:
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                {
                    binaryLogWriter.WriteEvent(LogCategory.Connection, "HttpServerConnectionManager.LowLevel_SendStream",
                        LogMessageType.MessageIsSentAsynchronously, ex, null, httpServerConnectionForDebugging.Remote, null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null,
                        httpServerConnectionForDebugging.DbgConnectionId, 0, 0, 0, null, null, null, null,
                        "Error occurred while sending a response.");
                }
                throw;
            }
        }
Пример #15
0
        /// <summary>
        /// Fills in the provided stream with the specified messages that the total size as close to the recommended size as possible.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="messageContainer">Accumulated messages or a null reference.</param>
        /// <param name="packedMessages">This instance will contain all packed messages after this function completes.</param>
        /// <param name="resultContent">The filled stream.</param>
        /// <param name="intermediateBuffer">The intermediate buffer.</param>
        /// <param name="recommendedSize">The recommended size.</param>
        public static void FillInLabelledStream(Message message, MessageContainer messageContainer, ArrayList packedMessages, GenuineChunkedStream resultContent, byte[] intermediateBuffer, int recommendedSize)
        {
            BinaryWriter binaryWriter = new BinaryWriter(resultContent);

            if (packedMessages != null)
                packedMessages.Clear();

            while ( message != null )
            {
                // not finished yet
                binaryWriter.Write((byte) 0);

                if (packedMessages != null)
                    packedMessages.Add(message);

                MessageCoder.WriteLabelledStream(message.SerializedContent, resultContent, binaryWriter, intermediateBuffer);
                message = null;

                if (resultContent.Length > recommendedSize)
                    break;

                if (messageContainer != null)
                    message = messageContainer.GetMessage();

                if (message == null)
                    break;
            }

            // "finish" flag
            binaryWriter.Write((byte) 1);
        }
        /// <summary>
        /// Processes the sender's request.
        /// </summary>
        /// <param name="genuineConnectionType">The type of the connection.</param>
        /// <param name="input">The incoming data.</param>
        /// <param name="httpServerRequestResult">The request.</param>
        /// <param name="httpServerConnection">The connection.</param>
        /// <param name="sequenceNo">The sequence number.</param>
        /// <param name="remote">The information about remote host.</param>
        public void LowLevel_ProcessSenderRequest(GenuineConnectionType genuineConnectionType, Stream input, HttpServerRequestResult httpServerRequestResult, HttpServerConnection httpServerConnection, int sequenceNo, HostInformation remote)
        {
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;
            GenuineChunkedStream outputStream = null;

            // parse the incoming stream
            bool directExecution = genuineConnectionType != GenuineConnectionType.Persistent;
            BinaryReader binaryReader = new BinaryReader(input);

            using (BufferKeeper bufferKeeper = new BufferKeeper(0))
            {
                switch(genuineConnectionType)
                {
                    case GenuineConnectionType.Persistent:
                        Exception gotException = null;

                        try
                        {
                            if (httpServerConnection.Sender_SecuritySession != null)
                            {
                                input = httpServerConnection.Sender_SecuritySession.Decrypt(input);
                                binaryReader = new BinaryReader(input);
                            }

                            while (binaryReader.ReadByte() == 0)
                                using(LabelledStream labelledStream = new LabelledStream(this.ITransportContext, input, bufferKeeper.Buffer))
                                {
                                    GenuineChunkedStream receivedContent = new GenuineChunkedStream(true);
                                    GenuineUtility.CopyStreamToStream(labelledStream, receivedContent);
                                    this.ITransportContext.IIncomingStreamHandler.HandleMessage(receivedContent, httpServerConnection.Remote, genuineConnectionType, httpServerConnection.ConnectionName, httpServerConnection.DbgConnectionId, false, this._iMessageRegistrator, httpServerConnection.Sender_SecuritySession, httpServerRequestResult);
                                }
                        }
                        catch(Exception ex)
                        {
                            gotException = ex;

                            // LOG:
                            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                            {
                                binaryLogWriter.WriteEvent(LogCategory.Connection, "HttpServerConnectionManager.LowLevel_ProcessSenderRequest",
                                    LogMessageType.Error, ex, null, httpServerConnection.Remote, null,
                                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null,
                                    httpServerConnection.DbgConnectionId, 0, 0, 0, null, null, null, null,
                                    "Error occurred while processing the sender request N: {0}.", httpServerConnection.Sender_SequenceNo);
                            }
                        }

                        if (gotException != null)
                        {
                            gotException = OperationException.WrapException(gotException);
                            outputStream = this.LowLevel_CreateStreamWithHeader(HttpPacketType.SenderError, sequenceNo, remote);
                            BinaryFormatter binaryFormatter = new BinaryFormatter(new RemotingSurrogateSelector(), new StreamingContext(StreamingContextStates.Other));
                            binaryFormatter.Serialize(outputStream, gotException);
                        }
                        else
                        {
                            // serialize and send the empty response
                            outputStream = this.LowLevel_CreateStreamWithHeader(HttpPacketType.SenderResponse, sequenceNo, remote);
                            MessageCoder.FillInLabelledStream(null, null, null, outputStream,
                                bufferKeeper.Buffer, (int) this.ITransportContext.IParameterProvider[GenuineParameter.HttpRecommendedPacketSize]);
                        }
                        break;

                    case GenuineConnectionType.Invocation:
                        // register the http context as an invocation waiters
                        string connectionGuid = Guid.NewGuid().ToString("N");

                        try
                        {
                            if (binaryReader.ReadByte() != 0)
                            {
                                // LOG:
                                if ( binaryLogWriter != null )
                                {
                                    binaryLogWriter.WriteImplementationWarningEvent("HttpServerConnectionManager.LowLevel_ProcessSenderRequest", LogMessageType.Error,
                                        GenuineExceptions.Get_Debugging_GeneralWarning("The invocation request doesn't contain any messages."),
                                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                        "The invocation request doesn't contain any messages.");
                                }
                            }

                            using(LabelledStream labelledStream = new LabelledStream(this.ITransportContext, input, bufferKeeper.Buffer))
                            {
                                // process the response
                                this._invocation[connectionGuid] = null;
                                this.ITransportContext.IIncomingStreamHandler.HandleMessage(labelledStream, remote, genuineConnectionType, connectionGuid, -1, true, null, null, httpServerRequestResult);
                            }

                            if (binaryReader.ReadByte() != 1)
                            {
                                // LOG:
                                if ( binaryLogWriter != null )
                                {
                                    binaryLogWriter.WriteImplementationWarningEvent("HttpServerConnectionManager.LowLevel_ProcessSenderRequest", LogMessageType.Error,
                                        GenuineExceptions.Get_Debugging_GeneralWarning("The invocation request must not contain more than one message."),
                                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                                        "The invocation request must not contain more than one message.");
                                }
                            }

                            // if there is a response, serialize it
                            outputStream = this.LowLevel_CreateStreamWithHeader(HttpPacketType.Usual, sequenceNo, remote);
                            Message message = this._invocation[connectionGuid] as Message;
                            MessageCoder.FillInLabelledStream(message, null, null, outputStream,
                                bufferKeeper.Buffer, (int) this.ITransportContext.IParameterProvider[GenuineParameter.HttpRecommendedPacketSize]);
                        }
                        finally
                        {
                            this._invocation.Remove(connectionGuid);
                        }
                        break;
                }
            }

            // report back to the client
            Stream finalStream = outputStream;
            this.LowLevel_SendStream(httpServerRequestResult.HttpContext, false, null, true, ref finalStream, httpServerConnection);
        }
 /// <summary>
 /// Creates and returns the stream with a written response header.
 /// </summary>
 /// <param name="httpPacketType">The type of the packet.</param>
 /// <param name="sequenceNo">The sequence number.</param>
 /// <param name="remote">The HostInformation of the remote host.</param>
 /// <returns>The stream with a written response header.</returns>
 public GenuineChunkedStream LowLevel_CreateStreamWithHeader(HttpPacketType httpPacketType, int sequenceNo, HostInformation remote)
 {
     GenuineChunkedStream output = new GenuineChunkedStream(false);
     BinaryWriter binaryWriter = new BinaryWriter(output);
     HttpMessageCoder.WriteResponseHeader(binaryWriter, remote.ProtocolVersion, this.ITransportContext.ConnectionManager.Local.Uri, sequenceNo, httpPacketType, remote.LocalHostUniqueIdentifier);
     return output;
 }
        /// <summary>
        /// Handles the incoming HTTP request.
        /// </summary>
        /// <param name="httpServerRequestResultAsObject">The HTTP request.</param>
        public void HandleIncomingRequest(object httpServerRequestResultAsObject)
        {
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            HttpServerRequestResult httpServerRequestResult = (HttpServerRequestResult) httpServerRequestResultAsObject;
            HttpServerConnection httpServerConnection = null;
            bool postponeResponse = false;

            try
            {
                // get the stream
                HttpRequest httpRequest = httpServerRequestResult.HttpContext.Request;
                Stream incomingStream = httpRequest.InputStream;

                if (incomingStream.Length <= 0)
                {
                    // LOG:
                    if ( binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0 )
                    {
                        binaryLogWriter.WriteEvent(LogCategory.Connection, "HttpServerConnectionManager.HandleIncomingRequest",
                            LogMessageType.LowLevelTransport_AsyncReceivingCompleted, null, null, null, null,
                            GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null,
                            -1, 0, 0, 0, null, null, null, null,
                            "Empty content has been received. It will be ignored.");
                    }

                    return ;
                }

                // LOG:
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0 )
                {
                    bool writeContent = binaryLogWriter[LogCategory.LowLevelTransport] > 1;
                    GenuineChunkedStream content = null;
                    if (writeContent)
                    {
                        content = new GenuineChunkedStream(false);
                        GenuineUtility.CopyStreamToStream(incomingStream, content);
                    }

                    binaryLogWriter.WriteTransportContentEvent(LogCategory.LowLevelTransport, "HttpServerConnectionManager.HandleIncomingRequest",
                        LogMessageType.LowLevelTransport_AsyncReceivingCompleted, null, null, null,
                        writeContent ? content : null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, -1, (int) httpServerRequestResult.HttpContext.Request.ContentLength,
                        httpServerRequestResult.HttpContext.Request.UserHostAddress,
                        null, null,
                        "HTTP request has been received.");

                    if (writeContent)
                        incomingStream = content;
                }

                BinaryReader binaryReader = new BinaryReader(incomingStream);

                // read the header
                byte protocolVersion;
                GenuineConnectionType genuineConnectionType;
                Guid hostId;
                HttpPacketType httpPacketType;
                int sequenceNo;
                string connectionName;
                int remoteHostUniqueIdentifier;
                HttpMessageCoder.ReadRequestHeader(binaryReader, out protocolVersion, out genuineConnectionType, out hostId, out httpPacketType, out sequenceNo, out connectionName, out remoteHostUniqueIdentifier);

                HostInformation remote = this.ITransportContext.KnownHosts["_ghttp://" + hostId.ToString("N")];
                remote.ProtocolVersion = protocolVersion;
            //				remote.Renew(this._hostRenewingSpan, false);
                remote.PhysicalAddress = httpRequest.UserHostAddress;

                // raise an event if we were not recognized
                remote.UpdateUri(remote.Uri, remoteHostUniqueIdentifier);

                // LOG:
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                {
                    binaryLogWriter.WriteEvent(LogCategory.Connection, "HttpServerConnectionManager.HandleIncomingRequest",
                        LogMessageType.ReceivingFinished, null, null, remote, null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, -1,
                        0, 0, 0, null, null, null, null,
                        "HTTP request is being processed. Packet type: {0}. Sequence no: {1}. Content length: {2}. Host address: {3}.",
                        Enum.Format(typeof(HttpPacketType), httpPacketType, "g"), sequenceNo, httpRequest.ContentLength, httpRequest.UserHostAddress);
                }

                // prepare the output stream
                GenuineChunkedStream outputStream = new GenuineChunkedStream(false);
                BinaryWriter binaryWriter = new BinaryWriter(outputStream);
                HttpMessageCoder.WriteResponseHeader(binaryWriter, protocolVersion, this.ITransportContext.ConnectionManager.Local.Uri, sequenceNo, httpPacketType, remote.LocalHostUniqueIdentifier);

                // analyze the received packet
                switch(genuineConnectionType)
                {
                    case GenuineConnectionType.Persistent:
                    {
                        // get the server connection
                        lock (remote.PersistentConnectionEstablishingLock)
                        {
                            httpServerConnection = this._persistent.Get(remote.Uri, connectionName) as HttpServerConnection;
                            if (httpServerConnection != null && httpServerConnection._disposed)
                                httpServerConnection = null;

                            // initialize CLSS from the very beginning, if necessary
                            if (httpPacketType == HttpPacketType.Establishing_ResetConnection)
                            {
                                if (httpServerConnection != null)
                                    httpServerConnection.Dispose(GenuineExceptions.Get_Receive_ConnectionClosed("Client sends Establishing_ResetCLSS flag."));
                                httpServerConnection = null;
                            }

                            if (httpServerConnection == null)
                            {
                                // create the new connection
                                httpServerConnection = new HttpServerConnection(this.ITransportContext, hostId, remote, connectionName,
                                    GenuineUtility.ConvertToMilliseconds(this.ITransportContext.IParameterProvider[GenuineParameter.ClosePersistentConnectionAfterInactivity]) + GenuineUtility.ConvertToMilliseconds(this.ITransportContext.IParameterProvider[GenuineParameter.MaxTimeSpanToReconnect]));

                                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                                {
                                    binaryLogWriter.WriteConnectionParameterEvent(LogCategory.Connection, "HttpServerConnectionManager.HandleIncomingRequest",
                                        LogMessageType.ConnectionParameters, null, remote, this.ITransportContext.IParameterProvider,
                                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, httpServerConnection.DbgConnectionId,
                                        "HTTP connection is being established.");
                                }

                                this._persistent.Set(remote.Uri, connectionName, httpServerConnection);

                                // and CLSS
                                string securitySessionName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForPersistentConnections] as string;
                                if (securitySessionName != null)
                                {
                                    httpServerConnection.Sender_SecuritySession = this.ITransportContext.IKeyStore.GetKey(securitySessionName).CreateSecuritySession(securitySessionName, null);
                                    httpServerConnection.Listener_SecuritySession = this.ITransportContext.IKeyStore.GetKey(securitySessionName).CreateSecuritySession(securitySessionName, null);
                                }

                                // LOG:
                                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                                {
                                    binaryLogWriter.WriteEvent(LogCategory.Connection, "HttpServerConnectionManager.HandleIncomingRequest",
                                        LogMessageType.ConnectionEstablished, null, null, remote, null,
                                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, httpServerConnection.Sender_SecuritySession, securitySessionName,
                                        httpServerConnection.DbgConnectionId, (int) GenuineConnectionType.Persistent, 0, 0, this.GetType().Name, null, null, null,
                                        "The connection is being established.");
                                }

                                // LOG:
                                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.HostInformation] > 0 )
                                {
                                    binaryLogWriter.WriteHostInformationEvent("HttpServerConnectionManager.HandleIncomingRequest",
                                        LogMessageType.HostInformationCreated, null, remote,
                                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, httpServerConnection.Sender_SecuritySession,
                                        securitySessionName, httpServerConnection.DbgConnectionId,
                                        "HostInformation is ready for actions.");
                                }

                                this.ITransportContext.IGenuineEventProvider.Fire(new GenuineEventArgs(GenuineEventType.GHttpConnectionAccepted, null, remote, httpRequest.UserHostAddress));
                            }
                        }

                        httpServerConnection.Renew();
                        httpServerConnection.SignalState(GenuineEventType.GeneralConnectionEstablished, null, null);

                        switch(httpPacketType)
                        {
                            case HttpPacketType.Establishing_ResetConnection:
                            case HttpPacketType.Establishing:
                                Stream clsseStream = Stream.Null;

                                // establish the CLSS
                                // P/Sender
                                int length = binaryReader.ReadInt32();
                                if (httpServerConnection.Sender_SecuritySession != null)
                                {
                                    using (Stream senderClssReading = new DelimiterStream(incomingStream, length))
                                    {
                                        clsseStream = httpServerConnection.Sender_SecuritySession.EstablishSession(
                                            senderClssReading, true);
                                    }
                                }

                                if (clsseStream == null)
                                    clsseStream = Stream.Null;

                                using (new GenuineChunkedStreamSizeLabel(outputStream))
                                    GenuineUtility.CopyStreamToStream(clsseStream, outputStream);

                                // P/Listener
                                length = binaryReader.ReadInt32();
                                clsseStream = Stream.Null;
                                if (httpServerConnection.Listener_SecuritySession != null)
                                    clsseStream = httpServerConnection.Listener_SecuritySession.EstablishSession(
                                        new DelimiterStream(incomingStream, length), true);

                                if (clsseStream == null)
                                    clsseStream = Stream.Null;

                                using (new GenuineChunkedStreamSizeLabel(outputStream))
                                    GenuineUtility.CopyStreamToStream(clsseStream, outputStream);

                                // write the answer
                                Stream finalStream = outputStream;
                                this.LowLevel_SendStream(httpServerRequestResult.HttpContext, false, null, false, ref finalStream, httpServerConnection);
                                break;

                            case HttpPacketType.Listening:
                                postponeResponse = this.LowLevel_ProcessListenerRequest(httpServerRequestResult, httpServerConnection, sequenceNo);
                                break;

                            case HttpPacketType.Usual:
                                this.LowLevel_ProcessSenderRequest(genuineConnectionType, incomingStream, httpServerRequestResult, httpServerConnection, sequenceNo, remote);
                                break;

                            default:
                                // LOG:
                                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                                {
                                    binaryLogWriter.WriteEvent(LogCategory.Connection, "HttpServerConnectionManager.HandleIncomingRequest",
                                        LogMessageType.Error, GenuineExceptions.Get_Debugging_GeneralWarning("Unexpected type of the packet."), null, remote, null,
                                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, httpServerConnection == null ? -1 : httpServerConnection.DbgConnectionId,
                                        0, 0, 0, null, null, null, null,
                                        "Unexpected type of the packet. Packet type: {0}. Sequence no: {1}. Content length: {2}. Host address: {3}.",
                                        Enum.Format(typeof(HttpPacketType), httpPacketType, "g"), sequenceNo, httpRequest.ContentLength, httpRequest.UserHostAddress);
                                }
                                break;
                        }
                    }
                        break;

                    case GenuineConnectionType.Named:
                        throw new NotSupportedException("Named connections are not supported.");

                    case GenuineConnectionType.Invocation:
                        // renew the host
                        remote.Renew(this._closeInvocationConnectionAfterInactivity, false);

                        this.LowLevel_ProcessSenderRequest(genuineConnectionType, incomingStream, httpServerRequestResult, null, sequenceNo, remote);
                        break;
                }
            }
            catch(Exception ex)
            {
                // LOG:
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                {
                    binaryLogWriter.WriteEvent(LogCategory.Connection, "HttpServerConnectionManager.HandleIncomingRequest",
                        LogMessageType.ReceivingFinished, ex, null, null, null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, -1,
                        0, 0, 0, null, null, null, null,
                        "Error occurred while processing incoming HTTP request.");
                }
            }
            finally
            {
                if (! postponeResponse)
                    httpServerRequestResult.Complete(true);
            }
        }
Пример #19
0
 /// <summary>
 /// Constructs an instance of the GenuineChunkedStreamSizeLabel class.
 /// </summary>
 /// <param name="outputStream"></param>
 public GenuineChunkedStreamSizeLabel(GenuineChunkedStream outputStream)
 {
     this._outputStream = outputStream;
     this._outputStream.WriteInt32AndRememberItsLocation(0, out this._chunk, out this._position);
     this._initialLength = this._outputStream.Length;
 }
Пример #20
0
        /// <summary>
        /// Copies the input stream to the output stream with intermediate size labels.
        /// </summary>
        /// <param name="inputStream">The source stream.</param>
        /// <param name="outputStream">The destination stream.</param>
        /// <param name="writer">The writer created on destination stream.</param>
        /// <param name="intermediateBuffer">The intermediate buffer.</param>
        public static void WriteLabelledStream(Stream inputStream, GenuineChunkedStream outputStream, BinaryWriter writer, byte[] intermediateBuffer)
        {
            if (inputStream.CanSeek)
            {
                writer.Write((byte) MessageCoder.COMMAND_MAGIC_CODE);
                writer.Write((int) inputStream.Length);
                writer.Write((byte) 1);
                outputStream.WriteStream(inputStream);
                return ;
            }

            for ( ; ; )
            {
                int bytesRead = inputStream.Read(intermediateBuffer, 0, intermediateBuffer.Length);
                writer.Write((byte) MessageCoder.COMMAND_MAGIC_CODE);
                writer.Write((int) bytesRead);
                writer.Write((byte) (bytesRead < intermediateBuffer.Length? 1 : 0));
                writer.BaseStream.Write(intermediateBuffer, 0, bytesRead);

                if (bytesRead < intermediateBuffer.Length)
                    return ;
            }
        }
 /// <summary>
 /// Encrypts the message data and put a result into the specified output stream.
 /// </summary>
 /// <param name="input">The stream containing the serialized message.</param>
 /// <param name="output">The result stream with the data being sent to the remote host.</param>
 public override void Encrypt(Stream input, GenuineChunkedStream output)
 {
     output.WriteByte(1);
     lock (this._encryptor)
         GenuineUtility.CopyStreamToStream(new CryptoStream(new FinishReadingStream(input), this._encryptor, CryptoStreamMode.Read), output);
 }
        /// <summary>
        /// Starts sending the message through the specified connection.
        /// </summary>
        /// <param name="message">The message being sent.</param>
        /// <param name="tcpSocketInfo">The connection.</param>
        private void LowLevel_StartSending(Message message, TcpSocketInfo tcpSocketInfo)
        {
            // PING: prevent the ping
            if (tcpSocketInfo.GenuineConnectionType == GenuineConnectionType.Persistent)
                tcpSocketInfo.LastTimeContentWasSent = GenuineUtility.TickCount;

            if (tcpSocketInfo.AsyncSendStream == null)
            {
                tcpSocketInfo.AsyncSendStream = message.SerializedContent;
                if (tcpSocketInfo.ConnectionLevelSecurity != null && message.SerializedContent != Stream.Null)
                {
                    GenuineChunkedStream encryptedContentStream = new GenuineChunkedStream(true);
                    tcpSocketInfo.ConnectionLevelSecurity.Encrypt(tcpSocketInfo.AsyncSendStream, encryptedContentStream);
                    tcpSocketInfo.AsyncSendStream = encryptedContentStream;
                }
            }

            // initiate the sending
            tcpSocketInfo.Message = message;
            if (tcpSocketInfo.AsyncSendBuffer == null)
                tcpSocketInfo.AsyncSendBuffer = new byte[tcpSocketInfo.MaxSendSize];
            tcpSocketInfo.AsyncSendBufferCurrentPosition = 0;
            tcpSocketInfo.AsyncSendBufferSizeOfValidContent = HEADER_SIZE + GenuineUtility.TryToReadFromStream(tcpSocketInfo.AsyncSendStream, tcpSocketInfo.AsyncSendBuffer, HEADER_SIZE, tcpSocketInfo.AsyncSendBuffer.Length - HEADER_SIZE);
            tcpSocketInfo.AsyncSendBuffer[0] = MessageCoder.COMMAND_MAGIC_CODE;
            MessageCoder.WriteInt32(tcpSocketInfo.AsyncSendBuffer, 1, tcpSocketInfo.AsyncSendBufferSizeOfValidContent - HEADER_SIZE);
            tcpSocketInfo.AsyncSendBufferIsLastPacket = tcpSocketInfo.AsyncSendBufferSizeOfValidContent < tcpSocketInfo.AsyncSendBuffer.Length - HEADER_SIZE;
            tcpSocketInfo.AsyncSendBuffer[5] = tcpSocketInfo.AsyncSendBufferIsLastPacket ? (byte) 1 : (byte) 0;

            // LOG:
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;
            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Transport] > 0 )
            {
                binaryLogWriter.WriteTransportContentEvent(LogCategory.Transport, "TcpConnectionManager.LowLevel_StartSending",
                    LogMessageType.AsynchronousSendingStarted, null, tcpSocketInfo.Message, tcpSocketInfo.Remote,
                    binaryLogWriter[LogCategory.Transport] > 1 ? new MemoryStream(GenuineUtility.CutOutBuffer(tcpSocketInfo.AsyncSendBuffer, tcpSocketInfo.AsyncSendBufferCurrentPosition, tcpSocketInfo.AsyncSendBufferSizeOfValidContent - tcpSocketInfo.AsyncSendBufferCurrentPosition)) : null,
                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                    tcpSocketInfo.DbgConnectionId, tcpSocketInfo.AsyncSendBufferSizeOfValidContent - tcpSocketInfo.AsyncSendBufferCurrentPosition, tcpSocketInfo.Remote.PhysicalAddress.ToString(), null, null,
                    "The chunk is being sent asynchronously.");
            }

            AsyncThreadStarter.QueueTask(new Async_InitiateSocketSending(tcpSocketInfo.Socket, tcpSocketInfo.AsyncSendBuffer, tcpSocketInfo.AsyncSendBufferCurrentPosition, tcpSocketInfo.AsyncSendBufferSizeOfValidContent - tcpSocketInfo.AsyncSendBufferCurrentPosition, this._onEndSending, tcpSocketInfo));
            //			tcpSocketInfo.Socket.BeginSend(tcpSocketInfo.AsyncSendBuffer, tcpSocketInfo.AsyncSendBufferCurrentPosition, tcpSocketInfo.AsyncSendBufferSizeOfValidContent - tcpSocketInfo.AsyncSendBufferCurrentPosition, SocketFlags.None, this._onEndSending, tcpSocketInfo);
        }
        /// <summary>
        /// Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>A new object that is a copy of this instance.</returns>
        public object Clone()
        {
            if (this._disposed)
                throw new ObjectDisposedException("GenuineChunkedStream");
            if (this._releaseOnReadMode)
                throw new InvalidOperationException();

            GenuineChunkedStream copy = new GenuineChunkedStream(false);
            copy._chunksAndStreams = this._chunksAndStreams;
            copy._currentWriteBlock = this._currentWriteBlock;
            copy._length = this._length;
            copy._writePosition = this._writePosition;

            // prevents buffers from being returned to Buffer Pool
            this._cloned = true;
            copy._cloned = true;

            return copy;
        }
        /// <summary>
        /// Continues receiving and processing of the message in half-sync mode.
        /// </summary>
        /// <param name="tcpSocketInfoAsObject">The connection.</param>
        private void Pool_ContinueHalfSyncReceiving(object tcpSocketInfoAsObject)
        {
            TcpSocketInfo tcpSocketInfo = null;
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            try
            {
                tcpSocketInfo = (TcpSocketInfo) tcpSocketInfoAsObject;

                bool automaticallyContinueReceiving = (tcpSocketInfo.ConnectionLevelSecurity == null);

                // create the stream
                SyncSocketReadingStream stream = new SyncSocketReadingStream(this, tcpSocketInfo, GenuineUtility.GetTimeout(tcpSocketInfo.CloseConnectionAfterInactivity), automaticallyContinueReceiving);

                tcpSocketInfo.Renew();

                if (stream.IsMessageProcessed)
                {
                    // it's a ping

                    // LOG:
                    if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                        binaryLogWriter.WriteEvent(LogCategory.Connection, "TcpConnectionManager.Pool_ContinueHalfSyncReceiving",
                            LogMessageType.ConnectionPingReceived, null, null, tcpSocketInfo == null ? null : tcpSocketInfo.Remote, null,
                            GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                            null, null, tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null,
                            "The ping message has been received. Stream number: {0}.", stream.DbgStreamId);

                    if (!automaticallyContinueReceiving)
                        this.LowLevel_HalfSync_StartReceiving(tcpSocketInfo);

                    return ;
                }

                // provide an option to read the entire message first
                Stream resultStream = null;
                bool contentLoggingRequired = binaryLogWriter != null && binaryLogWriter[LogCategory.Transport] > 1;
                if (this._tcpReadRequestBeforeProcessing || contentLoggingRequired)
                {
                    resultStream = new GenuineChunkedStream(contentLoggingRequired ? false : true);
                    GenuineUtility.CopyStreamToStream(stream, resultStream);
                }
                else
                    resultStream = stream;

                // LOG:
                if (binaryLogWriter != null && binaryLogWriter[LogCategory.Transport] > 0)
                    binaryLogWriter.WriteTransportContentEvent(LogCategory.Transport, "TcpConnectionManager.Pool_ContinueHalfSyncReceiving",
                        LogMessageType.ReceivingFinished, null, null, tcpSocketInfo.Remote,
                        contentLoggingRequired ? resultStream : null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                        tcpSocketInfo.DbgConnectionId, binaryLogWriter[LogCategory.Transport] > 1 ? (int)resultStream.Length : 0, tcpSocketInfo.Remote.PhysicalAddress.ToString(),
                        null, null,
                        "Content has been received. Stream number: {0}.", stream.DbgStreamId);

                if (tcpSocketInfo.ConnectionLevelSecurity != null)
                    resultStream = tcpSocketInfo.ConnectionLevelSecurity.Decrypt(resultStream);

                if (!automaticallyContinueReceiving)
                    this.LowLevel_HalfSync_StartReceiving(tcpSocketInfo);

                // provide it to the handler
                this.ITransportContext.IIncomingStreamHandler.HandleMessage(resultStream, tcpSocketInfo.Remote, tcpSocketInfo.GenuineConnectionType, tcpSocketInfo.ConnectionName, tcpSocketInfo.DbgConnectionId, true, tcpSocketInfo._iMessageRegistrator, tcpSocketInfo.ConnectionLevelSecurity, null);

                tcpSocketInfo.Renew();
            }
            catch(Exception ex)
            {
                this.SocketFailed(ex, tcpSocketInfo);
            }
        }
        /// <summary>
        /// Opens a connection to the host specified by the url.
        /// </summary>
        /// <param name="remote">The HostInformation of the Remote Host.</param>
        /// <param name="localUri">The uri of the local host.</param>
        /// <param name="remoteUri">The uri of the remote host.</param>
        /// <param name="remoteHostUniqueIdentifier">The unique identifier of the HostInformation used by the remote host.</param>
        /// <returns>The established connection.</returns>
        private SharedMemoryConnection LowLevel_OpenConnection(HostInformation remote, string localUri, out string remoteUri, out int remoteHostUniqueIdentifier)
        {
            using (new ReaderAutoLocker(this._disposeLock))
            {
                if (this._disposed)
                    throw OperationException.WrapException(this._disposeReason);
            }

            remoteUri = null;
            Stream inputStream = null;
            Stream outputStream = null;
            string url = remote.Url;

            // the maximum time during which the connection must be established
            int timeout = GenuineUtility.GetTimeout((TimeSpan) this.ITransportContext.IParameterProvider[GenuineParameter.ConnectTimeout]);

            IParameterProvider parameters = this.ITransportContext.IParameterProvider;

            string mutexName = GenuineSharedMemoryChannel.ConstructSharedObjectName(
                "MUTEX" + url, parameters);
            string clientConnected = GenuineSharedMemoryChannel.ConstructSharedObjectName(
                "CC" + url, parameters);
            string clientAccepted = GenuineSharedMemoryChannel.ConstructSharedObjectName(
                "CA" + url, parameters);

            // open the server share
            SharedMemoryConnection serverSharedMemoryConnection = new SharedMemoryConnection(this.ITransportContext, url, false, false);

            // LOG:
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;
            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
            {
                binaryLogWriter.WriteConnectionParameterEvent(LogCategory.Connection, "SharedMemoryConnectionManager.LowLevel_OpenConnection",
                    LogMessageType.ConnectionParameters, null, remote, this.ITransportContext.IParameterProvider,
                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, serverSharedMemoryConnection.DbgConnectionId,
                    "A Shared Memory connection is being established.");
            }

            // and create the local share
            string shareName = "gshmem://" + Guid.NewGuid().ToString("N");
            SharedMemoryConnection sharedMemoryConnection = new SharedMemoryConnection(this.ITransportContext, shareName, true, true);

            BinaryWriter connectionInformation = MessageCoder.SerializeConnectionHeader(MessageCoder.PROTOCOL_VERSION, GenuineConnectionType.Persistent, "Default");
            connectionInformation.Write(shareName);

            // let the server know that a client's share is ready
            Mutex mutex = null;
            try
            {
                mutex = WindowsAPI.OpenMutex(mutexName);

                NamedEvent _clientConnected = NamedEvent.OpenNamedEvent(clientConnected);
                NamedEvent _clientAccepted = NamedEvent.OpenNamedEvent(clientAccepted);

                if (! GenuineUtility.WaitOne(mutex, GenuineUtility.GetMillisecondsLeft(timeout)) )
                    throw GenuineExceptions.Get_Connect_CanNotConnectToRemoteHost(url, "Can not acquire the lock for the global mutex.");

                // wait until server accepts this client
                _clientAccepted.ManualResetEvent.Reset();
                _clientConnected.ManualResetEvent.Set();

                // copy client's name
                serverSharedMemoryConnection.LowLevel_SendSync(connectionInformation.BaseStream, timeout);

                if (! GenuineUtility.WaitOne(_clientAccepted.ManualResetEvent, GenuineUtility.GetMillisecondsLeft(timeout)) )
                    throw GenuineExceptions.Get_Connect_CanNotConnectToRemoteHost(url, "Remote server did not accept a request within the specified time span.");
            }
            finally
            {
                if (mutex != null)
                {
                    try
                    {
                        mutex.ReleaseMutex();
                    }
                    catch
                    {
                    }

                    try
                    {
                        mutex.Close();
                    }
                    catch
                    {
                    }
                }
            }

            // get the connection-level Security Session
            string connectionLevelSSName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForPersistentConnections] as string;
            SecuritySession securitySession = null;
            if (connectionLevelSSName != null)
                securitySession = this.ITransportContext.IKeyStore.GetKey(connectionLevelSSName).CreateSecuritySession(connectionLevelSSName, null);

            // establish it
            if (securitySession != null && ! securitySession.IsEstablished)
            {
                bool firstPass = true;
                for ( ; ; )
                {
                    inputStream = Stream.Null;

                    try
                    {
                        // prepare streams
                        if (! firstPass)
                            inputStream = sharedMemoryConnection.LowLevel_ReadSync(timeout);
                        else
                            firstPass = false;

                        outputStream = securitySession.EstablishSession(inputStream, true);

                        if (outputStream == null)
                            break;

                        // send a packet to the remote host
                        sharedMemoryConnection.LowLevel_SendSync(outputStream, timeout);
                        if (securitySession.IsEstablished)
                            break;
                    }
                    finally
                    {
                        if (inputStream != null)
                            inputStream.Close();
                        if (outputStream != null)
                            outputStream.Close();
                    }
                }
            }

            sharedMemoryConnection.ConnectionLevelSecurity = securitySession;

            // now send connection info through the established connection
            using (GenuineChunkedStream serializedLocalInfo = new GenuineChunkedStream(false))
            {
                // serialize local info
                BinaryWriter binaryWriter = new BinaryWriter(serializedLocalInfo);
                binaryWriter.Write((string) localUri);
                binaryWriter.Write((int) remote.LocalHostUniqueIdentifier);

                // and send it
                sharedMemoryConnection.LowLevel_SendSync(serializedLocalInfo, timeout);

                // read remote info
                using (Stream remoteUriStream = sharedMemoryConnection.LowLevel_ReadSync(timeout))
                {
                    BinaryReader binaryReader = new BinaryReader(remoteUriStream);
                    remoteUri = binaryReader.ReadString();
                    remoteHostUniqueIdentifier = binaryReader.ReadInt32();
                }
            }

            sharedMemoryConnection.Remote = remote;
            sharedMemoryConnection.Remote.UpdateUri(remoteUri, remoteHostUniqueIdentifier);
            sharedMemoryConnection.Remote.GenuinePersistentConnectionState = GenuinePersistentConnectionState.Opened;

            // LOG:
            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.HostInformation] > 0 )
            {
                binaryLogWriter.WriteHostInformationEvent("SharedMemoryConnectionManager.LowLevel_OpenConnection",
                    LogMessageType.HostInformationCreated, null, remote,
                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null,
                    sharedMemoryConnection.DbgConnectionId,
                    "HostInformation is ready for actions.");
            }

            // LOG:
            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
            {
                binaryLogWriter.WriteEvent(LogCategory.Connection, "SharedMemoryConnectionManager.LowLevel_OpenConnection",
                    LogMessageType.ConnectionEstablished, null, null, remote, null,
                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                    securitySession, connectionLevelSSName,
                    sharedMemoryConnection.DbgConnectionId, (int) GenuineConnectionType.Persistent, 0, 0, this.GetType().Name, null, null, null,
                    "The connection to the remote host is established.");
            }

            return sharedMemoryConnection;
        }
        /// <summary>
        /// Sends a message synchronously. Does not process exceptions!
        /// </summary>
        /// <param name="message">Message.</param>
        /// <param name="tcpSocketInfo">Acquired connection.</param>
        public void LowLevel_SendSync(Message message, TcpSocketInfo tcpSocketInfo)
        {
            Stream stream = null;
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            // LOG:
            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Transport] > 0 )
                binaryLogWriter.WriteEvent(LogCategory.Transport, "TcpConnectionManager.LowLevel_SendSync",
                    LogMessageType.MessageIsSentSynchronously, null, message, message.Recipient, null,
                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                    tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity,
                    tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity.Name,
                    tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null,
                    "The connection has been obtained and the message is being sent synchronously.");

            try
            {
                // PING: prevent a ping
                if (tcpSocketInfo.GenuineConnectionType == GenuineConnectionType.Persistent)
                    tcpSocketInfo.LastTimeContentWasSent = GenuineUtility.TickCount;

                tcpSocketInfo.SetupWriting(message.FinishTime);

                // create a stream
                bool finished = false;

                // enable connection-level security encryption
                stream = message.SerializedContent;
                if (tcpSocketInfo.ConnectionLevelSecurity != null)
                {
                    GenuineChunkedStream encryptedContentStream = new GenuineChunkedStream(true);
                    tcpSocketInfo.ConnectionLevelSecurity.Encrypt(stream, encryptedContentStream);
                    stream = encryptedContentStream;
                }

                // send it in chunks
                while ( ! finished )
                {
                    int currentPosition = HEADER_SIZE;

                    // read data
                    int size = 0;
                    while ( tcpSocketInfo._sendBuffer.Length > currentPosition &&
                        (size = stream.Read(tcpSocketInfo._sendBuffer, currentPosition, tcpSocketInfo._sendBuffer.Length - currentPosition)) > 0)
                    {
                        if (size <= 0)
                            break;

                        currentPosition += size;
                    }

                    finished = currentPosition < tcpSocketInfo._sendBuffer.Length;
                    int totalSize = currentPosition;

                    // prepare header
                    tcpSocketInfo._sendBuffer[0] = MessageCoder.COMMAND_MAGIC_CODE;
                    MessageCoder.WriteInt32(tcpSocketInfo._sendBuffer, 1, totalSize - HEADER_SIZE);
                    tcpSocketInfo._sendBuffer[5] = finished ? (byte) 1 : (byte) 0;

                    // and send it
                    currentPosition = 0;
                    tcpSocketInfo.Write(tcpSocketInfo._sendBuffer, currentPosition, totalSize);
                    this.IncreaseBytesSent(totalSize);
                }

                // the message can be resent only if the persistent pattern is used
                if (tcpSocketInfo.GenuineConnectionType == GenuineConnectionType.Persistent  && ! (bool) this.ITransportContext.IParameterProvider[GenuineParameter.TcpDoNotResendMessages])
                    tcpSocketInfo.MessagesSentSynchronously.PutMessage(message);
            }
            catch(Exception ex)
            {
                // LOG:
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Transport] > 0 )
                    binaryLogWriter.WriteEvent(LogCategory.Transport, "TcpConnectionManager.LowLevel_SendSync",
                        LogMessageType.MessageIsSentSynchronously, ex, message, message.Recipient, null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                        tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity,
                        tcpSocketInfo.ConnectionLevelSecurity == null ? null : tcpSocketInfo.ConnectionLevelSecurity.Name,
                        tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null,
                        "The exception occurred while synchronous sending.");

                throw;
            }
            finally
            {
                lock (tcpSocketInfo)
                    tcpSocketInfo.LockForSending = false;
            }

            // the message was sent
            // PING: schedule a ping
            if (tcpSocketInfo.GenuineConnectionType == GenuineConnectionType.Persistent)
                tcpSocketInfo.LastTimeContentWasSent = GenuineUtility.TickCount;
        }
        /// <summary>
        /// Sends the message to the remote host.
        /// </summary>
        /// <param name="message">The message to be sent.</param>
        protected override void InternalSend(Message message)
        {
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            // get IP end point of the remote host
            IPEndPoint remoteEndPoint;

            if (message.Recipient.Uri != null && message.Recipient.Uri.StartsWith("_gb"))
                remoteEndPoint = this._multicastTo;
            else
                remoteEndPoint = message.Recipient.PhysicalAddress as IPEndPoint;
            if (remoteEndPoint == null)
            {
                try
                {
                    int port;
                    string baseUrl = GenuineUtility.SplitToHostAndPort(message.Recipient.Url, out port);
                    message.Recipient.PhysicalAddress = remoteEndPoint = new IPEndPoint(GenuineUtility.ResolveIPAddress(baseUrl), port);
                }
                catch(Exception)
                {
                    throw GenuineExceptions.Get_Send_DestinationIsUnreachable(message.Recipient.ToString());
                }
            }

            Stream streamToSend = message.SerializedContent;

            // write the host URI
            if ((int) this.ITransportContext.IParameterProvider[GenuineParameter.CompatibilityLevel] > 0)
            {
                GenuineChunkedStream streamWith250Header = new GenuineChunkedStream(false);
                BinaryWriter binaryWriter = new BinaryWriter(streamWith250Header);
                streamWith250Header.Write(this.ITransportContext.BinaryHostIdentifier, 0, this.ITransportContext.BinaryHostIdentifier.Length);
                binaryWriter.Write((int) message.Recipient.LocalHostUniqueIdentifier);
                binaryWriter.Write((Int16) 0);

                streamWith250Header.WriteStream(streamToSend);

                streamToSend = streamWith250Header;
            }

            // LOG:
            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
            {
                binaryLogWriter.WriteEvent(LogCategory.Connection, "UdpConnectionManager.InternalSend",
                    LogMessageType.MessageIsSentSynchronously, null, message, message.Recipient, null,
                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                    message.ConnectionLevelSecuritySession, message.ConnectionLevelSecuritySession == null ? null : message.ConnectionLevelSecuritySession.Name,
                    -1, 0, 0, 0, remoteEndPoint.ToString(), null, null, null,
                    "The message is being sent synchronously to {0}.", remoteEndPoint.ToString());
            }

            // send the message
            byte[] streamId = Guid.NewGuid().ToByteArray();

            lock (_socketLock)
            {
                for ( int chunkNumber = 1; ; chunkNumber++ )
                {
                    // read the next chunk
                    int chunkSize = streamToSend.Read(this._sendBuffer, HEADER_SIZE, this._sendBuffer.Length - HEADER_SIZE);

                    // fill in the header
                    this._sendBuffer[0] = MessageCoder.COMMAND_MAGIC_CODE;
                    Buffer.BlockCopy(streamId, 0, this._sendBuffer, 1, 16);
                    if (chunkSize < this._sendBuffer.Length - HEADER_SIZE)
                        chunkNumber = - chunkNumber;
                    MessageCoder.WriteInt32(this._sendBuffer, 17, chunkNumber);

                    // and just send it!

                    // LOG:
                    if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Transport] > 0 )
                    {
                        binaryLogWriter.WriteTransportContentEvent(LogCategory.Transport, "UdpConnectionManager.InternalSend",
                            LogMessageType.SynchronousSendingStarted, null, message, message.Recipient,
                            binaryLogWriter[LogCategory.Transport] > 1 ? new MemoryStream(GenuineUtility.CutOutBuffer(this._sendBuffer, 0, chunkSize + HEADER_SIZE)) : null,
                            GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                            this.DbgConnectionId, chunkSize + HEADER_SIZE, remoteEndPoint.ToString(),
                            null, null,
                            "Content is sent synchronously to {0}.", remoteEndPoint.ToString());
                    }

                    this._socket.SendTo(this._sendBuffer, 0, chunkSize + HEADER_SIZE, SocketFlags.None, remoteEndPoint);

                    if (chunkNumber < 0)
                        break;
                }
            }
        }
        /// <summary>
        /// Accepts an incoming TCP connection.
        /// </summary>
        /// <param name="socket">The socket.</param>
        /// <param name="localUri">URI of the local host.</param>
        /// <param name="remoteUri">Uri of the remote host.</param>
        /// <param name="remoteAddress">Address of the remote host.</param>
        /// <param name="connectionName">The name of the connection.</param>
        /// <param name="remoteHostUniqueIdentifier">The unique identifier of the HostInformation used by the remote host.</param>
        /// <param name="reasonOfStateLost">The reason why the remote host has lost its state (if it's happened).</param>
        /// <returns>An instance of the TcpSocketInfo class.</returns>
        internal TcpSocketInfo LowLevel_AcceptConnection(Socket socket, string localUri, out string remoteUri, out string remoteAddress, out string connectionName, out int remoteHostUniqueIdentifier, out Exception reasonOfStateLost)
        {
            using (new ReaderAutoLocker(this._disposeLock))
            {
                if (this._disposed)
                    throw OperationException.WrapException(this._disposeReason);
            }

            // set the remote end point and local end point
            using (new ThreadDataSlotKeeper(OccupiedThreadSlots.SocketDuringEstablishing, socket))
            {
                remoteUri = null;
                remoteAddress = null;
                remoteHostUniqueIdentifier = 0;

                Stream inputStream = null;
                Stream outputStream = null;

                // the time we should finish connection establishing before
                int timeout = GenuineUtility.GetTimeout( (TimeSpan) this.ITransportContext.IParameterProvider[GenuineParameter.ConnectTimeout]);

                // setup a socket
                LingerOption lingerOption = new LingerOption(true, 3);
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lingerOption);

                if ((bool) this.ITransportContext.IParameterProvider[GenuineParameter.TcpDisableNagling])
                    socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, 1);

                // create a connection
                TcpSocketInfo tcpSocketInfo = new TcpSocketInfo(socket, this.ITransportContext, null
            #if DEBUG
                    ,"Accepted connection"
            #endif
                    );

                // LOG:
                BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.AcceptingConnection] > 0 )
                    binaryLogWriter.WriteEvent(LogCategory.AcceptingConnection, "TcpConnectionManager.LowLevel_AcceptConnection",
                        LogMessageType.ConnectionAccepting, null, null, null, null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                        null, null, tcpSocketInfo.DbgConnectionId, 0, 0, 0, socket.RemoteEndPoint.ToString(), socket.LocalEndPoint.ToString(), null, null,
                        "An inbound connection is being accepted. Remote end point: {0}.", socket.RemoteEndPoint.ToString());

                // receive and analyze protocol version and the type of the connection
                GenuineConnectionType genuineConnectionType;
                byte protocolVersion;
                using (Stream readingStream = this.LowLevel_ReadSync(tcpSocketInfo, timeout, false))
                {
                    BinaryReader binaryReader = new BinaryReader(readingStream);
                    MessageCoder.DeserializeConnectionHeader(binaryReader, out protocolVersion, out genuineConnectionType, out connectionName);
                }

                // define the connection logic
                tcpSocketInfo.GenuineConnectionType = genuineConnectionType;
                tcpSocketInfo.ConnectionName = connectionName;

                // get connection-level SS
                string connectionLevelSSName = null;
                switch (tcpSocketInfo.GenuineConnectionType)
                {
                    case GenuineConnectionType.Persistent:
                        connectionLevelSSName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForPersistentConnections] as string;
                        break;

                    case GenuineConnectionType.Named:
                        connectionLevelSSName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForNamedConnections] as string;
                        break;

                    case GenuineConnectionType.Invocation:
                        connectionLevelSSName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForInvocationConnections] as string;
                        break;
                }

                SecuritySession securitySession = null;
                if (connectionLevelSSName != null)
                    securitySession = this.ITransportContext.IKeyStore.GetKey(connectionLevelSSName).CreateSecuritySession(connectionLevelSSName, null);

                // establish a SS
                if (securitySession != null && ! securitySession.IsEstablished)
                {
                    // LOG:
                    if ( binaryLogWriter != null && binaryLogWriter[LogCategory.AcceptingConnection] > 0 )
                        binaryLogWriter.WriteEvent(LogCategory.AcceptingConnection, "TcpConnectionManager.LowLevel_AcceptConnection",
                            LogMessageType.ConnectionSecurityIsEstablished, null, null, null, null,
                            GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                            securitySession, connectionLevelSSName, tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null,
                            "The Connection Level Security Session must be established prior to connection is accepted.");

                    for ( ; ; )
                    {
                        inputStream = null;

                        try
                        {
                            // prepare streams
                            inputStream = this.LowLevel_ReadSync(tcpSocketInfo, timeout, false);
                            outputStream = securitySession.EstablishSession(inputStream, true);

                            if (outputStream == null)
                                break;

                            // send a packet to the remote host
                            Message message = new Message(null, null, -1, new TransportHeaders(), Stream.Null);
                            message.FinishTime = timeout;
                            message.SerializedContent = outputStream;
                            LowLevel_SendSync(message, tcpSocketInfo);
                            tcpSocketInfo.MessagesSentSynchronously.ReleaseAllMessages();

                            if (securitySession.IsEstablished)
                                break;
                        }
                        finally
                        {
                            if (inputStream != null)
                                inputStream.Close();
                            if (outputStream != null)
                                outputStream.Close();
                        }
                    }
                }

                tcpSocketInfo.ConnectionLevelSecurity = securitySession;

                // exchange with connection info
                int remotePort = 0;

                // read remote info
                using (Stream headerStream = this.LowLevel_ReadSync(tcpSocketInfo, timeout, false))
                {
                    //				this.SkipPacketHeader(headerStream, connectionLevelSSName);
                    BinaryReader binaryReader = new BinaryReader(headerStream);

                    remoteUri = binaryReader.ReadString();
                    remotePort = binaryReader.ReadInt32();
                    tcpSocketInfo.GenuineConnectionType = (GenuineConnectionType) binaryReader.ReadByte();

                    if (protocolVersion >= 0x1)
                        remoteHostUniqueIdentifier = binaryReader.ReadInt32();
                }

                HostInformation remote = this.ITransportContext.KnownHosts[remoteUri];
                remote.ProtocolVersion = protocolVersion;

                // LOG:
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                {
                    binaryLogWriter.WriteConnectionParameterEvent(LogCategory.Connection, "TcpConnectionManager.LowLevel_AcceptConnection",
                        LogMessageType.ConnectionParameters, null, remote, this.ITransportContext.IParameterProvider,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.DbgConnectionId,
                        "The connection is accepted. Protocol version: \"{0}\".", protocolVersion);
                }

                reasonOfStateLost = remote.UpdateUri(remoteUri, remoteHostUniqueIdentifier, tcpSocketInfo.GenuineConnectionType == GenuineConnectionType.Persistent);

                using (GenuineChunkedStream serializedLocalInfo = new GenuineChunkedStream(false))
                {
                    // serialize local info
                    BinaryWriter binaryWriter = new BinaryWriter(serializedLocalInfo);
                    binaryWriter.Write((string) localUri);

                    if (protocolVersion >= 0x1)
                        binaryWriter.Write((int) remote.LocalHostUniqueIdentifier);

                    // and send it
                    Message message = new Message(null, null, -1, new TransportHeaders(), Stream.Null);
                    message.FinishTime = timeout;
                    message.SerializedContent = serializedLocalInfo;
                    LowLevel_SendSync(message, tcpSocketInfo);
                    tcpSocketInfo.MessagesSentSynchronously.ReleaseAllMessages();
                }

                // build network address of the remote host
                if (remotePort > 0)
                {
                    IPEndPoint remoteHostIpEndPoint = (IPEndPoint) socket.RemoteEndPoint;
                    remoteAddress = "gtcp://" + remoteHostIpEndPoint.Address.ToString() + ":" + remotePort;
                }

                tcpSocketInfo.IsServer = true;
                return tcpSocketInfo;
            }
        }
        /// <summary>
        /// Processes incoming requests and responses.
        /// </summary>
        /// <param name="stream">The stream containing a request or a response.</param>
        /// <param name="remote">The remote host.</param>
        /// <param name="genuineConnectionType">The type of the connection.</param>
        /// <param name="connectionName">Connection id to send a response through.</param>
        /// <param name="dbgConnectionId">The identifier of the connection, which is used for debugging purposes only.</param>
        /// <param name="useThisThread">True to invoke the target in the current thread.</param>
        /// <param name="iMessageRegistrator">The message registrator.</param>
        /// <param name="connectionLevelSecuritySession">Connection Level Security Session.</param>
        /// <param name="httpServerRequestResult">The HTTP request through which the message was received.</param>
        /// <returns>True if it's a one-way message.</returns>
        public bool HandleMessage(Stream stream, HostInformation remote, GenuineConnectionType genuineConnectionType, string connectionName, int dbgConnectionId, bool useThisThread, IMessageRegistrator iMessageRegistrator, SecuritySession connectionLevelSecuritySession, HttpServerRequestResult httpServerRequestResult)
        {
            // read the Security Session name
            BinaryReader binaryReader = new BinaryReader(stream);
            string sessionName = binaryReader.ReadString();
            Message message = null;
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            // and decode the packet
            SecuritySession securitySession = remote.GetSecuritySession(sessionName, this.ITransportContext.IKeyStore);
            if (securitySession == null)
            {
                // LOG:
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Security] > 0 )
                {
                    binaryLogWriter.WriteEvent(LogCategory.Security, "GenuineReceivingHandler.HandleMessage",
                        LogMessageType.SecuritySessionApplied, GenuineExceptions.Get_Security_ContextNotFound(sessionName),
                        message, remote,
                        null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                        securitySession, sessionName, dbgConnectionId,
                        0, 0, 0, null, null, null, null,
                        "The requested Security Session can not be constructed or established. The name of Security Session: {0}.",
                        sessionName);
                }

                this.ITransportContext.IGenuineEventProvider.Fire(new GenuineEventArgs(GenuineEventType.SecuritySessionWasNotFound, GenuineExceptions.Get_Security_ContextNotFound(sessionName),
                    remote, null));

                return true;
            }

            // decode the stream and roll back if it was a Security Session's message
            stream = securitySession.Decrypt(stream);
            if (stream == null)
                return true;

            // read the message
            message = MessageCoder.Deserialize(stream, sessionName);
            message.ConnectionName = connectionName;
            message.SecuritySessionParameters._connectionName = connectionName;
            message.SecuritySessionParameters._genuineConnectionType = genuineConnectionType;
            message.Sender = remote;
            message.ITransportContext = this.ITransportContext;
            message.ConnectionLevelSecuritySession = connectionLevelSecuritySession;
            message.HttpServerRequestResult = httpServerRequestResult;

            // LOG:
            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Security] > 0 )
            {
                binaryLogWriter.WriteEvent(LogCategory.Security, "GenuineReceivingHandler.HandleMessage",
                    LogMessageType.SecuritySessionApplied, null, message, remote,
                    null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                    securitySession, sessionName, dbgConnectionId,
                    0, 0, 0, null, null, null, null,
                    "The Security Session has been used for decrypting the message.");
            }

            // LOG:
            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.MessageProcessing] > 0 )
            {
                bool readContent = this.ITransportContext.BinaryLogWriter[LogCategory.MessageProcessing] > 1;
                if (readContent)
                {
                    GenuineChunkedStream streamClone = new GenuineChunkedStream();
                    GenuineUtility.CopyStreamToStream(message.Stream, streamClone);
                    message.Stream = streamClone;
                }

                binaryLogWriter.WriteMessageCreatedEvent("GenuineReceivingHandler.HandleMessage",
                    LogMessageType.MessageReceived, null, message, message.ReplyToId > 0, remote,
                    readContent ? message.Stream : null,
                    message.ITransportHeaders[Message.TransportHeadersInvocationTarget] as string, message.ITransportHeaders[Message.TransportHeadersMethodName] as string,
                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, connectionName, dbgConnectionId,
                    connectionLevelSecuritySession == null ? -1 : connectionLevelSecuritySession.SecuritySessionId,
                    connectionLevelSecuritySession == null ? null : connectionLevelSecuritySession.Name,
                    securitySession == null ? -1 : securitySession.SecuritySessionId,
                    securitySession.Name,
                    "The message has been received.");
            }

            if (message.ReplyToId == PING_MESSAGE_REPLYID)
                return true;

            if (iMessageRegistrator != null && iMessageRegistrator.WasRegistered(remote.Uri, message.MessageId, message.ReplyToId))
            {
                // LOG:
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.MessageProcessing] > 0 )
                    binaryLogWriter.WriteEvent(LogCategory.MessageProcessing, "GenuineReceivingHandler.HandleMessage",
                        LogMessageType.MessageDispatched, GenuineExceptions.Get_Debugging_GeneralWarning("The message has been already processed."), message, remote,
                        null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, securitySession, securitySession.Name,
                        dbgConnectionId,
                        GenuineUtility.TickCount, 0, message.SeqNo, null, null, null, null,
                        "The message has been already processed. Therefore, this message is ignored.");

                return true;
            }

            // if it's a response, then direct the message to the response handler
            if (message.ReplyToId > 0)
            {
                message.IsOneWay = true;
                IResponseProcessor iResponseProcessor = GenuineReceivingHandler._responseHandlers[message.ReplyToId] as IResponseProcessor;

                // nothing waits for this request
                if (iResponseProcessor == null)
                    return true;

                // 2.5.1: set the answer flag
                if (iResponseProcessor.Message != null)
                    iResponseProcessor.Message.HasBeenAsnwered = true;

                if (iResponseProcessor.IsShortInProcessing)
                {
                    iResponseProcessor.ProcessRespose(message);

            #if TRIAL
            #else
                    if (iResponseProcessor.IsExpired(GenuineUtility.TickCount))
                        GenuineReceivingHandler._responseHandlers.Remove(message.ReplyToId);
            #endif

                    return true;
                }
            }

            // take care about the thread and call context
            if (useThisThread)
                InternalExecuteMessage(message);
            else
                GenuineThreadPool.QueueUserWorkItem(this._waitCallback_InternalExecuteMessagewaitCallback, message, false);

            return message.IsOneWay;
        }
Пример #30
0
        /// <summary>
        /// Fills in the provided stream with the specified messages that the total size as close to the recommended size as possible.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="messageContainer">Accumulated messages or a null reference.</param>
        /// <param name="packedMessages">This instance will contain all packed messages after this function completes.</param>
        /// <param name="resultContent">The filled stream.</param>
        /// <param name="intermediateBuffer">The intermediate buffer.</param>
        /// <param name="recommendedSize">The recommended size.</param>
        public static void FillInLabelledStream(Message message, MessageContainer messageContainer, ArrayList packedMessages, GenuineChunkedStream resultContent, byte[] intermediateBuffer, int recommendedSize)
        {
            BinaryWriter binaryWriter = new BinaryWriter(resultContent);

            if (packedMessages != null)
            {
                packedMessages.Clear();
            }

            while (message != null)
            {
                // not finished yet
                binaryWriter.Write((byte)0);

                if (packedMessages != null)
                {
                    packedMessages.Add(message);
                }

                MessageCoder.WriteLabelledStream(message.SerializedContent, resultContent, binaryWriter, intermediateBuffer);
                message = null;

                if (resultContent.Length > recommendedSize)
                {
                    break;
                }

                if (messageContainer != null)
                {
                    message = messageContainer.GetMessage();
                }

                if (message == null)
                {
                    break;
                }
            }

            // "finish" flag
            binaryWriter.Write((byte)1);
        }
        /// <summary>
        /// Packs and returns a message that contains back response to the broadcast message.
        /// </summary>
        /// <param name="message">The source message.</param>
        /// <param name="returnMessage">IMethodReturnMessage response.</param>
        /// <param name="binaryFormatter">Just to prevent creating addition instance.</param>
        /// <returns>The reply message.</returns>
        private Message CreateResponseToBroadcastMessage(Message message, object returnMessage, BinaryFormatter binaryFormatter)
        {
            // serialize the reply
            GenuineChunkedStream stream = new GenuineChunkedStream(false);
            binaryFormatter.Serialize(stream, returnMessage);

            // and wrap it into the message
            return new Message(message, new TransportHeaders(), stream);
        }
        /// <summary>
        /// Initiates or continues establishing of the Security Session.
        /// </summary>
        /// <param name="input">A null reference or an incoming stream.</param>
        /// <param name="connectionLevel">Indicates whether the Security Session operates on connection level.</param>
        /// <returns>A stream containing data for sending to the remote host or a null reference if Security Session is established.</returns>
        public override GenuineChunkedStream EstablishSession(Stream input, bool connectionLevel)
        {
            BinaryLogWriter binaryLogWriter = GenuineLoggingServices.BinaryLogWriter;
            bool passException = false;

            // a dance is over
            if (this.IsEstablished)
                return null;

            GenuineChunkedStream outputStream = null;
            BinaryFormatter binaryFormatter = new BinaryFormatter();

            // skip the status flag
            if (connectionLevel)
            {
                if (input != null)
                    input.ReadByte();
                outputStream = new GenuineChunkedStream(false);
            }
            else
                outputStream = this.CreateOutputStream();

            // write session is being established flag
            BinaryWriter binaryWriter = new BinaryWriter(outputStream);
            binaryWriter.Write((byte) 0);

            try
            {
                lock(this)
                {
                    if (input == Stream.Null)
                    {
                        // start a new session
                        binaryWriter.Write((byte) ZpaPacketStatusFlag.ForceInitialization);
                        binaryFormatter.Serialize(outputStream, this.KeyProvider_ZpaClient.Login);
                        return outputStream;
                    }

                    ZpaPacketStatusFlag zpaPacketStatusFlag = (ZpaPacketStatusFlag) input.ReadByte();

                    // LOG:
                    if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Security] > 0 )
                    {
                        binaryLogWriter.WriteEvent(LogCategory.Security, "SecuritySession_ZpaClient.EstablishSession",
                            LogMessageType.SecuritySessionEstablishing, null, null, this.Remote, null,
                            GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name,
                            this, this.Name, -1,
                            0, 0, 0, Enum.Format(typeof(ZpaPacketStatusFlag), zpaPacketStatusFlag, "g"), null, null, null,
                            "ZPA Client Session is being established. Status: {0}.", Enum.Format(typeof(ZpaPacketStatusFlag), zpaPacketStatusFlag, "g"));
                    }

                    switch (zpaPacketStatusFlag)
                    {
                        case ZpaPacketStatusFlag.ExceptionThrown:
                            Exception receivedException = GenuineUtility.ReadException(input);

            #if DEBUG
            //							this.Remote.ITransportContext.IEventLogger.Log(LogMessageCategory.Security, receivedException, "SecuritySession_ZpaClient.EstablishSession",
            //								null, "Zero Proof Authorization ends up with an exception at the remote host. Remote host: {0}.",
            //								this.Remote.ToString());
            #endif

                            if (this.Remote != null)
                                this.Remote.ITransportContext.IGenuineEventProvider.Fire(new GenuineEventArgs(
                                    GenuineEventType.SecuritySessionFailed, receivedException, this.Remote, this));

                            this.DispatchException(receivedException);
                            passException = true;
                            throw receivedException;

                        case ZpaPacketStatusFlag.ForceInitialization:
                        case ZpaPacketStatusFlag.HashedPassword:
                            throw GenuineExceptions.Get_Processing_LogicError(
                                string.Format("The remote host must have the Security Session of the type SecuritySession_ZpaClient registered with the name {0}. SecuritySession_ZpaClient never sends {1} packet marker.",
                                this.Name, Enum.GetName(typeof(ZpaPacketStatusFlag), zpaPacketStatusFlag)));

                        case ZpaPacketStatusFlag.Salt:
                            this.Salt = (byte[]) binaryFormatter.Deserialize(input);

                            // server may immediately start sending the content
                            this.SetupSecurityAlgorithms(this.KeyProvider_ZpaClient.Password);

                            // the sault is received, sends the login and hashed password
                            binaryWriter.Write((byte) ZpaPacketStatusFlag.HashedPassword);
                            binaryFormatter.Serialize(outputStream, this.KeyProvider_ZpaClient.Login);
                            binaryFormatter.Serialize(outputStream, ZeroProofAuthorizationUtility.CalculateDefaultKeyedHash(this.KeyProvider_ZpaClient.Password, this.Salt));
                            return outputStream;

                        case ZpaPacketStatusFlag.SessionEstablished:
                            this.SessionEstablished();
                            return null;
                    }
                }
            }
            catch(Exception opEx)
            {
            #if DEBUG
            //				this.Remote.ITransportContext.IEventLogger.Log(LogMessageCategory.Security, opEx, "SecuritySession_SspiServer.EstablishSession",
            //					null, "Exception was thrown while establishing security context.");
            #endif

                if (this.Remote != null)
                    this.Remote.ITransportContext.IGenuineEventProvider.Fire(new GenuineEventArgs(
                        GenuineEventType.SecuritySessionFailed, opEx, this.Remote, this));

                this.DispatchException(opEx);
                if (passException)
                    throw;

                binaryWriter.Write((byte) ZpaPacketStatusFlag.ExceptionThrown);
                binaryFormatter.Serialize(outputStream, opEx);
                return outputStream;
            }

            return null;
        }
        /// <summary>
        /// Initiates or continues establishing of the Security Session.
        /// Implementation notes: receiving of exceptions no more breaks up the connection like
        /// it was in the previous versions.
        /// </summary>
        /// <param name="input">A null reference or an incoming stream.</param>
        /// <param name="connectionLevel">Indicates whether the Security Session operates on connection level.</param>
        /// <returns>A stream containing data for sending to the remote host or a null reference if Security Session is established.</returns>
        public override GenuineChunkedStream EstablishSession(Stream input, bool connectionLevel)
        {
            bool passException = false;

            // a dance is over
            if (this.IsEstablished)
                return null;

            GenuineChunkedStream outputStream = null;
            BinaryFormatter binaryFormatter = new BinaryFormatter();

            // skip the status flag
            if (connectionLevel)
            {
                if (input != null)
                    input.ReadByte();
                outputStream = new GenuineChunkedStream(false);
            }
            else
                outputStream = this.CreateOutputStream();

            // write session is being established flag
            BinaryWriter binaryWriter = new BinaryWriter(outputStream);
            binaryWriter.Write((byte) 0);

            try
            {
                lock(this)
                {
                    if (input == Stream.Null)
                    {
                        if (this.KeyProvider_SspiClient.DelegatedContext != null)
                        {
                            try
                            {
                                SspiApi.ImpersonateSecurityContext(this.KeyProvider_SspiClient.DelegatedContext.SspiSecurityContext._phContext);

                                // start new session
                                this.SspiSecurityContext = new SspiClientSecurityContext(this.KeyProvider_SspiClient);
                                binaryWriter.Write((byte) SspiPacketStatusFlags.InitializeFromScratch);
                                this.SspiSecurityContext.BuildUpSecurityContext(null, outputStream);
                                return outputStream;
                            }
                            finally
                            {
                                SspiApi.RevertSecurityContext(this.KeyProvider_SspiClient.DelegatedContext.SspiSecurityContext._phContext);
                            }
                        }

                        // start new session
                        this.SspiSecurityContext = new SspiClientSecurityContext(this.KeyProvider_SspiClient);
                        binaryWriter.Write((byte) SspiPacketStatusFlags.InitializeFromScratch);
                        this.SspiSecurityContext.BuildUpSecurityContext(null, outputStream);
                        return outputStream;
                    }

                    SspiPacketStatusFlags sspiPacketStatusFlags = (SspiPacketStatusFlags) input.ReadByte();
                    switch (sspiPacketStatusFlags)
                    {
                        case SspiPacketStatusFlags.ContinueAuthentication:
                            // continue building a security context
                            GenuineChunkedStream sspiData = new GenuineChunkedStream(false);
                            this.SspiSecurityContext.BuildUpSecurityContext(input, sspiData);

                            if (sspiData.Length == 0)
                            {
                                // SSPI session has been built up
                                outputStream.WriteByte((byte) SspiPacketStatusFlags.SessionEstablished);
                                this.SessionEstablished();
                            }
                            else
                            {
                                outputStream.WriteByte((byte) SspiPacketStatusFlags.ContinueAuthentication);
                                outputStream.WriteStream(sspiData);
                            }
                            return outputStream;

                        case SspiPacketStatusFlags.ExceptionThrown:
                            Exception receivedException = GenuineUtility.ReadException(input);

            #if DEBUG
            //							this.Remote.ITransportContext.IEventLogger.Log(LogMessageCategory.Security, receivedException, "SecuritySession_SspiServer.EstablishSession",
            //								null, "SSPI initialization ends up with an exception at the remote host. Remote host: {0}.",
            //								this.Remote.ToString());
            #endif

                            if (this.Remote != null)
                                this.Remote.ITransportContext.IGenuineEventProvider.Fire(new GenuineEventArgs(
                                    GenuineEventType.SecuritySessionFailed, receivedException, this.Remote, this));

                            this.DispatchException(receivedException);
                            passException = true;
                            throw receivedException;

                        case SspiPacketStatusFlags.ForceInitialization:
                            return this.EstablishSession(Stream.Null, connectionLevel);

                        case SspiPacketStatusFlags.InitializeFromScratch:
                            throw GenuineExceptions.Get_Processing_LogicError(
                                string.Format("The remote host must have the Security Session of the type SecuritySession_SspiServer registered with the name {0}. SecuritySession_SspiServer never sends SspiPacketMark.InitializeFromScratch packet marker.",
                                this.Name));

                        case SspiPacketStatusFlags.SessionEstablished:
                            this.SessionEstablished();
                            break;
                    }
                }
            }
            catch(Exception opEx)
            {
            #if DEBUG
            //				this.Remote.ITransportContext.IEventLogger.Log(LogMessageCategory.Security, opEx, "SecuritySession_SspiServer.EstablishSession",
            //					null, "Exception was thrown while establishing security context.");
            #endif

                if (this.Remote != null)
                    this.Remote.ITransportContext.IGenuineEventProvider.Fire(new GenuineEventArgs(
                        GenuineEventType.SecuritySessionFailed, opEx, this.Remote, this));

                this.DispatchException(opEx);
                if (passException)
                    throw;

                binaryWriter.Write((byte) SspiPacketStatusFlags.ExceptionThrown);
                binaryFormatter.Serialize(outputStream, opEx);
                return outputStream;
            }

            return null;
        }
        /// <summary>
        /// Creates and returns a stream containing decrypted data.
        /// </summary>
        /// <param name="input">A stream containing encrypted data.</param>
        /// <returns>A stream with decrypted data.</returns>
        public override Stream Decrypt(Stream input)
        {
            // check on view whether it's session's packet
            if (input.ReadByte() == 0)
            {
                // continue the Security Session establishing
                Stream outputStream = this.EstablishSession(input, false);

                if (outputStream != null)
                    GenuineThreadPool.QueueUserWorkItem(new WaitCallback(this.SendMessage), outputStream, false);
                return null;
            }

            if (this.RijndaelKey == null)
                throw GenuineExceptions.Get_Security_ContextWasNotEstablished(this.Name);

            lock (this.RijndaelKey)
            {
                if (this._decryptor == null)
                {
                    Rijndael rijndael = Rijndael.Create();
                    rijndael.Key = this.RijndaelKey;
                    rijndael.Mode = CipherMode.ECB;

                    this._encryptor = rijndael.CreateEncryptor();
                    this._decryptor = rijndael.CreateDecryptor();
                }
            }

            lock (this._decryptor)
            {
                GenuineChunkedStream output = new GenuineChunkedStream(true);
                GenuineUtility.CopyStreamToStream(new CryptoStream(new FinishReadingStream(input), this._decryptor, CryptoStreamMode.Read), output);

                GenuineUtility.CopyStreamToStream(input, Stream.Null);
                input.Close();

                return output;
            }
        }
        /// <summary>
        /// Establishes a connection to the remote host.
        /// </summary>
        /// <param name="remote">The HostInformation of the remote host.</param>
        /// <param name="genuineConnectionType">Type of the connection.</param>
        /// <param name="localUri">Local URI.</param>
        /// <param name="localPort">Local port.</param>
        /// <param name="connectionName">The name of the connection or a null reference.</param>
        /// <param name="remoteUri">Remote URI.</param>
        /// <param name="remoteHostUniqueIdentifier">The unique identifier of the HostInformation used by the remote host.</param>
        /// <returns>A connection.</returns>
        internal TcpSocketInfo LowLevel_OpenConnection(HostInformation remote, GenuineConnectionType genuineConnectionType, string localUri, int localPort, string connectionName, out string remoteUri, out int remoteHostUniqueIdentifier)
        {
            BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter;

            using (new ReaderAutoLocker(this._disposeLock))
            {
                if (this._disposed)
                    throw OperationException.WrapException(this._disposeReason);
            }

            remoteUri = null;
            Stream inputStream = null;
            Stream outputStream = null;
            remoteHostUniqueIdentifier = 0;
            string url = remote.Url;

            // parse provided url and fetch a port and IP address
            int portNumber;
            string hostName = GenuineUtility.SplitToHostAndPort(url, out portNumber);

            // LOG:
            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
            {
                binaryLogWriter.WriteEvent(LogCategory.Connection, "TcpConnectionManager.LowLevel_OpenConnection",
                    LogMessageType.ConnectionEstablishing, null, null, remote, null,
                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null,
                    -1, 0, 0, 0, null, null, null, null,
                    "The connection is being established to {0}.", hostName);
            }

            Socket socket = null;

            // the time we should finish connection establishing before
            int timeout = GenuineUtility.GetTimeout( (TimeSpan) this.ITransportContext.IParameterProvider[GenuineParameter.ConnectTimeout] );
            using (ConnectionEstablishingClosure connectionEstablishingClosure = new ConnectionEstablishingClosure(hostName, portNumber, this.ITransportContext.IParameterProvider))
            {
                connectionEstablishingClosure.StartOperation();
                if (! connectionEstablishingClosure.Completed.WaitOne( GenuineUtility.GetMillisecondsLeft(timeout), false))
                    throw GenuineExceptions.Get_Connect_CanNotConnectToRemoteHost(url, "Timeout expired.");

                if (connectionEstablishingClosure.Exception != null)
                    throw GenuineExceptions.Get_Connect_CanNotConnectToRemoteHost(url, connectionEstablishingClosure.Exception.Message);

                socket = connectionEstablishingClosure.CompleteOperation();
            }

            if (! socket.Connected)
                throw GenuineExceptions.Get_Connect_CanNotConnectToRemoteHost(url, "Socket.Connected property is false after connecting.");

            if (connectionName == null)
                connectionName = "$/__GC/" + hostName;
            TcpSocketInfo tcpSocketInfo = new TcpSocketInfo(socket, this.ITransportContext, connectionName
            #if DEBUG
                ,"Opened connection"
            #endif
                );
            tcpSocketInfo.GenuineConnectionType = genuineConnectionType;

            // LOG:
            if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
            {
                binaryLogWriter.WriteConnectionParameterEvent(LogCategory.Connection, "TcpConnectionManager.LowLevel_OpenConnection",
                    LogMessageType.ConnectionParameters, null, remote, this.ITransportContext.IParameterProvider,
                    GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, tcpSocketInfo.DbgConnectionId,
                    "The connection is being established to \"{0}\".", hostName);
            }

            // send protocol version and the type of the connection
            Message message = new Message(null, null, -1, new TransportHeaders(), Stream.Null);
            message.FinishTime = timeout;
            message.SerializedContent = MessageCoder.SerializeConnectionHeader(MessageCoder.PROTOCOL_VERSION, genuineConnectionType, tcpSocketInfo.ConnectionName).BaseStream;
            LowLevel_SendSync(message, tcpSocketInfo);
            tcpSocketInfo.MessagesSentSynchronously.ReleaseAllMessages();

            // get connection-level SS
            string connectionLevelSSName = null;
            switch(genuineConnectionType)
            {
                case GenuineConnectionType.Persistent:
                    connectionLevelSSName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForPersistentConnections] as string;
                    break;

                case GenuineConnectionType.Named:
                    connectionLevelSSName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForNamedConnections] as string;
                    break;

                case GenuineConnectionType.Invocation:
                    connectionLevelSSName = this.ITransportContext.IParameterProvider[GenuineParameter.SecuritySessionForInvocationConnections] as string;
                    break;
            }

            SecuritySession securitySession = null;
            if (connectionLevelSSName != null)
                securitySession = this.ITransportContext.IKeyStore.GetKey(connectionLevelSSName).CreateSecuritySession(connectionLevelSSName, null);

            // establish it
            if (securitySession != null && ! securitySession.IsEstablished)
            {
                // LOG:
                if ( binaryLogWriter != null && binaryLogWriter[LogCategory.Connection] > 0 )
                {
                    binaryLogWriter.WriteEvent(LogCategory.Connection, "TcpConnectionManager.LowLevel_OpenConnection",
                        LogMessageType.ConnectionSecurityIsEstablished, null, null, tcpSocketInfo.Remote, null,
                        GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, securitySession, connectionLevelSSName,
                        tcpSocketInfo.DbgConnectionId, 0, 0, 0, null, null, null, null,
                        "The Connection Level Security Session is being established.");
                }

                bool firstPass = true;
                for ( ; ; )
                {
                    inputStream = Stream.Null;

                    try
                    {
                        // prepare streams
                        if (! firstPass)
                            inputStream = this.LowLevel_ReadSync(tcpSocketInfo, timeout, false);
                        else
                            firstPass = false;

                        outputStream = securitySession.EstablishSession(inputStream, true);

                        if (outputStream == null)
                            break;

                        // send a packet to the remote host
                        message = new Message(null, null, -1, new TransportHeaders(), Stream.Null);
                        message.FinishTime = timeout;
                        message.SerializedContent = outputStream;
                        LowLevel_SendSync(message, tcpSocketInfo);
                        tcpSocketInfo.MessagesSentSynchronously.ReleaseAllMessages();

                        if (securitySession.IsEstablished)
                            break;
                    }
                    finally
                    {
                        if (inputStream != null)
                            inputStream.Close();
                        if (outputStream != null)
                            outputStream.Close();
                    }
                }
            }

            tcpSocketInfo.ConnectionLevelSecurity = securitySession;

            // now send connection info through the established connection
            using (GenuineChunkedStream serializedLocalInfo = new GenuineChunkedStream(false))
            {
                // serialize local info
                BinaryWriter binaryWriter = new BinaryWriter(serializedLocalInfo);
                binaryWriter.Write((string) localUri);

                // 2.5.2 fix
                //				binaryWriter.Write((int) localPort);
                binaryWriter.Write((int) -1);
                binaryWriter.Write((byte) genuineConnectionType);
                binaryWriter.Write((int) remote.LocalHostUniqueIdentifier);

                // and send it
                message = new Message(null, null, -1, new TransportHeaders(), Stream.Null);
                message.FinishTime = timeout;
                message.SerializedContent = serializedLocalInfo;
                LowLevel_SendSync(message, tcpSocketInfo);
                tcpSocketInfo.MessagesSentSynchronously.ReleaseAllMessages();

                // read remote info
                using (Stream remoteUriStream = this.LowLevel_ReadSync(tcpSocketInfo, timeout, false))
                {
                    BinaryReader binaryReader = new BinaryReader(remoteUriStream);
                    remoteUri = binaryReader.ReadString();
                    remoteHostUniqueIdentifier = binaryReader.ReadInt32();
                }
            }

            tcpSocketInfo.IsServer = false;
            return tcpSocketInfo;
        }
Пример #36
0
        /// <summary>
        /// Serializes a message to the GenuineChunkedStream stream.
        /// </summary>
        /// <param name="stream">Stream to serialize the message to.</param>
        /// <param name="message">The message being serialized.</param>
        /// <param name="compress">Indicates whether content should be compressed.</param>
        public static void Serialize(GenuineChunkedStream stream, Message message, bool compress)
        {
            // write a mark whether the content will be compressed
            BinaryWriter binaryWriter = new BinaryWriter(stream);

            binaryWriter.Write((bool)compress);

            // gather messages into a separate stream if compression is required
            GenuineChunkedStream usedStream = stream;

            if (compress)
            {
                usedStream = new GenuineChunkedStream(false);
            }
            binaryWriter = new BinaryWriter(usedStream);

            // all simple values
            binaryWriter.Write((byte)message.GenuineMessageType);
            binaryWriter.Write(message.MessageId);
            binaryWriter.Write(message.ReplyToId);
            //			binaryWriter.Write(message.Recipient.Uri);
            binaryWriter.Write((bool)message.IsOneWay);

            // set DestinationMarshalByRef if it is specified in headers
            object broadcastObjRefOrCourt = message.ITransportHeaders[Message.TransportHeadersBroadcastObjRefOrCourt];

            if (broadcastObjRefOrCourt != null)
            {
                message.DestinationMarshalByRef = broadcastObjRefOrCourt;
            }

            // objref if it exists
            if (message.DestinationMarshalByRef != null)
            {
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                binaryWriter.Write(true);
                binaryFormatter.Serialize(binaryWriter.BaseStream, message.DestinationMarshalByRef);
            }
            else
            {
                binaryWriter.Write(false);
            }

            // Security Session parameters
            binaryWriter.Write((Int16)message.SecuritySessionParameters.Attributes);
            binaryWriter.Write(message.SecuritySessionParameters.RemoteTransportUser);

            // now headers
            foreach (DictionaryEntry entry in message.ITransportHeaders)
            {
                string key = entry.Key as string;
                if (key == null || key == "__" || key == Message.TransportHeadersBroadcastObjRefOrCourt ||
                    entry.Value == null || key == Message.TransportHeadersGenuineMessageType)
                {
                    continue;
                }

                string val = entry.Value.ToString();

                // now write these strings
                binaryWriter.Write(key);
                binaryWriter.Write(val);
            }

            // headers end tag
            binaryWriter.Write("__");

            // and finally the content
            usedStream.WriteStream(message.Stream);

            // compress the content
            if (compress)
            {
                var compressingStream = new GZipStream(new NonClosableStream(stream), CompressionMode.Compress, leaveOpen: true);
                GenuineUtility.CopyStreamToStream(usedStream, compressingStream);
                compressingStream.Close();
            }
        }