17949SAli.Saidi@ARM.com/*
210839Sandreas.sandberg@arm.com * Copyright (c) 2010, 2015 ARM Limited
37949SAli.Saidi@ARM.com * All rights reserved
47949SAli.Saidi@ARM.com *
57949SAli.Saidi@ARM.com * The license below extends only to copyright in the software and shall
67949SAli.Saidi@ARM.com * not be construed as granting a license to any other intellectual
77949SAli.Saidi@ARM.com * property including but not limited to intellectual property relating
87949SAli.Saidi@ARM.com * to a hardware implementation of the functionality of the software
97949SAli.Saidi@ARM.com * licensed hereunder.  You may use the software subject to the license
107949SAli.Saidi@ARM.com * terms below provided that you ensure that this notice is replicated
117949SAli.Saidi@ARM.com * unmodified and in its entirety in all distributions of the software,
127949SAli.Saidi@ARM.com * modified or unmodified, in source code or in binary form.
137949SAli.Saidi@ARM.com *
147949SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without
157949SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are
167949SAli.Saidi@ARM.com * met: redistributions of source code must retain the above copyright
177949SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer;
187949SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright
197949SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the
207949SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution;
217949SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its
227949SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from
237949SAli.Saidi@ARM.com * this software without specific prior written permission.
247949SAli.Saidi@ARM.com *
257949SAli.Saidi@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
267949SAli.Saidi@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
277949SAli.Saidi@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
287949SAli.Saidi@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
297949SAli.Saidi@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
307949SAli.Saidi@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
317949SAli.Saidi@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
327949SAli.Saidi@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
337949SAli.Saidi@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
347949SAli.Saidi@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
357949SAli.Saidi@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
367949SAli.Saidi@ARM.com *
377949SAli.Saidi@ARM.com * Authors: Ali Saidi
387949SAli.Saidi@ARM.com *          William Wang
397949SAli.Saidi@ARM.com */
407949SAli.Saidi@ARM.com
417949SAli.Saidi@ARM.com/** @file
427949SAli.Saidi@ARM.com * Declaration of a VNC server
437949SAli.Saidi@ARM.com */
447949SAli.Saidi@ARM.com
459330Schander.sudanthi@arm.com#ifndef __BASE_VNC_VNC_SERVER_HH__
469330Schander.sudanthi@arm.com#define __BASE_VNC_VNC_SERVER_HH__
477949SAli.Saidi@ARM.com
487949SAli.Saidi@ARM.com#include <iostream>
497949SAli.Saidi@ARM.com
509330Schander.sudanthi@arm.com#include "base/vnc/vncinput.hh"
517949SAli.Saidi@ARM.com#include "base/circlebuf.hh"
527949SAli.Saidi@ARM.com#include "base/pollevent.hh"
537949SAli.Saidi@ARM.com#include "base/socket.hh"
548229Snate@binkert.org#include "params/VncServer.hh"
557949SAli.Saidi@ARM.com#include "sim/sim_object.hh"
567949SAli.Saidi@ARM.com
579330Schander.sudanthi@arm.com/** @file
589330Schander.sudanthi@arm.com * Declaration of a VNC server
599330Schander.sudanthi@arm.com */
608635Schris.emmons@arm.com
619330Schander.sudanthi@arm.comclass VncServer : public VncInput
627949SAli.Saidi@ARM.com{
637949SAli.Saidi@ARM.com  public:
647949SAli.Saidi@ARM.com
657949SAli.Saidi@ARM.com    /**
667949SAli.Saidi@ARM.com     * \defgroup VncConstants A set of constants and structs from the VNC spec
677949SAli.Saidi@ARM.com     * @{
687949SAli.Saidi@ARM.com     */
697949SAli.Saidi@ARM.com    /** Authentication modes */
707949SAli.Saidi@ARM.com    const static uint32_t AuthInvalid = 0;
717949SAli.Saidi@ARM.com    const static uint32_t AuthNone    = 1;
727949SAli.Saidi@ARM.com
737949SAli.Saidi@ARM.com    /** Error conditions */
747949SAli.Saidi@ARM.com    const static uint32_t VncOK   = 0;
757949SAli.Saidi@ARM.com
767949SAli.Saidi@ARM.com    /** Server -> Client message IDs */
777949SAli.Saidi@ARM.com    enum ServerMessages {
787949SAli.Saidi@ARM.com        ServerFrameBufferUpdate     = 0,
797949SAli.Saidi@ARM.com        ServerSetColorMapEntries    = 1,
807949SAli.Saidi@ARM.com        ServerBell                  = 2,
817949SAli.Saidi@ARM.com        ServerCutText               = 3
827949SAli.Saidi@ARM.com    };
837949SAli.Saidi@ARM.com
847949SAli.Saidi@ARM.com    /** Encoding types */
857949SAli.Saidi@ARM.com    enum EncodingTypes {
867949SAli.Saidi@ARM.com        EncodingRaw         = 0,
877949SAli.Saidi@ARM.com        EncodingCopyRect    = 1,
887949SAli.Saidi@ARM.com        EncodingHextile     = 5,
897949SAli.Saidi@ARM.com        EncodingDesktopSize = -223
907949SAli.Saidi@ARM.com    };
917949SAli.Saidi@ARM.com
927949SAli.Saidi@ARM.com    /** keyboard/mouse support */
937949SAli.Saidi@ARM.com    enum MouseEvents {
947949SAli.Saidi@ARM.com        MouseLeftButton     = 0x1,
957949SAli.Saidi@ARM.com        MouseRightButton    = 0x2,
967949SAli.Saidi@ARM.com        MouseMiddleButton   = 0x4
977949SAli.Saidi@ARM.com    };
987949SAli.Saidi@ARM.com
997949SAli.Saidi@ARM.com    const char* vncVersion() const
1007949SAli.Saidi@ARM.com    {
1017949SAli.Saidi@ARM.com        return "RFB 003.008\n";
1027949SAli.Saidi@ARM.com    }
1037949SAli.Saidi@ARM.com
1047949SAli.Saidi@ARM.com    enum ConnectionState {
1057949SAli.Saidi@ARM.com        WaitForProtocolVersion,
1067949SAli.Saidi@ARM.com        WaitForSecurityResponse,
1077949SAli.Saidi@ARM.com        WaitForClientInit,
1087949SAli.Saidi@ARM.com        InitializationPhase,
1097949SAli.Saidi@ARM.com        NormalPhase
1107949SAli.Saidi@ARM.com    };
1117949SAli.Saidi@ARM.com
1127949SAli.Saidi@ARM.com    struct ServerInitMsg {
1137949SAli.Saidi@ARM.com        uint16_t fbWidth;
1147949SAli.Saidi@ARM.com        uint16_t fbHeight;
1157949SAli.Saidi@ARM.com        PixelFormat px;
1167949SAli.Saidi@ARM.com        uint32_t namelen;
1177949SAli.Saidi@ARM.com        char name[2]; // just to put M5 in here
1187949SAli.Saidi@ARM.com    } M5_ATTR_PACKED;
1197949SAli.Saidi@ARM.com
1207949SAli.Saidi@ARM.com    struct FrameBufferUpdate {
1217949SAli.Saidi@ARM.com        uint8_t type;
1227949SAli.Saidi@ARM.com        uint8_t padding;
1237949SAli.Saidi@ARM.com        uint16_t num_rects;
1247949SAli.Saidi@ARM.com    } M5_ATTR_PACKED;
1257949SAli.Saidi@ARM.com
1267949SAli.Saidi@ARM.com    struct FrameBufferRect {
1277949SAli.Saidi@ARM.com        uint16_t x;
1287949SAli.Saidi@ARM.com        uint16_t y;
1297949SAli.Saidi@ARM.com        uint16_t width;
1307949SAli.Saidi@ARM.com        uint16_t height;
1317949SAli.Saidi@ARM.com        int32_t encoding;
1327949SAli.Saidi@ARM.com    } M5_ATTR_PACKED;
1337949SAli.Saidi@ARM.com
1347949SAli.Saidi@ARM.com    struct ServerCutText {
1357949SAli.Saidi@ARM.com        uint8_t type;
1367949SAli.Saidi@ARM.com        uint8_t padding[3];
1377949SAli.Saidi@ARM.com        uint32_t length;
1387949SAli.Saidi@ARM.com    } M5_ATTR_PACKED;
1397949SAli.Saidi@ARM.com
1407949SAli.Saidi@ARM.com    /** @} */
1417949SAli.Saidi@ARM.com
1427949SAli.Saidi@ARM.com  protected:
1437949SAli.Saidi@ARM.com    /** ListenEvent to accept a vnc client connection */
1447949SAli.Saidi@ARM.com    class ListenEvent: public PollEvent
1457949SAli.Saidi@ARM.com    {
1467949SAli.Saidi@ARM.com      protected:
1477949SAli.Saidi@ARM.com        VncServer *vncserver;
1487949SAli.Saidi@ARM.com
1497949SAli.Saidi@ARM.com      public:
1507949SAli.Saidi@ARM.com        ListenEvent(VncServer *vs, int fd, int e);
1517949SAli.Saidi@ARM.com        void process(int revent);
1527949SAli.Saidi@ARM.com    };
1537949SAli.Saidi@ARM.com
1547949SAli.Saidi@ARM.com    friend class ListenEvent;
1557949SAli.Saidi@ARM.com    ListenEvent *listenEvent;
1567949SAli.Saidi@ARM.com
1577949SAli.Saidi@ARM.com    /** DataEvent to read data from vnc */
1587949SAli.Saidi@ARM.com    class DataEvent: public PollEvent
1597949SAli.Saidi@ARM.com    {
1607949SAli.Saidi@ARM.com      protected:
1617949SAli.Saidi@ARM.com        VncServer *vncserver;
1627949SAli.Saidi@ARM.com
1637949SAli.Saidi@ARM.com      public:
1647949SAli.Saidi@ARM.com        DataEvent(VncServer *vs, int fd, int e);
1657949SAli.Saidi@ARM.com        void process(int revent);
1667949SAli.Saidi@ARM.com    };
1677949SAli.Saidi@ARM.com
1687949SAli.Saidi@ARM.com    friend class DataEvent;
1697949SAli.Saidi@ARM.com    DataEvent *dataEvent;
1707949SAli.Saidi@ARM.com
1717949SAli.Saidi@ARM.com    int number;
1727949SAli.Saidi@ARM.com    int dataFd; // data stream file describer
1737949SAli.Saidi@ARM.com
1747949SAli.Saidi@ARM.com    ListenSocket listener;
1757949SAli.Saidi@ARM.com
1767949SAli.Saidi@ARM.com    void listen(int port);
1777949SAli.Saidi@ARM.com    void accept();
1787949SAli.Saidi@ARM.com    void data();
1797949SAli.Saidi@ARM.com    void detach();
1807949SAli.Saidi@ARM.com
1817949SAli.Saidi@ARM.com  public:
1827949SAli.Saidi@ARM.com    typedef VncServerParams Params;
1837949SAli.Saidi@ARM.com    VncServer(const Params *p);
1847949SAli.Saidi@ARM.com    ~VncServer();
1857949SAli.Saidi@ARM.com
1867949SAli.Saidi@ARM.com    // RFB
1877949SAli.Saidi@ARM.com  protected:
1887949SAli.Saidi@ARM.com
1897949SAli.Saidi@ARM.com    /** The rfb prototol state the connection is in */
1907949SAli.Saidi@ARM.com    ConnectionState curState;
1917949SAli.Saidi@ARM.com
1927949SAli.Saidi@ARM.com    /** An update needs to be sent to the client. Without doing this the
1937949SAli.Saidi@ARM.com     * client will constantly request data that is pointless */
1947949SAli.Saidi@ARM.com    bool sendUpdate;
1957949SAli.Saidi@ARM.com
1967949SAli.Saidi@ARM.com    /** The one and only pixel format we support */
1977949SAli.Saidi@ARM.com    PixelFormat pixelFormat;
1987949SAli.Saidi@ARM.com
1997949SAli.Saidi@ARM.com    /** If the vnc client supports receiving raw data. It always should */
2007949SAli.Saidi@ARM.com    bool supportsRawEnc;
2017949SAli.Saidi@ARM.com
2027949SAli.Saidi@ARM.com    /** If the vnc client supports the desktop resize command */
2037949SAli.Saidi@ARM.com    bool supportsResizeEnc;
2047949SAli.Saidi@ARM.com
2057949SAli.Saidi@ARM.com  protected:
2067949SAli.Saidi@ARM.com    /**
2077949SAli.Saidi@ARM.com     * vnc client Interface
2087949SAli.Saidi@ARM.com     */
2097949SAli.Saidi@ARM.com
2107949SAli.Saidi@ARM.com    /** Send an error message to the client
2117949SAli.Saidi@ARM.com     * @param error_msg text to send describing the error
2127949SAli.Saidi@ARM.com     */
2137949SAli.Saidi@ARM.com    void sendError(const char* error_msg);
2147949SAli.Saidi@ARM.com
2157949SAli.Saidi@ARM.com    /** Read some data from the client
2167949SAli.Saidi@ARM.com     * @param buf the data to read
2177949SAli.Saidi@ARM.com     * @param len the amount of data to read
21812020Sgabeblack@google.com     * @return whether the read was successful
2197949SAli.Saidi@ARM.com     */
22012020Sgabeblack@google.com    bool read(uint8_t *buf, size_t len);
2217949SAli.Saidi@ARM.com
2227949SAli.Saidi@ARM.com    /** Read len -1 bytes from the client into the buffer provided + 1
2237949SAli.Saidi@ARM.com     * assert that we read enough bytes. This function exists to handle
2247949SAli.Saidi@ARM.com     * reading all of the protocol structs above when we've already read
2257949SAli.Saidi@ARM.com     * the first byte which describes which one we're reading
2267949SAli.Saidi@ARM.com     * @param buf the address of the buffer to add one to and read data into
2277949SAli.Saidi@ARM.com     * @param len the amount of data  + 1 to read
22812020Sgabeblack@google.com     * @return whether the read was successful.
2297949SAli.Saidi@ARM.com     */
23012020Sgabeblack@google.com    bool read1(uint8_t *buf, size_t len);
2317949SAli.Saidi@ARM.com
2327949SAli.Saidi@ARM.com
2337949SAli.Saidi@ARM.com    /** Templated version of the read function above to
2347949SAli.Saidi@ARM.com     * read simple data to the client
2357949SAli.Saidi@ARM.com     * @param val data to recv from the client
2367949SAli.Saidi@ARM.com     */
23712020Sgabeblack@google.com    template <typename T> bool read(T* val);
2387949SAli.Saidi@ARM.com
2397949SAli.Saidi@ARM.com
2407949SAli.Saidi@ARM.com    /** Write a buffer to the client.
2417949SAli.Saidi@ARM.com     * @param buf buffer to send
2427949SAli.Saidi@ARM.com     * @param len length of the buffer
24312020Sgabeblack@google.com     * @return whether the write was successful
2447949SAli.Saidi@ARM.com     */
24512020Sgabeblack@google.com    bool write(const uint8_t *buf, size_t len);
2467949SAli.Saidi@ARM.com
2477949SAli.Saidi@ARM.com    /** Templated version of the write function above to
2487949SAli.Saidi@ARM.com     * write simple data to the client
2497949SAli.Saidi@ARM.com     * @param val data to send to the client
2507949SAli.Saidi@ARM.com     */
25112020Sgabeblack@google.com    template <typename T> bool write(T* val);
2527949SAli.Saidi@ARM.com
2537949SAli.Saidi@ARM.com    /** Send a string to the client
2547949SAli.Saidi@ARM.com     * @param str string to transmit
2557949SAli.Saidi@ARM.com     */
25612020Sgabeblack@google.com    bool write(const char* str);
2577949SAli.Saidi@ARM.com
2587949SAli.Saidi@ARM.com    /** Check the client's protocol verion for compatibility and send
2597949SAli.Saidi@ARM.com     * the security types we support
2607949SAli.Saidi@ARM.com     */
2617949SAli.Saidi@ARM.com    void checkProtocolVersion();
2627949SAli.Saidi@ARM.com
2637949SAli.Saidi@ARM.com    /** Check that the security exchange was successful
2647949SAli.Saidi@ARM.com     */
2657949SAli.Saidi@ARM.com    void checkSecurity();
2667949SAli.Saidi@ARM.com
2677949SAli.Saidi@ARM.com    /** Send client our idea about what the frame buffer looks like */
2687949SAli.Saidi@ARM.com    void sendServerInit();
2697949SAli.Saidi@ARM.com
2707949SAli.Saidi@ARM.com    /** Send an error message to the client when something goes wrong
2717949SAli.Saidi@ARM.com     * @param error_msg error to send
2727949SAli.Saidi@ARM.com     */
2737949SAli.Saidi@ARM.com    void sendError(std::string error_msg);
2747949SAli.Saidi@ARM.com
2757949SAli.Saidi@ARM.com    /** Send a updated frame buffer to the client.
2767949SAli.Saidi@ARM.com     * @todo this doesn't do anything smart and just sends the entire image
2777949SAli.Saidi@ARM.com     */
2787949SAli.Saidi@ARM.com    void sendFrameBufferUpdate();
2797949SAli.Saidi@ARM.com
2807949SAli.Saidi@ARM.com    /** Receive pixel foramt message from client and process it. */
2817949SAli.Saidi@ARM.com    void setPixelFormat();
2827949SAli.Saidi@ARM.com
2837949SAli.Saidi@ARM.com    /** Receive encodings message from client and process it. */
2847949SAli.Saidi@ARM.com    void setEncodings();
2857949SAli.Saidi@ARM.com
2867949SAli.Saidi@ARM.com    /** Receive message from client asking for updated frame buffer */
2877949SAli.Saidi@ARM.com    void requestFbUpdate();
2887949SAli.Saidi@ARM.com
2897949SAli.Saidi@ARM.com    /** Receive message from client providing new keyboard input */
2907949SAli.Saidi@ARM.com    void recvKeyboardInput();
2917949SAli.Saidi@ARM.com
2927949SAli.Saidi@ARM.com    /** Recv message from client providing new mouse movement or button click */
2937949SAli.Saidi@ARM.com    void recvPointerInput();
2947949SAli.Saidi@ARM.com
2957949SAli.Saidi@ARM.com    /**  Receive message from client that there is text in it's paste buffer.
2967949SAli.Saidi@ARM.com     * This is a no-op at the moment, but perhaps we would want to be able to
2977949SAli.Saidi@ARM.com     * paste it at some point.
2987949SAli.Saidi@ARM.com     */
2997949SAli.Saidi@ARM.com    void recvCutText();
3007949SAli.Saidi@ARM.com
3017949SAli.Saidi@ARM.com    /** Tell the client that the frame buffer resized. This happens when the
3027949SAli.Saidi@ARM.com     * simulated system changes video modes (E.g. X11 starts).
3037949SAli.Saidi@ARM.com     */
3047949SAli.Saidi@ARM.com    void sendFrameBufferResized();
3057949SAli.Saidi@ARM.com
30610839Sandreas.sandberg@arm.com    static const PixelConverter pixelConverter;
30710839Sandreas.sandberg@arm.com
3087949SAli.Saidi@ARM.com  public:
30911168Sandreas.hansson@arm.com    void setDirty() override;
31011168Sandreas.hansson@arm.com    void frameBufferResized() override;
3117949SAli.Saidi@ARM.com};
3127949SAli.Saidi@ARM.com
3137949SAli.Saidi@ARM.com#endif
314