├── .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 |
--------------------------------------------------------------------------------