diff options
Diffstat (limited to 'libs/surfaceflinger/RFBServer.h')
-rw-r--r-- | libs/surfaceflinger/RFBServer.h | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/libs/surfaceflinger/RFBServer.h b/libs/surfaceflinger/RFBServer.h new file mode 100644 index 0000000..420912e --- /dev/null +++ b/libs/surfaceflinger/RFBServer.h @@ -0,0 +1,316 @@ +/* + * 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 <stdint.h> +#include <sys/types.h> +#include <sys/uio.h> +#include <unistd.h> +#include <arpa/inet.h> + +#include <utils/Errors.h> +#include <utils/threads.h> +#include <ui/Region.h> +#include <ui/PixelFormat.h> + +#include <pixelflinger/pixelflinger.h> + +#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<char*>(mPayload)+offset; + } + void const * payload(int offset=0) const { + return static_cast<char const *>(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<char*>(payload()); + snprintf(p, 13, "RFB %03u.%03u%c", major, minor, 0xA); + } + status_t decode(int& maj, int& min) { + char* p = static_cast<char*>(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<card32*>(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*>(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<ClientMessages const *>(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<RFBServer>& receiver); + virtual ~ServerThread(); + void wake(); + void exitAndWait(); + private: + virtual bool threadLoop(); + virtual status_t readyToRun(); + virtual void onFirstRef(); + wp<RFBServer> 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<ServerThread> 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 |