diff --git a/KVMControl.cs b/KVMControl.cs index eb0101b..bc6206f 100644 --- a/KVMControl.cs +++ b/KVMControl.cs @@ -30,8 +30,8 @@ namespace MeshCentralRouter private bool remotepause = true; private Bitmap desktop = null; private Graphics desktopGraphics = null; - private uint screenWidth = 0; - private uint screenHeight = 0; + public uint screenWidth = 0; + public uint screenHeight = 0; private Pen RedPen = new Pen(System.Drawing.Color.Red); private Font DebugFont = new Font(FontFamily.GenericSansSerif, 14); private int compressionlevel = 60; // 60% compression @@ -502,12 +502,15 @@ namespace MeshCentralRouter public void Send(BinaryWriter bw) { //if (state == ConnectState.Disconnected) { RecycleBinaryWriter(bw); return; } - try + //try + //{ + if ((parent != null) && (parent.wc != null)) { parent.wc.SendBinary(((MemoryStream)bw.BaseStream).GetBuffer(), 0, (int)((MemoryStream)bw.BaseStream).Length); bytesent += (int)((MemoryStream)bw.BaseStream).Length; } - catch (Exception) { } + //} + //catch (Exception) { } RecycleBinaryWriter(bw); } diff --git a/KVMViewer.Designer.cs b/KVMViewer.Designer.cs index 6570ed8..f1e60c2 100644 --- a/KVMViewer.Designer.cs +++ b/KVMViewer.Designer.cs @@ -46,23 +46,6 @@ namespace MeshCentralRouter { this.components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(KVMViewer)); - this.mainMenu = new System.Windows.Forms.MenuStrip(); - this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripMenuItem(); - this.MenuItemConnect = new System.Windows.Forms.ToolStripMenuItem(); - this.MenuItemDisconnect = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMenuItem5 = new System.Windows.Forms.ToolStripSeparator(); - this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); - this.MenuItemExit = new System.Windows.Forms.ToolStripMenuItem(); - this.viewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.zoomtofitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.statusToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.debugToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMenuItem6 = new System.Windows.Forms.ToolStripSeparator(); - this.refreshToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.pauseToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.actionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.sendCtrlAltDelToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.mainStatusStrip = new System.Windows.Forms.StatusStrip(); this.mainToolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); @@ -73,133 +56,13 @@ namespace MeshCentralRouter this.zoomButton = new System.Windows.Forms.Button(); this.cadButton = new System.Windows.Forms.Button(); this.connectButton = new System.Windows.Forms.Button(); + this.consoleMessage = new System.Windows.Forms.Label(); this.resizeKvmControl = new MeshCentralRouter.KVMResizeControl(); - this.mainMenu.SuspendLayout(); + this.consoleTimer = new System.Windows.Forms.Timer(this.components); this.mainStatusStrip.SuspendLayout(); this.topPanel.SuspendLayout(); this.SuspendLayout(); // - // mainMenu - // - this.mainMenu.BackColor = System.Drawing.SystemColors.Menu; - this.mainMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.toolStripMenuItem2, - this.viewToolStripMenuItem, - this.actionsToolStripMenuItem}); - resources.ApplyResources(this.mainMenu, "mainMenu"); - this.mainMenu.Name = "mainMenu"; - // - // toolStripMenuItem2 - // - this.toolStripMenuItem2.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.MenuItemConnect, - this.MenuItemDisconnect, - this.toolStripMenuItem5, - this.settingsToolStripMenuItem, - this.toolStripMenuItem1, - this.MenuItemExit}); - this.toolStripMenuItem2.Name = "toolStripMenuItem2"; - resources.ApplyResources(this.toolStripMenuItem2, "toolStripMenuItem2"); - this.toolStripMenuItem2.DropDownOpening += new System.EventHandler(this.toolStripMenuItem2_DropDownOpening); - // - // MenuItemConnect - // - this.MenuItemConnect.Name = "MenuItemConnect"; - resources.ApplyResources(this.MenuItemConnect, "MenuItemConnect"); - this.MenuItemConnect.Click += new System.EventHandler(this.MenuItemConnect_Click); - // - // MenuItemDisconnect - // - this.MenuItemDisconnect.Name = "MenuItemDisconnect"; - resources.ApplyResources(this.MenuItemDisconnect, "MenuItemDisconnect"); - this.MenuItemDisconnect.Click += new System.EventHandler(this.MenuItemDisconnect_Click); - // - // toolStripMenuItem5 - // - this.toolStripMenuItem5.Name = "toolStripMenuItem5"; - resources.ApplyResources(this.toolStripMenuItem5, "toolStripMenuItem5"); - // - // settingsToolStripMenuItem - // - this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem"; - resources.ApplyResources(this.settingsToolStripMenuItem, "settingsToolStripMenuItem"); - this.settingsToolStripMenuItem.Click += new System.EventHandler(this.settingsToolStripMenuItem_Click); - // - // toolStripMenuItem1 - // - this.toolStripMenuItem1.Name = "toolStripMenuItem1"; - resources.ApplyResources(this.toolStripMenuItem1, "toolStripMenuItem1"); - // - // MenuItemExit - // - this.MenuItemExit.Name = "MenuItemExit"; - resources.ApplyResources(this.MenuItemExit, "MenuItemExit"); - this.MenuItemExit.Click += new System.EventHandler(this.MenuItemExit_Click); - // - // viewToolStripMenuItem - // - this.viewToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.zoomtofitToolStripMenuItem, - this.statusToolStripMenuItem, - this.debugToolStripMenuItem, - this.toolStripMenuItem6, - this.refreshToolStripMenuItem, - this.pauseToolStripMenuItem}); - this.viewToolStripMenuItem.Name = "viewToolStripMenuItem"; - resources.ApplyResources(this.viewToolStripMenuItem, "viewToolStripMenuItem"); - this.viewToolStripMenuItem.DropDownOpening += new System.EventHandler(this.viewToolStripMenuItem_DropDownOpening); - // - // zoomtofitToolStripMenuItem - // - this.zoomtofitToolStripMenuItem.CheckOnClick = true; - this.zoomtofitToolStripMenuItem.Name = "zoomtofitToolStripMenuItem"; - resources.ApplyResources(this.zoomtofitToolStripMenuItem, "zoomtofitToolStripMenuItem"); - this.zoomtofitToolStripMenuItem.CheckStateChanged += new System.EventHandler(this.zoomtofitToolStripMenuItem_CheckStateChanged); - // - // statusToolStripMenuItem - // - this.statusToolStripMenuItem.Checked = true; - this.statusToolStripMenuItem.CheckOnClick = true; - this.statusToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; - this.statusToolStripMenuItem.Name = "statusToolStripMenuItem"; - resources.ApplyResources(this.statusToolStripMenuItem, "statusToolStripMenuItem"); - this.statusToolStripMenuItem.CheckedChanged += new System.EventHandler(this.statusToolStripMenuItem_CheckedChanged); - // - // debugToolStripMenuItem - // - this.debugToolStripMenuItem.CheckOnClick = true; - this.debugToolStripMenuItem.Name = "debugToolStripMenuItem"; - resources.ApplyResources(this.debugToolStripMenuItem, "debugToolStripMenuItem"); - this.debugToolStripMenuItem.Click += new System.EventHandler(this.debugToolStripMenuItem_Click); - // - // toolStripMenuItem6 - // - this.toolStripMenuItem6.Name = "toolStripMenuItem6"; - resources.ApplyResources(this.toolStripMenuItem6, "toolStripMenuItem6"); - // - // refreshToolStripMenuItem - // - this.refreshToolStripMenuItem.Name = "refreshToolStripMenuItem"; - resources.ApplyResources(this.refreshToolStripMenuItem, "refreshToolStripMenuItem"); - // - // pauseToolStripMenuItem - // - this.pauseToolStripMenuItem.Name = "pauseToolStripMenuItem"; - resources.ApplyResources(this.pauseToolStripMenuItem, "pauseToolStripMenuItem"); - // - // actionsToolStripMenuItem - // - this.actionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.sendCtrlAltDelToolStripMenuItem}); - this.actionsToolStripMenuItem.Name = "actionsToolStripMenuItem"; - resources.ApplyResources(this.actionsToolStripMenuItem, "actionsToolStripMenuItem"); - // - // sendCtrlAltDelToolStripMenuItem - // - this.sendCtrlAltDelToolStripMenuItem.Name = "sendCtrlAltDelToolStripMenuItem"; - resources.ApplyResources(this.sendCtrlAltDelToolStripMenuItem, "sendCtrlAltDelToolStripMenuItem"); - this.sendCtrlAltDelToolStripMenuItem.Click += new System.EventHandler(this.sendCtrlAltDelToolStripMenuItem_Click); - // // mainStatusStrip // this.mainStatusStrip.BackColor = System.Drawing.SystemColors.Menu; @@ -277,6 +140,12 @@ namespace MeshCentralRouter this.connectButton.UseVisualStyleBackColor = true; this.connectButton.Click += new System.EventHandler(this.MenuItemDisconnect_Click); // + // consoleMessage + // + resources.ApplyResources(this.consoleMessage, "consoleMessage"); + this.consoleMessage.ForeColor = System.Drawing.Color.Black; + this.consoleMessage.Name = "consoleMessage"; + // // resizeKvmControl // this.resizeKvmControl.BackColor = System.Drawing.Color.Gray; @@ -286,21 +155,24 @@ namespace MeshCentralRouter this.resizeKvmControl.StateChanged += new System.EventHandler(this.kvmControl_StateChanged); this.resizeKvmControl.DisplaysReceived += new System.EventHandler(this.resizeKvmControl_DisplaysReceived); // + // consoleTimer + // + this.consoleTimer.Interval = 5000; + this.consoleTimer.Tick += new System.EventHandler(this.consoleTimer_Tick); + // // KVMViewer // resources.ApplyResources(this, "$this"); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.BackColor = System.Drawing.Color.Gray; + this.Controls.Add(this.consoleMessage); this.Controls.Add(this.resizeKvmControl); this.Controls.Add(this.topPanel); this.Controls.Add(this.mainStatusStrip); - this.Controls.Add(this.mainMenu); this.Name = "KVMViewer"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Main_FormClosing); this.Load += new System.EventHandler(this.MainForm_Load); this.Resize += new System.EventHandler(this.MainForm_Resize); - this.mainMenu.ResumeLayout(false); - this.mainMenu.PerformLayout(); this.mainStatusStrip.ResumeLayout(false); this.mainStatusStrip.PerformLayout(); this.topPanel.ResumeLayout(false); @@ -310,43 +182,19 @@ namespace MeshCentralRouter } #endregion - - private MenuStrip mainMenu; - private ToolStripMenuItem toolStripMenuItem2; - private ToolStripMenuItem MenuItemConnect; - private ToolStripMenuItem MenuItemExit; - private ToolStripMenuItem MenuItemDisconnect; private StatusStrip mainStatusStrip; private ToolStripStatusLabel mainToolStripStatusLabel; private Timer updateTimer; - private ToolStripSeparator toolStripMenuItem1; - private ToolStripMenuItem viewToolStripMenuItem; - private ToolStripMenuItem statusToolStripMenuItem; - private ToolStripMenuItem debugToolStripMenuItem; - private ToolStripMenuItem settingsToolStripMenuItem; - private ToolStripMenuItem refreshToolStripMenuItem; - private ToolStripMenuItem pauseToolStripMenuItem; - private ToolStripSeparator toolStripMenuItem5; private KVMResizeControl resizeKvmControl; private ToolStripStatusLabel toolStripStatusLabel1; - private ToolStripMenuItem zoomtofitToolStripMenuItem; - private ToolStripMenuItem actionsToolStripMenuItem; - private ToolStripMenuItem sendCtrlAltDelToolStripMenuItem; private Panel topPanel; private Button connectButton; private Button cadButton; private Button zoomButton; private Button settingsButton; private ComboBox displaySelectComboBox; - private ToolStripSeparator toolStripMenuItem6; - - - - - - - - + private Label consoleMessage; + private Timer consoleTimer; } } diff --git a/KVMViewer.cs b/KVMViewer.cs index a738fe2..4873b57 100644 --- a/KVMViewer.cs +++ b/KVMViewer.cs @@ -15,15 +15,11 @@ limitations under the License. */ using System; -using System.IO; -using System.Text; using System.Drawing; -using System.Net.Sockets; -using System.Net.Security; using System.Windows.Forms; using System.Collections.Generic; using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; +using System.Web.Script.Serialization; using Microsoft.Win32; namespace MeshCentralRouter @@ -36,7 +32,9 @@ namespace MeshCentralRouter private int state = 0; private RandomNumberGenerator rand = RandomNumberGenerator.Create(); private string randomIdHex = null; + private bool sessionIsRecorded = false; public webSocketClient wc = null; + public Dictionary userSessions = null; public KVMViewer(MeshCentralServer server, NodeClass node) { @@ -46,11 +44,17 @@ namespace MeshCentralRouter this.server = server; kvmControl = resizeKvmControl.KVM; kvmControl.parent = this; + kvmControl.DesktopSizeChanged += KvmControl_DesktopSizeChanged; resizeKvmControl.ZoomToFit = true; UpdateStatus(); this.MouseWheel += MainForm_MouseWheel; } + private void KvmControl_DesktopSizeChanged(object sender, EventArgs e) + { + kvmControl.Visible = true; + } + private void Server_onStateChanged(int state) { UpdateStatus(); @@ -65,7 +69,6 @@ namespace MeshCentralRouter private void MainForm_Load(object sender, EventArgs e) { - this.Controls.Remove(mainMenu); this.Size = new Size(820, 480); resizeKvmControl.CenterKvmControl(false); topPanel.Visible = true; @@ -113,6 +116,7 @@ namespace MeshCentralRouter case webSocketClient.ConnectionStates.Connecting: { state = 1; + displayMessage(null); break; } case webSocketClient.ConnectionStates.Connected: @@ -120,6 +124,7 @@ namespace MeshCentralRouter state = 2; string u = "*/meshrelay.ashx?p=2&nodeid=" + node.nodeid + "&id=" + randomIdHex + "&rauth=" + server.rauthCookie; server.sendCommand("{ \"action\": \"msg\", \"type\": \"tunnel\", \"nodeid\": \"" + node.nodeid + "\", \"value\": \"" + u.ToString() + "\", \"usage\": 2 }"); + displayMessage(null); break; } } @@ -130,15 +135,50 @@ namespace MeshCentralRouter { if ((state == 2) && ((data == "c") || (data == "cr"))) { + if (data == "cr") { sessionIsRecorded = true; } state = 3; kvmControl.Send("2"); kvmControl.SendCompressionLevel(); kvmControl.SendPause(false); kvmControl.SendRefresh(); UpdateStatus(); + displayMessage(null); return; } if (state != 3) return; + + // Parse the received JSON + Dictionary jsonAction = new Dictionary(); + jsonAction = new JavaScriptSerializer().Deserialize>(data); + if ((jsonAction == null) || (jsonAction.ContainsKey("type") == false) || (jsonAction["type"].GetType() != typeof(string))) return; + + string action = jsonAction["type"].ToString(); + switch (action) + { + case "metadata": + { + if ((jsonAction.ContainsKey("users") == false) || (jsonAction["users"] == null)) return; + Dictionary usersex = (Dictionary)jsonAction["users"]; + userSessions = new Dictionary(); + foreach (string user in usersex.Keys) { userSessions.Add(user, (int)usersex[user]); } + UpdateStatus(); + break; + } + case "console": + { + string msg = null; + int msgid = -1; + if ((jsonAction.ContainsKey("msg")) && (jsonAction["msg"] != null)) { msg = jsonAction["msg"].ToString(); } + if (jsonAction.ContainsKey("msgid")) { msgid = (int)jsonAction["msgid"]; } + if (msgid == 1) { msg = "Waiting for user to grant access..."; } + if (msgid == 2) { msg = "Denied"; } + if (msgid == 3) { msg = "Failed to start remote terminal session"; } // , {0} ({1}) + if (msgid == 4) { msg = "Timeout"; } + if (msgid == 5) { msg = "Received invalid network data"; } + displayMessage(msg); + break; + } + } } private void Wc_onBinaryData(byte[] data, int offset, int length) @@ -162,6 +202,7 @@ namespace MeshCentralRouter // Connect MenuItemConnect_Click(null, null); } + displayMessage(null); } @@ -178,6 +219,8 @@ namespace MeshCentralRouter mainToolStripStatusLabel.Text = "Disconnected"; displaySelectComboBox.Visible = false; kvmControl.Visible = false; + kvmControl.screenWidth = 0; + kvmControl.screenHeight = 0; connectButton.Text = "Connect"; break; case 1: // Connecting @@ -193,15 +236,17 @@ namespace MeshCentralRouter connectButton.Text = "Disconnect"; break; case 3: // Connected - //string extras = "."; - //if (kvmControl.touchEnabled) extras = ", touch enabled."; - //mainToolStripStatusLabel.Text = string.Format("Connected. {0} tiles received, {1} tiles copied, {2} received, {3} sent{4}", kvmControl.tilecount, kvmControl.tilecopy, MeshUtils.GetKiloShortString((ulong)kvmControl.byterecv), MeshUtils.GetKiloShortString((ulong)kvmControl.bytesent), extras); - mainToolStripStatusLabel.Text = "Connected."; - kvmControl.Visible = true; + string label = "Connected"; + if (sessionIsRecorded) { label += ", Recorded Session"; } + if ((userSessions != null) && (userSessions.Count > 1)) { label += string.Format(", {0} users", userSessions.Count); } + label += "."; + mainToolStripStatusLabel.Text = label; connectButton.Text = "Disconnect"; kvmControl.SendCompressionLevel(); break; } + + cadButton.Enabled = (state == 3); } private void updateTimer_Tick(object sender, EventArgs e) @@ -222,11 +267,6 @@ namespace MeshCentralRouter node.desktopViewer = null; } - private void statusToolStripMenuItem_CheckedChanged(object sender, EventArgs e) - { - mainStatusStrip.Visible = statusToolStripMenuItem.Checked; - } - private void toolStripMenuItem2_DropDownOpening(object sender, EventArgs e) { //MenuItemConnect.Enabled = (kvmControl.State == KVMControl.ConnectState.Disconnected); @@ -235,17 +275,6 @@ namespace MeshCentralRouter //serviceDisconnectToolStripMenuItem.Enabled = (server != null && server.CurrentState != MeshSwarmServer.State.Disconnected); } - private void viewToolStripMenuItem_DropDownOpening(object sender, EventArgs e) - { - debugToolStripMenuItem.Checked = kvmControl.debugmode; - //pauseToolStripMenuItem.Checked = kvmControl.Pause; - } - - private void debugToolStripMenuItem_Click(object sender, EventArgs e) - { - if (kvmControl != null) kvmControl.debugmode = debugToolStripMenuItem.Checked; - } - private void kvmControl_StateChanged(object sender, EventArgs e) { UpdateStatus(); @@ -271,11 +300,6 @@ namespace MeshCentralRouter if (kvmControl != null) kvmControl.SendPause(WindowState == FormWindowState.Minimized); } - private void zoomtofitToolStripMenuItem_CheckStateChanged(object sender, EventArgs e) - { - resizeKvmControl.ZoomToFit = zoomtofitToolStripMenuItem.Checked; - } - private void sendCtrlAltDelToolStripMenuItem_Click(object sender, EventArgs e) { if (kvmControl != null) kvmControl.SendCtrlAltDel(); @@ -323,7 +347,7 @@ namespace MeshCentralRouter if (displayText == "All Displays") displaynum = 0xFFFF; if (displaynum != 0 || int.TryParse(displayText.Substring(8), out displaynum)) { - //if (kvmControl != null) kvmControl.SendDisplay(displaynum); + if (kvmControl != null) kvmControl.SendDisplay(displaynum); } } @@ -372,5 +396,27 @@ namespace MeshCentralRouter try { return Registry.GetValue(@"HKEY_CURRENT_USER\SOFTWARE\OpenSource\MeshRouter", name, "").ToString(); } catch (Exception) { return ""; } } + public delegate void displayMessageHandler(string msg); + public void displayMessage(string msg) + { + if (this.InvokeRequired) { this.Invoke(new displayMessageHandler(displayMessage), msg); return; } + if (msg == null) + { + consoleMessage.Visible = false; + consoleTimer.Enabled = false; + } + else + { + consoleMessage.Text = msg; + consoleMessage.Visible = true; + //consoleTimer.Enabled = true; + } + } + + private void consoleTimer_Tick(object sender, EventArgs e) + { + consoleMessage.Visible = false; + consoleTimer.Enabled = false; + } } } diff --git a/KVMViewer.resx b/KVMViewer.resx index 765329b..6271800 100644 --- a/KVMViewer.resx +++ b/KVMViewer.resx @@ -117,134 +117,12 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - 17, 17 - - - - 167, 22 - - - &Connect... - - - 167, 22 - - - &Disconnect - - - 164, 6 - - - 167, 22 - - - Session Settings... - - - 164, 6 - - - 167, 22 - - - E&xit - - - 59, 20 - - - &Control - - - 138, 22 - - - &Zoom-to-fit - - - 138, 22 - - - &Status - - - 138, 22 - - - &Debug - - - 135, 6 - - - - F5 - - - 138, 22 - - - &Refresh - - - F7 - - - 138, 22 - - - &Pause - - - 44, 20 - - - &View - - - 164, 22 - - - Send &Ctrl-Alt-Del - - - 59, 20 - - - Actions - - - 0, 0 - - - 1227, 24 - - - - 1 - - - menuStrip1 - - - mainMenu - - - System.Windows.Forms.MenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - - 3 - 127, 17 + - 1212, 17 + 1029, 17 --- @@ -258,14 +136,15 @@ v + False - 0, 787 + 0, 772 - 1227, 22 + 1044, 22 9 @@ -283,7 +162,7 @@ $this - 2 + 3 264, 17 @@ -312,6 +191,10 @@ 0 + + + NoControl + 288, 3 @@ -336,6 +219,9 @@ 1 + + NoControl + 193, 3 @@ -360,6 +246,9 @@ 2 + + NoControl + 98, 3 @@ -384,6 +273,9 @@ 3 + + NoControl + 3, 3 @@ -412,10 +304,10 @@ Top - 0, 24 + 0, 0 - 1227, 32 + 1044, 32 11 @@ -433,16 +325,52 @@ $this - 1 + 2 + + + True + + + Microsoft Sans Serif, 15.75pt + + + NoControl + + + 12, 59 + + + 70, 25 + + + 12 + + + label1 + + + False + + + consoleMessage + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 Fill - 0, 56 + 0, 32 - 1227, 731 + 1044, 740 10 @@ -451,14 +379,17 @@ resizeKvmControl - MeshCentralRouter.KVMResizeControl, MeshCentralRouter, Version=1.0.7529.21143, Culture=neutral, PublicKeyToken=null + MeshCentralRouter.KVMResizeControl, MeshCentralRouter, Version=1.0.7531.27756, Culture=neutral, PublicKeyToken=null $this - 0 + 1 + + 385, 17 + True @@ -466,7 +397,7 @@ 6, 13 - 1227, 809 + 1044, 794 @@ -902,102 +833,6 @@ Remote Desktop - - toolStripMenuItem2 - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - MenuItemConnect - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - MenuItemDisconnect - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - toolStripMenuItem5 - - - System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - settingsToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - toolStripMenuItem1 - - - System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - MenuItemExit - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - viewToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - zoomtofitToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - statusToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - debugToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - toolStripMenuItem6 - - - System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - refreshToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - pauseToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - actionsToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - sendCtrlAltDelToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - mainToolStripStatusLabel @@ -1016,6 +851,12 @@ System.Windows.Forms.Timer, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + consoleTimer + + + System.Windows.Forms.Timer, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + KVMViewer diff --git a/WebSocketClient.cs b/WebSocketClient.cs index 8f489e4..ef434cd 100644 --- a/WebSocketClient.cs +++ b/WebSocketClient.cs @@ -19,6 +19,7 @@ using System.IO; using System.Text; using System.Net.Sockets; using System.Net.Security; +using System.IO.Compression; using System.Collections.Generic; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; @@ -45,6 +46,11 @@ namespace MeshCentralRouter public bool xdebug = false; public bool xignoreCert = false; public string extraHeaders = null; + private MemoryStream inflateMemory; + private DeflateStream inflate; + private MemoryStream deflateMemory; + private static byte[] inflateEnd = { 0x00, 0x00, 0xff, 0xff }; + private static byte[] inflateStart = { 0x00, 0x00, 0x00, 0x00 }; public enum ConnectionStates { @@ -128,6 +134,7 @@ namespace MeshCentralRouter wsclient = new TcpClient(); wsclient.BeginConnect(url.Host, url.Port, new AsyncCallback(OnConnectSink), this); } + return true; } @@ -245,7 +252,9 @@ namespace MeshCentralRouter // Send the HTTP headers Debug("Websocket TLS setup, sending HTTP header..."); - string header = "GET " + url.PathAndQuery + " HTTP/1.1\r\nHost: " + url.Host + "\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n" + extraHeaders + "\r\n"; + //string header = "GET " + url.PathAndQuery + " HTTP/1.1\r\nHost: " + url.Host + "\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n" + extraHeaders + "\r\n"; + //string header = "GET " + url.PathAndQuery + " HTTP/1.1\r\nHost: " + url.Host + "\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Extensions: permessage-deflate; client_no_context_takeover; server_no_context_takeover\r\n" + extraHeaders + "\r\n"; + string header = "GET " + url.PathAndQuery + " HTTP/1.1\r\nHost: " + url.Host + "\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Extensions: permessage-deflate; client_no_context_takeover\r\n" + extraHeaders + "\r\n"; wsstream.Write(UTF8Encoding.UTF8.GetBytes(header)); // Start receiving data @@ -313,6 +322,14 @@ namespace MeshCentralRouter if ((parsedHeader == null) || (parsedHeader["_Path"] != "101")) { Debug("Websocket bad header."); return -1; } // Bad header, close the connection Debug("Websocket got setup upgrade header."); SetState(ConnectionStates.Connected); + + if ((parsedHeader.ContainsKey("sec-websocket-extensions") && (parsedHeader["sec-websocket-extensions"].IndexOf("permessage-deflate") >= 0))) + { + inflateMemory = new MemoryStream(); + inflate = new DeflateStream(inflateMemory, CompressionMode.Decompress); + deflateMemory = new MemoryStream(); + } + fragmentParsingState = 1; return len; // TODO: Technically we need to return the header length before UTF8 convert. } @@ -371,13 +388,32 @@ namespace MeshCentralRouter private void ProcessWsBuffer(byte[] data, int offset, int len, int op) { + MemoryStream mem = null; + if (((op & 0x40) != 0) && (inflateMemory != null)) + { + // This is a deflate compressed frame + inflateMemory.SetLength(0); + inflateMemory.Write(data, offset, len); + inflateMemory.Write(inflateEnd, 0, 4); + inflateMemory.Seek(0, SeekOrigin.Begin); + MemoryStream memoryStream = new MemoryStream(); + inflate.CopyTo(memoryStream); + data = memoryStream.GetBuffer(); + offset = 0; + len = (int)memoryStream.Length; + } + if ((op & 1) == 0) { + // This is a birnay frame Debug("Websocket got binary data, len = " + len); if (onBinaryData != null) { onBinaryData(data, offset, len); } } else { + // This is a string frame Debug("Websocket got string data, len = " + len); if (onStringData != null) { onStringData(UTF8Encoding.UTF8.GetString(data, offset, len)); } } + + if (mem != null) { mem.Dispose(); mem = null; } } private Dictionary ParseHttpHeader(string header) @@ -425,47 +461,47 @@ namespace MeshCentralRouter public void SendString(string data) { if (state != ConnectionStates.Connected) return; - - // Convert the string into a buffer with 4 byte of header space. - int len = UTF8Encoding.UTF8.GetByteCount(data); - byte[] buf = new byte[4 + len]; - UTF8Encoding.UTF8.GetBytes(data, 0, data.Length, buf, 4); - len = buf.Length - 4; - - // Check that everything is ok - if ((len < 1) || (len > 65535)) { Dispose(); return; } - - //Console.Write("Length: " + len + "\r\n"); - //System.Threading.Thread.Sleep(0); - - if (len < 126) - { - // Small fragment - buf[2] = 129; // Fragment op code (129 = text, 130 = binary) - buf[3] = (byte)(len & 0x7F); - //try { wsstream.BeginWrite(buf, 2, len + 2, new AsyncCallback(WriteWebSocketAsyncDone), args); } catch (Exception) { Dispose(); return; } - wsstream.Write(buf, 2, len + 2); - } - else - { - // Large fragment - buf[0] = 129; // Fragment op code (129 = text, 130 = binary) - buf[1] = 126; - buf[2] = (byte)((len >> 8) & 0xFF); - buf[3] = (byte)(len & 0xFF); - //try { wsstream.BeginWrite(buf, 0, len + 4, new AsyncCallback(WriteWebSocketAsyncDone), args); } catch (Exception) { Dispose(); return; } - wsstream.Write(buf, 0, len + 4); - } + byte[] buf = UTF8Encoding.UTF8.GetBytes(data); + SendFragment(buf, 0, buf.Length, 129); } - public void SendBinary(byte[] data, int offset, int len) + public void SendBinary(byte[] data, int offset, int len) { SendFragment(data, offset, len, 130); } + + // Fragment op code (129 = text, 130 = binary) + public void SendFragment(byte[] data, int offset, int len, byte op) { if (state != ConnectionStates.Connected) return; + byte[] buf; - // Convert the string into a buffer with 4 byte of header space. - byte[] buf = new byte[4 + len]; - Array.Copy(data, offset, buf, 4, len); - len = buf.Length - 4; + // If deflate is active, attempt to compress the data here. + if ((deflateMemory != null) && (len > 32)) + { + deflateMemory.SetLength(0); + deflateMemory.Write(inflateStart, 0, 4); + DeflateStream deflate = new DeflateStream(deflateMemory, CompressionMode.Compress, true); + deflate.Write(data, offset, len); + deflate.Dispose(); + deflate = null; + if (deflateMemory.Length < len) + { + // Use the compressed data + int newlen = (int)deflateMemory.Length; + buf = deflateMemory.GetBuffer(); + len = newlen - 4; + op |= 0x40; // Add compression op + } else { + // Don't use the compress data + // Convert the string into a buffer with 4 byte of header space. + buf = new byte[4 + len]; + Array.Copy(data, offset, buf, 4, len); + } + } + else + { + // Convert the string into a buffer with 4 byte of header space. + buf = new byte[4 + len]; + Array.Copy(data, offset, buf, 4, len); + } // Check that everything is ok if ((len < 1) || (len > 65535)) { Dispose(); return; } @@ -476,7 +512,7 @@ namespace MeshCentralRouter if (len < 126) { // Small fragment - buf[2] = 130; // Fragment op code (129 = text, 130 = binary) + buf[2] = op; buf[3] = (byte)(len & 0x7F); //try { wsstream.BeginWrite(buf, 2, len + 2, new AsyncCallback(WriteWebSocketAsyncDone), args); } catch (Exception) { Dispose(); return; } wsstream.Write(buf, 2, len + 2); @@ -484,7 +520,7 @@ namespace MeshCentralRouter else { // Large fragment - buf[0] = 130; // Fragment op code (129 = text, 130 = binary) + buf[0] = op; buf[1] = 126; buf[2] = (byte)((len >> 8) & 0xFF); buf[3] = (byte)(len & 0xFF);