├── .gitignore ├── .ycm_extra_conf.py ├── COPYING ├── COPYING.GPL ├── README.md ├── include ├── buffer.h ├── crypto.h ├── inhibitor.h ├── keyboard.h ├── keysym.h ├── open-h264.h ├── output.h ├── pixels.h ├── pointer.h ├── region.h ├── renderer-egl.h ├── renderer.h ├── rfbclient.h ├── rfbproto.h ├── sasl.h ├── seat.h ├── shm.h ├── sockets.h ├── strlcpy.h ├── threading.h ├── time-util.h ├── tls.h ├── turbojpeg.h ├── usdt.h └── vnc.h ├── meson.build ├── protocols ├── keyboard-shortcuts-inhibit-unstable-v1.xml ├── linux-dmabuf-v1.xml ├── meson.build ├── single-pixel-buffer-v1.xml ├── viewporter-v1.xml └── xdg-shell.xml ├── scripts └── auth-script.sh └── src ├── buffer.c ├── crypto_included.c ├── crypto_libgcrypt.c ├── crypto_openssl.c ├── cursor.c ├── encodings ├── corre.c ├── hextile.c ├── rre.c ├── tight.c ├── trle.c ├── ultra.c ├── vncauth.c ├── zlib.c ├── zrle.c └── zywrletemplate.c ├── evdev-to-qnum.c ├── inhibitor.c ├── keyboard.c ├── main.c ├── open-h264.c ├── output.c ├── pixels.c ├── pointer.c ├── region.c ├── renderer-egl.c ├── renderer.c ├── rfbproto.c ├── sasl.c ├── seat.c ├── shm.c ├── sockets.c ├── strlcpy.c ├── tls_gnutls.c ├── tls_none.c ├── tls_openssl.c ├── turbojpeg.c ├── vnc.c └── vncviewer.c /.gitignore: -------------------------------------------------------------------------------- 1 | build* 2 | subprojects 3 | .clang_complete 4 | -------------------------------------------------------------------------------- /.ycm_extra_conf.py: -------------------------------------------------------------------------------- 1 | def Settings(**kwargs): 2 | return { 3 | 'flags': [ 4 | '-std=gnu11', 5 | '-D_GNU_SOURCE', 6 | '-Iinclude', 7 | '-Ibuild', 8 | '-Ibuild/wvncc@exe/', 9 | '-I/usr/include/pixman-1', 10 | '-Isubprojects/aml/include', 11 | '-Wall', 12 | '-Wextra', 13 | '-Wno-unused-parameter' 14 | ], 15 | } 16 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 - 2020 Andri Yngvason 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any purpose 4 | with or without fee is hereby granted, provided that the above copyright notice 5 | and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 8 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 9 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 10 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 11 | OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 12 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 13 | THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Wayland VNC Client 2 | 3 | ## Introduction 4 | This is a work-in-progress implementation of a Wayland native VNC client. 5 | Expect bugs and missing features. 6 | 7 | ## Runtime Dependencies 8 | * aml 9 | * libwayland 10 | * libxkbcommon 11 | * pixman 12 | 13 | ## Build Dependencies 14 | * GCC/clang 15 | * meson 16 | * ninja 17 | * pkg-config 18 | * wayland-protocols 19 | 20 | ## Building & Running 21 | ``` 22 | git clone https://github.com/any1/aml.git 23 | git clone https://github.com/any1/wlvncc.git 24 | 25 | cd wlvncc 26 | mkdir subprojects 27 | cd subprojects 28 | ln -s ../../aml . 29 | cd - 30 | 31 | meson build 32 | ninja -C build 33 | 34 | ./build/wlvncc
35 | ``` 36 | -------------------------------------------------------------------------------- /include/buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | struct wl_buffer; 25 | struct gbm_bo; 26 | 27 | enum buffer_type { 28 | BUFFER_UNSPEC = 0, 29 | BUFFER_WL_SHM, 30 | BUFFER_DMABUF, 31 | }; 32 | 33 | struct buffer { 34 | enum buffer_type type; 35 | 36 | int width, height; 37 | size_t size; 38 | uint32_t format; 39 | struct wl_buffer* wl_buffer; 40 | bool is_attached; 41 | bool please_clean_up; 42 | struct pixman_region16 damage; 43 | 44 | // wl_shm: 45 | void* pixels; 46 | int stride; 47 | 48 | // dmabuf: 49 | struct gbm_bo* bo; 50 | }; 51 | 52 | struct buffer* buffer_create_shm(int width, int height, int stride, uint32_t format); 53 | struct buffer* buffer_create_dmabuf(int width, int height, uint32_t format); 54 | void buffer_destroy(struct buffer* self); 55 | -------------------------------------------------------------------------------- /include/crypto.h: -------------------------------------------------------------------------------- 1 | #ifndef _RFB_CRYPTO_H 2 | #define _RFB_CRYPTO_H 1 3 | 4 | #include 5 | #include "config.h" 6 | 7 | #define SHA1_HASH_SIZE 20 8 | #define MD5_HASH_SIZE 16 9 | 10 | /* Generates an MD5 hash of 'in' and writes it to 'out', which must be 16 bytes in size. */ 11 | int hash_md5(void *out, const void *in, const size_t in_len); 12 | 13 | /* Generates an SHA1 hash of 'in' and writes it to 'out', which must be 20 bytes in size. */ 14 | int hash_sha1(void *out, const void *in, const size_t in_len); 15 | 16 | /* Fill 'out' with 'len' random bytes. */ 17 | void random_bytes(void *out, size_t len); 18 | 19 | /* 20 | Takes the 8-byte key in 'key', reverses the bits in each byte of key as required by the RFB protocol, 21 | encrypts 'in' with the resulting key using single-key 56-bit DES and writes the result to 'out'. 22 | */ 23 | int encrypt_rfbdes(void *out, int *out_len, const unsigned char key[8], const void *in, const size_t in_len); 24 | 25 | /* 26 | Takes the 8-byte key in 'key', reverses the bits in each byte of key as required by the RFB protocol, 27 | decrypts 'in' with the resulting key using single-key 56-bit DES and writes the result to 'out'. 28 | */ 29 | int decrypt_rfbdes(void *out, int *out_len, const unsigned char key[8], const void *in, const size_t in_len); 30 | 31 | /* Encrypts 'in' with the the 16-byte key in 'key' using AES-128-ECB and writes the result to 'out'. */ 32 | int encrypt_aes128ecb(void *out, int *out_len, const unsigned char key[16], const void *in, const size_t in_len); 33 | 34 | /* 35 | Generates a Diffie-Hellman public-private keypair using the generator value 'gen' and prime modulo 36 | 'prime', writing the result to 'pub_out' and 'priv_out', which must be 'keylen' in size. 37 | */ 38 | int dh_generate_keypair(uint8_t *priv_out, uint8_t *pub_out, const uint8_t *gen, const size_t gen_len, const uint8_t *prime, const size_t keylen); 39 | 40 | /* 41 | Computes the shared Diffie-Hellman secret using the private key 'priv', the other side's public 42 | key 'pub' and the modulo prime 'prime' and writes it to 'shared_out', which must be 'keylen' in size. 43 | */ 44 | int dh_compute_shared_key(uint8_t *shared_out, const uint8_t *priv, const uint8_t *pub, const uint8_t *prime, const size_t keylen); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /include/inhibitor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "seat.h" 5 | 6 | #include "keyboard-shortcuts-inhibit-unstable-v1.h" 7 | 8 | struct shortcuts_inhibitor { 9 | //TODO add the inhibitor toggle key to the struct ? 10 | struct zwp_keyboard_shortcuts_inhibit_manager_v1* manager; 11 | 12 | struct wl_surface* surface; 13 | struct wl_list seat_inhibitors; 14 | }; 15 | 16 | struct shortcuts_seat_inhibitor { 17 | struct wl_list link; 18 | 19 | struct seat* seat; 20 | bool active; 21 | 22 | struct zwp_keyboard_shortcuts_inhibitor_v1* inhibitor; 23 | }; 24 | 25 | struct shortcuts_inhibitor* inhibitor_new(struct zwp_keyboard_shortcuts_inhibit_manager_v1*); 26 | struct shortcuts_seat_inhibitor* seat_inhibitor_find_by_seat(struct wl_list*, struct seat*); 27 | void inhibitor_destroy(struct shortcuts_inhibitor*); 28 | bool inhibitor_init(struct shortcuts_inhibitor*, struct wl_surface*, struct wl_list*); 29 | void inhibitor_add_seat(struct shortcuts_inhibitor*, struct seat*); 30 | void inhibitor_remove_seat(struct shortcuts_inhibitor*, struct seat*); 31 | 32 | bool inhibitor_is_inhibited(struct shortcuts_inhibitor*, struct seat* seat); 33 | void inhibitor_inhibit(struct shortcuts_inhibitor*, struct seat* seat); 34 | void inhibitor_release(struct shortcuts_inhibitor*, struct seat* seat); 35 | void inhibitor_toggle(struct shortcuts_inhibitor*, struct seat* seat); 36 | -------------------------------------------------------------------------------- /include/keyboard.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 - 2024 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #define PRESSED_KEYS_MAX 256 24 | 25 | struct xkb_context; 26 | struct xkb_keymap; 27 | struct xkb_state; 28 | 29 | struct keyboard_collection; 30 | 31 | struct keyboard { 32 | struct wl_keyboard* wl_keyboard; 33 | struct wl_list link; 34 | 35 | struct seat* seat; 36 | 37 | struct xkb_context* context; 38 | struct xkb_keymap* keymap; 39 | struct xkb_state* state; 40 | 41 | struct keyboard_collection* collection; 42 | uint32_t led_state; 43 | 44 | uint32_t pressed_keys[PRESSED_KEYS_MAX]; 45 | 46 | bool waiting_for_modifiers; 47 | }; 48 | 49 | struct keyboard_collection { 50 | struct wl_list keyboards; 51 | void (*on_event)(struct keyboard_collection*, struct keyboard*, 52 | uint32_t key, bool is_pressed); 53 | void* userdata; 54 | }; 55 | 56 | struct keyboard_collection* keyboard_collection_new(void); 57 | void keyboard_collection_destroy(struct keyboard_collection*); 58 | 59 | int keyboard_collection_add_wl_keyboard(struct keyboard_collection* self, 60 | struct wl_keyboard* wl_keyboard, struct seat* seat); 61 | void keyboard_collection_remove_wl_keyboard(struct keyboard_collection* self, 62 | struct wl_keyboard* wl_keyboard); 63 | -------------------------------------------------------------------------------- /include/open-h264.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #define OPEN_H264_MAX_CONTEXTS 64 20 | 21 | #include "rfbclient.h" 22 | 23 | #include 24 | 25 | struct AVFrame; 26 | struct open_h264; 27 | struct open_h264_context; 28 | 29 | struct open_h264* open_h264_create(rfbClient* client); 30 | void open_h264_destroy(struct open_h264*); 31 | 32 | struct AVFrame* open_h264_decode_rect(struct open_h264* self, 33 | rfbFramebufferUpdateRectHeader* message); 34 | -------------------------------------------------------------------------------- /include/output.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 - 2022 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | struct output { 24 | struct wl_output* wl_output; 25 | struct wl_list link; 26 | 27 | uint32_t id; 28 | int32_t scale; 29 | bool has_surface; 30 | }; 31 | 32 | struct output* output_new(struct wl_output* wl_output, uint32_t id); 33 | void output_destroy(struct output* output); 34 | 35 | void output_list_destroy(struct wl_list* list); 36 | struct output* output_find_by_id(struct wl_list* list, uint32_t id); 37 | struct output* output_find_by_wl_output(struct wl_list* list, struct wl_output* wl_output); 38 | int32_t output_list_get_max_scale(const struct wl_list* list); 39 | 40 | -------------------------------------------------------------------------------- /include/pixels.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | enum wl_shm_format drm_format_to_wl_shm(uint32_t in); 24 | uint32_t drm_format_from_wl_shm(enum wl_shm_format in); 25 | bool drm_format_to_pixman_fmt(pixman_format_code_t* dst, uint32_t src); 26 | -------------------------------------------------------------------------------- /include/pointer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | struct wl_cursor_theme; 22 | 23 | enum pointer_cursor_type { 24 | POINTER_CURSOR_NONE = 0, 25 | POINTER_CURSOR_LEFT_PTR, 26 | }; 27 | 28 | enum pointer_button_mask { 29 | POINTER_BUTTON_LEFT = 1 << 0, 30 | POINTER_BUTTON_MIDDLE = 1 << 1, 31 | POINTER_BUTTON_RIGHT = 1 << 2, 32 | // TODO: More buttons 33 | POINTER_SCROLL_UP = 1 << 3, 34 | POINTER_SCROLL_DOWN = 1 << 4, 35 | POINTER_SCROLL_LEFT = 1 << 5, 36 | POINTER_SCROLL_RIGHT = 1 << 6, 37 | }; 38 | 39 | struct pointer { 40 | struct wl_pointer* wl_pointer; 41 | struct wl_list link; 42 | 43 | struct seat* seat; 44 | 45 | uint32_t serial; 46 | bool handle_event; 47 | enum pointer_button_mask pressed; 48 | wl_fixed_t x, y; 49 | 50 | int vertical_scroll_steps; 51 | int horizontal_scroll_steps; 52 | 53 | double vertical_axis_value; 54 | double horizontal_axis_value; 55 | 56 | struct wl_cursor_theme* cursor_theme; 57 | struct wl_surface* cursor_surface; 58 | 59 | enum pointer_cursor_type cursor_type; 60 | }; 61 | 62 | struct pointer_collection { 63 | struct wl_list pointers; 64 | void (*on_frame)(struct pointer_collection*, struct pointer*); 65 | bool (*handle_event)(struct wl_surface*); 66 | enum pointer_cursor_type cursor_type; 67 | void* userdata; 68 | }; 69 | 70 | struct pointer_collection* pointer_collection_new(enum pointer_cursor_type); 71 | void pointer_collection_destroy(struct pointer_collection*); 72 | 73 | int pointer_collection_add_wl_pointer(struct pointer_collection* self, 74 | struct wl_pointer* wl_pointer, struct seat*); 75 | void pointer_collection_remove_wl_pointer(struct pointer_collection* self, 76 | struct wl_pointer* wl_pointer); 77 | -------------------------------------------------------------------------------- /include/region.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | struct pixman_region16; 20 | 21 | void region_scale(struct pixman_region16* dst, struct pixman_region16* src, 22 | double scale); 23 | void region_translate(struct pixman_region16* dst, struct pixman_region16* src, 24 | int x, int y); 25 | -------------------------------------------------------------------------------- /include/renderer-egl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct buffer; 4 | struct image; 5 | struct vnc_av_frame; 6 | struct gbm_device; 7 | 8 | int egl_init(struct gbm_device* gbm); 9 | void egl_finish(void); 10 | 11 | void render_image_egl(struct buffer* dst, const struct image* src); 12 | void render_av_frames_egl(struct buffer* dst, struct vnc_av_frame** src, 13 | int n_av_frames); 14 | 15 | -------------------------------------------------------------------------------- /include/renderer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | struct buffer; 22 | 23 | struct image { 24 | int width, height, stride; 25 | uint32_t format; 26 | void* pixels; 27 | struct pixman_region16* damage; 28 | }; 29 | 30 | void render_image(struct buffer* dst, const struct image* src); 31 | -------------------------------------------------------------------------------- /include/sasl.h: -------------------------------------------------------------------------------- 1 | #ifndef RFBSASL_H 2 | #define RFBSASL_H 3 | 4 | /* 5 | * Copyright (C) 2017 S. Waterman. All Rights Reserved. 6 | * 7 | * This is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This software is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this software; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 20 | * USA. 21 | */ 22 | 23 | #ifdef LIBVNCSERVER_HAVE_SASL 24 | 25 | #include "rfbclient.h" 26 | 27 | /* 28 | * Perform the SASL authentication process 29 | */ 30 | rfbBool HandleSASLAuth(rfbClient *client); 31 | 32 | /* 33 | * Read from SASL when the SASL SSF is in use. 34 | */ 35 | int ReadFromSASL(rfbClient* client, char *out, unsigned int n); 36 | 37 | #endif /* LIBVNCSERVER_HAVE_SASL */ 38 | 39 | #endif /* RFBSASL_H */ 40 | -------------------------------------------------------------------------------- /include/seat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 - 2020 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | struct seat { 23 | struct wl_seat* wl_seat; 24 | struct wl_list link; 25 | 26 | uint32_t id; 27 | uint32_t capabilities; 28 | char name[256]; 29 | 30 | void (*on_capability_change)(struct seat*); 31 | void* userdata; 32 | }; 33 | 34 | struct seat* seat_new(struct wl_seat* wl_seat, uint32_t id); 35 | void seat_destroy(struct seat* self); 36 | void seat_list_destroy(struct wl_list* list); 37 | 38 | struct seat* seat_find_by_name(struct wl_list* list, const char* name); 39 | struct seat* seat_find_by_id(struct wl_list* list, uint32_t id); 40 | struct seat* seat_first(struct wl_list* list); 41 | -------------------------------------------------------------------------------- /include/shm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 - 2020 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | int shm_alloc_fd(size_t size); 22 | -------------------------------------------------------------------------------- /include/sockets.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LibVNCServer/LibVNCClient common platform socket defines and includes. 3 | * 4 | * Copyright (C) 2020 Christian Beier 5 | * 6 | * This is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This software is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this software; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 19 | * USA. 20 | */ 21 | 22 | #ifndef _RFB_COMMON_SOCKETS_H 23 | #define _RFB_COMMON_SOCKETS_H 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #endif /* _RFB_COMMON_SOCKETS_H */ 33 | -------------------------------------------------------------------------------- /include/strlcpy.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 - 2020 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | size_t strlcpy(char *dst, const char *src, size_t siz); 22 | 23 | -------------------------------------------------------------------------------- /include/threading.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LibVNCServer/LibVNCClient common platform threading defines and includes. 3 | * 4 | * Copyright (C) 2020 Christian Beier 5 | * 6 | * This is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This software is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this software; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 19 | * USA. 20 | */ 21 | 22 | #ifndef _RFB_COMMON_THREADING_H 23 | #define _RFB_COMMON_THREADING_H 24 | 25 | #include "config.h" 26 | 27 | #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD 28 | #include 29 | #if 0 /* debugging */ 30 | #define LOCK(mutex) (rfbLog("%s:%d LOCK(%s,0x%x)\n",__FILE__,__LINE__,#mutex,&(mutex)), pthread_mutex_lock(&(mutex))) 31 | #define UNLOCK(mutex) (rfbLog("%s:%d UNLOCK(%s,0x%x)\n",__FILE__,__LINE__,#mutex,&(mutex)), pthread_mutex_unlock(&(mutex))) 32 | #define MUTEX(mutex) pthread_mutex_t (mutex) 33 | #define INIT_MUTEX(mutex) (rfbLog("%s:%d INIT_MUTEX(%s,0x%x)\n",__FILE__,__LINE__,#mutex,&(mutex)), pthread_mutex_init(&(mutex),NULL)) 34 | #define TINI_MUTEX(mutex) (rfbLog("%s:%d TINI_MUTEX(%s)\n",__FILE__,__LINE__,#mutex), pthread_mutex_destroy(&(mutex))) 35 | #define TSIGNAL(cond) (rfbLog("%s:%d TSIGNAL(%s)\n",__FILE__,__LINE__,#cond), pthread_cond_signal(&(cond))) 36 | #define WAIT(cond,mutex) (rfbLog("%s:%d WAIT(%s,%s)\n",__FILE__,__LINE__,#cond,#mutex), pthread_cond_wait(&(cond),&(mutex))) 37 | #define COND(cond) pthread_cond_t (cond) 38 | #define INIT_COND(cond) (rfbLog("%s:%d INIT_COND(%s)\n",__FILE__,__LINE__,#cond), pthread_cond_init(&(cond),NULL)) 39 | #define TINI_COND(cond) (rfbLog("%s:%d TINI_COND(%s)\n",__FILE__,__LINE__,#cond), pthread_cond_destroy(&(cond))) 40 | #define IF_PTHREADS(x) x 41 | #else 42 | #if !NONETWORK 43 | #define LOCK(mutex) pthread_mutex_lock(&(mutex)) 44 | #define UNLOCK(mutex) pthread_mutex_unlock(&(mutex)) 45 | #endif 46 | #define MUTEX(mutex) pthread_mutex_t (mutex) 47 | #define MUTEX_SIZE (sizeof(pthread_mutex_t)) 48 | #define INIT_MUTEX(mutex) pthread_mutex_init(&(mutex),NULL) 49 | #define TINI_MUTEX(mutex) pthread_mutex_destroy(&(mutex)) 50 | #define TSIGNAL(cond) pthread_cond_signal(&(cond)) 51 | #define WAIT(cond,mutex) pthread_cond_wait(&(cond),&(mutex)) 52 | #define COND(cond) pthread_cond_t (cond) 53 | #define INIT_COND(cond) pthread_cond_init(&(cond),NULL) 54 | #define TINI_COND(cond) pthread_cond_destroy(&(cond)) 55 | #define IF_PTHREADS(x) x 56 | #define THREAD_ROUTINE_RETURN_TYPE void* 57 | #define THREAD_ROUTINE_RETURN_VALUE NULL 58 | #define THREAD_SLEEP_MS(ms) usleep(ms*1000) 59 | #define THREAD_JOIN(thread) pthread_join(thread, NULL) 60 | #define CURRENT_THREAD_ID pthread_self() 61 | #endif 62 | #else 63 | #define LOCK(mutex) 64 | #define UNLOCK(mutex) 65 | #define MUTEX(mutex) 66 | #define INIT_MUTEX(mutex) 67 | #define TINI_MUTEX(mutex) 68 | #define TSIGNAL(cond) 69 | #define WAIT(cond,mutex) this_is_unsupported 70 | #define COND(cond) 71 | #define INIT_COND(cond) 72 | #define TINI_COND(cond) 73 | #define IF_PTHREADS(x) 74 | #endif 75 | 76 | #endif /* _RFB_COMMON_THREADING_H */ 77 | -------------------------------------------------------------------------------- /include/time-util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 - 2020 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | static inline uint64_t timespec_to_us(const struct timespec* ts) 23 | { 24 | return (uint64_t)ts->tv_sec * UINT64_C(1000000) + 25 | (uint64_t)ts->tv_nsec / UINT64_C(1000); 26 | } 27 | 28 | static inline uint64_t timespec_to_ms(const struct timespec* ts) 29 | { 30 | return (uint64_t)ts->tv_sec * UINT64_C(1000) + 31 | (uint64_t)ts->tv_nsec / UINT64_C(1000000); 32 | } 33 | 34 | static inline uint64_t gettime_us(void) 35 | { 36 | struct timespec ts = { 0 }; 37 | clock_gettime(CLOCK_MONOTONIC, &ts); 38 | return timespec_to_us(&ts); 39 | } 40 | 41 | static inline uint64_t gettime_ms(void) 42 | { 43 | struct timespec ts = { 0 }; 44 | clock_gettime(CLOCK_MONOTONIC, &ts); 45 | return timespec_to_ms(&ts); 46 | } 47 | -------------------------------------------------------------------------------- /include/tls.h: -------------------------------------------------------------------------------- 1 | #ifndef TLS_H 2 | #define TLS_H 3 | 4 | /* 5 | * Copyright (C) 2009 Vic Lee. 6 | * 7 | * This is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This software is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this software; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 20 | * USA. 21 | */ 22 | 23 | /* Handle Anonymous TLS Authentication (18) with the server. 24 | * After authentication, client->tlsSession will be set. 25 | */ 26 | rfbBool HandleAnonTLSAuth(rfbClient* client); 27 | 28 | /* Handle VeNCrypt Authentication (19) with the server. 29 | * The callback function GetX509Credential will be called. 30 | * After authentication, client->tlsSession will be set. 31 | */ 32 | rfbBool HandleVeNCryptAuth(rfbClient* client); 33 | 34 | /* Read desired bytes from TLS session. 35 | * It's a wrapper function over gnutls_record_recv() and return values 36 | * are same as read(), that is, >0 for actual bytes read, 0 for EOF, 37 | * or EAGAIN, EINTR. 38 | * This should be a non-blocking call. Blocking is handled in sockets.c. 39 | */ 40 | int ReadFromTLS(rfbClient* client, char *out, unsigned int n); 41 | 42 | /* Write desired bytes to TLS session. 43 | * It's a wrapper function over gnutls_record_send() and it will be 44 | * blocking call, until all bytes are written or error returned. 45 | */ 46 | int WriteToTLS(rfbClient* client, const char *buf, unsigned int n); 47 | 48 | /* Free TLS resources */ 49 | void FreeTLS(rfbClient* client); 50 | 51 | #ifdef LIBVNCSERVER_HAVE_SASL 52 | /* Get the number of bits in the current cipher */ 53 | int GetTLSCipherBits(rfbClient* client); 54 | #endif /* LIBVNCSERVER_HAVE_SASL */ 55 | 56 | #endif /* TLS_H */ 57 | -------------------------------------------------------------------------------- /include/usdt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "config.h" 20 | 21 | #ifdef HAVE_USDT 22 | #include 23 | #else 24 | #define DTRACE_PROBE(...) 25 | #define DTRACE_PROBE1(...) 26 | #define DTRACE_PROBE2(...) 27 | #define DTRACE_PROBE3(...) 28 | #define DTRACE_PROBE4(...) 29 | #define DTRACE_PROBE5(...) 30 | #define DTRACE_PROBE6(...) 31 | #endif 32 | -------------------------------------------------------------------------------- /include/vnc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 - 2022 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "rfbclient.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #define VNC_CLIENT_MAX_AV_FRAMES 64 27 | 28 | struct open_h264; 29 | struct AVFrame; 30 | 31 | struct vnc_av_frame { 32 | struct AVFrame* frame; 33 | int x, y, width, height; 34 | }; 35 | 36 | struct vnc_client { 37 | rfbClient* client; 38 | 39 | struct open_h264* open_h264; 40 | bool current_rect_is_av_frame; 41 | struct vnc_av_frame* av_frames[VNC_CLIENT_MAX_AV_FRAMES]; 42 | int n_av_frames; 43 | uint64_t pts; 44 | 45 | int (*alloc_fb)(struct vnc_client*); 46 | void (*update_fb)(struct vnc_client*); 47 | void (*cut_text)(struct vnc_client*, const char*, size_t); 48 | 49 | void* userdata; 50 | struct pixman_region16 damage; 51 | 52 | bool handler_lock; 53 | bool is_updating; 54 | }; 55 | 56 | struct vnc_client* vnc_client_create(void); 57 | void vnc_client_destroy(struct vnc_client* self); 58 | 59 | int vnc_client_connect(struct vnc_client* self, const char* address, int port); 60 | int vnc_client_init(struct vnc_client* self); 61 | 62 | int vnc_client_set_pixel_format(struct vnc_client* self, uint32_t format); 63 | 64 | int vnc_client_get_fd(const struct vnc_client* self); 65 | int vnc_client_get_width(const struct vnc_client* self); 66 | int vnc_client_get_height(const struct vnc_client* self); 67 | int vnc_client_get_stride(const struct vnc_client* self); 68 | void* vnc_client_get_fb(const struct vnc_client* self); 69 | void vnc_client_set_fb(struct vnc_client* self, void* fb); 70 | const char* vnc_client_get_desktop_name(const struct vnc_client* self); 71 | int vnc_client_process(struct vnc_client* self); 72 | void vnc_client_send_pointer_event(struct vnc_client* self, int x, int y, 73 | uint32_t button_mask); 74 | void vnc_client_send_keyboard_event(struct vnc_client* self, uint32_t symbol, 75 | uint32_t code, bool is_pressed); 76 | void vnc_client_set_encodings(struct vnc_client* self, const char* encodings); 77 | void vnc_client_set_quality_level(struct vnc_client* self, int value); 78 | void vnc_client_set_compression_level(struct vnc_client* self, int value); 79 | void vnc_client_send_cut_text(struct vnc_client* self, const char* text, 80 | size_t len); 81 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'wlvncc', 3 | 'c', 4 | version: '0.1.0', 5 | license: 'ISC', 6 | default_options: [ 7 | 'c_std=gnu11', 8 | ], 9 | ) 10 | 11 | cmake = import('cmake') 12 | 13 | buildtype = get_option('buildtype') 14 | host_system = host_machine.system() 15 | prefix = get_option('prefix') 16 | 17 | c_args = [ 18 | '-D_GNU_SOURCE', 19 | '-DAML_UNSTABLE_API=1', 20 | ] 21 | 22 | if buildtype != 'debug' and buildtype != 'debugoptimized' 23 | c_args += '-DNDEBUG' 24 | endif 25 | 26 | add_project_arguments(c_args, language: 'c') 27 | 28 | cc = meson.get_compiler('c') 29 | 30 | libm = cc.find_library('m', required: false) 31 | librt = cc.find_library('rt', required: false) 32 | pthread = cc.find_library('pthread', required: false) 33 | 34 | xkbcommon = dependency('xkbcommon') 35 | pixman = dependency('pixman-1') 36 | wayland_client = dependency('wayland-client') 37 | wayland_cursor = dependency('wayland-cursor') 38 | drm = dependency('libdrm') 39 | gbm = dependency('gbm') 40 | egl = dependency('egl') 41 | glesv2 = dependency('glesv2') 42 | lavc = dependency('libavcodec') 43 | lavu = dependency('libavutil') 44 | gcrypt = dependency('libgcrypt', required: false) 45 | openssl = dependency('openssl', required: false) 46 | gnutls = dependency('gnutls', required: false) 47 | sasl = dependency('libsasl2', required: false) 48 | libjpeg = dependency('libjpeg', required: false) 49 | libpng = dependency('libpng', required: false) 50 | lzo = dependency('lzo2', required: false) 51 | libz = dependency('zlib', required: false) 52 | 53 | aml_project = subproject('aml', required: false, 54 | default_options: ['default_library=static']) 55 | if aml_project.found() 56 | aml = aml_project.get_variable('aml_dep') 57 | else 58 | aml = dependency('aml') 59 | endif 60 | 61 | inc = include_directories('include', 'src/encodings') 62 | 63 | subdir('protocols') 64 | 65 | sources = [ 66 | 'src/main.c', 67 | 'src/shm.c', 68 | 'src/seat.c', 69 | 'src/output.c', 70 | 'src/pointer.c', 71 | 'src/keyboard.c', 72 | 'src/vnc.c', 73 | 'src/strlcpy.c', 74 | 'src/evdev-to-qnum.c', 75 | 'src/pixels.c', 76 | 'src/region.c', 77 | 'src/renderer.c', 78 | 'src/renderer-egl.c', 79 | 'src/buffer.c', 80 | 'src/open-h264.c', 81 | 'src/cursor.c', 82 | 'src/rfbproto.c', 83 | 'src/sockets.c', 84 | 'src/vncviewer.c', 85 | 'src/inhibitor.c', 86 | ] 87 | 88 | dependencies = [ 89 | libm, 90 | librt, 91 | xkbcommon, 92 | pixman, 93 | aml, 94 | wayland_client, 95 | wayland_cursor, 96 | drm, 97 | gbm, 98 | egl, 99 | glesv2, 100 | lavc, 101 | lavu, 102 | client_protos, 103 | ] 104 | 105 | config = configuration_data() 106 | 107 | config.set('PREFIX', '"' + prefix + '"') 108 | 109 | if gcrypt.found() 110 | sources += 'src/crypto_libgcrypt.c' 111 | dependencies += gcrypt 112 | elif openssl.found() 113 | sources += 'src/crypto_openssl.c' 114 | dependencies += openssl 115 | else 116 | sources += 'src/crypto_included.c' 117 | endif 118 | 119 | if gnutls.found() 120 | sources += 'src/tls_gnutls.c' 121 | dependencies += gnutls 122 | config.set('LIBVNCSERVER_HAVE_GNUTLS', true) 123 | elif openssl.found() 124 | sources += 'src/tls_openssl.c' 125 | dependencies += openssl 126 | config.set('LIBVNCSERVER_HAVE_LIBSSL', true) 127 | else 128 | sources += 'src/tls_none.c' 129 | endif 130 | 131 | if sasl.found() 132 | dependencies += sasl 133 | sources += 'src/sasl.c' 134 | config.set('LIBVNCSERVER_HAVE_SASL', true) 135 | endif 136 | 137 | if libjpeg.found() 138 | sources += 'src/turbojpeg.c' 139 | dependencies += libjpeg 140 | config.set('LIBVNCSERVER_HAVE_LIBJPEG', true) 141 | endif 142 | 143 | if libpng.found() 144 | dependencies += libpng 145 | config.set('LIBVNCSERVER_HAVE_LIBPNG', true) 146 | endif 147 | 148 | if pthread.found() 149 | dependencies += pthread 150 | config.set('LIBVNCSERVER_HAVE_PTHREAD', true) 151 | endif 152 | 153 | if libz.found() 154 | dependencies += libz 155 | config.set('LIBVNCSERVER_HAVE_LIBZ', true) 156 | endif 157 | 158 | if lzo.found() 159 | dependencies += lzo 160 | config.set('LIBVNCSERVER_HAVE_LZO', true) 161 | endif 162 | 163 | if host_system == 'linux' and cc.has_header('sys/sdt.h') 164 | config.set('HAVE_USDT', true) 165 | endif 166 | 167 | configure_file( 168 | output: 'config.h', 169 | configuration: config, 170 | ) 171 | 172 | executable( 173 | 'wlvncc', 174 | sources, 175 | dependencies: dependencies, 176 | include_directories: inc, 177 | install: true, 178 | ) 179 | -------------------------------------------------------------------------------- /protocols/keyboard-shortcuts-inhibit-unstable-v1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright © 2017 Red Hat Inc. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice (including the next 15 | paragraph) shall be included in all copies or substantial portions of the 16 | Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | DEALINGS IN THE SOFTWARE. 25 | 26 | 27 | 28 | This protocol specifies a way for a client to request the compositor 29 | to ignore its own keyboard shortcuts for a given seat, so that all 30 | key events from that seat get forwarded to a surface. 31 | 32 | Warning! The protocol described in this file is experimental and 33 | backward incompatible changes may be made. Backward compatible 34 | changes may be added together with the corresponding interface 35 | version bump. 36 | Backward incompatible changes are done by bumping the version 37 | number in the protocol and interface names and resetting the 38 | interface version. Once the protocol is to be declared stable, 39 | the 'z' prefix and the version number in the protocol and 40 | interface names are removed and the interface version number is 41 | reset. 42 | 43 | 44 | 45 | 46 | A global interface used for inhibiting the compositor keyboard shortcuts. 47 | 48 | 49 | 50 | 51 | Destroy the keyboard shortcuts inhibitor manager. 52 | 53 | 54 | 55 | 56 | 57 | Create a new keyboard shortcuts inhibitor object associated with 58 | the given surface for the given seat. 59 | 60 | If shortcuts are already inhibited for the specified seat and surface, 61 | a protocol error "already_inhibited" is raised by the compositor. 62 | 63 | 64 | 66 | 68 | 69 | 70 | 71 | 74 | 75 | 76 | 77 | 78 | 79 | A keyboard shortcuts inhibitor instructs the compositor to ignore 80 | its own keyboard shortcuts when the associated surface has keyboard 81 | focus. As a result, when the surface has keyboard focus on the given 82 | seat, it will receive all key events originating from the specified 83 | seat, even those which would normally be caught by the compositor for 84 | its own shortcuts. 85 | 86 | The Wayland compositor is however under no obligation to disable 87 | all of its shortcuts, and may keep some special key combo for its own 88 | use, including but not limited to one allowing the user to forcibly 89 | restore normal keyboard events routing in the case of an unwilling 90 | client. The compositor may also use the same key combo to reactivate 91 | an existing shortcut inhibitor that was previously deactivated on 92 | user request. 93 | 94 | When the compositor restores its own keyboard shortcuts, an 95 | "inactive" event is emitted to notify the client that the keyboard 96 | shortcuts inhibitor is not effectively active for the surface and 97 | seat any more, and the client should not expect to receive all 98 | keyboard events. 99 | 100 | When the keyboard shortcuts inhibitor is inactive, the client has 101 | no way to forcibly reactivate the keyboard shortcuts inhibitor. 102 | 103 | The user can chose to re-enable a previously deactivated keyboard 104 | shortcuts inhibitor using any mechanism the compositor may offer, 105 | in which case the compositor will send an "active" event to notify 106 | the client. 107 | 108 | If the surface is destroyed, unmapped, or loses the seat's keyboard 109 | focus, the keyboard shortcuts inhibitor becomes irrelevant and the 110 | compositor will restore its own keyboard shortcuts but no "inactive" 111 | event is emitted in this case. 112 | 113 | 114 | 115 | 116 | Remove the keyboard shortcuts inhibitor from the associated wl_surface. 117 | 118 | 119 | 120 | 121 | 122 | This event indicates that the shortcut inhibitor is active. 123 | 124 | The compositor sends this event every time compositor shortcuts 125 | are inhibited on behalf of the surface. When active, the client 126 | may receive input events normally reserved by the compositor 127 | (see zwp_keyboard_shortcuts_inhibitor_v1). 128 | 129 | This occurs typically when the initial request "inhibit_shortcuts" 130 | first becomes active or when the user instructs the compositor to 131 | re-enable and existing shortcuts inhibitor using any mechanism 132 | offered by the compositor. 133 | 134 | 135 | 136 | 137 | 138 | This event indicates that the shortcuts inhibitor is inactive, 139 | normal shortcuts processing is restored by the compositor. 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /protocols/meson.build: -------------------------------------------------------------------------------- 1 | wayland_scanner = find_program('wayland-scanner') 2 | wayland_client = dependency('wayland-client') 3 | 4 | wayland_scanner_code = generator( 5 | wayland_scanner, 6 | output: '@BASENAME@.c', 7 | arguments: ['private-code', '@INPUT@', '@OUTPUT@'], 8 | ) 9 | 10 | wayland_scanner_client = generator( 11 | wayland_scanner, 12 | output: '@BASENAME@.h', 13 | arguments: ['client-header', '@INPUT@', '@OUTPUT@'], 14 | ) 15 | 16 | client_protocols = [ 17 | 'xdg-shell.xml', 18 | 'linux-dmabuf-v1.xml', 19 | 'keyboard-shortcuts-inhibit-unstable-v1.xml', 20 | 'viewporter-v1.xml', 21 | 'single-pixel-buffer-v1.xml', 22 | ] 23 | 24 | client_protos_src = [] 25 | client_protos_headers = [] 26 | 27 | foreach xml: client_protocols 28 | client_protos_src += wayland_scanner_code.process(xml) 29 | client_protos_headers += wayland_scanner_client.process(xml) 30 | endforeach 31 | 32 | lib_client_protos = static_library( 33 | 'client_protos', 34 | client_protos_src + client_protos_headers, 35 | dependencies: [ 36 | wayland_client 37 | ] 38 | ) 39 | 40 | client_protos = declare_dependency( 41 | link_with: lib_client_protos, 42 | sources: client_protos_headers, 43 | ) 44 | -------------------------------------------------------------------------------- /protocols/single-pixel-buffer-v1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Copyright © 2022 Simon Ser 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the "Software"), 8 | to deal in the Software without restriction, including without limitation 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice (including the next 14 | paragraph) shall be included in all copies or substantial portions of the 15 | Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | 25 | 26 | 27 | This protocol extension allows clients to create single-pixel buffers. 28 | 29 | Compositors supporting this protocol extension should also support the 30 | viewporter protocol extension. Clients may use viewporter to scale a 31 | single-pixel buffer to a desired size. 32 | 33 | Warning! The protocol described in this file is currently in the testing 34 | phase. Backward compatible changes may be added together with the 35 | corresponding interface version bump. Backward incompatible changes can 36 | only be done by creating a new major version of the extension. 37 | 38 | 39 | 40 | 41 | The wp_single_pixel_buffer_manager_v1 interface is a factory for 42 | single-pixel buffers. 43 | 44 | 45 | 46 | 47 | Destroy the wp_single_pixel_buffer_manager_v1 object. 48 | 49 | The child objects created via this interface are unaffected. 50 | 51 | 52 | 53 | 54 | 55 | Create a single-pixel buffer from four 32-bit RGBA values. 56 | 57 | Unless specified in another protocol extension, the RGBA values use 58 | pre-multiplied alpha. 59 | 60 | The width and height of the buffer are 1. 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /protocols/viewporter-v1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright © 2013-2016 Collabora, Ltd. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice (including the next 15 | paragraph) shall be included in all copies or substantial portions of the 16 | Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | DEALINGS IN THE SOFTWARE. 25 | 26 | 27 | 28 | 29 | The global interface exposing surface cropping and scaling 30 | capabilities is used to instantiate an interface extension for a 31 | wl_surface object. This extended interface will then allow 32 | cropping and scaling the surface contents, effectively 33 | disconnecting the direct relationship between the buffer and the 34 | surface size. 35 | 36 | 37 | 38 | 39 | Informs the server that the client will not be using this 40 | protocol object anymore. This does not affect any other objects, 41 | wp_viewport objects included. 42 | 43 | 44 | 45 | 46 | 48 | 49 | 50 | 51 | 52 | Instantiate an interface extension for the given wl_surface to 53 | crop and scale its content. If the given wl_surface already has 54 | a wp_viewport object associated, the viewport_exists 55 | protocol error is raised. 56 | 57 | 59 | 61 | 62 | 63 | 64 | 65 | 66 | An additional interface to a wl_surface object, which allows the 67 | client to specify the cropping and scaling of the surface 68 | contents. 69 | 70 | This interface works with two concepts: the source rectangle (src_x, 71 | src_y, src_width, src_height), and the destination size (dst_width, 72 | dst_height). The contents of the source rectangle are scaled to the 73 | destination size, and content outside the source rectangle is ignored. 74 | This state is double-buffered, see wl_surface.commit. 75 | 76 | The two parts of crop and scale state are independent: the source 77 | rectangle, and the destination size. Initially both are unset, that 78 | is, no scaling is applied. The whole of the current wl_buffer is 79 | used as the source, and the surface size is as defined in 80 | wl_surface.attach. 81 | 82 | If the destination size is set, it causes the surface size to become 83 | dst_width, dst_height. The source (rectangle) is scaled to exactly 84 | this size. This overrides whatever the attached wl_buffer size is, 85 | unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface 86 | has no content and therefore no size. Otherwise, the size is always 87 | at least 1x1 in surface local coordinates. 88 | 89 | If the source rectangle is set, it defines what area of the wl_buffer is 90 | taken as the source. If the source rectangle is set and the destination 91 | size is not set, then src_width and src_height must be integers, and the 92 | surface size becomes the source rectangle size. This results in cropping 93 | without scaling. If src_width or src_height are not integers and 94 | destination size is not set, the bad_size protocol error is raised when 95 | the surface state is applied. 96 | 97 | The coordinate transformations from buffer pixel coordinates up to 98 | the surface-local coordinates happen in the following order: 99 | 1. buffer_transform (wl_surface.set_buffer_transform) 100 | 2. buffer_scale (wl_surface.set_buffer_scale) 101 | 3. crop and scale (wp_viewport.set*) 102 | This means, that the source rectangle coordinates of crop and scale 103 | are given in the coordinates after the buffer transform and scale, 104 | i.e. in the coordinates that would be the surface-local coordinates 105 | if the crop and scale was not applied. 106 | 107 | If src_x or src_y are negative, the bad_value protocol error is raised. 108 | Otherwise, if the source rectangle is partially or completely outside of 109 | the non-NULL wl_buffer, then the out_of_buffer protocol error is raised 110 | when the surface state is applied. A NULL wl_buffer does not raise the 111 | out_of_buffer error. 112 | 113 | If the wl_surface associated with the wp_viewport is destroyed, 114 | all wp_viewport requests except 'destroy' raise the protocol error 115 | no_surface. 116 | 117 | If the wp_viewport object is destroyed, the crop and scale 118 | state is removed from the wl_surface. The change will be applied 119 | on the next wl_surface.commit. 120 | 121 | 122 | 123 | 124 | The associated wl_surface's crop and scale state is removed. 125 | The change is applied on the next wl_surface.commit. 126 | 127 | 128 | 129 | 130 | 132 | 134 | 136 | 138 | 139 | 140 | 141 | 142 | Set the source rectangle of the associated wl_surface. See 143 | wp_viewport for the description, and relation to the wl_buffer 144 | size. 145 | 146 | If all of x, y, width and height are -1.0, the source rectangle is 147 | unset instead. Any other set of values where width or height are zero 148 | or negative, or x or y are negative, raise the bad_value protocol 149 | error. 150 | 151 | The crop and scale state is double-buffered, see wl_surface.commit. 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | Set the destination size of the associated wl_surface. See 162 | wp_viewport for the description, and relation to the wl_buffer 163 | size. 164 | 165 | If width is -1 and height is -1, the destination size is unset 166 | instead. Any other pair of values for width and height that 167 | contains zero or negative values raises the bad_value protocol 168 | error. 169 | 170 | The crop and scale state is double-buffered, see wl_surface.commit. 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /scripts/auth-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This is an example script that displays a pop-up dialogue for user 4 | # authentication. 5 | # It can be enabled via the --auth-command option. E.g. 6 | # wlvncc --auth-command=$HOME/projects/wlvncc/scripts/auth-script.h my-vnc-server.local 7 | 8 | ENTRY=$(zenity --password --username) 9 | 10 | case $? in 11 | 0) 12 | echo "$ENTRY" | tr '|' "\n" 13 | ;; 14 | 1) 15 | echo "Stop login." &>2 16 | ;; 17 | -1) 18 | echo "An unexpected error has occurred." &>2 19 | ;; 20 | esac 21 | -------------------------------------------------------------------------------- /src/buffer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "buffer.h" 18 | #include "shm.h" 19 | #include "pixels.h" 20 | #include "linux-dmabuf-v1.h" 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | /* Origin: main.c */ 29 | extern struct wl_shm* wl_shm; 30 | extern struct gbm_device* gbm_device; 31 | extern struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1; 32 | 33 | static void buffer_release(void* data, struct wl_buffer* wl_buffer) 34 | { 35 | (void)wl_buffer; 36 | struct buffer* self = data; 37 | self->is_attached = false; 38 | 39 | if (self->please_clean_up) { 40 | buffer_destroy(self); 41 | } 42 | } 43 | 44 | static const struct wl_buffer_listener buffer_listener = { 45 | .release = buffer_release, 46 | }; 47 | 48 | struct buffer* buffer_create_shm(int width, int height, int stride, 49 | uint32_t format) 50 | { 51 | assert(wl_shm); 52 | 53 | struct buffer* self = calloc(1, sizeof(*self)); 54 | if (!self) 55 | return NULL; 56 | 57 | self->type = BUFFER_WL_SHM; 58 | self->width = width; 59 | self->height = height; 60 | self->stride = stride; 61 | self->format = format; 62 | 63 | pixman_region_init_rect(&self->damage, 0, 0, width, height); 64 | 65 | self->size = height * stride; 66 | int fd = shm_alloc_fd(self->size); 67 | if (fd < 0) 68 | goto failure; 69 | 70 | self->pixels = mmap(NULL, self->size, PROT_READ | PROT_WRITE, 71 | MAP_SHARED, fd, 0); 72 | if (!self->pixels) 73 | goto mmap_failure; 74 | 75 | struct wl_shm_pool* pool = wl_shm_create_pool(wl_shm, fd, self->size); 76 | if (!pool) 77 | goto pool_failure; 78 | 79 | self->wl_buffer = wl_shm_pool_create_buffer(pool, 0, width, height, 80 | stride, drm_format_to_wl_shm(format)); 81 | wl_shm_pool_destroy(pool); 82 | if (!self->wl_buffer) 83 | goto shm_failure; 84 | 85 | close(fd); 86 | 87 | wl_buffer_add_listener(self->wl_buffer, &buffer_listener, self); 88 | 89 | return self; 90 | 91 | shm_failure: 92 | pool_failure: 93 | munmap(self->pixels, self->size); 94 | mmap_failure: 95 | close(fd); 96 | failure: 97 | free(self); 98 | return NULL; 99 | } 100 | 101 | struct buffer* buffer_create_dmabuf(int width, int height, uint32_t format) 102 | { 103 | assert(gbm_device && zwp_linux_dmabuf_v1); 104 | 105 | struct buffer* self = calloc(1, sizeof(*self)); 106 | if (!self) 107 | return NULL; 108 | 109 | self->type = BUFFER_DMABUF; 110 | self->width = width; 111 | self->height = height; 112 | self->format = format; 113 | 114 | pixman_region_init_rect(&self->damage, 0, 0, width, height); 115 | 116 | self->bo = gbm_bo_create(gbm_device, width, height, format, 117 | GBM_BO_USE_RENDERING); 118 | if (!self->bo) 119 | goto bo_failure; 120 | 121 | struct zwp_linux_buffer_params_v1* params; 122 | params = zwp_linux_dmabuf_v1_create_params(zwp_linux_dmabuf_v1); 123 | if (!params) 124 | goto params_failure; 125 | 126 | uint32_t offset = gbm_bo_get_offset(self->bo, 0); 127 | uint32_t stride = gbm_bo_get_stride(self->bo); 128 | uint64_t mod = gbm_bo_get_modifier(self->bo); 129 | int fd = gbm_bo_get_fd(self->bo); 130 | if (fd < 0) 131 | goto fd_failure; 132 | 133 | zwp_linux_buffer_params_v1_add(params, fd, 0, offset, stride, 134 | mod >> 32, mod & 0xffffffff); 135 | self->wl_buffer = zwp_linux_buffer_params_v1_create_immed(params, width, 136 | height, format, /* flags */ 0); 137 | zwp_linux_buffer_params_v1_destroy(params); 138 | close(fd); 139 | 140 | if (!self->wl_buffer) 141 | goto buffer_failure; 142 | 143 | wl_buffer_add_listener(self->wl_buffer, &buffer_listener, self); 144 | 145 | return self; 146 | 147 | buffer_failure: 148 | fd_failure: 149 | zwp_linux_buffer_params_v1_destroy(params); 150 | params_failure: 151 | gbm_bo_destroy(self->bo); 152 | bo_failure: 153 | free(self); 154 | return NULL; 155 | } 156 | 157 | void buffer_destroy(struct buffer* self) 158 | { 159 | if (!self) 160 | return; 161 | 162 | if (self->is_attached) 163 | self->please_clean_up = true; 164 | 165 | pixman_region_fini(&self->damage); 166 | wl_buffer_destroy(self->wl_buffer); 167 | 168 | switch (self->type) { 169 | case BUFFER_WL_SHM: 170 | munmap(self->pixels, self->size); 171 | break; 172 | case BUFFER_DMABUF: 173 | gbm_bo_destroy(self->bo); 174 | break; 175 | default: 176 | abort(); 177 | break; 178 | } 179 | 180 | free(self); 181 | } 182 | -------------------------------------------------------------------------------- /src/crypto_included.c: -------------------------------------------------------------------------------- 1 | /* 2 | * crypto_included.c - Crypto wrapper (included version) 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2011 Gernot Tenchio 7 | * Copyright (C) 2019 Christian Beier 8 | * 9 | * This is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This software is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this software; if not, write to the Free Software 21 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 22 | * USA. 23 | */ 24 | 25 | #include 26 | #include "sha.h" 27 | #include "d3des.h" 28 | #include "crypto.h" 29 | 30 | 31 | int hash_md5(void *out, const void *in, const size_t in_len) 32 | { 33 | return 0; 34 | } 35 | 36 | int hash_sha1(void *out, const void *in, const size_t in_len) 37 | { 38 | SHA1Context sha1; 39 | if(SHA1Reset(&sha1) != shaSuccess) 40 | return 0; 41 | if(SHA1Input(&sha1, in, in_len) != shaSuccess) 42 | return 0; 43 | if(SHA1Result(&sha1, out) != shaSuccess) 44 | return 0; 45 | 46 | return 1; 47 | } 48 | 49 | void random_bytes(void *out, size_t len) 50 | { 51 | 52 | } 53 | 54 | int encrypt_rfbdes(void *out, int *out_len, const unsigned char key[8], const void *in, const size_t in_len) 55 | { 56 | int eightbyteblocks = in_len/8; 57 | int i; 58 | rfbDesKey((unsigned char*)key, EN0); 59 | for(i = 0; i < eightbyteblocks; ++i) 60 | rfbDes((unsigned char*)in + i*8, (unsigned char*)out + i*8); 61 | 62 | *out_len = in_len; 63 | 64 | return 1; 65 | } 66 | 67 | int decrypt_rfbdes(void *out, int *out_len, const unsigned char key[8], const void *in, const size_t in_len) 68 | { 69 | int eightbyteblocks = in_len/8; 70 | int i; 71 | rfbDesKey((unsigned char*)key, DE1); 72 | for(i = 0; i < eightbyteblocks; ++i) 73 | rfbDes((unsigned char*)in + i*8, (unsigned char*)out + i*8); 74 | 75 | *out_len = in_len; 76 | 77 | return 1; 78 | } 79 | 80 | int encrypt_aes128ecb(void *out, int *out_len, const unsigned char key[16], const void *in, const size_t in_len) 81 | { 82 | return 0; 83 | } 84 | 85 | int dh_generate_keypair(uint8_t *priv_out, uint8_t *pub_out, const uint8_t *gen, const size_t gen_len, const uint8_t *prime, const size_t keylen) 86 | { 87 | return 0; 88 | } 89 | 90 | int dh_compute_shared_key(uint8_t *shared_out, const uint8_t *priv, const uint8_t *pub, const uint8_t *prime, const size_t keylen) 91 | { 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /src/crypto_libgcrypt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * crypto_gnutls.c - Crypto wrapper (libgcrypt version) 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2011 Gernot Tenchio 7 | * Copyright (C) 2019 Christian Beier 8 | * 9 | * This is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This software is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this software; if not, write to the Free Software 21 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 22 | * USA. 23 | */ 24 | 25 | #include 26 | #include 27 | #include "crypto.h" 28 | 29 | static int mpiToBytes(const gcry_mpi_t value, uint8_t *result, size_t size) 30 | { 31 | gcry_error_t error; 32 | size_t len; 33 | int i; 34 | 35 | error = gcry_mpi_print(GCRYMPI_FMT_USG, result, size, &len, value); 36 | if (gcry_err_code(error) != GPG_ERR_NO_ERROR) 37 | return 0; 38 | for (i=size-1;i>(int)size-1-(int)len;--i) 39 | result[i] = result[i-size+len]; 40 | for (;i>=0;--i) 41 | result[i] = 0; 42 | return 1; 43 | } 44 | 45 | static unsigned char reverseByte(unsigned char b) { 46 | b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; 47 | b = (b & 0xCC) >> 2 | (b & 0x33) << 2; 48 | b = (b & 0xAA) >> 1 | (b & 0x55) << 1; 49 | return b; 50 | } 51 | 52 | int hash_md5(void *out, const void *in, const size_t in_len) 53 | { 54 | int result = 0; 55 | gcry_error_t error; 56 | gcry_md_hd_t md5 = NULL; 57 | void *digest; 58 | 59 | error = gcry_md_open(&md5, GCRY_MD_MD5, 0); 60 | if (gcry_err_code(error) != GPG_ERR_NO_ERROR) 61 | goto out; 62 | 63 | gcry_md_write(md5, in, in_len); 64 | 65 | if(!(digest = gcry_md_read(md5, GCRY_MD_MD5))) 66 | goto out; 67 | 68 | memcpy(out, digest, gcry_md_get_algo_dlen(GCRY_MD_MD5)); 69 | 70 | result = 1; 71 | 72 | out: 73 | gcry_md_close(md5); 74 | return result; 75 | } 76 | 77 | int hash_sha1(void *out, const void *in, const size_t in_len) 78 | { 79 | int result = 0; 80 | gcry_error_t error; 81 | gcry_md_hd_t sha1 = NULL; 82 | void *digest; 83 | 84 | error = gcry_md_open(&sha1, GCRY_MD_SHA1, 0); 85 | if (gcry_err_code(error) != GPG_ERR_NO_ERROR) 86 | goto out; 87 | 88 | gcry_md_write(sha1, in, in_len); 89 | 90 | if(!(digest = gcry_md_read(sha1, GCRY_MD_SHA1))) 91 | goto out; 92 | 93 | memcpy(out, digest, gcry_md_get_algo_dlen(GCRY_MD_SHA1)); 94 | 95 | result = 1; 96 | 97 | out: 98 | gcry_md_close(sha1); 99 | return result; 100 | } 101 | 102 | void random_bytes(void *out, size_t len) 103 | { 104 | gcry_randomize(out, len, GCRY_STRONG_RANDOM); 105 | } 106 | 107 | int encrypt_rfbdes(void *out, int *out_len, const unsigned char key[8], const void *in, const size_t in_len) 108 | { 109 | int result = 0; 110 | gcry_error_t error; 111 | gcry_cipher_hd_t des = NULL; 112 | unsigned char mungedkey[8]; 113 | int i; 114 | 115 | for (i = 0; i < 8; i++) 116 | mungedkey[i] = reverseByte(key[i]); 117 | 118 | error = gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); 119 | if (gcry_err_code(error) != GPG_ERR_NO_ERROR) 120 | goto out; 121 | 122 | error = gcry_cipher_setkey(des, mungedkey, 8); 123 | if (gcry_err_code(error) != GPG_ERR_NO_ERROR) 124 | goto out; 125 | 126 | error = gcry_cipher_encrypt(des, out, in_len, in, in_len); 127 | if (gcry_err_code(error) != GPG_ERR_NO_ERROR) 128 | goto out; 129 | 130 | *out_len = in_len; 131 | 132 | result = 1; 133 | 134 | out: 135 | gcry_cipher_close(des); 136 | return result; 137 | } 138 | 139 | int decrypt_rfbdes(void *out, int *out_len, const unsigned char key[8], const void *in, const size_t in_len) 140 | { 141 | int result = 0; 142 | gcry_error_t error; 143 | gcry_cipher_hd_t des = NULL; 144 | unsigned char mungedkey[8]; 145 | int i; 146 | 147 | for (i = 0; i < 8; i++) 148 | mungedkey[i] = reverseByte(key[i]); 149 | 150 | error = gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); 151 | if (gcry_err_code(error) != GPG_ERR_NO_ERROR) 152 | goto out; 153 | 154 | error = gcry_cipher_setkey(des, mungedkey, 8); 155 | if (gcry_err_code(error) != GPG_ERR_NO_ERROR) 156 | goto out; 157 | 158 | error = gcry_cipher_decrypt(des, out, in_len, in, in_len); 159 | if (gcry_err_code(error) != GPG_ERR_NO_ERROR) 160 | goto out; 161 | 162 | *out_len = in_len; 163 | 164 | result = 1; 165 | 166 | out: 167 | gcry_cipher_close(des); 168 | return result; 169 | } 170 | 171 | 172 | int encrypt_aes128ecb(void *out, int *out_len, const unsigned char key[16], const void *in, const size_t in_len) 173 | { 174 | int result = 0; 175 | gcry_error_t error; 176 | gcry_cipher_hd_t aes = NULL; 177 | 178 | error = gcry_cipher_open(&aes, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0); 179 | if (gcry_err_code(error) != GPG_ERR_NO_ERROR) 180 | goto out; 181 | 182 | error = gcry_cipher_setkey(aes, key, 16); 183 | if (gcry_err_code(error) != GPG_ERR_NO_ERROR) 184 | goto out; 185 | 186 | error = gcry_cipher_encrypt(aes, out, in_len, in, in_len); 187 | if (gcry_err_code(error) != GPG_ERR_NO_ERROR) 188 | goto out; 189 | *out_len = in_len; 190 | 191 | result = 1; 192 | 193 | out: 194 | gcry_cipher_close(aes); 195 | return result; 196 | } 197 | 198 | int dh_generate_keypair(uint8_t *priv_out, uint8_t *pub_out, const uint8_t *gen, const size_t gen_len, const uint8_t *prime, const size_t keylen) 199 | { 200 | int result = 0; 201 | gcry_error_t error; 202 | gcry_mpi_t genmpi = NULL, modmpi = NULL, privmpi = NULL, pubmpi = NULL; 203 | 204 | error = gcry_mpi_scan(&genmpi, GCRYMPI_FMT_USG, gen, gen_len, NULL); 205 | if (gcry_err_code(error) != GPG_ERR_NO_ERROR) 206 | goto out; 207 | error = gcry_mpi_scan(&modmpi, GCRYMPI_FMT_USG, prime, keylen, NULL); 208 | if (gcry_err_code(error) != GPG_ERR_NO_ERROR) 209 | goto out; 210 | 211 | privmpi = gcry_mpi_new(keylen); 212 | if (!privmpi) 213 | goto out; 214 | gcry_mpi_randomize(privmpi, (keylen/8)*8, GCRY_STRONG_RANDOM); 215 | 216 | pubmpi = gcry_mpi_new(keylen); 217 | if (!pubmpi) 218 | goto out; 219 | 220 | gcry_mpi_powm(pubmpi, genmpi, privmpi, modmpi); 221 | 222 | if (!mpiToBytes(pubmpi, pub_out, keylen)) 223 | goto out; 224 | if (!mpiToBytes(privmpi, priv_out, keylen)) 225 | goto out; 226 | 227 | result = 1; 228 | 229 | out: 230 | gcry_mpi_release(genmpi); 231 | gcry_mpi_release(modmpi); 232 | gcry_mpi_release(privmpi); 233 | gcry_mpi_release(pubmpi); 234 | return result; 235 | } 236 | 237 | int dh_compute_shared_key(uint8_t *shared_out, const uint8_t *priv, const uint8_t *pub, const uint8_t *prime, const size_t keylen) 238 | { 239 | int result = 1; 240 | gcry_error_t error; 241 | gcry_mpi_t keympi = NULL, modmpi = NULL, privmpi = NULL, pubmpi = NULL; 242 | 243 | error = gcry_mpi_scan(&privmpi, GCRYMPI_FMT_USG, priv, keylen, NULL); 244 | if (gcry_err_code(error) != GPG_ERR_NO_ERROR) 245 | goto out; 246 | error = gcry_mpi_scan(&pubmpi, GCRYMPI_FMT_USG, pub, keylen, NULL); 247 | if (gcry_err_code(error) != GPG_ERR_NO_ERROR) 248 | goto out; 249 | error = gcry_mpi_scan(&modmpi, GCRYMPI_FMT_USG, prime, keylen, NULL); 250 | if (gcry_err_code(error) != GPG_ERR_NO_ERROR) 251 | goto out; 252 | 253 | keympi = gcry_mpi_new(keylen); 254 | if (!keympi) 255 | goto out; 256 | 257 | gcry_mpi_powm(keympi, pubmpi, privmpi, modmpi); 258 | 259 | if (!mpiToBytes(keympi, shared_out, keylen)) 260 | goto out; 261 | 262 | result = 1; 263 | 264 | out: 265 | gcry_mpi_release(keympi); 266 | gcry_mpi_release(modmpi); 267 | gcry_mpi_release(privmpi); 268 | gcry_mpi_release(pubmpi); 269 | 270 | return result; 271 | } 272 | -------------------------------------------------------------------------------- /src/crypto_openssl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * crypto_openssl.c - Crypto wrapper (openssl version) 3 | */ 4 | 5 | /* 6 | * Copyright (C) 2011 Gernot Tenchio 7 | * Copyright (C) 2019 Christian Beier 8 | * 9 | * This is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This software is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this software; if not, write to the Free Software 21 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 22 | * USA. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "crypto.h" 32 | 33 | static unsigned char reverseByte(unsigned char b) { 34 | b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; 35 | b = (b & 0xCC) >> 2 | (b & 0x33) << 2; 36 | b = (b & 0xAA) >> 1 | (b & 0x55) << 1; 37 | return b; 38 | } 39 | 40 | int hash_md5(void *out, const void *in, const size_t in_len) 41 | { 42 | MD5_CTX md5; 43 | if(!MD5_Init(&md5)) 44 | return 0; 45 | if(!MD5_Update(&md5, in, in_len)) 46 | return 0; 47 | if(!MD5_Final(out, &md5)) 48 | return 0; 49 | return 1; 50 | } 51 | 52 | int hash_sha1(void *out, const void *in, const size_t in_len) 53 | { 54 | SHA_CTX sha1; 55 | if(!SHA1_Init(&sha1)) 56 | return 0; 57 | if(!SHA1_Update(&sha1, in, in_len)) 58 | return 0; 59 | if(!SHA1_Final(out, &sha1)) 60 | return 0; 61 | return 1; 62 | } 63 | 64 | void random_bytes(void *out, size_t len) 65 | { 66 | RAND_bytes(out, len); 67 | } 68 | 69 | int encrypt_rfbdes(void *out, int *out_len, const unsigned char key[8], const void *in, const size_t in_len) 70 | { 71 | int result = 0; 72 | EVP_CIPHER_CTX *des; 73 | unsigned char mungedkey[8]; 74 | int i; 75 | 76 | for (i = 0; i < 8; i++) 77 | mungedkey[i] = reverseByte(key[i]); 78 | 79 | if(!(des = EVP_CIPHER_CTX_new())) 80 | goto out; 81 | if(!EVP_EncryptInit_ex(des, EVP_des_ecb(), NULL, mungedkey, NULL)) 82 | goto out; 83 | if(!EVP_EncryptUpdate(des, out, out_len, in, in_len)) 84 | goto out; 85 | 86 | result = 1; 87 | 88 | out: 89 | EVP_CIPHER_CTX_free(des); 90 | return result; 91 | } 92 | 93 | int decrypt_rfbdes(void *out, int *out_len, const unsigned char key[8], const void *in, const size_t in_len) 94 | { 95 | int result = 0; 96 | EVP_CIPHER_CTX *des; 97 | unsigned char mungedkey[8]; 98 | int i; 99 | 100 | for (i = 0; i < 8; i++) 101 | mungedkey[i] = reverseByte(key[i]); 102 | 103 | if(!(des = EVP_CIPHER_CTX_new())) 104 | goto out; 105 | if(!EVP_DecryptInit_ex(des, EVP_des_ecb(), NULL, mungedkey, NULL)) 106 | goto out; 107 | if(!EVP_DecryptUpdate(des, out, out_len, in, in_len)) 108 | goto out; 109 | 110 | result = 1; 111 | 112 | out: 113 | EVP_CIPHER_CTX_free(des); 114 | return result; 115 | } 116 | 117 | int encrypt_aes128ecb(void *out, int *out_len, const unsigned char key[16], const void *in, const size_t in_len) 118 | { 119 | int result = 0; 120 | EVP_CIPHER_CTX *aes; 121 | 122 | if(!(aes = EVP_CIPHER_CTX_new())) 123 | goto out; 124 | EVP_CIPHER_CTX_set_padding(aes, 0); 125 | if(!EVP_EncryptInit_ex(aes, EVP_aes_128_ecb(), NULL, key, NULL)) 126 | goto out; 127 | if(!EVP_EncryptUpdate(aes, out, out_len, in, in_len)) 128 | goto out; 129 | 130 | result = 1; 131 | 132 | out: 133 | EVP_CIPHER_CTX_free(aes); 134 | return result; 135 | } 136 | 137 | int dh_generate_keypair(uint8_t *priv_out, uint8_t *pub_out, const uint8_t *gen, const size_t gen_len, const uint8_t *prime, const size_t keylen) 138 | { 139 | int result = 0; 140 | DH *dh; 141 | #if OPENSSL_VERSION_NUMBER >= 0x10100000L || \ 142 | (defined (LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x30500000) 143 | const BIGNUM *pub_key = NULL; 144 | const BIGNUM *priv_key = NULL; 145 | #endif 146 | 147 | if(!(dh = DH_new())) 148 | goto out; 149 | #if OPENSSL_VERSION_NUMBER < 0x10100000L || \ 150 | (defined (LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x30500000) 151 | dh->p = BN_bin2bn(prime, keylen, NULL); 152 | dh->g = BN_bin2bn(gen, gen_len, NULL); 153 | #else 154 | if(!DH_set0_pqg(dh, BN_bin2bn(prime, keylen, NULL), NULL, BN_bin2bn(gen, gen_len, NULL))) 155 | goto out; 156 | #endif 157 | if(!DH_generate_key(dh)) 158 | goto out; 159 | #if OPENSSL_VERSION_NUMBER < 0x10100000L || \ 160 | (defined (LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x30500000) 161 | if(BN_bn2bin(dh->priv_key, priv_out) == 0) 162 | goto out; 163 | if(BN_bn2bin(dh->pub_key, pub_out) == 0) 164 | goto out; 165 | #else 166 | DH_get0_key(dh, &pub_key, &priv_key); 167 | if(BN_bn2binpad(priv_key, priv_out, keylen) == -1) 168 | goto out; 169 | if(BN_bn2binpad(pub_key, pub_out, keylen) == -1) 170 | goto out; 171 | #endif 172 | 173 | result = 1; 174 | 175 | out: 176 | DH_free(dh); 177 | return result; 178 | } 179 | 180 | int dh_compute_shared_key(uint8_t *shared_out, const uint8_t *priv, const uint8_t *pub, const uint8_t *prime, const size_t keylen) 181 | { 182 | int result = 0; 183 | DH *dh; 184 | 185 | if(!(dh = DH_new())) 186 | goto out; 187 | #if OPENSSL_VERSION_NUMBER < 0x10100000L || \ 188 | (defined LIBRESSL_VERSION_NUMBER && LIBRESSL_VERSION_NUMBER < 0x30500000) 189 | dh->p = BN_bin2bn(prime, keylen, NULL); 190 | dh->priv_key = BN_bin2bn(priv, keylen, NULL); 191 | #else 192 | if(!DH_set0_pqg(dh, BN_bin2bn(prime, keylen, NULL), NULL, BN_new())) 193 | goto out; 194 | if(!DH_set0_key(dh, NULL, BN_bin2bn(priv, keylen, NULL))) 195 | goto out; 196 | #endif 197 | if(DH_compute_key(shared_out, BN_bin2bn(pub, keylen, NULL), dh) == -1) 198 | goto out; 199 | 200 | result = 1; 201 | 202 | out: 203 | DH_free(dh); 204 | return result; 205 | } 206 | -------------------------------------------------------------------------------- /src/cursor.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2001,2002 Constantin Kaplinsky. All Rights Reserved. 3 | * 4 | * This is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This software is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this software; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 17 | * USA. 18 | */ 19 | 20 | /* 21 | * cursor.c - code to support cursor shape updates (XCursor and 22 | * RichCursor preudo-encodings). 23 | */ 24 | 25 | #include "rfbclient.h" 26 | 27 | #define OPER_SAVE 0 28 | #define OPER_RESTORE 1 29 | 30 | #define MAX_CURSOR_SIZE 1024 31 | 32 | #define RGB24_TO_PIXEL(bpp,r,g,b) \ 33 | ((((uint##bpp##_t)(r) & 0xFF) * client->format.redMax + 127) / 255 \ 34 | << client->format.redShift | \ 35 | (((uint##bpp##_t)(g) & 0xFF) * client->format.greenMax + 127) / 255 \ 36 | << client->format.greenShift | \ 37 | (((uint##bpp##_t)(b) & 0xFF) * client->format.blueMax + 127) / 255 \ 38 | << client->format.blueShift) 39 | 40 | 41 | rfbBool HandleCursorShape(rfbClient* client,int xhot, int yhot, int width, int height, uint32_t enc) 42 | { 43 | int bytesPerPixel; 44 | size_t bytesPerRow, bytesMaskData; 45 | rfbXCursorColors rgb; 46 | uint32_t colors[2]; 47 | char *buf; 48 | uint8_t *ptr; 49 | int x, y, b; 50 | 51 | bytesPerPixel = client->format.bitsPerPixel / 8; 52 | bytesPerRow = (width + 7) / 8; 53 | bytesMaskData = bytesPerRow * height; 54 | 55 | if (width * height == 0) 56 | return TRUE; 57 | 58 | if (width >= MAX_CURSOR_SIZE || height >= MAX_CURSOR_SIZE) 59 | return FALSE; 60 | 61 | /* Allocate memory for pixel data and temporary mask data. */ 62 | if(client->rcSource) 63 | free(client->rcSource); 64 | 65 | client->rcSource = malloc((size_t)width * height * bytesPerPixel); 66 | if (client->rcSource == NULL) 67 | return FALSE; 68 | 69 | buf = malloc(bytesMaskData); 70 | if (buf == NULL) { 71 | free(client->rcSource); 72 | client->rcSource = NULL; 73 | return FALSE; 74 | } 75 | 76 | /* Read and decode cursor pixel data, depending on the encoding type. */ 77 | 78 | if (enc == rfbEncodingXCursor) { 79 | /* Read and convert background and foreground colors. */ 80 | if (!ReadFromRFBServer(client, (char *)&rgb, sz_rfbXCursorColors)) { 81 | free(client->rcSource); 82 | client->rcSource = NULL; 83 | free(buf); 84 | return FALSE; 85 | } 86 | colors[0] = RGB24_TO_PIXEL(32, rgb.backRed, rgb.backGreen, rgb.backBlue); 87 | colors[1] = RGB24_TO_PIXEL(32, rgb.foreRed, rgb.foreGreen, rgb.foreBlue); 88 | 89 | /* Read 1bpp pixel data into a temporary buffer. */ 90 | if (!ReadFromRFBServer(client, buf, bytesMaskData)) { 91 | free(client->rcSource); 92 | client->rcSource = NULL; 93 | free(buf); 94 | return FALSE; 95 | } 96 | 97 | /* Convert 1bpp data to byte-wide color indices. */ 98 | ptr = client->rcSource; 99 | for (y = 0; y < height; y++) { 100 | for (x = 0; x < width / 8; x++) { 101 | for (b = 7; b >= 0; b--) { 102 | *ptr = buf[y * bytesPerRow + x] >> b & 1; 103 | ptr += bytesPerPixel; 104 | } 105 | } 106 | for (b = 7; b > 7 - width % 8; b--) { 107 | *ptr = buf[y * bytesPerRow + x] >> b & 1; 108 | ptr += bytesPerPixel; 109 | } 110 | } 111 | 112 | /* Convert indices into the actual pixel values. */ 113 | switch (bytesPerPixel) { 114 | case 1: 115 | for (x = 0; x < width * height; x++) 116 | client->rcSource[x] = (uint8_t)colors[client->rcSource[x]]; 117 | break; 118 | case 2: 119 | for (x = 0; x < width * height; x++) 120 | ((uint16_t *)client->rcSource)[x] = (uint16_t)colors[client->rcSource[x * 2]]; 121 | break; 122 | case 4: 123 | for (x = 0; x < width * height; x++) 124 | ((uint32_t *)client->rcSource)[x] = colors[client->rcSource[x * 4]]; 125 | break; 126 | } 127 | 128 | } else { /* enc == rfbEncodingRichCursor */ 129 | 130 | if (!ReadFromRFBServer(client, (char *)client->rcSource, width * height * bytesPerPixel)) { 131 | free(client->rcSource); 132 | client->rcSource = NULL; 133 | free(buf); 134 | return FALSE; 135 | } 136 | 137 | } 138 | 139 | /* Read and decode mask data. */ 140 | 141 | if (!ReadFromRFBServer(client, buf, bytesMaskData)) { 142 | free(client->rcSource); 143 | client->rcSource = NULL; 144 | free(buf); 145 | return FALSE; 146 | } 147 | 148 | client->rcMask = malloc((size_t)width * height); 149 | if (client->rcMask == NULL) { 150 | free(client->rcSource); 151 | client->rcSource = NULL; 152 | free(buf); 153 | return FALSE; 154 | } 155 | 156 | ptr = client->rcMask; 157 | for (y = 0; y < height; y++) { 158 | for (x = 0; x < width / 8; x++) { 159 | for (b = 7; b >= 0; b--) { 160 | *ptr++ = buf[y * bytesPerRow + x] >> b & 1; 161 | } 162 | } 163 | for (b = 7; b > 7 - width % 8; b--) { 164 | *ptr++ = buf[y * bytesPerRow + x] >> b & 1; 165 | } 166 | } 167 | 168 | if (client->GotCursorShape != NULL) { 169 | client->GotCursorShape(client, xhot, yhot, width, height, bytesPerPixel); 170 | } 171 | 172 | free(buf); 173 | 174 | return TRUE; 175 | } 176 | 177 | 178 | -------------------------------------------------------------------------------- /src/encodings/corre.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 3 | * 4 | * This is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This software is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this software; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 17 | * USA. 18 | */ 19 | 20 | /* 21 | * corre.c - handle CoRRE encoding. 22 | * 23 | * This file shouldn't be compiled directly. It is included multiple times by 24 | * rfbproto.c, each time with a different definition of the macro BPP. For 25 | * each value of BPP, this file defines a function which handles a CoRRE 26 | * encoded rectangle with BPP bits per pixel. 27 | */ 28 | 29 | #define HandleCoRREBPP CONCAT2E(HandleCoRRE,BPP) 30 | #define CARDBPP CONCAT3E(uint,BPP,_t) 31 | 32 | static rfbBool 33 | HandleCoRREBPP (rfbClient* client, int rx, int ry, int rw, int rh) 34 | { 35 | rfbRREHeader hdr; 36 | int i; 37 | CARDBPP pix; 38 | uint8_t *ptr; 39 | int x, y, w, h; 40 | 41 | if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbRREHeader)) 42 | return FALSE; 43 | 44 | hdr.nSubrects = rfbClientSwap32IfLE(hdr.nSubrects); 45 | 46 | if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix))) 47 | return FALSE; 48 | 49 | client->GotFillRect(client, rx, ry, rw, rh, pix); 50 | 51 | if (hdr.nSubrects > RFB_BUFFER_SIZE / (4 + (BPP / 8)) || !ReadFromRFBServer(client, client->buffer, hdr.nSubrects * (4 + (BPP / 8)))) 52 | return FALSE; 53 | 54 | ptr = (uint8_t *)client->buffer; 55 | 56 | for (i = 0; i < hdr.nSubrects; i++) { 57 | pix = *(CARDBPP *)ptr; 58 | ptr += BPP/8; 59 | x = *ptr++; 60 | y = *ptr++; 61 | w = *ptr++; 62 | h = *ptr++; 63 | 64 | client->GotFillRect(client, rx+x, ry+y, w, h, pix); 65 | } 66 | 67 | return TRUE; 68 | } 69 | 70 | #undef CARDBPP 71 | -------------------------------------------------------------------------------- /src/encodings/hextile.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 3 | * 4 | * This is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This software is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this software; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 17 | * USA. 18 | */ 19 | 20 | /* 21 | * hextile.c - handle hextile encoding. 22 | * 23 | * This file shouldn't be compiled directly. It is included multiple times by 24 | * rfbproto.c, each time with a different definition of the macro BPP. For 25 | * each value of BPP, this file defines a function which handles a hextile 26 | * encoded rectangle with BPP bits per pixel. 27 | */ 28 | 29 | #define HandleHextileBPP CONCAT2E(HandleHextile,BPP) 30 | #define CARDBPP CONCAT3E(uint,BPP,_t) 31 | 32 | static rfbBool 33 | HandleHextileBPP (rfbClient* client, int rx, int ry, int rw, int rh) 34 | { 35 | CARDBPP bg = 0, fg; 36 | int i; 37 | uint8_t *ptr; 38 | int x, y, w, h; 39 | int sx, sy, sw, sh; 40 | uint8_t subencoding; 41 | uint8_t nSubrects; 42 | 43 | for (y = ry; y < ry+rh; y += 16) { 44 | for (x = rx; x < rx+rw; x += 16) { 45 | w = h = 16; 46 | if (rx+rw - x < 16) 47 | w = rx+rw - x; 48 | if (ry+rh - y < 16) 49 | h = ry+rh - y; 50 | 51 | if (!ReadFromRFBServer(client, (char *)&subencoding, 1)) 52 | return FALSE; 53 | 54 | if (subencoding & rfbHextileRaw) { 55 | if (!ReadFromRFBServer(client, client->buffer, w * h * (BPP / 8))) 56 | return FALSE; 57 | 58 | client->GotBitmap(client, (uint8_t *)client->buffer, x, y, w, h); 59 | 60 | continue; 61 | } 62 | 63 | if (subencoding & rfbHextileBackgroundSpecified) 64 | if (!ReadFromRFBServer(client, (char *)&bg, sizeof(bg))) 65 | return FALSE; 66 | 67 | client->GotFillRect(client, x, y, w, h, bg); 68 | 69 | if (subencoding & rfbHextileForegroundSpecified) 70 | if (!ReadFromRFBServer(client, (char *)&fg, sizeof(fg))) 71 | return FALSE; 72 | 73 | if (!(subencoding & rfbHextileAnySubrects)) { 74 | continue; 75 | } 76 | 77 | if (!ReadFromRFBServer(client, (char *)&nSubrects, 1)) 78 | return FALSE; 79 | 80 | ptr = (uint8_t*)client->buffer; 81 | 82 | if (subencoding & rfbHextileSubrectsColoured) { 83 | if (!ReadFromRFBServer(client, client->buffer, nSubrects * (2 + (BPP / 8)))) 84 | return FALSE; 85 | 86 | for (i = 0; i < nSubrects; i++) { 87 | #if BPP==8 88 | GET_PIXEL8(fg, ptr); 89 | #elif BPP==16 90 | GET_PIXEL16(fg, ptr); 91 | #elif BPP==32 92 | GET_PIXEL32(fg, ptr); 93 | #else 94 | #error "Invalid BPP" 95 | #endif 96 | sx = rfbHextileExtractX(*ptr); 97 | sy = rfbHextileExtractY(*ptr); 98 | ptr++; 99 | sw = rfbHextileExtractW(*ptr); 100 | sh = rfbHextileExtractH(*ptr); 101 | ptr++; 102 | 103 | client->GotFillRect(client, x+sx, y+sy, sw, sh, fg); 104 | } 105 | 106 | } else { 107 | if (!ReadFromRFBServer(client, client->buffer, nSubrects * 2)) 108 | return FALSE; 109 | 110 | for (i = 0; i < nSubrects; i++) { 111 | sx = rfbHextileExtractX(*ptr); 112 | sy = rfbHextileExtractY(*ptr); 113 | ptr++; 114 | sw = rfbHextileExtractW(*ptr); 115 | sh = rfbHextileExtractH(*ptr); 116 | ptr++; 117 | 118 | client->GotFillRect(client, x+sx, y+sy, sw, sh, fg); 119 | } 120 | } 121 | } 122 | } 123 | 124 | return TRUE; 125 | } 126 | 127 | #undef CARDBPP 128 | -------------------------------------------------------------------------------- /src/encodings/rre.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 3 | * 4 | * This is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This software is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this software; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 17 | * USA. 18 | */ 19 | 20 | /* 21 | * rre.c - handle RRE encoding. 22 | * 23 | * This file shouldn't be compiled directly. It is included multiple times by 24 | * rfbproto.c, each time with a different definition of the macro BPP. For 25 | * each value of BPP, this file defines a function which handles an RRE 26 | * encoded rectangle with BPP bits per pixel. 27 | */ 28 | 29 | #define HandleRREBPP CONCAT2E(HandleRRE,BPP) 30 | #define CARDBPP CONCAT3E(uint,BPP,_t) 31 | 32 | static rfbBool 33 | HandleRREBPP (rfbClient* client, int rx, int ry, int rw, int rh) 34 | { 35 | rfbRREHeader hdr; 36 | int i; 37 | CARDBPP pix; 38 | rfbRectangle subrect; 39 | 40 | if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbRREHeader)) 41 | return FALSE; 42 | 43 | hdr.nSubrects = rfbClientSwap32IfLE(hdr.nSubrects); 44 | 45 | if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix))) 46 | return FALSE; 47 | 48 | client->GotFillRect(client, rx, ry, rw, rh, pix); 49 | 50 | for (i = 0; i < hdr.nSubrects; i++) { 51 | if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix))) 52 | return FALSE; 53 | 54 | if (!ReadFromRFBServer(client, (char *)&subrect, sz_rfbRectangle)) 55 | return FALSE; 56 | 57 | subrect.x = rfbClientSwap16IfLE(subrect.x); 58 | subrect.y = rfbClientSwap16IfLE(subrect.y); 59 | subrect.w = rfbClientSwap16IfLE(subrect.w); 60 | subrect.h = rfbClientSwap16IfLE(subrect.h); 61 | 62 | client->GotFillRect(client, rx+subrect.x, ry+subrect.y, subrect.w, subrect.h, pix); 63 | } 64 | 65 | return TRUE; 66 | } 67 | 68 | #undef CARDBPP 69 | -------------------------------------------------------------------------------- /src/encodings/trle.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Wiki Wang . All Rights Reserved. 3 | * 4 | * This is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This software is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this software; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 17 | * USA. 18 | */ 19 | 20 | /* 21 | * trle.c - handle trle encoding. 22 | * 23 | * This file shouldn't be compiled directly. It is included multiple times by 24 | * rfbproto.c, each time with a different definition of the macro BPP. For 25 | * each value of BPP, this file defines a function which handles a trle 26 | * encoded rectangle with BPP bits per pixel. 27 | */ 28 | 29 | #ifndef REALBPP 30 | #define REALBPP BPP 31 | #endif 32 | 33 | #if !defined(UNCOMP) || UNCOMP == 0 34 | #define HandleTRLE CONCAT2E(HandleTRLE, REALBPP) 35 | #elif UNCOMP > 0 36 | #define HandleTRLE CONCAT3E(HandleTRLE, REALBPP, Down) 37 | #else 38 | #define HandleTRLE CONCAT3E(HandleTRLE, REALBPP, Up) 39 | #endif 40 | #define CARDBPP CONCAT3E(uint, BPP, _t) 41 | #define CARDREALBPP CONCAT3E(uint, REALBPP, _t) 42 | 43 | #if REALBPP != BPP && defined(UNCOMP) && UNCOMP != 0 44 | #if UNCOMP > 0 45 | #define UncompressCPixel(pointer) ((*(CARDBPP *)pointer) >> UNCOMP) 46 | #else 47 | #define UncompressCPixel(pointer) ((*(CARDBPP *)pointer) << (-(UNCOMP))) 48 | #endif 49 | #else 50 | #define UncompressCPixel(pointer) (*(CARDBPP *)pointer) 51 | #endif 52 | 53 | static rfbBool HandleTRLE(rfbClient *client, int rx, int ry, int rw, int rh) { 54 | int x, y, w, h; 55 | uint8_t type, last_type = 0; 56 | int min_buffer_size = 16 * 16 * (REALBPP / 8) * 2; 57 | uint8_t *buffer; 58 | CARDBPP palette[128]; 59 | int bpp = 0, mask = 0, divider = 0; 60 | CARDBPP color = 0; 61 | 62 | /* First make sure we have a large enough raw buffer to hold the 63 | * decompressed data. In practice, with a fixed REALBPP, fixed frame 64 | * buffer size and the first update containing the entire frame 65 | * buffer, this buffer allocation should only happen once, on the 66 | * first update. 67 | */ 68 | if (client->raw_buffer_size < min_buffer_size) { 69 | 70 | if (client->raw_buffer != NULL) { 71 | 72 | free(client->raw_buffer); 73 | } 74 | 75 | client->raw_buffer_size = min_buffer_size; 76 | client->raw_buffer = (char *)malloc(client->raw_buffer_size); 77 | } 78 | 79 | rfbClientLog("Update %d %d %d %d\n", rx, ry, rw, rh); 80 | 81 | for (y = ry; y < ry + rh; y += 16) { 82 | for (x = rx; x < rx + rw; x += 16) { 83 | w = h = 16; 84 | if (rx + rw - x < 16) 85 | w = rx + rw - x; 86 | if (ry + rh - y < 16) 87 | h = ry + rh - y; 88 | 89 | if (!ReadFromRFBServer(client, (char *)(&type), 1)) 90 | return FALSE; 91 | 92 | buffer = (uint8_t*)(client->raw_buffer); 93 | 94 | switch (type) { 95 | case 0: { 96 | if (!ReadFromRFBServer(client, (char *)buffer, w * h * REALBPP / 8)) 97 | return FALSE; 98 | #if REALBPP != BPP 99 | int i, j; 100 | 101 | for (j = y * client->width; j < (y + h) * client->width; 102 | j += client->width) 103 | for (i = x; i < x + w; i++, buffer += REALBPP / 8) 104 | ((CARDBPP *)client->frameBuffer)[j + i] = UncompressCPixel(buffer); 105 | #else 106 | client->GotBitmap(client, buffer, x, y, w, h); 107 | #endif 108 | type = last_type; 109 | break; 110 | } 111 | case 1: { 112 | if (!ReadFromRFBServer(client, (char *)buffer, REALBPP / 8)) 113 | return FALSE; 114 | 115 | color = UncompressCPixel(buffer); 116 | 117 | client->GotFillRect(client, x, y, w, h, color); 118 | 119 | last_type = type; 120 | break; 121 | } 122 | case_127: 123 | case 127: 124 | switch (last_type) { 125 | case 0: 126 | return FALSE; 127 | case 1: 128 | client->GotFillRect(client, x, y, w, h, color); 129 | type = last_type; 130 | break; 131 | case 128: 132 | return FALSE; 133 | default: 134 | if (last_type >= 130) { 135 | last_type = last_type & 0x7f; 136 | 137 | bpp = (last_type > 4 ? (last_type > 16 ? 8 : 4) 138 | : (last_type > 2 ? 2 : 1)), 139 | mask = (1 << bpp) - 1, divider = (8 / bpp); 140 | } 141 | if (last_type <= 16) { 142 | int i, j, shift; 143 | 144 | if (!ReadFromRFBServer(client, (char*)buffer, 145 | (w + divider - 1) / divider * h)) 146 | return FALSE; 147 | 148 | /* read palettized pixels */ 149 | for (j = y * client->width; j < (y + h) * client->width; 150 | j += client->width) { 151 | for (i = x, shift = 8 - bpp; i < x + w; i++) { 152 | ((CARDBPP *)client->frameBuffer)[j + i] = 153 | palette[((*buffer) >> shift) & mask]; 154 | shift -= bpp; 155 | if (shift < 0) { 156 | shift = 8 - bpp; 157 | buffer++; 158 | } 159 | } 160 | if (shift < 8 - bpp) 161 | buffer++; 162 | 163 | type = last_type; 164 | } 165 | } else 166 | return FALSE; 167 | } 168 | break; 169 | case 128: { 170 | int i = 0, j = 0; 171 | while (j < h) { 172 | int color, length, buffer_pos = 0; 173 | /* read color */ 174 | if (!ReadFromRFBServer(client, (char*)buffer, REALBPP / 8 + 1)) 175 | return FALSE; 176 | color = UncompressCPixel(buffer); 177 | buffer += REALBPP / 8; 178 | buffer_pos += REALBPP / 8; 179 | /* read run length */ 180 | length = 1; 181 | while (*buffer == 0xff && buffer_pos < client->raw_buffer_size-1) { 182 | if (!ReadFromRFBServer(client, (char*)buffer + 1, 1)) 183 | return FALSE; 184 | length += *buffer; 185 | buffer++; 186 | buffer_pos++; 187 | } 188 | length += *buffer; 189 | buffer++; 190 | while (j < h && length > 0) { 191 | ((CARDBPP *)client->frameBuffer)[(y + j) * client->width + x + i] = 192 | color; 193 | length--; 194 | i++; 195 | if (i >= w) { 196 | i = 0; 197 | j++; 198 | } 199 | } 200 | if (length > 0) 201 | rfbClientLog("Warning: possible TRLE corruption\n"); 202 | } 203 | 204 | type = last_type; 205 | 206 | break; 207 | } 208 | case_129: 209 | case 129: { 210 | int i, j; 211 | /* read palettized pixels */ 212 | i = j = 0; 213 | while (j < h) { 214 | int color, length, buffer_pos = 0; 215 | /* read color */ 216 | if (!ReadFromRFBServer(client, (char *)buffer, 1)) 217 | return FALSE; 218 | color = palette[(*buffer) & 0x7f]; 219 | length = 1; 220 | if (*buffer & 0x80) { 221 | if (!ReadFromRFBServer(client, (char *)buffer + 1, 1)) 222 | return FALSE; 223 | buffer++; 224 | buffer_pos++; 225 | /* read run length */ 226 | while (*buffer == 0xff && buffer_pos < client->raw_buffer_size-1) { 227 | if (!ReadFromRFBServer(client, (char *)buffer + 1, 1)) 228 | return FALSE; 229 | length += *buffer; 230 | buffer++; 231 | buffer_pos++; 232 | } 233 | length += *buffer; 234 | } 235 | buffer++; 236 | while (j < h && length > 0) { 237 | ((CARDBPP *)client->frameBuffer)[(y + j) * client->width + x + i] = 238 | color; 239 | length--; 240 | i++; 241 | if (i >= w) { 242 | i = 0; 243 | j++; 244 | } 245 | } 246 | if (length > 0) 247 | rfbClientLog("Warning: possible TRLE corruption\n"); 248 | } 249 | 250 | if (type == 129) { 251 | type = last_type; 252 | } 253 | 254 | break; 255 | } 256 | default: 257 | if (type <= 16) { 258 | int i; 259 | 260 | bpp = (type > 4 ? 4 : (type > 2 ? 2 : 1)), 261 | mask = (1 << bpp) - 1, divider = (8 / bpp); 262 | 263 | if (!ReadFromRFBServer(client, (char *)buffer, type * REALBPP / 8)) 264 | return FALSE; 265 | 266 | /* read palette */ 267 | for (i = 0; i < type; i++, buffer += REALBPP / 8) 268 | palette[i] = UncompressCPixel(buffer); 269 | 270 | last_type = type; 271 | goto case_127; 272 | } else if (type >= 130) { 273 | int i; 274 | 275 | if (!ReadFromRFBServer(client, (char *)buffer, (type - 128) * REALBPP / 8)) 276 | return FALSE; 277 | 278 | /* read palette */ 279 | for (i = 0; i < type - 128; i++, buffer += REALBPP / 8) 280 | palette[i] = UncompressCPixel(buffer); 281 | 282 | last_type = type; 283 | goto case_129; 284 | } else 285 | return FALSE; 286 | } 287 | last_type = type; 288 | } 289 | } 290 | 291 | return TRUE; 292 | } 293 | 294 | #undef CARDBPP 295 | #undef CARDREALBPP 296 | #undef HandleTRLE 297 | #undef UncompressCPixel 298 | #undef REALBPP 299 | #undef UNCOMP 300 | -------------------------------------------------------------------------------- /src/encodings/ultra.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. 3 | * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 18 | * USA. 19 | */ 20 | 21 | /* 22 | * ultrazip.c - handle ultrazip encoding. 23 | * 24 | * This file shouldn't be compiled directly. It is included multiple times by 25 | * rfbproto.c, each time with a different definition of the macro BPP. For 26 | * each value of BPP, this file defines a function which handles an zlib 27 | * encoded rectangle with BPP bits per pixel. 28 | */ 29 | 30 | #define HandleUltraZipBPP CONCAT2E(HandleUltraZip,BPP) 31 | #define HandleUltraBPP CONCAT2E(HandleUltra,BPP) 32 | #define CARDBPP CONCAT3E(uint,BPP,_t) 33 | 34 | static rfbBool 35 | HandleUltraBPP (rfbClient* client, int rx, int ry, int rw, int rh) 36 | { 37 | rfbZlibHeader hdr; 38 | int toRead=0; 39 | int inflateResult=0; 40 | lzo_uint uncompressedBytes = (( rw * rh ) * ( BPP / 8 )); 41 | 42 | if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbZlibHeader)) 43 | return FALSE; 44 | 45 | toRead = rfbClientSwap32IfLE(hdr.nBytes); 46 | if (toRead==0) return TRUE; 47 | 48 | if (toRead < 0) { 49 | rfbClientErr("ultra error: remote sent negative payload size\n"); 50 | return FALSE; 51 | } 52 | 53 | if (uncompressedBytes==0) 54 | { 55 | rfbClientLog("ultra error: rectangle has 0 uncomressed bytes ((%dw * %dh) * (%d / 8))\n", rw, rh, BPP); 56 | return FALSE; 57 | } 58 | 59 | /* First make sure we have a large enough raw buffer to hold the 60 | * decompressed data. In practice, with a fixed BPP, fixed frame 61 | * buffer size and the first update containing the entire frame 62 | * buffer, this buffer allocation should only happen once, on the 63 | * first update. 64 | */ 65 | if ( client->raw_buffer_size < (int)uncompressedBytes) { 66 | if ( client->raw_buffer != NULL ) { 67 | free( client->raw_buffer ); 68 | } 69 | client->raw_buffer_size = uncompressedBytes; 70 | /* buffer needs to be aligned on 4-byte boundaries */ 71 | if ((client->raw_buffer_size % 4)!=0) 72 | client->raw_buffer_size += (4-(client->raw_buffer_size % 4)); 73 | client->raw_buffer = (char*) malloc( client->raw_buffer_size ); 74 | if(client->raw_buffer == NULL) 75 | return FALSE; 76 | } 77 | 78 | /* allocate enough space to store the incoming compressed packet */ 79 | if ( client->ultra_buffer_size < toRead ) { 80 | if ( client->ultra_buffer != NULL ) { 81 | free( client->ultra_buffer ); 82 | } 83 | client->ultra_buffer_size = toRead; 84 | /* buffer needs to be aligned on 4-byte boundaries */ 85 | if ((client->ultra_buffer_size % 4)!=0) 86 | client->ultra_buffer_size += (4-(client->ultra_buffer_size % 4)); 87 | client->ultra_buffer = (char*) malloc( client->ultra_buffer_size ); 88 | } 89 | 90 | /* Fill the buffer, obtaining data from the server. */ 91 | if (!ReadFromRFBServer(client, client->ultra_buffer, toRead)) 92 | return FALSE; 93 | 94 | /* uncompress the data */ 95 | uncompressedBytes = client->raw_buffer_size; 96 | inflateResult = lzo1x_decompress_safe( 97 | (lzo_byte *)client->ultra_buffer, toRead, 98 | (lzo_byte *)client->raw_buffer, (lzo_uintp) &uncompressedBytes, 99 | NULL); 100 | 101 | /* Note that uncompressedBytes will be 0 on output overrun */ 102 | if ((rw * rh * (BPP / 8)) != uncompressedBytes) 103 | rfbClientLog("Ultra decompressed unexpected amount of data (%d != %d)\n", (rw * rh * (BPP / 8)), uncompressedBytes); 104 | 105 | /* Put the uncompressed contents of the update on the screen. */ 106 | if ( inflateResult == LZO_E_OK ) 107 | { 108 | client->GotBitmap(client, (unsigned char *)client->raw_buffer, rx, ry, rw, rh); 109 | } 110 | else 111 | { 112 | rfbClientLog("ultra decompress returned error: %d\n", 113 | inflateResult); 114 | return FALSE; 115 | } 116 | return TRUE; 117 | } 118 | 119 | 120 | /* UltraZip is like rre in that it is composed of subrects */ 121 | static rfbBool 122 | HandleUltraZipBPP (rfbClient* client, int rx, int ry, int rw, int rh) 123 | { 124 | rfbZlibHeader hdr; 125 | int i=0; 126 | int toRead=0; 127 | int inflateResult=0; 128 | unsigned char *ptr=NULL; 129 | lzo_uint uncompressedBytes = ry + (rw * 65535); 130 | unsigned int numCacheRects = rx; 131 | 132 | if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbZlibHeader)) 133 | return FALSE; 134 | 135 | toRead = rfbClientSwap32IfLE(hdr.nBytes); 136 | 137 | if (toRead==0) return TRUE; 138 | 139 | if (toRead < 0) { 140 | rfbClientErr("ultrazip error: remote sent negative payload size\n"); 141 | return FALSE; 142 | } 143 | 144 | if (uncompressedBytes==0) 145 | { 146 | rfbClientLog("ultrazip error: rectangle has 0 uncomressed bytes (%dy + (%dw * 65535)) (%d rectangles)\n", ry, rw, rx); 147 | return FALSE; 148 | } 149 | 150 | /* First make sure we have a large enough raw buffer to hold the 151 | * decompressed data. In practice, with a fixed BPP, fixed frame 152 | * buffer size and the first update containing the entire frame 153 | * buffer, this buffer allocation should only happen once, on the 154 | * first update. 155 | */ 156 | if ( client->raw_buffer_size < (int)(uncompressedBytes + 500)) { 157 | if ( client->raw_buffer != NULL ) { 158 | free( client->raw_buffer ); 159 | } 160 | client->raw_buffer_size = uncompressedBytes + 500; 161 | /* buffer needs to be aligned on 4-byte boundaries */ 162 | if ((client->raw_buffer_size % 4)!=0) 163 | client->raw_buffer_size += (4-(client->raw_buffer_size % 4)); 164 | client->raw_buffer = (char*) malloc( client->raw_buffer_size ); 165 | if(client->raw_buffer == NULL) 166 | return FALSE; 167 | } 168 | 169 | 170 | /* allocate enough space to store the incoming compressed packet */ 171 | if ( client->ultra_buffer_size < toRead ) { 172 | if ( client->ultra_buffer != NULL ) { 173 | free( client->ultra_buffer ); 174 | } 175 | client->ultra_buffer_size = toRead; 176 | client->ultra_buffer = (char*) malloc( client->ultra_buffer_size ); 177 | } 178 | 179 | /* Fill the buffer, obtaining data from the server. */ 180 | if (!ReadFromRFBServer(client, client->ultra_buffer, toRead)) 181 | return FALSE; 182 | 183 | /* uncompress the data */ 184 | uncompressedBytes = client->raw_buffer_size; 185 | inflateResult = lzo1x_decompress_safe( 186 | (lzo_byte *)client->ultra_buffer, toRead, 187 | (lzo_byte *)client->raw_buffer, &uncompressedBytes, NULL); 188 | if ( inflateResult != LZO_E_OK ) 189 | { 190 | rfbClientLog("ultra decompress returned error: %d\n", 191 | inflateResult); 192 | return FALSE; 193 | } 194 | 195 | /* Put the uncompressed contents of the update on the screen. */ 196 | ptr = (unsigned char *)client->raw_buffer; 197 | for (i=0; iGotBitmap(client, (unsigned char *)ptr, sx, sy, sw, sh); 217 | ptr += ((sw * sh) * (BPP / 8)); 218 | } 219 | } 220 | 221 | return TRUE; 222 | } 223 | 224 | #undef CARDBPP 225 | -------------------------------------------------------------------------------- /src/encodings/vncauth.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 3 | * 4 | * This is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This software is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 17 | * USA. 18 | */ 19 | 20 | /* 21 | * vncauth.c - Functions for VNC password management and authentication. 22 | */ 23 | 24 | #include "rfbproto.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "crypto.h" 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | #include 37 | 38 | #include 39 | 40 | /* libvncclient does not need this */ 41 | #ifndef rfbEncryptBytes 42 | 43 | /* 44 | * We use a fixed key to store passwords, since we assume that our local 45 | * file system is secure but nonetheless don't want to store passwords 46 | * as plaintext. 47 | */ 48 | 49 | static unsigned char fixedkey[8] = {23,82,107,6,35,78,88,7}; 50 | 51 | 52 | /* 53 | * Encrypt a password and store it in a file. Returns 0 if successful, 54 | * 1 if the file could not be written. 55 | */ 56 | 57 | int 58 | rfbEncryptAndStorePasswd(char *passwd, char *fname) 59 | { 60 | FILE *fp; 61 | unsigned int i; 62 | unsigned char encryptedPasswd[8]; 63 | int out_len; 64 | 65 | if ((fp = fopen(fname,"w")) == NULL) return 1; 66 | 67 | fchmod(fileno(fp), S_IRUSR|S_IWUSR); 68 | 69 | /* pad password with nulls */ 70 | 71 | for (i = 0; i < 8; i++) { 72 | if (i < strlen(passwd)) { 73 | encryptedPasswd[i] = passwd[i]; 74 | } else { 75 | encryptedPasswd[i] = 0; 76 | } 77 | } 78 | 79 | /* Do encryption in-place - this way we overwrite our copy of the plaintext 80 | password */ 81 | encrypt_rfbdes(encryptedPasswd, &out_len, fixedkey, encryptedPasswd, sizeof(encryptedPasswd)); 82 | 83 | for (i = 0; i < 8; i++) { 84 | putc(encryptedPasswd[i], fp); 85 | } 86 | 87 | fclose(fp); 88 | return 0; 89 | } 90 | 91 | 92 | /* 93 | * Decrypt a password from a file. Returns a pointer to a newly allocated 94 | * string containing the password or a null pointer if the password could 95 | * not be retrieved for some reason. 96 | */ 97 | 98 | char * 99 | rfbDecryptPasswdFromFile(char *fname) 100 | { 101 | FILE *fp; 102 | int i, ch; 103 | unsigned char *passwd = (unsigned char *)malloc(9); 104 | int out_len; 105 | 106 | if (!passwd || (fp = fopen(fname,"r")) == NULL) { 107 | free(passwd); 108 | return NULL; 109 | } 110 | 111 | for (i = 0; i < 8; i++) { 112 | ch = getc(fp); 113 | if (ch == EOF) { 114 | fclose(fp); 115 | free(passwd); 116 | return NULL; 117 | } 118 | passwd[i] = ch; 119 | } 120 | 121 | fclose(fp); 122 | 123 | if(!decrypt_rfbdes(passwd, &out_len, fixedkey, passwd, 8)) 124 | return NULL; 125 | 126 | passwd[8] = 0; 127 | 128 | return (char *)passwd; 129 | } 130 | 131 | 132 | /* 133 | * Generate CHALLENGESIZE random bytes for use in challenge-response 134 | * authentication. 135 | */ 136 | 137 | void 138 | rfbRandomBytes(unsigned char *bytes) 139 | { 140 | int i; 141 | static rfbBool s_srandom_called = FALSE; 142 | 143 | if (!s_srandom_called) { 144 | srandom((unsigned int)time(NULL) ^ (unsigned int)getpid()); 145 | s_srandom_called = TRUE; 146 | } 147 | 148 | for (i = 0; i < CHALLENGESIZE; i++) { 149 | bytes[i] = (unsigned char)(random() & 255); 150 | } 151 | } 152 | 153 | #endif 154 | 155 | /* 156 | * Encrypt CHALLENGESIZE bytes in memory using a password. 157 | */ 158 | 159 | void 160 | rfbEncryptBytes(unsigned char *bytes, char *passwd) 161 | { 162 | unsigned char key[8]; 163 | unsigned int i; 164 | int out_len; 165 | 166 | /* key is simply password padded with nulls */ 167 | 168 | for (i = 0; i < 8; i++) { 169 | if (i < strlen(passwd)) { 170 | key[i] = passwd[i]; 171 | } else { 172 | key[i] = 0; 173 | } 174 | } 175 | 176 | encrypt_rfbdes(bytes, &out_len, key, bytes, CHALLENGESIZE); 177 | } 178 | 179 | void 180 | rfbEncryptBytes2(unsigned char *where, const int length, unsigned char *key) { 181 | int i, j, out_len; 182 | for (i = 0; i< 8; i++) 183 | where[i] ^= key[i]; 184 | encrypt_rfbdes(where, &out_len, key, where, 8); 185 | for (i = 8; i < length; i += 8) { 186 | for (j = 0; j < 8; j++) { 187 | where[i + j] ^= where[i + j - 8]; 188 | } 189 | encrypt_rfbdes(where + i, &out_len, key, where + i, 8); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/encodings/zlib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. 3 | * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 18 | * USA. 19 | */ 20 | 21 | #ifdef LIBVNCSERVER_HAVE_LIBZ 22 | 23 | /* 24 | * zlib.c - handle zlib encoding. 25 | * 26 | * This file shouldn't be compiled directly. It is included multiple times by 27 | * rfbproto.c, each time with a different definition of the macro BPP. For 28 | * each value of BPP, this file defines a function which handles an zlib 29 | * encoded rectangle with BPP bits per pixel. 30 | */ 31 | 32 | #define HandleZlibBPP CONCAT2E(HandleZlib,BPP) 33 | #define CARDBPP CONCAT3E(uint,BPP,_t) 34 | 35 | static rfbBool 36 | HandleZlibBPP (rfbClient* client, int rx, int ry, int rw, int rh) 37 | { 38 | rfbZlibHeader hdr; 39 | int remaining; 40 | int inflateResult; 41 | int toRead; 42 | 43 | /* First make sure we have a large enough raw buffer to hold the 44 | * decompressed data. In practice, with a fixed BPP, fixed frame 45 | * buffer size and the first update containing the entire frame 46 | * buffer, this buffer allocation should only happen once, on the 47 | * first update. 48 | */ 49 | if ( client->raw_buffer_size < (( rw * rh ) * ( BPP / 8 ))) { 50 | 51 | if ( client->raw_buffer != NULL ) { 52 | 53 | free( client->raw_buffer ); 54 | 55 | } 56 | 57 | client->raw_buffer_size = (( rw * rh ) * ( BPP / 8 )); 58 | client->raw_buffer = (char*) malloc( client->raw_buffer_size ); 59 | 60 | } 61 | 62 | if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbZlibHeader)) 63 | return FALSE; 64 | 65 | remaining = rfbClientSwap32IfLE(hdr.nBytes); 66 | 67 | /* Need to initialize the decompressor state. */ 68 | client->decompStream.next_in = ( Bytef * )client->buffer; 69 | client->decompStream.avail_in = 0; 70 | client->decompStream.next_out = ( Bytef * )client->raw_buffer; 71 | client->decompStream.avail_out = client->raw_buffer_size; 72 | client->decompStream.data_type = Z_BINARY; 73 | 74 | /* Initialize the decompression stream structures on the first invocation. */ 75 | if ( client->decompStreamInited == FALSE ) { 76 | 77 | inflateResult = inflateInit( &client->decompStream ); 78 | 79 | if ( inflateResult != Z_OK ) { 80 | rfbClientLog( 81 | "inflateInit returned error: %d, msg: %s\n", 82 | inflateResult, 83 | client->decompStream.msg); 84 | return FALSE; 85 | } 86 | 87 | client->decompStreamInited = TRUE; 88 | 89 | } 90 | 91 | inflateResult = Z_OK; 92 | 93 | /* Process buffer full of data until no more to process, or 94 | * some type of inflater error, or Z_STREAM_END. 95 | */ 96 | while (( remaining > 0 ) && 97 | ( inflateResult == Z_OK )) { 98 | 99 | if ( remaining > RFB_BUFFER_SIZE ) { 100 | toRead = RFB_BUFFER_SIZE; 101 | } 102 | else { 103 | toRead = remaining; 104 | } 105 | 106 | /* Fill the buffer, obtaining data from the server. */ 107 | if (!ReadFromRFBServer(client, client->buffer,toRead)) 108 | return FALSE; 109 | 110 | client->decompStream.next_in = ( Bytef * )client->buffer; 111 | client->decompStream.avail_in = toRead; 112 | 113 | /* Need to uncompress buffer full. */ 114 | inflateResult = inflate( &client->decompStream, Z_SYNC_FLUSH ); 115 | 116 | /* We never supply a dictionary for compression. */ 117 | if ( inflateResult == Z_NEED_DICT ) { 118 | rfbClientLog("zlib inflate needs a dictionary!\n"); 119 | return FALSE; 120 | } 121 | if ( inflateResult < 0 ) { 122 | rfbClientLog( 123 | "zlib inflate returned error: %d, msg: %s\n", 124 | inflateResult, 125 | client->decompStream.msg); 126 | return FALSE; 127 | } 128 | 129 | /* Result buffer allocated to be at least large enough. We should 130 | * never run out of space! 131 | */ 132 | if (( client->decompStream.avail_in > 0 ) && 133 | ( client->decompStream.avail_out <= 0 )) { 134 | rfbClientLog("zlib inflate ran out of space!\n"); 135 | return FALSE; 136 | } 137 | 138 | remaining -= toRead; 139 | 140 | } /* while ( remaining > 0 ) */ 141 | 142 | if ( inflateResult == Z_OK ) { 143 | 144 | /* Put the uncompressed contents of the update on the screen. */ 145 | client->GotBitmap(client, (uint8_t *)client->raw_buffer, rx, ry, rw, rh); 146 | } 147 | else { 148 | 149 | rfbClientLog( 150 | "zlib inflate returned error: %d, msg: %s\n", 151 | inflateResult, 152 | client->decompStream.msg); 153 | return FALSE; 154 | 155 | } 156 | 157 | return TRUE; 158 | } 159 | 160 | #undef CARDBPP 161 | 162 | #endif 163 | -------------------------------------------------------------------------------- /src/encodings/zrle.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2005 Johannes E. Schindelin. All Rights Reserved. 3 | * 4 | * This is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This software is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this software; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 17 | * USA. 18 | */ 19 | 20 | #ifdef LIBVNCSERVER_HAVE_LIBZ 21 | 22 | /* 23 | * zrle.c - handle zrle encoding. 24 | * 25 | * This file shouldn't be compiled directly. It is included multiple times by 26 | * rfbproto.c, each time with a different definition of the macro BPP. For 27 | * each value of BPP, this file defines a function which handles an zrle 28 | * encoded rectangle with BPP bits per pixel. 29 | */ 30 | 31 | #ifndef REALBPP 32 | #define REALBPP BPP 33 | #endif 34 | 35 | #if !defined(UNCOMP) || UNCOMP==0 36 | #define HandleZRLE CONCAT2E(HandleZRLE,REALBPP) 37 | #define HandleZRLETile CONCAT2E(HandleZRLETile,REALBPP) 38 | #elif UNCOMP>0 39 | #define HandleZRLE CONCAT3E(HandleZRLE,REALBPP,Down) 40 | #define HandleZRLETile CONCAT3E(HandleZRLETile,REALBPP,Down) 41 | #else 42 | #define HandleZRLE CONCAT3E(HandleZRLE,REALBPP,Up) 43 | #define HandleZRLETile CONCAT3E(HandleZRLETile,REALBPP,Up) 44 | #endif 45 | #define CARDBPP CONCAT3E(uint,BPP,_t) 46 | #define CARDREALBPP CONCAT3E(uint,REALBPP,_t) 47 | 48 | #define ENDIAN_LITTLE 0 49 | #define ENDIAN_BIG 1 50 | #define ENDIAN_NO 2 51 | #define ZYWRLE_ENDIAN ENDIAN_LITTLE 52 | #undef END_FIX 53 | #if ZYWRLE_ENDIAN == ENDIAN_LITTLE 54 | # define END_FIX LE 55 | #elif ZYWRLE_ENDIAN == ENDIAN_BIG 56 | # define END_FIX BE 57 | #else 58 | # define END_FIX NE 59 | #endif 60 | #define __RFB_CONCAT3E(a,b,c) CONCAT3E(a,b,c) 61 | #define __RFB_CONCAT2E(a,b) CONCAT2E(a,b) 62 | #undef CPIXEL 63 | #if REALBPP != BPP 64 | #if UNCOMP == 0 65 | #define CPIXEL REALBPP 66 | #elif UNCOMP>0 67 | #define CPIXEL CONCAT2E(REALBPP,Down) 68 | #else 69 | #define CPIXEL CONCAT2E(REALBPP,Up) 70 | #endif 71 | #endif 72 | #define PIXEL_T __RFB_CONCAT3E(uint,BPP,_t) 73 | #if BPP!=8 74 | #define ZYWRLE_DECODE 1 75 | #include "zywrletemplate.c" 76 | #endif 77 | #undef CPIXEL 78 | 79 | static int HandleZRLETile(rfbClient* client, 80 | uint8_t* buffer,size_t buffer_length, 81 | int x,int y,int w,int h); 82 | 83 | static rfbBool 84 | HandleZRLE (rfbClient* client, int rx, int ry, int rw, int rh) 85 | { 86 | rfbZRLEHeader header; 87 | int remaining; 88 | int inflateResult; 89 | int toRead; 90 | int min_buffer_size = rw * rh * (REALBPP / 8) * 2; 91 | 92 | /* First make sure we have a large enough raw buffer to hold the 93 | * decompressed data. In practice, with a fixed REALBPP, fixed frame 94 | * buffer size and the first update containing the entire frame 95 | * buffer, this buffer allocation should only happen once, on the 96 | * first update. 97 | */ 98 | if ( client->raw_buffer_size < min_buffer_size) { 99 | 100 | if ( client->raw_buffer != NULL ) { 101 | 102 | free( client->raw_buffer ); 103 | 104 | } 105 | 106 | client->raw_buffer_size = min_buffer_size; 107 | client->raw_buffer = (char*) malloc( client->raw_buffer_size ); 108 | 109 | } 110 | 111 | if (!ReadFromRFBServer(client, (char *)&header, sz_rfbZRLEHeader)) 112 | return FALSE; 113 | 114 | remaining = rfbClientSwap32IfLE(header.length); 115 | 116 | /* Need to initialize the decompressor state. */ 117 | client->decompStream.next_in = ( Bytef * )client->buffer; 118 | client->decompStream.avail_in = 0; 119 | client->decompStream.next_out = ( Bytef * )client->raw_buffer; 120 | client->decompStream.avail_out = client->raw_buffer_size; 121 | client->decompStream.data_type = Z_BINARY; 122 | 123 | /* Initialize the decompression stream structures on the first invocation. */ 124 | if ( client->decompStreamInited == FALSE ) { 125 | 126 | inflateResult = inflateInit( &client->decompStream ); 127 | 128 | if ( inflateResult != Z_OK ) { 129 | rfbClientLog( 130 | "inflateInit returned error: %d, msg: %s\n", 131 | inflateResult, 132 | client->decompStream.msg); 133 | return FALSE; 134 | } 135 | 136 | client->decompStreamInited = TRUE; 137 | 138 | } 139 | 140 | inflateResult = Z_OK; 141 | 142 | /* Process buffer full of data until no more to process, or 143 | * some type of inflater error, or Z_STREAM_END. 144 | */ 145 | while (( remaining > 0 ) && 146 | ( inflateResult == Z_OK )) { 147 | 148 | if ( remaining > RFB_BUFFER_SIZE ) { 149 | toRead = RFB_BUFFER_SIZE; 150 | } 151 | else { 152 | toRead = remaining; 153 | } 154 | 155 | /* Fill the buffer, obtaining data from the server. */ 156 | if (!ReadFromRFBServer(client, client->buffer,toRead)) 157 | return FALSE; 158 | 159 | client->decompStream.next_in = ( Bytef * )client->buffer; 160 | client->decompStream.avail_in = toRead; 161 | 162 | /* Need to uncompress buffer full. */ 163 | inflateResult = inflate( &client->decompStream, Z_SYNC_FLUSH ); 164 | 165 | /* We never supply a dictionary for compression. */ 166 | if ( inflateResult == Z_NEED_DICT ) { 167 | rfbClientLog("zlib inflate needs a dictionary!\n"); 168 | return FALSE; 169 | } 170 | if ( inflateResult < 0 ) { 171 | rfbClientLog( 172 | "zlib inflate returned error: %d, msg: %s\n", 173 | inflateResult, 174 | client->decompStream.msg); 175 | return FALSE; 176 | } 177 | 178 | /* Result buffer allocated to be at least large enough. We should 179 | * never run out of space! 180 | */ 181 | if (( client->decompStream.avail_in > 0 ) && 182 | ( client->decompStream.avail_out <= 0 )) { 183 | rfbClientLog("zlib inflate ran out of space!\n"); 184 | return FALSE; 185 | } 186 | 187 | remaining -= toRead; 188 | 189 | } /* while ( remaining > 0 ) */ 190 | 191 | if ( inflateResult == Z_OK ) { 192 | char* buf=client->raw_buffer; 193 | int i,j; 194 | 195 | remaining = client->raw_buffer_size-client->decompStream.avail_out; 196 | 197 | for(j=0; jrw)?rw-i:rfbZRLETileWidth; 200 | int subHeight=(j+rfbZRLETileHeight>rh)?rh-j:rfbZRLETileHeight; 201 | int result=HandleZRLETile(client,(uint8_t *)buf,remaining,rx+i,ry+j,subWidth,subHeight); 202 | 203 | if(result<0) { 204 | rfbClientLog("ZRLE decoding failed (%d)\n",result); 205 | return TRUE; 206 | return FALSE; 207 | } 208 | 209 | buf+=result; 210 | remaining-=result; 211 | } 212 | } 213 | else { 214 | 215 | rfbClientLog( 216 | "zlib inflate returned error: %d, msg: %s\n", 217 | inflateResult, 218 | client->decompStream.msg); 219 | return FALSE; 220 | 221 | } 222 | 223 | return TRUE; 224 | } 225 | 226 | #if REALBPP!=BPP && defined(UNCOMP) && UNCOMP!=0 227 | #if UNCOMP>0 228 | #define UncompressCPixel(pointer) ((*(CARDBPP*)pointer)>>UNCOMP) 229 | #else 230 | #define UncompressCPixel(pointer) ((*(CARDBPP*)pointer)<<(-(UNCOMP))) 231 | #endif 232 | #else 233 | #define UncompressCPixel(pointer) (*(CARDBPP*)pointer) 234 | #endif 235 | 236 | static int HandleZRLETile(rfbClient* client, 237 | uint8_t* buffer,size_t buffer_length, 238 | int x,int y,int w,int h) { 239 | uint8_t* buffer_copy = buffer; 240 | uint8_t* buffer_end = buffer+buffer_length; 241 | uint8_t type; 242 | #if BPP!=8 243 | uint8_t zywrle_level = (client->appData.qualityLevel & 0x80) ? 244 | 0 : (3 - client->appData.qualityLevel / 3); 245 | #endif 246 | 247 | if(buffer_length<1) 248 | return -2; 249 | 250 | type = *buffer; 251 | buffer++; 252 | { 253 | if( type == 0 ) /* raw */ 254 | #if BPP!=8 255 | if( zywrle_level > 0 ){ 256 | CARDBPP* pFrame = (CARDBPP*)client->frameBuffer + y*client->width+x; 257 | int ret; 258 | client->appData.qualityLevel |= 0x80; 259 | ret = HandleZRLETile(client, buffer, buffer_end-buffer, x, y, w, h); 260 | client->appData.qualityLevel &= 0x7F; 261 | if( ret < 0 ){ 262 | return ret; 263 | } 264 | ZYWRLE_SYNTHESIZE( pFrame, pFrame, w, h, client->width, zywrle_level, (int*)client->zlib_buffer ); 265 | buffer += ret; 266 | }else 267 | #endif 268 | { 269 | #if REALBPP!=BPP 270 | int i,j; 271 | 272 | if(1+w*h*REALBPP/8>buffer_length) { 273 | rfbClientLog("expected %d bytes, got only %d (%dx%d)\n",1+w*h*REALBPP/8,buffer_length,w,h); 274 | return -3; 275 | } 276 | 277 | for(j=y*client->width; j<(y+h)*client->width; j+=client->width) 278 | for(i=x; iframeBuffer)[j+i] = UncompressCPixel(buffer); 280 | #else 281 | client->GotBitmap(client, buffer, x, y, w, h); 282 | buffer+=w*h*REALBPP/8; 283 | #endif 284 | } 285 | else if( type == 1 ) /* solid */ 286 | { 287 | CARDBPP color = UncompressCPixel(buffer); 288 | 289 | if(1+REALBPP/8>buffer_length) 290 | return -4; 291 | 292 | client->GotFillRect(client, x, y, w, h, color); 293 | 294 | buffer+=REALBPP/8; 295 | 296 | } 297 | else if( type <= 127 ) /* packed Palette */ 298 | { 299 | CARDBPP palette[128]; 300 | int i,j,shift, 301 | bpp=(type>4?(type>16?8:4):(type>2?2:1)), 302 | mask=(1<buffer_length) 306 | return -5; 307 | 308 | /* read palette */ 309 | for(i=0; iwidth; j<(y+h)*client->width; j+=client->width) { 314 | for(i=x,shift=8-bpp; iframeBuffer)[j+i] = palette[((*buffer)>>shift)&mask]; 316 | shift-=bpp; 317 | if(shift<0) { 318 | shift=8-bpp; 319 | buffer++; 320 | } 321 | } 322 | if(shift<8-bpp) 323 | buffer++; 324 | } 325 | 326 | } 327 | /* case 17 ... 127: not used, but valid */ 328 | else if( type == 128 ) /* plain RLE */ 329 | { 330 | int i=0,j=0; 331 | while(jbuffer_end) 335 | return -7; 336 | color = UncompressCPixel(buffer); 337 | buffer+=REALBPP/8; 338 | /* read run length */ 339 | length=1; 340 | while(*buffer==0xff) { 341 | if(buffer+1>=buffer_end) 342 | return -8; 343 | length+=*buffer; 344 | buffer++; 345 | } 346 | length+=*buffer; 347 | buffer++; 348 | while(j0) { 349 | ((CARDBPP*)client->frameBuffer)[(y+j)*client->width+x+i] = color; 350 | length--; 351 | i++; 352 | if(i>=w) { 353 | i=0; 354 | j++; 355 | } 356 | } 357 | if(length>0) 358 | rfbClientLog("Warning: possible ZRLE corruption\n"); 359 | } 360 | 361 | } 362 | else if( type == 129 ) /* unused */ 363 | { 364 | return -8; 365 | } 366 | else if( type >= 130 ) /* palette RLE */ 367 | { 368 | CARDBPP palette[128]; 369 | int i,j; 370 | 371 | if(2+(type-128)*REALBPP/8>buffer_length) 372 | return -9; 373 | 374 | /* read palette */ 375 | for(i=0; i=buffer_end) 383 | return -10; 384 | color = palette[(*buffer)&0x7f]; 385 | length=1; 386 | if(*buffer&0x80) { 387 | if(buffer+1>=buffer_end) 388 | return -11; 389 | buffer++; 390 | /* read run length */ 391 | while(*buffer==0xff) { 392 | if(buffer+1>=buffer_end) 393 | return -8; 394 | length+=*buffer; 395 | buffer++; 396 | } 397 | length+=*buffer; 398 | } 399 | buffer++; 400 | while(j0) { 401 | ((CARDBPP*)client->frameBuffer)[(y+j)*client->width+x+i] = color; 402 | length--; 403 | i++; 404 | if(i>=w) { 405 | i=0; 406 | j++; 407 | } 408 | } 409 | if(length>0) 410 | rfbClientLog("Warning: possible ZRLE corruption\n"); 411 | } 412 | } 413 | } 414 | 415 | return buffer-buffer_copy; 416 | } 417 | 418 | #undef CARDBPP 419 | #undef CARDREALBPP 420 | #undef HandleZRLE 421 | #undef HandleZRLETile 422 | #undef UncompressCPixel 423 | 424 | #endif 425 | 426 | #undef UNCOMP 427 | #undef REALBPP 428 | -------------------------------------------------------------------------------- /src/inhibitor.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "inhibitor.h" 4 | #include "seat.h" 5 | #include 6 | #include 7 | #include 8 | 9 | void inhibitor_active(void *data, 10 | struct zwp_keyboard_shortcuts_inhibitor_v1 *zwp_keyboard_shortcuts_inhibitor_v1) 11 | { 12 | struct shortcuts_seat_inhibitor* seat_inhibitor = data; 13 | seat_inhibitor->active = true; 14 | } 15 | 16 | void inhibitor_inactive(void *data, 17 | struct zwp_keyboard_shortcuts_inhibitor_v1 *zwp_keyboard_shortcuts_inhibitor_v1) 18 | { 19 | struct shortcuts_seat_inhibitor* seat_inhibitor = data; 20 | seat_inhibitor->active = false; 21 | } 22 | 23 | static struct zwp_keyboard_shortcuts_inhibitor_v1_listener inhibitor_listener = { 24 | .active = inhibitor_active, 25 | .inactive = inhibitor_inactive, 26 | }; 27 | 28 | struct shortcuts_inhibitor* inhibitor_new(struct zwp_keyboard_shortcuts_inhibit_manager_v1* manager) 29 | { 30 | struct shortcuts_inhibitor* self = calloc(1, sizeof(*self)); 31 | if (!self) 32 | return NULL; 33 | 34 | self->manager = manager; 35 | self->surface = NULL; 36 | wl_list_init(&self->seat_inhibitors); 37 | 38 | return self; 39 | } 40 | 41 | struct shortcuts_seat_inhibitor* seat_inhibitor_new(struct seat* seat) 42 | { 43 | struct shortcuts_seat_inhibitor* self = calloc(1, sizeof(*self)); 44 | if (!self) 45 | return NULL; 46 | 47 | self->seat = seat; 48 | self->inhibitor = NULL; 49 | 50 | return self; 51 | } 52 | 53 | struct shortcuts_seat_inhibitor* seat_inhibitor_find_by_seat(struct wl_list* list, struct seat* seat) 54 | { 55 | struct shortcuts_seat_inhibitor* seat_inhibitor; 56 | 57 | wl_list_for_each(seat_inhibitor, list, link) { 58 | if (seat == seat_inhibitor->seat) { 59 | return seat_inhibitor; 60 | } 61 | } 62 | 63 | return NULL; 64 | } 65 | 66 | bool inhibitor_init(struct shortcuts_inhibitor* self, struct wl_surface* surface, 67 | struct wl_list* seats) 68 | { 69 | if (!self) 70 | return false; 71 | if (self->surface) 72 | return false; 73 | 74 | self->surface = surface; 75 | 76 | struct shortcuts_seat_inhibitor* seat_inhibitor; 77 | wl_list_for_each(seat_inhibitor, &self->seat_inhibitors, link) 78 | inhibitor_inhibit(self, seat_inhibitor->seat); 79 | 80 | return true; 81 | } 82 | 83 | void seat_inhibitor_destroy(struct shortcuts_seat_inhibitor* self) 84 | { 85 | if (!self) 86 | return; 87 | 88 | if (self->inhibitor) 89 | zwp_keyboard_shortcuts_inhibitor_v1_destroy(self->inhibitor); 90 | free(self); 91 | } 92 | 93 | void inhibitor_destroy(struct shortcuts_inhibitor* self) 94 | { 95 | if (!self) 96 | return; 97 | 98 | struct shortcuts_seat_inhibitor* seat_inhibitor; 99 | struct shortcuts_seat_inhibitor* tmp; 100 | 101 | wl_list_for_each_safe(seat_inhibitor, tmp, &self->seat_inhibitors, link) 102 | seat_inhibitor_destroy(seat_inhibitor); 103 | zwp_keyboard_shortcuts_inhibit_manager_v1_destroy(self->manager); 104 | free(self); 105 | } 106 | 107 | bool inhibitor_is_inhibited(struct shortcuts_inhibitor* self, 108 | struct seat* seat) 109 | { 110 | if (!self) 111 | return false; 112 | 113 | struct shortcuts_seat_inhibitor* seat_inhibitor = seat_inhibitor_find_by_seat(&self->seat_inhibitors, seat); 114 | assert(seat_inhibitor); 115 | 116 | return seat_inhibitor->inhibitor != NULL; 117 | } 118 | 119 | void inhibitor_inhibit(struct shortcuts_inhibitor* self, struct seat* seat) 120 | { 121 | if (!self) 122 | return; 123 | if (inhibitor_is_inhibited(self, seat)) 124 | return; 125 | 126 | struct shortcuts_seat_inhibitor* seat_inhibitor = seat_inhibitor_find_by_seat(&self->seat_inhibitors, seat); 127 | assert(seat_inhibitor); 128 | 129 | seat_inhibitor->inhibitor = zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts( 130 | self->manager, self->surface, seat_inhibitor->seat->wl_seat); 131 | zwp_keyboard_shortcuts_inhibitor_v1_add_listener(seat_inhibitor->inhibitor, &inhibitor_listener, seat_inhibitor); 132 | } 133 | 134 | void inhibitor_release(struct shortcuts_inhibitor* self, struct seat* seat) 135 | { 136 | if (!self) 137 | return; 138 | if (!inhibitor_is_inhibited(self, seat)) 139 | return; 140 | 141 | struct shortcuts_seat_inhibitor* seat_inhibitor = seat_inhibitor_find_by_seat(&self->seat_inhibitors, seat); 142 | assert(seat_inhibitor); 143 | 144 | if (!seat_inhibitor->active) 145 | return; 146 | 147 | zwp_keyboard_shortcuts_inhibitor_v1_destroy(seat_inhibitor->inhibitor); 148 | seat_inhibitor->inhibitor = NULL; 149 | } 150 | 151 | void inhibitor_toggle(struct shortcuts_inhibitor* self, struct seat* seat) 152 | { 153 | if (!self) 154 | return; 155 | 156 | if (inhibitor_is_inhibited(self, seat)) { 157 | inhibitor_release(self, seat); 158 | } else { 159 | inhibitor_inhibit(self, seat); 160 | } 161 | } 162 | 163 | void inhibitor_add_seat(struct shortcuts_inhibitor* self, struct seat* seat) 164 | { 165 | if (!self) 166 | return; 167 | 168 | struct shortcuts_seat_inhibitor* seat_inhibitor = seat_inhibitor_find_by_seat(&self->seat_inhibitors, seat); 169 | if (seat_inhibitor) 170 | return; 171 | 172 | seat_inhibitor = seat_inhibitor_new(seat); 173 | wl_list_insert(&self->seat_inhibitors, &seat_inhibitor->link); 174 | 175 | if (self->surface) 176 | inhibitor_inhibit(self, seat); 177 | } 178 | 179 | void inhibitor_remove_seat(struct shortcuts_inhibitor* self, struct seat* seat) 180 | { 181 | if (!self) 182 | return; 183 | 184 | struct shortcuts_seat_inhibitor* seat_inhibitor = seat_inhibitor_find_by_seat(&self->seat_inhibitors, seat); 185 | if (!seat_inhibitor) 186 | return; 187 | 188 | wl_list_remove(&seat_inhibitor->link); 189 | seat_inhibitor_destroy(seat_inhibitor); 190 | } 191 | -------------------------------------------------------------------------------- /src/keyboard.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 - 2024 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "keyboard.h" 27 | 28 | enum keyboard_led_state { 29 | KEYBOARD_LED_SCROLL_LOCK = 1 << 0, 30 | KEYBOARD_LED_NUM_LOCK = 1 << 1, 31 | KEYBOARD_LED_CAPS_LOCK = 1 << 2, 32 | }; 33 | 34 | struct keyboard* keyboard_new(struct wl_keyboard* wl_keyboard, 35 | struct seat* seat) 36 | { 37 | struct keyboard* self = calloc(1, sizeof(*self)); 38 | if (!self) 39 | return NULL; 40 | 41 | self->wl_keyboard = wl_keyboard; 42 | self->seat = seat; 43 | self->context = xkb_context_new(0); 44 | 45 | return self; 46 | } 47 | 48 | uint32_t* keyboard_get_pressed_key(struct keyboard* keyboard, uint32_t key) 49 | { 50 | for (int i = 0; i < PRESSED_KEYS_MAX; i += 1) { 51 | if (key == keyboard->pressed_keys[i]) { 52 | return &keyboard->pressed_keys[i]; 53 | }; 54 | } 55 | return NULL; 56 | } 57 | 58 | void keyboard_add_pressed_key(struct keyboard* keyboard, uint32_t key) 59 | { 60 | if (keyboard_get_pressed_key(keyboard, key)) 61 | return; 62 | uint32_t* pressed_key = keyboard_get_pressed_key(keyboard, 0); 63 | if (!pressed_key) { 64 | fprintf(stderr, "Oops, pressed too many keys.\n"); 65 | return; 66 | } 67 | *pressed_key = key; 68 | } 69 | 70 | void keyboard_remove_pressed_key(struct keyboard* keyboard, uint32_t key) 71 | { 72 | uint32_t* pressed_key = keyboard_get_pressed_key(keyboard, key); 73 | if (!pressed_key) 74 | return; 75 | *pressed_key = 0; 76 | } 77 | 78 | void keyboard_destroy(struct keyboard* self) 79 | { 80 | if (self->state) 81 | xkb_state_unref(self->state); 82 | 83 | if (self->keymap) 84 | xkb_keymap_unref(self->keymap); 85 | 86 | xkb_context_unref(self->context); 87 | wl_keyboard_destroy(self->wl_keyboard); 88 | free(self); 89 | } 90 | 91 | struct keyboard_collection* keyboard_collection_new(void) 92 | { 93 | struct keyboard_collection* self = calloc(1, sizeof(*self)); 94 | if (!self) 95 | return NULL; 96 | 97 | wl_list_init(&self->keyboards); 98 | 99 | return self; 100 | } 101 | 102 | void keyboard_collection_destroy(struct keyboard_collection* self) 103 | { 104 | struct keyboard* keyboard; 105 | struct keyboard* tmp; 106 | 107 | wl_list_for_each_safe(keyboard, tmp, &self->keyboards, link) { 108 | wl_list_remove(&keyboard->link); 109 | keyboard_destroy(keyboard); 110 | } 111 | 112 | free(self); 113 | } 114 | 115 | struct keyboard* keyboard_collection_find_wl_keyboard( 116 | struct keyboard_collection* self, struct wl_keyboard* wl_keyboard) 117 | { 118 | struct keyboard* keyboard; 119 | wl_list_for_each(keyboard, &self->keyboards, link) 120 | if (keyboard->wl_keyboard == wl_keyboard) 121 | return keyboard; 122 | 123 | return NULL; 124 | } 125 | 126 | static void keyboard_keymap(void* data, struct wl_keyboard* wl_keyboard, 127 | enum wl_keyboard_keymap_format format, int32_t fd, 128 | uint32_t size) 129 | { 130 | struct keyboard_collection* self = data; 131 | struct keyboard* keyboard = 132 | keyboard_collection_find_wl_keyboard(self, wl_keyboard); 133 | assert(keyboard); 134 | 135 | if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) 136 | return; 137 | 138 | char* buffer = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); 139 | assert(buffer); 140 | 141 | if (keyboard->state) 142 | xkb_state_unref(keyboard->state); 143 | 144 | if (keyboard->keymap) 145 | xkb_keymap_unref(keyboard->keymap); 146 | 147 | keyboard->keymap = xkb_keymap_new_from_string(keyboard->context, 148 | buffer, XKB_KEYMAP_FORMAT_TEXT_V1, 0); 149 | assert(keyboard->keymap); 150 | 151 | munmap(buffer, size); 152 | 153 | keyboard->state = xkb_state_new(keyboard->keymap); 154 | assert(keyboard->state); 155 | } 156 | 157 | static void handle_key(struct keyboard_collection* self, struct keyboard* keyboard, 158 | uint32_t key, enum xkb_key_direction dir) 159 | { 160 | xkb_state_update_key(keyboard->state, key, dir); 161 | 162 | if (dir == XKB_KEY_DOWN) { 163 | keyboard_add_pressed_key(keyboard, key); 164 | } else { 165 | keyboard_remove_pressed_key(keyboard, key); 166 | } 167 | 168 | self->on_event(self, keyboard, key, dir == XKB_KEY_DOWN); 169 | } 170 | 171 | static void keyboard_enter(void* data, struct wl_keyboard* wl_keyboard, 172 | uint32_t serial, struct wl_surface* surface, 173 | struct wl_array* keys) 174 | { 175 | struct keyboard_collection* collection = data; 176 | struct keyboard* keyboard = 177 | keyboard_collection_find_wl_keyboard(collection, wl_keyboard); 178 | keyboard->waiting_for_modifiers = true; 179 | 180 | uint32_t* key; 181 | wl_array_for_each(key, keys) { 182 | handle_key(data, keyboard, *key + 8, XKB_KEY_DOWN); 183 | } 184 | } 185 | 186 | static void keyboard_leave(void* data, struct wl_keyboard* wl_keyboard, 187 | uint32_t serial, struct wl_surface* surface) 188 | { 189 | struct keyboard_collection* collection = data; 190 | struct keyboard* keyboard = 191 | keyboard_collection_find_wl_keyboard(collection, wl_keyboard); 192 | 193 | for (int i = 0; i < PRESSED_KEYS_MAX; i += 1) { 194 | if (!keyboard->pressed_keys[i]) 195 | continue; 196 | handle_key(collection, keyboard, keyboard->pressed_keys[i], XKB_KEY_UP); 197 | }; 198 | } 199 | 200 | static enum xkb_key_direction xbk_key_direction_from_wl_keyboard_key_state( 201 | enum wl_keyboard_key_state state) 202 | { 203 | switch (state) { 204 | case WL_KEYBOARD_KEY_STATE_PRESSED: 205 | return XKB_KEY_DOWN; 206 | case WL_KEYBOARD_KEY_STATE_RELEASED: 207 | return XKB_KEY_UP; 208 | } 209 | 210 | abort(); 211 | return 0; 212 | } 213 | 214 | static void keyboard_key(void* data, struct wl_keyboard* wl_keyboard, 215 | uint32_t serial, uint32_t t, uint32_t key, 216 | enum wl_keyboard_key_state state) 217 | { 218 | struct keyboard_collection* self = data; 219 | struct keyboard* keyboard = 220 | keyboard_collection_find_wl_keyboard(self, wl_keyboard); 221 | assert(keyboard); 222 | 223 | enum xkb_key_direction dir = 224 | xbk_key_direction_from_wl_keyboard_key_state(state); 225 | handle_key(self, keyboard, key + 8, dir); 226 | } 227 | 228 | static void keyboard_toggle_key(struct keyboard* self, uint32_t code) 229 | { 230 | struct keyboard_collection* collection = self->collection; 231 | collection->on_event(collection, self, code, 1); 232 | collection->on_event(collection, self, code, 0); 233 | } 234 | 235 | static void keyboard_sync_led_state(struct keyboard* self) 236 | { 237 | uint32_t leds = 0; 238 | if (xkb_state_led_name_is_active(self->state, XKB_LED_NAME_SCROLL)) 239 | leds |= KEYBOARD_LED_SCROLL_LOCK; 240 | if (xkb_state_led_name_is_active(self->state, XKB_LED_NAME_NUM)) 241 | leds |= KEYBOARD_LED_NUM_LOCK; 242 | if (xkb_state_led_name_is_active(self->state, XKB_LED_NAME_CAPS)) 243 | leds |= KEYBOARD_LED_CAPS_LOCK; 244 | 245 | uint32_t diff = self->led_state ^ leds; 246 | self->led_state = leds; 247 | if (!self->waiting_for_modifiers || !diff) 248 | return; 249 | 250 | if (diff & KEYBOARD_LED_SCROLL_LOCK) 251 | keyboard_toggle_key(self, KEY_SCROLLLOCK + 8); 252 | if (diff & KEYBOARD_LED_NUM_LOCK) 253 | keyboard_toggle_key(self, KEY_NUMLOCK + 8); 254 | if (diff & KEYBOARD_LED_CAPS_LOCK) 255 | keyboard_toggle_key(self, KEY_CAPSLOCK + 8); 256 | } 257 | 258 | static void keyboard_modifiers(void* data, struct wl_keyboard* wl_keyboard, 259 | uint32_t serial, uint32_t depressed, uint32_t latched, 260 | uint32_t locked, uint32_t group) 261 | { 262 | struct keyboard_collection* self = data; 263 | struct keyboard* keyboard = 264 | keyboard_collection_find_wl_keyboard(self, wl_keyboard); 265 | assert(keyboard); 266 | 267 | xkb_state_update_mask(keyboard->state, depressed, latched, locked, 0, 0, 268 | group); 269 | 270 | keyboard_sync_led_state(keyboard); 271 | keyboard->waiting_for_modifiers = false; 272 | } 273 | 274 | static void keyboard_repeat_info(void* data, struct wl_keyboard* wl_keyboard, 275 | int32_t rate, int32_t delay) 276 | { 277 | // TODO 278 | } 279 | 280 | static struct wl_keyboard_listener keyboard_listener = { 281 | .keymap = keyboard_keymap, 282 | .enter = keyboard_enter, 283 | .leave = keyboard_leave, 284 | .key = keyboard_key, 285 | .modifiers = keyboard_modifiers, 286 | .repeat_info = keyboard_repeat_info, 287 | }; 288 | 289 | int keyboard_collection_add_wl_keyboard(struct keyboard_collection* self, 290 | struct wl_keyboard* wl_keyboard, struct seat* seat) 291 | { 292 | struct keyboard* keyboard = keyboard_new(wl_keyboard, seat); 293 | if (!keyboard) 294 | return -1; 295 | 296 | keyboard->collection = self; 297 | wl_list_insert(&self->keyboards, &keyboard->link); 298 | wl_keyboard_add_listener(keyboard->wl_keyboard, &keyboard_listener, self); 299 | return 0; 300 | } 301 | 302 | void keyboard_collection_remove_wl_keyboard(struct keyboard_collection* self, 303 | struct wl_keyboard* wl_keyboard) 304 | { 305 | struct keyboard* keyboard = 306 | keyboard_collection_find_wl_keyboard(self, wl_keyboard); 307 | wl_list_remove(&keyboard->link); 308 | free(keyboard); 309 | } 310 | -------------------------------------------------------------------------------- /src/open-h264.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "open-h264.h" 18 | #include "rfbclient.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | extern struct gbm_device* gbm_device; 29 | 30 | enum open_h264_flags { 31 | OPEN_H264_RESET_CONTEXT = 1 << 0, 32 | OPEN_H264_RESET_ALL_CONTEXTS = 1 << 1, 33 | }; 34 | 35 | struct open_h264_msg_head { 36 | uint32_t length; 37 | uint32_t flags; 38 | } __attribute__((packed)); 39 | 40 | struct open_h264_context { 41 | rfbRectangle rect; 42 | 43 | AVCodecParserContext* parser; 44 | AVCodecContext* codec_ctx; 45 | AVBufferRef* hwctx_ref; 46 | }; 47 | 48 | struct open_h264 { 49 | rfbClient* client; 50 | 51 | struct open_h264_context* contexts[OPEN_H264_MAX_CONTEXTS]; 52 | int n_contexts; 53 | }; 54 | 55 | static char* get_device_name(void) 56 | { 57 | int fd = gbm_device_get_fd(gbm_device); 58 | if (fd < 0) 59 | return NULL; 60 | 61 | return drmGetDeviceNameFromFd2(fd); 62 | } 63 | 64 | static bool are_rects_equal(const rfbRectangle* a, const rfbRectangle* b) 65 | { 66 | return memcmp(a, b, sizeof(*a)) == 0; 67 | } 68 | 69 | static int find_context_index(const struct open_h264* self, 70 | const rfbRectangle* rect) 71 | { 72 | for (int i = 0; i < self->n_contexts; ++i) 73 | if (are_rects_equal(&self->contexts[i]->rect, rect)) 74 | return i; 75 | return -1; 76 | } 77 | 78 | static struct open_h264_context* find_context( 79 | const struct open_h264* self, const rfbRectangle* rect) 80 | { 81 | int i = find_context_index(self, rect); 82 | return i >= 0 ? self->contexts[i] : NULL; 83 | } 84 | 85 | static struct open_h264_context* open_h264_context_create( 86 | struct open_h264* self, const rfbRectangle* rect) 87 | { 88 | if (self->n_contexts >= OPEN_H264_MAX_CONTEXTS) 89 | return NULL; 90 | 91 | struct open_h264_context* context = calloc(1, sizeof(*context)); 92 | if (!context) 93 | return NULL; 94 | 95 | memcpy(&context->rect, rect, sizeof(context->rect)); 96 | 97 | const AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264); 98 | if (!codec) 99 | goto failure; 100 | 101 | context->parser = av_parser_init(codec->id); 102 | if (!context->parser) 103 | goto failure; 104 | 105 | context->codec_ctx = avcodec_alloc_context3(codec); 106 | if (!context->codec_ctx) 107 | goto failure; 108 | 109 | char* device_name = get_device_name(); 110 | if (!device_name) 111 | goto failure; 112 | 113 | int rc = av_hwdevice_ctx_create(&context->hwctx_ref, 114 | AV_HWDEVICE_TYPE_VAAPI, device_name, NULL, 0); 115 | free(device_name); 116 | if (rc != 0) 117 | goto failure; 118 | 119 | context->codec_ctx->hw_device_ctx = av_buffer_ref(context->hwctx_ref); 120 | 121 | if (avcodec_open2(context->codec_ctx, codec, NULL) != 0) 122 | goto failure; 123 | 124 | self->contexts[self->n_contexts++] = context; 125 | return context; 126 | 127 | failure: 128 | av_buffer_unref(&context->hwctx_ref); 129 | avcodec_free_context(&context->codec_ctx); 130 | av_parser_close(context->parser); 131 | free(context); 132 | return NULL; 133 | } 134 | 135 | static void open_h264_context_destroy(struct open_h264_context* context) 136 | { 137 | av_buffer_unref(&context->hwctx_ref); 138 | avcodec_free_context(&context->codec_ctx); 139 | av_parser_close(context->parser); 140 | free(context); 141 | } 142 | 143 | static struct open_h264_context* get_context(struct open_h264* self, 144 | const rfbRectangle* rect) 145 | { 146 | struct open_h264_context* context = find_context(self, rect); 147 | return context ? context : open_h264_context_create(self, rect); 148 | } 149 | 150 | 151 | static void reset_context(struct open_h264* self, 152 | const rfbRectangle* rect) 153 | { 154 | int i = find_context_index(self, rect); 155 | if (i < 0) 156 | return; 157 | 158 | open_h264_context_destroy(self->contexts[i]); 159 | --self->n_contexts; 160 | 161 | memmove(&self->contexts[i], &self->contexts[i + 1], 162 | self->n_contexts - i); 163 | } 164 | 165 | static void reset_all_contexts(struct open_h264* self) 166 | { 167 | for (int i = 0; i < self->n_contexts; ++i) { 168 | open_h264_context_destroy(self->contexts[i]); 169 | self->contexts[i] = NULL; 170 | } 171 | } 172 | 173 | struct open_h264* open_h264_create(rfbClient* client) 174 | { 175 | struct open_h264* self = calloc(1, sizeof(*self)); 176 | if (!self) 177 | return NULL; 178 | 179 | self->client = client; 180 | 181 | return self; 182 | } 183 | 184 | void open_h264_destroy(struct open_h264* self) 185 | { 186 | if (!self) 187 | return; 188 | 189 | reset_all_contexts(self); 190 | free(self); 191 | } 192 | 193 | static bool decode_frame(struct open_h264_context* context, AVFrame* frame, 194 | AVPacket* packet) 195 | { 196 | av_frame_unref(frame); 197 | 198 | int rc; 199 | 200 | rc = avcodec_send_packet(context->codec_ctx, packet); 201 | if (rc < 0) 202 | return false; 203 | 204 | struct AVFrame* vaapi_frame = av_frame_alloc(); 205 | if (!vaapi_frame) 206 | return false; 207 | 208 | rc = avcodec_receive_frame(context->codec_ctx, vaapi_frame); 209 | if (rc < 0) 210 | return false; 211 | 212 | frame->format = AV_PIX_FMT_DRM_PRIME; 213 | 214 | rc = av_hwframe_map(frame, vaapi_frame, AV_HWFRAME_MAP_DIRECT); 215 | if (rc < 0) { 216 | av_frame_free(&vaapi_frame); 217 | return false; 218 | } 219 | 220 | av_frame_copy_props(frame, vaapi_frame); 221 | av_frame_free(&vaapi_frame); 222 | 223 | return true; 224 | } 225 | 226 | static int parse_elementary_stream(struct open_h264_context* context, 227 | AVPacket* packet, const uint8_t* src, uint32_t length) 228 | { 229 | return av_parser_parse2(context->parser, context->codec_ctx, 230 | &packet->data, &packet->size, src, length, 231 | AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0); 232 | } 233 | 234 | struct AVFrame* open_h264_decode_rect(struct open_h264* self, 235 | rfbFramebufferUpdateRectHeader* msg) 236 | { 237 | bool have_frame = false; 238 | 239 | struct open_h264_msg_head head = { 0 }; 240 | if (!ReadFromRFBServer(self->client, (char*)&head, sizeof(head))) 241 | return NULL; 242 | 243 | uint32_t length = ntohl(head.length); 244 | enum open_h264_flags flags = ntohl(head.flags); 245 | 246 | if (flags & OPEN_H264_RESET_ALL_CONTEXTS) { 247 | reset_all_contexts(self); 248 | } else if (flags & OPEN_H264_RESET_CONTEXT) { 249 | reset_context(self, &msg->r); 250 | } 251 | 252 | struct open_h264_context* context = get_context(self, &msg->r); 253 | if (!context) 254 | return NULL; 255 | 256 | char* data = calloc(1, length + AV_INPUT_BUFFER_PADDING_SIZE); 257 | if (!data) 258 | return NULL; 259 | 260 | AVFrame* frame = av_frame_alloc(); 261 | if (!frame) 262 | goto failure; 263 | 264 | AVPacket* packet = av_packet_alloc(); 265 | if (!packet) 266 | goto failure; 267 | 268 | if (!ReadFromRFBServer(self->client, data, length)) 269 | goto failure; 270 | 271 | uint8_t* dp = (uint8_t*)data; 272 | 273 | while (length > 0) { 274 | int rc = parse_elementary_stream(context, packet, dp, length); 275 | if (rc < 0) 276 | goto failure; 277 | 278 | dp += rc; 279 | length -= rc; 280 | 281 | // The h264 elementary stream doesn't have end-markers, so the 282 | // parser doesn't know where the frame ends. This flushes it: 283 | if (packet->size == 0 && length == 0) { 284 | int rc = parse_elementary_stream(context, packet, dp, 285 | length); 286 | if (rc < 0) 287 | goto failure; 288 | } 289 | 290 | // If we get multiple frames per rect, there's no point in 291 | // rendering them all, so we just return the last one. 292 | if (packet->size != 0) 293 | have_frame = decode_frame(context, frame, packet); 294 | } 295 | 296 | failure: 297 | av_packet_free(&packet); 298 | if (!have_frame) 299 | av_frame_unref(frame); 300 | free(data); 301 | return have_frame ? frame : NULL; 302 | } 303 | -------------------------------------------------------------------------------- /src/output.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 - 2022 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "output.h" 23 | 24 | static void output_handle_geometry(void* data, struct wl_output* wl_output, 25 | int32_t x, int32_t y, int32_t phys_width, int32_t phys_height, 26 | int32_t subpixel, const char* make, const char* model, 27 | int32_t transform) 28 | { 29 | } 30 | 31 | static void output_handle_mode(void* data, struct wl_output* wl_output, 32 | uint32_t flags, int32_t width, int32_t height, int32_t refresh) 33 | { 34 | } 35 | 36 | static void output_handle_done(void* data, struct wl_output* wl_output) 37 | { 38 | } 39 | 40 | static void output_handle_scale(void* data, struct wl_output* wl_output, 41 | int32_t factor) 42 | { 43 | struct output* output = data; 44 | output->scale = factor; 45 | } 46 | 47 | static const struct wl_output_listener output_listener = { 48 | .geometry = output_handle_geometry, 49 | .mode = output_handle_mode, 50 | .done = output_handle_done, 51 | .scale = output_handle_scale, 52 | }; 53 | 54 | void output_destroy(struct output* output) 55 | { 56 | wl_output_destroy(output->wl_output); 57 | free(output); 58 | } 59 | 60 | void output_list_destroy(struct wl_list* list) 61 | { 62 | struct output* output; 63 | struct output* tmp; 64 | 65 | wl_list_for_each_safe(output, tmp, list, link) { 66 | wl_list_remove(&output->link); 67 | output_destroy(output); 68 | } 69 | } 70 | 71 | int32_t output_list_get_max_scale(const struct wl_list* list) 72 | { 73 | struct output* output; 74 | 75 | int32_t scale = 1; 76 | 77 | wl_list_for_each(output, list, link) 78 | if (output->has_surface && output->scale > scale) 79 | scale = output->scale; 80 | 81 | return scale; 82 | } 83 | 84 | struct output* output_new(struct wl_output* wl_output, uint32_t id) 85 | { 86 | struct output* output = calloc(1, sizeof(*output)); 87 | if (!output) 88 | return NULL; 89 | 90 | output->wl_output = wl_output; 91 | output->id = id; 92 | output->has_surface = false; 93 | 94 | wl_output_add_listener(output->wl_output, &output_listener, 95 | output); 96 | 97 | return output; 98 | } 99 | 100 | struct output* output_find_by_id(struct wl_list* list, uint32_t id) 101 | { 102 | struct output* output; 103 | 104 | wl_list_for_each(output, list, link) 105 | if (output->id == id) 106 | return output; 107 | 108 | return NULL; 109 | } 110 | 111 | struct output* output_find_by_wl_output(struct wl_list* list, struct wl_output* wl_output) 112 | { 113 | struct output* output; 114 | 115 | wl_list_for_each(output, list, link) 116 | if (output->wl_output == wl_output) 117 | return output; 118 | 119 | return NULL; 120 | } 121 | -------------------------------------------------------------------------------- /src/pixels.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | enum wl_shm_format drm_format_to_wl_shm(uint32_t in) 24 | { 25 | assert(!(in & DRM_FORMAT_BIG_ENDIAN)); 26 | 27 | switch (in) { 28 | case DRM_FORMAT_ARGB8888: return WL_SHM_FORMAT_ARGB8888; 29 | case DRM_FORMAT_XRGB8888: return WL_SHM_FORMAT_XRGB8888; 30 | } 31 | 32 | return in; 33 | } 34 | 35 | uint32_t drm_format_from_wl_shm(enum wl_shm_format in) 36 | { 37 | switch (in) { 38 | case WL_SHM_FORMAT_ARGB8888: return DRM_FORMAT_ARGB8888; 39 | case WL_SHM_FORMAT_XRGB8888: return DRM_FORMAT_XRGB8888; 40 | default:; 41 | } 42 | 43 | return in; 44 | } 45 | 46 | bool drm_format_to_pixman_fmt(pixman_format_code_t* dst, uint32_t src) 47 | { 48 | #define LOWER_R r 49 | #define LOWER_G g 50 | #define LOWER_B b 51 | #define LOWER_A a 52 | #define LOWER_X x 53 | #define LOWER_ 54 | #define LOWER(x) LOWER_##x 55 | 56 | #define CONCAT_(a, b) a ## b 57 | #define CONCAT(a, b) CONCAT_(a, b) 58 | 59 | #define FMT_DRM(x, y, z, v, a, b, c, d) DRM_FORMAT_##x##y##z##v##a##b##c##d 60 | 61 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 62 | #define FMT_PIXMAN(x, y, z, v, a, b, c, d) \ 63 | CONCAT(CONCAT(CONCAT(CONCAT(CONCAT(CONCAT(CONCAT(CONCAT(\ 64 | PIXMAN_, LOWER(x)), a), LOWER(y)), b), LOWER(z)), c), LOWER(v)), d) 65 | #else 66 | #define FMT_PIXMAN(x, y, z, v, a, b, c, d) \ 67 | CONCAT(CONCAT(CONCAT(CONCAT(CONCAT(CONCAT(CONCAT(CONCAT(\ 68 | PIXMAN_, LOWER(v)), d), LOWER(z)), c), LOWER(y)), b), LOWER(x)), a) 69 | #endif 70 | 71 | switch (src) { 72 | #define X(...) \ 73 | case FMT_DRM(__VA_ARGS__): *dst = FMT_PIXMAN(__VA_ARGS__); break 74 | 75 | /* 32 bits */ 76 | X(A,R,G,B,8,8,8,8); 77 | X(A,B,G,R,8,8,8,8); 78 | X(X,R,G,B,8,8,8,8); 79 | X(X,B,G,R,8,8,8,8); 80 | X(R,G,B,A,8,8,8,8); 81 | X(B,G,R,A,8,8,8,8); 82 | X(R,G,B,X,8,8,8,8); 83 | X(B,G,R,X,8,8,8,8); 84 | 85 | /* 24 bits */ 86 | X(R,G,B,,8,8,8,); 87 | X(B,G,R,,8,8,8,); 88 | 89 | /* 16 bits */ 90 | X(R,G,B,,5,6,5,); 91 | X(B,G,R,,5,6,5,); 92 | 93 | /* These are incompatible on big endian */ 94 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 95 | X(A,R,G,B,2,10,10,10); 96 | X(X,R,G,B,2,10,10,10); 97 | X(A,B,G,R,2,10,10,10); 98 | X(X,B,G,R,2,10,10,10); 99 | X(A,R,G,B,1,5,5,5); 100 | X(A,B,G,R,1,5,5,5); 101 | X(X,R,G,B,1,5,5,5); 102 | X(X,B,G,R,1,5,5,5); 103 | X(A,R,G,B,4,4,4,4); 104 | X(A,B,G,R,4,4,4,4); 105 | X(X,R,G,B,4,4,4,4); 106 | X(X,B,G,R,4,4,4,4); 107 | #endif 108 | 109 | #undef X 110 | 111 | default: return false; 112 | } 113 | 114 | return true; 115 | } 116 | -------------------------------------------------------------------------------- /src/pointer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "pointer.h" 27 | 28 | #define STEP_SIZE 15.0 29 | 30 | extern struct wl_shm* wl_shm; 31 | extern struct wl_compositor* wl_compositor; 32 | 33 | static struct wl_cursor_theme* pointer_load_cursor_theme(void) 34 | { 35 | const char* xcursor_theme = getenv("XCURSOR_THEME"); 36 | const char* xcursor_size_str = getenv("XCURSOR_SIZE"); 37 | 38 | unsigned long xcursor_size = 24; 39 | if (xcursor_size_str) { 40 | char* end; 41 | unsigned long size = strtoul(xcursor_size_str, &end, 10); 42 | if (!*end && *xcursor_size_str) 43 | xcursor_size = size; 44 | } 45 | 46 | return wl_cursor_theme_load(xcursor_theme, xcursor_size, wl_shm); 47 | } 48 | 49 | struct pointer* pointer_new(struct wl_pointer* wl_pointer, 50 | enum pointer_cursor_type cursor_type, struct seat *seat) 51 | { 52 | struct pointer* self = calloc(1, sizeof(*self)); 53 | if (!self) 54 | return NULL; 55 | 56 | self->seat = seat; 57 | self->wl_pointer = wl_pointer; 58 | self->cursor_type = cursor_type; 59 | self->handle_event = false; 60 | 61 | if (cursor_type == POINTER_CURSOR_LEFT_PTR) 62 | self->cursor_theme = pointer_load_cursor_theme(); 63 | 64 | self->cursor_surface = wl_compositor_create_surface(wl_compositor); 65 | 66 | return self; 67 | } 68 | 69 | void pointer_destroy(struct pointer* self) 70 | { 71 | wl_pointer_destroy(self->wl_pointer); 72 | if (self->cursor_theme) 73 | wl_cursor_theme_destroy(self->cursor_theme); 74 | wl_surface_destroy(self->cursor_surface); 75 | free(self); 76 | } 77 | 78 | struct pointer_collection* pointer_collection_new( 79 | enum pointer_cursor_type cursor_type) 80 | { 81 | struct pointer_collection* self = calloc(1, sizeof(*self)); 82 | if (!self) 83 | return NULL; 84 | 85 | wl_list_init(&self->pointers); 86 | self->cursor_type = cursor_type; 87 | 88 | return self; 89 | } 90 | 91 | void pointer_collection_destroy(struct pointer_collection* self) 92 | { 93 | struct pointer* pointer; 94 | struct pointer* tmp; 95 | 96 | wl_list_for_each_safe(pointer, tmp, &self->pointers, link) { 97 | wl_list_remove(&pointer->link); 98 | pointer_destroy(pointer); 99 | } 100 | 101 | free(self); 102 | } 103 | 104 | struct pointer* pointer_collection_find_wl_pointer( 105 | struct pointer_collection* self, struct wl_pointer* wl_pointer) 106 | { 107 | struct pointer* pointer; 108 | wl_list_for_each(pointer, &self->pointers, link) 109 | if (pointer->wl_pointer == wl_pointer) 110 | return pointer; 111 | 112 | return NULL; 113 | } 114 | 115 | static void pointer_update_cursor_none(struct pointer* self) 116 | { 117 | wl_surface_attach(self->cursor_surface, NULL, 0, 0); 118 | wl_pointer_set_cursor(self->wl_pointer, self->serial, 119 | self->cursor_surface, 0, 0); 120 | wl_surface_commit(self->cursor_surface); 121 | } 122 | 123 | static void pointer_update_cursor_left_ptr(struct pointer* self) 124 | { 125 | struct wl_cursor* cursor = wl_cursor_theme_get_cursor( 126 | self->cursor_theme, "left_ptr"); 127 | assert(cursor && cursor->image_count > 0); 128 | 129 | struct wl_cursor_image* image = cursor->images[0]; 130 | 131 | // TODO Set buffer scale 132 | wl_surface_attach(self->cursor_surface, 133 | wl_cursor_image_get_buffer(image), 0, 0); 134 | wl_pointer_set_cursor(self->wl_pointer, self->serial, 135 | self->cursor_surface, image->hotspot_x, 136 | image->hotspot_y); 137 | wl_surface_damage_buffer(self->cursor_surface, 0, 0, image->width, 138 | image->height); 139 | wl_surface_commit(self->cursor_surface); 140 | } 141 | 142 | static void pointer_update_cursor(struct pointer* self) 143 | { 144 | switch (self->cursor_type) { 145 | case POINTER_CURSOR_NONE: 146 | pointer_update_cursor_none(self); 147 | return; 148 | case POINTER_CURSOR_LEFT_PTR: 149 | pointer_update_cursor_left_ptr(self); 150 | return; 151 | } 152 | 153 | abort(); 154 | } 155 | 156 | static void pointer_enter(void* data, struct wl_pointer* wl_pointer, 157 | uint32_t serial, struct wl_surface* surface, wl_fixed_t x, 158 | wl_fixed_t y) 159 | { 160 | struct pointer_collection* self = data; 161 | struct pointer* pointer = 162 | pointer_collection_find_wl_pointer(self, wl_pointer); 163 | assert(pointer); 164 | 165 | pointer->handle_event = self->handle_event(surface); 166 | if (!pointer->handle_event) 167 | return; 168 | 169 | pointer->serial = serial; 170 | 171 | pointer_update_cursor(pointer); 172 | } 173 | 174 | static void pointer_leave(void* data, struct wl_pointer* wl_pointer, 175 | uint32_t serial, struct wl_surface* surface) 176 | { 177 | struct pointer_collection* self = data; 178 | struct pointer* pointer = 179 | pointer_collection_find_wl_pointer(self, wl_pointer); 180 | assert(pointer); 181 | 182 | pointer->handle_event = self->handle_event(surface); 183 | if (!pointer->handle_event) 184 | return; 185 | 186 | pointer->serial = serial; 187 | } 188 | 189 | static void pointer_motion(void* data, struct wl_pointer* wl_pointer, 190 | uint32_t t, wl_fixed_t x, wl_fixed_t y) 191 | { 192 | struct pointer_collection* self = data; 193 | struct pointer* pointer = 194 | pointer_collection_find_wl_pointer(self, wl_pointer); 195 | assert(pointer); 196 | 197 | if (!pointer->handle_event) 198 | return; 199 | 200 | pointer->x = x; 201 | pointer->y = y; 202 | } 203 | 204 | static void pointer_set_button_state(struct pointer* self, 205 | enum pointer_button_mask button, 206 | enum wl_pointer_button_state state) 207 | { 208 | if (state == WL_POINTER_BUTTON_STATE_PRESSED) { 209 | self->pressed |= button; 210 | } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) { 211 | self->pressed &= ~button; 212 | } else { 213 | abort(); 214 | } 215 | } 216 | 217 | static void pointer_button(void* data, struct wl_pointer* wl_pointer, 218 | uint32_t serial, uint32_t t, uint32_t button, 219 | enum wl_pointer_button_state state) 220 | { 221 | struct pointer_collection* self = data; 222 | struct pointer* pointer = 223 | pointer_collection_find_wl_pointer(self, wl_pointer); 224 | assert(pointer); 225 | 226 | if (!pointer->handle_event) 227 | return; 228 | 229 | pointer->serial = serial; 230 | 231 | switch (button) { 232 | case BTN_LEFT: 233 | pointer_set_button_state(pointer, POINTER_BUTTON_LEFT, state); 234 | break; 235 | case BTN_RIGHT: 236 | pointer_set_button_state(pointer, POINTER_BUTTON_RIGHT, state); 237 | break; 238 | case BTN_MIDDLE: 239 | pointer_set_button_state(pointer, POINTER_BUTTON_MIDDLE, state); 240 | break; 241 | // TODO: More buttons 242 | } 243 | } 244 | 245 | static void pointer_axis(void* data, struct wl_pointer* wl_pointer, uint32_t t, 246 | enum wl_pointer_axis axis, wl_fixed_t value) 247 | { 248 | struct pointer_collection* self = data; 249 | struct pointer* pointer = 250 | pointer_collection_find_wl_pointer(self, wl_pointer); 251 | 252 | if (!pointer->handle_event) 253 | return; 254 | 255 | switch (axis) { 256 | case WL_POINTER_AXIS_VERTICAL_SCROLL: 257 | pointer->vertical_axis_value += wl_fixed_to_double(value); 258 | break; 259 | case WL_POINTER_AXIS_HORIZONTAL_SCROLL: 260 | pointer->horizontal_axis_value += wl_fixed_to_double(value); 261 | break; 262 | default:; 263 | } 264 | } 265 | 266 | static void pointer_axis_source(void* data, struct wl_pointer* wl_pointer, 267 | enum wl_pointer_axis_source source) 268 | { 269 | // TODO 270 | } 271 | 272 | static void pointer_axis_stop(void* data, struct wl_pointer* wl_pointer, 273 | uint32_t t, enum wl_pointer_axis axis) 274 | { 275 | // TODO 276 | } 277 | 278 | static void pointer_axis_discrete(void* data, struct wl_pointer* wl_pointer, 279 | enum wl_pointer_axis axis, int steps) 280 | { 281 | // Deprecated 282 | } 283 | 284 | static void pointer_frame(void* data, struct wl_pointer* wl_pointer) 285 | { 286 | struct pointer_collection* self = data; 287 | struct pointer* pointer = 288 | pointer_collection_find_wl_pointer(self, wl_pointer); 289 | 290 | if (!pointer->handle_event) 291 | return; 292 | 293 | double vertical_steps = trunc(pointer->vertical_axis_value / STEP_SIZE); 294 | pointer->vertical_axis_value -= vertical_steps * STEP_SIZE; 295 | 296 | double horizontal_steps = trunc(pointer->horizontal_axis_value / STEP_SIZE); 297 | pointer->horizontal_axis_value -= horizontal_steps * STEP_SIZE; 298 | 299 | pointer->vertical_scroll_steps += vertical_steps; 300 | pointer->horizontal_scroll_steps += horizontal_steps; 301 | 302 | self->on_frame(self, pointer); 303 | 304 | pointer->vertical_scroll_steps = 0; 305 | pointer->horizontal_scroll_steps = 0; 306 | } 307 | 308 | static struct wl_pointer_listener pointer_listener = { 309 | .enter = pointer_enter, 310 | .leave = pointer_leave, 311 | .motion = pointer_motion, 312 | .button = pointer_button, 313 | .axis = pointer_axis, 314 | .axis_source = pointer_axis_source, 315 | .axis_stop = pointer_axis_stop, 316 | .axis_discrete = pointer_axis_discrete, 317 | .frame = pointer_frame, 318 | }; 319 | 320 | int pointer_collection_add_wl_pointer(struct pointer_collection* self, 321 | struct wl_pointer* wl_pointer, struct seat* seat) 322 | { 323 | struct pointer* pointer = pointer_new(wl_pointer, self->cursor_type, seat); 324 | if (!pointer) 325 | return -1; 326 | 327 | wl_list_insert(&self->pointers, &pointer->link); 328 | wl_pointer_add_listener(pointer->wl_pointer, &pointer_listener, self); 329 | return 0; 330 | } 331 | 332 | void pointer_collection_remove_wl_pointer(struct pointer_collection* self, 333 | struct wl_pointer* wl_pointer) 334 | { 335 | struct pointer* pointer = 336 | pointer_collection_find_wl_pointer(self, wl_pointer); 337 | wl_list_remove(&pointer->link); 338 | free(pointer); 339 | } 340 | -------------------------------------------------------------------------------- /src/region.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | void region_scale(struct pixman_region16* dst, struct pixman_region16* src, 21 | double scale) 22 | { 23 | if (scale == 1.0) { 24 | pixman_region_copy(dst, src); 25 | return; 26 | } 27 | 28 | pixman_region_fini(dst); 29 | pixman_region_init(dst); 30 | 31 | int n_rects = 0; 32 | pixman_box16_t* rects = pixman_region_rectangles(src, &n_rects); 33 | 34 | for (int i = 0; i < n_rects; ++i) { 35 | pixman_box16_t* r = &rects[i]; 36 | 37 | int x1 = floor((double)r->x1 * scale); 38 | int x2 = ceil((double)r->x2 * scale); 39 | int y1 = floor((double)r->y1 * scale); 40 | int y2 = ceil((double)r->y2 * scale); 41 | 42 | pixman_region_union_rect(dst, dst, x1, y1, x2 - x1, y2 - y1); 43 | } 44 | } 45 | 46 | void region_translate(struct pixman_region16* dst, struct pixman_region16* src, 47 | int x, int y) 48 | { 49 | if (x == 0 && y == 0) { 50 | pixman_region_copy(dst, src); 51 | return; 52 | } 53 | 54 | pixman_region_fini(dst); 55 | pixman_region_init(dst); 56 | 57 | int n_rects = 0; 58 | pixman_box16_t* rects = pixman_region_rectangles(src, &n_rects); 59 | 60 | for (int i = 0; i < n_rects; ++i) { 61 | pixman_box16_t* r = &rects[i]; 62 | 63 | int x1 = r->x1 + x; 64 | int x2 = r->x2 + x; 65 | int y1 = r->y1 + y; 66 | int y2 = r->y2 + y; 67 | 68 | pixman_region_union_rect(dst, dst, x1, y1, x2 - x1, y2 - y1); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/renderer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "renderer.h" 18 | #include "buffer.h" 19 | #include "pixels.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | void render_image(struct buffer* dst, const struct image* src) 28 | { 29 | bool ok __attribute__((unused)); 30 | 31 | pixman_format_code_t dst_fmt = 0; 32 | ok = drm_format_to_pixman_fmt(&dst_fmt, dst->format); 33 | assert(ok); 34 | 35 | pixman_format_code_t src_fmt = 0; 36 | ok = drm_format_to_pixman_fmt(&src_fmt, src->format); 37 | assert(ok); 38 | 39 | pixman_image_t* dstimg = pixman_image_create_bits_no_clear(dst_fmt, 40 | dst->width, dst->height, dst->pixels, dst->stride); 41 | 42 | pixman_image_t* srcimg = pixman_image_create_bits_no_clear(src_fmt, 43 | src->width, src->height, src->pixels, src->stride); 44 | 45 | pixman_image_set_clip_region(dstimg, &dst->damage); 46 | 47 | pixman_image_composite(PIXMAN_OP_SRC, srcimg, NULL, dstimg, 48 | 0, 0, 49 | 0, 0, 50 | 0, 0, 51 | dst->width, dst->height); 52 | 53 | pixman_image_unref(srcimg); 54 | pixman_image_unref(dstimg); 55 | 56 | pixman_region_clear(&dst->damage); 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/seat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 - 2020 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "seat.h" 24 | #include "strlcpy.h" 25 | 26 | static void seat_capabilities(void* data, struct wl_seat* wl_seat, 27 | uint32_t capabilities) 28 | { 29 | struct seat* self = data; 30 | 31 | self->capabilities = capabilities; 32 | 33 | if (self->on_capability_change) 34 | self->on_capability_change(self); 35 | } 36 | 37 | static void seat_name(void* data, struct wl_seat* wl_seat, const char* name) 38 | { 39 | struct seat* self = data; 40 | 41 | strlcpy(self->name, name, sizeof(self->name)); 42 | } 43 | 44 | static const struct wl_seat_listener seat_listener = { 45 | .capabilities = seat_capabilities, 46 | .name = seat_name, 47 | }; 48 | 49 | struct seat* seat_new(struct wl_seat* wl_seat, uint32_t id) 50 | { 51 | struct seat* self = calloc(1, sizeof(*self)); 52 | if (!self) 53 | return NULL; 54 | 55 | self->wl_seat = wl_seat; 56 | self->id = id; 57 | 58 | wl_seat_add_listener(wl_seat, &seat_listener, self); 59 | 60 | return self; 61 | } 62 | 63 | void seat_destroy(struct seat* self) 64 | { 65 | wl_seat_destroy(self->wl_seat); 66 | free(self); 67 | } 68 | 69 | void seat_list_destroy(struct wl_list* list) 70 | { 71 | struct seat* seat; 72 | struct seat* tmp; 73 | 74 | wl_list_for_each_safe(seat, tmp, list, link) { 75 | wl_list_remove(&seat->link); 76 | seat_destroy(seat); 77 | } 78 | } 79 | 80 | struct seat* seat_find_by_name(struct wl_list* list, const char* name) 81 | { 82 | struct seat* seat; 83 | 84 | wl_list_for_each(seat, list, link) 85 | if (strcmp(seat->name, name) == 0) 86 | return seat; 87 | 88 | return NULL; 89 | } 90 | 91 | struct seat* seat_find_by_id(struct wl_list* list, uint32_t id) 92 | { 93 | struct seat* seat; 94 | 95 | wl_list_for_each(seat, list, link) 96 | if (seat->id == id) 97 | return seat; 98 | 99 | return NULL; 100 | } 101 | 102 | struct seat* seat_first(struct wl_list* list) 103 | { 104 | struct seat* seat; 105 | 106 | wl_list_for_each(seat, list, link) 107 | return seat; 108 | 109 | return NULL; 110 | } 111 | -------------------------------------------------------------------------------- /src/shm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 - 2020 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "config.h" 24 | 25 | static void randname(char *buf) 26 | { 27 | struct timespec ts; 28 | clock_gettime(CLOCK_REALTIME, &ts); 29 | long r = ts.tv_nsec; 30 | 31 | for (int i = 0; i < 6; ++i) { 32 | buf[i] = 'A' + (r & 15) + (r & 16) * 2; 33 | r >>= 5; 34 | } 35 | } 36 | 37 | static int create_shm_file(void) 38 | { 39 | int retries = 100; 40 | 41 | do { 42 | char name[] = "/wl_shm-XXXXXX"; 43 | randname(name + sizeof(name) - 7); 44 | --retries; 45 | 46 | int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); 47 | if (fd >= 0) { 48 | shm_unlink(name); 49 | return fd; 50 | } 51 | } while (retries > 0 && errno == EEXIST); 52 | 53 | return -1; 54 | } 55 | 56 | int shm_alloc_fd(size_t size) 57 | { 58 | int fd = create_shm_file(); 59 | if (fd < 0) 60 | return -1; 61 | 62 | int ret; 63 | do ret = ftruncate(fd, size); 64 | while (ret < 0 && errno == EINTR); 65 | 66 | if (ret < 0) { 67 | close(fd); 68 | return -1; 69 | } 70 | 71 | return fd; 72 | } 73 | -------------------------------------------------------------------------------- /src/sockets.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022 Andri Yngvasin 3 | * Copyright (C) 2011-2012 Christian Beier 4 | * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 5 | * 6 | * This is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This software is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this software; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 19 | * USA. 20 | */ 21 | 22 | /* 23 | * sockets.c - functions to deal with sockets. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "rfbclient.h" 33 | #include "sockets.h" 34 | #include "tls.h" 35 | #include "sasl.h" 36 | 37 | void run_main_loop_once(void); 38 | 39 | rfbBool errorMessageOnReadFailure = TRUE; 40 | 41 | rfbBool ReadToBuffer(rfbClient* client) { 42 | if (client->buffered == RFB_BUF_SIZE) 43 | return FALSE; 44 | 45 | ssize_t size; 46 | 47 | #if defined(LIBVNCSERVER_HAVE_GNUTLS) || defined(LIBVNCSERVER_HAVE_LIBSSL) 48 | if (client->tlsSession) { 49 | size = ReadFromTLS(client, client->buf + client->buffered, 50 | RFB_BUF_SIZE - client->buffered); 51 | } else 52 | #endif 53 | #ifdef LIBVNCSERVER_HAVE_SASL 54 | if (client->saslconn) { 55 | size = ReadFromSASL(client, client->buf + client->buffered, 56 | RFB_BUF_SIZE - client->buffered); 57 | } else 58 | #endif 59 | { 60 | size = recv(client->sock, client->buf + client->buffered, 61 | RFB_BUF_SIZE - client->buffered, MSG_DONTWAIT); 62 | } 63 | 64 | if (size == 0) 65 | return FALSE; 66 | 67 | if (size > 0) 68 | client->buffered += size; 69 | 70 | return TRUE; 71 | } 72 | 73 | rfbBool ReadFromRFBServer(rfbClient* client, char *out, unsigned int n) 74 | { 75 | if (!out) 76 | return FALSE; 77 | 78 | while (n != 0) { 79 | while (n != 0 && client->buffered == 0) { 80 | run_main_loop_once(); 81 | if (!ReadToBuffer(client)) 82 | return FALSE; 83 | } 84 | 85 | unsigned int size = MIN(client->buffered, n); 86 | memcpy(out, client->buf, size); 87 | 88 | client->buffered -= size; 89 | memmove(client->buf, client->buf + size, client->buffered); 90 | 91 | out += size; 92 | n -= size; 93 | } 94 | 95 | return TRUE; 96 | } 97 | 98 | /* 99 | * Write an exact number of bytes, and don't return until you've sent them. 100 | */ 101 | rfbBool 102 | WriteToRFBServer(rfbClient* client, const char *buf, unsigned int n) 103 | { 104 | struct pollfd fds; 105 | int i = 0; 106 | int j; 107 | const char *obuf = buf; 108 | #ifdef LIBVNCSERVER_HAVE_SASL 109 | const char *output; 110 | unsigned int outputlen; 111 | int err; 112 | #endif /* LIBVNCSERVER_HAVE_SASL */ 113 | 114 | if (client->tlsSession) { 115 | /* WriteToTLS() will guarantee either everything is written, or error/eof returns */ 116 | i = WriteToTLS(client, buf, n); 117 | if (i <= 0) return FALSE; 118 | 119 | return TRUE; 120 | } 121 | #ifdef LIBVNCSERVER_HAVE_SASL 122 | if (client->saslconn) { 123 | err = sasl_encode(client->saslconn, 124 | buf, n, 125 | &output, &outputlen); 126 | if (err != SASL_OK) { 127 | rfbClientLog("Failed to encode SASL data %s", 128 | sasl_errstring(err, NULL, NULL)); 129 | return FALSE; 130 | } 131 | obuf = output; 132 | n = outputlen; 133 | } 134 | #endif /* LIBVNCSERVER_HAVE_SASL */ 135 | 136 | // TODO: Dispatch events while waiting 137 | while (i < n) { 138 | j = write(client->sock, obuf + i, (n - i)); 139 | if (j > 0) { 140 | i += j; 141 | continue; 142 | } 143 | 144 | if (j == 0) { 145 | rfbClientLog("write failed\n"); 146 | return FALSE; 147 | } 148 | 149 | if (errno != EWOULDBLOCK && errno != EAGAIN) { 150 | rfbClientErr("write\n"); 151 | return FALSE; 152 | } 153 | 154 | fds.fd = client->sock; 155 | fds.events = POLLOUT; 156 | if (poll(&fds, 1, -1) <= 0) { 157 | rfbClientErr("poll\n"); 158 | return FALSE; 159 | } 160 | } 161 | 162 | return TRUE; 163 | } 164 | 165 | static rfbBool WaitForConnected(int socket, unsigned int secs) 166 | { 167 | struct pollfd fds = { 168 | .fd = socket, 169 | .events = POLLIN | POLLOUT | POLLERR | POLLHUP, 170 | }; 171 | 172 | if (poll(&fds, 1, secs * 1000) != 1) 173 | return FALSE; 174 | 175 | int so_error = 0; 176 | socklen_t len = sizeof(so_error); 177 | getsockopt(socket, SOL_SOCKET, SO_ERROR, &so_error, &len); 178 | 179 | return so_error == 0 ? TRUE : FALSE; 180 | } 181 | 182 | rfbSocket 183 | ConnectClientToTcpAddr6(const char *hostname, int port) 184 | { 185 | rfbSocket sock = ConnectClientToTcpAddr6WithTimeout(hostname, port, DEFAULT_CONNECT_TIMEOUT); 186 | /* put socket back into blocking mode for compatibility reasons */ 187 | if (sock != RFB_INVALID_SOCKET) { 188 | SetBlocking(sock); 189 | } 190 | return sock; 191 | } 192 | 193 | rfbSocket 194 | ConnectClientToTcpAddr6WithTimeout(const char *hostname, int port, unsigned int timeout) 195 | { 196 | rfbSocket sock; 197 | int n; 198 | struct addrinfo hints, *res, *ressave; 199 | char port_s[10]; 200 | int one = 1; 201 | 202 | snprintf(port_s, 10, "%d", port); 203 | memset(&hints, 0, sizeof(struct addrinfo)); 204 | hints.ai_family = AF_UNSPEC; 205 | hints.ai_socktype = SOCK_STREAM; 206 | if ((n = getaddrinfo(strcmp(hostname,"") == 0 ? "localhost": hostname, port_s, &hints, &res))) 207 | { 208 | rfbClientErr("ConnectClientToTcpAddr6: getaddrinfo (%s)\n", gai_strerror(n)); 209 | return RFB_INVALID_SOCKET; 210 | } 211 | 212 | ressave = res; 213 | sock = RFB_INVALID_SOCKET; 214 | while (res) 215 | { 216 | sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 217 | if (sock != RFB_INVALID_SOCKET) 218 | { 219 | if (SetNonBlocking(sock)) { 220 | if (connect(sock, res->ai_addr, res->ai_addrlen) == 0) { 221 | break; 222 | } else { 223 | if ((errno == EWOULDBLOCK || errno == EINPROGRESS) && WaitForConnected(sock, timeout)) 224 | break; 225 | rfbCloseSocket(sock); 226 | sock = RFB_INVALID_SOCKET; 227 | } 228 | } else { 229 | rfbCloseSocket(sock); 230 | sock = RFB_INVALID_SOCKET; 231 | } 232 | } 233 | res = res->ai_next; 234 | } 235 | freeaddrinfo(ressave); 236 | 237 | if (sock == RFB_INVALID_SOCKET) 238 | { 239 | rfbClientErr("ConnectClientToTcpAddr6: connect\n"); 240 | return RFB_INVALID_SOCKET; 241 | } 242 | 243 | if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, 244 | (char *)&one, sizeof(one)) < 0) { 245 | rfbClientErr("ConnectToTcpAddr: setsockopt\n"); 246 | rfbCloseSocket(sock); 247 | return RFB_INVALID_SOCKET; 248 | } 249 | 250 | return sock; 251 | } 252 | 253 | rfbSocket 254 | ConnectClientToUnixSock(const char *sockFile) 255 | { 256 | rfbSocket sock = ConnectClientToUnixSockWithTimeout(sockFile, DEFAULT_CONNECT_TIMEOUT); 257 | /* put socket back into blocking mode for compatibility reasons */ 258 | if (sock != RFB_INVALID_SOCKET) { 259 | SetBlocking(sock); 260 | } 261 | return sock; 262 | } 263 | 264 | rfbSocket 265 | ConnectClientToUnixSockWithTimeout(const char *sockFile, unsigned int timeout) 266 | { 267 | rfbSocket sock; 268 | struct sockaddr_un addr; 269 | addr.sun_family = AF_UNIX; 270 | if(strlen(sockFile) + 1 > sizeof(addr.sun_path)) { 271 | rfbClientErr("ConnectToUnixSock: socket file name too long\n"); 272 | return RFB_INVALID_SOCKET; 273 | } 274 | strcpy(addr.sun_path, sockFile); 275 | 276 | sock = socket(AF_UNIX, SOCK_STREAM, 0); 277 | if (sock == RFB_INVALID_SOCKET) { 278 | rfbClientErr("ConnectToUnixSock: socket (%s)\n",strerror(errno)); 279 | return RFB_INVALID_SOCKET; 280 | } 281 | 282 | if (!SetNonBlocking(sock)) 283 | return RFB_INVALID_SOCKET; 284 | 285 | if (connect(sock, (struct sockaddr *)&addr, sizeof(addr.sun_family) + strlen(addr.sun_path)) < 0 && 286 | !(errno == EINPROGRESS && WaitForConnected(sock, timeout))) { 287 | rfbClientErr("ConnectToUnixSock: connect\n"); 288 | rfbCloseSocket(sock); 289 | return RFB_INVALID_SOCKET; 290 | } 291 | 292 | return sock; 293 | } 294 | 295 | 296 | /* 297 | * SetNonBlocking sets a socket into non-blocking mode. 298 | */ 299 | 300 | rfbBool 301 | SetNonBlocking(rfbSocket sock) 302 | { 303 | int flags = fcntl(sock, F_GETFL); 304 | if(flags < 0 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) { 305 | rfbClientErr("Setting socket to non-blocking failed: %s\n",strerror(errno)); 306 | return FALSE; 307 | } 308 | return TRUE; 309 | } 310 | 311 | 312 | rfbBool SetBlocking(rfbSocket sock) 313 | { 314 | int flags = fcntl(sock, F_GETFL); 315 | if(flags < 0 || fcntl(sock, F_SETFL, flags & ~O_NONBLOCK) < 0) { 316 | rfbClientErr("Setting socket to blocking failed: %s\n",strerror(errno)); 317 | return FALSE; 318 | } 319 | return TRUE; 320 | } 321 | 322 | 323 | /* 324 | * SetDSCP sets a socket's IP QoS parameters aka Differentiated Services Code Point field 325 | */ 326 | 327 | rfbBool 328 | SetDSCP(rfbSocket sock, int dscp) 329 | { 330 | int level, cmd; 331 | struct sockaddr addr; 332 | socklen_t addrlen = sizeof(addr); 333 | 334 | if(getsockname(sock, &addr, &addrlen) != 0) { 335 | rfbClientErr("Setting socket QoS failed while getting socket address: %s\n",strerror(errno)); 336 | return FALSE; 337 | } 338 | 339 | switch(addr.sa_family) 340 | { 341 | case AF_INET6: 342 | level = IPPROTO_IPV6; 343 | cmd = IPV6_TCLASS; 344 | break; 345 | case AF_INET: 346 | level = IPPROTO_IP; 347 | cmd = IP_TOS; 348 | break; 349 | default: 350 | rfbClientErr("Setting socket QoS failed: Not bound to IP address"); 351 | return FALSE; 352 | } 353 | 354 | if(setsockopt(sock, level, cmd, (void*)&dscp, sizeof(dscp)) != 0) { 355 | rfbClientErr("Setting socket QoS failed: %s\n", strerror(errno)); 356 | return FALSE; 357 | } 358 | 359 | return TRUE; 360 | } 361 | 362 | 363 | 364 | /* 365 | * Test if the other end of a socket is on the same machine. 366 | */ 367 | 368 | rfbBool 369 | SameMachine(rfbSocket sock) 370 | { 371 | struct sockaddr_in peeraddr, myaddr; 372 | socklen_t addrlen = sizeof(struct sockaddr_in); 373 | 374 | getpeername(sock, (struct sockaddr *)&peeraddr, &addrlen); 375 | getsockname(sock, (struct sockaddr *)&myaddr, &addrlen); 376 | 377 | return (peeraddr.sin_addr.s_addr == myaddr.sin_addr.s_addr); 378 | } 379 | -------------------------------------------------------------------------------- /src/strlcpy.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strlcpy.c,v 1.13 2015/08/31 02:53:57 guenther Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1998, 2015 Todd C. Miller 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | /* 23 | * Copy string src to buffer dst of size dsize. At most dsize-1 24 | * chars will be copied. Always NUL terminates (unless dsize == 0). 25 | * Returns strlen(src); if retval >= dsize, truncation occurred. 26 | */ 27 | size_t 28 | strlcpy(char *dst, const char *src, size_t dsize) 29 | { 30 | const char *osrc = src; 31 | size_t nleft = dsize; 32 | 33 | /* Copy as many bytes as will fit. */ 34 | if (nleft != 0) { 35 | while (--nleft != 0) { 36 | if ((*dst++ = *src++) == '\0') 37 | break; 38 | } 39 | } 40 | 41 | /* Not enough room in dst, add NUL and traverse rest of src. */ 42 | if (nleft == 0) { 43 | if (dsize != 0) 44 | *dst = '\0'; /* NUL-terminate dst */ 45 | while (*src++) 46 | ; 47 | } 48 | 49 | return(src - osrc - 1); /* count does not include NUL */ 50 | } 51 | -------------------------------------------------------------------------------- /src/tls_none.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Christian Beier. 3 | * 4 | * This is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This software is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this software; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 17 | * USA. 18 | */ 19 | 20 | #include "rfbclient.h" 21 | #include "tls.h" 22 | 23 | #include 24 | 25 | rfbBool HandleAnonTLSAuth(rfbClient* client) 26 | { 27 | rfbClientLog("TLS is not supported.\n"); 28 | return FALSE; 29 | } 30 | 31 | 32 | rfbBool HandleVeNCryptAuth(rfbClient* client) 33 | { 34 | rfbClientLog("TLS is not supported.\n"); 35 | return FALSE; 36 | } 37 | 38 | 39 | int ReadFromTLS(rfbClient* client, char *out, unsigned int n) 40 | { 41 | rfbClientLog("TLS is not supported.\n"); 42 | errno = EINTR; 43 | return -1; 44 | } 45 | 46 | 47 | int WriteToTLS(rfbClient* client, const char *buf, unsigned int n) 48 | { 49 | rfbClientLog("TLS is not supported.\n"); 50 | errno = EINTR; 51 | return -1; 52 | } 53 | 54 | 55 | void FreeTLS(rfbClient* client) 56 | { 57 | 58 | } 59 | 60 | #ifdef LIBVNCSERVER_HAVE_SASL 61 | int 62 | GetTLSCipherBits(rfbClient* client) 63 | { 64 | rfbClientLog("TLS is not supported.\n"); 65 | return 0; 66 | } 67 | #endif /* LIBVNCSERVER_HAVE_SASL */ 68 | 69 | -------------------------------------------------------------------------------- /src/vnc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 - 2022 Andri Yngvason 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 9 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 | * PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "rfbclient.h" 28 | #include "vnc.h" 29 | #include "open-h264.h" 30 | #include "usdt.h" 31 | 32 | #define RFB_ENCODING_OPEN_H264 50 33 | #define RFB_ENCODING_PTS -1000 34 | 35 | #define NO_PTS UINT64_MAX 36 | 37 | extern const unsigned short code_map_linux_to_qnum[]; 38 | extern const unsigned int code_map_linux_to_qnum_len; 39 | 40 | static uint64_t vnc_client_htonll(uint64_t x) 41 | { 42 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 43 | return __builtin_bswap64(x); 44 | #else 45 | return x; 46 | #endif 47 | } 48 | 49 | static bool vnc_client_lock_handler(struct vnc_client* self) 50 | { 51 | if (self->handler_lock) 52 | return false; 53 | 54 | self->handler_lock = true; 55 | return true; 56 | } 57 | 58 | static void vnc_client_unlock_handler(struct vnc_client* self) 59 | { 60 | assert(self->handler_lock); 61 | self->handler_lock = false; 62 | } 63 | 64 | static rfbBool vnc_client_alloc_fb(rfbClient* client) 65 | { 66 | struct vnc_client* self = rfbClientGetClientData(client, NULL); 67 | assert(self); 68 | 69 | return self->alloc_fb(self) < 0 ? FALSE : TRUE; 70 | } 71 | 72 | static void vnc_client_update_box(rfbClient* client, int x, int y, int width, 73 | int height) 74 | { 75 | struct vnc_client* self = rfbClientGetClientData(client, NULL); 76 | assert(self); 77 | 78 | if (self->current_rect_is_av_frame) { 79 | self->current_rect_is_av_frame = false; 80 | return; 81 | } 82 | 83 | pixman_region_union_rect(&self->damage, &self->damage, x, y, width, 84 | height); 85 | } 86 | 87 | static void vnc_client_clear_av_frames(struct vnc_client* self) 88 | { 89 | for (int i = 0; i < self->n_av_frames; ++i) { 90 | av_frame_unref(self->av_frames[i]->frame); 91 | av_frame_free(&self->av_frames[i]->frame); 92 | free(self->av_frames[i]); 93 | } 94 | self->n_av_frames = 0; 95 | } 96 | 97 | static void vnc_client_start_update(rfbClient* client) 98 | { 99 | struct vnc_client* self = rfbClientGetClientData(client, NULL); 100 | assert(self); 101 | 102 | self->pts = NO_PTS; 103 | pixman_region_clear(&self->damage); 104 | vnc_client_clear_av_frames(self); 105 | 106 | self->is_updating = true; 107 | } 108 | 109 | static void vnc_client_cancel_update(rfbClient* client) 110 | { 111 | struct vnc_client* self = rfbClientGetClientData(client, NULL); 112 | assert(self); 113 | 114 | self->is_updating = false; 115 | } 116 | 117 | static void vnc_client_finish_update(rfbClient* client) 118 | { 119 | struct vnc_client* self = rfbClientGetClientData(client, NULL); 120 | assert(self); 121 | 122 | DTRACE_PROBE2(wlvncc, vnc_client_finish_update, client, self->pts); 123 | 124 | self->is_updating = false; 125 | 126 | self->update_fb(self); 127 | } 128 | 129 | static void vnc_client_got_cut_text(rfbClient* client, const char* text, 130 | int len) 131 | { 132 | struct vnc_client* self = rfbClientGetClientData(client, NULL); 133 | assert(self); 134 | 135 | if (self->cut_text) 136 | self->cut_text(self, text, len); 137 | } 138 | 139 | static rfbBool vnc_client_handle_open_h264_rect(rfbClient* client, 140 | rfbFramebufferUpdateRectHeader* rect_header) 141 | { 142 | if ((int)rect_header->encoding != RFB_ENCODING_OPEN_H264) 143 | return FALSE; 144 | 145 | struct vnc_client* self = rfbClientGetClientData(client, NULL); 146 | assert(self); 147 | 148 | if (!self->open_h264) 149 | self->open_h264 = open_h264_create(client); 150 | 151 | if (!self->open_h264) 152 | return false; 153 | 154 | AVFrame* frame = open_h264_decode_rect(self->open_h264, rect_header); 155 | if (!frame) 156 | return false; 157 | 158 | assert(self->n_av_frames < VNC_CLIENT_MAX_AV_FRAMES); 159 | 160 | struct vnc_av_frame* f = calloc(1, sizeof(*f)); 161 | if (!f) { 162 | av_frame_unref(frame); 163 | av_frame_free(&frame); 164 | return false; 165 | } 166 | 167 | f->frame = frame; 168 | f->x = rect_header->r.x; 169 | f->y = rect_header->r.y; 170 | f->width = rect_header->r.w; 171 | f->height = rect_header->r.h; 172 | 173 | self->av_frames[self->n_av_frames++] = f; 174 | 175 | self->current_rect_is_av_frame = true; 176 | return true; 177 | } 178 | 179 | static void vnc_client_init_open_h264(void) 180 | { 181 | static int encodings[] = { RFB_ENCODING_OPEN_H264, 0 }; 182 | static rfbClientProtocolExtension ext = { 183 | .encodings = encodings, 184 | .handleEncoding = vnc_client_handle_open_h264_rect, 185 | }; 186 | rfbClientRegisterExtension(&ext); 187 | } 188 | 189 | static rfbBool vnc_client_handle_pts_rect(rfbClient* client, 190 | rfbFramebufferUpdateRectHeader* rect_header) 191 | { 192 | if ((int)rect_header->encoding != RFB_ENCODING_PTS) 193 | return FALSE; 194 | 195 | struct vnc_client* self = rfbClientGetClientData(client, NULL); 196 | assert(self); 197 | 198 | uint64_t pts_msg = 0; 199 | if (!ReadFromRFBServer(self->client, (char*)&pts_msg, sizeof(pts_msg))) 200 | return FALSE; 201 | 202 | self->pts = vnc_client_htonll(pts_msg); 203 | 204 | DTRACE_PROBE1(wlvncc, vnc_client_handle_pts_rect, self->pts); 205 | 206 | return TRUE; 207 | } 208 | 209 | static void vnc_client_init_pts_ext(void) 210 | { 211 | static int encodings[] = { RFB_ENCODING_PTS, 0 }; 212 | static rfbClientProtocolExtension ext = { 213 | .encodings = encodings, 214 | .handleEncoding = vnc_client_handle_pts_rect, 215 | }; 216 | rfbClientRegisterExtension(&ext); 217 | } 218 | 219 | struct vnc_client* vnc_client_create(void) 220 | { 221 | vnc_client_init_open_h264(); 222 | vnc_client_init_pts_ext(); 223 | 224 | struct vnc_client* self = calloc(1, sizeof(*self)); 225 | if (!self) 226 | return NULL; 227 | 228 | /* These are defaults that can be changed with 229 | * vnc_client_set_pixel_format(). 230 | */ 231 | int bits_per_sample = 8; 232 | int samples_per_pixel = 3; 233 | int bytes_per_pixel = 4; 234 | 235 | rfbClient* client = rfbGetClient(bits_per_sample, samples_per_pixel, 236 | bytes_per_pixel); 237 | if (!client) 238 | goto failure; 239 | 240 | self->client = client; 241 | rfbClientSetClientData(client, NULL, self); 242 | 243 | client->MallocFrameBuffer = vnc_client_alloc_fb; 244 | client->GotFrameBufferUpdate = vnc_client_update_box; 245 | client->FinishedFrameBufferUpdate = vnc_client_finish_update; 246 | client->StartingFrameBufferUpdate = vnc_client_start_update; 247 | client->CancelledFrameBufferUpdate = vnc_client_cancel_update; 248 | client->GotXCutText = vnc_client_got_cut_text; 249 | 250 | self->pts = NO_PTS; 251 | 252 | return self; 253 | 254 | failure: 255 | free(self); 256 | return NULL; 257 | } 258 | 259 | void vnc_client_destroy(struct vnc_client* self) 260 | { 261 | vnc_client_clear_av_frames(self); 262 | open_h264_destroy(self->open_h264); 263 | rfbClientCleanup(self->client); 264 | free(self); 265 | } 266 | 267 | int vnc_client_connect(struct vnc_client* self, const char* address, int port) 268 | { 269 | rfbClient* client = self->client; 270 | 271 | // This is needed for TLS authentication. TODO: Clean up 272 | free(client->serverHost); 273 | client->serverHost = strdup(address); 274 | 275 | return ConnectToRFBServer(client, address, port) ? 0 : -1; 276 | } 277 | 278 | int vnc_client_init(struct vnc_client* self) 279 | { 280 | int rc = -1; 281 | rfbClient* client = self->client; 282 | 283 | vnc_client_lock_handler(self); 284 | 285 | if (!InitialiseRFBConnection(client)) 286 | goto failure; 287 | 288 | client->width = client->si.framebufferWidth; 289 | client->height = client->si.framebufferHeight; 290 | 291 | if (!client->MallocFrameBuffer(client)) 292 | goto failure; 293 | 294 | if (!SetFormatAndEncodings(client)) 295 | goto failure; 296 | 297 | if (client->updateRect.x < 0) { 298 | client->updateRect.x = client->updateRect.y = 0; 299 | client->updateRect.w = client->width; 300 | client->updateRect.h = client->height; 301 | } 302 | 303 | if (!SendFramebufferUpdateRequest(client, 304 | client->updateRect.x, client->updateRect.y, 305 | client->updateRect.w, client->updateRect.h, 306 | FALSE)) 307 | goto failure; 308 | 309 | SendIncrementalFramebufferUpdateRequest(client); 310 | SendIncrementalFramebufferUpdateRequest(client); 311 | 312 | rc = 0; 313 | failure: 314 | vnc_client_unlock_handler(self); 315 | return rc; 316 | } 317 | 318 | int vnc_client_set_pixel_format(struct vnc_client* self, uint32_t format) 319 | { 320 | rfbPixelFormat* dst = &self->client->format; 321 | int bpp = -1; 322 | 323 | switch (format) { 324 | case DRM_FORMAT_ARGB8888: 325 | case DRM_FORMAT_XRGB8888: 326 | dst->redShift = 16; 327 | dst->greenShift = 8; 328 | dst->blueShift = 0; 329 | bpp = 32; 330 | break; 331 | case DRM_FORMAT_ABGR8888: 332 | case DRM_FORMAT_XBGR8888: 333 | dst->redShift = 0; 334 | dst->greenShift = 8; 335 | dst->blueShift = 16; 336 | bpp = 32; 337 | break; 338 | default: 339 | return -1; 340 | } 341 | 342 | switch (bpp) { 343 | case 32: 344 | dst->bitsPerPixel = 32; 345 | dst->depth = 24; 346 | dst->redMax = 0xff; 347 | dst->greenMax = 0xff; 348 | dst->blueMax = 0xff; 349 | break; 350 | default: 351 | abort(); 352 | } 353 | 354 | dst->trueColour = 1; 355 | dst->bigEndian = FALSE; 356 | self->client->appData.requestedDepth = dst->depth; 357 | 358 | return 0; 359 | } 360 | 361 | int vnc_client_get_width(const struct vnc_client* self) 362 | { 363 | return self->client->width; 364 | } 365 | 366 | int vnc_client_get_height(const struct vnc_client* self) 367 | { 368 | return self->client->height; 369 | } 370 | 371 | int vnc_client_get_stride(const struct vnc_client* self) 372 | { 373 | // TODO: What happens if bitsPerPixel == 24? 374 | return self->client->width * self->client->format.bitsPerPixel / 8; 375 | } 376 | 377 | void* vnc_client_get_fb(const struct vnc_client* self) 378 | { 379 | return self->client->frameBuffer; 380 | } 381 | 382 | void vnc_client_set_fb(struct vnc_client* self, void* fb) 383 | { 384 | self->client->frameBuffer = fb; 385 | } 386 | 387 | int vnc_client_get_fd(const struct vnc_client* self) 388 | { 389 | return self->client->sock; 390 | } 391 | 392 | const char* vnc_client_get_desktop_name(const struct vnc_client* self) 393 | { 394 | return self->client->desktopName; 395 | } 396 | 397 | int vnc_client_process(struct vnc_client* self) 398 | { 399 | if (!ReadToBuffer(self->client)) 400 | return -1; 401 | 402 | if (!vnc_client_lock_handler(self)) 403 | return 0; 404 | 405 | int rc; 406 | while (self->client->buffered > 0) { 407 | rc = HandleRFBServerMessage(self->client) ? 0 : -1; 408 | if (rc < 0) 409 | break; 410 | } 411 | 412 | vnc_client_unlock_handler(self); 413 | return rc; 414 | } 415 | 416 | void vnc_client_send_pointer_event(struct vnc_client* self, int x, int y, 417 | uint32_t button_mask) 418 | { 419 | SendPointerEvent(self->client, x, y, button_mask); 420 | } 421 | 422 | void vnc_client_send_keyboard_event(struct vnc_client* self, uint32_t symbol, 423 | uint32_t code, bool is_pressed) 424 | { 425 | if (code >= code_map_linux_to_qnum_len) 426 | return; 427 | 428 | uint32_t qnum = code_map_linux_to_qnum[code]; 429 | if (!qnum) 430 | qnum = code; 431 | 432 | if (!SendExtendedKeyEvent(self->client, symbol, qnum, is_pressed)) 433 | SendKeyEvent(self->client, symbol, is_pressed); 434 | } 435 | 436 | void vnc_client_set_encodings(struct vnc_client* self, const char* encodings) 437 | { 438 | self->client->appData.encodingsString = encodings; 439 | } 440 | 441 | void vnc_client_set_quality_level(struct vnc_client* self, int value) 442 | { 443 | self->client->appData.qualityLevel = value; 444 | } 445 | 446 | void vnc_client_set_compression_level(struct vnc_client* self, int value) 447 | { 448 | self->client->appData.compressLevel = value; 449 | } 450 | 451 | void vnc_client_send_cut_text(struct vnc_client* self, const char* text, 452 | size_t len) 453 | { 454 | // libvncclient doesn't modify text, so typecast is OK. 455 | SendClientCutText(self->client, (char*)text, len); 456 | } 457 | --------------------------------------------------------------------------------