Beispiel #1
0
        /// <summary>
        /// Initiates an asynchronous request/response transmission with a specific timeout.
        /// </summary>
        /// <param name="message">The request message.</param>
        /// <param name="timeout">The maximum time to wait for a response.</param>
        /// <param name="callback">The <see cref="AsyncCallback" /> delegate to be called when the operation completes (or <c>null</c>).</param>
        /// <param name="state">The application specific state (or <c>null</c>).</param>
        /// <returns>The <see cref="IAsyncResult" /> instance to be used to track the status of the operation.</returns>
        /// <remarks>
        /// <note>
        /// All successful calls to <see cref="BeginRequest(Message,TimeSpan,AsyncCallback,object)" /> must
        /// eventually be followed by a call to <see cref="EndRequest" />.
        /// </note>
        /// </remarks>
        public IAsyncResult BeginRequest(Message message, TimeSpan timeout, AsyncCallback callback, object state)
        {
            using (TimedLock.Lock(this))
            {
                ThrowIfDisposedOrNotOpen();
                ServiceModelHelper.ValidateTimeout(timeout);

                try
                {
                    using (MemoryStream ms = new MemoryStream(payloadEstimator.EstimateNextBufferSize()))
                    {
                        WcfEnvelopeMsg requestMsg = new WcfEnvelopeMsg();

                        encoder.WriteMessage(message, ms);
                        payloadEstimator.LastPayloadSize((int)ms.Length);

                        requestMsg.Payload = new ArraySegment <byte>(ms.GetBuffer(), 0, (int)ms.Length);
                        return(ChannelHost.Router.BeginQuery(ep, requestMsg, callback, state));
                    }
                }
                catch (Exception e)
                {
                    throw ServiceModelHelper.GetCommunicationException(e);
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Intitiates an asynchronous operation to send a reply to the context request.
        /// </summary>
        /// <param name="context">The <see cref="LillTekRequestContext" /> context.</param>
        /// <param name="message">The reply <see cref="Message" />.</param>
        /// <param name="callback">The <see cref="AsyncCallback" /> delegate to be called when the operation completes (or <c>null</c>).</param>
        /// <param name="state">Application defined state (or <c>null</c>).</param>
        /// <returns>The <see cref="IAsyncResult" /> to be used to track the status of the operation.</returns>
        /// <remarks>
        /// <note>
        /// Every successful call to <see cref="BeginReply(LillTekRequestContext,Message,AsyncCallback,object)" /> must eventually be followed by
        /// a call to <see cref="EndReply" />.
        /// </note>
        /// </remarks>
        public IAsyncResult BeginReply(LillTekRequestContext context, Message message, AsyncCallback callback, object state)
        {
            AsyncResult arReply;

            // This operation is inherently asynchronous at the LillTek Messaging level
            // so we'll complete the operation immediately.

            using (MemoryStream ms = new MemoryStream(payloadEstimator.EstimateNextBufferSize()))
            {
                WcfEnvelopeMsg replyMsg = new WcfEnvelopeMsg();

                encoder.WriteMessage(message, ms);
                payloadEstimator.LastPayloadSize((int)ms.Length);

                replyMsg.Payload = new ArraySegment <byte>(ms.GetBuffer(), 0, (int)ms.Length);

                using (TimedLock.Lock(this))
                {
                    if (pendingRequests.ContainsKey(context.MsgRequestContext.SessionID))
                    {
                        pendingRequests.Remove(context.MsgRequestContext.SessionID);
                    }

                    context.MsgRequestContext.Reply(replyMsg);
                }
            }

            arReply = new AsyncResult(null, callback, state);
            arReply.Started(ServiceModelHelper.AsyncTrace);
            arReply.Notify();

            return(arReply);
        }
Beispiel #3
0
        //---------------------------------------------------------------------
        // DuplexSession event handlers

        /// <summary>
        /// Handles messages received on the underlying LillTek <see cref="DuplexSession" /> session.
        /// </summary>
        /// <param name="session">The <see cref="DuplexSession" />.</param>
        /// <param name="msg">The received LillTek message.</param>
        private void OnSessionReceive(DuplexSession session, Msg msg)
        {
            WcfEnvelopeMsg envelopeMsg = msg as WcfEnvelopeMsg;

            if (envelopeMsg == null)
            {
                return;     // Discard anything but WCF messages
            }
            Enqueue(listener.DecodeMessage(envelopeMsg));
        }
Beispiel #4
0
 /// <summary>
 /// Decodes the WCF <see cref="Message" /> encapsulated within a LillTek <see cref="WcfEnvelopeMsg" />.
 /// </summary>
 /// <param name="msg">The LillTek message.</param>
 /// <returns>The WCF <see cref="Message" />.</returns>
 /// <exception cref="CommunicationException">Thrown if the message could not be decoded.</exception>
 public Message DecodeMessage(WcfEnvelopeMsg msg)
 {
     using (BlockStream bs = new BlockStream((Block)msg.Payload))
     {
         try
         {
             return(messageEncoderFactory.Encoder.ReadMessage(bs, ServiceModelHelper.MaxXmlHeaderSize));
         }
         catch (Exception e)
         {
             throw ServiceModelHelper.GetCommunicationException(e);
         }
     }
 }
Beispiel #5
0
        /// <summary>
        /// Synchronously sends a message on the output channel.
        /// </summary>
        /// <param name="message">The <see cref="Message" />.</param>
        /// <remarks>
        /// <note>
        /// This method does not guarantee delivery of the message.
        /// Messages can be silently dropped for reasons including lack of buffer
        /// space, network congestion, unavailable remote endpoint, etc.
        /// </note>
        /// </remarks>
        public void Send(Message message)
        {
            try
            {
                using (MemoryStream ms = new MemoryStream(payloadEstimator.EstimateNextBufferSize()))
                {
                    WcfEnvelopeMsg envelopeMsg = new WcfEnvelopeMsg();

                    encoder.WriteMessage(message, ms);
                    payloadEstimator.LastPayloadSize((int)ms.Length);

                    envelopeMsg.Payload = new ArraySegment <byte>(ms.GetBuffer(), 0, (int)ms.Length);
                    ChannelHost.Router.SendTo(ep, envelopeMsg);
                }
            }
            catch (Exception e)
            {
                throw ServiceModelHelper.GetCommunicationException(e);
            }
        }
Beispiel #6
0
        /// <summary>
        /// Called when the message router receives a LillTek message.
        /// </summary>
        /// <param name="msg">The received message.</param>
        private void OnReceive(Msg msg)
        {
            try
            {
                if (sessionMode)
                {
                    DuplexSessionMsg duplexMsg = msg as DuplexSessionMsg;

                    // Handle client session connection attempts.

                    if (duplexMsg != null)
                    {
                        OnSessionConnect(duplexMsg);
                        return;
                    }
                }
                else
                {
                    // Handle encapsulated WCF messages.

                    WcfEnvelopeMsg envelopeMsg = msg as WcfEnvelopeMsg;
                    Message        message;

                    if (envelopeMsg == null)
                    {
                        return;     // Discard non-envelope messages
                    }
                    message = DecodeMessage(envelopeMsg);

                    // Let the derived listener decide what to do with the message.

                    OnMessageReceived(message, envelopeMsg);
                }
            }
            catch (Exception e)
            {
                SysLog.LogException(e);
            }
        }
Beispiel #7
0
 /// <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>
 protected abstract void OnMessageReceived(Message message, WcfEnvelopeMsg msg);
Beispiel #8
0
        /// <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);
            }
        }
Beispiel #9
0
 /// <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)
 {
     throw new InvalidOperationException();
 }
Beispiel #10
0
 /// <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>
 protected override void OnMessageReceived(Message message, WcfEnvelopeMsg msg)
 {
 }
Beispiel #11
0
        /// <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);
            }
        }