Exemple #1
0
 /// <summary>
 /// If the tunnel is connected, a new AnpTransport is created and the
 /// method returns true. Otherwise, the method returns false.
 /// </summary>
 public bool CheckConnect()
 {
     SelectSockets select = new SelectSockets();
     select.Timeout = 0;
     select.AddRead(tunnel.Sock);
     tunnel.CheckTls();
     select.Select();
     if (select.ReadSockets.Contains(tunnel.Sock))
     {
         CreateTransport();
         return true;
     }
     return false;
 }
Exemple #2
0
        protected override void Run()
        {
            // Connect the tunnel.
            InternalAnpTunnel = new AnpTunnel(Host, Port);
            Tunnel tunnel = InternalAnpTunnel.GetTunnel();
            InternalAnpTunnel.BeginConnect(ReconnectHost, ReconnectPort);

            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();
        }
Exemple #3
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;
 }
Exemple #4
0
 /// <summary>
 /// Called when the channel is open before the call to select().
 /// </summary>
 public void BeforeSelectOpen(SelectSockets selectSockets)
 {
     PrepareNextMsgTransfer();
     Transport.UpdateSelect(selectSockets);
 }
Exemple #5
0
 public virtual void BeforeSelectHandshake(SelectSockets selectSockets)
 {
 }
Exemple #6
0
        /// <summary>
        /// Called before the call to select().
        /// </summary>
        public void BeforeSelect(SelectSockets selectSockets)
        {
            try
            {
                if (Status == EAnpThreadChannelStatus.Initial) BeforeSelectInitial(selectSockets);
                else if (Status == EAnpThreadChannelStatus.Connecting) BeforeSelectConnecting(selectSockets);
                else if (Status == EAnpThreadChannelStatus.Handshake) BeforeSelectHandshake(selectSockets);
                else if (Status == EAnpThreadChannelStatus.Open) BeforeSelectOpen(selectSockets);
            }

            catch (Exception ex)
            {
                HandleError(ex);
                selectSockets.LowerTimeout(0);
            }
        }
Exemple #7
0
 public virtual void AfterSelectHandshake(SelectSockets selectSockets)
 {
 }
Exemple #8
0
 public override void BeforeSelectHandshake(SelectSockets selectSockets)
 {
     double timeout = GetHandshakeTimeout();
     if (timeout <= 0) throw new Exception("timeout waiting for client authentication data");
     selectSockets.AddRead(Sock);
     selectSockets.LowerTimeout((int)timeout);
 }
Exemple #9
0
 /// <summary>
 /// Update the select set specified with the socket of the transport.
 /// </summary>
 public void UpdateSelect(SelectSockets selectSocket)
 {
     Debug.Assert(IsReceiving || DoneReceiving);
     if (IsSending) selectSocket.AddWrite(sock);
     if (IsReceiving && !DoneReceiving) selectSocket.AddRead(sock);
 }
Exemple #10
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;
 }
Exemple #11
0
        /// <summary>
        /// Analyse the result of the select() call for the specified KCD.
        /// </summary>
        private void UpdateStateAfterSelect(KcdThreadHost k, SelectSockets selectSockets)
        {
            try
            {
                k.CheckNoMessageReceivedInvariant();

                // We have nothing to do if we don't have an established TCP
                // connection.
                if (k.ConnStatus != KcdThreadConnStatus.Connected &&
                    k.ConnStatus != KcdThreadConnStatus.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()) ProcessIncomingKcdMessage(k, k.Tunnel.GetMsg());
                }

                k.CheckNoMessageReceivedInvariant();
            }

            catch (Exception ex)
            {
                HandleDisconnectedKcd(k, ex);
            }
        }
Exemple #12
0
        /// <summary>
        /// Add the socket of the KCD in the select sets as needed and manage
        /// ktlstunnel.exe processes.
        /// </summary>
        private void PrepareStateForSelect(KcdThreadHost k, SelectSockets selectSockets, bool quenchFlag,
            ref bool connWatchFlag)
        {
            // Note: the KCD 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 == KcdThreadConnStatus.Scheduled)
                {
                    // Start ktlstunnel.exe.
                    k.ConnStatus = KcdThreadConnStatus.Connecting;
                    k.Tunnel.BeginConnect();
                }

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

                        // Wait for the reply to arrive.
                        k.ConnStatus = KcdThreadConnStatus.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 == KcdThreadConnStatus.RoleReply)
                {
                    // Wait for the reply to arrive.
                    if (!quenchFlag) k.Tunnel.UpdateSelect(selectSockets);
                }

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

                k.CheckNoMessageReceivedInvariant();
            }

            catch (Exception ex)
            {
                HandleDisconnectedKcd(k, ex);
            }
        }
Exemple #13
0
        /// <summary>
        /// Loop processing KCDs.
        /// </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 the call to select.
                bool connWatchFlag = false;
                SelectSockets selectSockets = new SelectSockets();
                foreach (KcdThreadHost k in m_kcdTree.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 (KcdThreadHost k in m_kcdTree.Values) UpdateStateAfterSelect(k, selectSockets);
                    ReplyToWm();
                }
            }
        }
Exemple #14
0
        /// <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);
                }
            }
        }
Exemple #15
0
        /// <summary>
        /// Accept a connection after the call to select.
        /// </summary>
        private void AfterSelectListen(SelectSockets selectSockets)
        {
            if (!selectSockets.InRead(ListenSock)) return;
            Socket sock = null;

            try
            {
                sock = ListenSock.Accept();
                sock.Blocking = false;
            }

            catch (Exception)
            {
                return;
            }

            EAnpServerThreadChannel c = new EAnpServerThreadChannel(this, sock);
            ChannelTree[c.ChannelID] = c;
        }
Exemple #16
0
        /// <summary>
        /// Execute an iteration of the main loop.
        /// </summary>
        protected override void RunPass()
        {
            SelectSockets selectSockets = new SelectSockets();

            // Dispatch before the call to select().
            if (Channel == null) BeforeSelectNoChannel(selectSockets);
            else Channel.BeforeSelect(selectSockets);

            // Block.
            Block(selectSockets);

            // Dispatch after the call to select().
            if (Channel != null) Channel.AfterSelect(selectSockets);
        }
Exemple #17
0
        public override void AfterSelectHandshake(SelectSockets selectSockets)
        {
            // Determine the number of bytes to send.
            int nbLeft = Secret.Length - SecretPos;
            Debug.Assert(nbLeft != 0);

            // Read the remaining data.
            int r = KSocket.SockRead(Sock, ClientSecret, SecretPos, nbLeft);

            // We have read some data.
            if (r != -1) SecretPos += r;

            // We're not done yet.
            if (Secret.Length != SecretPos) return;

            // Verify the secret.
            if (!KUtil.ByteArrayEqual(Secret, ClientSecret))
                throw new Exception("invalid authentication data received");

            // The channel is now open.
            HandleChannelOpened();
        }
Exemple #18
0
 /// <summary>
 /// Called when there is no channel before the call to select().
 /// </summary>
 private void BeforeSelectNoChannel(SelectSockets selectSockets)
 {
     // Try to connect.
     if (TryConnectFlag)
     {
         TryConnectFlag = false;
         Channel = new EAnpClientThreadChannel(this);
         Channel.BeforeSelect(selectSockets);
     }
 }
Exemple #19
0
        /// <summary>
        /// Called after the call to select().
        /// </summary>
        public void AfterSelect(SelectSockets selectSockets)
        {
            try
            {
                if (Status == EAnpThreadChannelStatus.Handshake) AfterSelectHandshake(selectSockets);
                else if (Status == EAnpThreadChannelStatus.Open) AfterSelectOpen(selectSockets);
            }

            catch (Exception ex)
            {
                HandleError(ex);
            }
        }
Exemple #20
0
        /// <summary>
        /// Send some handshake data.
        /// </summary>
        public override void AfterSelectHandshake(SelectSockets selectSockets)
        {
            // Determine the number of bytes to send.
            int nbLeft = Secret.Length - SecretPos;
            Debug.Assert(nbLeft != 0);

            // Send the remaining data.
            int r = KSocket.SockWrite(Sock, Secret, SecretPos, nbLeft);

            // We have written some data.
            if (r != -1) SecretPos += r;

            // We're not done yet.
            if (Secret.Length != SecretPos) return;

            // The channel is now open.
            HandleChannelOpened();
        }
Exemple #21
0
        /// <summary>
        /// Called when the channel is open after the call to select().
        /// </summary>
        public void AfterSelectOpen(SelectSockets selectSockets)
        {
            // Perform transfers only if the socket is ready.
            if (!selectSockets.InReadOrWrite(Sock)) return;

            // Build the received message list.
            List<AnpMsg> recvList = new List<AnpMsg>();

            while (true)
            {
                // Prepare a transfer.
                PrepareNextMsgTransfer();

                // Remember if we are sending a message.
                bool sendingFlag = Transport.IsSending;

                // Do transfers.
                Transport.DoXfer();

                // Stop if no message has been received and no message has been sent.
                if (!Transport.DoneReceiving && (!sendingFlag || Transport.IsSending)) break;

                // Add the message received.
                if (Transport.DoneReceiving) recvList.Add(Transport.GetRecv());
            }

            // Dispatch the received messages.
            if (recvList.Count > 0) Worker.NotifyMsgReceived(ChannelID, recvList);
        }
Exemple #22
0
        /// <summary>
        /// Check if we are connected.
        /// </summary>
        public override void BeforeSelectConnecting(SelectSockets selectSockets)
        {
            // The socket is connected.
            if (Sock.Poll(0, SelectMode.SelectWrite))
            {
                Status = EAnpThreadChannelStatus.Handshake;
                selectSockets.LowerTimeout(0);
            }

            // The connection has failed.
            else if (Sock.Poll(0, SelectMode.SelectError))
            {
                throw new Exception("the connection to the KWM could not be established");
            }

            // Add the socket in the write set and wait forever.
            else
            {
                selectSockets.AddWrite(Sock);
            }
        }
Exemple #23
0
 public virtual void BeforeSelectConnecting(SelectSockets selectSockets)
 {
 }
Exemple #24
0
 /// <summary>
 /// Prepare to send handshake data.
 /// </summary>
 public override void BeforeSelectHandshake(SelectSockets selectSockets)
 {
     selectSockets.AddWrite(Sock);
 }
Exemple #25
0
 // Stubs.
 public virtual void BeforeSelectInitial(SelectSockets selectSockets)
 {
 }
Exemple #26
0
        /// <summary>
        /// Try to connect to the KWM.
        /// </summary>
        public override void BeforeSelectInitial(SelectSockets selectSockets)
        {
            // Get the connection info.
            ClientThread.GetConnectInfo();

            // Try to connect.
            Sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            Sock.Blocking = false;

            try
            {
                Sock.Connect(new IPEndPoint(IPAddress.Loopback, ClientThread.Port));
            }

            catch (SocketException ex)
            {
                // This exception will always happen after we try async
                // connect. Awesome API there.
                if (ex.SocketErrorCode != SocketError.WouldBlock) throw;
            }

            // We're now connecting.
            Status = EAnpThreadChannelStatus.Connecting;
            selectSockets.LowerTimeout(0);
        }
Exemple #27
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);
                }
            }
        }
Exemple #28
0
        protected override void RunPass()
        {
            SelectSockets selectSockets = new SelectSockets();
            SortedDictionary<UInt64, EAnpServerThreadChannel> tree =
                new SortedDictionary<UInt64, EAnpServerThreadChannel>(ChannelTree);

            // Dispatch before the call to select().
            selectSockets.AddRead(ListenSock);
            foreach (EAnpThreadChannel c in tree.Values) c.BeforeSelect(selectSockets);

            // Block.
            Block(selectSockets);

            // Dispatch after the call to select().
            foreach (EAnpThreadChannel c in tree.Values) c.AfterSelect(selectSockets);
            AfterSelectListen(selectSockets);
        }
Exemple #29
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 = KwmReg.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 = KwmPath.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 = KwmCfg.Cur.KtlstunnelLoggingLevel > 0 ? " -l 3" : "";
                String args = " -C kmod_connect -p " + port + debug + " -m 20000 -k \"" + KmodDir + "\"";
                String cmdLine = Kmod + args;
                KLogging.Log("About to start kmod.exe: " + cmdLine);
                m_kmodProc = new KProcess(cmdLine);
                m_kmodProc.InheritHandles = false;
                m_kmodProc.CreationFlags = (uint)KSyscalls.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 = KSocket.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 (!KUtil.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();
            }
        }
Exemple #30
0
        /// <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;
        }