示例#1
0
        /// <summary>
        /// Called by the router whenever it receives a message with a non-empty
        /// _SessionID.  This method dispatches the message to the associated session
        /// (if any).
        /// </summary>
        /// <param name="msg">The message.</param>
        /// <param name="sessionInfo">The session information associated with the handler.</param>
        public void OnMsg(Msg msg, SessionHandlerInfo sessionInfo)
        {
            ISession session;

            Assertion.Test(msg._SessionID != Guid.Empty);

            using (TimedLock.Lock(router.SyncRoot))
            {
                if ((msg._Flags & MsgFlag.ServerSession) != 0)
                {
                    serverSessions.TryGetValue(msg._SessionID, out session);
                }
                else
                {
                    clientSessions.TryGetValue(msg._SessionID, out session);
                }
            }

            if (session != null)
            {
                msg._Trace(router, 2, "SessionManager: Dispached", null);
                session.OnMsg(msg, sessionInfo);
            }
            else
            {
                msg._Trace(router, 2, "SessionManager: No session", null);
            }
        }
示例#2
0
        /// <summary>
        /// Handles message packets received on the socket.
        /// </summary>
        /// <param name="ar">The async result.</param>
        private void OnSocketReceive(IAsyncResult ar)
        {
            int cb;
            Msg msg = null;

            byte[]     msgBuf;
            int        cbMsg;
            IPEndPoint fromEP = NetworkBinding.Any;

            using (TimedLock.Lock(router.SyncRoot))
            {
                if (!isOpen)
                {
                    return;
                }

                try
                {
                    cb = sock.EndReceiveFrom(ar, ref recvEP);
                    if (cb > 0)
                    {
                        msgBuf = router.DecryptFrame(recvBuf, cb, out cbMsg);
                        msg    = Msg.Load(new EnhancedMemoryStream(msgBuf));

                        fromEP = (IPEndPoint)recvEP;
                        msg._SetFromChannel(new ChannelEP(transport, fromEP));
                    }
                }
                catch (MsgException)
                {
                    // Ignore messages that can't be parsed
                }
                catch (Exception e)
                {
                    SysLog.LogException(e);
                }

                // Initiate the receive of the next message

                if (sock.IsOpen)
                {
                    try
                    {
                        sock.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref recvEP, onSocketReceive, null);
                    }
                    catch (Exception e)
                    {
                        SysLog.LogException(e, "LillTek UDP message channel is no longer able to receive messages.");
                    }
                }
            }

            if (msg != null)
            {
                msg._Trace(router, 2, "UDP: Recv", string.Format("From: {0}", fromEP));
                msg._Trace(router, 0, "Receive", string.Empty);
                router.OnReceive(this, msg);
            }
        }
示例#3
0
        /// <summary>
        /// Transmits the message via the UDP broadcast client.
        /// </summary>
        /// <param name="toEP">The target endpoint.</param>
        /// <param name="msg">The message.</param>
        private void TransmitViaUdpBroadcast(ChannelEP toEP, Msg msg)
        {
            byte[] sendBuf;
            int    cbSend;
            int    cbMsg;

            msg._SetToChannel(toEP);
            msg._SetFromChannel(localEP);
            msg._Trace(router, 2, "UDP: Send", null);

            using (TimedLock.Lock(router.SyncRoot))
            {
                // Initiate transmission of the message

                cbMsg   = Msg.Save(new EnhancedMemoryStream(msgBuf), msg);
                sendBuf = router.EncryptFrame(msgBuf, cbMsg);
                cbSend  = sendBuf.Length;

                Assertion.Validate(cbSend <= TcpConst.MTU - UdpBroadcastClient.MessageEnvelopeSize, "Message larger than UDP MTU.");

                try
                {
                    broadcastClient.Broadcast(sendBuf);
                }
                catch
                {
                }
            }
        }
示例#4
0
        /// <summary>
        /// Completes the execution of an asynchronous query operation.
        /// </summary>
        /// <param name="ar">The async result returned by <see cref="BeginQuery" />.</param>
        /// <returns>The query response message.</returns>
        /// <remarks>
        /// <note>
        /// Each call to <see cref="BeginQuery" /> must be matched with
        /// a call to EndQuery.
        /// </note>
        /// </remarks>
        public Msg EndQuery(IAsyncResult ar)
        {
            var arQuery = (AsyncResult)ar;

            arQuery.Wait();

            try
            {
                if (arQuery.Exception != null)
                {
                    throw arQuery.Exception;
                }
#if TRACE
                if (error != null)
                {
                    query._Trace(base.Router, 2, "Q/R Finish", null, "Exception: {0}", error.ToString());
                }
                else
                {
                    var sb = new StringBuilder(512);

                    sb.Append("\r\nResponse:\r\n\r\n");
                    response._TraceDetails(base.Router, sb);

                    query._Trace(base.Router, 2, "Q/R Finish", "", sb.ToString());
                }
#endif
                Assertion.Test(error != null || response != null, "Either an error or a response should be present.");

                if (error != null)
                {
                    Helper.Rethrow(error);
                    throw null;
                }
                else
                {
                    return(response);
                }
            }
            finally
            {
                arQuery.Dispose();
            }
        }
示例#5
0
        /// <summary>
        /// Handles messages received from the UdpBroadcast client.
        /// </summary>
        /// <param name="sender">The UDP broadcast client.</param>
        /// <param name="args">Event arguments.</param>
        private void OnBroadcastReceive(object sender, UdpBroadcastEventArgs args)
        {
            Msg msg = null;

            byte[] msgBuf;
            int    cbMsg;
            int    cb;

            using (TimedLock.Lock(router.SyncRoot))
            {
                if (!isOpen)
                {
                    return;
                }

                try
                {
                    cb = args.Payload.Length;
                    if (cb > 0)
                    {
                        msgBuf = router.DecryptFrame(args.Payload, cb, out cbMsg);
                        msg    = Msg.Load(new EnhancedMemoryStream(msgBuf));

                        msg._SetFromChannel(new ChannelEP(transport, new IPEndPoint(args.SourceAddress, 0)));
                    }
                }
                catch (MsgException)
                {
                    // Ignore messages that can't be parsed
                }
                catch (Exception e)
                {
                    SysLog.LogException(e);
                }
            }

            if (msg != null)
            {
                msg._Trace(router, 2, "UDP: Broadcast Recv", string.Format("From: {0}", args.SourceAddress));
                msg._Trace(router, 0, "Receive", string.Empty);
                router.OnReceive(this, msg);
            }
        }
示例#6
0
        /// <summary>
        /// Initiates a network connection to the message router at the
        /// specified network endpoint and then initiates the transmission
        /// of the message once the connection is established.
        /// </summary>
        /// <param name="ep">The remote router's endpoint.</param>
        /// <param name="msg">The message to be sent (or <c>null</c>).</param>
        public void Connect(IPEndPoint ep, Msg msg)
        {
            using (TimedLock.Lock(router.SyncRoot))
            {
                Assertion.Test(sock == null);
                sock    = new EnhancedSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                localEP = new ChannelEP(Transport.Tcp, router.NormalizeEP(router.TcpEP));

                sock.NoDelay           = !router.TcpDelay;
                sock.SendBufferSize    = router.TcpSockConfig.SendBufferSize;
                sock.ReceiveBufferSize = router.TcpSockConfig.ReceiveBufferSize;

                if (router.FragmentTcp)
                {
                    sock.SendMax    = 1;
                    sock.ReceiveMax = 1;
                }

                // Queue the channel initialization message and the message passed

                Msg initMsg;

                initMsg      = new TcpInitMsg(router.RouterEP, new MsgRouterInfo(router), isUplink, router.TcpEP.Port);
                initMsg._TTL = 1;

                Serialize(initMsg);
                Enqueue(initMsg);

                try
                {
                    SetLastAccess();
                    remoteEP = new ChannelEP(Transport.Tcp, router.NormalizeEP(ep));

                    if (msg != null)
                    {
                        msg._SetToChannel(remoteEP);
                        msg._SetFromChannel(localEP);
                        msg._Trace(router, 2, "TCP: Queue", null);

                        Serialize(msg);
                        Enqueue(msg);
                    }

                    router.Trace(2, "TCP: Outbound", "LocalEP=" + localEP.NetEP.ToString() + " remoteEP=" + remoteEP.NetEP.ToString(), null);
                    sock.BeginConnect(remoteEP.NetEP, new AsyncCallback(OnConnect), null);
                }
                catch (Exception e)
                {
                    router.Trace(string.Format(null, "TCP: Connect Failed [{0}]", ep), e);
                    router.OnTcpClose(this);
                    Close();
                }
            }
        }
示例#7
0
        /// <summary>
        /// Private implementation of the Transmit() method that implements an
        /// option that disables queuing for the message passed.
        /// </summary>
        /// <param name="toEP">The target endpoint.</param>
        /// <param name="msg">The message.</param>
        /// <param name="queue">Indicates whether queuing should be enabled for this message.</param>
        private void Transmit(ChannelEP toEP, Msg msg, bool queue)
        {
            msg._SetToChannel(toEP);
            msg._SetFromChannel(localEP);
            msg._Trace(router, 2, "TCP: Send", null);

            // Serialize the message here rather than within the lock
            // below for better multiprocessor performance.

            Serialize(msg);

            // Initiate transmission of the message or queue it if other
            // messages are awaiting transmission (if queuing is enabled).

            try
            {
                using (TimedLock.Lock(router.SyncRoot))
                {
                    if (!connected || sending)
                    {
                        Enqueue(msg);
                        return;
                    }

                    // If there are already messages in the queue then add this
                    // message to the end of the queue and then dequeue a message
                    // from the front of the queue and send it.

                    if (queue && sendQueue.Count > 0)
                    {
                        Enqueue(msg);
                        msg = Dequeue();
                    }

                    // Initiate message transmission

                    sendBuf = msg._MsgFrame;
                    sending = true;
                    sendPos = 0;
                    cbSend  = sendBuf.Length;

                    sock.BeginSend(sendBuf, sendPos, cbSend, SocketFlags.None, onSend, null);
                }
            }
            catch (Exception e)
            {
                TraceException(e);
                router.OnTcpClose(this);
                Close();
            }
        }
示例#8
0
        /// <summary>
        /// Queues the message passed rather than initiating an
        /// immediate transmission.
        /// </summary>
        /// <param name="toEP">The target endpoint.</param>
        /// <param name="msg">The message to queue.</param>
        internal void QueueTo(ChannelEP toEP, Msg msg)
        {
            msg._SetToChannel(toEP);
            msg._SetFromChannel(localEP);
            msg._Trace(router, 2, "TCP: Queue", null);

            Serialize(msg);

            using (TimedLock.Lock(router.SyncRoot))
            {
                msg._SetToChannel(toEP);
                Enqueue(msg);
            }
        }
示例#9
0
        /// <summary>
        /// Handles server side messages.
        /// </summary>
        /// <param name="msg">The message.</param>
        private void OnServerMsg(Msg msg)
        {
            // If we haved a cached reply for this session then
            // resend it, otherwise ignore this message.

            if (base.Reply != null)
            {
                base.Reply._Trace(base.Router, 2, "Q/R Cached Reply", null);
                base.Router.Send(base.Reply.Clone());
            }
            else
            {
                msg._Trace(base.Router, 2, "Q/R Msg Ignored", null);
            }
        }
示例#10
0
        private AsyncResult arQuery;            // The query async result

        /// <summary>
        /// Initiates an asynchronous query operation by sending the message
        /// passed to the target endpoint.
        /// </summary>
        /// <param name="toEP">The target endpoint.</param>
        /// <param name="query">The query message.</param>
        /// <param name="callback">The delegate to be called when the operation completes (or <c>null</c>).</param>
        /// <param name="state">Application specific state (or <c>null</c>).</param>
        /// <returns>The async result used to track the operation.</returns>
        /// <remarks>
        /// <note>
        /// Each call to <see cref="BeginQuery" /> must be matched with a call to <see cref="EndQuery" />.
        /// </note>
        /// </remarks>
        public IAsyncResult BeginQuery(MsgEP toEP, Msg query, AsyncCallback callback, object state)
        {
            Assertion.Test(arQuery == null, "Cannot reuse a query session.");

            this.query = query;

            query._ToEP      = toEP.Clone(true);
            query._FromEP    = base.Router.RouterEP.Clone(true);
            query._SessionID = base.SessionID;
            query._Flags    |= MsgFlag.OpenSession | MsgFlag.ServerSession;

            if (base.Router.DeadRouterDetection)
            {
                query._Flags |= MsgFlag.ReceiptRequest;
            }

            retry     = 0;
            retryTime = base.StartTime + TimeSpan.FromTicks(base.Router.SessionTimeout.Ticks);
            arQuery   = new AsyncResult(base.SessionManager, callback, state);
            response  = null;
            error     = null;

            base.TTD       = DateTime.MaxValue;   // Client side QuerySessions handle their own lifespan
            base.IsRunning = true;

            try
            {
                query._Trace(base.Router, 2, "Q/R Query", null);
                base.SessionManager.ClientStart(this);
                base.Router.Send(query);
            }
            catch (Exception e)
            {
                AsyncResult arTemp;

                arQuery.Notify(e);
                arTemp  = arQuery;
                arQuery = null;

                base.IsRunning = false;

                return(arTemp);
            }

            arQuery.Started();
            return(arQuery);
        }
示例#11
0
        /// <summary>
        /// Handles client side messages.
        /// </summary>
        /// <param name="msg">The message.</param>
        private void OnClientMsg(Msg msg)
        {
            msg._Trace(base.Router, 2, "Q/R Client Recv", null);
            Assertion.Test((msg._Flags & MsgFlag.OpenSession) == 0);

            using (TimedLock.Lock(base.Router.SyncRoot))
            {
                if (arQuery == null)
                {
                    return;
                }

                // If the message is a SessionKeepAliveMsg then reset
                // the time-to-retry timer.

                var keepAliveMsg = msg as SessionKeepAliveMsg;

                if (keepAliveMsg != null)
                {
                    retryTime = SysTime.Now + keepAliveMsg.SessionTTL;
                    return;
                }

                // I'm going to assume that any other message received that is
                // associated with this session is the response so
                // set the response field and signal that the session
                // is finished.

                response = msg;
                arQuery.Notify();
                arQuery = null;

                base.IsRunning = false;

                // Tell the session manager

                base.SessionManager.OnFinished(this);
            }
        }
示例#12
0
        /// <summary>
        /// Transmits the message via the socket.
        /// </summary>
        /// <param name="toEP">The target endpoint.</param>
        /// <param name="msg">The message.</param>
        private void TransmitViaSocket(ChannelEP toEP, Msg msg)
        {
            int cbMsg;

            if (cloudEP != null && !multicastInit)
            {
                // Retry adding the socket to the multicast group if this didn't
                // work earlier.

                try
                {
                    this.sock.MulticastGroup = cloudEP.Address;
                    this.multicastInit       = true;
                }
                catch
                {
                    this.multicastInit = false;
                }
            }

            msg._SetToChannel(toEP);
            msg._SetFromChannel(localEP);
            msg._Trace(router, 2, "UDP: Send", null);

            using (TimedLock.Lock(router.SyncRoot))
            {
                if (sendMsg != null)
                {
                    // We're already in the process of transmitting
                    // a message so queue this one.

                    Enqueue(msg);
                    return;
                }

                // If there are already messages in the queue then queue
                // this one and then setup to transmit the first message
                // waiting in the queue.

                if (sendQueue.Count > 0)
                {
                    Enqueue(msg);
                    msg = sendQueue.Dequeue();
                }

                // Initiate transmission of the message

                sendMsg = msg;
                cbMsg   = Msg.Save(new EnhancedMemoryStream(msgBuf), sendMsg);
                sendBuf = router.EncryptFrame(msgBuf, cbMsg);
                cbSend  = sendBuf.Length;

                Assertion.Validate(cbSend <= TcpConst.MTU, "Message larger than UDP MTU.");

                try
                {
                    sock.BeginSendTo(sendBuf, 0, cbSend, SocketFlags.None, router.NormalizeEP(toEP.NetEP), onSend, null);
                }
                catch
                {
                    // Ignoring
                }
            }
        }