summaryrefslogtreecommitdiffstats
path: root/libs/surfaceflinger/RFBServer.h
blob: 420912ed724da32afbac83be183c72108485e3fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
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