/// <summary> /// Creates the encoded pixel data in a form of an EncodedRectangle with the preferred encoding. /// </summary> private void DoFrameBufferUpdate(Framebuffer fb, bool incremental, int x, int y, int width, int height) { //if (incremental) // return; Trace.WriteLine("X: " + x + " Y: " + y + " W: " + fb.Width + " H: " + fb.Height); int w = fb.Width; int h = fb.Height; if ((x < 0) || (y < 0) || (width <= 0) || (height <= 0)) { Trace.WriteLine("Neg:" + x + ":" + y + ":" + width + ":" + height); return; } if (x + width > w) { Trace.WriteLine("Too wide"); return; } if (y + height > h) { Trace.WriteLine("Too high"); return; } Trace.WriteLine("Bounds OK!"); HashSet <EncodedRectangle> rectangles = new HashSet <EncodedRectangle>(); try { Stopwatch tip = Stopwatch.StartNew(); EncodedRectangleFactory factory = new EncodedRectangleFactory(this, fb); ICollection <QuadNode> list = screenHandler.GetChange(); Trace.WriteLine(list.Count + " rectangles to encode"); foreach (QuadNode iter in list) { Trace.WriteLine(iter.ToString()); EncodedRectangle localRect = factory.Build(iter, GetPreferredEncoding()); localRect.Encode(); rectangles.Add(localRect); } Trace.WriteLine("Encoding took: " + tip.Elapsed); } catch (Exception localException) { Console.WriteLine(localException.StackTrace); if (localException is IOException) { Close(); return; } } if (rectangles.Count != 0) { WriteFrameBufferUpdate(rectangles); } }
/// <summary> /// Creates an object type derived from EncodedRectangle, based on the value of encoding. /// </summary> /// <param name="rectangle">A Rectangle object defining the bounds of the rectangle to be created</param> /// <param name="encoding">An Integer indicating the encoding type to be used for this rectangle. Used to determine the type of EncodedRectangle to create.</param> /// <returns></returns> public EncodedRectangle Build(Rectangle rectangle, int encoding) { EncodedRectangle e = null; switch (encoding) { case RfbProtocol.RAW_ENCODING: e = new RawRectangle(rfb, framebuffer, rectangle); break; case RfbProtocol.COPYRECT_ENCODING: e = new CopyRectRectangle(rfb, framebuffer, rectangle); break; case RfbProtocol.RRE_ENCODING: e = new RreRectangle(rfb, framebuffer, rectangle); break; case RfbProtocol.CORRE_ENCODING: e = new CoRreRectangle(rfb, framebuffer, rectangle); break; case RfbProtocol.HEXTILE_ENCODING: e = new HextileRectangle(rfb, framebuffer, rectangle); break; case RfbProtocol.ZRLE_ENCODING: e = new ZrleRectangle(rfb, framebuffer, rectangle); break; case RfbProtocol.CURSOR_PSEUDO_ENCODING: e = new CursorRectangle(rfb, framebuffer, rectangle); break; default: // Sanity check throw new Exception("Unsupported Encoding Format received: " + encoding.ToString() + "."); } return(e); }
/// <summary> /// Creates an object type derived from EncodedRectangle, based on the value of encoding. /// </summary> /// <param name="rectangle">A Rectangle object defining the bounds of the rectangle to be created</param> /// <param name="encoding">An Integer indicating the encoding type to be used for this rectangle. Used to determine the type of EncodedRectangle to create.</param> /// <returns></returns> public EncodedRectangle Build(Rectangle rectangle, int encoding) { EncodedRectangle e = null; switch (encoding) { case RfbProtocol.RAW_ENCODING: e = new RawRectangle(rfb, framebuffer, rectangle); break; case RfbProtocol.COPYRECT_ENCODING: e = new CopyRectRectangle(rfb, framebuffer, rectangle); break; case RfbProtocol.RRE_ENCODING: e = new RreRectangle(rfb, framebuffer, rectangle); break; case RfbProtocol.CORRE_ENCODING: e = new CoRreRectangle(rfb, framebuffer, rectangle); break; case RfbProtocol.HEXTILE_ENCODING: e = new HextileRectangle(rfb, framebuffer, rectangle); break; case RfbProtocol.ZRLE_ENCODING: // TODO: ZRLE is not written yet, but when it is, this needs to be changed. // e = new ZrleRectangle(rfb, framebuffer, rectangle); // break; throw new NotImplementedException("Need to implement Zrle Encoding!!!"); default: // Sanity check throw new VncProtocolException("Unsupported Encoding Format received: " + encoding.ToString() + "."); } return(e); }
/// <summary> /// Worker thread lives here and processes protocol messages infinitely, triggering events or other actions as necessary. /// </summary> private void GetRfbUpdates() { int rectangles; int enc; // Get the initial destkop from the host RequestScreenUpdate(true); while (true) { if (CheckIfThreadDone()) { break; } try { switch (rfb.ReadServerMessageType()) { case RfbProtocol.FRAMEBUFFER_UPDATE: rectangles = rfb.ReadFramebufferUpdate(); if (CheckIfThreadDone()) { break; } for (int i = 0; i < rectangles; ++i) { // Get the update rectangle's info Rectangle rectangle; rfb.ReadFramebufferUpdateRectHeader(out rectangle, out enc); // Build a derived EncodedRectangle type and pull-down all the pixel info EncodedRectangle er = factory.Build(rectangle, enc); er.Decode(); // Let the UI know that an updated rectangle is available, but check // to see if the user closed things down first. if (!CheckIfThreadDone() && VncUpdate != null) { VncEventArgs e = new VncEventArgs(er); // In order to play nicely with WinForms controls, we do a check here to // see if it is necessary to synchronize this event with the UI thread. if (VncUpdate.Target is System.Windows.Forms.Control) { Control target = VncUpdate.Target as Control; if (target != null) { target.Invoke(VncUpdate, new object[] { this, e }); } } else { // Target is not a WinForms control, so do it on this thread... VncUpdate(this, new VncEventArgs(er)); } } } break; case RfbProtocol.BELL: Beep(500, 300); // TODO: are there better values than these? break; case RfbProtocol.SERVER_CUT_TEXT: if (CheckIfThreadDone()) { break; } Clipboard.SetDataObject(rfb.ReadServerCutText().Replace("\n", Environment.NewLine), true); break; case RfbProtocol.SET_COLOUR_MAP_ENTRIES: // TODO: Needs to be implemented fully // rfb.ReadColourMapEntry(); break; } } catch { OnConnectionLost(); } } }
/// <summary> /// Worker thread lives here and processes protocol messages infinitely, triggering events or other actions as necessary. /// </summary> private void GetRfbUpdates() { Thread.Sleep(1000); int rectangles; int enc; // Get the initial destkop from the host RequestScreenUpdate(true); while (true) { if (CheckIfThreadDone()) { break; } try { switch (rfb.ReadServerMessageType()) { case RfbProtocol.FRAMEBUFFER_UPDATE: rectangles = rfb.ReadFramebufferUpdate(); if (CheckIfThreadDone()) { break; } // TODO: consider gathering all update rectangles in a batch and *then* posting the event back to the main thread. for (int i = 0; i < rectangles; ++i) { // Get the update rectangle's info Rectangle rectangle; rfb.ReadFramebufferUpdateRectHeader(out rectangle, out enc); // Build a derived EncodedRectangle type and pull-down all the pixel info EncodedRectangle er = factory.Build(rectangle, BufferInfos.BitsPerPixel, enc); er.Decode(); // Let the UI know that an updated rectangle is available, but check // to see if the user closed things down first. if (!CheckIfThreadDone()) { updates.Add(er); } } break; case RfbProtocol.BELL: Beep(500, 300); // TODO: are there better values than these? break; case RfbProtocol.SERVER_CUT_TEXT: if (CheckIfThreadDone()) { break; } // TODO: This is invasive, should there be a bool property allowing this message to be ignored? // Clipboard.SetDataObject(rfb.ReadServerCutText().Replace("\n", Environment.NewLine), true); OnServerCutText(); break; case RfbProtocol.SET_COLOUR_MAP_ENTRIES: rfb.ReadColourMapEntry(); break; } } catch (Exception e) { OnConnectionLost(e); } } }
/// <summary> /// Creates the encoded pixel data in a form of an EncodedRectangle with the preferred encoding. /// </summary> private void DoFrameBufferUpdate(Framebuffer fb, bool incremental, int x, int y, int width, int height) { //if (incremental) // return; Trace.WriteLine("X: " + x + " Y: " + y + " W: " + fb.Width + " H: " + fb.Height); int w = fb.Width; int h = fb.Height; if ((x < 0) || (y < 0) || (width <= 0) || (height <= 0)) { Trace.WriteLine("Neg:" + x + ":" + y + ":" + width + ":" + height); return; } if (x + width > w) { Trace.WriteLine("Too wide"); return; } if (y + height > h) { Trace.WriteLine("Too high"); return; } Trace.WriteLine("Bounds OK!"); List <EncodedRectangle> lst = new List <EncodedRectangle>(); //List<byte[]> lstHash = new List<byte[]>(); try { //Console.WriteLine("Framebuffer: "); //fb.Print(); //Console.ReadLine(); System.Diagnostics.Stopwatch tip = System.Diagnostics.Stopwatch.StartNew(); EncodedRectangleFactory factory = new EncodedRectangleFactory(this, fb); /* * int i = width / 4; * int j = height / 4; * int m = 0; * Rectangle lRect = Rectangle.Empty; * for (int k = 0; k < 4; k++) * for (m = 0; m < 4; m++) * { * lRect = new Rectangle(); * lRect.X = (i * k); * lRect.Y = (j * m); * lRect.Width = i; * lRect.Height = j; * //lRect = PixelGrabber.AlignRectangle(lRect, width, height); * * EncodedRectangle localRect = factory.Build(lRect, GetPreferredEncoding()); * localRect.Encode(); * lst.Add(localRect); * } */ EncodedRectangle localRect = factory.Build(new Rectangle(x, y, width, height), GetPreferredEncoding()); localRect.Encode(); lst.Add(localRect); Console.WriteLine("Encoding took: " + tip.Elapsed); } catch (Exception localException) { Console.WriteLine(localException.StackTrace.ToString()); if (localException is IOException) { this.Close(); return; } } if (lst.Count != 0) { WriteFrameBufferUpdate(lst.ToArray()); } }
// vnc client handling - main thread private void RunNetThread() { while (!terminate) { if (autoconnect && host != "") { try { sleeptime = 0; Log.Info("Connecting to \"" + host + ":" + port + "\"..."); rfb = new RfbProtocol(); rfb.Connect(host, (int)port); Log.Debug("Connected."); rfb.ReadProtocolVersion(); // Handle possible repeater connection if (rfb.ServerVersion == 0.0) { rfb.WriteProxyAddress(); // Now we are connected to the real server; read the protocol version of the // server rfb.ReadProtocolVersion(); // Resume normal handshake and protocol } rfb.WriteProtocolVersion(); Log.Debug("Protocol Version:" + rfb.ServerVersion); // Figure out which type of authentication the server uses byte[] types = rfb.ReadSecurityTypes(); // Based on what the server sends back in the way of supported Security Types, one of // two things will need to be done: either the server will reject the connection (i.e., type = 0), // or a list of supported types will be sent, of which we need to choose and use one. if (types.Length > 0) { if (types[0] == 0) { // The server is not able (or willing) to accept the connection. // A message follows indicating why the connection was dropped. throw new Exception("Connection Failed. The server rejected the connection for the following reason: " + rfb.ReadSecurityFailureReason()); } else { byte securityType = GetSupportedSecurityType(types); if (securityType == 0) { throw new Exception("Unknown Security Type(s), The server sent one or more unknown Security Types."); } rfb.WriteSecurityType(securityType); // Protocol 3.8 states that a SecurityResult is still sent when using NONE (see 6.2.1) if (rfb.ServerVersion >= 3.799f && rfb.ServerVersion <= 3.801 && securityType == 1) { if (rfb.ReadSecurityResult() > 0) { // For some reason, the server is not accepting the connection. Get the // reason and throw an exception throw new Exception("Unable to Connect to the Server. The Server rejected the connection for the following reason: " + rfb.ReadSecurityFailureReason()); } } if (securityType > 1) { byte[] challenge = rfb.ReadSecurityChallenge(); rfb.WriteSecurityResponse(EncryptChallenge(pass, challenge)); if (rfb.ReadSecurityResult() != 0) { // Authentication failed, and if the server is using Protocol version 3.8, a // plain text message follows indicating why the error happend. I'm not // currently using this message, but it is read here to clean out the stream. // In earlier versions of the protocol, the server will just drop the connection. autoconnect = false; if (rfb.ServerVersion == 3.8) { throw new Exception("The server denyes the authentication. Reason: \"" + rfb.ReadSecurityFailureReason() + "\""); } throw new Exception("The server denyes the authentication."); } } } } else { // Something is wrong, since we should have gotten at least 1 Security Type throw new Exception("Protocol Error Connecting to Server. The Server didn't send any Security Types during the initial handshake."); } // Finish initializing protocol with host rfb.WriteClientInitialisation(shared); buffer = rfb.ReadServerInit(); rfb.WriteSetPixelFormat(buffer); // just use the server's framebuffer format if (hideRemoteCursor) { rfb.WriteSetEncodings(new int[] { RfbProtocol.ZRLE_ENCODING, RfbProtocol.HEXTILE_ENCODING, RfbProtocol.RRE_ENCODING, RfbProtocol.COPYRECT_ENCODING, RfbProtocol.RAW_ENCODING, RfbProtocol.CURSOR_PSEUDO_ENCODING }); } else { rfb.WriteSetEncodings(new int[] { RfbProtocol.ZRLE_ENCODING, RfbProtocol.HEXTILE_ENCODING, RfbProtocol.RRE_ENCODING, RfbProtocol.COPYRECT_ENCODING, RfbProtocol.RAW_ENCODING }); } // Create an EncodedRectangleFactory so that EncodedRectangles can be built according to set pixel layout factory = new EncodedRectangleFactory(rfb, buffer); // Get the initial destkop from the host rfb.WriteFramebufferUpdateRequest(0, 0, (ushort)buffer.Width, (ushort)buffer.Height, false); while (!terminate && autoconnect) { switch (rfb.ReadServerMessageType()) { case RfbProtocol.FRAMEBUFFER_UPDATE: int rectangles = rfb.ReadFramebufferUpdate(); for (int i = 0; i < rectangles; ++i) { // Get the update rectangle's info Rectangle rectangle; int enc; rfb.ReadFramebufferUpdateRectHeader(out rectangle, out enc); // Build a derived EncodedRectangle type and pull-down all the pixel info EncodedRectangle er = factory.Build(rectangle, enc); er.Decode(); er.Draw(); } break; case RfbProtocol.BELL: Log.Debug("Bell"); break; case RfbProtocol.SERVER_CUT_TEXT: rfb.ReadServerCutText(); Log.Debug("server-cut-text"); break; case RfbProtocol.SET_COLOUR_MAP_ENTRIES: Log.Debug("SET_COLOUR_MAP_ENTRIES"); rfb.ReadColourMapEntry(); break; default: throw new Exception("Unknown messagetype."); } invalid = true; rfb.WriteFramebufferUpdateRequest(0, 0, (ushort)buffer.Width, (ushort)buffer.Height, true); } } catch (SocketException) { Log.Info("Unable to connect to the server. Retry in 60s."); sleeptime = 60000; } catch (IOException e) { Log.Debug("Exception in NetThread(" + e.GetType().ToString() + "): " + e.Message); } catch (Exception e) { Log.Error("Exception in NetThread(" + e.GetType().ToString() + "): " + e.Message); sleeptime = 10000; } try { rfb.Close(); } catch (Exception) {} rfb = null; buffer = null; factory = null; invalid = true; Thread.Sleep(sleeptime); } } }
/// <summary> /// Worker thread lives here and processes protocol messages infinitely, triggering events or other actions as necessary. /// </summary> private void GetRfbUpdates(CancellationToken token) { // Get the initial destkop from the host int connLostCount = 0; RequestScreenUpdate(true); while (!token.IsCancellationRequested) { try { // ReSharper disable once SwitchStatementMissingSomeCases var msgType = rfb.ReadServerMessageType(); switch (msgType) { case ServerClientMessageType.FramebufferUpdate: var rectangles = rfb.ReadFramebufferUpdate(); if (token.IsCancellationRequested) { break; } // TODO: consider gathering all update rectangles in a batch and *then* posting the event back to the main thread. for (var i = 0; i < rectangles; ++i) { // Get the update rectangle's info var(rectangle, enc) = rfb.ReadFramebufferUpdateRectHeader(); // Build a derived EncodedRectangle type and pull-down all the pixel info var er = EncodedRectangle.Build(rfb, Framebuffer, rectangle, enc); er.Decode(); // Let the UI know that an updated rectangle is available, but check // to see if the user closed things down first. if (token.IsCancellationRequested || VncUpdate == null) { continue; } var e = new VncEventArgs(er); VncUpdate(this, new VncEventArgs(er)); } break; case ServerClientMessageType.Bell: //Beep(); break; case ServerClientMessageType.ServerCutText: // TODO: This is invasive, should there be a bool property allowing this message to be ignored? OnServerCutText(); break; case ServerClientMessageType.SetColourMapEntries: rfb.ReadColourMapEntry(); break; } // Moved screen update request here to prevent it being called multiple times // This was the case when multiple rectangles were returned by the host RequestScreenUpdate(FullScreenRefresh); connLostCount = 0; } catch (Exception ex) { Debug.WriteLine(ex.Message); // On the first time of no data being received we force a complete update // This is for times when the server has no update, and caused the timeout. if (connLostCount++ > 1) { OnConnectionLost(); } else { RequestScreenUpdate(true); } } FullScreenRefresh = false; } }