vncserver.cc revision 8635
17949SAli.Saidi@ARM.com/* 27949SAli.Saidi@ARM.com * Copyright (c) 2010 ARM Limited 37949SAli.Saidi@ARM.com * All rights reserved 47949SAli.Saidi@ARM.com * 57949SAli.Saidi@ARM.com * The license below extends only to copyright in the software and shall 67949SAli.Saidi@ARM.com * not be construed as granting a license to any other intellectual 77949SAli.Saidi@ARM.com * property including but not limited to intellectual property relating 87949SAli.Saidi@ARM.com * to a hardware implementation of the functionality of the software 97949SAli.Saidi@ARM.com * licensed hereunder. You may use the software subject to the license 107949SAli.Saidi@ARM.com * terms below provided that you ensure that this notice is replicated 117949SAli.Saidi@ARM.com * unmodified and in its entirety in all distributions of the software, 127949SAli.Saidi@ARM.com * modified or unmodified, in source code or in binary form. 137949SAli.Saidi@ARM.com * 147949SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without 157949SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are 167949SAli.Saidi@ARM.com * met: redistributions of source code must retain the above copyright 177949SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer; 187949SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright 197949SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the 207949SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution; 217949SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its 227949SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from 237949SAli.Saidi@ARM.com * this software without specific prior written permission. 247949SAli.Saidi@ARM.com * 257949SAli.Saidi@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 267949SAli.Saidi@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 277949SAli.Saidi@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 287949SAli.Saidi@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 297949SAli.Saidi@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 307949SAli.Saidi@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 317949SAli.Saidi@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 327949SAli.Saidi@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 337949SAli.Saidi@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 347949SAli.Saidi@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 357949SAli.Saidi@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 367949SAli.Saidi@ARM.com * 377949SAli.Saidi@ARM.com * Authors: Ali Saidi 387949SAli.Saidi@ARM.com * William Wang 397949SAli.Saidi@ARM.com */ 407949SAli.Saidi@ARM.com 417949SAli.Saidi@ARM.com/** @file 427949SAli.Saidi@ARM.com * Implementiation of a VNC server 437949SAli.Saidi@ARM.com */ 447949SAli.Saidi@ARM.com 457949SAli.Saidi@ARM.com#include <sys/ioctl.h> 468635Schris.emmons@arm.com#include <sys/stat.h> 477949SAli.Saidi@ARM.com#include <sys/termios.h> 488635Schris.emmons@arm.com#include <sys/types.h> 498635Schris.emmons@arm.com#include <fcntl.h> 507949SAli.Saidi@ARM.com#include <poll.h> 517949SAli.Saidi@ARM.com#include <unistd.h> 527949SAli.Saidi@ARM.com 538229Snate@binkert.org#include <cerrno> 548229Snate@binkert.org#include <cstdio> 558229Snate@binkert.org 568229Snate@binkert.org#include "base/vnc/vncserver.hh" 577949SAli.Saidi@ARM.com#include "base/atomicio.hh" 588635Schris.emmons@arm.com#include "base/bitmap.hh" 597949SAli.Saidi@ARM.com#include "base/misc.hh" 608635Schris.emmons@arm.com#include "base/output.hh" 617949SAli.Saidi@ARM.com#include "base/socket.hh" 627949SAli.Saidi@ARM.com#include "base/trace.hh" 638232Snate@binkert.org#include "debug/VNC.hh" 647949SAli.Saidi@ARM.com#include "sim/byteswap.hh" 658635Schris.emmons@arm.com#include "sim/core.hh" 667949SAli.Saidi@ARM.com 677949SAli.Saidi@ARM.comusing namespace std; 687949SAli.Saidi@ARM.com 697949SAli.Saidi@ARM.com/** 707949SAli.Saidi@ARM.com * Poll event for the listen socket 717949SAli.Saidi@ARM.com */ 727949SAli.Saidi@ARM.comVncServer::ListenEvent::ListenEvent(VncServer *vs, int fd, int e) 737949SAli.Saidi@ARM.com : PollEvent(fd, e), vncserver(vs) 747949SAli.Saidi@ARM.com{ 757949SAli.Saidi@ARM.com} 767949SAli.Saidi@ARM.com 777949SAli.Saidi@ARM.comvoid 787949SAli.Saidi@ARM.comVncServer::ListenEvent::process(int revent) 797949SAli.Saidi@ARM.com{ 807949SAli.Saidi@ARM.com vncserver->accept(); 817949SAli.Saidi@ARM.com} 827949SAli.Saidi@ARM.com 837949SAli.Saidi@ARM.com/** 847949SAli.Saidi@ARM.com * Poll event for the data socket 857949SAli.Saidi@ARM.com */ 867949SAli.Saidi@ARM.comVncServer::DataEvent::DataEvent(VncServer *vs, int fd, int e) 877949SAli.Saidi@ARM.com : PollEvent(fd, e), vncserver(vs) 887949SAli.Saidi@ARM.com{ 897949SAli.Saidi@ARM.com} 907949SAli.Saidi@ARM.com 917949SAli.Saidi@ARM.comvoid 927949SAli.Saidi@ARM.comVncServer::DataEvent::process(int revent) 937949SAli.Saidi@ARM.com{ 947949SAli.Saidi@ARM.com if (revent & POLLIN) 957949SAli.Saidi@ARM.com vncserver->data(); 967949SAli.Saidi@ARM.com else if (revent & POLLNVAL) 977949SAli.Saidi@ARM.com vncserver->detach(); 987949SAli.Saidi@ARM.com} 997949SAli.Saidi@ARM.com 1007949SAli.Saidi@ARM.com/** 1017949SAli.Saidi@ARM.com * VncServer 1027949SAli.Saidi@ARM.com */ 1037949SAli.Saidi@ARM.comVncServer::VncServer(const Params *p) 1047949SAli.Saidi@ARM.com : SimObject(p), listenEvent(NULL), dataEvent(NULL), number(p->number), 1057949SAli.Saidi@ARM.com dataFd(-1), _videoWidth(1), _videoHeight(1), clientRfb(0), keyboard(NULL), 1067949SAli.Saidi@ARM.com mouse(NULL), sendUpdate(false), videoMode(VideoConvert::UnknownMode), 1078635Schris.emmons@arm.com vc(NULL), captureEnabled(p->frame_capture), captureCurrentFrame(0), 1088635Schris.emmons@arm.com captureLastHash(0), captureBitmap(0) 1097949SAli.Saidi@ARM.com{ 1107949SAli.Saidi@ARM.com if (p->port) 1117949SAli.Saidi@ARM.com listen(p->port); 1127949SAli.Saidi@ARM.com 1137949SAli.Saidi@ARM.com curState = WaitForProtocolVersion; 1147949SAli.Saidi@ARM.com 1157949SAli.Saidi@ARM.com // currently we only support this one pixel format 1167949SAli.Saidi@ARM.com // unpacked 32bit rgb (rgb888 + 8 bits of nothing/alpha) 1177949SAli.Saidi@ARM.com // keep it around for telling the client and making 1187949SAli.Saidi@ARM.com // sure the client cooperates 1197949SAli.Saidi@ARM.com pixelFormat.bpp = 32; 1207949SAli.Saidi@ARM.com pixelFormat.depth = 24; 1217949SAli.Saidi@ARM.com pixelFormat.bigendian = 0; 1227949SAli.Saidi@ARM.com pixelFormat.truecolor = 1; 1237949SAli.Saidi@ARM.com pixelFormat.redmax = 0xff; 1247949SAli.Saidi@ARM.com pixelFormat.greenmax = 0xff; 1257949SAli.Saidi@ARM.com pixelFormat.bluemax = 0xff; 1267949SAli.Saidi@ARM.com pixelFormat.redshift = 16; 1277949SAli.Saidi@ARM.com pixelFormat.greenshift = 8; 1287949SAli.Saidi@ARM.com pixelFormat.blueshift = 0; 1297949SAli.Saidi@ARM.com 1308635Schris.emmons@arm.com if (captureEnabled) { 1318635Schris.emmons@arm.com // remove existing frame output directory if it exists, then create a 1328635Schris.emmons@arm.com // clean empty directory 1338635Schris.emmons@arm.com const string FRAME_OUTPUT_SUBDIR = "frames_" + name(); 1348635Schris.emmons@arm.com simout.remove(FRAME_OUTPUT_SUBDIR, true); 1358635Schris.emmons@arm.com captureOutputDirectory = simout.createSubdirectory( 1368635Schris.emmons@arm.com FRAME_OUTPUT_SUBDIR); 1378635Schris.emmons@arm.com } 1387949SAli.Saidi@ARM.com 1397949SAli.Saidi@ARM.com DPRINTF(VNC, "Vnc server created at port %d\n", p->port); 1407949SAli.Saidi@ARM.com} 1417949SAli.Saidi@ARM.com 1427949SAli.Saidi@ARM.comVncServer::~VncServer() 1437949SAli.Saidi@ARM.com{ 1447949SAli.Saidi@ARM.com if (dataFd != -1) 1457949SAli.Saidi@ARM.com ::close(dataFd); 1467949SAli.Saidi@ARM.com 1477949SAli.Saidi@ARM.com if (listenEvent) 1487949SAli.Saidi@ARM.com delete listenEvent; 1497949SAli.Saidi@ARM.com 1507949SAli.Saidi@ARM.com if (dataEvent) 1517949SAli.Saidi@ARM.com delete dataEvent; 1527949SAli.Saidi@ARM.com} 1537949SAli.Saidi@ARM.com 1547949SAli.Saidi@ARM.com 1557949SAli.Saidi@ARM.com//socket creation and vnc client attach 1567949SAli.Saidi@ARM.comvoid 1577949SAli.Saidi@ARM.comVncServer::listen(int port) 1587949SAli.Saidi@ARM.com{ 1597949SAli.Saidi@ARM.com if (ListenSocket::allDisabled()) { 1607949SAli.Saidi@ARM.com warn_once("Sockets disabled, not accepting vnc client connections"); 1617949SAli.Saidi@ARM.com return; 1627949SAli.Saidi@ARM.com } 1637949SAli.Saidi@ARM.com 1647949SAli.Saidi@ARM.com while (!listener.listen(port, true)) { 1657949SAli.Saidi@ARM.com DPRINTF(VNC, 1667949SAli.Saidi@ARM.com "can't bind address vnc server port %d in use PID %d\n", 1677949SAli.Saidi@ARM.com port, getpid()); 1687949SAli.Saidi@ARM.com port++; 1697949SAli.Saidi@ARM.com } 1707949SAli.Saidi@ARM.com 1717949SAli.Saidi@ARM.com int p1, p2; 1727949SAli.Saidi@ARM.com p2 = name().rfind('.') - 1; 1737949SAli.Saidi@ARM.com p1 = name().rfind('.', p2); 1747949SAli.Saidi@ARM.com ccprintf(cerr, "Listening for %s connection on port %d\n", 1757949SAli.Saidi@ARM.com name().substr(p1 + 1, p2 - p1), port); 1767949SAli.Saidi@ARM.com 1777949SAli.Saidi@ARM.com listenEvent = new ListenEvent(this, listener.getfd(), POLLIN); 1787949SAli.Saidi@ARM.com pollQueue.schedule(listenEvent); 1797949SAli.Saidi@ARM.com} 1807949SAli.Saidi@ARM.com 1817949SAli.Saidi@ARM.com// attach a vnc client 1827949SAli.Saidi@ARM.comvoid 1837949SAli.Saidi@ARM.comVncServer::accept() 1847949SAli.Saidi@ARM.com{ 1857949SAli.Saidi@ARM.com if (!listener.islistening()) 1867949SAli.Saidi@ARM.com panic("%s: cannot accept a connection if not listening!", name()); 1877949SAli.Saidi@ARM.com 1887949SAli.Saidi@ARM.com int fd = listener.accept(true); 1897949SAli.Saidi@ARM.com if (dataFd != -1) { 1907949SAli.Saidi@ARM.com char message[] = "vnc server already attached!\n"; 1917949SAli.Saidi@ARM.com atomic_write(fd, message, sizeof(message)); 1927949SAli.Saidi@ARM.com ::close(fd); 1937949SAli.Saidi@ARM.com return; 1947949SAli.Saidi@ARM.com } 1957949SAli.Saidi@ARM.com 1967949SAli.Saidi@ARM.com dataFd = fd; 1977949SAli.Saidi@ARM.com 1987949SAli.Saidi@ARM.com // Send our version number to the client 1997949SAli.Saidi@ARM.com write((uint8_t*)vncVersion(), strlen(vncVersion())); 2007949SAli.Saidi@ARM.com 2017949SAli.Saidi@ARM.com // read the client response 2027949SAli.Saidi@ARM.com dataEvent = new DataEvent(this, dataFd, POLLIN); 2037949SAli.Saidi@ARM.com pollQueue.schedule(dataEvent); 2047949SAli.Saidi@ARM.com 2057949SAli.Saidi@ARM.com inform("VNC client attached\n"); 2067949SAli.Saidi@ARM.com} 2077949SAli.Saidi@ARM.com 2087949SAli.Saidi@ARM.com// data called by data event 2097949SAli.Saidi@ARM.comvoid 2107949SAli.Saidi@ARM.comVncServer::data() 2117949SAli.Saidi@ARM.com{ 2127949SAli.Saidi@ARM.com // We have new data, see if we can handle it 2137949SAli.Saidi@ARM.com size_t len; 2147949SAli.Saidi@ARM.com DPRINTF(VNC, "Vnc client message recieved\n"); 2157949SAli.Saidi@ARM.com 2167949SAli.Saidi@ARM.com switch (curState) { 2177949SAli.Saidi@ARM.com case WaitForProtocolVersion: 2187949SAli.Saidi@ARM.com checkProtocolVersion(); 2197949SAli.Saidi@ARM.com break; 2207949SAli.Saidi@ARM.com case WaitForSecurityResponse: 2217949SAli.Saidi@ARM.com checkSecurity(); 2227949SAli.Saidi@ARM.com break; 2237949SAli.Saidi@ARM.com case WaitForClientInit: 2247949SAli.Saidi@ARM.com // Don't care about shared, just need to read it out of the socket 2257949SAli.Saidi@ARM.com uint8_t shared; 2267949SAli.Saidi@ARM.com len = read(&shared); 2277949SAli.Saidi@ARM.com assert(len == 1); 2287949SAli.Saidi@ARM.com 2297949SAli.Saidi@ARM.com // Send our idea of the frame buffer 2307949SAli.Saidi@ARM.com sendServerInit(); 2317949SAli.Saidi@ARM.com 2327949SAli.Saidi@ARM.com break; 2337949SAli.Saidi@ARM.com case NormalPhase: 2347949SAli.Saidi@ARM.com uint8_t message_type; 2357949SAli.Saidi@ARM.com len = read(&message_type); 2367949SAli.Saidi@ARM.com if (!len) { 2377949SAli.Saidi@ARM.com detach(); 2387949SAli.Saidi@ARM.com return; 2397949SAli.Saidi@ARM.com } 2407949SAli.Saidi@ARM.com assert(len == 1); 2417949SAli.Saidi@ARM.com 2427949SAli.Saidi@ARM.com switch (message_type) { 2437949SAli.Saidi@ARM.com case ClientSetPixelFormat: 2447949SAli.Saidi@ARM.com setPixelFormat(); 2457949SAli.Saidi@ARM.com break; 2467949SAli.Saidi@ARM.com case ClientSetEncodings: 2477949SAli.Saidi@ARM.com setEncodings(); 2487949SAli.Saidi@ARM.com break; 2497949SAli.Saidi@ARM.com case ClientFrameBufferUpdate: 2507949SAli.Saidi@ARM.com requestFbUpdate(); 2517949SAli.Saidi@ARM.com break; 2527949SAli.Saidi@ARM.com case ClientKeyEvent: 2537949SAli.Saidi@ARM.com recvKeyboardInput(); 2547949SAli.Saidi@ARM.com break; 2557949SAli.Saidi@ARM.com case ClientPointerEvent: 2567949SAli.Saidi@ARM.com recvPointerInput(); 2577949SAli.Saidi@ARM.com break; 2587949SAli.Saidi@ARM.com case ClientCutText: 2597949SAli.Saidi@ARM.com recvCutText(); 2607949SAli.Saidi@ARM.com break; 2617949SAli.Saidi@ARM.com default: 2627949SAli.Saidi@ARM.com panic("Unimplemented message type recv from client: %d\n", 2637949SAli.Saidi@ARM.com message_type); 2647949SAli.Saidi@ARM.com break; 2657949SAli.Saidi@ARM.com } 2667949SAli.Saidi@ARM.com break; 2677949SAli.Saidi@ARM.com default: 2687949SAli.Saidi@ARM.com panic("Unknown vnc server state\n"); 2697949SAli.Saidi@ARM.com } 2707949SAli.Saidi@ARM.com} 2717949SAli.Saidi@ARM.com 2727949SAli.Saidi@ARM.com 2737949SAli.Saidi@ARM.com// read from socket 2747949SAli.Saidi@ARM.comsize_t 2757949SAli.Saidi@ARM.comVncServer::read(uint8_t *buf, size_t len) 2767949SAli.Saidi@ARM.com{ 2777949SAli.Saidi@ARM.com if (dataFd < 0) 2787949SAli.Saidi@ARM.com panic("vnc not properly attached.\n"); 2797949SAli.Saidi@ARM.com 2807949SAli.Saidi@ARM.com size_t ret; 2817949SAli.Saidi@ARM.com do { 2827949SAli.Saidi@ARM.com ret = ::read(dataFd, buf, len); 2837949SAli.Saidi@ARM.com } while (ret == -1 && errno == EINTR); 2847949SAli.Saidi@ARM.com 2857949SAli.Saidi@ARM.com 2867949SAli.Saidi@ARM.com if (ret <= 0){ 2877949SAli.Saidi@ARM.com DPRINTF(VNC, "Read failed.\n"); 2887949SAli.Saidi@ARM.com detach(); 2897949SAli.Saidi@ARM.com return 0; 2907949SAli.Saidi@ARM.com } 2917949SAli.Saidi@ARM.com 2927949SAli.Saidi@ARM.com return ret; 2937949SAli.Saidi@ARM.com} 2947949SAli.Saidi@ARM.com 2957949SAli.Saidi@ARM.comsize_t 2967949SAli.Saidi@ARM.comVncServer::read1(uint8_t *buf, size_t len) 2977949SAli.Saidi@ARM.com{ 2987949SAli.Saidi@ARM.com size_t read_len M5_VAR_USED; 2997949SAli.Saidi@ARM.com read_len = read(buf + 1, len - 1); 3007949SAli.Saidi@ARM.com assert(read_len == len - 1); 3017949SAli.Saidi@ARM.com return read_len; 3027949SAli.Saidi@ARM.com} 3037949SAli.Saidi@ARM.com 3047949SAli.Saidi@ARM.com 3057949SAli.Saidi@ARM.comtemplate<typename T> 3067949SAli.Saidi@ARM.comsize_t 3077949SAli.Saidi@ARM.comVncServer::read(T* val) 3087949SAli.Saidi@ARM.com{ 3097949SAli.Saidi@ARM.com return read((uint8_t*)val, sizeof(T)); 3107949SAli.Saidi@ARM.com} 3117949SAli.Saidi@ARM.com 3127949SAli.Saidi@ARM.com// write to socket 3137949SAli.Saidi@ARM.comsize_t 3147949SAli.Saidi@ARM.comVncServer::write(const uint8_t *buf, size_t len) 3157949SAli.Saidi@ARM.com{ 3167949SAli.Saidi@ARM.com if (dataFd < 0) 3177949SAli.Saidi@ARM.com panic("Vnc client not properly attached.\n"); 3187949SAli.Saidi@ARM.com 3197949SAli.Saidi@ARM.com ssize_t ret; 3207949SAli.Saidi@ARM.com ret = atomic_write(dataFd, buf, len); 3217949SAli.Saidi@ARM.com 3227949SAli.Saidi@ARM.com if (ret < len) 3237949SAli.Saidi@ARM.com detach(); 3247949SAli.Saidi@ARM.com 3257949SAli.Saidi@ARM.com return ret; 3267949SAli.Saidi@ARM.com} 3277949SAli.Saidi@ARM.com 3287949SAli.Saidi@ARM.comtemplate<typename T> 3297949SAli.Saidi@ARM.comsize_t 3307949SAli.Saidi@ARM.comVncServer::write(T* val) 3317949SAli.Saidi@ARM.com{ 3327949SAli.Saidi@ARM.com return write((uint8_t*)val, sizeof(T)); 3337949SAli.Saidi@ARM.com} 3347949SAli.Saidi@ARM.com 3357949SAli.Saidi@ARM.comsize_t 3367949SAli.Saidi@ARM.comVncServer::write(const char* str) 3377949SAli.Saidi@ARM.com{ 3387949SAli.Saidi@ARM.com return write((uint8_t*)str, strlen(str)); 3397949SAli.Saidi@ARM.com} 3407949SAli.Saidi@ARM.com 3417949SAli.Saidi@ARM.com// detach a vnc client 3427949SAli.Saidi@ARM.comvoid 3437949SAli.Saidi@ARM.comVncServer::detach() 3447949SAli.Saidi@ARM.com{ 3457949SAli.Saidi@ARM.com if (dataFd != -1) { 3467949SAli.Saidi@ARM.com ::close(dataFd); 3477949SAli.Saidi@ARM.com dataFd = -1; 3487949SAli.Saidi@ARM.com } 3497949SAli.Saidi@ARM.com 3507949SAli.Saidi@ARM.com if (!dataEvent || !dataEvent->queued()) 3517949SAli.Saidi@ARM.com return; 3527949SAli.Saidi@ARM.com 3537949SAli.Saidi@ARM.com pollQueue.remove(dataEvent); 3547949SAli.Saidi@ARM.com delete dataEvent; 3557949SAli.Saidi@ARM.com dataEvent = NULL; 3567949SAli.Saidi@ARM.com curState = WaitForProtocolVersion; 3577949SAli.Saidi@ARM.com 3587949SAli.Saidi@ARM.com inform("VNC client detached\n"); 3597949SAli.Saidi@ARM.com DPRINTF(VNC, "detach vnc client %d\n", number); 3607949SAli.Saidi@ARM.com} 3617949SAli.Saidi@ARM.com 3627949SAli.Saidi@ARM.comvoid 3637949SAli.Saidi@ARM.comVncServer::sendError(const char* error_msg) 3647949SAli.Saidi@ARM.com{ 3657949SAli.Saidi@ARM.com uint32_t len = strlen(error_msg); 3667949SAli.Saidi@ARM.com write(&len); 3677949SAli.Saidi@ARM.com write(error_msg); 3687949SAli.Saidi@ARM.com} 3697949SAli.Saidi@ARM.com 3707949SAli.Saidi@ARM.comvoid 3717949SAli.Saidi@ARM.comVncServer::checkProtocolVersion() 3727949SAli.Saidi@ARM.com{ 3737949SAli.Saidi@ARM.com assert(curState == WaitForProtocolVersion); 3747949SAli.Saidi@ARM.com 3757949SAli.Saidi@ARM.com size_t len M5_VAR_USED; 3767949SAli.Saidi@ARM.com char version_string[13]; 3777949SAli.Saidi@ARM.com 3787949SAli.Saidi@ARM.com // Null terminate the message so it's easier to work with 3797949SAli.Saidi@ARM.com version_string[12] = 0; 3807949SAli.Saidi@ARM.com 3817949SAli.Saidi@ARM.com len = read((uint8_t*)version_string, 12); 3827949SAli.Saidi@ARM.com assert(len == 12); 3837949SAli.Saidi@ARM.com 3847949SAli.Saidi@ARM.com uint32_t major, minor; 3857949SAli.Saidi@ARM.com 3867949SAli.Saidi@ARM.com // Figure out the major/minor numbers 3877949SAli.Saidi@ARM.com if (sscanf(version_string, "RFB %03d.%03d\n", &major, &minor) != 2) { 3887949SAli.Saidi@ARM.com warn(" Malformed protocol version %s\n", version_string); 3897949SAli.Saidi@ARM.com sendError("Malformed protocol version\n"); 3907949SAli.Saidi@ARM.com detach(); 3917949SAli.Saidi@ARM.com } 3927949SAli.Saidi@ARM.com 3937949SAli.Saidi@ARM.com DPRINTF(VNC, "Client request protocol version %d.%d\n", major, minor); 3947949SAli.Saidi@ARM.com 3957949SAli.Saidi@ARM.com // If it's not 3.X we don't support it 3967949SAli.Saidi@ARM.com if (major != 3 || minor < 2) { 3977949SAli.Saidi@ARM.com warn("Unsupported VNC client version... disconnecting\n"); 3987949SAli.Saidi@ARM.com uint8_t err = AuthInvalid; 3997949SAli.Saidi@ARM.com write(&err); 4007949SAli.Saidi@ARM.com detach(); 4017949SAli.Saidi@ARM.com } 4027949SAli.Saidi@ARM.com // Auth is different based on version number 4037949SAli.Saidi@ARM.com if (minor < 7) { 4047949SAli.Saidi@ARM.com uint32_t sec_type = htobe((uint32_t)AuthNone); 4057949SAli.Saidi@ARM.com write(&sec_type); 4067949SAli.Saidi@ARM.com } else { 4077949SAli.Saidi@ARM.com uint8_t sec_cnt = 1; 4087949SAli.Saidi@ARM.com uint8_t sec_type = htobe((uint8_t)AuthNone); 4097949SAli.Saidi@ARM.com write(&sec_cnt); 4107949SAli.Saidi@ARM.com write(&sec_type); 4117949SAli.Saidi@ARM.com } 4127949SAli.Saidi@ARM.com 4137949SAli.Saidi@ARM.com // Wait for client to respond 4147949SAli.Saidi@ARM.com curState = WaitForSecurityResponse; 4157949SAli.Saidi@ARM.com} 4167949SAli.Saidi@ARM.com 4177949SAli.Saidi@ARM.comvoid 4187949SAli.Saidi@ARM.comVncServer::checkSecurity() 4197949SAli.Saidi@ARM.com{ 4207949SAli.Saidi@ARM.com assert(curState == WaitForSecurityResponse); 4217949SAli.Saidi@ARM.com 4227949SAli.Saidi@ARM.com uint8_t security_type; 4237949SAli.Saidi@ARM.com size_t len M5_VAR_USED = read(&security_type); 4247949SAli.Saidi@ARM.com 4257949SAli.Saidi@ARM.com assert(len == 1); 4267949SAli.Saidi@ARM.com 4277949SAli.Saidi@ARM.com if (security_type != AuthNone) { 4287949SAli.Saidi@ARM.com warn("Unknown VNC security type\n"); 4297949SAli.Saidi@ARM.com sendError("Unknown security type\n"); 4307949SAli.Saidi@ARM.com } 4317949SAli.Saidi@ARM.com 4327949SAli.Saidi@ARM.com DPRINTF(VNC, "Sending security auth OK\n"); 4337949SAli.Saidi@ARM.com 4347949SAli.Saidi@ARM.com uint32_t success = htobe(VncOK); 4357949SAli.Saidi@ARM.com write(&success); 4367949SAli.Saidi@ARM.com curState = WaitForClientInit; 4377949SAli.Saidi@ARM.com} 4387949SAli.Saidi@ARM.com 4397949SAli.Saidi@ARM.comvoid 4407949SAli.Saidi@ARM.comVncServer::sendServerInit() 4417949SAli.Saidi@ARM.com{ 4427949SAli.Saidi@ARM.com ServerInitMsg msg; 4437949SAli.Saidi@ARM.com 4447949SAli.Saidi@ARM.com DPRINTF(VNC, "Sending server init message to client\n"); 4457949SAli.Saidi@ARM.com 4467949SAli.Saidi@ARM.com msg.fbWidth = htobe(videoWidth()); 4477949SAli.Saidi@ARM.com msg.fbHeight = htobe(videoHeight()); 4487949SAli.Saidi@ARM.com 4497949SAli.Saidi@ARM.com msg.px.bpp = htobe(pixelFormat.bpp); 4507949SAli.Saidi@ARM.com msg.px.depth = htobe(pixelFormat.depth); 4517949SAli.Saidi@ARM.com msg.px.bigendian = htobe(pixelFormat.bigendian); 4527949SAli.Saidi@ARM.com msg.px.truecolor = htobe(pixelFormat.truecolor); 4537949SAli.Saidi@ARM.com msg.px.redmax = htobe(pixelFormat.redmax); 4547949SAli.Saidi@ARM.com msg.px.greenmax = htobe(pixelFormat.greenmax); 4557949SAli.Saidi@ARM.com msg.px.bluemax = htobe(pixelFormat.bluemax); 4567949SAli.Saidi@ARM.com msg.px.redshift = htobe(pixelFormat.redshift); 4577949SAli.Saidi@ARM.com msg.px.greenshift = htobe(pixelFormat.greenshift); 4587949SAli.Saidi@ARM.com msg.px.blueshift = htobe(pixelFormat.blueshift); 4597949SAli.Saidi@ARM.com memset(msg.px.padding, 0, 3); 4607949SAli.Saidi@ARM.com msg.namelen = 2; 4617949SAli.Saidi@ARM.com msg.namelen = htobe(msg.namelen); 4627949SAli.Saidi@ARM.com memcpy(msg.name, "M5", 2); 4637949SAli.Saidi@ARM.com 4647949SAli.Saidi@ARM.com write(&msg); 4657949SAli.Saidi@ARM.com curState = NormalPhase; 4667949SAli.Saidi@ARM.com} 4677949SAli.Saidi@ARM.com 4687949SAli.Saidi@ARM.com 4697949SAli.Saidi@ARM.comvoid 4707949SAli.Saidi@ARM.comVncServer::setPixelFormat() 4717949SAli.Saidi@ARM.com{ 4727949SAli.Saidi@ARM.com DPRINTF(VNC, "Received pixel format from client message\n"); 4737949SAli.Saidi@ARM.com 4747949SAli.Saidi@ARM.com PixelFormatMessage pfm; 4757949SAli.Saidi@ARM.com read1((uint8_t*)&pfm, sizeof(PixelFormatMessage)); 4767949SAli.Saidi@ARM.com 4777949SAli.Saidi@ARM.com DPRINTF(VNC, " -- bpp = %d; depth = %d; be = %d\n", pfm.px.bpp, 4787949SAli.Saidi@ARM.com pfm.px.depth, pfm.px.bigendian); 4797949SAli.Saidi@ARM.com DPRINTF(VNC, " -- true color = %d red,green,blue max = %d,%d,%d\n", 4807949SAli.Saidi@ARM.com pfm.px.truecolor, betoh(pfm.px.redmax), betoh(pfm.px.greenmax), 4817949SAli.Saidi@ARM.com betoh(pfm.px.bluemax)); 4827949SAli.Saidi@ARM.com DPRINTF(VNC, " -- red,green,blue shift = %d,%d,%d\n", pfm.px.redshift, 4837949SAli.Saidi@ARM.com pfm.px.greenshift, pfm.px.blueshift); 4847949SAli.Saidi@ARM.com 4857949SAli.Saidi@ARM.com if (betoh(pfm.px.bpp) != pixelFormat.bpp || 4867949SAli.Saidi@ARM.com betoh(pfm.px.depth) != pixelFormat.depth || 4877949SAli.Saidi@ARM.com betoh(pfm.px.bigendian) != pixelFormat.bigendian || 4887949SAli.Saidi@ARM.com betoh(pfm.px.truecolor) != pixelFormat.truecolor || 4897949SAli.Saidi@ARM.com betoh(pfm.px.redmax) != pixelFormat.redmax || 4907949SAli.Saidi@ARM.com betoh(pfm.px.greenmax) != pixelFormat.greenmax || 4917949SAli.Saidi@ARM.com betoh(pfm.px.bluemax) != pixelFormat.bluemax || 4927949SAli.Saidi@ARM.com betoh(pfm.px.redshift) != pixelFormat.redshift || 4937949SAli.Saidi@ARM.com betoh(pfm.px.greenshift) != pixelFormat.greenshift || 4947949SAli.Saidi@ARM.com betoh(pfm.px.blueshift) != pixelFormat.blueshift) 4957949SAli.Saidi@ARM.com fatal("VNC client doesn't support true color raw encoding\n"); 4967949SAli.Saidi@ARM.com} 4977949SAli.Saidi@ARM.com 4987949SAli.Saidi@ARM.comvoid 4997949SAli.Saidi@ARM.comVncServer::setEncodings() 5007949SAli.Saidi@ARM.com{ 5017949SAli.Saidi@ARM.com DPRINTF(VNC, "Received supported encodings from client\n"); 5027949SAli.Saidi@ARM.com 5037949SAli.Saidi@ARM.com PixelEncodingsMessage pem; 5047949SAli.Saidi@ARM.com read1((uint8_t*)&pem, sizeof(PixelEncodingsMessage)); 5057949SAli.Saidi@ARM.com 5067949SAli.Saidi@ARM.com pem.num_encodings = betoh(pem.num_encodings); 5077949SAli.Saidi@ARM.com 5087949SAli.Saidi@ARM.com DPRINTF(VNC, " -- %d encoding present\n", pem.num_encodings); 5097949SAli.Saidi@ARM.com supportsRawEnc = supportsResizeEnc = false; 5107949SAli.Saidi@ARM.com 5117949SAli.Saidi@ARM.com for (int x = 0; x < pem.num_encodings; x++) { 5127949SAli.Saidi@ARM.com int32_t encoding; 5137949SAli.Saidi@ARM.com size_t len M5_VAR_USED; 5147949SAli.Saidi@ARM.com len = read(&encoding); 5157949SAli.Saidi@ARM.com assert(len == sizeof(encoding)); 5167949SAli.Saidi@ARM.com DPRINTF(VNC, " -- supports %d\n", betoh(encoding)); 5177949SAli.Saidi@ARM.com 5187949SAli.Saidi@ARM.com switch (betoh(encoding)) { 5197949SAli.Saidi@ARM.com case EncodingRaw: 5207949SAli.Saidi@ARM.com supportsRawEnc = true; 5217949SAli.Saidi@ARM.com break; 5227949SAli.Saidi@ARM.com case EncodingDesktopSize: 5237949SAli.Saidi@ARM.com supportsResizeEnc = true; 5247949SAli.Saidi@ARM.com break; 5257949SAli.Saidi@ARM.com } 5267949SAli.Saidi@ARM.com } 5277949SAli.Saidi@ARM.com 5287949SAli.Saidi@ARM.com if (!supportsRawEnc) 5297949SAli.Saidi@ARM.com fatal("VNC clients must always support raw encoding\n"); 5307949SAli.Saidi@ARM.com} 5317949SAli.Saidi@ARM.com 5327949SAli.Saidi@ARM.comvoid 5337949SAli.Saidi@ARM.comVncServer::requestFbUpdate() 5347949SAli.Saidi@ARM.com{ 5357949SAli.Saidi@ARM.com DPRINTF(VNC, "Received frame buffer update request from client\n"); 5367949SAli.Saidi@ARM.com 5377949SAli.Saidi@ARM.com FrameBufferUpdateReq fbr; 5387949SAli.Saidi@ARM.com read1((uint8_t*)&fbr, sizeof(FrameBufferUpdateReq)); 5397949SAli.Saidi@ARM.com 5407949SAli.Saidi@ARM.com fbr.x = betoh(fbr.x); 5417949SAli.Saidi@ARM.com fbr.y = betoh(fbr.y); 5427949SAli.Saidi@ARM.com fbr.width = betoh(fbr.width); 5437949SAli.Saidi@ARM.com fbr.height = betoh(fbr.height); 5447949SAli.Saidi@ARM.com 5457949SAli.Saidi@ARM.com DPRINTF(VNC, " -- x = %d y = %d w = %d h = %d\n", fbr.x, fbr.y, fbr.width, 5467949SAli.Saidi@ARM.com fbr.height); 5477949SAli.Saidi@ARM.com 5487949SAli.Saidi@ARM.com sendFrameBufferUpdate(); 5497949SAli.Saidi@ARM.com} 5507949SAli.Saidi@ARM.com 5517949SAli.Saidi@ARM.comvoid 5527949SAli.Saidi@ARM.comVncServer::recvKeyboardInput() 5537949SAli.Saidi@ARM.com{ 5547949SAli.Saidi@ARM.com DPRINTF(VNC, "Received keyboard input from client\n"); 5557949SAli.Saidi@ARM.com KeyEventMessage kem; 5567949SAli.Saidi@ARM.com read1((uint8_t*)&kem, sizeof(KeyEventMessage)); 5577949SAli.Saidi@ARM.com 5587949SAli.Saidi@ARM.com kem.key = betoh(kem.key); 5597949SAli.Saidi@ARM.com DPRINTF(VNC, " -- received key code %d (%s)\n", kem.key, kem.down_flag ? 5607949SAli.Saidi@ARM.com "down" : "up"); 5617949SAli.Saidi@ARM.com 5627949SAli.Saidi@ARM.com if (keyboard) 5637949SAli.Saidi@ARM.com keyboard->keyPress(kem.key, kem.down_flag); 5647949SAli.Saidi@ARM.com} 5657949SAli.Saidi@ARM.com 5667949SAli.Saidi@ARM.comvoid 5677949SAli.Saidi@ARM.comVncServer::recvPointerInput() 5687949SAli.Saidi@ARM.com{ 5697949SAli.Saidi@ARM.com DPRINTF(VNC, "Received pointer input from client\n"); 5707949SAli.Saidi@ARM.com PointerEventMessage pem; 5717949SAli.Saidi@ARM.com 5727949SAli.Saidi@ARM.com read1((uint8_t*)&pem, sizeof(PointerEventMessage));; 5737949SAli.Saidi@ARM.com 5747949SAli.Saidi@ARM.com pem.x = betoh(pem.x); 5757949SAli.Saidi@ARM.com pem.y = betoh(pem.y); 5767949SAli.Saidi@ARM.com DPRINTF(VNC, " -- pointer at x = %d y = %d buttons = %#x\n", pem.x, pem.y, 5777949SAli.Saidi@ARM.com pem.button_mask); 5787949SAli.Saidi@ARM.com 5797949SAli.Saidi@ARM.com if (mouse) 5807949SAli.Saidi@ARM.com mouse->mouseAt(pem.x, pem.y, pem.button_mask); 5817949SAli.Saidi@ARM.com} 5827949SAli.Saidi@ARM.com 5837949SAli.Saidi@ARM.comvoid 5847949SAli.Saidi@ARM.comVncServer::recvCutText() 5857949SAli.Saidi@ARM.com{ 5867949SAli.Saidi@ARM.com DPRINTF(VNC, "Received client copy buffer message\n"); 5877949SAli.Saidi@ARM.com 5887949SAli.Saidi@ARM.com ClientCutTextMessage cct; 5897949SAli.Saidi@ARM.com read1((uint8_t*)&cct, sizeof(ClientCutTextMessage)); 5907949SAli.Saidi@ARM.com 5917949SAli.Saidi@ARM.com char str[1025]; 5927949SAli.Saidi@ARM.com size_t data_len = betoh(cct.length); 5937949SAli.Saidi@ARM.com DPRINTF(VNC, "String length %d\n", data_len); 5947949SAli.Saidi@ARM.com while (data_len > 0) { 5957949SAli.Saidi@ARM.com size_t len; 5967949SAli.Saidi@ARM.com size_t bytes_to_read = data_len > 1024 ? 1024 : data_len; 5977949SAli.Saidi@ARM.com len = read((uint8_t*)&str, bytes_to_read); 5987949SAli.Saidi@ARM.com str[bytes_to_read] = 0; 5997949SAli.Saidi@ARM.com data_len -= len; 6007949SAli.Saidi@ARM.com assert(data_len >= 0); 6017949SAli.Saidi@ARM.com DPRINTF(VNC, "Buffer: %s\n", str); 6027949SAli.Saidi@ARM.com } 6037949SAli.Saidi@ARM.com 6047949SAli.Saidi@ARM.com} 6057949SAli.Saidi@ARM.com 6067949SAli.Saidi@ARM.com 6077949SAli.Saidi@ARM.comvoid 6087949SAli.Saidi@ARM.comVncServer::sendFrameBufferUpdate() 6097949SAli.Saidi@ARM.com{ 6107949SAli.Saidi@ARM.com 6117949SAli.Saidi@ARM.com if (!clientRfb || dataFd <= 0 || curState != NormalPhase || !sendUpdate) { 6127949SAli.Saidi@ARM.com DPRINTF(VNC, "NOT sending framebuffer update\n"); 6137949SAli.Saidi@ARM.com return; 6147949SAli.Saidi@ARM.com } 6157949SAli.Saidi@ARM.com 6167949SAli.Saidi@ARM.com assert(vc); 6177949SAli.Saidi@ARM.com 6187949SAli.Saidi@ARM.com // The client will request data constantly, unless we throttle it 6197949SAli.Saidi@ARM.com sendUpdate = false; 6207949SAli.Saidi@ARM.com 6217949SAli.Saidi@ARM.com DPRINTF(VNC, "Sending framebuffer update\n"); 6227949SAli.Saidi@ARM.com 6237949SAli.Saidi@ARM.com FrameBufferUpdate fbu; 6247949SAli.Saidi@ARM.com FrameBufferRect fbr; 6257949SAli.Saidi@ARM.com 6267949SAli.Saidi@ARM.com fbu.type = ServerFrameBufferUpdate; 6277949SAli.Saidi@ARM.com fbu.num_rects = 1; 6287949SAli.Saidi@ARM.com fbr.x = 0; 6297949SAli.Saidi@ARM.com fbr.y = 0; 6307949SAli.Saidi@ARM.com fbr.width = videoWidth(); 6317949SAli.Saidi@ARM.com fbr.height = videoHeight(); 6327949SAli.Saidi@ARM.com fbr.encoding = EncodingRaw; 6337949SAli.Saidi@ARM.com 6347949SAli.Saidi@ARM.com // fix up endian 6357949SAli.Saidi@ARM.com fbu.num_rects = htobe(fbu.num_rects); 6367949SAli.Saidi@ARM.com fbr.x = htobe(fbr.x); 6377949SAli.Saidi@ARM.com fbr.y = htobe(fbr.y); 6387949SAli.Saidi@ARM.com fbr.width = htobe(fbr.width); 6397949SAli.Saidi@ARM.com fbr.height = htobe(fbr.height); 6407949SAli.Saidi@ARM.com fbr.encoding = htobe(fbr.encoding); 6417949SAli.Saidi@ARM.com 6427949SAli.Saidi@ARM.com // send headers to client 6437949SAli.Saidi@ARM.com write(&fbu); 6447949SAli.Saidi@ARM.com write(&fbr); 6457949SAli.Saidi@ARM.com 6467949SAli.Saidi@ARM.com assert(clientRfb); 6477949SAli.Saidi@ARM.com 6487949SAli.Saidi@ARM.com uint8_t *tmp = vc->convert(clientRfb); 6497949SAli.Saidi@ARM.com write(tmp, videoWidth() * videoHeight() * sizeof(uint32_t)); 6507949SAli.Saidi@ARM.com delete [] tmp; 6517949SAli.Saidi@ARM.com 6527949SAli.Saidi@ARM.com} 6537949SAli.Saidi@ARM.com 6547949SAli.Saidi@ARM.comvoid 6557949SAli.Saidi@ARM.comVncServer::sendFrameBufferResized() 6567949SAli.Saidi@ARM.com{ 6577949SAli.Saidi@ARM.com assert(clientRfb && dataFd > 0 && curState == NormalPhase); 6587949SAli.Saidi@ARM.com DPRINTF(VNC, "Sending framebuffer resize\n"); 6597949SAli.Saidi@ARM.com 6607949SAli.Saidi@ARM.com FrameBufferUpdate fbu; 6617949SAli.Saidi@ARM.com FrameBufferRect fbr; 6627949SAli.Saidi@ARM.com 6637949SAli.Saidi@ARM.com fbu.type = ServerFrameBufferUpdate; 6647949SAli.Saidi@ARM.com fbu.num_rects = 1; 6657949SAli.Saidi@ARM.com fbr.x = 0; 6667949SAli.Saidi@ARM.com fbr.y = 0; 6677949SAli.Saidi@ARM.com fbr.width = videoWidth(); 6687949SAli.Saidi@ARM.com fbr.height = videoHeight(); 6697949SAli.Saidi@ARM.com fbr.encoding = EncodingDesktopSize; 6707949SAli.Saidi@ARM.com 6717949SAli.Saidi@ARM.com // fix up endian 6727949SAli.Saidi@ARM.com fbu.num_rects = htobe(fbu.num_rects); 6737949SAli.Saidi@ARM.com fbr.x = htobe(fbr.x); 6747949SAli.Saidi@ARM.com fbr.y = htobe(fbr.y); 6757949SAli.Saidi@ARM.com fbr.width = htobe(fbr.width); 6767949SAli.Saidi@ARM.com fbr.height = htobe(fbr.height); 6777949SAli.Saidi@ARM.com fbr.encoding = htobe(fbr.encoding); 6787949SAli.Saidi@ARM.com 6797949SAli.Saidi@ARM.com // send headers to client 6807949SAli.Saidi@ARM.com write(&fbu); 6817949SAli.Saidi@ARM.com write(&fbr); 6827949SAli.Saidi@ARM.com 6837949SAli.Saidi@ARM.com // No actual data is sent in this message 6847949SAli.Saidi@ARM.com} 6857949SAli.Saidi@ARM.com 6867949SAli.Saidi@ARM.comvoid 6877949SAli.Saidi@ARM.comVncServer::setFrameBufferParams(VideoConvert::Mode mode, int width, int height) 6887949SAli.Saidi@ARM.com{ 6897949SAli.Saidi@ARM.com DPRINTF(VNC, "Updating video params: mode: %d width: %d height: %d\n", mode, 6907949SAli.Saidi@ARM.com width, height); 6917949SAli.Saidi@ARM.com 6927949SAli.Saidi@ARM.com if (mode != videoMode || width != videoWidth() || height != videoHeight()) { 6937949SAli.Saidi@ARM.com videoMode = mode; 6947949SAli.Saidi@ARM.com _videoWidth = width; 6957949SAli.Saidi@ARM.com _videoHeight = height; 6967949SAli.Saidi@ARM.com 6977949SAli.Saidi@ARM.com if (vc) 6987949SAli.Saidi@ARM.com delete vc; 6997949SAli.Saidi@ARM.com 7007949SAli.Saidi@ARM.com vc = new VideoConvert(mode, VideoConvert::rgb8888, videoWidth(), 7017949SAli.Saidi@ARM.com videoHeight()); 7027949SAli.Saidi@ARM.com 7038635Schris.emmons@arm.com if (captureEnabled) { 7048635Schris.emmons@arm.com // create bitmap of the frame with new attributes 7058635Schris.emmons@arm.com if (captureBitmap) 7068635Schris.emmons@arm.com delete captureBitmap; 7078635Schris.emmons@arm.com 7088635Schris.emmons@arm.com assert(clientRfb); 7098635Schris.emmons@arm.com captureBitmap = new Bitmap(videoMode, width, height, clientRfb); 7108635Schris.emmons@arm.com assert(captureBitmap); 7118635Schris.emmons@arm.com } 7128635Schris.emmons@arm.com 7137949SAli.Saidi@ARM.com if (dataFd > 0 && clientRfb && curState == NormalPhase) { 7147949SAli.Saidi@ARM.com if (supportsResizeEnc) 7157949SAli.Saidi@ARM.com sendFrameBufferResized(); 7167949SAli.Saidi@ARM.com else 7177949SAli.Saidi@ARM.com // The frame buffer changed size and we can't update the client 7187949SAli.Saidi@ARM.com detach(); 7197949SAli.Saidi@ARM.com } 7207949SAli.Saidi@ARM.com } 7217949SAli.Saidi@ARM.com} 7227949SAli.Saidi@ARM.com 7237949SAli.Saidi@ARM.com// create the VNC server object 7247949SAli.Saidi@ARM.comVncServer * 7257949SAli.Saidi@ARM.comVncServerParams::create() 7267949SAli.Saidi@ARM.com{ 7277949SAli.Saidi@ARM.com return new VncServer(this); 7287949SAli.Saidi@ARM.com} 7298635Schris.emmons@arm.com 7308635Schris.emmons@arm.comvoid 7318635Schris.emmons@arm.comVncServer::captureFrameBuffer() 7328635Schris.emmons@arm.com{ 7338635Schris.emmons@arm.com assert(captureBitmap); 7348635Schris.emmons@arm.com 7358635Schris.emmons@arm.com // skip identical frames 7368635Schris.emmons@arm.com uint64_t new_hash = captureBitmap->getHash(); 7378635Schris.emmons@arm.com if (captureLastHash == new_hash) 7388635Schris.emmons@arm.com return; 7398635Schris.emmons@arm.com captureLastHash = new_hash; 7408635Schris.emmons@arm.com 7418635Schris.emmons@arm.com // get the filename for the current frame 7428635Schris.emmons@arm.com char frameFilenameBuffer[64]; 7438635Schris.emmons@arm.com snprintf(frameFilenameBuffer, 64, "fb.%06d.%lld.bmp.gz", 7448635Schris.emmons@arm.com captureCurrentFrame, static_cast<long long int>(curTick())); 7458635Schris.emmons@arm.com const string frameFilename(frameFilenameBuffer); 7468635Schris.emmons@arm.com 7478635Schris.emmons@arm.com // create the compressed framebuffer file 7488635Schris.emmons@arm.com ostream *fb_out = simout.create(captureOutputDirectory + frameFilename, 7498635Schris.emmons@arm.com true); 7508635Schris.emmons@arm.com captureBitmap->write(fb_out); 7518635Schris.emmons@arm.com simout.close(fb_out); 7528635Schris.emmons@arm.com 7538635Schris.emmons@arm.com ++captureCurrentFrame; 7548635Schris.emmons@arm.com} 755