summaryrefslogtreecommitdiff
path: root/src/base/vnc/vncserver.hh
blob: f64ccd7cda9307829550615007dc94c17af29b88 (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
/*
 * Copyright (c) 2010, 2015 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Ali Saidi
 *          William Wang
 */

/** @file
 * Declaration of a VNC server
 */

#ifndef __BASE_VNC_VNC_SERVER_HH__
#define __BASE_VNC_VNC_SERVER_HH__

#include <iostream>

#include "base/vnc/vncinput.hh"
#include "base/circlebuf.hh"
#include "base/pollevent.hh"
#include "base/socket.hh"
#include "params/VncServer.hh"
#include "sim/sim_object.hh"

/** @file
 * Declaration of a VNC server
 */

class VncServer : public VncInput
{
  public:

    /**
     * \defgroup VncConstants A set of constants and structs from the VNC spec
     * @{
     */
    /** Authentication modes */
    const static uint32_t AuthInvalid = 0;
    const static uint32_t AuthNone    = 1;

    /** Error conditions */
    const static uint32_t VncOK   = 0;

    /** Server -> Client message IDs */
    enum ServerMessages {
        ServerFrameBufferUpdate     = 0,
        ServerSetColorMapEntries    = 1,
        ServerBell                  = 2,
        ServerCutText               = 3
    };

    /** Encoding types */
    enum EncodingTypes {
        EncodingRaw         = 0,
        EncodingCopyRect    = 1,
        EncodingHextile     = 5,
        EncodingDesktopSize = -223
    };

    /** keyboard/mouse support */
    enum MouseEvents {
        MouseLeftButton     = 0x1,
        MouseRightButton    = 0x2,
        MouseMiddleButton   = 0x4
    };

    const char* vncVersion() const
    {
        return "RFB 003.008\n";
    }

    enum ConnectionState {
        WaitForProtocolVersion,
        WaitForSecurityResponse,
        WaitForClientInit,
        InitializationPhase,
        NormalPhase
    };

    struct ServerInitMsg {
        uint16_t fbWidth;
        uint16_t fbHeight;
        PixelFormat px;
        uint32_t namelen;
        char name[2]; // just to put M5 in here
    } M5_ATTR_PACKED;

    struct FrameBufferUpdate {
        uint8_t type;
        uint8_t padding;
        uint16_t num_rects;
    } M5_ATTR_PACKED;

    struct FrameBufferRect {
        uint16_t x;
        uint16_t y;
        uint16_t width;
        uint16_t height;
        int32_t encoding;
    } M5_ATTR_PACKED;

    struct ServerCutText {
        uint8_t type;
        uint8_t padding[3];
        uint32_t length;
    } M5_ATTR_PACKED;

    /** @} */

  protected:
    /** ListenEvent to accept a vnc client connection */
    class ListenEvent: public PollEvent
    {
      protected:
        VncServer *vncserver;

      public:
        ListenEvent(VncServer *vs, int fd, int e);
        void process(int revent);
    };

    friend class ListenEvent;
    ListenEvent *listenEvent;

    /** DataEvent to read data from vnc */
    class DataEvent: public PollEvent
    {
      protected:
        VncServer *vncserver;

      public:
        DataEvent(VncServer *vs, int fd, int e);
        void process(int revent);
    };

    friend class DataEvent;
    DataEvent *dataEvent;

    int number;
    int dataFd; // data stream file describer

    ListenSocket listener;

    void listen(int port);
    void accept();
    void data();
    void detach();

  public:
    typedef VncServerParams Params;
    VncServer(const Params *p);
    ~VncServer();

    // RFB
  protected:

    /** The rfb prototol state the connection is in */
    ConnectionState curState;

    /** An update needs to be sent to the client. Without doing this the
     * client will constantly request data that is pointless */
    bool sendUpdate;

    /** The one and only pixel format we support */
    PixelFormat pixelFormat;

    /** If the vnc client supports receiving raw data. It always should */
    bool supportsRawEnc;

    /** If the vnc client supports the desktop resize command */
    bool supportsResizeEnc;

  protected:
    /**
     * vnc client Interface
     */

    /** Send an error message to the client
     * @param error_msg text to send describing the error
     */
    void sendError(const char* error_msg);

    /** Read some data from the client
     * @param buf the data to read
     * @param len the amount of data to read
     * @return whether the read was successful
     */
    bool read(uint8_t *buf, size_t len);

    /** Read len -1 bytes from the client into the buffer provided + 1
     * assert that we read enough bytes. This function exists to handle
     * reading all of the protocol structs above when we've already read
     * the first byte which describes which one we're reading
     * @param buf the address of the buffer to add one to and read data into
     * @param len the amount of data  + 1 to read
     * @return whether the read was successful.
     */
    bool read1(uint8_t *buf, size_t len);


    /** Templated version of the read function above to
     * read simple data to the client
     * @param val data to recv from the client
     */
    template <typename T> bool read(T* val);


    /** Write a buffer to the client.
     * @param buf buffer to send
     * @param len length of the buffer
     * @return whether the write was successful
     */
    bool write(const uint8_t *buf, size_t len);

    /** Templated version of the write function above to
     * write simple data to the client
     * @param val data to send to the client
     */
    template <typename T> bool write(T* val);

    /** Send a string to the client
     * @param str string to transmit
     */
    bool write(const char* str);

    /** Check the client's protocol verion for compatibility and send
     * the security types we support
     */
    void checkProtocolVersion();

    /** Check that the security exchange was successful
     */
    void checkSecurity();

    /** Send client our idea about what the frame buffer looks like */
    void sendServerInit();

    /** Send an error message to the client when something goes wrong
     * @param error_msg error to send
     */
    void sendError(std::string error_msg);

    /** Send a updated frame buffer to the client.
     * @todo this doesn't do anything smart and just sends the entire image
     */
    void sendFrameBufferUpdate();

    /** Receive pixel foramt message from client and process it. */
    void setPixelFormat();

    /** Receive encodings message from client and process it. */
    void setEncodings();

    /** Receive message from client asking for updated frame buffer */
    void requestFbUpdate();

    /** Receive message from client providing new keyboard input */
    void recvKeyboardInput();

    /** Recv message from client providing new mouse movement or button click */
    void recvPointerInput();

    /**  Receive message from client that there is text in it's paste buffer.
     * This is a no-op at the moment, but perhaps we would want to be able to
     * paste it at some point.
     */
    void recvCutText();

    /** Tell the client that the frame buffer resized. This happens when the
     * simulated system changes video modes (E.g. X11 starts).
     */
    void sendFrameBufferResized();

    static const PixelConverter pixelConverter;

  public:
    void setDirty() override;
    void frameBufferResized() override;
};

#endif