Ejemplo n.º 1
0
        private void NegotiateDesktop()
        {
            this.c.SendByte((byte)(this.options.ShareDesktop ? 1 : 0));

            var width = this.c.ReceiveUInt16BE();

            VncStream.SanityCheck(width > 0 && width < 0x8000);
            var height = this.c.ReceiveUInt16BE();

            VncStream.SanityCheck(height > 0 && height < 0x8000);

            VncPixelFormat pixelFormat;

            try
            {
                pixelFormat = VncPixelFormat.Decode(this.c.Receive(VncPixelFormat.Size), 0);
            }
            catch (ArgumentException e)
            {
                throw new VncException(
                          "Unsupported pixel format.",
                          VncFailureReason.UnsupportedPixelFormat,
                          e);
            }

            var name = this.c.ReceiveString();

            this.Framebuffer = new VncFramebuffer(name, width, height, pixelFormat);
        }
Ejemplo n.º 2
0
        private void NegotiateVersion()
        {
            this.serverVersion = this.c.ReceiveVersion();
            VncStream.Require(
                this.serverVersion >= new Version(3, 8),
                "RFB 3.8 not supported by server.",
                VncFailureReason.UnsupportedProtocolVersion);

            this.c.SendVersion(new Version(3, 8));
        }
Ejemplo n.º 3
0
        /// <inheritdoc/>
        public virtual void GetChallengeResponse(byte[] challenge, char[] password, byte[] response)
        {
            if (password == null)
            {
                throw new ArgumentNullException(nameof(password));
            }

            var passwordBytes = VncStream.EncodeString(password, 0, password.Length);

            using (new Utility.AutoClear(passwordBytes))
            {
                this.GetChallengeResponse(challenge, passwordBytes, response);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Notifies the server that the local clipboard has changed.
        /// If you are implementing clipboard integration, use this to set the remote clipboard.
        /// </summary>
        /// <param name="data">The contents of the local clipboard.</param>
        public void SendLocalClipboardChange(string data)
        {
            Throw.If.Null(data, "data");

            var bytes = VncStream.EncodeString(data);

            var p = new byte[8 + bytes.Length];

            p[0] = (byte)6;
            VncUtility.EncodeUInt32BE(p, 4, (uint)bytes.Length);
            Array.Copy(bytes, 0, p, 8, bytes.Length);

            if (this.IsConnected)
            {
                this.c.Send(p);
            }
        }
Ejemplo n.º 5
0
        private ResponseType HandleResponse(PeriodicThread requester = null)
        {
            var command = (ResponseType)this.c.ReceiveByte();

            switch (command)
            {
            case ResponseType.FramebufferUpdate:
                requester?.Signal();
                if (!this.HandleFramebufferUpdate())
                {
                    command = ResponseType.DesktopSize;
                }

                break;

            case ResponseType.SetColorMapEntries:
                this.HandleSetColorMapEntries();
                break;

            case ResponseType.Bell:
                this.HandleBell();
                break;

            case ResponseType.ReceiveClipboardData:
                this.HandleReceiveClipboardData();
                break;

            default:
                VncStream.Require(
                    false,
                    "Unsupported command.",
                    VncFailureReason.UnrecognizedProtocolElement);
                break;
            }

            return(command);
        }
Ejemplo n.º 6
0
        private void NegotiateSecurity()
        {
            int count = this.c.ReceiveByte();

            if (count == 0)
            {
                string message = this.c.ReceiveString().Trim('\0');
                VncStream.Require(false, message, VncFailureReason.ServerOfferedNoAuthenticationMethods);
            }

            var types = new List <AuthenticationMethod>();

            for (int i = 0; i < count; i++)
            {
                types.Add((AuthenticationMethod)this.c.ReceiveByte());
            }

            if (types.Contains(AuthenticationMethod.None))
            {
                this.c.SendByte((byte)AuthenticationMethod.None);
            }
            else if (types.Contains(AuthenticationMethod.Password))
            {
                if (this.options.Password == null)
                {
                    var callback = this.options.PasswordRequiredCallback;
                    if (callback != null)
                    {
                        this.options.Password = callback(this);
                    }

                    VncStream.Require(
                        this.options.Password != null,
                        "Password required.",
                        VncFailureReason.PasswordRequired);
                }

                this.c.SendByte((byte)AuthenticationMethod.Password);

                var challenge = this.c.Receive(16);
                var password  = this.options.Password;
                var response  = new byte[16];

                using (new Utility.AutoClear(challenge))
                    using (new Utility.AutoClear(response))
                    {
                        this.passwordChallenge.GetChallengeResponse(challenge, this.options.Password, response);
                        this.c.Send(response);
                    }
            }
            else
            {
                VncStream.Require(
                    false,
                    "No supported authentication methods.",
                    VncFailureReason.NoSupportedAuthenticationMethods);
            }

            uint status = this.c.ReceiveUInt32BE();

            if (status != 0)
            {
                string message = this.c.ReceiveString().Trim('\0');
                VncStream.Require(false, message, VncFailureReason.AuthenticationFailed);
            }
        }
        private bool HandleFramebufferUpdate()
        {
            this.c.ReceiveByte(); // padding

            var numRects = this.c.ReceiveUInt16BE();
            var rects    = new List <VncRectangle>();
            var encoding = VncEncoding.DesktopSize;

            for (int i = 0; i < numRects; i++)
            {
                var r = this.c.ReceiveRectangle();
                int x = r.X, y = r.Y, w = r.Width, h = r.Height;
                VncStream.SanityCheck(w > 0 && w < 0x8000);
                VncStream.SanityCheck(h > 0 && h < 0x8000);

                int    fbW = this.Framebuffer.Width, fbH = this.Framebuffer.Height, bpp = this.Framebuffer.PixelFormat.BytesPerPixel;
                var    inRange = w <= fbW && h <= fbH && x <= fbW - w && y <= fbH - h;
                byte[] pixels;

                encoding = (VncEncoding)this.c.ReceiveUInt32BE();
                switch (encoding)
                {
                case VncEncoding.Hextile:     // KVM seems to avoid this now that I support Zlib.
                    var background = new byte[bpp];
                    var foreground = new byte[bpp];

                    for (int ty = 0; ty < h; ty += 16)
                    {
                        int th = Math.Min(16, h - ty);
                        for (int tx = 0; tx < w; tx += 16)
                        {
                            int tw = Math.Min(16, w - tx);

                            var subencoding = this.c.ReceiveByte();
                            pixels = this.AllocateFramebufferScratch(tw * th * bpp);

                            if ((subencoding & 1) != 0)
                            {
                                // raw
                                this.c.Receive(pixels, 0, tw * th * bpp);

                                if (inRange)
                                {
                                    lock (this.Framebuffer.SyncRoot)
                                    {
                                        this.CopyToFramebuffer(x + tx, y + ty, tw, th, pixels);
                                    }
                                }
                            }
                            else
                            {
                                pixels = this.AllocateFramebufferScratch(tw * th * bpp);
                                if ((subencoding & 2) != 0)
                                {
                                    background = this.c.Receive(bpp);
                                }

                                if ((subencoding & 4) != 0)
                                {
                                    foreground = this.c.Receive(bpp);
                                }

                                int ptr = 0;
                                for (int pp = 0; pp < tw * th; pp++)
                                {
                                    for (int pe = 0; pe < bpp; pe++)
                                    {
                                        pixels[ptr++] = background[pe];
                                    }
                                }

                                int nsubrects = (subencoding & 8) != 0 ? this.c.ReceiveByte() : 0;
                                if (nsubrects > 0)
                                {
                                    var subrectsColored = (subencoding & 16) != 0;
                                    for (int subrect = 0; subrect < nsubrects; subrect++)
                                    {
                                        var color = subrectsColored ? this.c.Receive(bpp) : foreground;
                                        var srxy = this.c.ReceiveByte();
                                        var srwh = this.c.ReceiveByte();
                                        int srx = (srxy >> 4) & 0xf, srw = ((srwh >> 4) & 0xf) + 1;
                                        int sry = (srxy >> 0) & 0xf, srh = ((srwh >> 0) & 0xf) + 1;
                                        if (srx + srw > tw || sry + srh > th)
                                        {
                                            continue;
                                        }

                                        for (int py = 0; py < srh; py++)
                                        {
                                            for (int px = 0; px < srw; px++)
                                            {
                                                int off = bpp * (((py + sry) * tw) + (px + srx));
                                                for (int pe = 0; pe < bpp; pe++)
                                                {
                                                    pixels[off + pe] = color[pe];
                                                }
                                            }
                                        }
                                    }
                                }

                                lock (this.Framebuffer.SyncRoot)
                                {
                                    this.CopyToFramebuffer(x + tx, y + ty, tw, th, pixels);
                                }
                            }
                        }
                    }

                    break;

                case VncEncoding.CopyRect:
                    var srcx = (int)this.c.ReceiveUInt16BE();
                    var srcy = (int)this.c.ReceiveUInt16BE();
                    if (srcx + w > fbW)
                    {
                        w = fbW - srcx;
                    }

                    if (srcy + h > fbH)
                    {
                        h = fbH - srcy;
                    }

                    if (w < 1 || h < 1)
                    {
                        continue;
                    }

                    pixels = this.AllocateFramebufferScratch(w * h * bpp);
                    lock (this.Framebuffer.SyncRoot)
                    {
                        this.CopyToGeneral(0, 0, w, h, pixels, srcx, srcy, fbW, fbH, this.Framebuffer.GetBuffer(), w, h);
                        this.CopyToFramebuffer(x, y, w, h, pixels);
                    }

                    break;

                case VncEncoding.Raw:
                    pixels = this.AllocateFramebufferScratch(w * h * bpp);
                    this.c.Receive(pixels, 0, w * h * bpp);

                    if (inRange)
                    {
                        lock (this.Framebuffer.SyncRoot)
                        {
                            this.CopyToFramebuffer(x, y, w, h, pixels);
                        }
                    }

                    break;

                case VncEncoding.Zlib:
                    int bytesDesired = w * h * bpp;

                    int size = (int)this.c.ReceiveUInt32BE(); VncStream.SanityCheck(size >= 0 && size < 0x10000000);
                    VncUtility.AllocateScratch(size, ref this.zlibScratch);
                    this.c.Receive(this.zlibScratch, 0, size);

                    this.zlibMemoryStream.Position = 0;
                    this.zlibMemoryStream.Write(this.zlibScratch, 0, size);
                    this.zlibMemoryStream.SetLength(size);
                    this.zlibMemoryStream.Position = 0;

                    if (this.zlibInflater == null)
                    {
                        // Zlib has a two-byte header.
                        VncStream.SanityCheck(size >= 2);
                        this.zlibMemoryStream.Position = 2;
                        this.zlibInflater = new DeflateStream(this.zlibMemoryStream, CompressionMode.Decompress, false);
                    }

                    pixels = this.AllocateFramebufferScratch(bytesDesired);
                    for (int j = 0; j < bytesDesired;)
                    {
                        int count = 0;

                        try
                        {
                            count = this.zlibInflater.Read(pixels, j, bytesDesired - j);
                        }
                        catch (InvalidDataException)
                        {
                            VncStream.Require(
                                false,
                                "Bad data compressed.",
                                VncFailureReason.UnrecognizedProtocolElement);
                        }

                        VncStream.Require(
                            count > 0,
                            "No data compressed.",
                            VncFailureReason.UnrecognizedProtocolElement);
                        j += count;
                    }

                    if (inRange)
                    {
                        lock (this.Framebuffer.SyncRoot)
                        {
                            this.CopyToFramebuffer(x, y, w, h, pixels);
                        }
                    }

                    break;

                case VncEncoding.PseudoDesktopSize:
                    this.Framebuffer = new VncFramebuffer(this.Framebuffer.Name, w, h, this.Framebuffer.PixelFormat);
                    continue;     // Don't call OnFramebufferChanged for this one.

                default:
                    VncStream.Require(
                        false,
                        "Unsupported encoding.",
                        VncFailureReason.UnrecognizedProtocolElement);
                    break;
                }

                rects.Add(new VncRectangle(x, y, w, h));
            }

            if (rects.Count > 0)
            {
                this.OnFramebufferChanged(new FramebufferChangedEventArgs(rects));
            }

            return(encoding != VncEncoding.DesktopSize);
        }