Example #1
1
        /// <summary>
        /// Exchange messages with Outlook.
        /// </summary>
        private void ChatWithOutlook()
        {
            Debug.Assert(m_msgQueue.Count == 0);
            Debug.Assert(m_chattingFlag);

            try
            {
                AnpTransport transport = new AnpTransport(m_outlookSock);

                while (true)
                {
                    if (!transport.isReceiving) transport.beginRecv();
                    if (!transport.isSending && m_msgQueue.Count != 0) transport.sendMsg(m_msgQueue.Dequeue());
                    SelectSockets select = new SelectSockets();
                    select.AddRead(m_outlookSock);
                    if (transport.isSending) select.AddWrite(m_outlookSock);
                    Block(select);
                    transport.doXfer();

                    if (transport.doneReceiving)
                    {
                        OutlookUiThreadMsg msg = new OutlookUiThreadMsg(m_broker, OutlookBrokerMsgType.ReceivedMsg);
                        msg.Msg = transport.getRecv();
                        PostToUI(msg);
                    }
                }
            }

            catch (Exception ex)
            {
                m_chattingFlag = false;
                CloseOutlookSock();
                m_msgQueue.Clear();
                if (ex is WorkerCancellationException) throw;
                OutlookUiThreadMsg msg = new OutlookUiThreadMsg(m_broker, OutlookBrokerMsgType.Disconnected);
                msg.Ex = ex;
                PostToUI(msg);
            }
        }
Example #2
0
 /// <summary>
 /// Wait for one of the sockets specified to become ready, for a message
 /// to arrive or for the thread to be cancelled. Be careful not to call
 /// Block() while handling a message, since this method does not handle
 /// recursivity. Do not call this method after it has thrown an exception.
 /// </summary>
 protected void Block(SelectSockets set)
 {
     Debug.Assert(!BlockedFlag);
     BlockedFlag = true;
     set.AddRead(SocketPair[1]);
     set.Select();
     FlushWakeUp();
     CheckCancellation();
     CheckMessages();
     BlockedFlag = false;
 }
Example #3
0
File: Tunnel.cs Project: tmbx/kwm
 /// <summary>
 /// Block until the tunnel is connected or a timeout occurs. If the tunnel
 /// is connected, a new AnpTransport is created and the method returns true.
 /// Otherwise, the method returns false.
 /// </summary>
 /// <param name="timeout">Microseconds to wait in the Select.</param>
 public bool CheckConnect(int timeout)
 {
     // FIXME : loop to call tunnel.CheckTls()
     // at regular intervals.
     SelectSockets select = new SelectSockets();
     select.Timeout = timeout;
     select.AddRead(tunnel.Sock);
     tunnel.CheckTls();
     select.Select();
     if (select.ReadSockets.Contains(tunnel.Sock))
     {
         CreateTransport();
         return true;
     }
     return false;
 }
Example #4
0
        /// <summary>
        /// Run one pass of the main loop.
        /// </summary>
        private void RunPass()
        {
            // Wait for a command.
            while (m_commandQueue.Count == 0) Block(new SelectSockets());

            // Get the next command.
            KmodThreadCommand command = m_commandQueue.Dequeue();

            // Send the command.
            m_transport.sendMsg(command.Msg);
            while (true)
            {
                m_transport.doXfer();
                if (!m_transport.isSending) break;
                SelectSockets select = new SelectSockets();
                select.AddWrite(m_kmodSock);
                Block(select);
            }

            // We're done.
            if (!command.HaveResultFlag) return;

            // Wait for the results or the next command.
            bool firstFlag = true;
            while (m_commandQueue.Count == 0)
            {
                if (!m_transport.isReceiving) m_transport.beginRecv();
                m_transport.doXfer();

                // Push the next result.
                if (m_transport.doneReceiving)
                {
                    lock (Mon)
                    {
                        m_elementQueue.Enqueue(m_transport.getRecv());
                        Monitor.Pulse(Mon);
                    }

                    // Send the notification that results are ready for this command.
                    if (firstFlag)
                    {
                        firstFlag = false;
                        PostToUI(new KmodThreadNotif(m_broker, command));
                    }
                }

                // Wait for the next result or the next command.
                else
                {
                    SelectSockets select = new SelectSockets();
                    select.AddRead(m_kmodSock);
                    Block(select);
                }
            }
        }
Example #5
0
        /// <summary>
        /// Analyse the result of the select() call for the specified KAS.
        /// </summary>
        private void UpdateStateAfterSelect(KcmKas k, SelectSockets selectSockets)
        {
            try
            {
                k.CheckNoMessageReceivedInvariant();

                // We have nothing to do if we don't have an established TCP
                // connection.
                if (k.ConnStatus != KcmKasConnectionStatus.Connected &&
                    k.ConnStatus != KcmKasConnectionStatus.RoleReply) return;

                // Perform transfers only if the socket is ready.
                Debug.Assert(k.Tunnel.Sock != null);
                if (!selectSockets.InReadOrWrite(k.Tunnel.Sock)) return;

                // Do up to 20 transfers (the limit exists for quenching purposes).
                for (int i = 0; i < 20; i++)
                {
                    // Send a message if possible.
                    k.SendNextQueuedMsgIfNeeded();

                    // Remember if we are sending a message.
                    bool sendingFlag = k.Tunnel.IsSendingMessage();

                    // Do transfers.
                    k.Tunnel.DoXfer();

                    // Stop if no message has been received and no message has been sent.
                    if (!k.Tunnel.HasReceivedMessage() &&
                        (!sendingFlag || k.Tunnel.IsSendingMessage())) break;

                    // Process the message received.
                    if (k.Tunnel.HasReceivedMessage()) ProcessIncomingKasMessage(k, k.Tunnel.GetMsg());
                }

                k.CheckNoMessageReceivedInvariant();
            }

            catch (Exception ex)
            {
                HandleDisconnectedKas(k, ex);
            }
        }
Example #6
0
        /// <summary>
        /// Add the socket of the KAS in the select sets as needed and manage
        /// ktlstunnel.exe processes.
        /// </summary>
        private void PrepareStateForSelect(KcmKas k, SelectSockets selectSockets, bool quenchFlag,
            ref bool connWatchFlag)
        {
            // Note: the KAS should never have received a message when this function
            // is called. The function UpdateStateAfterSelect() is responsible for
            // doing all the transfers and handling any message received after these
            // transfers.
            try
            {
                k.CheckNoMessageReceivedInvariant();

                if (k.ConnStatus == KcmKasConnectionStatus.Scheduled)
                {
                    // Start ktlstunnel.exe.
                    k.ConnStatus = KcmKasConnectionStatus.Connecting;
                    k.Tunnel.BeginConnect();
                }

                if (k.ConnStatus == KcmKasConnectionStatus.Connecting)
                {
                    // The TCP connection is now open.
                    if (k.Tunnel.CheckConnect(0))
                    {
                        // Send the select role command.
                        k.SendSelectRoleMsg();

                        // Wait for the reply to arrive.
                        k.ConnStatus = KcmKasConnectionStatus.RoleReply;
                    }

                    // Wait for the TCP connection to be established. We busy wait
                    // to monitor the status of ktlstunnel.exe regularly, to detect
                    // the case where the connection fails.
                    else connWatchFlag = true;
                }

                if (k.ConnStatus == KcmKasConnectionStatus.RoleReply)
                {
                    // Wait for the reply to arrive.
                    if (!quenchFlag) k.Tunnel.UpdateSelect(selectSockets);
                }

                if (k.ConnStatus == KcmKasConnectionStatus.Connected)
                {
                    // Send the next message, if possible.
                    k.SendNextQueuedMsgIfNeeded();
                    if (!quenchFlag) k.Tunnel.UpdateSelect(selectSockets);
                }

                k.CheckNoMessageReceivedInvariant();
            }

            catch (Exception ex)
            {
                HandleDisconnectedKas(k, ex);
            }
        }
Example #7
0
        /// <summary>
        /// Loop processing KASes.
        /// </summary>
        private void MainLoop()
        {
            while (true)
            {
                Debug.Assert(!MustReplyToWm());

                // Refresh the quench deadline if it depends on the amount of
                // time elapsed.
                if (m_quenchDeadline != DateTime.MinValue && m_quenchDeadline != DateTime.MaxValue)
                    m_wmNotifFlag = true;

                // If we were notified, process the WM messages. This refreshes
                // the quench deadline.
                if (m_wmNotifFlag)
                {
                    m_wmNotifFlag = false;
                    ProcessIncomingWmMessages();
                }

                Debug.Assert(!MustReplyToWm());

                // Determine whether we are quenched and the value of the
                // select timeout. By default we wait forever in select().
                bool quenchFlag = false;
                int timeout = -2;

                // Be quenched until we are notified.
                if (m_quenchDeadline == DateTime.MaxValue)
                    quenchFlag = true;

                // Be quenched up to the deadline we were given.
                else if (m_quenchDeadline != DateTime.MinValue)
                {
                    DateTime now = DateTime.Now;
                    if (m_quenchDeadline > now)
                    {
                        quenchFlag = true;
                        timeout = (int)(m_quenchDeadline - now).TotalMilliseconds;
                    }
                }

                // Prepare for call to select.
                bool connWatchFlag = false;
                SelectSockets selectSockets = new SelectSockets();
                foreach (KcmKas k in m_kasTree.Values) PrepareStateForSelect(k, selectSockets,
                                                                             quenchFlag, ref connWatchFlag);

                // Our state has changed. Notify the WM and recompute our state.
                if (MustReplyToWm())
                {
                    ReplyToWm();
                    continue;
                }

                // Reduce the timeout to account for ktlstunnel.exe.
                if (connWatchFlag) DecrementTimeout(ref timeout, 300);

                // Block in the call to select(). Note that we receive notifications
                // here.
                selectSockets.Timeout = timeout * 1000;
                Block(selectSockets);

                // If we are not quenched, perform transfers.
                if (!quenchFlag)
                {
                    foreach (KcmKas k in m_kasTree.Values) UpdateStateAfterSelect(k, selectSockets);
                    ReplyToWm();
                }
            }
        }
Example #8
0
        /// <summary>
        /// Block until the connection to Outlook is established.
        /// </summary>
        private void ConnectToOutlook()
        {
            Debug.Assert(!m_chattingFlag);

            Logging.Log("ConnectToOutlook() called.");
            while (!m_chattingFlag)
            {
                Logging.Log("In while loop.");
                // Close the Outlook socket if we have opened it inconclusively.
                CloseOutlookSock();

                try
                {
                    // Accept a connection.
                    SelectSockets select = new SelectSockets();
                    select.AddRead(m_listenSock);
                    Block(select);
                    if (!select.InRead(m_listenSock)) continue;
                    m_outlookSock = m_listenSock.Accept();
                    m_outlookSock.Blocking = false;

                    Logging.Log("About to read MSO auth data.");
                    // Read the authentication data. Timeout after 2 seconds.
                    DateTime startTime = DateTime.Now;
                    byte[] authSockData = new byte[m_secret.Length];
                    int nbRead = 0;
                    while (nbRead != m_secret.Length)
                    {
                        Logging.Log("In Read while loop");
                        select = new SelectSockets();
                        select.AddRead(m_outlookSock);
                        SetSelectTimeout(startTime, 2000, select, "no authentication data received");
                        Logging.Log("About to block");
                        Block(select);
                        Logging.Log("Out of block");
                        int r = Base.SockRead(m_outlookSock, authSockData, nbRead, m_secret.Length - nbRead);
                        if (r > 0) nbRead += r;
                        Logging.Log("End Read while loop");
                    }

                    if (!Base.ByteArrayEqual(m_secret, authSockData))
                        throw new Exception("invalid authentication data received");

                    Logging.Log("About to tell the broker we are connected.");
                    // Inform the broker that we're connected.
                    OutlookUiThreadMsg msg = new OutlookUiThreadMsg(m_broker, OutlookBrokerMsgType.Connected);
                    msg.SessionID = ++m_sessionID;
                    PostToUI(msg);

                    // We're now chatting.
                    m_chattingFlag = true;
                }

                catch (Exception ex)
                {
                    if (ex is WorkerCancellationException) throw;
                    Logging.Log(2, ex.Message);
                }
            }
        }
Example #9
0
File: Tunnel.cs Project: tmbx/kwm
        /// <summary>
        /// Send a message on the tunnel.
        /// </summary>
        protected void SendAnpMsg(AnpMsg m)
        {
            AnpTransport transfer = InternalAnpTunnel.GetTransport();
            Debug.Assert(transfer.isReceiving || transfer.doneReceiving);
            Debug.Assert(!transfer.isSending);
            transfer.sendMsg(m);

            while (transfer.isSending)
            {
                transfer.doXfer();

                if (transfer.isSending)
                {
                    SelectSockets set = new SelectSockets();
                    InternalAnpTunnel.UpdateSelect(set);
                    Block(set);
                }
            }
        }
Example #10
0
File: Tunnel.cs Project: tmbx/kwm
        protected override void Run()
        {
            // Connect the tunnel.
            InternalAnpTunnel = Helper.CreateTunnel();
            Tunnel tunnel = InternalAnpTunnel.GetTunnel();
            InternalAnpTunnel.BeginConnect(Host, Port);

            while (true)
            {
                SelectSockets set = new SelectSockets();
                set.Timeout = 100;
                tunnel.CheckTls();
                set.AddRead(tunnel.Sock);
                Block(set);
                if (set.ReadSockets.Contains(tunnel.Sock))
                {
                    InternalAnpTunnel.CreateTransport();
                    break;
                }
            }

            // Handle the tunnel.
            OnTunnelConnected();
        }
Example #11
0
File: Tunnel.cs Project: tmbx/kwm
        /// <summary>
        /// Retrieve a message from the tunnel.
        /// </summary>
        protected AnpMsg GetAnpMsg()
        {
            AnpTransport transfer = InternalAnpTunnel.GetTransport();
            Debug.Assert(transfer.isReceiving || transfer.doneReceiving);
            Debug.Assert(!transfer.isSending);

            while (!transfer.doneReceiving)
            {
                transfer.doXfer();

                if (!transfer.doneReceiving)
                {
                    SelectSockets set = new SelectSockets();
                    InternalAnpTunnel.UpdateSelect(set);
                    Block(set);
                }
            }

            AnpMsg msg = transfer.getRecv();
            transfer.beginRecv();
            return msg;
        }
Example #12
0
File: Tunnel.cs Project: tmbx/kwm
 /// <summary>
 /// Update the select set specified with the socket of the tunnel.
 /// </summary>
 public void UpdateSelect(SelectSockets select)
 {
     Debug.Assert(transport.isReceiving || transport.doneReceiving);
     if (transport.isSending)
         select.AddWrite(tunnel.Sock);
     if (transport.isReceiving && !transport.doneReceiving)
         select.AddRead(tunnel.Sock);
 }
Example #13
0
File: Tunnel.cs Project: tmbx/kwm
 /// <summary>
 /// Send an AnpMsg. This method blocks if a message is currently being
 /// transferred.
 /// </summary>
 /// <param name="msg"></param>
 public void SendMsg(AnpMsg msg)
 {
     Debug.Assert(transport.isReceiving || transport.doneReceiving);
     while (transport.isSending)
     {
         SelectSockets select = new SelectSockets();
         transport.doXfer();
         UpdateSelect(select);
         if (transport.isSending)
             select.Select();
     }
     transport.sendMsg(msg);
     transport.doXfer();
 }
Example #14
0
File: Tunnel.cs Project: tmbx/kwm
 /// <summary>
 /// Get an AnpMsg. This is a blocking method, unless a message has already
 /// been received.
 /// </summary>
 public AnpMsg GetMsg()
 {
     Debug.Assert(transport.isReceiving || transport.doneReceiving);
     while (!transport.doneReceiving)
     {
         SelectSockets select = new SelectSockets();
         transport.doXfer();
         UpdateSelect(select);
         if (!transport.doneReceiving)
             select.Select();
     }
     AnpMsg msg = transport.getRecv();
     transport.beginRecv();
     return msg;
 }
Example #15
0
 /// <summary>
 /// Helper method for StartKmod().
 /// </summary>
 private void SetSelectTimeout(DateTime startTime, int msec, SelectSockets select, String msg)
 {
     int remaining = msec - (int)(DateTime.Now - startTime).TotalMilliseconds;
     if (remaining < 0 ) throw new Exception(msg);
     select.Timeout = remaining * 1000;
 }
Example #16
0
        /// <summary>
        /// Start kmod and connect to it.
        /// </summary>
        private void StartKmod()
        {
            FileStream file = null;
            Socket listenSock = null;
            RegistryKey kwmRegKey = null;

            try
            {
                // Get the path to the kmod executable in the registry.
                kwmRegKey = Base.GetKwmLMRegKey();
                String Kmod = "\"" + (String)kwmRegKey.GetValue("InstallDir", @"C:\Program Files\Teambox\Teambox Manager") + "\\kmod\\kmod.exe\"";

                // The directory where KMOD will save logs and its database for use with the kwm.
                String KmodDir = Misc.GetKmodDirPath();
                Directory.CreateDirectory(KmodDir);

                // Start listening for kmod to connect when it'll be started.
                IPEndPoint endPoint = new IPEndPoint(IPAddress.Loopback, 0);
                listenSock = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                listenSock.Bind(endPoint);
                listenSock.Listen(1);
                int port = ((IPEndPoint)listenSock.LocalEndPoint).Port;

                // Start KMOD in debugging mode if our settings say so.
                String debug = Misc.ApplicationSettings.ktlstunnelLoggingLevel > 0 ? " -l 3" : "";
                String args = " -C kmod_connect -p " + port + debug + " -m 20000 -k \"" + KmodDir + "\"";
                String cmdLine = Kmod + args;
                Logging.Log("About to start kmod.exe: " + cmdLine);
                m_kmodProc = new RawProcess(cmdLine);
                m_kmodProc.InheritHandles = false;
                m_kmodProc.CreationFlags = (uint)Syscalls.CREATION_FLAGS.CREATE_NO_WINDOW;
                m_kmodProc.Start();

                // Wait for KMOD to connect for about 10 seconds.
                DateTime startTime = DateTime.Now;
                while (true)
                {
                    SelectSockets select = new SelectSockets();
                    select.AddRead(listenSock);
                    SetSelectTimeout(startTime, 10000, select, "no KMOD connection received");
                    Block(select);

                    if (select.InRead(listenSock))
                    {
                        m_kmodSock = listenSock.Accept();
                        m_kmodSock.Blocking = false;
                        break;
                    }
                }

                // Read the authentication data.
                byte[] authSockData = new byte[32];
                byte[] authFileData = new byte[32];

                startTime = DateTime.Now;
                int nbRead = 0;
                while (nbRead != 32)
                {
                    SelectSockets select = new SelectSockets();
                    select.AddRead(m_kmodSock);
                    SetSelectTimeout(startTime, 2000, select, "no authentication data received");
                    Block(select);
                    int r = Base.SockRead(m_kmodSock, authSockData, nbRead, 32 - nbRead);
                    if (r > 0) nbRead += r;
                }

                file = File.Open(KmodDir + "\\connect_secret", FileMode.Open);
                file.Read(authFileData, 0, 32);
                if (!Base.ByteArrayEqual(authFileData, authSockData))
                    throw new Exception("invalid authentication data received");

                // Set the transport.
                m_transport = new K3pTransport(m_kmodSock);
            }

            finally
            {
                if (file != null) file.Close();
                if (listenSock != null) listenSock.Close();
                if (kwmRegKey != null) kwmRegKey.Close();
            }
        }
Example #17
0
 /// <summary>
 /// Wait for one of the sockets specified to become ready, for a message
 /// to arrive or for the thread to be cancelled. Be careful not to call
 /// Block() while handling a message, since this method does not handle
 /// recursivity. Do not call this method after it has thrown an exception.
 /// </summary>
 protected void Block(SelectSockets set)
 {
     Debug.Assert(!BlockedFlag);
     BlockedFlag = true;
     set.AddRead(SocketPair[1]);
     set.Select();
     FlushWakeUp();
     CheckCancellation();
     CheckMessages();
     BlockedFlag = false;
 }