/* * 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. */ #ifndef ANDROID_RFB_SERVER_H #define ANDROID_RFB_SERVER_H #include #include #include #include #include #include #include #include #include #include #include "Barrier.h" namespace android { class SurfaceFlinger; class RFBServer : public Thread { public: RFBServer(uint32_t w, uint32_t h, android::PixelFormat format); virtual ~RFBServer(); void frameBufferUpdated(const GGLSurface& front, const Region& reg); bool isConnected() const; private: typedef uint8_t card8; typedef uint16_t card16; typedef uint32_t card32; struct Message { Message(size_t size); virtual ~Message(); void* payload(int offset=0) { return static_cast(mPayload)+offset; } void const * payload(int offset=0) const { return static_cast(mPayload)+offset; } size_t size() const { return mSize; } protected: Message(void* payload, size_t size); status_t resize(size_t size); private: void* mPayload; size_t mSize; size_t mAllocatedSize; }; struct ProtocolVersion : public Message { ProtocolVersion(uint8_t major, uint8_t minor) : Message(&messageData, 12) { char* p = static_cast(payload()); snprintf(p, 13, "RFB %03u.%03u%c", major, minor, 0xA); } status_t decode(int& maj, int& min) { char* p = static_cast(payload()); int n = sscanf(p, "RFB %03u.%03u", &maj, &min); return (n == 2) ? NO_ERROR : NOT_ENOUGH_DATA; } private: char messageData[12+1]; }; struct Authentication : public Message { enum { Failed=0, None=1, Vnc=2 }; Authentication(int auth) : Message(&messageData, 4) { *static_cast(payload()) = htonl(auth); } private: card32 messageData; }; struct ClientInitialization : public Message { ClientInitialization() : Message(&messageData, 1) { } int sharedFlags() { return messageData; } private: card8 messageData; }; struct PixelFormat { card8 bitsPerPixel; card8 depth; card8 bigEndianFlag; card8 trueColorFlag; card16 redMax; card16 greenMax; card16 blueMax; card8 redShift; card8 greenShift; card8 blueShift; uint8_t padding[3]; } __attribute__((packed)); struct ServerInitialization : public Message { ServerInitialization(char const * name) : Message(sizeof(Payload) + strlen(name)) { const size_t nameLength = size() - sizeof(Payload); message().nameLength = htonl(nameLength); memcpy((char*)message().nameString, name,nameLength); } struct Payload { card16 framebufferWidth; card16 framebufferHeight; PixelFormat serverPixelFormat; card32 nameLength; card8 nameString[0]; } __attribute__((packed)); Payload& message() { return *static_cast(payload()); } }; // client messages... struct SetPixelFormat { card8 type; uint8_t padding[3]; PixelFormat pixelFormat; } __attribute__((packed)); struct SetEncodings { enum { Raw=0, CoR=1, RRE=2, CoRRE=4, Hextile=5 }; card8 type; uint8_t padding; card16 numberOfEncodings; card32 encodings[0]; } __attribute__((packed)); struct FrameBufferUpdateRequest { card8 type; card8 incremental; card16 x; card16 y; card16 width; card16 height; } __attribute__((packed)); struct KeyEvent { card8 type; card8 downFlag; uint8_t padding[2]; card32 key; } __attribute__((packed)); struct PointerEvent { card8 type; card8 buttonMask; card16 x; card16 y; } __attribute__((packed)); struct ClientCutText { card8 type; uint8_t padding[3]; card32 length; card8 text[0]; } __attribute__((packed)); union ClientMessages { card8 type; SetPixelFormat setPixelFormat; SetEncodings setEncodings; FrameBufferUpdateRequest frameBufferUpdateRequest; KeyEvent keyEvent; PointerEvent pointerEvent; ClientCutText clientCutText; }; struct Rectangle { card16 x; card16 y; card16 w; card16 h; card32 encoding; } __attribute__((packed)); struct FrameBufferUpdate { card8 type; uint8_t padding; card16 numberOfRectangles; Rectangle rectangles[0]; } __attribute__((packed)); enum { SET_PIXEL_FORMAT = 0, FIX_COLOUR_MAP_ENTRIES = 1, SET_ENCODINGS = 2, FRAME_BUFFER_UPDATE_REQ = 3, KEY_EVENT = 4, POINTER_EVENT = 5, CLIENT_CUT_TEXT = 6, }; struct ClientMessage : public Message { ClientMessage() : Message(&messageData, sizeof(messageData)) { } const ClientMessages& messages() const { return *static_cast(payload()); } const int type() const { return messages().type; } status_t resize(size_t size) { return Message::resize(size); } ClientMessages messageData; }; class ServerThread : public Thread { friend class RFBServer; public: ServerThread(const sp& receiver); virtual ~ServerThread(); void wake(); void exitAndWait(); private: virtual bool threadLoop(); virtual status_t readyToRun(); virtual void onFirstRef(); wp mReceiver; bool (RFBServer::*mAction)(); Barrier mUpdateBarrier; }; class EventInjector { public: enum { UP=0, DOWN=1 }; EventInjector(); ~EventInjector(); void injectKey(uint16_t code, uint16_t value); private: struct input_event { struct timeval time; uint16_t type; uint16_t code; uint32_t value; }; int mFD; }; void handshake(uint8_t major, uint8_t minor, uint32_t auth); void waitForClientMessage(ClientMessage& msg); void handleClientMessage(const ClientMessage& msg); void handleSetPixelFormat(const SetPixelFormat& msg); void handleSetEncodings(const SetEncodings& msg); void handleFrameBufferUpdateReq(const FrameBufferUpdateRequest& msg); void handleKeyEvent(const KeyEvent& msg); void sendFrameBufferUpdates(); bool validatePixelFormat(const PixelFormat& pf); bool alive() const; bool write(const Message& msg); bool read(Message& msg); bool write(const void* buffer, int size); bool read(void* buffer, int size); virtual bool threadLoop(); virtual status_t readyToRun(); virtual void onFirstRef(); sp mRobinThread; int mFD; int mStatus; iovec* mIoVec; EventInjector mEventInjector; Mutex mRegionLock; // This is the region requested by the client since the last // time we updated it Region mClientRegionRequest; // This is the region of the screen that needs to be sent to the // client since the last time we updated it. // Typically this is the dirty region, but not necessarily, for // instance if the client asked for a non incremental update. Region mDirtyRegion; GGLSurface mFrameBuffer; GGLSurface mFrontBuffer; }; }; // namespace android #endif // ANDROID_RFB_SERVER_H