Beispiel #1
0
        /// <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);
                }
            }
        }
        // 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);
                }
            }
        }