diff options
Diffstat (limited to 'libs/surfaceflinger/RFBServer.cpp')
-rw-r--r-- | libs/surfaceflinger/RFBServer.cpp | 722 |
1 files changed, 0 insertions, 722 deletions
diff --git a/libs/surfaceflinger/RFBServer.cpp b/libs/surfaceflinger/RFBServer.cpp deleted file mode 100644 index c2c1989..0000000 --- a/libs/surfaceflinger/RFBServer.cpp +++ /dev/null @@ -1,722 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "RFBServer" - -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <errno.h> -#include <fcntl.h> - -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/ioctl.h> - -#include <netinet/in.h> - -#include <cutils/sockets.h> - -#include <utils/Log.h> -#include <ui/Rect.h> - -#ifdef HAVE_ANDROID_OS -#include <linux/input.h> -#endif - -#include "RFBServer.h" -#include "SurfaceFlinger.h" - -/* BUG=773511: this is a temporary hack required while developing the new - set of "clean kernel headers" for the Bionic C library. */ -#ifndef KEY_STAR -#define KEY_STAR 227 -#endif -#ifndef KEY_SHARP -#define KEY_SHARP 228 -#endif -#ifndef KEY_SOFT1 -#define KEY_SOFT1 229 -#endif -#ifndef KEY_SOFT2 -#define KEY_SOFT2 230 -#endif -#ifndef KEY_CENTER -#define KEY_CENTER 232 -#endif - -// ---------------------------------------------------------------------------- - -#define DEBUG_MSG 0 - -// ---------------------------------------------------------------------------- - -namespace android { - -const int VNC_PORT = 5900; - -RFBServer::RFBServer(uint32_t w, uint32_t h, android::PixelFormat format) - : Thread(false), mFD(-1), mStatus(NO_INIT), mIoVec(0) -{ - mFrameBuffer.version = sizeof(mFrameBuffer); - mFrameBuffer.width = w; - mFrameBuffer.height = h; - mFrameBuffer.stride = w; - mFrameBuffer.format = format; - mFrameBuffer.data = 0; -} - -RFBServer::~RFBServer() -{ - if (mRobinThread != 0) { - // ask the thread to exit first - mRobinThread->exitAndWait(); - } - - free(mFrameBuffer.data); - - delete [] mIoVec; -} - -void RFBServer::onFirstRef() -{ - run("Batman"); -} - -status_t RFBServer::readyToRun() -{ - LOGI("RFB server ready to run"); - return NO_ERROR; -} - -bool RFBServer::threadLoop() -{ - struct sockaddr addr; - socklen_t alen; - int serverfd = -1; - int port = VNC_PORT; - - do { - retry: - if (serverfd < 0) { - serverfd = socket_loopback_server(port, SOCK_STREAM); - if (serverfd < 0) { - if ((errno == EADDRINUSE) && (port < (VNC_PORT+10))) { - LOGW("port %d already in use, trying %d", port, port+1); - port++; - goto retry; - } - LOGE("couldn't create socket, port=%d, error %d (%s)", - port, errno, strerror(errno)); - sleep(1); - break; - } - fcntl(serverfd, F_SETFD, FD_CLOEXEC); - } - - alen = sizeof(addr); - mFD = accept(serverfd, &addr, &alen); - - if (mFD < 0) { - LOGE("couldn't accept(), error %d (%s)", errno, strerror(errno)); - // we could have run out of file descriptors, wait a bit and - // try again. - sleep(1); - goto retry; - } - fcntl(mFD, F_SETFD, FD_CLOEXEC); - - // send protocol version and Authentication method - mStatus = NO_ERROR; - handshake(3, 3, Authentication::None); - - if (alive()) { - // create the thread we use to send data to the client - mRobinThread = new ServerThread(this); - } - - while( alive() ) { - // client message must be destroyed at each iteration - // (most of the time this is a no-op) - ClientMessage msg; - waitForClientMessage(msg); - if (alive()) { - handleClientMessage(msg); - } - } - - } while( alive() ); - - // free-up some resources - if (mRobinThread != 0) { - mRobinThread->exitAndWait(); - mRobinThread.clear(); - } - - free(mFrameBuffer.data); - mFrameBuffer.data = 0; - - close(mFD); - close(serverfd); - mFD = -1; - - // we'll try again - return true; -} - -// ---------------------------------------------------------------------------- - -RFBServer::ServerThread::ServerThread(const sp<RFBServer>& receiver) - : Thread(false), mReceiver(receiver) -{ - LOGD("RFB Server Thread created"); -} - -RFBServer::ServerThread::~ServerThread() -{ - LOGD("RFB Server Thread destroyed"); -} - -void RFBServer::ServerThread::onFirstRef() -{ - mUpdateBarrier.close(); - run("Robin"); -} - -status_t RFBServer::ServerThread::readyToRun() -{ - return NO_ERROR; -} - -void RFBServer::ServerThread::wake() -{ - mUpdateBarrier.open(); -} - -void RFBServer::ServerThread::exitAndWait() -{ - requestExit(); - mUpdateBarrier.open(); - requestExitAndWait(); -} - -bool RFBServer::ServerThread::threadLoop() -{ - sp<RFBServer> receiver(mReceiver.promote()); - if (receiver == 0) - return false; - - // wait for something to do - mUpdateBarrier.wait(); - - // we're asked to quit, abort everything - if (exitPending()) - return false; - - mUpdateBarrier.close(); - - // process updates - receiver->sendFrameBufferUpdates(); - return !exitPending(); -} - -// ---------------------------------------------------------------------------- - -void RFBServer::handshake(uint8_t major, uint8_t minor, uint32_t auth) -{ - ProtocolVersion protocolVersion(major, minor); - if( !write(protocolVersion) ) - return; - - if ( !read(protocolVersion) ) - return; - - int maj, min; - if ( protocolVersion.decode(maj, min) != NO_ERROR ) { - mStatus = -1; - return; - } - -#if DEBUG_MSG - LOGD("client protocol string: <%s>", (char*)protocolVersion.payload()); - LOGD("client wants protocol version %d.%d\n", maj, min); -#endif - - Authentication authentication(auth); - if( !write(authentication) ) - return; - - ClientInitialization clientInit; - if ( !read(clientInit) ) - return; - -#if DEBUG_MSG - LOGD("client initialization: sharedFlags = %d\n", clientInit.sharedFlags()); -#endif - - ServerInitialization serverInit("Android RFB"); - ServerInitialization::Payload& message(serverInit.message()); - message.framebufferWidth = htons(mFrameBuffer.width); - message.framebufferHeight = htons(mFrameBuffer.height); - message.serverPixelFormat.bitsPerPixel = 16; - message.serverPixelFormat.depth = 16; - message.serverPixelFormat.bigEndianFlag = 0; - message.serverPixelFormat.trueColorFlag = 1; - message.serverPixelFormat.redMax = htons((1<<5)-1); - message.serverPixelFormat.greenMax = htons((1<<6)-1); - message.serverPixelFormat.blueMax = htons((1<<5)-1); - message.serverPixelFormat.redShift = 11; - message.serverPixelFormat.greenShift = 5; - message.serverPixelFormat.blueShift = 0; - - mIoVec = new iovec[mFrameBuffer.height]; - - write(serverInit); -} - -void RFBServer::handleClientMessage(const ClientMessage& msg) -{ - switch(msg.type()) { - case SET_PIXEL_FORMAT: - handleSetPixelFormat(msg.messages().setPixelFormat); - break; - case SET_ENCODINGS: - handleSetEncodings(msg.messages().setEncodings); - break; - case FRAME_BUFFER_UPDATE_REQ: - handleFrameBufferUpdateReq(msg.messages().frameBufferUpdateRequest); - break; - case KEY_EVENT: - handleKeyEvent(msg.messages().keyEvent); - break; - } -} - -void RFBServer::handleSetPixelFormat(const SetPixelFormat& msg) -{ - if (!validatePixelFormat(msg.pixelFormat)) { - LOGE("The builtin VNC server only supports the RGB 565 pixel format"); - LOGD("requested pixel format:"); - LOGD("bitsPerPixel: %d", msg.pixelFormat.bitsPerPixel); - LOGD("depth: %d", msg.pixelFormat.depth); - LOGD("bigEndianFlag: %d", msg.pixelFormat.bigEndianFlag); - LOGD("trueColorFlag: %d", msg.pixelFormat.trueColorFlag); - LOGD("redmax: %d", ntohs(msg.pixelFormat.redMax)); - LOGD("bluemax: %d", ntohs(msg.pixelFormat.greenMax)); - LOGD("greenmax: %d", ntohs(msg.pixelFormat.blueMax)); - LOGD("redshift: %d", msg.pixelFormat.redShift); - LOGD("greenshift: %d", msg.pixelFormat.greenShift); - LOGD("blueshift: %d", msg.pixelFormat.blueShift); - mStatus = -1; - } -} - -bool RFBServer::validatePixelFormat(const PixelFormat& pf) -{ - if ((pf.bitsPerPixel != 16) || (pf.depth != 16)) - return false; - - if (pf.bigEndianFlag || !pf.trueColorFlag) - return false; - - if (ntohs(pf.redMax)!=0x1F || - ntohs(pf.greenMax)!=0x3F || - ntohs(pf.blueMax)!=0x1F) { - return false; - } - - if (pf.redShift!=11 || pf.greenShift!=5 || pf.blueShift!=0) - return false; - - return true; -} - -void RFBServer::handleSetEncodings(const SetEncodings& msg) -{ - /* From the RFB specification: - Sets the encoding types in which pixel data can be sent by the server. - The order of the encoding types given in this message is a hint by the - client as to its preference (the first encoding specified being most - preferred). The server may or may not choose to make use of this hint. - Pixel data may always be sent in raw encoding even if not specified - explicitly here. - */ - - LOGW("SetEncodings received. Only RAW is supported."); -} - -void RFBServer::handleFrameBufferUpdateReq(const FrameBufferUpdateRequest& msg) -{ -#if DEBUG_MSG - LOGD("handle FrameBufferUpdateRequest"); -#endif - - Rect r; - r.left = ntohs(msg.x); - r.top = ntohs(msg.y); - r.right = r.left + ntohs(msg.width); - r.bottom = r.top + ntohs(msg.height); - - Mutex::Autolock _l(mRegionLock); - mClientRegionRequest.set(r); - if (!msg.incremental) - mDirtyRegion.orSelf(r); - - mRobinThread->wake(); -} - -void RFBServer::handleKeyEvent(const KeyEvent& msg) -{ -#ifdef HAVE_ANDROID_OS - - int scancode = 0; - int code = ntohl(msg.key); - - if (code>='0' && code<='9') { - scancode = (code & 0xF) - 1; - if (scancode<0) scancode += 10; - scancode += KEY_1; - } else if (code>=0xFF50 && code<=0xFF58) { - static const uint16_t map[] = - { KEY_HOME, KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN, - KEY_SOFT1, KEY_SOFT2, KEY_END, 0 }; - scancode = map[code & 0xF]; - } else if (code>=0xFFE1 && code<=0xFFEE) { - static const uint16_t map[] = - { KEY_LEFTSHIFT, KEY_LEFTSHIFT, - KEY_COMPOSE, KEY_COMPOSE, - KEY_LEFTSHIFT, KEY_LEFTSHIFT, - 0,0, - KEY_LEFTALT, KEY_RIGHTALT, - 0, 0, 0, 0 }; - scancode = map[code & 0xF]; - } else if ((code>='A' && code<='Z') || (code>='a' && code<='z')) { - static const uint16_t map[] = { - KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, - KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, - KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, - KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, - KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z }; - scancode = map[(code & 0x5F) - 'A']; - } else { - switch (code) { - case 0x0003: scancode = KEY_CENTER; break; - case 0x0020: scancode = KEY_SPACE; break; - case 0x0023: scancode = KEY_SHARP; break; - case 0x0033: scancode = KEY_SHARP; break; - case 0x002C: scancode = KEY_COMMA; break; - case 0x003C: scancode = KEY_COMMA; break; - case 0x002E: scancode = KEY_DOT; break; - case 0x003E: scancode = KEY_DOT; break; - case 0x002F: scancode = KEY_SLASH; break; - case 0x003F: scancode = KEY_SLASH; break; - case 0x0032: scancode = KEY_EMAIL; break; - case 0x0040: scancode = KEY_EMAIL; break; - case 0xFF08: scancode = KEY_BACKSPACE; break; - case 0xFF1B: scancode = KEY_BACK; break; - case 0xFF09: scancode = KEY_TAB; break; - case 0xFF0D: scancode = KEY_ENTER; break; - case 0x002A: scancode = KEY_STAR; break; - case 0xFFBE: scancode = KEY_SEND; break; // F1 - case 0xFFBF: scancode = KEY_END; break; // F2 - case 0xFFC0: scancode = KEY_HOME; break; // F3 - case 0xFFC5: scancode = KEY_POWER; break; // F8 - } - } - -#if DEBUG_MSG - LOGD("handle KeyEvent 0x%08x, %d, scancode=%d\n", code, msg.downFlag, scancode); -#endif - - if (scancode) { - mEventInjector.injectKey(uint16_t(scancode), - msg.downFlag ? EventInjector::DOWN : EventInjector::UP); - } -#endif -} - -void RFBServer::waitForClientMessage(ClientMessage& msg) -{ - if ( !read(msg.payload(), 1) ) - return; - - switch(msg.type()) { - - case SET_PIXEL_FORMAT: - read(msg.payload(1), sizeof(SetPixelFormat)-1); - break; - - case FIX_COLOUR_MAP_ENTRIES: - mStatus = UNKNOWN_ERROR; - return; - - case SET_ENCODINGS: - { - if ( !read(msg.payload(1), sizeof(SetEncodings)-1) ) - return; - - size_t size = ntohs( msg.messages().setEncodings.numberOfEncodings ) * 4; - if (msg.resize(sizeof(SetEncodings) + size) != NO_ERROR) { - mStatus = NO_MEMORY; - return; - } - - if ( !read(msg.payload(sizeof(SetEncodings)), size) ) - return; - - break; - } - - case FRAME_BUFFER_UPDATE_REQ: - read(msg.payload(1), sizeof(FrameBufferUpdateRequest)-1); - break; - - case KEY_EVENT: - read(msg.payload(1), sizeof(KeyEvent)-1); - break; - - case POINTER_EVENT: - read(msg.payload(1), sizeof(PointerEvent)-1); - break; - - case CLIENT_CUT_TEXT: - { - if ( !read(msg.payload(1), sizeof(ClientCutText)-1) ) - return; - - size_t size = ntohl( msg.messages().clientCutText.length ); - if (msg.resize(sizeof(ClientCutText) + size) != NO_ERROR) { - mStatus = NO_MEMORY; - return; - } - - if ( !read(msg.payload(sizeof(SetEncodings)), size) ) - return; - - break; - } - - default: - LOGE("Unknown Message %d", msg.type()); - mStatus = UNKNOWN_ERROR; - return; - } -} - -// ---------------------------------------------------------------------------- - -bool RFBServer::write(const Message& msg) -{ - write(msg.payload(), msg.size()); - return alive(); -} - -bool RFBServer::read(Message& msg) -{ - read(msg.payload(), msg.size()); - return alive(); -} - -bool RFBServer::write(const void* buffer, int size) -{ - int wr = ::write(mFD, buffer, size); - if (wr != size) { - //LOGE("write(%d) error %d (%s)", size, wr, strerror(errno)); - mStatus = (wr == -1) ? errno : -1; - } - return alive(); -} - -bool RFBServer::read(void* buffer, int size) -{ - int rd = ::read(mFD, buffer, size); - if (rd != size) { - //LOGE("read(%d) error %d (%s)", size, rd, strerror(errno)); - mStatus = (rd == -1) ? errno : -1; - } - return alive(); -} - -bool RFBServer::alive() const -{ - return mStatus == 0; -} - -bool RFBServer::isConnected() const -{ - return alive(); -} - -// ---------------------------------------------------------------------------- - -void RFBServer::frameBufferUpdated(const GGLSurface& front, const Region& reg) -{ - Mutex::Autolock _l(mRegionLock); - - // update dirty region - mDirtyRegion.orSelf(reg); - - // remember the front-buffer - mFrontBuffer = front; - - // The client has not requested anything, don't do anything more - if (mClientRegionRequest.isEmpty()) - return; - - // wake the sending thread up - mRobinThread->wake(); -} - -void RFBServer::sendFrameBufferUpdates() -{ - Vector<Rect> rects; - size_t countRects; - GGLSurface fb; - - { // Scope for the lock - Mutex::Autolock _l(mRegionLock); - if (mFrontBuffer.data == 0) - return; - - const Region reg( mDirtyRegion.intersect(mClientRegionRequest) ); - if (reg.isEmpty()) - return; - - mDirtyRegion.subtractSelf(reg); - countRects = reg.rects(rects); - - // copy the frame-buffer so we can stay responsive - size_t bytesPerPix = bytesPerPixel(mFrameBuffer.format); - size_t bpr = mFrameBuffer.stride * bytesPerPix; - if (mFrameBuffer.data == 0) { - mFrameBuffer.data = (GGLubyte*)malloc(bpr * mFrameBuffer.height); - if (mFrameBuffer.data == 0) - return; - } - - memcpy(mFrameBuffer.data, mFrontBuffer.data, bpr*mFrameBuffer.height); - fb = mFrameBuffer; - } - - FrameBufferUpdate msgHeader; - msgHeader.type = 0; - msgHeader.numberOfRectangles = htons(countRects); - write(&msgHeader, sizeof(msgHeader)); - - Rectangle rectangle; - for (size_t i=0 ; i<countRects ; i++) { - const Rect& r = rects[i]; - rectangle.x = htons( r.left ); - rectangle.y = htons( r.top ); - rectangle.w = htons( r.width() ); - rectangle.h = htons( r.height() ); - rectangle.encoding = htons( SetEncodings::Raw ); - write(&rectangle, sizeof(rectangle)); - size_t h = r.height(); - size_t w = r.width(); - size_t bytesPerPix = bytesPerPixel(fb.format); - size_t bpr = fb.stride * bytesPerPix; - size_t bytes = w * bytesPerPix; - size_t offset = (r.top * bpr) + (r.left * bytesPerPix); - uint8_t* src = static_cast<uint8_t*>(fb.data) + offset; - iovec* iov = mIoVec; - while (h--) { - iov->iov_base = src; - iov->iov_len = bytes; - src += bpr; - iov++; - } - size_t iovcnt = iov - mIoVec; - int wr = ::writev(mFD, mIoVec, iovcnt); - if (wr < 0) { - //LOGE("write(%d) error %d (%s)", size, wr, strerror(errno)); - mStatus = errno; - } - } -} - -// ---------------------------------------------------------------------------- - -RFBServer::Message::Message(size_t size) - : mSize(size), mAllocatedSize(size) -{ - mPayload = malloc(size); -} - -RFBServer::Message::Message(void* payload, size_t size) - : mPayload(payload), mSize(size), mAllocatedSize(0) -{ -} - -RFBServer::Message::~Message() -{ - if (mAllocatedSize) - free(mPayload); -} - -status_t RFBServer::Message::resize(size_t size) -{ - if (size > mAllocatedSize) { - void* newp; - if (mAllocatedSize) { - newp = realloc(mPayload, size); - if (!newp) return NO_MEMORY; - } else { - newp = malloc(size); - if (!newp) return NO_MEMORY; - memcpy(newp, mPayload, mSize); - mAllocatedSize = size; - } - mPayload = newp; - } - mSize = size; - return NO_ERROR; -} - -// ---------------------------------------------------------------------------- - -RFBServer::EventInjector::EventInjector() - : mFD(-1) -{ -} - -RFBServer::EventInjector::~EventInjector() -{ -} - -void RFBServer::EventInjector::injectKey(uint16_t code, uint16_t value) -{ -#ifdef HAVE_ANDROID_OS - // XXX: we need to open the right event device - int version; - mFD = open("/dev/input/event0", O_RDWR); - ioctl(mFD, EVIOCGVERSION, &version); - - input_event ev; - memset(&ev, 0, sizeof(ev)); - ev.type = EV_KEY; - ev.code = code; - ev.value = value; - ::write(mFD, &ev, sizeof(ev)); - - close(mFD); - mFD = -1; -#endif -} - - -}; // namespace android - |