Create an interface
parent
f31b5a6915
commit
33324c9373
10
Makefile
10
Makefile
|
@ -1,14 +1,14 @@
|
||||||
all: neatvnc
|
all: libneatvnc.so.0.0
|
||||||
|
|
||||||
DEPENDENCIES := pixman-1 libpng libuv
|
DEPENDENCIES := pixman-1 libpng libuv
|
||||||
|
|
||||||
CFLAGS := -g -O3 -DNDEBUG -std=gnu11 -D_GNU_SOURCE -Iinc \
|
CFLAGS := -g -O3 -mavx2 -DNDEBUG -std=gnu11 -D_GNU_SOURCE -Iinc -fvisibility=hidden \
|
||||||
$(foreach dep,$(DEPENDENCIES),$(shell pkg-config --cflags $(dep)))
|
$(foreach dep,$(DEPENDENCIES),$(shell pkg-config --cflags $(dep)))
|
||||||
|
|
||||||
LDFLAGS := $(foreach dep,$(DEPENDENCIES),$(shell pkg-config --libs $(dep)))
|
LDFLAGS := $(foreach dep,$(DEPENDENCIES),$(shell pkg-config --libs $(dep)))
|
||||||
|
|
||||||
neatvnc: src/server.o src/util.o src/vec.o src/zrle.o src/pngfb.o
|
libneatvnc.so.0.0: src/server.o src/util.o src/vec.o src/zrle.o src/pngfb.o
|
||||||
$(CC) $^ $(LDFLAGS) -o $@
|
$(CC) -fPIC -shared $^ $(LDFLAGS) -o $@
|
||||||
|
|
||||||
zrle-bench: bench/zrle-bench.o src/server.o src/util.o src/vec.o src/zrle.o \
|
zrle-bench: bench/zrle-bench.o src/server.o src/util.o src/vec.o src/zrle.o \
|
||||||
src/pngfb.o
|
src/pngfb.o
|
||||||
|
@ -22,7 +22,7 @@ bench/%.o: bench/%.c
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
rm -f neatvnc
|
rm -f libneatvnc.so.0.0
|
||||||
rm -f src/*.o src/*.deps bench/*.o bench/*.deps
|
rm -f src/*.o src/*.deps bench/*.o bench/*.deps
|
||||||
|
|
||||||
-include src/*.deps
|
-include src/*.deps
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
//#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
struct nvnc;
|
||||||
|
struct pixman_region16;
|
||||||
|
|
||||||
|
enum nvnc_button_mask {
|
||||||
|
NVNC_BUTTON_LEFT = 1 << 0,
|
||||||
|
NVNC_BUTTON_MIDDLE = 1 << 1,
|
||||||
|
NVNC_BUTTON_RIGHT = 1 << 2,
|
||||||
|
NVNC_SCROLL_UP = 1 << 3,
|
||||||
|
NVNC_SCROLL_DOWN = 1 << 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nvnc_fb {
|
||||||
|
void *addr;
|
||||||
|
uint32_t size;
|
||||||
|
uint16_t width;
|
||||||
|
uint16_t height;
|
||||||
|
uint32_t fourcc_format;
|
||||||
|
uint64_t fourcc_modifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*nvnc_key_fn)(struct nvnc*, uint32_t keysym, bool is_pressed);
|
||||||
|
typedef void (*nvnc_pointer_fn)(struct nvnc*, uint16_t x, uint16_t y,
|
||||||
|
enum nvnc_button_mask);
|
||||||
|
typedef void (*nvnc_fb_req_fn)(struct nvnc*, bool is_incremental,
|
||||||
|
uint16_t x, uint16_t y,
|
||||||
|
uint16_t width, uint16_t height);
|
||||||
|
|
||||||
|
struct nvnc *nvnc_open(const char *addr, uint16_t port);
|
||||||
|
void nvnc_close(struct nvnc *self);
|
||||||
|
|
||||||
|
void nvnc_set_userdata(struct nvnc *self, void* userdata);
|
||||||
|
void* nvnc_get_userdata(struct nvnc *self);
|
||||||
|
|
||||||
|
void nvnc_set_key_fn(struct nvnc *self, nvnc_key_fn);
|
||||||
|
void nvnc_set_pointer_fn(struct nvnc *self, nvnc_pointer_fn);
|
||||||
|
void nvnc_set_fb_req_fn(struct nvnc *self, nvnc_fb_req_fn);
|
||||||
|
|
||||||
|
int nvnc_update_fb(struct nvnc *self, const struct nvnc_fb* fb,
|
||||||
|
const struct pixman_region16* region);
|
188
src/server.c
188
src/server.c
|
@ -2,6 +2,7 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "zrle.h"
|
#include "zrle.h"
|
||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
|
#include "neatvnc.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -14,6 +15,8 @@
|
||||||
#define READ_BUFFER_SIZE 4096
|
#define READ_BUFFER_SIZE 4096
|
||||||
#define MSG_BUFFER_SIZE 4096
|
#define MSG_BUFFER_SIZE 4096
|
||||||
|
|
||||||
|
#define EXPORT __attribute__((visibility("default")))
|
||||||
|
|
||||||
enum vnc_encodings {
|
enum vnc_encodings {
|
||||||
VNC_ENCODING_RAW = 1 << 0,
|
VNC_ENCODING_RAW = 1 << 0,
|
||||||
VNC_ENCODING_COPYRECT = 1 << 1,
|
VNC_ENCODING_COPYRECT = 1 << 1,
|
||||||
|
@ -33,16 +36,17 @@ enum vnc_client_state {
|
||||||
VNC_CLIENT_STATE_READY,
|
VNC_CLIENT_STATE_READY,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vnc_server;
|
struct nvnc;
|
||||||
|
|
||||||
struct vnc_client {
|
struct vnc_client {
|
||||||
uv_tcp_t stream_handle;
|
uv_tcp_t stream_handle;
|
||||||
struct vnc_server *server;
|
struct nvnc *server;
|
||||||
enum vnc_client_state state;
|
enum vnc_client_state state;
|
||||||
uint32_t fourcc;
|
uint32_t fourcc;
|
||||||
struct rfb_pixel_format pixfmt;
|
struct rfb_pixel_format pixfmt;
|
||||||
enum vnc_encodings encodings;
|
enum vnc_encodings encodings;
|
||||||
LIST_ENTRY(vnc_client) link;
|
LIST_ENTRY(vnc_client) link;
|
||||||
|
struct pixman_region16 requested_region;
|
||||||
size_t buffer_index;
|
size_t buffer_index;
|
||||||
size_t buffer_len;
|
size_t buffer_len;
|
||||||
uint8_t msg_buffer[MSG_BUFFER_SIZE];
|
uint8_t msg_buffer[MSG_BUFFER_SIZE];
|
||||||
|
@ -57,11 +61,15 @@ struct vnc_display {
|
||||||
char *name;
|
char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vnc_server {
|
struct nvnc {
|
||||||
uv_tcp_t tcp_handle;
|
uv_tcp_t tcp_handle;
|
||||||
struct vnc_client_list clients;
|
struct vnc_client_list clients;
|
||||||
struct vnc_display display;
|
struct vnc_display display;
|
||||||
struct vnc_framebuffer* fb;
|
struct vnc_framebuffer* fb;
|
||||||
|
void *userdata;
|
||||||
|
nvnc_key_fn key_fn;
|
||||||
|
nvnc_pointer_fn pointer_fn;
|
||||||
|
nvnc_fb_req_fn fb_req_fn;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char* fourcc_to_string(uint32_t fourcc)
|
static const char* fourcc_to_string(uint32_t fourcc)
|
||||||
|
@ -91,6 +99,7 @@ static void cleanup_client(uv_handle_t* handle)
|
||||||
struct vnc_client *client = (struct vnc_client*)handle;
|
struct vnc_client *client = (struct vnc_client*)handle;
|
||||||
|
|
||||||
LIST_REMOVE(client, link);
|
LIST_REMOVE(client, link);
|
||||||
|
pixman_region_fini(&client->requested_region);
|
||||||
free(client);
|
free(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,7 +362,7 @@ uint32_t rfb_pixfmt_to_fourcc(const struct rfb_pixel_format *fmt)
|
||||||
|
|
||||||
static void send_server_init_message(struct vnc_client *client)
|
static void send_server_init_message(struct vnc_client *client)
|
||||||
{
|
{
|
||||||
struct vnc_server *server = client->server;
|
struct nvnc *server = client->server;
|
||||||
struct vnc_display *display = &server->display;
|
struct vnc_display *display = &server->display;
|
||||||
|
|
||||||
size_t name_len = strlen(display->name);
|
size_t name_len = strlen(display->name);
|
||||||
|
@ -451,14 +460,10 @@ static int on_client_set_encodings(struct vnc_client *client)
|
||||||
return sizeof(*msg) + 4 * n_encodings;
|
return sizeof(*msg) + 4 * n_encodings;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_done= 0;
|
|
||||||
|
|
||||||
static int on_client_fb_update_request(struct vnc_client *client)
|
static int on_client_fb_update_request(struct vnc_client *client)
|
||||||
{
|
{
|
||||||
|
struct nvnc *server = client->server;
|
||||||
|
|
||||||
if (is_done)
|
|
||||||
return 0;
|
|
||||||
is_done = 1;
|
|
||||||
struct rfb_client_fb_update_req_msg *msg =
|
struct rfb_client_fb_update_req_msg *msg =
|
||||||
(struct rfb_client_fb_update_req_msg*)(client->msg_buffer +
|
(struct rfb_client_fb_update_req_msg*)(client->msg_buffer +
|
||||||
client->buffer_index);
|
client->buffer_index);
|
||||||
|
@ -469,52 +474,39 @@ static int on_client_fb_update_request(struct vnc_client *client)
|
||||||
int width = ntohs(msg->width);
|
int width = ntohs(msg->width);
|
||||||
int height = ntohs(msg->height);
|
int height = ntohs(msg->height);
|
||||||
|
|
||||||
printf("framebuffer update: %d, %d. %d %d\n", x, y, width, height);
|
pixman_region_union_rect(&client->requested_region,
|
||||||
|
&client->requested_region,
|
||||||
|
x, y, width, height);
|
||||||
|
|
||||||
struct vnc_server *server = client->server;
|
nvnc_fb_req_fn fn = server->fb_req_fn;
|
||||||
struct vnc_display *display = &server->display;
|
if (fn)
|
||||||
struct vnc_framebuffer *fb = server->fb;
|
fn(server, incremental, x, y, width, height);
|
||||||
|
|
||||||
struct rfb_pixel_format server_fmt;
|
|
||||||
rfb_pixfmt_from_fourcc(&server_fmt, server->display.pixfmt);
|
|
||||||
|
|
||||||
struct pixman_region16 region;
|
|
||||||
pixman_region_init(®ion);
|
|
||||||
|
|
||||||
pixman_region_union_rect(®ion, ®ion, x, y, width, height);
|
|
||||||
pixman_region_intersect_rect(®ion, ®ion, 0, 0, display->width,
|
|
||||||
display->height);
|
|
||||||
|
|
||||||
struct vec frame;
|
|
||||||
vec_init(&frame, width * height * 3 / 2);
|
|
||||||
|
|
||||||
zrle_encode_frame(&frame, &client->pixfmt, server->fb->addr,
|
|
||||||
&server_fmt, fb->width, fb->height, ®ion);
|
|
||||||
|
|
||||||
pixman_region_fini(®ion);
|
|
||||||
|
|
||||||
vnc__write((uv_stream_t*)&client->stream_handle, frame.data, frame.len, NULL);
|
|
||||||
|
|
||||||
return sizeof(*msg);
|
return sizeof(*msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_client_key_event(struct vnc_client *client)
|
static int on_client_key_event(struct vnc_client *client)
|
||||||
{
|
{
|
||||||
|
struct nvnc *server = client->server;
|
||||||
|
|
||||||
struct rfb_client_key_event_msg *msg =
|
struct rfb_client_key_event_msg *msg =
|
||||||
(struct rfb_client_key_event_msg*)(client->msg_buffer +
|
(struct rfb_client_key_event_msg*)(client->msg_buffer +
|
||||||
client->buffer_index);
|
client->buffer_index);
|
||||||
|
|
||||||
int down_flag = msg->down_flag;
|
int down_flag = msg->down_flag;
|
||||||
uint32_t key = ntohl(msg->key);
|
uint32_t keysym = ntohl(msg->key);
|
||||||
|
|
||||||
printf("key event: %d\n", key);
|
nvnc_key_fn fn = server->key_fn;
|
||||||
// TODO
|
if (fn)
|
||||||
|
fn(server, keysym, !!down_flag);
|
||||||
|
|
||||||
return sizeof(*msg);
|
return sizeof(*msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_client_pointer_event(struct vnc_client *client)
|
static int on_client_pointer_event(struct vnc_client *client)
|
||||||
{
|
{
|
||||||
|
struct nvnc *server = client->server;
|
||||||
|
|
||||||
struct rfb_client_pointer_event_msg *msg =
|
struct rfb_client_pointer_event_msg *msg =
|
||||||
(struct rfb_client_pointer_event_msg*)(client->msg_buffer +
|
(struct rfb_client_pointer_event_msg*)(client->msg_buffer +
|
||||||
client->buffer_index);
|
client->buffer_index);
|
||||||
|
@ -523,8 +515,9 @@ static int on_client_pointer_event(struct vnc_client *client)
|
||||||
uint16_t x = ntohs(msg->x);
|
uint16_t x = ntohs(msg->x);
|
||||||
uint16_t y = ntohs(msg->y);
|
uint16_t y = ntohs(msg->y);
|
||||||
|
|
||||||
printf("pointer event: %d, %d, %d\n", x, y, button_mask);
|
nvnc_pointer_fn fn = server->pointer_fn;
|
||||||
// TODO
|
if (fn)
|
||||||
|
fn(server, x, y, button_mask);
|
||||||
|
|
||||||
return sizeof(*msg);
|
return sizeof(*msg);
|
||||||
}
|
}
|
||||||
|
@ -635,7 +628,7 @@ static void on_client_read(uv_stream_t *stream, ssize_t n_read,
|
||||||
|
|
||||||
static void on_connection(uv_stream_t *server_stream, int status)
|
static void on_connection(uv_stream_t *server_stream, int status)
|
||||||
{
|
{
|
||||||
struct vnc_server *server = (struct vnc_server*)server_stream;
|
struct nvnc *server = (struct nvnc*)server_stream;
|
||||||
|
|
||||||
struct vnc_client *client = calloc(1, sizeof(*client));
|
struct vnc_client *client = calloc(1, sizeof(*client));
|
||||||
if (!client)
|
if (!client)
|
||||||
|
@ -643,6 +636,8 @@ static void on_connection(uv_stream_t *server_stream, int status)
|
||||||
|
|
||||||
client->server = server;
|
client->server = server;
|
||||||
|
|
||||||
|
pixman_region_init(&client->requested_region);
|
||||||
|
|
||||||
uv_tcp_init(uv_default_loop(), &client->stream_handle);
|
uv_tcp_init(uv_default_loop(), &client->stream_handle);
|
||||||
|
|
||||||
uv_accept((uv_stream_t*)&server->tcp_handle,
|
uv_accept((uv_stream_t*)&server->tcp_handle,
|
||||||
|
@ -659,7 +654,7 @@ static void on_connection(uv_stream_t *server_stream, int status)
|
||||||
client->state = VNC_CLIENT_STATE_WAITING_FOR_VERSION;
|
client->state = VNC_CLIENT_STATE_WAITING_FOR_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vnc_server_init(struct vnc_server *self, const char* address, int port)
|
int vnc_server_init(struct nvnc *self, const char* address, int port)
|
||||||
{
|
{
|
||||||
LIST_INIT(&self->clients);
|
LIST_INIT(&self->clients);
|
||||||
|
|
||||||
|
@ -683,6 +678,119 @@ failure:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPORT
|
||||||
|
struct nvnc *nvnc_open(const char *address, uint16_t port)
|
||||||
|
{
|
||||||
|
struct nvnc *self = calloc(1, sizeof(*self));
|
||||||
|
if (!self)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
LIST_INIT(&self->clients);
|
||||||
|
|
||||||
|
uv_tcp_init(uv_default_loop(), &self->tcp_handle);
|
||||||
|
|
||||||
|
struct sockaddr_in addr = { 0 };
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = inet_addr(address);
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
|
||||||
|
if (uv_tcp_bind(&self->tcp_handle, (const struct sockaddr*)&addr, 0) < 0)
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
if (uv_listen((uv_stream_t*)&self->tcp_handle, 16, on_connection) < 0)
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
failure:
|
||||||
|
uv_unref((uv_handle_t*)&self->tcp_handle);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT
|
||||||
|
void nvnc_close(struct nvnc *self)
|
||||||
|
{
|
||||||
|
struct vnc_client *client;
|
||||||
|
|
||||||
|
LIST_FOREACH(client, &self->clients, link)
|
||||||
|
uv_close((uv_handle_t*)&client->stream_handle, cleanup_client);
|
||||||
|
|
||||||
|
uv_unref((uv_handle_t*)&self->tcp_handle);
|
||||||
|
free(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT
|
||||||
|
int nvnc_update_fb(struct nvnc *self, const struct nvnc_fb *fb,
|
||||||
|
const struct pixman_region16 *input_region)
|
||||||
|
{
|
||||||
|
int rc = -1;
|
||||||
|
|
||||||
|
struct rfb_pixel_format server_fmt;
|
||||||
|
rfb_pixfmt_from_fourcc(&server_fmt, fb->fourcc_format);
|
||||||
|
|
||||||
|
struct pixman_region16 region;
|
||||||
|
pixman_region_init(®ion);
|
||||||
|
|
||||||
|
pixman_region_intersect_rect(®ion,
|
||||||
|
(struct pixman_region16*)input_region,
|
||||||
|
0, 0, fb->width, fb->height);
|
||||||
|
|
||||||
|
struct vec frame;
|
||||||
|
rc = vec_init(&frame, fb->width * fb->height * 3 / 2);
|
||||||
|
if (rc < 0)
|
||||||
|
goto failure;
|
||||||
|
|
||||||
|
struct vnc_client *client;
|
||||||
|
|
||||||
|
LIST_FOREACH(client, &self->clients, link) {
|
||||||
|
struct pixman_region16* cregion = &client->requested_region;
|
||||||
|
|
||||||
|
pixman_region_intersect(cregion, cregion, ®ion);
|
||||||
|
|
||||||
|
zrle_encode_frame(&frame, &client->pixfmt, fb->addr,
|
||||||
|
&server_fmt, fb->width, fb->height, ®ion);
|
||||||
|
|
||||||
|
pixman_region_clear(cregion);
|
||||||
|
|
||||||
|
vnc__write((uv_stream_t*)&client->stream_handle, frame.data,
|
||||||
|
frame.len, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = 0;
|
||||||
|
failure:
|
||||||
|
pixman_region_fini(®ion);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT
|
||||||
|
void nvnc_set_userdata(struct nvnc *self, void *userdata)
|
||||||
|
{
|
||||||
|
self->userdata = userdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT
|
||||||
|
void* nvnc_get_userdata(struct nvnc *self)
|
||||||
|
{
|
||||||
|
return self->userdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT
|
||||||
|
void nvnc_set_key_fn(struct nvnc *self, nvnc_key_fn fn)
|
||||||
|
{
|
||||||
|
self->key_fn = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT
|
||||||
|
void nvnc_set_pointer_fn(struct nvnc *self, nvnc_pointer_fn fn)
|
||||||
|
{
|
||||||
|
self->pointer_fn = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT
|
||||||
|
void nvnc_set_fb_req_fn(struct nvnc *self, nvnc_fb_req_fn fn)
|
||||||
|
{
|
||||||
|
self->fb_req_fn = fn;
|
||||||
|
}
|
||||||
|
|
||||||
int read_png_file(struct vnc_framebuffer* fb, const char *filename);
|
int read_png_file(struct vnc_framebuffer* fb, const char *filename);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue