Dispatch events while waiting for server data
Blocking the event loop is very badlibvncclient-integration
parent
60574ba34b
commit
33d13e4b4f
|
@ -604,6 +604,8 @@ extern rfbBool SendClientCutText(rfbClient* client,char *str, int len);
|
||||||
*/
|
*/
|
||||||
extern rfbBool HandleRFBServerMessage(rfbClient* client);
|
extern rfbBool HandleRFBServerMessage(rfbClient* client);
|
||||||
|
|
||||||
|
extern void ReadToBuffer(rfbClient* client);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a text chat message to the server.
|
* Sends a text chat message to the server.
|
||||||
* @param client The client through which to send the message
|
* @param client The client through which to send the message
|
||||||
|
|
|
@ -47,12 +47,15 @@ struct vnc_client {
|
||||||
|
|
||||||
void* userdata;
|
void* userdata;
|
||||||
struct pixman_region16 damage;
|
struct pixman_region16 damage;
|
||||||
|
|
||||||
|
bool handler_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vnc_client* vnc_client_create(void);
|
struct vnc_client* vnc_client_create(void);
|
||||||
void vnc_client_destroy(struct vnc_client* self);
|
void vnc_client_destroy(struct vnc_client* self);
|
||||||
|
|
||||||
int vnc_client_connect(struct vnc_client* self, const char* address, int port);
|
int vnc_client_connect(struct vnc_client* self, const char* address, int port);
|
||||||
|
int vnc_client_init(struct vnc_client* self);
|
||||||
|
|
||||||
int vnc_client_set_pixel_format(struct vnc_client* self, uint32_t format);
|
int vnc_client_set_pixel_format(struct vnc_client* self, uint32_t format);
|
||||||
|
|
||||||
|
|
20
src/main.c
20
src/main.c
|
@ -670,6 +670,14 @@ failure:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void run_main_loop_once(void)
|
||||||
|
{
|
||||||
|
struct aml* aml = aml_get_default();
|
||||||
|
wl_display_flush(wl_display);
|
||||||
|
aml_poll(aml, -1);
|
||||||
|
aml_dispatch(aml);
|
||||||
|
}
|
||||||
|
|
||||||
static int usage(int r)
|
static int usage(int r)
|
||||||
{
|
{
|
||||||
fprintf(r ? stderr : stdout, "\
|
fprintf(r ? stderr : stdout, "\
|
||||||
|
@ -842,16 +850,18 @@ int main(int argc, char* argv[])
|
||||||
if (init_vnc_client_handler(vnc) < 0)
|
if (init_vnc_client_handler(vnc) < 0)
|
||||||
goto vnc_setup_failure;
|
goto vnc_setup_failure;
|
||||||
|
|
||||||
|
if (vnc_client_init(vnc) < 0) {
|
||||||
|
fprintf(stderr, "Failed to connect to server\n");
|
||||||
|
goto vnc_setup_failure;
|
||||||
|
}
|
||||||
|
|
||||||
pointers->userdata = vnc;
|
pointers->userdata = vnc;
|
||||||
keyboards->userdata = vnc;
|
keyboards->userdata = vnc;
|
||||||
|
|
||||||
wl_display_dispatch(wl_display);
|
wl_display_dispatch(wl_display);
|
||||||
|
|
||||||
while (do_run) {
|
while (do_run)
|
||||||
wl_display_flush(wl_display);
|
run_main_loop_once();
|
||||||
aml_poll(aml, -1);
|
|
||||||
aml_dispatch(aml);
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
if (window)
|
if (window)
|
||||||
|
|
227
src/sockets.c
227
src/sockets.c
|
@ -1,4 +1,5 @@
|
||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2022 Andri Yngvasin <andri@yngvason.is>
|
||||||
* Copyright (C) 2011-2012 Christian Beier <dontmind@freeshell.org>
|
* Copyright (C) 2011-2012 Christian Beier <dontmind@freeshell.org>
|
||||||
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||||
*
|
*
|
||||||
|
@ -34,206 +35,72 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <rfb/rfbclient.h>
|
#include <sys/param.h>
|
||||||
|
#include "rfb/rfbclient.h"
|
||||||
#include "sockets.h"
|
#include "sockets.h"
|
||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
#include "sasl.h"
|
#include "sasl.h"
|
||||||
|
|
||||||
|
void run_main_loop_once(void);
|
||||||
|
|
||||||
void PrintInHex(char *buf, int len);
|
void PrintInHex(char *buf, int len);
|
||||||
|
|
||||||
rfbBool errorMessageOnReadFailure = TRUE;
|
rfbBool errorMessageOnReadFailure = TRUE;
|
||||||
|
|
||||||
/*
|
void ReadToBuffer(rfbClient* client) {
|
||||||
* ReadFromRFBServer is called whenever we want to read some data from the RFB
|
if (client->buffered == RFB_BUF_SIZE)
|
||||||
* server. It is non-trivial for two reasons:
|
return;
|
||||||
*
|
|
||||||
* 1. For efficiency it performs some intelligent buffering, avoiding invoking
|
|
||||||
* the read() system call too often. For small chunks of data, it simply
|
|
||||||
* copies the data out of an internal buffer. For large amounts of data it
|
|
||||||
* reads directly into the buffer provided by the caller.
|
|
||||||
*
|
|
||||||
* 2. Whenever read() would block, it invokes the Xt event dispatching
|
|
||||||
* mechanism to process X events. In fact, this is the only place these
|
|
||||||
* events are processed, as there is no XtAppMainLoop in the program.
|
|
||||||
*/
|
|
||||||
|
|
||||||
rfbBool
|
ssize_t size;
|
||||||
ReadFromRFBServer(rfbClient* client, char *out, unsigned int n)
|
|
||||||
{
|
#if defined(LIBVNCSERVER_HAVE_GNUTLS) || defined(LIBVNCSERVER_HAVE_LIBSSL)
|
||||||
const int USECS_WAIT_PER_RETRY = 100000;
|
if (client->tlsSession) {
|
||||||
int retries = 0;
|
size = ReadFromTLS(client, client->buf + client->buffered,
|
||||||
#undef DEBUG_READ_EXACT
|
RFB_BUF_SIZE - client->buffered);
|
||||||
#ifdef DEBUG_READ_EXACT
|
} else
|
||||||
char* oout=out;
|
|
||||||
unsigned int nn=n;
|
|
||||||
rfbClientLog("ReadFromRFBServer %d bytes\n",n);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Handle attempts to write to NULL out buffer that might occur
|
|
||||||
when an outside malloc() fails. For instance, memcpy() to NULL
|
|
||||||
results in undefined behaviour and probably memory corruption.*/
|
|
||||||
if(!out)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (client->serverPort==-1) {
|
|
||||||
/* vncrec playing */
|
|
||||||
rfbVNCRec* rec = client->vncRec;
|
|
||||||
struct timeval tv;
|
|
||||||
|
|
||||||
if (rec->readTimestamp) {
|
|
||||||
rec->readTimestamp = FALSE;
|
|
||||||
if (!fread(&tv,sizeof(struct timeval),1,rec->file))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
tv.tv_sec = rfbClientSwap32IfLE (tv.tv_sec);
|
|
||||||
tv.tv_usec = rfbClientSwap32IfLE (tv.tv_usec);
|
|
||||||
|
|
||||||
if (rec->tv.tv_sec!=0 && !rec->doNotSleep) {
|
|
||||||
struct timeval diff;
|
|
||||||
diff.tv_sec = tv.tv_sec - rec->tv.tv_sec;
|
|
||||||
diff.tv_usec = tv.tv_usec - rec->tv.tv_usec;
|
|
||||||
if(diff.tv_usec<0) {
|
|
||||||
diff.tv_sec--;
|
|
||||||
diff.tv_usec+=1000000;
|
|
||||||
}
|
|
||||||
sleep (diff.tv_sec);
|
|
||||||
usleep (diff.tv_usec);
|
|
||||||
}
|
|
||||||
|
|
||||||
rec->tv=tv;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (fread(out,1,n,rec->file) != n ? FALSE : TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n <= client->buffered) {
|
|
||||||
memcpy(out, client->bufoutptr, n);
|
|
||||||
client->bufoutptr += n;
|
|
||||||
client->buffered -= n;
|
|
||||||
#ifdef DEBUG_READ_EXACT
|
|
||||||
goto hexdump;
|
|
||||||
#endif
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(out, client->bufoutptr, client->buffered);
|
|
||||||
|
|
||||||
out += client->buffered;
|
|
||||||
n -= client->buffered;
|
|
||||||
|
|
||||||
client->bufoutptr = client->buf;
|
|
||||||
client->buffered = 0;
|
|
||||||
|
|
||||||
if (n <= RFB_BUF_SIZE) {
|
|
||||||
|
|
||||||
while (client->buffered < n) {
|
|
||||||
int i;
|
|
||||||
if (client->tlsSession)
|
|
||||||
i = ReadFromTLS(client, client->buf + client->buffered, RFB_BUF_SIZE - client->buffered);
|
|
||||||
else
|
|
||||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
#ifdef LIBVNCSERVER_HAVE_SASL
|
||||||
if (client->saslconn)
|
if (client->saslconn) {
|
||||||
i = ReadFromSASL(client, client->buf + client->buffered, RFB_BUF_SIZE - client->buffered);
|
size = ReadFromSASL(client, client->buf + client->buffered,
|
||||||
else {
|
RFB_BUF_SIZE - client->buffered);
|
||||||
#endif /* LIBVNCSERVER_HAVE_SASL */
|
} else
|
||||||
i = read(client->sock, client->buf + client->buffered, RFB_BUF_SIZE - client->buffered);
|
|
||||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
if (i <= 0) {
|
size = recv(client->sock, client->buf + client->buffered,
|
||||||
if (i < 0) {
|
RFB_BUF_SIZE - client->buffered, MSG_DONTWAIT);
|
||||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
|
||||||
if (client->readTimeout > 0 &&
|
|
||||||
++retries > (client->readTimeout * 1000 * 1000 / USECS_WAIT_PER_RETRY))
|
|
||||||
{
|
|
||||||
rfbClientLog("Connection timed out\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
/* TODO:
|
|
||||||
ProcessXtEvents();
|
|
||||||
*/
|
|
||||||
WaitForMessage(client, USECS_WAIT_PER_RETRY);
|
|
||||||
i = 0;
|
|
||||||
} else {
|
|
||||||
rfbClientErr("read (%d: %s)\n",errno,strerror(errno));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (errorMessageOnReadFailure) {
|
|
||||||
rfbClientLog("VNC server closed connection\n");
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
client->buffered += i;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(out, client->bufoutptr, n);
|
if (size > 0)
|
||||||
client->bufoutptr += n;
|
client->buffered += size;
|
||||||
client->buffered -= n;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
while (n > 0) {
|
|
||||||
int i;
|
|
||||||
if (client->tlsSession)
|
|
||||||
i = ReadFromTLS(client, out, n);
|
|
||||||
else
|
|
||||||
#ifdef LIBVNCSERVER_HAVE_SASL
|
|
||||||
if (client->saslconn)
|
|
||||||
i = ReadFromSASL(client, out, n);
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
i = read(client->sock, out, n);
|
|
||||||
|
|
||||||
if (i <= 0) {
|
|
||||||
if (i < 0) {
|
|
||||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
|
||||||
if (client->readTimeout > 0 &&
|
|
||||||
++retries > (client->readTimeout * 1000 * 1000 / USECS_WAIT_PER_RETRY))
|
|
||||||
{
|
|
||||||
rfbClientLog("Connection timed out\n");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
/* TODO:
|
|
||||||
ProcessXtEvents();
|
|
||||||
*/
|
|
||||||
WaitForMessage(client, USECS_WAIT_PER_RETRY);
|
|
||||||
i = 0;
|
|
||||||
} else {
|
|
||||||
rfbClientErr("read (%s)\n",strerror(errno));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (errorMessageOnReadFailure) {
|
|
||||||
rfbClientLog("VNC server closed connection\n");
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out += i;
|
|
||||||
n -= i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_READ_EXACT
|
|
||||||
hexdump:
|
|
||||||
{ unsigned int ii;
|
|
||||||
for(ii=0;ii<nn;ii++)
|
|
||||||
fprintf(stderr,"%02x ",(unsigned char)oout[ii]);
|
|
||||||
fprintf(stderr,"\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rfbBool ReadFromRFBServer(rfbClient* client, char *out, unsigned int n)
|
||||||
|
{
|
||||||
|
if (!out)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
while (n != 0) {
|
||||||
|
while (n != 0 && client->buffered == 0) {
|
||||||
|
run_main_loop_once();
|
||||||
|
ReadToBuffer(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int size = MIN(client->buffered, n);
|
||||||
|
memcpy(out, client->buf, size);
|
||||||
|
|
||||||
|
client->buffered -= size;
|
||||||
|
memmove(client->buf, client->buf + size, client->buffered);
|
||||||
|
|
||||||
|
out += size;
|
||||||
|
n -= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write an exact number of bytes, and don't return until you've sent them.
|
* Write an exact number of bytes, and don't return until you've sent them.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
rfbBool
|
rfbBool
|
||||||
WriteToRFBServer(rfbClient* client, const char *buf, unsigned int n)
|
WriteToRFBServer(rfbClient* client, const char *buf, unsigned int n)
|
||||||
{
|
{
|
||||||
|
|
48
src/vnc.c
48
src/vnc.c
|
@ -47,6 +47,21 @@ static uint64_t vnc_client_htonll(uint64_t x)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool vnc_client_lock_handler(struct vnc_client* self)
|
||||||
|
{
|
||||||
|
if (self->handler_lock)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
self->handler_lock = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vnc_client_unlock_handler(struct vnc_client* self)
|
||||||
|
{
|
||||||
|
assert(self->handler_lock);
|
||||||
|
self->handler_lock = false;
|
||||||
|
}
|
||||||
|
|
||||||
static rfbBool vnc_client_alloc_fb(rfbClient* client)
|
static rfbBool vnc_client_alloc_fb(rfbClient* client)
|
||||||
{
|
{
|
||||||
struct vnc_client* self = rfbClientGetClientData(client, NULL);
|
struct vnc_client* self = rfbClientGetClientData(client, NULL);
|
||||||
|
@ -228,20 +243,27 @@ int vnc_client_connect(struct vnc_client* self, const char* address, int port)
|
||||||
{
|
{
|
||||||
rfbClient* client = self->client;
|
rfbClient* client = self->client;
|
||||||
|
|
||||||
if (!ConnectToRFBServer(client, address, port))
|
return ConnectToRFBServer(client, address, port) ? 0 : -1;
|
||||||
return -1;
|
}
|
||||||
|
|
||||||
|
int vnc_client_init(struct vnc_client* self)
|
||||||
|
{
|
||||||
|
int rc = -1;
|
||||||
|
rfbClient* client = self->client;
|
||||||
|
|
||||||
|
vnc_client_lock_handler(self);
|
||||||
|
|
||||||
if (!InitialiseRFBConnection(client))
|
if (!InitialiseRFBConnection(client))
|
||||||
return -1;
|
goto failure;
|
||||||
|
|
||||||
client->width = client->si.framebufferWidth;
|
client->width = client->si.framebufferWidth;
|
||||||
client->height = client->si.framebufferHeight;
|
client->height = client->si.framebufferHeight;
|
||||||
|
|
||||||
if (!client->MallocFrameBuffer(client))
|
if (!client->MallocFrameBuffer(client))
|
||||||
return -1;
|
goto failure;
|
||||||
|
|
||||||
if (!vnc_client_set_format_and_encodings(client))
|
if (!vnc_client_set_format_and_encodings(client))
|
||||||
return -1;
|
goto failure;
|
||||||
|
|
||||||
if (client->updateRect.x < 0) {
|
if (client->updateRect.x < 0) {
|
||||||
client->updateRect.x = client->updateRect.y = 0;
|
client->updateRect.x = client->updateRect.y = 0;
|
||||||
|
@ -253,12 +275,15 @@ int vnc_client_connect(struct vnc_client* self, const char* address, int port)
|
||||||
client->updateRect.x, client->updateRect.y,
|
client->updateRect.x, client->updateRect.y,
|
||||||
client->updateRect.w, client->updateRect.h,
|
client->updateRect.w, client->updateRect.h,
|
||||||
FALSE))
|
FALSE))
|
||||||
return -1;
|
goto failure;
|
||||||
|
|
||||||
SendIncrementalFramebufferUpdateRequest(client);
|
SendIncrementalFramebufferUpdateRequest(client);
|
||||||
SendIncrementalFramebufferUpdateRequest(client);
|
SendIncrementalFramebufferUpdateRequest(client);
|
||||||
|
|
||||||
return 0;
|
rc = 0;
|
||||||
|
failure:
|
||||||
|
vnc_client_unlock_handler(self);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vnc_client_set_pixel_format(struct vnc_client* self, uint32_t format)
|
int vnc_client_set_pixel_format(struct vnc_client* self, uint32_t format)
|
||||||
|
@ -335,7 +360,14 @@ const char* vnc_client_get_desktop_name(const struct vnc_client* self)
|
||||||
|
|
||||||
int vnc_client_process(struct vnc_client* self)
|
int vnc_client_process(struct vnc_client* self)
|
||||||
{
|
{
|
||||||
return HandleRFBServerMessage(self->client) ? 0 : -1;
|
ReadToBuffer(self->client);
|
||||||
|
|
||||||
|
if (!vnc_client_lock_handler(self))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int rc = HandleRFBServerMessage(self->client) ? 0 : -1;
|
||||||
|
vnc_client_unlock_handler(self);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vnc_client_send_pointer_event(struct vnc_client* self, int x, int y,
|
void vnc_client_send_pointer_event(struct vnc_client* self, int x, int y,
|
||||||
|
|
Loading…
Reference in New Issue