/// <summary> /// Handle a message received from a KCD. /// </summary> private void ProcessIncomingKcdMessage(KcdThreadHost k, AnpMsg msg) { if (k.ConnStatus == KcdThreadConnStatus.RoleReply) { if (msg.Type == KAnp.KANP_RES_FAIL_MUST_UPGRADE) { throw new EAnpExUpgradeKwm(); } else if (msg.Type != KAnp.KANP_RES_OK) { throw new Exception(msg.Elements[1].String); } else if (msg.Minor < KAnp.LastCompMinor) { throw new Exception("The KCD at " + k.KcdID.Host + " is too old and needs to be upgraded."); } else { HandleConnectedKcd(k, Math.Min(msg.Minor, KAnp.Minor)); } } else { m_toWmAnpMsgList.Add(new KcdAnpMsg(msg, k.KcdID)); } }
/// <summary> /// Process a control message received from the WM. /// </summary> private void ProcessWmControlMsg(KcdControlMsg msg) { Debug.Assert(msg is KcdConnectionRequest); KcdConnectionRequest req = (KcdConnectionRequest)msg; // Handle new KCD to connect. if (req.ConnectFlag) { Debug.Assert(!m_kcdTree.ContainsKey(req.KcdID)); m_kcdTree[req.KcdID] = new KcdThreadHost(req.KcdID); } // Disconnect the KCD, if we didn't disconnect it yet. else { if (!m_kcdTree.ContainsKey(req.KcdID)) { return; } KcdThreadHost kcd = m_kcdTree[req.KcdID]; if (kcd.ConnStatus == KcdThreadConnStatus.Disconnected) { return; } HandleDisconnectedKcd(kcd, null); } }
/// <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); } }
/// <summary> /// Mark the KCD as disconnected, add a control message for the KCD in /// the control message list and add the KCD to the disconnected list. /// </summary> private void HandleDisconnectedKcd(KcdThreadHost k, Exception ex) { if (ex != null) { KLogging.Log(2, "KCD " + k.KcdID.Host + " exception: " + ex.Message); } if (k.Tunnel != null) { k.Tunnel.Disconnect(); } k.ConnStatus = KcdThreadConnStatus.Disconnected; k.Ex = new EAnpExKcdConn(); m_toWmControlMsgList.Add(new KcdDisconnectionNotice(k.KcdID, k.Ex)); m_disconnectedList.Add(k); }
/// <summary> /// Process an ANP message received from the WM. /// </summary> private void ProcessWmAnpMsg(KcdAnpMsg msg) { // Ignore messages not destined to connected KCDs. if (!m_kcdTree.ContainsKey(msg.KcdID)) { return; } KcdThreadHost kcd = m_kcdTree[msg.KcdID]; if (kcd.ConnStatus != KcdThreadConnStatus.Connected) { return; } // Enqueue the message. kcd.SendQueue.Enqueue(msg.Msg); }
/// <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); } }
/// <summary> /// Mark the KCD as connected and add a control message for the KCD in /// the control message list. /// </summary> private void HandleConnectedKcd(KcdThreadHost k, UInt32 minor) { k.ConnStatus = KcdThreadConnStatus.Connected; m_toWmControlMsgList.Add(new KcdConnectionNotice(k.KcdID, minor)); }
/// <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); } }
/// <summary> /// Handle a message received from a KCD. /// </summary> private void ProcessIncomingKcdMessage(KcdThreadHost k, AnpMsg msg) { if (k.ConnStatus == KcdThreadConnStatus.RoleReply) { if (msg.Type == KAnp.KANP_RES_FAIL_MUST_UPGRADE) throw new EAnpExUpgradeKwm(); else if (msg.Type != KAnp.KANP_RES_OK) throw new Exception(msg.Elements[1].String); else if (msg.Minor < KAnp.LastCompMinor) throw new Exception("The KCD at " + k.KcdID.Host + " is too old and needs to be upgraded."); else HandleConnectedKcd(k, Math.Min(msg.Minor, KAnp.Minor)); } else m_toWmAnpMsgList.Add(new KcdAnpMsg(msg, k.KcdID)); }
/// <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); } }
/// <summary> /// Mark the KCD as disconnected, add a control message for the KCD in /// the control message list and add the KCD to the disconnected list. /// </summary> private void HandleDisconnectedKcd(KcdThreadHost k, Exception ex) { if (ex != null) KLogging.Log(2, "KCD " + k.KcdID.Host + " exception: " + ex.Message); if (k.Tunnel != null) k.Tunnel.Disconnect(); k.ConnStatus = KcdThreadConnStatus.Disconnected; k.Ex = new EAnpExKcdConn(); m_toWmControlMsgList.Add(new KcdDisconnectionNotice(k.KcdID, k.Ex)); m_disconnectedList.Add(k); }