vncserver.cc revision 10360
12810SN/A/* 22810SN/A * Copyright (c) 2010 ARM Limited 32810SN/A * All rights reserved 42810SN/A * 52810SN/A * The license below extends only to copyright in the software and shall 62810SN/A * not be construed as granting a license to any other intellectual 72810SN/A * property including but not limited to intellectual property relating 82810SN/A * to a hardware implementation of the functionality of the software 92810SN/A * licensed hereunder. You may use the software subject to the license 102810SN/A * terms below provided that you ensure that this notice is replicated 112810SN/A * unmodified and in its entirety in all distributions of the software, 122810SN/A * modified or unmodified, in source code or in binary form. 132810SN/A * 142810SN/A * Redistribution and use in source and binary forms, with or without 152810SN/A * modification, are permitted provided that the following conditions are 162810SN/A * met: redistributions of source code must retain the above copyright 172810SN/A * notice, this list of conditions and the following disclaimer; 182810SN/A * redistributions in binary form must reproduce the above copyright 192810SN/A * notice, this list of conditions and the following disclaimer in the 202810SN/A * documentation and/or other materials provided with the distribution; 212810SN/A * neither the name of the copyright holders nor the names of its 222810SN/A * contributors may be used to endorse or promote products derived from 232810SN/A * this software without specific prior written permission. 242810SN/A * 252810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 262810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 272810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 282810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 292810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 302810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 312810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 322810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 332810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 342810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 352810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 365875Ssteve.reinhardt@amd.com * 372810SN/A * Authors: Ali Saidi 385338Sstever@gmail.com * William Wang 395338Sstever@gmail.com */ 402814SN/A 412810SN/A/** @file 422810SN/A * Implementiation of a VNC server 435034SN/A */ 445034SN/A 455034SN/A#include <sys/ioctl.h> 465034SN/A#include <sys/stat.h> 475875Ssteve.reinhardt@amd.com#include <sys/termios.h> 482810SN/A#include <sys/types.h> 492810SN/A#include <fcntl.h> 502810SN/A#include <poll.h> 512810SN/A#include <unistd.h> 522810SN/A 532810SN/A#include <cerrno> 542810SN/A#include <cstdio> 552810SN/A 565875Ssteve.reinhardt@amd.com#include "base/vnc/vncserver.hh" 572810SN/A#include "base/atomicio.hh" 582810SN/A#include "base/bitmap.hh" 592810SN/A#include "base/misc.hh" 602810SN/A#include "base/output.hh" 612810SN/A#include "base/socket.hh" 622810SN/A#include "base/trace.hh" 632810SN/A#include "debug/VNC.hh" 642810SN/A#include "sim/byteswap.hh" 652810SN/A#include "sim/core.hh" 662810SN/A 672810SN/Ausing namespace std; 682810SN/A 692810SN/A/** @file 702810SN/A * Implementiation of a VNC server 712810SN/A */ 722810SN/A 732810SN/A/** 742810SN/A * Poll event for the listen socket 752810SN/A */ 762810SN/AVncServer::ListenEvent::ListenEvent(VncServer *vs, int fd, int e) 772810SN/A : PollEvent(fd, e), vncserver(vs) 782810SN/A{ 792810SN/A} 802810SN/A 812810SN/Avoid 822810SN/AVncServer::ListenEvent::process(int revent) 832810SN/A{ 842810SN/A vncserver->accept(); 852810SN/A} 862810SN/A 872810SN/A/** 882810SN/A * Poll event for the data socket 892810SN/A */ 902810SN/AVncServer::DataEvent::DataEvent(VncServer *vs, int fd, int e) 912810SN/A : PollEvent(fd, e), vncserver(vs) 922810SN/A{ 932810SN/A} 942810SN/A 952810SN/Avoid 962810SN/AVncServer::DataEvent::process(int revent) 972810SN/A{ 982810SN/A if (revent & POLLIN) 992810SN/A vncserver->data(); 1002810SN/A else if (revent & POLLNVAL) 1012810SN/A vncserver->detach(); 1022810SN/A} 1032810SN/A 1045875Ssteve.reinhardt@amd.com/** 1055875Ssteve.reinhardt@amd.com * VncServer 1062810SN/A */ 1072810SN/AVncServer::VncServer(const Params *p) 1082810SN/A : VncInput(p), listenEvent(NULL), dataEvent(NULL), number(p->number), 1093861SN/A dataFd(-1), sendUpdate(false), 1103861SN/A supportsRawEnc(false), supportsResizeEnc(false) 1113861SN/A{ 1123861SN/A if (p->port) 1133861SN/A listen(p->port); 1143861SN/A 1153861SN/A curState = WaitForProtocolVersion; 1163861SN/A 1173861SN/A // currently we only support this one pixel format 1183861SN/A // unpacked 32bit rgb (rgb888 + 8 bits of nothing/alpha) 1193861SN/A // keep it around for telling the client and making 1203861SN/A // sure the client cooperates 1213861SN/A pixelFormat.bpp = 32; 1223861SN/A pixelFormat.depth = 24; 1233861SN/A pixelFormat.bigendian = 0; 1243861SN/A pixelFormat.truecolor = 1; 1253861SN/A pixelFormat.redmax = 0xff; 1263861SN/A pixelFormat.greenmax = 0xff; 1273861SN/A pixelFormat.bluemax = 0xff; 1283861SN/A pixelFormat.redshift = 16; 1293349SN/A pixelFormat.greenshift = 8; 1302810SN/A pixelFormat.blueshift = 0; 1312810SN/A 1325875Ssteve.reinhardt@amd.com DPRINTF(VNC, "Vnc server created at port %d\n", p->port); 1332810SN/A} 1342810SN/A 1355875Ssteve.reinhardt@amd.comVncServer::~VncServer() 1362810SN/A{ 1372810SN/A if (dataFd != -1) 1382810SN/A ::close(dataFd); 1393349SN/A 1405875Ssteve.reinhardt@amd.com if (listenEvent) 1412810SN/A delete listenEvent; 1422810SN/A 1432810SN/A if (dataEvent) 1442810SN/A delete dataEvent; 1455875Ssteve.reinhardt@amd.com} 1462810SN/A 1475875Ssteve.reinhardt@amd.com 1485875Ssteve.reinhardt@amd.com//socket creation and vnc client attach 1495875Ssteve.reinhardt@amd.comvoid 1505875Ssteve.reinhardt@amd.comVncServer::listen(int port) 1515875Ssteve.reinhardt@amd.com{ 1525875Ssteve.reinhardt@amd.com if (ListenSocket::allDisabled()) { 1535875Ssteve.reinhardt@amd.com warn_once("Sockets disabled, not accepting vnc client connections"); 1545875Ssteve.reinhardt@amd.com return; 1552810SN/A } 1564628SN/A 1575875Ssteve.reinhardt@amd.com while (!listener.listen(port, true)) { 1585875Ssteve.reinhardt@amd.com DPRINTF(VNC, 1595875Ssteve.reinhardt@amd.com "can't bind address vnc server port %d in use PID %d\n", 1602810SN/A port, getpid()); 1615875Ssteve.reinhardt@amd.com port++; 1622810SN/A } 1632810SN/A 1645875Ssteve.reinhardt@amd.com int p1, p2; 1655875Ssteve.reinhardt@amd.com p2 = name().rfind('.') - 1; 1662810SN/A p1 = name().rfind('.', p2); 1672810SN/A ccprintf(cerr, "Listening for %s connection on port %d\n", 1682810SN/A name().substr(p1 + 1, p2 - p1), port); 1695875Ssteve.reinhardt@amd.com 1705875Ssteve.reinhardt@amd.com listenEvent = new ListenEvent(this, listener.getfd(), POLLIN); 1715875Ssteve.reinhardt@amd.com pollQueue.schedule(listenEvent); 1722810SN/A} 1735875Ssteve.reinhardt@amd.com 1745875Ssteve.reinhardt@amd.com// attach a vnc client 1755875Ssteve.reinhardt@amd.comvoid 1762810SN/AVncServer::accept() 1775875Ssteve.reinhardt@amd.com{ 1785875Ssteve.reinhardt@amd.com // As a consequence of being called from the PollQueue, we might 1792810SN/A // have been called from a different thread. Migrate to "our" 1805875Ssteve.reinhardt@amd.com // thread. 1815875Ssteve.reinhardt@amd.com EventQueue::ScopedMigration migrate(eventQueue()); 1822810SN/A 1835875Ssteve.reinhardt@amd.com if (!listener.islistening()) 1845875Ssteve.reinhardt@amd.com panic("%s: cannot accept a connection if not listening!", name()); 1852810SN/A 1862810SN/A int fd = listener.accept(true); 1874628SN/A if (dataFd != -1) { 1882810SN/A char message[] = "vnc server already attached!\n"; 1892810SN/A atomic_write(fd, message, sizeof(message)); 1905875Ssteve.reinhardt@amd.com ::close(fd); 1915875Ssteve.reinhardt@amd.com return; 1925875Ssteve.reinhardt@amd.com } 1935875Ssteve.reinhardt@amd.com 1945875Ssteve.reinhardt@amd.com dataFd = fd; 1952810SN/A 1962810SN/A // Send our version number to the client 1972810SN/A write((uint8_t*)vncVersion(), strlen(vncVersion())); 1982810SN/A 1992810SN/A // read the client response 2005875Ssteve.reinhardt@amd.com dataEvent = new DataEvent(this, dataFd, POLLIN); 2015875Ssteve.reinhardt@amd.com pollQueue.schedule(dataEvent); 2025875Ssteve.reinhardt@amd.com 2035875Ssteve.reinhardt@amd.com inform("VNC client attached\n"); 2045875Ssteve.reinhardt@amd.com} 2052810SN/A 2062810SN/A// data called by data event 2072810SN/Avoid 2084628SN/AVncServer::data() 2092810SN/A{ 2102810SN/A // We have new data, see if we can handle it 2112810SN/A size_t len; 2122810SN/A DPRINTF(VNC, "Vnc client message recieved\n"); 2132810SN/A 2142810SN/A switch (curState) { 2152810SN/A case WaitForProtocolVersion: 2165875Ssteve.reinhardt@amd.com checkProtocolVersion(); 2175875Ssteve.reinhardt@amd.com break; 2185875Ssteve.reinhardt@amd.com case WaitForSecurityResponse: 2195875Ssteve.reinhardt@amd.com checkSecurity(); 2205875Ssteve.reinhardt@amd.com break; 2212810SN/A case WaitForClientInit: 2225875Ssteve.reinhardt@amd.com // Don't care about shared, just need to read it out of the socket 2235875Ssteve.reinhardt@amd.com uint8_t shared; 2245875Ssteve.reinhardt@amd.com len = read(&shared); 2255875Ssteve.reinhardt@amd.com assert(len == 1); 2265875Ssteve.reinhardt@amd.com 2275875Ssteve.reinhardt@amd.com // Send our idea of the frame buffer 2285875Ssteve.reinhardt@amd.com sendServerInit(); 2295875Ssteve.reinhardt@amd.com 2305875Ssteve.reinhardt@amd.com break; 2315875Ssteve.reinhardt@amd.com case NormalPhase: 2325875Ssteve.reinhardt@amd.com uint8_t message_type; 2335875Ssteve.reinhardt@amd.com len = read(&message_type); 2345875Ssteve.reinhardt@amd.com if (!len) { 2355875Ssteve.reinhardt@amd.com detach(); 2365875Ssteve.reinhardt@amd.com return; 2375875Ssteve.reinhardt@amd.com } 2385875Ssteve.reinhardt@amd.com assert(len == 1); 2395875Ssteve.reinhardt@amd.com 2405875Ssteve.reinhardt@amd.com switch (message_type) { 2415875Ssteve.reinhardt@amd.com case ClientSetPixelFormat: 2425875Ssteve.reinhardt@amd.com setPixelFormat(); 2435875Ssteve.reinhardt@amd.com break; 2445875Ssteve.reinhardt@amd.com case ClientSetEncodings: 2455875Ssteve.reinhardt@amd.com setEncodings(); 2465875Ssteve.reinhardt@amd.com break; 2475875Ssteve.reinhardt@amd.com case ClientFrameBufferUpdate: 2485875Ssteve.reinhardt@amd.com requestFbUpdate(); 2495875Ssteve.reinhardt@amd.com break; 2502825SN/A case ClientKeyEvent: 2515714Shsul@eecs.umich.edu recvKeyboardInput(); 2525714Shsul@eecs.umich.edu break; 2532814SN/A case ClientPointerEvent: 2545875Ssteve.reinhardt@amd.com recvPointerInput(); 2552810SN/A break; 2565875Ssteve.reinhardt@amd.com case ClientCutText: 2575875Ssteve.reinhardt@amd.com recvCutText(); 2582810SN/A break; 2595875Ssteve.reinhardt@amd.com default: 2605875Ssteve.reinhardt@amd.com panic("Unimplemented message type recv from client: %d\n", 2615875Ssteve.reinhardt@amd.com message_type); 2625875Ssteve.reinhardt@amd.com break; 2635875Ssteve.reinhardt@amd.com } 2642810SN/A break; 2652810SN/A default: 2662810SN/A panic("Unknown vnc server state\n"); 2672810SN/A } 2682810SN/A} 2692810SN/A 2705875Ssteve.reinhardt@amd.com 2715875Ssteve.reinhardt@amd.com// read from socket 2722810SN/Asize_t 2732810SN/AVncServer::read(uint8_t *buf, size_t len) 2743349SN/A{ 2752810SN/A if (dataFd < 0) 2762810SN/A panic("vnc not properly attached.\n"); 2775875Ssteve.reinhardt@amd.com 2783349SN/A size_t ret; 2795875Ssteve.reinhardt@amd.com do { 2802814SN/A ret = ::read(dataFd, buf, len); 2812810SN/A } while (ret == -1 && errno == EINTR); 2822810SN/A 2832810SN/A 2842810SN/A if (ret <= 0){ 2852810SN/A DPRINTF(VNC, "Read failed.\n"); 2862810SN/A detach(); 2875875Ssteve.reinhardt@amd.com return 0; 2885875Ssteve.reinhardt@amd.com } 2895875Ssteve.reinhardt@amd.com 2905875Ssteve.reinhardt@amd.com return ret; 2915875Ssteve.reinhardt@amd.com} 292 293size_t 294VncServer::read1(uint8_t *buf, size_t len) 295{ 296 size_t read_len M5_VAR_USED; 297 read_len = read(buf + 1, len - 1); 298 assert(read_len == len - 1); 299 return read_len; 300} 301 302 303template<typename T> 304size_t 305VncServer::read(T* val) 306{ 307 return read((uint8_t*)val, sizeof(T)); 308} 309 310// write to socket 311size_t 312VncServer::write(const uint8_t *buf, size_t len) 313{ 314 if (dataFd < 0) 315 panic("Vnc client not properly attached.\n"); 316 317 ssize_t ret; 318 ret = atomic_write(dataFd, buf, len); 319 320 if (ret < len) 321 detach(); 322 323 return ret; 324} 325 326template<typename T> 327size_t 328VncServer::write(T* val) 329{ 330 return write((uint8_t*)val, sizeof(T)); 331} 332 333size_t 334VncServer::write(const char* str) 335{ 336 return write((uint8_t*)str, strlen(str)); 337} 338 339// detach a vnc client 340void 341VncServer::detach() 342{ 343 if (dataFd != -1) { 344 ::close(dataFd); 345 dataFd = -1; 346 } 347 348 if (!dataEvent || !dataEvent->queued()) 349 return; 350 351 pollQueue.remove(dataEvent); 352 delete dataEvent; 353 dataEvent = NULL; 354 curState = WaitForProtocolVersion; 355 356 inform("VNC client detached\n"); 357 DPRINTF(VNC, "detach vnc client %d\n", number); 358} 359 360void 361VncServer::sendError(const char* error_msg) 362{ 363 uint32_t len = strlen(error_msg); 364 write(&len); 365 write(error_msg); 366} 367 368void 369VncServer::checkProtocolVersion() 370{ 371 assert(curState == WaitForProtocolVersion); 372 373 size_t len M5_VAR_USED; 374 char version_string[13]; 375 376 // Null terminate the message so it's easier to work with 377 version_string[12] = 0; 378 379 len = read((uint8_t*)version_string, 12); 380 assert(len == 12); 381 382 uint32_t major, minor; 383 384 // Figure out the major/minor numbers 385 if (sscanf(version_string, "RFB %03d.%03d\n", &major, &minor) != 2) { 386 warn(" Malformed protocol version %s\n", version_string); 387 sendError("Malformed protocol version\n"); 388 detach(); 389 } 390 391 DPRINTF(VNC, "Client request protocol version %d.%d\n", major, minor); 392 393 // If it's not 3.X we don't support it 394 if (major != 3 || minor < 2) { 395 warn("Unsupported VNC client version... disconnecting\n"); 396 uint8_t err = AuthInvalid; 397 write(&err); 398 detach(); 399 } 400 // Auth is different based on version number 401 if (minor < 7) { 402 uint32_t sec_type = htobe((uint32_t)AuthNone); 403 write(&sec_type); 404 } else { 405 uint8_t sec_cnt = 1; 406 uint8_t sec_type = htobe((uint8_t)AuthNone); 407 write(&sec_cnt); 408 write(&sec_type); 409 } 410 411 // Wait for client to respond 412 curState = WaitForSecurityResponse; 413} 414 415void 416VncServer::checkSecurity() 417{ 418 assert(curState == WaitForSecurityResponse); 419 420 uint8_t security_type; 421 size_t len M5_VAR_USED = read(&security_type); 422 423 assert(len == 1); 424 425 if (security_type != AuthNone) { 426 warn("Unknown VNC security type\n"); 427 sendError("Unknown security type\n"); 428 } 429 430 DPRINTF(VNC, "Sending security auth OK\n"); 431 432 uint32_t success = htobe(VncOK); 433 write(&success); 434 curState = WaitForClientInit; 435} 436 437void 438VncServer::sendServerInit() 439{ 440 ServerInitMsg msg; 441 442 DPRINTF(VNC, "Sending server init message to client\n"); 443 444 msg.fbWidth = htobe(videoWidth()); 445 msg.fbHeight = htobe(videoHeight()); 446 447 msg.px.bpp = htobe(pixelFormat.bpp); 448 msg.px.depth = htobe(pixelFormat.depth); 449 msg.px.bigendian = htobe(pixelFormat.bigendian); 450 msg.px.truecolor = htobe(pixelFormat.truecolor); 451 msg.px.redmax = htobe(pixelFormat.redmax); 452 msg.px.greenmax = htobe(pixelFormat.greenmax); 453 msg.px.bluemax = htobe(pixelFormat.bluemax); 454 msg.px.redshift = htobe(pixelFormat.redshift); 455 msg.px.greenshift = htobe(pixelFormat.greenshift); 456 msg.px.blueshift = htobe(pixelFormat.blueshift); 457 memset(msg.px.padding, 0, 3); 458 msg.namelen = 2; 459 msg.namelen = htobe(msg.namelen); 460 memcpy(msg.name, "M5", 2); 461 462 write(&msg); 463 curState = NormalPhase; 464} 465 466void 467VncServer::setPixelFormat() 468{ 469 DPRINTF(VNC, "Received pixel format from client message\n"); 470 471 PixelFormatMessage pfm; 472 read1((uint8_t*)&pfm, sizeof(PixelFormatMessage)); 473 474 DPRINTF(VNC, " -- bpp = %d; depth = %d; be = %d\n", pfm.px.bpp, 475 pfm.px.depth, pfm.px.bigendian); 476 DPRINTF(VNC, " -- true color = %d red,green,blue max = %d,%d,%d\n", 477 pfm.px.truecolor, betoh(pfm.px.redmax), betoh(pfm.px.greenmax), 478 betoh(pfm.px.bluemax)); 479 DPRINTF(VNC, " -- red,green,blue shift = %d,%d,%d\n", pfm.px.redshift, 480 pfm.px.greenshift, pfm.px.blueshift); 481 482 if (betoh(pfm.px.bpp) != pixelFormat.bpp || 483 betoh(pfm.px.depth) != pixelFormat.depth || 484 betoh(pfm.px.bigendian) != pixelFormat.bigendian || 485 betoh(pfm.px.truecolor) != pixelFormat.truecolor || 486 betoh(pfm.px.redmax) != pixelFormat.redmax || 487 betoh(pfm.px.greenmax) != pixelFormat.greenmax || 488 betoh(pfm.px.bluemax) != pixelFormat.bluemax || 489 betoh(pfm.px.redshift) != pixelFormat.redshift || 490 betoh(pfm.px.greenshift) != pixelFormat.greenshift || 491 betoh(pfm.px.blueshift) != pixelFormat.blueshift) 492 fatal("VNC client doesn't support true color raw encoding\n"); 493} 494 495void 496VncServer::setEncodings() 497{ 498 DPRINTF(VNC, "Received supported encodings from client\n"); 499 500 PixelEncodingsMessage pem; 501 read1((uint8_t*)&pem, sizeof(PixelEncodingsMessage)); 502 503 pem.num_encodings = betoh(pem.num_encodings); 504 505 DPRINTF(VNC, " -- %d encoding present\n", pem.num_encodings); 506 supportsRawEnc = supportsResizeEnc = false; 507 508 for (int x = 0; x < pem.num_encodings; x++) { 509 int32_t encoding; 510 size_t len M5_VAR_USED; 511 len = read(&encoding); 512 assert(len == sizeof(encoding)); 513 DPRINTF(VNC, " -- supports %d\n", betoh(encoding)); 514 515 switch (betoh(encoding)) { 516 case EncodingRaw: 517 supportsRawEnc = true; 518 break; 519 case EncodingDesktopSize: 520 supportsResizeEnc = true; 521 break; 522 } 523 } 524 525 if (!supportsRawEnc) 526 fatal("VNC clients must always support raw encoding\n"); 527} 528 529void 530VncServer::requestFbUpdate() 531{ 532 DPRINTF(VNC, "Received frame buffer update request from client\n"); 533 534 FrameBufferUpdateReq fbr; 535 read1((uint8_t*)&fbr, sizeof(FrameBufferUpdateReq)); 536 537 fbr.x = betoh(fbr.x); 538 fbr.y = betoh(fbr.y); 539 fbr.width = betoh(fbr.width); 540 fbr.height = betoh(fbr.height); 541 542 DPRINTF(VNC, " -- x = %d y = %d w = %d h = %d\n", fbr.x, fbr.y, fbr.width, 543 fbr.height); 544 545 sendFrameBufferUpdate(); 546} 547 548void 549VncServer::recvKeyboardInput() 550{ 551 DPRINTF(VNC, "Received keyboard input from client\n"); 552 KeyEventMessage kem; 553 read1((uint8_t*)&kem, sizeof(KeyEventMessage)); 554 555 kem.key = betoh(kem.key); 556 DPRINTF(VNC, " -- received key code %d (%s)\n", kem.key, kem.down_flag ? 557 "down" : "up"); 558 559 if (keyboard) 560 keyboard->keyPress(kem.key, kem.down_flag); 561} 562 563void 564VncServer::recvPointerInput() 565{ 566 DPRINTF(VNC, "Received pointer input from client\n"); 567 PointerEventMessage pem; 568 569 read1((uint8_t*)&pem, sizeof(PointerEventMessage));; 570 571 pem.x = betoh(pem.x); 572 pem.y = betoh(pem.y); 573 DPRINTF(VNC, " -- pointer at x = %d y = %d buttons = %#x\n", pem.x, pem.y, 574 pem.button_mask); 575 576 if (mouse) 577 mouse->mouseAt(pem.x, pem.y, pem.button_mask); 578} 579 580void 581VncServer::recvCutText() 582{ 583 DPRINTF(VNC, "Received client copy buffer message\n"); 584 585 ClientCutTextMessage cct; 586 read1((uint8_t*)&cct, sizeof(ClientCutTextMessage)); 587 588 char str[1025]; 589 size_t data_len = betoh(cct.length); 590 DPRINTF(VNC, "String length %d\n", data_len); 591 while (data_len > 0) { 592 size_t len; 593 size_t bytes_to_read = data_len > 1024 ? 1024 : data_len; 594 len = read((uint8_t*)&str, bytes_to_read); 595 str[bytes_to_read] = 0; 596 data_len -= len; 597 assert(data_len >= 0); 598 DPRINTF(VNC, "Buffer: %s\n", str); 599 } 600 601} 602 603 604void 605VncServer::sendFrameBufferUpdate() 606{ 607 608 if (!fbPtr || dataFd <= 0 || curState != NormalPhase || !sendUpdate) { 609 DPRINTF(VNC, "NOT sending framebuffer update\n"); 610 return; 611 } 612 613 assert(vc); 614 615 // The client will request data constantly, unless we throttle it 616 sendUpdate = false; 617 618 DPRINTF(VNC, "Sending framebuffer update\n"); 619 620 FrameBufferUpdate fbu; 621 FrameBufferRect fbr; 622 623 fbu.type = ServerFrameBufferUpdate; 624 fbu.num_rects = 1; 625 fbr.x = 0; 626 fbr.y = 0; 627 fbr.width = videoWidth(); 628 fbr.height = videoHeight(); 629 fbr.encoding = EncodingRaw; 630 631 // fix up endian 632 fbu.num_rects = htobe(fbu.num_rects); 633 fbr.x = htobe(fbr.x); 634 fbr.y = htobe(fbr.y); 635 fbr.width = htobe(fbr.width); 636 fbr.height = htobe(fbr.height); 637 fbr.encoding = htobe(fbr.encoding); 638 639 // send headers to client 640 write(&fbu); 641 write(&fbr); 642 643 assert(fbPtr); 644 645 uint8_t *tmp = vc->convert(fbPtr); 646 write(tmp, videoWidth() * videoHeight() * sizeof(uint32_t)); 647 delete [] tmp; 648 649} 650 651void 652VncServer::sendFrameBufferResized() 653{ 654 assert(fbPtr && dataFd > 0 && curState == NormalPhase); 655 DPRINTF(VNC, "Sending framebuffer resize\n"); 656 657 FrameBufferUpdate fbu; 658 FrameBufferRect fbr; 659 660 fbu.type = ServerFrameBufferUpdate; 661 fbu.num_rects = 1; 662 fbr.x = 0; 663 fbr.y = 0; 664 fbr.width = videoWidth(); 665 fbr.height = videoHeight(); 666 fbr.encoding = EncodingDesktopSize; 667 668 // fix up endian 669 fbu.num_rects = htobe(fbu.num_rects); 670 fbr.x = htobe(fbr.x); 671 fbr.y = htobe(fbr.y); 672 fbr.width = htobe(fbr.width); 673 fbr.height = htobe(fbr.height); 674 fbr.encoding = htobe(fbr.encoding); 675 676 // send headers to client 677 write(&fbu); 678 write(&fbr); 679 680 // No actual data is sent in this message 681} 682 683void 684VncServer::setFrameBufferParams(VideoConvert::Mode mode, uint16_t width, 685 uint16_t height) 686{ 687 VncInput::setFrameBufferParams(mode, width, height); 688 689 if (mode != videoMode || width != videoWidth() || height != videoHeight()) { 690 if (dataFd > 0 && fbPtr && curState == NormalPhase) { 691 if (supportsResizeEnc) 692 sendFrameBufferResized(); 693 else 694 // The frame buffer changed size and we can't update the client 695 detach(); 696 } 697 } 698} 699 700// create the VNC server object 701VncServer * 702VncServerParams::create() 703{ 704 return new VncServer(this); 705} 706 707