/* * Copyright (c) 2010 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 __DEV_VNC_SERVER_HH__ #define __DEV_VNC_SERVER_HH__ #include #include "base/vnc/convert.hh" #include "base/bitmap.hh" #include "base/circlebuf.hh" #include "base/pollevent.hh" #include "base/socket.hh" #include "cpu/intr_control.hh" #include "params/VncServer.hh" #include "sim/sim_object.hh" /** * A device that expects to receive input from the vnc server should derrive * (through mulitple inheritence if necessary from VncKeyboard or VncMouse * and call setKeyboard() or setMouse() respectively on the vnc server. */ class VncKeyboard { public: /** * Called when the vnc server receives a key press event from the * client. * @param key the key passed is an x11 keysym * @param down is the key now down or up? */ virtual void keyPress(uint32_t key, bool down) = 0; }; class VncMouse { public: /** * called whenever the mouse moves or it's button state changes * buttons is a simple mask with each button (0-8) corresponding to * a bit position in the byte with 1 being down and 0 being up * @param x the x position of the mouse * @param y the y position of the mouse * @param buttos the button state as described above */ virtual void mouseAt(uint16_t x, uint16_t y, uint8_t buttons) = 0; }; class VncServer : public SimObject { 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; /** Client -> Server message IDs */ enum ClientMessages { ClientSetPixelFormat = 0, ClientSetEncodings = 2, ClientFrameBufferUpdate = 3, ClientKeyEvent = 4, ClientPointerEvent = 5, ClientCutText = 6 }; /** 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 PixelFormat { uint8_t bpp; uint8_t depth; uint8_t bigendian; uint8_t truecolor; uint16_t redmax; uint16_t greenmax; uint16_t bluemax; uint8_t redshift; uint8_t greenshift; uint8_t blueshift; uint8_t padding[3]; } M5_ATTR_PACKED; 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 PixelFormatMessage { uint8_t type; uint8_t padding[3]; PixelFormat px; } M5_ATTR_PACKED; struct PixelEncodingsMessage { uint8_t type; uint8_t padding; uint16_t num_encodings; } M5_ATTR_PACKED; struct FrameBufferUpdateReq { uint8_t type; uint8_t incremental; uint16_t x; uint16_t y; uint16_t width; uint16_t height; } M5_ATTR_PACKED; struct KeyEventMessage { uint8_t type; uint8_t down_flag; uint8_t padding[2]; uint32_t key; } M5_ATTR_PACKED; struct PointerEventMessage { uint8_t type; uint8_t button_mask; uint16_t x; uint16_t y; } M5_ATTR_PACKED; struct ClientCutTextMessage { uint8_t type; uint8_t padding[3]; uint32_t length; } 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; /** the width of the frame buffer we are sending to the client */ uint16_t _videoWidth; /** the height of the frame buffer we are sending to the client */ uint16_t _videoHeight; /** pointer to the actual data that is stored in the frame buffer device */ uint8_t* clientRfb; /** The device to notify when we get key events */ VncKeyboard *keyboard; /** The device to notify when we get mouse events */ VncMouse *mouse; /** 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; /** The mode of data we're getting frame buffer in */ VideoConvert::Mode videoMode; /** The video converter that transforms data for us */ VideoConvert *vc; /** Flag indicating whether to capture snapshots of frame buffer or not */ bool captureEnabled; /** Current frame number being captured to a file */ int captureCurrentFrame; /** Directory to store captured frames to */ std::string captureOutputDirectory; /** Computed hash of the last captured frame */ uint64_t captureLastHash; /** Cached bitmap object for writing out frame buffers to file */ Bitmap *captureBitmap; protected: /** Captures the current frame buffer to a file */ void captureFrameBuffer(); /** * 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 length read */ size_t 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 length read */ size_t 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 size_t read(T* val); /** Write a buffer to the client. * @param buf buffer to send * @param len length of the buffer * @return number of bytes sent */ size_t 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 size_t write(T* val); /** Send a string to the client * @param str string to transmit */ size_t 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(); public: /** Set the address of the frame buffer we are going to show. * To avoid copying, just have the display controller * tell us where the data is instead of constanly copying it around * @param rfb frame buffer that we're going to use */ void setFramebufferAddr(uint8_t* rfb) { clientRfb = rfb; } /** Set up the device that would like to receive notifications when keys are * pressed in the vnc client keyboard * @param _keyboard an object that derrives from VncKeyboard */ void setKeyboard(VncKeyboard *_keyboard) { keyboard = _keyboard; } /** Setup the device that would like to receive notifications when mouse * movements or button presses are received from the vnc client. * @param _mouse an object that derrives from VncMouse */ void setMouse(VncMouse *_mouse) { mouse = _mouse; } /** The frame buffer uses this call to notify the vnc server that * the frame buffer has been updated and a new image needs to be sent to the * client */ void setDirty() { sendUpdate = true; if (captureEnabled) captureFrameBuffer(); sendFrameBufferUpdate(); } /** What is the width of the screen we're displaying. * This is used for pointer/tablet devices that need to know to calculate * the correct value to send to the device driver. * @return the width of the simulated screen */ uint16_t videoWidth() { return _videoWidth; } /** What is the height of the screen we're displaying. * This is used for pointer/tablet devices that need to know to calculate * the correct value to send to the device driver. * @return the height of the simulated screen */ uint16_t videoHeight() { return _videoHeight; } /** Set the mode of the data the frame buffer will be sending us * @param mode the mode */ void setFrameBufferParams(VideoConvert::Mode mode, int width, int height); }; #endif