/// <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; } }