/// <summary> /// Returns the receiver associated with the specified uri. /// </summary> /// <param name="mbrUri">The uri associated with the receiver.</param> /// <returns>The receiver associated with the specified uri.</returns> public ReceiverInfo GetReceiverInfo(string mbrUri) { using (ReaderAutoLocker reader = new ReaderAutoLocker(this._readerWriterLock)) { return(this._receivers[mbrUri] as ReceiverInfo); } }
/// <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> /// Returns the receiver associated with the specified uri. /// </summary> /// <param name="uri">The uri associated with the receiver.</param> /// <returns>The receiver associated with the specified uri.</returns> public MarshalByRefObject FindObjectByUri(string uri) { using (ReaderAutoLocker reader = new ReaderAutoLocker(this._readerWriterLock)) { ReceiverInfo receiverInfo = this._receivers[uri] as ReceiverInfo; if (receiverInfo == null) { return(null); } return(receiverInfo.MbrObject); } }
/// <summary> /// Broadcasts message to all registered receivers. /// </summary> /// <param name="msg">The message to be broadcasted.</param> /// <returns></returns> public override IMessage Invoke(IMessage msg) { ResultCollector resultCollector = null; // broadcasting using (ReaderAutoLocker reader = new ReaderAutoLocker(this._dispatcher._readerWriterLock)) { resultCollector = new ResultCollector(this._dispatcher, this._dispatcher._receivers.Count + 3, msg); } resultCollector.PerformBroadcasting(msg); return(new ReturnMessage(resultCollector, null, 0, (LogicalCallContext)msg.Properties["__CallContext"], (IMethodCallMessage)msg)); }
/// <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> /// 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); }