vncinput.cc revision 7949
11060SN/A/* 29814Sandreas.hansson@arm.com * Copyright (c) 2010 ARM Limited 39920Syasuko.eckert@amd.com * All rights reserved 47944SGiacomo.Gabrielli@arm.com * 57944SGiacomo.Gabrielli@arm.com * The license below extends only to copyright in the software and shall 67944SGiacomo.Gabrielli@arm.com * not be construed as granting a license to any other intellectual 77944SGiacomo.Gabrielli@arm.com * property including but not limited to intellectual property relating 87944SGiacomo.Gabrielli@arm.com * to a hardware implementation of the functionality of the software 97944SGiacomo.Gabrielli@arm.com * licensed hereunder. You may use the software subject to the license 107944SGiacomo.Gabrielli@arm.com * terms below provided that you ensure that this notice is replicated 117944SGiacomo.Gabrielli@arm.com * unmodified and in its entirety in all distributions of the software, 127944SGiacomo.Gabrielli@arm.com * modified or unmodified, in source code or in binary form. 137944SGiacomo.Gabrielli@arm.com * 147944SGiacomo.Gabrielli@arm.com * Redistribution and use in source and binary forms, with or without 152702Sktlim@umich.edu * modification, are permitted provided that the following conditions are 166973Stjones1@inf.ed.ac.uk * met: redistributions of source code must retain the above copyright 171060SN/A * notice, this list of conditions and the following disclaimer; 181060SN/A * redistributions in binary form must reproduce the above copyright 191060SN/A * notice, this list of conditions and the following disclaimer in the 201060SN/A * documentation and/or other materials provided with the distribution; 211060SN/A * neither the name of the copyright holders nor the names of its 221060SN/A * contributors may be used to endorse or promote products derived from 231060SN/A * this software without specific prior written permission. 241060SN/A * 251060SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 261060SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 271060SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 281060SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 291060SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 301060SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 311060SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 321060SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 331060SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 341060SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 351060SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 361060SN/A * 371060SN/A * Authors: Ali Saidi 381060SN/A * William Wang 391060SN/A */ 401060SN/A 412665Ssaidi@eecs.umich.edu/** @file 422665Ssaidi@eecs.umich.edu * Implementiation of a VNC server 436973Stjones1@inf.ed.ac.uk */ 441060SN/A 451060SN/A#include <cstdio> 461464SN/A 471464SN/A#include <sys/ioctl.h> 481060SN/A#include <sys/termios.h> 492731Sktlim@umich.edu#include <errno.h> 502292SN/A#include <poll.h> 511464SN/A#include <unistd.h> 528733Sgeoffrey.blake@arm.com 531060SN/A#include "base/atomicio.hh" 547720Sgblack@eecs.umich.edu#include "base/misc.hh" 551060SN/A#include "base/socket.hh" 566658Snate@binkert.org#include "base/trace.hh" 578887Sgeoffrey.blake@arm.com#include "base/vnc/vncserver.hh" 583770Sgblack@eecs.umich.edu#include "sim/byteswap.hh" 591464SN/A 601464SN/Ausing namespace std; 612669Sktlim@umich.edu 621060SN/A/** 636973Stjones1@inf.ed.ac.uk * Poll event for the listen socket 642669Sktlim@umich.edu */ 657678Sgblack@eecs.umich.eduVncServer::ListenEvent::ListenEvent(VncServer *vs, int fd, int e) 668817Sgblack@eecs.umich.edu : PollEvent(fd, e), vncserver(vs) 672292SN/A{ 686023Snate@binkert.org} 691060SN/A 701060SN/Avoid 711060SN/AVncServer::ListenEvent::process(int revent) 721060SN/A{ 731060SN/A vncserver->accept(); 741060SN/A} 751060SN/A 769044SAli.Saidi@ARM.com/** 771060SN/A * Poll event for the data socket 781060SN/A */ 791060SN/AVncServer::DataEvent::DataEvent(VncServer *vs, int fd, int e) 802733Sktlim@umich.edu : PollEvent(fd, e), vncserver(vs) 812733Sktlim@umich.edu{ 821060SN/A} 832292SN/A 842107SN/Avoid 852690Sktlim@umich.eduVncServer::DataEvent::process(int revent) 862107SN/A{ 872690Sktlim@umich.edu if (revent & POLLIN) 882690Sktlim@umich.edu vncserver->data(); 891060SN/A else if (revent & POLLNVAL) 902292SN/A vncserver->detach(); 912292SN/A} 928486Sgblack@eecs.umich.edu 932292SN/A/** 942292SN/A * VncServer 952292SN/A */ 962292SN/AVncServer::VncServer(const Params *p) 971060SN/A : SimObject(p), listenEvent(NULL), dataEvent(NULL), number(p->number), 985543Ssaidi@eecs.umich.edu dataFd(-1), _videoWidth(1), _videoHeight(1), clientRfb(0), keyboard(NULL), 998902Sandreas.hansson@arm.com mouse(NULL), sendUpdate(false), videoMode(VideoConvert::UnknownMode), 1001060SN/A vc(NULL) 1011060SN/A{ 1029046SAli.Saidi@ARM.com if (p->port) 1039046SAli.Saidi@ARM.com listen(p->port); 1049046SAli.Saidi@ARM.com 1059046SAli.Saidi@ARM.com curState = WaitForProtocolVersion; 1069046SAli.Saidi@ARM.com 1079046SAli.Saidi@ARM.com 1089046SAli.Saidi@ARM.com // currently we only support this one pixel format 1099046SAli.Saidi@ARM.com // unpacked 32bit rgb (rgb888 + 8 bits of nothing/alpha) 1109046SAli.Saidi@ARM.com // keep it around for telling the client and making 1119046SAli.Saidi@ARM.com // sure the client cooperates 1129046SAli.Saidi@ARM.com pixelFormat.bpp = 32; 1139046SAli.Saidi@ARM.com pixelFormat.depth = 24; 1149046SAli.Saidi@ARM.com pixelFormat.bigendian = 0; 1159046SAli.Saidi@ARM.com pixelFormat.truecolor = 1; 1169046SAli.Saidi@ARM.com pixelFormat.redmax = 0xff; 1179046SAli.Saidi@ARM.com pixelFormat.greenmax = 0xff; 1189046SAli.Saidi@ARM.com pixelFormat.bluemax = 0xff; 1199046SAli.Saidi@ARM.com pixelFormat.redshift = 16; 1209046SAli.Saidi@ARM.com pixelFormat.greenshift = 8; 1219046SAli.Saidi@ARM.com pixelFormat.blueshift = 0; 1229046SAli.Saidi@ARM.com 1239046SAli.Saidi@ARM.com 1249046SAli.Saidi@ARM.com DPRINTF(VNC, "Vnc server created at port %d\n", p->port); 1259046SAli.Saidi@ARM.com} 1269046SAli.Saidi@ARM.com 1279046SAli.Saidi@ARM.comVncServer::~VncServer() 1289046SAli.Saidi@ARM.com{ 1299046SAli.Saidi@ARM.com if (dataFd != -1) 1309046SAli.Saidi@ARM.com ::close(dataFd); 1319046SAli.Saidi@ARM.com 1329046SAli.Saidi@ARM.com if (listenEvent) 1339046SAli.Saidi@ARM.com delete listenEvent; 1349046SAli.Saidi@ARM.com 1359046SAli.Saidi@ARM.com if (dataEvent) 1369046SAli.Saidi@ARM.com delete dataEvent; 1379046SAli.Saidi@ARM.com} 1389046SAli.Saidi@ARM.com 1399046SAli.Saidi@ARM.com 1409046SAli.Saidi@ARM.com//socket creation and vnc client attach 1419046SAli.Saidi@ARM.comvoid 1429046SAli.Saidi@ARM.comVncServer::listen(int port) 1439046SAli.Saidi@ARM.com{ 1449046SAli.Saidi@ARM.com if (ListenSocket::allDisabled()) { 1459046SAli.Saidi@ARM.com warn_once("Sockets disabled, not accepting vnc client connections"); 1469046SAli.Saidi@ARM.com return; 1479046SAli.Saidi@ARM.com } 1489046SAli.Saidi@ARM.com 1499046SAli.Saidi@ARM.com while (!listener.listen(port, true)) { 1509046SAli.Saidi@ARM.com DPRINTF(VNC, 1519046SAli.Saidi@ARM.com "can't bind address vnc server port %d in use PID %d\n", 1529046SAli.Saidi@ARM.com port, getpid()); 1539046SAli.Saidi@ARM.com port++; 1549046SAli.Saidi@ARM.com } 1559046SAli.Saidi@ARM.com 1569046SAli.Saidi@ARM.com int p1, p2; 1579046SAli.Saidi@ARM.com p2 = name().rfind('.') - 1; 1589046SAli.Saidi@ARM.com p1 = name().rfind('.', p2); 1599046SAli.Saidi@ARM.com ccprintf(cerr, "Listening for %s connection on port %d\n", 1609046SAli.Saidi@ARM.com name().substr(p1 + 1, p2 - p1), port); 1612292SN/A 1622107SN/A listenEvent = new ListenEvent(this, listener.getfd(), POLLIN); 1639046SAli.Saidi@ARM.com pollQueue.schedule(listenEvent); 1649046SAli.Saidi@ARM.com} 1659046SAli.Saidi@ARM.com 1669046SAli.Saidi@ARM.com// attach a vnc client 16710030SAli.Saidi@ARM.comvoid 16810030SAli.Saidi@ARM.comVncServer::accept() 1699046SAli.Saidi@ARM.com{ 1709046SAli.Saidi@ARM.com if (!listener.islistening()) 1719046SAli.Saidi@ARM.com panic("%s: cannot accept a connection if not listening!", name()); 1729046SAli.Saidi@ARM.com 1739046SAli.Saidi@ARM.com int fd = listener.accept(true); 1749046SAli.Saidi@ARM.com if (dataFd != -1) { 1759046SAli.Saidi@ARM.com char message[] = "vnc server already attached!\n"; 1769046SAli.Saidi@ARM.com atomic_write(fd, message, sizeof(message)); 1779046SAli.Saidi@ARM.com ::close(fd); 1789046SAli.Saidi@ARM.com return; 1799046SAli.Saidi@ARM.com } 1809046SAli.Saidi@ARM.com 1819046SAli.Saidi@ARM.com dataFd = fd; 1829046SAli.Saidi@ARM.com 1839046SAli.Saidi@ARM.com // Send our version number to the client 1849046SAli.Saidi@ARM.com write((uint8_t*)vncVersion(), strlen(vncVersion())); 1859046SAli.Saidi@ARM.com 1869046SAli.Saidi@ARM.com // read the client response 1879046SAli.Saidi@ARM.com dataEvent = new DataEvent(this, dataFd, POLLIN); 1889046SAli.Saidi@ARM.com pollQueue.schedule(dataEvent); 1899046SAli.Saidi@ARM.com 1909046SAli.Saidi@ARM.com inform("VNC client attached\n"); 1919046SAli.Saidi@ARM.com} 1929046SAli.Saidi@ARM.com 1939046SAli.Saidi@ARM.com// data called by data event 1949046SAli.Saidi@ARM.comvoid 1959046SAli.Saidi@ARM.comVncServer::data() 1969046SAli.Saidi@ARM.com{ 1979046SAli.Saidi@ARM.com // We have new data, see if we can handle it 1989046SAli.Saidi@ARM.com size_t len; 1999046SAli.Saidi@ARM.com DPRINTF(VNC, "Vnc client message recieved\n"); 2009046SAli.Saidi@ARM.com 2019046SAli.Saidi@ARM.com switch (curState) { 2029046SAli.Saidi@ARM.com case WaitForProtocolVersion: 2039046SAli.Saidi@ARM.com checkProtocolVersion(); 2049046SAli.Saidi@ARM.com break; 2059046SAli.Saidi@ARM.com case WaitForSecurityResponse: 2069046SAli.Saidi@ARM.com checkSecurity(); 2079046SAli.Saidi@ARM.com break; 2089046SAli.Saidi@ARM.com case WaitForClientInit: 2099046SAli.Saidi@ARM.com // Don't care about shared, just need to read it out of the socket 2108502Sgblack@eecs.umich.edu uint8_t shared; 2111060SN/A len = read(&shared); 2129046SAli.Saidi@ARM.com assert(len == 1); 2139046SAli.Saidi@ARM.com 2149046SAli.Saidi@ARM.com // Send our idea of the frame buffer 2159046SAli.Saidi@ARM.com sendServerInit(); 2169046SAli.Saidi@ARM.com 2179046SAli.Saidi@ARM.com break; 2189046SAli.Saidi@ARM.com case NormalPhase: 2199046SAli.Saidi@ARM.com uint8_t message_type; 2209046SAli.Saidi@ARM.com len = read(&message_type); 2219046SAli.Saidi@ARM.com if (!len) { 2229046SAli.Saidi@ARM.com detach(); 2239046SAli.Saidi@ARM.com return; 2249046SAli.Saidi@ARM.com } 2259046SAli.Saidi@ARM.com assert(len == 1); 2269046SAli.Saidi@ARM.com 2279046SAli.Saidi@ARM.com switch (message_type) { 2289046SAli.Saidi@ARM.com case ClientSetPixelFormat: 2299046SAli.Saidi@ARM.com setPixelFormat(); 2309046SAli.Saidi@ARM.com break; 2319046SAli.Saidi@ARM.com case ClientSetEncodings: 2329046SAli.Saidi@ARM.com setEncodings(); 2339046SAli.Saidi@ARM.com break; 2349046SAli.Saidi@ARM.com case ClientFrameBufferUpdate: 2359046SAli.Saidi@ARM.com requestFbUpdate(); 2369046SAli.Saidi@ARM.com break; 2379046SAli.Saidi@ARM.com case ClientKeyEvent: 2389046SAli.Saidi@ARM.com recvKeyboardInput(); 2399046SAli.Saidi@ARM.com break; 2409046SAli.Saidi@ARM.com case ClientPointerEvent: 2419046SAli.Saidi@ARM.com recvPointerInput(); 2429046SAli.Saidi@ARM.com break; 2439046SAli.Saidi@ARM.com case ClientCutText: 2449046SAli.Saidi@ARM.com recvCutText(); 2459046SAli.Saidi@ARM.com break; 2469046SAli.Saidi@ARM.com default: 2479046SAli.Saidi@ARM.com panic("Unimplemented message type recv from client: %d\n", 2489046SAli.Saidi@ARM.com message_type); 2499046SAli.Saidi@ARM.com break; 2509046SAli.Saidi@ARM.com } 2519046SAli.Saidi@ARM.com break; 2529046SAli.Saidi@ARM.com default: 2539046SAli.Saidi@ARM.com panic("Unknown vnc server state\n"); 2549046SAli.Saidi@ARM.com } 2559046SAli.Saidi@ARM.com} 2569046SAli.Saidi@ARM.com 2579046SAli.Saidi@ARM.com 2589046SAli.Saidi@ARM.com// read from socket 2599046SAli.Saidi@ARM.comsize_t 2609046SAli.Saidi@ARM.comVncServer::read(uint8_t *buf, size_t len) 2619046SAli.Saidi@ARM.com{ 2629046SAli.Saidi@ARM.com if (dataFd < 0) 2639046SAli.Saidi@ARM.com panic("vnc not properly attached.\n"); 2649046SAli.Saidi@ARM.com 2659046SAli.Saidi@ARM.com size_t ret; 2669046SAli.Saidi@ARM.com do { 2679046SAli.Saidi@ARM.com ret = ::read(dataFd, buf, len); 2689046SAli.Saidi@ARM.com } while (ret == -1 && errno == EINTR); 2699046SAli.Saidi@ARM.com 2709046SAli.Saidi@ARM.com 2719046SAli.Saidi@ARM.com if (ret <= 0){ 2729046SAli.Saidi@ARM.com DPRINTF(VNC, "Read failed.\n"); 2739046SAli.Saidi@ARM.com detach(); 2749046SAli.Saidi@ARM.com return 0; 2759046SAli.Saidi@ARM.com } 2769046SAli.Saidi@ARM.com 2779046SAli.Saidi@ARM.com return ret; 2789046SAli.Saidi@ARM.com} 2799046SAli.Saidi@ARM.com 2809046SAli.Saidi@ARM.comsize_t 2819046SAli.Saidi@ARM.comVncServer::read1(uint8_t *buf, size_t len) 2829046SAli.Saidi@ARM.com{ 2839046SAli.Saidi@ARM.com size_t read_len M5_VAR_USED; 2849046SAli.Saidi@ARM.com read_len = read(buf + 1, len - 1); 2859046SAli.Saidi@ARM.com assert(read_len == len - 1); 2869046SAli.Saidi@ARM.com return read_len; 2879046SAli.Saidi@ARM.com} 2889046SAli.Saidi@ARM.com 2899046SAli.Saidi@ARM.com 2909046SAli.Saidi@ARM.comtemplate<typename T> 2919046SAli.Saidi@ARM.comsize_t 2929046SAli.Saidi@ARM.comVncServer::read(T* val) 2939046SAli.Saidi@ARM.com{ 2949046SAli.Saidi@ARM.com return read((uint8_t*)val, sizeof(T)); 2951060SN/A} 2961060SN/A 2971060SN/A// write to socket 2981060SN/Asize_t 2991060SN/AVncServer::write(const uint8_t *buf, size_t len) 3001060SN/A{ 3015358Sgblack@eecs.umich.edu if (dataFd < 0) 3025358Sgblack@eecs.umich.edu panic("Vnc client not properly attached.\n"); 3035358Sgblack@eecs.umich.edu 3045358Sgblack@eecs.umich.edu ssize_t ret; 3055358Sgblack@eecs.umich.edu ret = atomic_write(dataFd, buf, len); 3065358Sgblack@eecs.umich.edu 3075358Sgblack@eecs.umich.edu if (ret < len) 3085358Sgblack@eecs.umich.edu detach(); 3095358Sgblack@eecs.umich.edu 3105358Sgblack@eecs.umich.edu return ret; 3115358Sgblack@eecs.umich.edu} 3125358Sgblack@eecs.umich.edu 3135358Sgblack@eecs.umich.edutemplate<typename T> 3148444Sgblack@eecs.umich.edusize_t 3157520Sgblack@eecs.umich.eduVncServer::write(T* val) 3168444Sgblack@eecs.umich.edu{ 3178444Sgblack@eecs.umich.edu return write((uint8_t*)val, sizeof(T)); 3187520Sgblack@eecs.umich.edu} 3196974Stjones1@inf.ed.ac.uk 3206974Stjones1@inf.ed.ac.uksize_t 3216974Stjones1@inf.ed.ac.ukVncServer::write(const char* str) 3226974Stjones1@inf.ed.ac.uk{ 3236973Stjones1@inf.ed.ac.uk return write((uint8_t*)str, strlen(str)); 3246974Stjones1@inf.ed.ac.uk} 3256974Stjones1@inf.ed.ac.uk 3266973Stjones1@inf.ed.ac.uk// detach a vnc client 3276973Stjones1@inf.ed.ac.ukvoid 3286973Stjones1@inf.ed.ac.ukVncServer::detach() 3296973Stjones1@inf.ed.ac.uk{ 3301060SN/A if (dataFd != -1) { 3317944SGiacomo.Gabrielli@arm.com ::close(dataFd); 3329046SAli.Saidi@ARM.com dataFd = -1; 3339046SAli.Saidi@ARM.com } 3347944SGiacomo.Gabrielli@arm.com 3357944SGiacomo.Gabrielli@arm.com if (!dataEvent || !dataEvent->queued()) 3369046SAli.Saidi@ARM.com return; 3379046SAli.Saidi@ARM.com 3387944SGiacomo.Gabrielli@arm.com pollQueue.remove(dataEvent); 3398545Ssaidi@eecs.umich.edu delete dataEvent; 3408545Ssaidi@eecs.umich.edu dataEvent = NULL; 3418545Ssaidi@eecs.umich.edu curState = WaitForProtocolVersion; 3428545Ssaidi@eecs.umich.edu 3438545Ssaidi@eecs.umich.edu inform("VNC client detached\n"); 3449046SAli.Saidi@ARM.com DPRINTF(VNC, "detach vnc client %d\n", number); 3459046SAli.Saidi@ARM.com} 3468545Ssaidi@eecs.umich.edu 3478545Ssaidi@eecs.umich.eduvoid 3488545Ssaidi@eecs.umich.eduVncServer::sendError(const char* error_msg) 3498545Ssaidi@eecs.umich.edu{ 3508545Ssaidi@eecs.umich.edu uint32_t len = strlen(error_msg); 3519046SAli.Saidi@ARM.com write(&len); 3529046SAli.Saidi@ARM.com write(error_msg); 3538545Ssaidi@eecs.umich.edu} 3547944SGiacomo.Gabrielli@arm.com 3557944SGiacomo.Gabrielli@arm.comvoid 3567944SGiacomo.Gabrielli@arm.comVncServer::checkProtocolVersion() 3577944SGiacomo.Gabrielli@arm.com{ 3587944SGiacomo.Gabrielli@arm.com assert(curState == WaitForProtocolVersion); 3597944SGiacomo.Gabrielli@arm.com 3609046SAli.Saidi@ARM.com size_t len M5_VAR_USED; 3617944SGiacomo.Gabrielli@arm.com char version_string[13]; 3627944SGiacomo.Gabrielli@arm.com 3631060SN/A // Null terminate the message so it's easier to work with 3642292SN/A version_string[12] = 0; 3652292SN/A 3662292SN/A len = read((uint8_t*)version_string, 12); 3672292SN/A assert(len == 12); 3683770Sgblack@eecs.umich.edu 3693770Sgblack@eecs.umich.edu uint32_t major, minor; 3703770Sgblack@eecs.umich.edu 3713770Sgblack@eecs.umich.edu // Figure out the major/minor numbers 3723770Sgblack@eecs.umich.edu if (sscanf(version_string, "RFB %03d.%03d\n", &major, &minor) != 2) { 3733770Sgblack@eecs.umich.edu warn(" Malformed protocol version %s\n", version_string); 3743770Sgblack@eecs.umich.edu sendError("Malformed protocol version\n"); 3753770Sgblack@eecs.umich.edu detach(); 3763770Sgblack@eecs.umich.edu } 3773770Sgblack@eecs.umich.edu 3783770Sgblack@eecs.umich.edu DPRINTF(VNC, "Client request protocol version %d.%d\n", major, minor); 3799046SAli.Saidi@ARM.com 3803770Sgblack@eecs.umich.edu // If it's not 3.X we don't support it 3813770Sgblack@eecs.umich.edu if (major != 3 || minor < 2) { 3823770Sgblack@eecs.umich.edu warn("Unsupported VNC client version... disconnecting\n"); 3833770Sgblack@eecs.umich.edu uint8_t err = AuthInvalid; 3843770Sgblack@eecs.umich.edu write(&err); 3853770Sgblack@eecs.umich.edu detach(); 3863770Sgblack@eecs.umich.edu } 3873770Sgblack@eecs.umich.edu // Auth is different based on version number 3883770Sgblack@eecs.umich.edu if (minor < 7) { 3893770Sgblack@eecs.umich.edu uint32_t sec_type = htobe((uint32_t)AuthNone); 3903770Sgblack@eecs.umich.edu write(&sec_type); 3913770Sgblack@eecs.umich.edu } else { 3923770Sgblack@eecs.umich.edu uint8_t sec_cnt = 1; 3933770Sgblack@eecs.umich.edu uint8_t sec_type = htobe((uint8_t)AuthNone); 3943770Sgblack@eecs.umich.edu write(&sec_cnt); 3953770Sgblack@eecs.umich.edu write(&sec_type); 3963770Sgblack@eecs.umich.edu } 3973770Sgblack@eecs.umich.edu 3983770Sgblack@eecs.umich.edu // Wait for client to respond 3993770Sgblack@eecs.umich.edu curState = WaitForSecurityResponse; 4003770Sgblack@eecs.umich.edu} 4013770Sgblack@eecs.umich.edu 4023770Sgblack@eecs.umich.eduvoid 4033770Sgblack@eecs.umich.eduVncServer::checkSecurity() 4043770Sgblack@eecs.umich.edu{ 4053770Sgblack@eecs.umich.edu assert(curState == WaitForSecurityResponse); 4063770Sgblack@eecs.umich.edu 4073770Sgblack@eecs.umich.edu uint8_t security_type; 4083770Sgblack@eecs.umich.edu size_t len M5_VAR_USED = read(&security_type); 4093770Sgblack@eecs.umich.edu 4103770Sgblack@eecs.umich.edu assert(len == 1); 4113770Sgblack@eecs.umich.edu 4123770Sgblack@eecs.umich.edu if (security_type != AuthNone) { 4133770Sgblack@eecs.umich.edu warn("Unknown VNC security type\n"); 4143770Sgblack@eecs.umich.edu sendError("Unknown security type\n"); 4153770Sgblack@eecs.umich.edu } 4163770Sgblack@eecs.umich.edu 4173770Sgblack@eecs.umich.edu DPRINTF(VNC, "Sending security auth OK\n"); 4183770Sgblack@eecs.umich.edu 4193770Sgblack@eecs.umich.edu uint32_t success = htobe(VncOK); 4203770Sgblack@eecs.umich.edu write(&success); 4213770Sgblack@eecs.umich.edu curState = WaitForClientInit; 4223770Sgblack@eecs.umich.edu} 4233770Sgblack@eecs.umich.edu 4243770Sgblack@eecs.umich.eduvoid 4253770Sgblack@eecs.umich.eduVncServer::sendServerInit() 4264636Sgblack@eecs.umich.edu{ 4274636Sgblack@eecs.umich.edu ServerInitMsg msg; 4287720Sgblack@eecs.umich.edu 4297720Sgblack@eecs.umich.edu DPRINTF(VNC, "Sending server init message to client\n"); 4304636Sgblack@eecs.umich.edu 4314636Sgblack@eecs.umich.edu msg.fbWidth = htobe(videoWidth()); 4324636Sgblack@eecs.umich.edu msg.fbHeight = htobe(videoHeight()); 4338502Sgblack@eecs.umich.edu 4348502Sgblack@eecs.umich.edu msg.px.bpp = htobe(pixelFormat.bpp); 4358502Sgblack@eecs.umich.edu msg.px.depth = htobe(pixelFormat.depth); 4363770Sgblack@eecs.umich.edu msg.px.bigendian = htobe(pixelFormat.bigendian); 4372292SN/A msg.px.truecolor = htobe(pixelFormat.truecolor); 4382292SN/A msg.px.redmax = htobe(pixelFormat.redmax); 4392292SN/A msg.px.greenmax = htobe(pixelFormat.greenmax); 4408502Sgblack@eecs.umich.edu msg.px.bluemax = htobe(pixelFormat.bluemax); 4411060SN/A msg.px.redshift = htobe(pixelFormat.redshift); 4421060SN/A msg.px.greenshift = htobe(pixelFormat.greenshift); 4431060SN/A msg.px.blueshift = htobe(pixelFormat.blueshift); 4441060SN/A memset(msg.px.padding, 0, 3); 4451464SN/A msg.namelen = 2; 4461684SN/A msg.namelen = htobe(msg.namelen); 4471464SN/A memcpy(msg.name, "M5", 2); 4481060SN/A 4491464SN/A write(&msg); 4501060SN/A curState = NormalPhase; 4511060SN/A} 4521060SN/A 4531060SN/A 4541060SN/Avoid 4551060SN/AVncServer::setPixelFormat() 4563326Sktlim@umich.edu{ 4575712Shsul@eecs.umich.edu DPRINTF(VNC, "Received pixel format from client message\n"); 4583326Sktlim@umich.edu 4598832SAli.Saidi@ARM.com PixelFormatMessage pfm; 4608832SAli.Saidi@ARM.com read1((uint8_t*)&pfm, sizeof(PixelFormatMessage)); 4618832SAli.Saidi@ARM.com 4625714Shsul@eecs.umich.edu DPRINTF(VNC, " -- bpp = %d; depth = %d; be = %d\n", pfm.px.bpp, 4635714Shsul@eecs.umich.edu pfm.px.depth, pfm.px.bigendian); 4645714Shsul@eecs.umich.edu DPRINTF(VNC, " -- true color = %d red,green,blue max = %d,%d,%d\n", 4651060SN/A pfm.px.truecolor, betoh(pfm.px.redmax), betoh(pfm.px.greenmax), 4662132SN/A betoh(pfm.px.bluemax)); 4671060SN/A DPRINTF(VNC, " -- red,green,blue shift = %d,%d,%d\n", pfm.px.redshift, 4681060SN/A pfm.px.greenshift, pfm.px.blueshift); 4691060SN/A 4701060SN/A if (betoh(pfm.px.bpp) != pixelFormat.bpp || 4712292SN/A betoh(pfm.px.depth) != pixelFormat.depth || 4721060SN/A betoh(pfm.px.bigendian) != pixelFormat.bigendian || 4731060SN/A betoh(pfm.px.truecolor) != pixelFormat.truecolor || 4741060SN/A betoh(pfm.px.redmax) != pixelFormat.redmax || 4757720Sgblack@eecs.umich.edu betoh(pfm.px.greenmax) != pixelFormat.greenmax || 4767720Sgblack@eecs.umich.edu betoh(pfm.px.bluemax) != pixelFormat.bluemax || 4773965Sgblack@eecs.umich.edu betoh(pfm.px.redshift) != pixelFormat.redshift || 4787720Sgblack@eecs.umich.edu betoh(pfm.px.greenshift) != pixelFormat.greenshift || 4793965Sgblack@eecs.umich.edu betoh(pfm.px.blueshift) != pixelFormat.blueshift) 4802935Sksewell@umich.edu fatal("VNC client doesn't support true color raw encoding\n"); 4817720Sgblack@eecs.umich.edu} 4821060SN/A 4833794Sgblack@eecs.umich.eduvoid 4847720Sgblack@eecs.umich.eduVncServer::setEncodings() 4853794Sgblack@eecs.umich.edu{ 4863794Sgblack@eecs.umich.edu DPRINTF(VNC, "Received supported encodings from client\n"); 4877720Sgblack@eecs.umich.edu 4881060SN/A PixelEncodingsMessage pem; 4894636Sgblack@eecs.umich.edu read1((uint8_t*)&pem, sizeof(PixelEncodingsMessage)); 4907720Sgblack@eecs.umich.edu 4914636Sgblack@eecs.umich.edu pem.num_encodings = betoh(pem.num_encodings); 4921060SN/A 4933794Sgblack@eecs.umich.edu DPRINTF(VNC, " -- %d encoding present\n", pem.num_encodings); 4943794Sgblack@eecs.umich.edu supportsRawEnc = supportsResizeEnc = false; 4959046SAli.Saidi@ARM.com 4963794Sgblack@eecs.umich.edu for (int x = 0; x < pem.num_encodings; x++) { 4973794Sgblack@eecs.umich.edu int32_t encoding; 4983794Sgblack@eecs.umich.edu size_t len M5_VAR_USED; 4993794Sgblack@eecs.umich.edu len = read(&encoding); 5009046SAli.Saidi@ARM.com assert(len == sizeof(encoding)); 5013794Sgblack@eecs.umich.edu DPRINTF(VNC, " -- supports %d\n", betoh(encoding)); 5021060SN/A 5031060SN/A switch (betoh(encoding)) { 5042935Sksewell@umich.edu case EncodingRaw: 5053794Sgblack@eecs.umich.edu supportsRawEnc = true; 5067720Sgblack@eecs.umich.edu break; 5077720Sgblack@eecs.umich.edu case EncodingDesktopSize: 5087720Sgblack@eecs.umich.edu supportsResizeEnc = true; 5093794Sgblack@eecs.umich.edu break; 5103794Sgblack@eecs.umich.edu } 5111060SN/A } 5121060SN/A 5131060SN/A if (!supportsRawEnc) 5145543Ssaidi@eecs.umich.edu fatal("VNC clients must always support raw encoding\n"); 5155543Ssaidi@eecs.umich.edu} 5165543Ssaidi@eecs.umich.edu 5175543Ssaidi@eecs.umich.eduvoid 5182336SN/AVncServer::requestFbUpdate() 5192336SN/A{ 5201060SN/A DPRINTF(VNC, "Received frame buffer update request from client\n"); 5211060SN/A 5225543Ssaidi@eecs.umich.edu FrameBufferUpdateReq fbr; 5235543Ssaidi@eecs.umich.edu read1((uint8_t*)&fbr, sizeof(FrameBufferUpdateReq)); 5245543Ssaidi@eecs.umich.edu 5255543Ssaidi@eecs.umich.edu fbr.x = betoh(fbr.x); 5265543Ssaidi@eecs.umich.edu fbr.y = betoh(fbr.y); 5275543Ssaidi@eecs.umich.edu fbr.width = betoh(fbr.width); 5281060SN/A fbr.height = betoh(fbr.height); 5295543Ssaidi@eecs.umich.edu 5305543Ssaidi@eecs.umich.edu DPRINTF(VNC, " -- x = %d y = %d w = %d h = %d\n", fbr.x, fbr.y, fbr.width, 5312935Sksewell@umich.edu fbr.height); 5321060SN/A 5331060SN/A sendFrameBufferUpdate(); 5342292SN/A} 5352731Sktlim@umich.edu 5362292SN/Avoid 5372731Sktlim@umich.eduVncServer::recvKeyboardInput() 5387784SAli.Saidi@ARM.com{ 5391060SN/A DPRINTF(VNC, "Received keyboard input from client\n"); 5401060SN/A KeyEventMessage kem; 5411060SN/A read1((uint8_t*)&kem, sizeof(KeyEventMessage)); 5422292SN/A 5432336SN/A kem.key = betoh(kem.key); 5442308SN/A DPRINTF(VNC, " -- received key code %d (%s)\n", kem.key, kem.down_flag ? 5454828Sgblack@eecs.umich.edu "down" : "up"); 5464654Sgblack@eecs.umich.edu 5474654Sgblack@eecs.umich.edu if (keyboard) 5484636Sgblack@eecs.umich.edu keyboard->keyPress(kem.key, kem.down_flag); 5494654Sgblack@eecs.umich.edu} 5504654Sgblack@eecs.umich.edu 5514636Sgblack@eecs.umich.eduvoid 5522292SN/AVncServer::recvPointerInput() 5532292SN/A{ 5542731Sktlim@umich.edu DPRINTF(VNC, "Received pointer input from client\n"); 5552292SN/A PointerEventMessage pem; 5562292SN/A 5572731Sktlim@umich.edu read1((uint8_t*)&pem, sizeof(PointerEventMessage));; 5582292SN/A 5592292SN/A pem.x = betoh(pem.x); 5602731Sktlim@umich.edu pem.y = betoh(pem.y); 5612292SN/A DPRINTF(VNC, " -- pointer at x = %d y = %d buttons = %#x\n", pem.x, pem.y, 5622292SN/A pem.button_mask); 5632731Sktlim@umich.edu 5642292SN/A if (mouse) 5652292SN/A mouse->mouseAt(pem.x, pem.y, pem.button_mask); 5662731Sktlim@umich.edu} 5672292SN/A 5682292SN/Avoid 5692731Sktlim@umich.eduVncServer::recvCutText() 5702292SN/A{ 5712731Sktlim@umich.edu DPRINTF(VNC, "Received client copy buffer message\n"); 5722731Sktlim@umich.edu 5732292SN/A ClientCutTextMessage cct; 5742292SN/A read1((uint8_t*)&cct, sizeof(ClientCutTextMessage)); 5752292SN/A 5762292SN/A char str[1025]; 5772292SN/A size_t data_len = betoh(cct.length); 5782292SN/A DPRINTF(VNC, "String length %d\n", data_len); 5792731Sktlim@umich.edu while (data_len > 0) { 5801060SN/A size_t len; 5811464SN/A size_t bytes_to_read = data_len > 1024 ? 1024 : data_len; 5821464SN/A len = read((uint8_t*)&str, bytes_to_read); 5831464SN/A str[bytes_to_read] = 0; 5841464SN/A data_len -= len; 5857720Sgblack@eecs.umich.edu assert(data_len >= 0); 5867720Sgblack@eecs.umich.edu DPRINTF(VNC, "Buffer: %s\n", str); 5871464SN/A } 5882292SN/A 5895543Ssaidi@eecs.umich.edu} 5901684SN/A 5912292SN/A 5921060SN/Avoid 5931060SN/AVncServer::sendFrameBufferUpdate() 5941060SN/A{ 5951060SN/A 5961060SN/A if (!clientRfb || dataFd <= 0 || curState != NormalPhase || !sendUpdate) { 5971060SN/A DPRINTF(VNC, "NOT sending framebuffer update\n"); 5981060SN/A return; 5991060SN/A } 6002292SN/A 6011060SN/A assert(vc); 6021060SN/A 6032292SN/A // The client will request data constantly, unless we throttle it 6041060SN/A sendUpdate = false; 6058733Sgeoffrey.blake@arm.com 6068733Sgeoffrey.blake@arm.com DPRINTF(VNC, "Sending framebuffer update\n"); 6078733Sgeoffrey.blake@arm.com 6088733Sgeoffrey.blake@arm.com FrameBufferUpdate fbu; 6098733Sgeoffrey.blake@arm.com FrameBufferRect fbr; 6108733Sgeoffrey.blake@arm.com 6118733Sgeoffrey.blake@arm.com fbu.type = ServerFrameBufferUpdate; 6128733Sgeoffrey.blake@arm.com fbu.num_rects = 1; 6138733Sgeoffrey.blake@arm.com fbr.x = 0; 6141684SN/A fbr.y = 0; 6158733Sgeoffrey.blake@arm.com fbr.width = videoWidth(); 6168733Sgeoffrey.blake@arm.com fbr.height = videoHeight(); 6178733Sgeoffrey.blake@arm.com fbr.encoding = EncodingRaw; 6188733Sgeoffrey.blake@arm.com 6198733Sgeoffrey.blake@arm.com // fix up endian 6208733Sgeoffrey.blake@arm.com fbu.num_rects = htobe(fbu.num_rects); 6211684SN/A fbr.x = htobe(fbr.x); 6228733Sgeoffrey.blake@arm.com fbr.y = htobe(fbr.y); 6238733Sgeoffrey.blake@arm.com fbr.width = htobe(fbr.width); 6248733Sgeoffrey.blake@arm.com fbr.height = htobe(fbr.height); 6258733Sgeoffrey.blake@arm.com fbr.encoding = htobe(fbr.encoding); 6269046SAli.Saidi@ARM.com 6278733Sgeoffrey.blake@arm.com // send headers to client 6288733Sgeoffrey.blake@arm.com write(&fbu); 6298733Sgeoffrey.blake@arm.com write(&fbr); 6308733Sgeoffrey.blake@arm.com 6318733Sgeoffrey.blake@arm.com assert(clientRfb); 6321060SN/A 6332702Sktlim@umich.edu uint8_t *tmp = vc->convert(clientRfb); 6343735Sstever@eecs.umich.edu write(tmp, videoWidth() * videoHeight() * sizeof(uint32_t)); 6351060SN/A delete [] tmp; 6368733Sgeoffrey.blake@arm.com 6371060SN/A} 6381060SN/A 6399920Syasuko.eckert@amd.comvoid 6409920Syasuko.eckert@amd.comVncServer::sendFrameBufferResized() 6419920Syasuko.eckert@amd.com{ 6429920Syasuko.eckert@amd.com assert(clientRfb && dataFd > 0 && curState == NormalPhase); 6439920Syasuko.eckert@amd.com DPRINTF(VNC, "Sending framebuffer resize\n"); 6449920Syasuko.eckert@amd.com 6452702Sktlim@umich.edu FrameBufferUpdate fbu; 6463735Sstever@eecs.umich.edu FrameBufferRect fbr; 6473735Sstever@eecs.umich.edu 6482690Sktlim@umich.edu fbu.type = ServerFrameBufferUpdate; 6498733Sgeoffrey.blake@arm.com fbu.num_rects = 1; 6508733Sgeoffrey.blake@arm.com fbr.x = 0; 6518733Sgeoffrey.blake@arm.com fbr.y = 0; 6528733Sgeoffrey.blake@arm.com fbr.width = videoWidth(); 6533326Sktlim@umich.edu fbr.height = videoHeight(); 6542690Sktlim@umich.edu fbr.encoding = EncodingDesktopSize; 6552690Sktlim@umich.edu 6562702Sktlim@umich.edu // fix up endian 6573735Sstever@eecs.umich.edu fbu.num_rects = htobe(fbu.num_rects); 6581060SN/A fbr.x = htobe(fbr.x); 6598733Sgeoffrey.blake@arm.com fbr.y = htobe(fbr.y); 6602308SN/A fbr.width = htobe(fbr.width); 6611060SN/A fbr.height = htobe(fbr.height); 6622702Sktlim@umich.edu fbr.encoding = htobe(fbr.encoding); 6633735Sstever@eecs.umich.edu 6643735Sstever@eecs.umich.edu // send headers to client 6652308SN/A write(&fbu); 6668733Sgeoffrey.blake@arm.com write(&fbr); 6672308SN/A 6681060SN/A // No actual data is sent in this message 6692702Sktlim@umich.edu} 6703735Sstever@eecs.umich.edu 6712308SN/Avoid 6728733Sgeoffrey.blake@arm.comVncServer::setFrameBufferParams(VideoConvert::Mode mode, int width, int height) 6731060SN/A{ 6741060SN/A DPRINTF(VNC, "Updating video params: mode: %d width: %d height: %d\n", mode, 6752190SN/A width, height); 6762292SN/A 6772190SN/A if (mode != videoMode || width != videoWidth() || height != videoHeight()) { 6782331SN/A videoMode = mode; 6792292SN/A _videoWidth = width; 6802190SN/A _videoHeight = height; 6811684SN/A 6821464SN/A if (vc) 6831464SN/A delete vc; 6841464SN/A 6851464SN/A vc = new VideoConvert(mode, VideoConvert::rgb8888, videoWidth(), 6861464SN/A videoHeight()); 6871684SN/A 6882731Sktlim@umich.edu if (dataFd > 0 && clientRfb && curState == NormalPhase) { 6891464SN/A if (supportsResizeEnc) 6902292SN/A sendFrameBufferResized(); 6912731Sktlim@umich.edu else 6921464SN/A // The frame buffer changed size and we can't update the client 6932731Sktlim@umich.edu detach(); 6942731Sktlim@umich.edu } 6952308SN/A } 6962731Sktlim@umich.edu} 6972731Sktlim@umich.edu 6982308SN/A// create the VNC server object 6991060SN/AVncServer * 7002731Sktlim@umich.eduVncServerParams::create() 7011060SN/A{ 7021060SN/A return new VncServer(this); 7032731Sktlim@umich.edu} 7041060SN/A