| /* |
| * 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 |
| |