/// <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) { #if DEBUG input.Position = 0; #endif output.WriteByte(1); lock (this) { // write encrypted content if (this._encryptor != null) { GenuineUtility.CopyStreamToStream(new CryptoStream(new FinishReadingStream(input), this._encryptor, CryptoStreamMode.Read), output); } else { output.WriteStream(input); } if (this.KeyedHashAlgorithm != null) { // and write down the calculated message hash input.Position = 0; output.WriteBuffer(this.KeyedHashAlgorithm.ComputeHash(input), -1); // it's in the content, reset its position if (this._encryptor == null) { input.Position = 0; } } } }
/// <summary> /// Processes incoming Security Session Establishing message and sent a response if it's available. /// </summary> /// <param name="ignored">Ignored.</param> private void Internal_InitiateEstablishingSecuritySession(object ignored) { try { // get the next packet if (this.IsEstablished) { return; } GenuineChunkedStream outputStream = this.EstablishSession(Stream.Null, false); if (outputStream != null) { this.SendMessage(outputStream); } return; } catch (Exception ex) { this.DispatchException(ex); #if DEBUG // this.Remote.ITransportContext.IEventLogger.Log(LogMessageCategory.Security, null, "SecuritySession.Internal_InitiateEstablishingSecuritySession", // null, "Exception during establishing Security Session. Exception: {0}. Stack trace: {1}.", ex.Message, ex.StackTrace); #endif this.Remote.ITransportContext.IGenuineEventProvider.Fire(new GenuineEventArgs(GenuineEventType.SecuritySessionFailed, ex, this.Remote, this)); } }
/// <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) { // there are two good approaches here: either encrypt the stream directly into the target lock (this._encryptor) GenuineUtility.CopyStreamToStream(new CryptoStream(new FinishReadingStream(input), this._encryptor, CryptoStreamMode.Read), output); // or create separate encryptor instance for encrypting at run-time // stream.WriteStream(new ResettableCryptoStream(input, this.SymmetricAlgorithm.CreateEncryptor())); }
/// <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 the output stream this.SspiSecurityContext.EncryptMessage(input, output, this.KeyProvider_SspiServer.RequiredFeatures); }
/// <summary> /// Sends a message synchronously. Does not process exceptions! /// </summary> /// <param name="content">The content being sent to the remote host.</param> /// <param name="timeout">The sending must be completed before this moment.</param> public void LowLevel_SendSync(Stream content, int timeout) { // apply the connection-level security session if (this.ConnectionLevelSecurity != null) { GenuineChunkedStream outputStream = new GenuineChunkedStream(true); this.ConnectionLevelSecurity.Encrypt(content, outputStream); content = outputStream; } for ( ; ;) { if (!this.IsValid) { throw GenuineExceptions.Get_Processing_TransportConnectionFailed(); } if (!GenuineUtility.WaitOne(_namedEventRemoteReadCompleted.ManualResetEvent, GenuineUtility.GetMillisecondsLeft(timeout))) { throw GenuineExceptions.Get_Send_Timeout(); } if (this._closed != 0) { throw GenuineExceptions.Get_Receive_ConnectionClosed(); } this._namedEventRemoteReadCompleted.ManualResetEvent.Reset(); // read the next portion int bytesRead = content.Read(this._sendBuffer, 0, this._sendSpaceSize); // LOG: BinaryLogWriter binaryLogWriter = this.ITransportContext.BinaryLogWriter; if (binaryLogWriter != null && binaryLogWriter[LogCategory.LowLevelTransport] > 0) { binaryLogWriter.WriteTransportContentEvent(LogCategory.LowLevelTransport, "GenuineSaredMemoryConnection.LowLevel_SendSync", LogMessageType.LowLevelTransport_AsyncSendingInitiating, null, null, this.Remote, binaryLogWriter[LogCategory.LowLevelTransport] > 1 ? new MemoryStream(this._sendBuffer, 0, bytesRead) : null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, this.DbgConnectionId, bytesRead, null, null, null, "Content sending."); } Marshal.Copy(this._sendBuffer, 0, (IntPtr)(this._pointer.ToInt32() + this._sendOffset + SHARE_CONTENT_OFFSET), bytesRead); this._MessageToSendTotalSize = bytesRead; this._MessageToSendFinishFlag = bytesRead < this._sendSpaceSize ? 1 : 0; this._namedEventWriteCompleted.ManualResetEvent.Set(); if (bytesRead < this._sendSpaceSize) { this.UpdateLastTimeAMessageWasSent(); return; } } }
/// <summary> /// Creates and initializes GenuineChunkedStream with the header containing Processor's /// data and the security context name. /// </summary> /// <returns>Created and initialized GenuineChunkedStream.</returns> protected GenuineChunkedStream CreateOutputStream() { GenuineChunkedStream stream = new GenuineChunkedStream(false); // name of the coder BinaryWriter binaryWriter = new BinaryWriter(stream); binaryWriter.Write(this.Name); return(stream); }
/// <summary> /// Sends the stream to the remote host. /// </summary> /// <param name="message">The message.</param> public void SendMessage(Message message) { int availableConnectionEntry = 0; HttpWebRequest httpWebRequest = null; try { // serialize the message GenuineChunkedStream stream = new GenuineChunkedStream(false); using (BufferKeeper bufferKeeper = new BufferKeeper(0)) { MessageCoder.FillInLabelledStream(message, null, null, stream, bufferKeeper.Buffer, (int)this.ITransportContext.IParameterProvider[GenuineParameter.HttpRecommendedPacketSize]); } // add the header GenuineChunkedStream resultStream = new GenuineChunkedStream(false); BinaryWriter binaryWriter = new BinaryWriter(resultStream); HttpMessageCoder.WriteRequestHeader(binaryWriter, MessageCoder.PROTOCOL_VERSION, GenuineConnectionType.Invocation, this.ITransportContext.BinaryHostIdentifier, HttpPacketType.Usual, message.MessageId, string.Empty, this.Remote.LocalHostUniqueIdentifier); if (stream.CanSeek) { resultStream.WriteStream(stream); } else { GenuineUtility.CopyStreamToStream(stream, resultStream); } // get a connection availableConnectionEntry = FindAvailableConnectionEntry(); httpWebRequest = this.InitializeRequest("__GC_INVC_" + availableConnectionEntry.ToString(), this._keepalive); this.InitiateSending(new ConnectionInfo(httpWebRequest, availableConnectionEntry, message), resultStream, this._httpAsynchronousRequestTimeout); } catch { try { if (httpWebRequest != null) { httpWebRequest.Abort(); } } catch { } this.ReleaseConnectionEntry(availableConnectionEntry); throw; } }
/// <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); } lock (this) { GenuineChunkedStream output = new GenuineChunkedStream(false); byte[] sign = null; int signSize = 0; if (this.KeyedHashAlgorithm != null) { signSize = this.KeyedHashAlgorithm.HashSize / 8; } // decrypt the content and fetch the sign if (this._decryptor != null) { CryptoStream cryptoStream = new CryptoStream(new FinishReadingStream(output), this._decryptor, CryptoStreamMode.Write); sign = GenuineUtility.CopyStreamToStreamExceptSign(input, cryptoStream, signSize); cryptoStream.FlushFinalBlock(); } else { sign = GenuineUtility.CopyStreamToStreamExceptSign(input, output, signSize); } // check the sign if (this.KeyedHashAlgorithm != null) { if (!ZeroProofAuthorizationUtility.CompareBuffers(sign, this.KeyedHashAlgorithm.ComputeHash(output), sign.Length)) { throw GenuineExceptions.Get_Security_WrongSignature(); } output.Position = 0; } output.ReleaseOnReadMode = true; return(output); } }
/// <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) { // the first approach lock (this._decryptor) { GenuineChunkedStream output = new GenuineChunkedStream(true); GenuineUtility.CopyStreamToStream(new CryptoStream(new FinishReadingStream(input), this._decryptor, CryptoStreamMode.Read), output); return(output); } // the second approach // return new CryptoStream(new FinishReadingStream(input), this.SymmetricAlgorithm.CreateDecryptor(), CryptoStreamMode.Read); }
/// <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> /// 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> /// 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> /// 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> /// Copies data from the input stream to the output stream. /// WARNING: sometimes it does not actually copy the content of the input stream, it attaches it to the output stream. /// </summary> /// <param name="inputStream">The stream to copy from.</param> /// <param name="outputStream">The stream to copy to.</param> /// <param name="buffer">The intermediate buffer used during copying.</param> public static void CopyStreamToStreamWithMinimumOperations(Stream inputStream, Stream outputStream, byte[] buffer) { GenuineChunkedStream inputGenuineChunkedStream = inputStream as GenuineChunkedStream; if (inputGenuineChunkedStream != null) { inputGenuineChunkedStream.WriteTo(outputStream); return; } int bufSize = buffer.Length; int readSize = inputStream.Read(buffer, 0, bufSize); while (readSize > 0) { outputStream.Write(buffer, 0, readSize); readSize = inputStream.Read(buffer, 0, bufSize); } }
/// <summary> /// Copies data from one stream to another. /// </summary> /// <param name="inputStream">Stream to copy from.</param> /// <param name="outputStream">Stream to copy to.</param> public static void CopyStreamToStream(Stream inputStream, Stream outputStream) { GenuineChunkedStream inputGenuineChunkedStream = inputStream as GenuineChunkedStream; if (inputGenuineChunkedStream != null) { inputGenuineChunkedStream.WriteTo(outputStream); return; } using (BufferKeeper bufferKeeper = new BufferKeeper(0)) { int bufSize = bufferKeeper.Buffer.Length; int readSize = inputStream.Read(bufferKeeper.Buffer, 0, bufSize); while (readSize > 0) { outputStream.Write(bufferKeeper.Buffer, 0, readSize); readSize = inputStream.Read(bufferKeeper.Buffer, 0, bufSize); } } }
/// <summary> /// Sends the invocation to all registered receivers. /// </summary> /// <param name="msg">The message to be sent.</param> public void PerformBroadcasting(IMessage msg) { BinaryLogWriter binaryLogWriter = GenuineLoggingServices.BinaryLogWriter; string methodName = null; string invocationTarget = null; // the first stage of the broadcasting try { ArrayList listOfExcludedReceivers = new ArrayList(); this._iMessage = msg; methodName = BinaryLogWriter.ParseInvocationMethod(msg.Properties["__MethodName"] as string, msg.Properties["__TypeName"] as string); BinaryFormatter formatterForLocalRecipients = null; // serialize the message BinaryFormatter binaryFormatter = new BinaryFormatter(new RemotingSurrogateSelector(), new StreamingContext(StreamingContextStates.Other)); this._messageStream = new GenuineChunkedStream(false); binaryFormatter.Serialize(this._messageStream, msg); // to trace the message if it could reach the server via several channels string callGuidSubstring = null; if (this._dispatcher.IgnoreRecurrentCalls) { callGuidSubstring = Guid.NewGuid().ToString("N"); } // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0) { binaryLogWriter.WriteBroadcastEngineEvent(LogCategory.BroadcastEngine, "ResultCollector.PerformBroadcasting", LogMessageType.BroadcastInvocationInitiated, null, null, null, binaryLogWriter[LogCategory.BroadcastEngine] > 1 ? (Stream)this._messageStream.Clone() : null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, true, this._dispatcher, this, false, null, methodName, null, "The broadcast invocation is initiated."); } // to prevent firing resultCollector.AllMessagesReceived event this.UnrepliedReceivers[_uniqueReceiverName] = null; object[] listOfReceiverInfo; this._dispatcher.GetListOfReceivers(out listOfReceiverInfo, msg, this); // through all recipients for (int i = 0; i < listOfReceiverInfo.Length; i++) { ReceiverInfo receiverInfo = listOfReceiverInfo[i] as ReceiverInfo; if (receiverInfo == null) { continue; } string mbrUri = (string)receiverInfo.MbrUri; invocationTarget = mbrUri; try { lock (receiverInfo) { if (this._dispatcher.MaximumNumberOfConsecutiveFailsToExcludeReceiverAutomatically != 0 && receiverInfo.NumberOfFails >= this._dispatcher.MaximumNumberOfConsecutiveFailsToExcludeReceiverAutomatically) { // put it to the list containing receivers being excluded listOfExcludedReceivers.Add(mbrUri); continue; } } // think that it'll fail if (!receiverInfo.Local && receiverInfo.GeneralBroadcastSender == null) { lock (this) { this.Failed[mbrUri] = GenuineExceptions.Get_Broadcast_RemoteEndPointDidNotReplyForTimeOut(); } } if (receiverInfo.Local) { // call to local appdomain // ignore recurrent calls if (this._dispatcher.IgnoreRecurrentCalls && UniqueCallTracer.Instance.WasGuidRegistered(mbrUri + callGuidSubstring)) { continue; } // we'll wait for the answer from this receiver this.UnrepliedReceivers[mbrUri] = null; // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0) { binaryLogWriter.WriteBroadcastEngineEvent(LogCategory.BroadcastEngine, "ResultCollector.PerformBroadcasting", LogMessageType.BroadcastRecipientInvoked, null, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, false, this._dispatcher, this, false, receiverInfo, null, null, "The local receiver is invoked via LocalPerformer."); } if (formatterForLocalRecipients == null) { formatterForLocalRecipients = new BinaryFormatter(); } // fixed in 2.5.9.6 IMessage iLocalMessage = (IMessage)formatterForLocalRecipients.Deserialize((Stream)this._messageStream.Clone()); // queue task to run the call locally //IMessage iLocalMessage = (IMessage) binaryFormatter.Deserialize( (Stream) this._messageStream.Clone() ); LocalPerformer localPerformer = new LocalPerformer(iLocalMessage, this, receiverInfo.MbrObject); GenuineThreadPool.QueueUserWorkItem(new WaitCallback(localPerformer.Call), null, false); } else if (receiverInfo.GeneralBroadcastSender != null) { // call via true multicast channel Stream messageToBeSent = (Stream)this._messageStream.Clone(); // send via real broadcast sender to the specific court msg.Properties["__Uri"] = string.Empty; Message message = Message.CreateOutcomingMessage(receiverInfo.GeneralBroadcastSender.ITransportContext, msg, new TransportHeaders(), messageToBeSent, false); message.DestinationMarshalByRef = receiverInfo.SerializedObjRef; message.GenuineMessageType = GenuineMessageType.TrueBroadcast; // to ignore recurrent calls on the remote side if (this._dispatcher.IgnoreRecurrentCalls) { message.ITransportHeaders[Message.TransportHeadersBroadcastSendGuid] = callGuidSubstring; } // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0) { message.ITransportHeaders[Message.TransportHeadersInvocationTarget] = invocationTarget; message.ITransportHeaders[Message.TransportHeadersMethodName] = methodName; binaryLogWriter.WriteBroadcastEngineEvent(LogCategory.BroadcastEngine, "ResultCollector.PerformBroadcasting", LogMessageType.BroadcastRecipientInvoked, null, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, false, this._dispatcher, this, false, receiverInfo, null, null, "Mulsticast sender is being invoked."); } // register to catch all the answers receiverInfo.GeneralBroadcastSender.ITransportContext.IIncomingStreamHandler.RegisterResponseProcessor(message.MessageId, this); // and send it receiverInfo.GeneralBroadcastSender.SendMessage(message, this); } else { // send the invocation through the usual channel // we'll wait for the reply this.UnrepliedReceivers[mbrUri] = null; // send only if this receiver is not expected to receive message via broadcast channel if (receiverInfo.NeedsBroadcastSimulation) { // each time a new stream is created because sinks change stream position concurrently Stream messageToBeSent = (Stream)this._messageStream.Clone(); TransportHeaders transportHeaders = new TransportHeaders(); // to ignore recurrent calls on the remote side if (this._dispatcher.IgnoreRecurrentCalls) { transportHeaders[Message.TransportHeadersBroadcastSendGuid] = callGuidSubstring; } // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0) { binaryLogWriter.WriteBroadcastEngineEvent(LogCategory.BroadcastEngine, "ResultCollector.PerformBroadcasting", LogMessageType.BroadcastRecipientInvoked, null, null, receiverInfo.DbgRemoteHost, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, false, this._dispatcher, this, false, receiverInfo, null, null, "The broadcast recipient is being invoked directly."); } // invoke the destination MBR msg.Properties["__Uri"] = receiverInfo.MbrUri; transportHeaders[Message.TransportHeadersBroadcastObjRefOrCourt] = receiverInfo.SerializedObjRef; transportHeaders[Message.TransportHeadersMbrUriName] = receiverInfo.MbrUri; transportHeaders[Message.TransportHeadersGenuineMessageType] = GenuineMessageType.BroadcastEngine; transportHeaders[Message.TransportHeadersInvocationTarget] = invocationTarget; transportHeaders[Message.TransportHeadersMethodName] = methodName; ClientChannelSinkStack clientChannelSinkStack = new ClientChannelSinkStack(this); clientChannelSinkStack.Push(this, null); receiverInfo.IClientChannelSink.AsyncProcessRequest(clientChannelSinkStack, this._iMessage, transportHeaders, messageToBeSent); } } } catch (Exception ex) { this.ParseResult(mbrUri, null, ex); } } // remove set uri from the hash to check wither the invocation finished this.UnrepliedReceivers.Remove(_uniqueReceiverName); if (this.UnrepliedReceivers.Count <= 0) { this.AllMessagesReceived.Set(); } this.StartReceiving(); if (listOfExcludedReceivers.Count > 0) { foreach (string uri in listOfExcludedReceivers) { this._dispatcher.Remove(uri); } } } catch (Exception ex) { // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0) { binaryLogWriter.WriteBroadcastEngineEvent(LogCategory.BroadcastEngine, "ResultCollector.PerformBroadcasting", LogMessageType.BroadcastInvocationInitiated, ex, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, false, this._dispatcher, this, false, null, invocationTarget, methodName, "A critical failure occurred during broadcast."); } throw; } }
/// <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> /// 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; var binaryFormatter = new BinaryFormatter().Safe(); // 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> /// Establishes Connection Level Security Session and gather their output into specified stream. /// </summary> /// <param name="senderInput">The input stream.</param> /// <param name="listenerInput">The input stream.</param> /// <param name="output">The output stream.</param> /// <param name="sender">The sender's Security Session.</param> /// <param name="listener">The listener's Security Session.</param> /// <returns>True if at least one Security Session requested sending of data.</returns> public bool GatherContentOfConnectionLevelSecuritySessions(Stream senderInput, Stream listenerInput, GenuineChunkedStream output, SecuritySession sender, SecuritySession listener) { bool clssDataPresents = false; Stream clsseStream; // CLSSE info using (new GenuineChunkedStreamSizeLabel(output)) { if (sender != null && !sender.IsEstablished) { clsseStream = sender.EstablishSession(senderInput, true); if (clsseStream != null) { clssDataPresents = true; GenuineUtility.CopyStreamToStream(clsseStream, output); } } } // CLSSE info using (new GenuineChunkedStreamSizeLabel(output)) { if (listener != null && !listener.IsEstablished) { clsseStream = listener.EstablishSession(listenerInput, true); if (clsseStream != null) { clssDataPresents = true; GenuineUtility.CopyStreamToStream(clsseStream, output); } } } return(clssDataPresents); }
/// <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> /// 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; var binaryFormatter = new BinaryFormatter().Safe(); // 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) { ZpaPacketStatusFlag zpaPacketStatusFlag; if (input == Stream.Null) { zpaPacketStatusFlag = ZpaPacketStatusFlag.ForceInitialization; } else { zpaPacketStatusFlag = (ZpaPacketStatusFlag)input.ReadByte(); } // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.Security] > 0) { binaryLogWriter.WriteEvent(LogCategory.Security, "SecuritySession_ZpaServer.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 Server 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_ZpaServer.EstablishSession", // null, "Zero Proof Authorization ends up with an exception at the remote host. Remote host: {0}.", // this.Remote.ToString()); #endif this.Remote.ITransportContext.IGenuineEventProvider.Fire(new GenuineEventArgs( GenuineEventType.SecuritySessionFailed, receivedException, this.Remote, this)); this.DispatchException(receivedException); passException = true; throw receivedException; case ZpaPacketStatusFlag.ForceInitialization: // send the sault to the remote host binaryWriter.Write((byte)ZpaPacketStatusFlag.Salt); binaryFormatter.Serialize(outputStream, this.Salt); return(outputStream); case ZpaPacketStatusFlag.HashedPassword: // the the password this._login = binaryFormatter.Deserialize(input); string password = this.KeyProvider_ZpaServer.IAuthorizationManager.GetPassword(this._login); // and check on the hash byte[] calculatedHash = (byte[])binaryFormatter.Deserialize(input); byte[] expectedHash = ZeroProofAuthorizationUtility.CalculateDefaultKeyedHash(password, this.Salt); if (!ZeroProofAuthorizationUtility.CompareBuffers(calculatedHash, expectedHash, expectedHash.Length)) { throw GenuineExceptions.Get_Security_PasswordKnowledgeIsNotProved(); } // ok the hash is correct. Complete the authorization this.SetupSecurityAlgorithms(password); this.SessionEstablished(); binaryWriter.Write((byte)ZpaPacketStatusFlag.SessionEstablished); return(outputStream); case ZpaPacketStatusFlag.Salt: case ZpaPacketStatusFlag.SessionEstablished: throw GenuineExceptions.Get_Processing_LogicError( string.Format("The remote host must have the Security Session of the type SecuritySession_ZpaServer registered with the name {0}. SecuritySession_ZpaServer never sends {1} packet marker.", this.Name, Enum.GetName(typeof(ZpaPacketStatusFlag), zpaPacketStatusFlag))); } } } 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> /// Handles incoming message (message, response or event). /// </summary> /// <param name="message">The message to handle.</param> public void HandleIncomingMessage(Message message) { BinaryLogWriter binaryLogWriter = message.ITransportContext.BinaryLogWriter; try { ServerChannelSinkStack stack = new ServerChannelSinkStack(); stack.Push(this, message); ITransportHeaders responseHeaders; Stream responseStream; IMessage responseMsg; // FIX: 2.5.8 removing the application name from the object URI string applicationName = RemotingConfiguration.ApplicationName; if (applicationName != null) { string uri = (string)message.ITransportHeaders["__RequestUri"]; if (uri.Length > applicationName.Length && uri.StartsWith(applicationName)) { int sizeToBeCut = applicationName.Length + (uri[applicationName.Length] == '/' ? 1 : 0); uri = uri.Substring(sizeToBeCut); message.ITransportHeaders["__RequestUri"] = uri; } } message.ITransportHeaders["__CustomErrorsEnabled"] = false; message.ITransportHeaders[CommonTransportKeys.IPAddress] = message.Sender.PhysicalAddress is IPEndPoint ? ((IPEndPoint)message.Sender.PhysicalAddress).Address : message.Sender.PhysicalAddress; // LOG: put down the log record if (binaryLogWriter != null && binaryLogWriter[LogCategory.MessageProcessing] > 0) { binaryLogWriter.WriteEvent(LogCategory.MessageProcessing, "GenuineUniversalServerTransportSink.HandleIncomingMessage", LogMessageType.MessageRequestInvoking, null, message, message.Sender, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, -1, GenuineUtility.TickCount, 0, 0, null, null, null, null, "The .NET Remoting request is being invoked."); } ServerProcessing serverProcessing = this._nextChannelSink.ProcessMessage(stack, null, message.ITransportHeaders, message.Stream, out responseMsg, out responseHeaders, out responseStream); switch (serverProcessing) { case ServerProcessing.Complete: Message reply = new Message(message, responseHeaders, responseStream); // LOG: put down the log record if (binaryLogWriter != null && binaryLogWriter[LogCategory.MessageProcessing] > 0) { string invocationTarget = responseMsg.Properties["__Uri"] as string; string methodName = BinaryLogWriter.ParseInvocationMethod(responseMsg.Properties["__MethodName"] as string, responseMsg.Properties["__TypeName"] as string); binaryLogWriter.WriteMessageCreatedEvent("GenuineUniversalServerTransportSink.HandleIncomingMessage", 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 message has been created."); reply.ITransportHeaders[Message.TransportHeadersInvocationTarget] = invocationTarget; reply.ITransportHeaders[Message.TransportHeadersMethodName] = methodName; binaryLogWriter.WriteEvent(LogCategory.MessageProcessing, "GenuineUniversalServerTransportSink.HandleIncomingMessage", LogMessageType.MessageRequestInvoked, null, reply, message.Sender, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, -1, GenuineUtility.TickCount, 0, message.SeqNo, null, null, null, null, "The .NET Remoting invocation has been performed."); } message.ITransportContext.ConnectionManager.Send(reply); break; case ServerProcessing.Async: // asyncProcessResponse will be called later break; case ServerProcessing.OneWay: // LOG: put down the log record if (binaryLogWriter != null && binaryLogWriter[LogCategory.MessageProcessing] > 0) { binaryLogWriter.WriteEvent(LogCategory.MessageProcessing, "GenuineUniversalServerTransportSink.HandleIncomingMessage", LogMessageType.MessageRequestInvoked, null, null, message.Sender, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, -1, GenuineUtility.TickCount, 0, message.SeqNo, null, null, null, null, "One-way .NET Remoting invocation has been performed. No response is available."); } break; } } catch (Exception ex) { try { // LOG: put down the log record if (binaryLogWriter != null && binaryLogWriter[LogCategory.MessageProcessing] > 0) { binaryLogWriter.WriteEvent(LogCategory.MessageProcessing, "GenuineUniversalServerTransportSink.HandleIncomingMessage", LogMessageType.MessageRequestInvoking, ex, message, message.Sender, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, -1, 0, 0, 0, null, null, null, null, "The .NET Remoting request resulted in exception. The exception is being sent back."); } // return this exception as a result BinaryFormatter binaryFormatter = new BinaryFormatter(); GenuineChunkedStream serializedException = new GenuineChunkedStream(false); binaryFormatter.Serialize(serializedException, ex); Message reply = new Message(message, new TransportHeaders(), serializedException); reply.ContainsSerializedException = true; this.ITransportContext.ConnectionManager.Send(reply); } catch (Exception internalEx) { // It's a destiny not to deliver an exception back to the caller // LOG: put down the log record if (binaryLogWriter != null && binaryLogWriter[LogCategory.MessageProcessing] > 0) { binaryLogWriter.WriteEvent(LogCategory.MessageProcessing, "GenuineUniversalServerTransportSink.HandleIncomingMessage", LogMessageType.MessageRequestInvoking, internalEx, message, message.Sender, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, -1, 0, 0, 0, null, null, null, null, "The source exception cannot be sent over the network. Both exceptions are ignored."); } } } }
/// <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. /// 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) { // request establishing the Security Session binaryWriter.Write((byte)SspiPacketStatusFlags.ForceInitialization); return(outputStream); } SspiPacketStatusFlags sspiPacketStatusFlags = (SspiPacketStatusFlags)input.ReadByte(); switch (sspiPacketStatusFlags) { case SspiPacketStatusFlags.InitializeFromScratch: case SspiPacketStatusFlags.ContinueAuthentication: if (sspiPacketStatusFlags == SspiPacketStatusFlags.InitializeFromScratch) { this.SspiSecurityContext = new SspiServerSecurityContext(this.KeyProvider_SspiServer); } // continue building a security context GenuineChunkedStream sspiData = new GenuineChunkedStream(false); this.SspiSecurityContext.BuildUpSecurityContext(input, sspiData); if (sspiData.Length == 0) { // SSPI session is 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 = this.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: throw GenuineExceptions.Get_Processing_LogicError( string.Format("The remote host must have the Security Session of the type SecuritySession_SspiClient registered with the name {0}. SecuritySession_SspiClient never sends SspiPacketMark.ForceInitialization packet mark.", 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> /// Completes the HTTP request. /// </summary> /// <param name="ar">The result of the HTTP request.</param> private void OnRequestCompleted(IAsyncResult ar) { HttpWebResponse httpWebResponse = null; Stream inputStream = null; ConnectionInfo connectionInfo = null; try { connectionInfo = (ConnectionInfo)ar.AsyncState; HttpWebRequest httpWebRequest = connectionInfo.HttpWebRequest; #if (FRM20) // timeout has been already set try { httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); } catch (WebException ex) { if (ex.Status == WebExceptionStatus.Timeout) { return; } } #else httpWebResponse = (HttpWebResponse)httpWebRequest.EndGetResponse(ar); #endif this.Remote.Renew(this._hostRenewingSpan, false); // process the content inputStream = httpWebResponse.GetResponseStream(); #if DEBUG // if (this.ITransportContext.IEventLogger.AcceptBinaryData) // { // byte[] content = new byte[(int) httpWebResponse.ContentLength]; // GenuineUtility.ReadDataFromStream(inputStream, content, 0, content.Length); // // this.ITransportContext.IEventLogger.Log(LogMessageCategory.Traffic, null, "HttpInvocationConnection.OnRequestCompleted", // content, "The content of the response received by the HttpInvocationConnection. Size: {0}.", content.Length); // inputStream = new MemoryStream(content, false); // } #endif BinaryReader binaryReader = new BinaryReader(inputStream); string serverUri; int sequenceNo; HttpPacketType httpPacketType; int remoteHostUniqueIdentifier; HttpMessageCoder.ReadResponseHeader(binaryReader, out serverUri, out sequenceNo, out httpPacketType, out remoteHostUniqueIdentifier); #if DEBUG // this.ITransportContext.IEventLogger.Log(LogMessageCategory.TransportLayer, null, "HttpInvocationConnection.OnRequestCompleted", // null, "The invocation request returned. Server uri: {0}. Sequence no: {1}. Packet type: {2}. Content-encoding: {3}. Content-length: {4}. Protocol version: {5}. Response uri: \"{6}\". Server: \"{7}\". Status code: {8}. Status description: \"{9}\".", // serverUri, sequenceNo, Enum.Format(typeof(HttpPacketType), httpPacketType, "g"), // httpWebResponse.ContentEncoding, httpWebResponse.ContentLength, // httpWebResponse.ProtocolVersion, httpWebResponse.ResponseUri, // httpWebResponse.Server, httpWebResponse.StatusCode, httpWebResponse.StatusDescription); #endif // if the remote host has asked to terminate a connection if (httpPacketType == HttpPacketType.ClosedManually || httpPacketType == HttpPacketType.Desynchronization || httpPacketType == HttpPacketType.SenderError) { throw GenuineExceptions.Get_Receive_ConnectionClosed(); } // skip the first byte if (binaryReader.ReadByte() != 0) { if (!connectionInfo.Message.IsOneWay) { // this.ITransportContext.IEventLogger.Log(LogMessageCategory.FatalError, GenuineExceptions.Get_Processing_LogicError("The invocation response doesn't contain any messages."), "HttpInvocationConnection.OnRequestCompleted", // null, "The HTTP response doesn't contain content. The response to the request was not received."); } } else { // fetch and process the response messages using (BufferKeeper bufferKeeper = new BufferKeeper(0)) { using (LabelledStream labelledStream = new LabelledStream(this.ITransportContext, inputStream, bufferKeeper.Buffer)) { GenuineChunkedStream receivedRequest = new GenuineChunkedStream(true); GenuineUtility.CopyStreamToStream(labelledStream, receivedRequest); this.ITransportContext.IIncomingStreamHandler.HandleMessage(receivedRequest, this.Remote, GenuineConnectionType.Invocation, string.Empty, -1, true, null, null, null); } } } } catch (Exception ex) { // this.ITransportContext.IEventLogger.Log(LogMessageCategory.Error, ex, "HttpInvocationConnection.OnRequestCompleted", // null, "Exception occurred during receiving a response to an invocation request."); // dispatch the exception to the caller context if (connectionInfo != null) { this.ITransportContext.IIncomingStreamHandler.DispatchException(connectionInfo.Message, ex); } } finally { if (inputStream != null) { inputStream.Close(); } if (httpWebResponse != null) { httpWebResponse.Close(); } // release the connection if (connectionInfo != null) { this.ReleaseConnectionEntry(connectionInfo.Index); } } }
/// <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> /// 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); }
/// <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.WriteStream(input); }
/// <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 abstract void Encrypt(Stream input, GenuineChunkedStream output);