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