vncserver.hh revision 7949
1/*
2 * Copyright (c) 2010 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Ali Saidi
38 *          William Wang
39 */
40
41/** @file
42 * Declaration of a VNC server
43 */
44
45#ifndef __DEV_VNC_SERVER_HH__
46#define __DEV_VNC_SERVER_HH__
47
48#include <iostream>
49
50#include "base/circlebuf.hh"
51#include "base/pollevent.hh"
52#include "base/socket.hh"
53#include "base/vnc/convert.hh"
54#include "cpu/intr_control.hh"
55#include "sim/sim_object.hh"
56#include "params/VncServer.hh"
57
58/**
59 * A device that expects to receive input from the vnc server should derrive
60 * (through mulitple inheritence if necessary from VncKeyboard or VncMouse
61 * and call setKeyboard() or setMouse() respectively on the vnc server.
62 */
63class VncKeyboard
64{
65  public:
66    /**
67     * Called when the vnc server receives a key press event from the
68     * client.
69     * @param key the key passed is an x11 keysym
70     * @param down is the key now down or up?
71     */
72    virtual void keyPress(uint32_t key, bool down) = 0;
73};
74
75class VncMouse
76{
77  public:
78    /**
79     * called whenever the mouse moves or it's button state changes
80     * buttons is a simple mask with each button (0-8) corresponding to
81     * a bit position in the byte with 1 being down and 0 being up
82     * @param x the x position of the mouse
83     * @param y the y position of the mouse
84     * @param buttos the button state as described above
85     */
86    virtual void mouseAt(uint16_t x, uint16_t y, uint8_t buttons) = 0;
87};
88
89class VncServer : public SimObject
90{
91  public:
92
93    /**
94     * \defgroup VncConstants A set of constants and structs from the VNC spec
95     * @{
96     */
97    /** Authentication modes */
98    const static uint32_t AuthInvalid = 0;
99    const static uint32_t AuthNone    = 1;
100
101    /** Error conditions */
102    const static uint32_t VncOK   = 0;
103
104    /** Client -> Server message IDs */
105    enum ClientMessages {
106        ClientSetPixelFormat    = 0,
107        ClientSetEncodings      = 2,
108        ClientFrameBufferUpdate = 3,
109        ClientKeyEvent          = 4,
110        ClientPointerEvent      = 5,
111        ClientCutText           = 6
112    };
113
114    /** Server -> Client message IDs */
115    enum ServerMessages {
116        ServerFrameBufferUpdate     = 0,
117        ServerSetColorMapEntries    = 1,
118        ServerBell                  = 2,
119        ServerCutText               = 3
120    };
121
122    /** Encoding types */
123    enum EncodingTypes {
124        EncodingRaw         = 0,
125        EncodingCopyRect    = 1,
126        EncodingHextile     = 5,
127        EncodingDesktopSize = -223
128    };
129
130    /** keyboard/mouse support */
131    enum MouseEvents {
132        MouseLeftButton     = 0x1,
133        MouseRightButton    = 0x2,
134        MouseMiddleButton   = 0x4
135    };
136
137    const char* vncVersion() const
138    {
139        return "RFB 003.008\n";
140    }
141
142    enum ConnectionState {
143        WaitForProtocolVersion,
144        WaitForSecurityResponse,
145        WaitForClientInit,
146        InitializationPhase,
147        NormalPhase
148    };
149
150    struct PixelFormat {
151        uint8_t bpp;
152        uint8_t depth;
153        uint8_t bigendian;
154        uint8_t truecolor;
155        uint16_t redmax;
156        uint16_t greenmax;
157        uint16_t bluemax;
158        uint8_t redshift;
159        uint8_t greenshift;
160        uint8_t blueshift;
161        uint8_t padding[3];
162    } M5_ATTR_PACKED;
163
164    struct ServerInitMsg {
165        uint16_t fbWidth;
166        uint16_t fbHeight;
167        PixelFormat px;
168        uint32_t namelen;
169        char name[2]; // just to put M5 in here
170    } M5_ATTR_PACKED;
171
172    struct PixelFormatMessage {
173        uint8_t type;
174        uint8_t padding[3];
175        PixelFormat px;
176    } M5_ATTR_PACKED;
177
178    struct PixelEncodingsMessage {
179        uint8_t type;
180        uint8_t padding;
181        uint16_t num_encodings;
182    } M5_ATTR_PACKED;
183
184    struct FrameBufferUpdateReq {
185        uint8_t type;
186        uint8_t incremental;
187        uint16_t x;
188        uint16_t y;
189        uint16_t width;
190        uint16_t height;
191    } M5_ATTR_PACKED;
192
193    struct KeyEventMessage {
194        uint8_t type;
195        uint8_t down_flag;
196        uint8_t padding[2];
197        uint32_t key;
198    } M5_ATTR_PACKED;
199
200    struct PointerEventMessage {
201        uint8_t type;
202        uint8_t button_mask;
203        uint16_t x;
204        uint16_t y;
205    } M5_ATTR_PACKED;
206
207    struct ClientCutTextMessage {
208        uint8_t type;
209        uint8_t padding[3];
210        uint32_t length;
211    } M5_ATTR_PACKED;
212
213    struct FrameBufferUpdate {
214        uint8_t type;
215        uint8_t padding;
216        uint16_t num_rects;
217    } M5_ATTR_PACKED;
218
219    struct FrameBufferRect {
220        uint16_t x;
221        uint16_t y;
222        uint16_t width;
223        uint16_t height;
224        int32_t encoding;
225    } M5_ATTR_PACKED;
226
227    struct ServerCutText {
228        uint8_t type;
229        uint8_t padding[3];
230        uint32_t length;
231    } M5_ATTR_PACKED;
232
233    /** @} */
234
235  protected:
236    /** ListenEvent to accept a vnc client connection */
237    class ListenEvent: public PollEvent
238    {
239      protected:
240        VncServer *vncserver;
241
242      public:
243        ListenEvent(VncServer *vs, int fd, int e);
244        void process(int revent);
245    };
246
247    friend class ListenEvent;
248    ListenEvent *listenEvent;
249
250    /** DataEvent to read data from vnc */
251    class DataEvent: public PollEvent
252    {
253      protected:
254        VncServer *vncserver;
255
256      public:
257        DataEvent(VncServer *vs, int fd, int e);
258        void process(int revent);
259    };
260
261    friend class DataEvent;
262    DataEvent *dataEvent;
263
264    int number;
265    int dataFd; // data stream file describer
266
267    ListenSocket listener;
268
269    void listen(int port);
270    void accept();
271    void data();
272    void detach();
273
274  public:
275    typedef VncServerParams Params;
276    VncServer(const Params *p);
277    ~VncServer();
278
279    // RFB
280  protected:
281
282    /** The rfb prototol state the connection is in */
283    ConnectionState curState;
284
285    /** the width of the frame buffer we are sending to the client */
286    uint16_t _videoWidth;
287
288    /** the height of the frame buffer we are sending to the client */
289    uint16_t _videoHeight;
290
291    /** pointer to the actual data that is stored in the frame buffer device */
292    uint8_t* clientRfb;
293
294    /** The device to notify when we get key events */
295    VncKeyboard *keyboard;
296
297    /** The device to notify when we get mouse events */
298    VncMouse *mouse;
299
300    /** An update needs to be sent to the client. Without doing this the
301     * client will constantly request data that is pointless */
302    bool sendUpdate;
303
304    /** The one and only pixel format we support */
305    PixelFormat pixelFormat;
306
307    /** If the vnc client supports receiving raw data. It always should */
308    bool supportsRawEnc;
309
310    /** If the vnc client supports the desktop resize command */
311    bool supportsResizeEnc;
312
313    /** The mode of data we're getting frame buffer in */
314    VideoConvert::Mode videoMode;
315
316    /** The video converter that transforms data for us */
317    VideoConvert *vc;
318
319  protected:
320    /**
321     * vnc client Interface
322     */
323
324    /** Send an error message to the client
325     * @param error_msg text to send describing the error
326     */
327    void sendError(const char* error_msg);
328
329    /** Read some data from the client
330     * @param buf the data to read
331     * @param len the amount of data to read
332     * @return length read
333     */
334    size_t read(uint8_t *buf, size_t len);
335
336    /** Read len -1 bytes from the client into the buffer provided + 1
337     * assert that we read enough bytes. This function exists to handle
338     * reading all of the protocol structs above when we've already read
339     * the first byte which describes which one we're reading
340     * @param buf the address of the buffer to add one to and read data into
341     * @param len the amount of data  + 1 to read
342     * @return length read
343     */
344    size_t read1(uint8_t *buf, size_t len);
345
346
347    /** Templated version of the read function above to
348     * read simple data to the client
349     * @param val data to recv from the client
350     */
351    template <typename T> size_t read(T* val);
352
353
354    /** Write a buffer to the client.
355     * @param buf buffer to send
356     * @param len length of the buffer
357     * @return number of bytes sent
358     */
359    size_t write(const uint8_t *buf, size_t len);
360
361    /** Templated version of the write function above to
362     * write simple data to the client
363     * @param val data to send to the client
364     */
365    template <typename T> size_t write(T* val);
366
367    /** Send a string to the client
368     * @param str string to transmit
369     */
370    size_t write(const char* str);
371
372    /** Check the client's protocol verion for compatibility and send
373     * the security types we support
374     */
375    void checkProtocolVersion();
376
377    /** Check that the security exchange was successful
378     */
379    void checkSecurity();
380
381    /** Send client our idea about what the frame buffer looks like */
382    void sendServerInit();
383
384    /** Send an error message to the client when something goes wrong
385     * @param error_msg error to send
386     */
387    void sendError(std::string error_msg);
388
389    /** Send a updated frame buffer to the client.
390     * @todo this doesn't do anything smart and just sends the entire image
391     */
392    void sendFrameBufferUpdate();
393
394    /** Receive pixel foramt message from client and process it. */
395    void setPixelFormat();
396
397    /** Receive encodings message from client and process it. */
398    void setEncodings();
399
400    /** Receive message from client asking for updated frame buffer */
401    void requestFbUpdate();
402
403    /** Receive message from client providing new keyboard input */
404    void recvKeyboardInput();
405
406    /** Recv message from client providing new mouse movement or button click */
407    void recvPointerInput();
408
409    /**  Receive message from client that there is text in it's paste buffer.
410     * This is a no-op at the moment, but perhaps we would want to be able to
411     * paste it at some point.
412     */
413    void recvCutText();
414
415    /** Tell the client that the frame buffer resized. This happens when the
416     * simulated system changes video modes (E.g. X11 starts).
417     */
418    void sendFrameBufferResized();
419
420  public:
421    /** Set the address of the frame buffer we are going to show.
422     * To avoid copying, just have the display controller
423     * tell us where the data is instead of constanly copying it around
424     * @param rfb frame buffer that we're going to use
425     */
426    void
427    setFramebufferAddr(uint8_t* rfb)
428    {
429        clientRfb = rfb;
430    }
431
432    /** Set up the device that would like to receive notifications when keys are
433     * pressed in the vnc client keyboard
434     * @param _keyboard an object that derrives from VncKeyboard
435     */
436    void setKeyboard(VncKeyboard *_keyboard) { keyboard = _keyboard; }
437
438    /** Setup the device that would like to receive notifications when mouse
439     * movements or button presses are received from the vnc client.
440     * @param _mouse an object that derrives from VncMouse
441     */
442    void setMouse(VncMouse *_mouse) { mouse = _mouse; }
443
444    /** The frame buffer uses this call to notify the vnc server that
445     * the frame buffer has been updated and a new image needs to be sent to the
446     * client
447     */
448    void
449    setDirty()
450    {
451        sendUpdate = true;
452        sendFrameBufferUpdate();
453    }
454
455    /** What is the width of the screen we're displaying.
456     * This is used for pointer/tablet devices that need to know to calculate
457     * the correct value to send to the device driver.
458     * @return the width of the simulated screen
459     */
460    uint16_t videoWidth() { return _videoWidth; }
461
462    /** What is the height of the screen we're displaying.
463     * This is used for pointer/tablet devices that need to know to calculate
464     * the correct value to send to the device driver.
465     * @return the height of the simulated screen
466     */
467    uint16_t videoHeight() { return _videoHeight; }
468
469    /** Set the mode of the data the frame buffer will be sending us
470     * @param mode the mode
471     */
472    void setFrameBufferParams(VideoConvert::Mode mode, int width, int height);
473};
474
475#endif
476