/// <summary> /// Called by the derived class when it has created a new channel to /// accept a message received by the base class and passed to the /// derived class via <see cref="OnMessageReceived" />. /// </summary> /// <param name="channel">The accepted channel.</param> protected void OnChannelCreated(TInternal channel) { bool abortChannel = false; using (TimedLock.Lock(this)) { // The derived class has accepted a new channel. If we have a // an AcceptChannel() or WaitFoprChannel() operation pending, complete // them in that order. if (acceptQueue.Count > 0) { AsyncResult <TInternal, object> arAccept = acceptQueue.Dequeue(); arAccept.Result = channel; arAccept.Notify(); return; } // Queue the accepted channel channelQueue.Enqueue(channel); // Complete the first queued wait operation, if there is one. if (waitQueue.Count > 0) { AsyncResult <bool, object> arWait; arWait = waitQueue.Dequeue(); arWait.Result = true; arWait.Notify(); } } if (abortChannel) { channel.Abort(); // Do this outside of the lock to be safe } }
/// <summary> /// Adds a message to the channel's receive queue, completing a /// pending receive related operation. /// </summary> /// <param name="message">The received message.</param> internal void Enqueue(Message message) { using (TimedLock.Lock(this)) { if (!base.CanAcceptMessages) { return; } // If there's a pending receive operation then have it // complete with the message. QueueArray <AsyncResult <Message, InputChannel> > receiveQueue = listener.ReceiveQueue; if (receiveQueue != null && receiveQueue.Count > 0) { AsyncResult <Message, InputChannel> arReceive; arReceive = receiveQueue.Dequeue(); arReceive.Result = message; arReceive.Notify(); return; } // There were no pending receive operations so queue the message. msgQueue.Enqueue(message); // Complete the first pending WaitForMessage() request, // if there is one queued. QueueArray <AsyncResult <bool, InputChannel> > waitQueue; waitQueue = listener.WaitForMessageQueue; if (waitQueue != null && waitQueue.Count > 0) { AsyncResult <bool, InputChannel> arWait; arWait = waitQueue.Dequeue(); arWait.Result = true; arWait.Notify(); } } }
/// <summary> /// Called when the base class receives a LillTek envelope message with an /// encapsulated WCF message from the router. Non-session oriented derived /// classes must implement this to accept a new channel or route the message /// to an existing channel. /// </summary> /// <param name="message">The decoded WCF <see cref="Message" />.</param> /// <param name="msg">The received LillTek <see cref="Msg" />.</param> /// <remarks> /// <para> /// This method takes different actions depending on whether there are /// any pending channel <b>WaitForMessage()</b> or <b>Receive()</b> requests. /// </para> /// <para> /// If there are pending message receive operations, then these will be completed /// and the message queued to the associated channel as is appropriate. /// </para> /// <para> /// Finally, if no pending message receive requests and the base class has a /// pending <b>WaitForChannel()</b> or <b>AcceptChannel()</b>, then the base class /// <see cref="LillTekChannelListener{IInputSessionChannel,InputSessionChannel}.OnChannelCreated" /> /// method will be called so that a new channel will be accepted. /// </para> /// <para> /// Finally, if there are no pending message receive requests or base channel /// channel accept related requests, the message will be queued internally. /// </para> /// </remarks> protected override void OnMessageReceived(Message message, WcfEnvelopeMsg msg) { InputChannel newChannel = null; if (base.State != CommunicationState.Opened) { return; } if (msg._SessionID != Guid.Empty) { return; // Reject messages that are part of a session } using (TimedLock.Lock(this)) { // Handle any pending channel Receive() operations first. if (receiveQueue.Count > 0) { AsyncResult <Message, InputChannel> arReceive; arReceive = receiveQueue.Dequeue(); arReceive.Result = message; arReceive.Notify(); return; } // Next, handle any pending channel WaitForMessage() operations. if (waitQueue.Count > 0) { AsyncResult <bool, InputChannel> arWait; // Queue the message to the input channel so it will assured // to be available when the WaitForMessage() completes and // the application calls Receive(). arWait = waitQueue.Dequeue(); arWait.Result = true; arWait.InternalState.Enqueue(message); arWait.Notify(); return; } // Queue the message. msgQueue.Enqueue(message); // Create new channel if there are pending channel accept // or wait operations. if (base.HasPendingChannelOperation) { newChannel = new InputChannel(this, new EndpointAddress(this.Uri)); AddChannel(newChannel); } } // Do this outside of the lock just to be safe if (newChannel != null) { base.OnChannelCreated(newChannel); } }
/// <summary> /// Called when the base class receives a LillTek envelope message with an /// encapsulated WCF message from the router. Non-session oriented derived /// classes must implement this to accept a new channel or route the message /// to an existing channel. /// </summary> /// <param name="message">The decoded WCF <see cref="Message" />.</param> /// <param name="msg">The received LillTek <see cref="Msg" />.</param> /// <remarks> /// <para> /// This method takes different actions depending on whether there are /// any pending channel <b>WaitForRequest()</b> or <b>ReceiveRequest()</b> requests. /// </para> /// <para> /// If there are pending request receive operations, then these will be completed /// and the rfequest information will be queued to the associated channel as is appropriate. /// </para> /// <para> /// Finally, if no pending request receive requests and the base class has a /// pending <b>WaitForChannel()</b> or <b>AcceptChannel()</b>, then the base class /// <see cref="LillTekChannelListener{IInputSessionChannel,InputSessionChannel}.OnChannelCreated" /> /// method will be called so that a new channel will be accepted. /// </para> /// <para> /// Finally, if there are no pending request receive requests or base channel /// channel accept related requests, the message will be queued internally. /// </para> /// </remarks> protected override void OnMessageReceived(Message message, WcfEnvelopeMsg msg) { RequestInfo requestInfo = new RequestInfo(message, msg.CreateRequestContext(), SysTime.Now + maxRequestQueueTime); ReplyChannel newChannel = null; if (base.State != CommunicationState.Opened) { return; } using (TimedLock.Lock(this)) { // Handle any pending channel ReceiveRequest() operations first. if (receiveQueue.Count > 0) { AsyncResult <RequestInfo, ReplyChannel> arReceive; arReceive = receiveQueue.Dequeue(); arReceive.Result = requestInfo; arReceive.Notify(); return; } // Next, handle any pending channel WaitForRequest() operations. if (waitQueue.Count > 0) { AsyncResult <bool, ReplyChannel> arWait; // Queue the request information to the input channel so it will assured // to be available when the WaitForRequest() completes and // the application calls ReceiveRequest(). arWait = waitQueue.Dequeue(); arWait.Result = true; arWait.InternalState.Enqueue(requestInfo); arWait.Notify(); return; } // Queue the request. requestQueue.Enqueue(requestInfo); // Create new channel if there are pending channel accept // or wait operations. if (base.HasPendingChannelOperation) { newChannel = new ReplyChannel(this, new EndpointAddress(this.Uri), base.MessageEncoder); AddChannel(newChannel); } } // Do this outside of the lock just to be safe if (newChannel != null) { base.OnChannelCreated(newChannel); } }