/// <summary> /// Registers the broadcast sender that sends a message to several receivers. /// Returns Guid (it's like URI for an MBR object) assigned for this sender that can be used /// to delete this broadcast sender later. /// </summary> /// <param name="generalBroadcastSender">The broadcast sender which sends a message via "true" multicast channel.</param> public string Add(GeneralBroadcastSender generalBroadcastSender) { // just add it as it would be the usual receiver ReceiverInfo receiverInfo = new ReceiverInfo(); receiverInfo.GeneralBroadcastSender = generalBroadcastSender; receiverInfo.Local = false; string uri = Guid.NewGuid().ToString("N") + "/" + generalBroadcastSender.Court; receiverInfo.MbrUri = uri; // register it using (WriterAutoLocker writer = new WriterAutoLocker(this._readerWriterLock)) { this._cachedReceiversInfoArray = null; this._receivers[uri] = receiverInfo; } // LOG: BinaryLogWriter binaryLogWriter = GenuineLoggingServices.BinaryLogWriter; if (binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0) { binaryLogWriter.WriteBroadcastEngineEvent(LogCategory.BroadcastEngine, "Dispatcher.Add", LogMessageType.BroadcastRecipientAdded, null, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, false, this, null, true, receiverInfo, generalBroadcastSender.Court, generalBroadcastSender.ITransportContext.HostIdentifier, "The \"true\" multicast sender is added."); } return(uri); }
/// <summary> /// Returns the filtered array of the ReceiverInfo instances. /// </summary> /// <param name="arrayOfReceiverInfo">The list of receivers being filtered out.</param> /// <param name="iMessage">The invocation.</param> /// <param name="resultCollector">The Result Collector obtaining the list of receivers. Is used for debugging purposes only.</param> public void GetListOfReceivers(out object[] arrayOfReceiverInfo, IMessage iMessage, ResultCollector resultCollector) { arrayOfReceiverInfo = null; try { using (ReaderAutoLocker reader = new ReaderAutoLocker(this._readerWriterLock)) { // check whether they were cached if (this._cachedReceiversInfoArray == null) { this._cachedReceiversInfoArray = new object[this._receivers.Values.Count]; this._receivers.Values.CopyTo(this._cachedReceiversInfoArray, 0); } // get the cached array arrayOfReceiverInfo = this._cachedReceiversInfoArray; // and drive it thru the filter IMulticastFilter iMulticastFilter = Dispatcher.GetCurrentFilter(); if (iMulticastFilter == null) { iMulticastFilter = this.IMulticastFilter; } if (iMulticastFilter != null) { // LOG: BinaryLogWriter binaryLogWriter = GenuineLoggingServices.BinaryLogWriter; if (binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0) { binaryLogWriter.WriteBroadcastEngineEvent(LogCategory.BroadcastEngine, "Dispatcher.GetListOfReceivers", LogMessageType.BroadcastFilterCalled, null, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, false, this, resultCollector, false, null, iMulticastFilter.GetType().ToString(), null, "The broadcast filter is called. The type of the filter: {0}.", iMulticastFilter.GetType().ToString()); } arrayOfReceiverInfo = iMulticastFilter.GetReceivers(arrayOfReceiverInfo, iMessage); } } } catch (Exception ex) { // LOG: BinaryLogWriter binaryLogWriter = GenuineLoggingServices.BinaryLogWriter; if (binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0) { binaryLogWriter.WriteBroadcastEngineEvent(LogCategory.BroadcastEngine, "Dispatcher.GetListOfReceivers", LogMessageType.BroadcastFilterCalled, ex, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, false, this, resultCollector, false, null, null, null, "The exception occurred while calling the broadcast filter."); } } }
/// <summary> /// Removes the receiver or the broadcast sender associated with the specified uri. /// Returns false if there is no such receiver found in the list of receivers. /// </summary> /// <param name="uri">The uri of the receiver.</param> public bool Remove(string uri) { if (uri == null || uri.Length <= 0) { return(false); } using (WriterAutoLocker writer = new WriterAutoLocker(this._readerWriterLock)) { // check if it is in the list if (!this._receivers.ContainsKey(uri)) { return(false); } this._cachedReceiversInfoArray = null; ReceiverInfo receiverInfo = (ReceiverInfo)this._receivers[uri]; this._receivers.Remove(uri); // LOG: BinaryLogWriter binaryLogWriter = GenuineLoggingServices.BinaryLogWriter; if (binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0) { binaryLogWriter.WriteBroadcastEngineEvent(LogCategory.BroadcastEngine, "Dispatcher.Remove", LogMessageType.BroadcastRecipientRemoved, null, null, receiverInfo.DbgRemoteHost, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, false, this, null, true, receiverInfo, uri, null, "The broadcast recipient or \"true\" broadcast sender is removed from the list of recipients."); } // Sponsor is being deleted in another thread; otherwise client disconnection // will cause dispatcher to be freezed for lengthy time out GenuineThreadPool.QueueUserWorkItem(new WaitCallback(this.DeleteSponsorFromTheObjectAndFireEvent), receiverInfo, false); } return(true); }
/// <summary> /// Initiate the receiving of responses. /// Returns true if the invocation has been completed synchronously. /// </summary> /// <returns>The true value if the invocation has been completed synchronously.</returns> public bool StartReceiving() { bool callIsAsync = false; lock (this._dispatcher) { callIsAsync = this._dispatcher.CallIsAsync; this._broadcastCallFinishedHandler = this._dispatcher.BroadcastCallFinishedHandler; } if (!callIsAsync || this._broadcastCallFinishedHandler == null) { this.AllMessagesReceived.WaitOne(this._dispatcher.ReceiveResultsTimeOut, false); // this call sends messages to failed receivers this.WaitUntilReceiversReplyOrTimeOut(null, false); // LOG: BinaryLogWriter binaryLogWriter = GenuineLoggingServices.BinaryLogWriter; if (binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0) { binaryLogWriter.WriteBroadcastEngineEvent(LogCategory.BroadcastEngine, "ResultCollector.StartReceiving", LogMessageType.BroadcastInvocationCompleted, null, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, false, this._dispatcher, this, false, null, null, null, "The broadcast invocation is completed."); } this.AllMessagesReceived.Set(); return(true); } ThreadPool.RegisterWaitForSingleObject(this.AllMessagesReceived, new WaitOrTimerCallback(this.WaitUntilReceiversReplyOrTimeOut), null, this._dispatcher.ReceiveResultsTimeOut, true); return(false); }
/// <summary> /// Unregisters the sponsor. /// </summary> /// <param name="receiverInfoItemsAsObject">Array of receivers.</param> private void UnregisterSponsor(object receiverInfoItemsAsObject) { object[] receiverInfoItems = (object[])receiverInfoItemsAsObject; // go though the list of receivers to remove sponsors from all MBR objects foreach (ReceiverInfo receiverInfo in receiverInfoItems) { try { // remove the sponsor if (receiverInfo.MbrObject != null) { // LOG: BinaryLogWriter binaryLogWriter = GenuineLoggingServices.BinaryLogWriter; if (binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0) { binaryLogWriter.WriteBroadcastEngineEvent(LogCategory.BroadcastEngine, "Dispatcher.UnregisterSponsor", LogMessageType.BroadcastRecipientRemoved, null, null, receiverInfo.DbgRemoteHost, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, false, this, null, true, receiverInfo, null, null, "The broadcast recipient is removed after Dispatcher.Clear call."); } ILease lease = (ILease)RemotingServices.GetLifetimeService(receiverInfo.MbrObject); if (lease != null) { lease.Unregister(this.GlobalSponsor); } } } catch { } } }
/// <summary> /// Looks for a failed broadcast receivers and invoke them again. /// </summary> public void SendMessageToFailedReceiversDirectly() { if (this._secondStagePerformed) { return; } this._secondStagePerformed = true; BinaryLogWriter binaryLogWriter = GenuineLoggingServices.BinaryLogWriter; // the second stage of the broadcasting using (ReaderAutoLocker reader = new ReaderAutoLocker(this._dispatcher._readerWriterLock)) { // to prevent firing resultCollector.AllMessagesReceived event this.UnrepliedReceivers[_uniqueReceiverName] = null; lock (this) { foreach (DictionaryEntry entry in this.Failed) { OperationException operationException = entry.Value as OperationException; if (operationException != null && operationException.OperationErrorMessage != null && operationException.OperationErrorMessage.ErrorIdentifier == "GenuineChannels.Exception.Broadcast.RemoteEndPointDidNotReplyForTimeOut") { string uri = (string)entry.Key; ReceiverInfo receiverInfo = this._dispatcher.GetReceiverInfo(uri); // whether this receiver is expected to receive message via broadcast channel if (receiverInfo == null || receiverInfo.NeedsBroadcastSimulation) { continue; } // switch it back to simulation mode if the limit is exceeded lock (receiverInfo) { receiverInfo.NumberOfMulticastFails++; if (this._dispatcher.MaximumNumberOfConsecutiveFailsToEnableSimulationMode != 0 && receiverInfo.NumberOfMulticastFails >= this._dispatcher.MaximumNumberOfConsecutiveFailsToEnableSimulationMode) { // force simulation receiverInfo.NeedsBroadcastSimulation = true; receiverInfo.NumberOfMulticastFails = 0; } } // each time a new stream is created because sinks change stream position concurrently Stream messageToBeSent = (Stream)this._messageStream.Clone(); TransportHeaders transportHeaders = new TransportHeaders(); // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0) { string methodName = BinaryLogWriter.ParseInvocationMethod(this._iMessage.Properties["__MethodName"] as string, this._iMessage.Properties["__TypeName"] as string); string invocationTarget = receiverInfo.MbrUri; binaryLogWriter.WriteBroadcastEngineEvent(LogCategory.BroadcastEngine, "ResultCollector.SendMessageToFailedReceiversDirectly", LogMessageType.BroadcastRecipientInvokedAfterTimeout, null, null, receiverInfo.DbgRemoteHost, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, false, this._dispatcher, this, false, receiverInfo, invocationTarget, methodName, "The broadcast invocation is being directed to the recipient, which did not respond during the first stage."); } // set destination MBR this._iMessage.Properties["__Uri"] = receiverInfo.MbrUri; transportHeaders[Message.TransportHeadersBroadcastObjRefOrCourt] = receiverInfo.SerializedObjRef; ClientChannelSinkStack clientChannelSinkStack = new ClientChannelSinkStack(this); clientChannelSinkStack.Push(this, null); receiverInfo.IClientChannelSink.AsyncProcessRequest(clientChannelSinkStack, this._iMessage, transportHeaders, messageToBeSent); } } } this.UnrepliedReceivers.Remove(_uniqueReceiverName); if (this.UnrepliedReceivers.Count <= 0) { this.AllMessagesReceived.Set(); } } }
/// <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> /// Calls the callback when either all receivers reply or wait time elapses. /// </summary> /// <param name="state">Ignored.</param> /// <param name="timeOut">Ignored.</param> private void WaitUntilReceiversReplyOrTimeOut(object state, bool timeOut) { // check whether we have any unreplied true multicast-enabled receivers bool unrepliedReceivers = false; lock (this) { if (this.Failed.Count > 0 && !this._secondStagePerformed) { foreach (DictionaryEntry entry in this.Failed) { // fixed in 2.2 version string uri = (string)entry.Key; ReceiverInfo receiverInfo = this._dispatcher.GetReceiverInfo(uri); int numberOfFails = 0; if (receiverInfo != null) { lock (receiverInfo) { numberOfFails = ++receiverInfo.NumberOfFails; } } if (this._dispatcher.MaximumNumberOfConsecutiveFailsToExcludeReceiverAutomatically != 0 && numberOfFails >= this._dispatcher.MaximumNumberOfConsecutiveFailsToExcludeReceiverAutomatically) { this._dispatcher.Remove(uri); } // set time-out exception OperationException operationException = entry.Value as OperationException; if (operationException != null && operationException.OperationErrorMessage != null && operationException.OperationErrorMessage.ErrorIdentifier == "GenuineChannels.Exception.Broadcast.RemoteEndPointDidNotReplyForTimeOut") { unrepliedReceivers = true; break; } } } } if (unrepliedReceivers) { this.SendMessageToFailedReceiversDirectly(); this.StartReceiving(); return; } // LOG: BinaryLogWriter binaryLogWriter = GenuineLoggingServices.BinaryLogWriter; if (binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0) { binaryLogWriter.WriteBroadcastEngineEvent(LogCategory.BroadcastEngine, "ResultCollector.WaitUntilReceiversReplyOrTimeOut", LogMessageType.BroadcastInvocationCompleted, null, null, null, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, false, this._dispatcher, this, false, null, null, null, "The broadcast invocation is completed."); } // to stop receiving info this.AllMessagesReceived.Set(); if (this._broadcastCallFinishedHandler != null) { this._broadcastCallFinishedHandler(this._dispatcher, this._iMessage, this); } }
/// <summary> /// Writes down response came from the remote host. /// </summary> /// <param name="mbrUri">The uri of the remote MBR.</param> /// <param name="returnMessage">The received message or a null reference.</param> /// <param name="ex">The exception occurred during sending or receiving.</param> public void ParseResult(string mbrUri, IMethodReturnMessage returnMessage, Exception ex) { // if time-out has expired if (this.AllMessagesReceived.WaitOne(0, false)) { return; } // to increase or zero the number of consecutive fails ReceiverInfo receiverInfo = this._dispatcher.GetReceiverInfo(mbrUri); BinaryLogWriter binaryLogWriter = GenuineLoggingServices.BinaryLogWriter; // if an exception is received Exception exception = null; if (ex != null || (returnMessage != null && returnMessage.Exception != null)) { exception = ex != null ? ex : returnMessage.Exception; HostInformation dbgRemoteHost = (receiverInfo == null ? null : receiverInfo.DbgRemoteHost); string numberOfFails = (receiverInfo == null ? string.Empty : receiverInfo.NumberOfFails.ToString()); // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0) { binaryLogWriter.WriteBroadcastEngineEvent(LogCategory.BroadcastEngine, "ResultCollector.ParseResult", LogMessageType.BroadcastResponseParsed, exception, null, dbgRemoteHost, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, false, this._dispatcher, this, false, receiverInfo, numberOfFails, "false", "The exception is received in response to the broadcast. NumberOfFails: {0}.", numberOfFails); } } // if it's a message that the invocation was repeated, ignore it if (exception is OperationException) { OperationException operationException = (OperationException)exception; if (operationException.OperationErrorMessage.ErrorIdentifier == "GenuineChannels.Exception.Broadcast.CallHasAlreadyBeenMade") { return; } } lock (this) { // if successful response from this object has already been received this.UnrepliedReceivers.Remove(mbrUri); if (this.Successful.ContainsKey(mbrUri)) { return; } } lock (this) { // if an exception is received if (exception != null) { this.Failed[mbrUri] = exception; if (receiverInfo != null) { lock (receiverInfo) { if (receiverInfo.GeneralBroadcastSender == null && this._dispatcher.MaximumNumberOfConsecutiveFailsToExcludeReceiverAutomatically != 0 && receiverInfo.NumberOfFails >= this._dispatcher.MaximumNumberOfConsecutiveFailsToExcludeReceiverAutomatically) { // exclude it this._dispatcher.Remove(receiverInfo.MbrObject); } } } } else { // successful response this.Successful[mbrUri] = returnMessage; this.Failed.Remove(mbrUri); // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0) { HostInformation dbgRemoteHost = (receiverInfo == null ? null : receiverInfo.DbgRemoteHost); binaryLogWriter.WriteBroadcastEngineEvent(LogCategory.BroadcastEngine, "ResultCollector.ParseResult", LogMessageType.BroadcastResponseParsed, null, null, dbgRemoteHost, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, false, this._dispatcher, this, false, receiverInfo, null, "true", "The successful response is received."); } if (receiverInfo != null) { lock (receiverInfo) { receiverInfo.NumberOfFails = 0; } } } if (this.UnrepliedReceivers.Count == 0) { this.AllMessagesReceived.Set(); } } }
/// <summary> /// Registers the receiver and associate the provided object with it. /// Returns false if the receiver has already been registered. /// WARNING: does not check whether the receiver supports the required interface (via Reflection) /// because this check requires client's dll. /// </summary> /// <param name="obj">The receiver being registered.</param> /// <param name="tag">The object associated with the receiver. This object is accessible when receiver is being unregistered or during filtering.</param> /// <param name="remoteGenuineUri">The uri of the remote host provided by any of Genuine Channels.</param> /// <param name="transportContext">The transport context of the remote host.</param> /// <returns>False if the receiver has been already registered.</returns> public bool Add(MarshalByRefObject obj, object tag, string remoteGenuineUri, ITransportContext transportContext) { if (obj == null) { throw new ArgumentNullException("obj"); } BinaryLogWriter binaryLogWriter = GenuineLoggingServices.BinaryLogWriter; // check if it is in the list string uri = RemotingServices.GetObjectUri(obj); if (uri == null && !RemotingServices.IsObjectOutOfAppDomain(obj)) { // it was not marshalled RemotingServices.Marshal(obj); uri = RemotingServices.GetObjectUri(obj); } using (ReaderAutoLocker reader = new ReaderAutoLocker(this._readerWriterLock)) { if (this._receivers.ContainsKey(uri)) { return(false); } } // this check can not be performed because client's dll is required // // check on the interface // bool supportInterface = false; // foreach(Type interfaceType in obj.GetType().GetInterfaces()) // if (interfaceType == this._interfaceToSupport) // { // supportInterface = true; // break; // } // if (! supportInterface) // throw GenuineExceptions.Get_Broadcast_ObjectDoesNotSupportDestinationInterface(); // adds the object to the receiver list ReceiverInfo receiverInfo = new ReceiverInfo(); receiverInfo.MbrObject = obj; receiverInfo.MbrUri = uri; receiverInfo.Tag = tag; if (binaryLogWriter != null) { try { if (receiverInfo.MbrObject != null) { receiverInfo.DbgRemoteHost = GenuineUtility.FetchHostInformationFromMbr(receiverInfo.MbrObject); } } catch (Exception ex) { binaryLogWriter.WriteImplementationWarningEvent("Dispatcher.Add", LogMessageType.Error, ex, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, "Can't get HostInformation from MbrObject."); } } ObjRef objRef = receiverInfo.MbrObject.CreateObjRef(typeof(MarshalByRefObject)); receiverInfo.Local = objRef.IsFromThisAppDomain(); // cache object's info to speed up sending thru Genuine Channels if (!receiverInfo.Local) { if (remoteGenuineUri != null) { receiverInfo.IClientChannelSink = new GenuineTcpClientTransportSink(remoteGenuineUri, transportContext); } else { // check whether the client sink has registered itself on this MBR receiverInfo.IClientChannelSink = ChannelServices.GetChannelSinkProperties(obj)["GC_TS"] as IClientChannelSink; if (receiverInfo.IClientChannelSink == null) { throw GenuineExceptions.Get_Broadcast_ClientSinkIsUnknown(); } } // object uri receiverInfo.SerializedObjRef = objRef; // // and shell's uri // string shellUri; // ITransportContext iTransportContext; // GenuineUtility.FetchChannelUriFromMbr(obj, out shellUri, out iTransportContext); // if (shellUri == null) // throw GenuineExceptions.Get_Send_NoSender(objRef.URI); // // receiverInfo.ReceiverUri = shellUri; } // LOG: if (binaryLogWriter != null && binaryLogWriter[LogCategory.BroadcastEngine] > 0) { binaryLogWriter.WriteBroadcastEngineEvent(LogCategory.BroadcastEngine, "Dispatcher.Add", LogMessageType.BroadcastRecipientAdded, null, null, receiverInfo.DbgRemoteHost, null, GenuineUtility.CurrentThreadId, Thread.CurrentThread.Name, null, null, false, this, null, true, receiverInfo, null, null, "The broadcast recipient is added."); } // register the sponsor to prevent unexpected reclaiming ILease lease = (ILease)RemotingServices.GetLifetimeService(obj); if (lease != null) { lease.Register(this.GlobalSponsor); } // and register it using (WriterAutoLocker writer = new WriterAutoLocker(this._readerWriterLock)) { this._cachedReceiversInfoArray = null; this._receivers[uri] = receiverInfo; } return(true); }