You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
241 lines
8.0 KiB
241 lines
8.0 KiB
From e4849b01fec4494057728d1aa3a165ed21705682 Mon Sep 17 00:00:00 2001 |
|
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com> |
|
Date: Mon, 11 Jun 2018 23:47:02 +0200 |
|
Subject: [PATCH 1/4] libvncserver: Add API to add custom I/O entry points |
|
|
|
Add API to make it possible to channel RFB input and output through |
|
another layer, for example TLS. This is done by making it possible to |
|
override the default read/write/peek functions. |
|
--- |
|
libvncserver/rfbserver.c | 4 ++ |
|
libvncserver/sockets.c | 79 ++++++++++++++++++++++++++++++++++++---- |
|
rfb/rfb.h | 17 +++++++++ |
|
3 files changed, 93 insertions(+), 7 deletions(-) |
|
|
|
diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c |
|
index e9eaa5fc..72e9ba79 100644 |
|
--- a/libvncserver/rfbserver.c |
|
+++ b/libvncserver/rfbserver.c |
|
@@ -319,6 +319,10 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen, |
|
|
|
cl->screen = rfbScreen; |
|
cl->sock = sock; |
|
+ cl->readFromSocket = rfbDefaultReadFromSocket; |
|
+ cl->peekAtSocket = rfbDefaultPeekAtSocket; |
|
+ cl->hasPendingOnSocket = rfbDefaultHasPendingOnSocket; |
|
+ cl->writeToSocket = rfbDefaultWriteToSocket; |
|
cl->viewOnly = FALSE; |
|
/* setup pseudo scaling */ |
|
cl->scaledScreen = rfbScreen; |
|
diff --git a/libvncserver/sockets.c b/libvncserver/sockets.c |
|
index 2c87376b..4bb881ec 100644 |
|
--- a/libvncserver/sockets.c |
|
+++ b/libvncserver/sockets.c |
|
@@ -101,6 +101,9 @@ int deny_severity=LOG_WARNING; |
|
int rfbMaxClientWait = 20000; /* time (ms) after which we decide client has |
|
gone away - needed to stop us hanging */ |
|
|
|
+static rfbBool |
|
+rfbHasPendingOnSocket(rfbClientPtr cl); |
|
+ |
|
static rfbBool |
|
rfbNewConnectionFromSock(rfbScreenInfoPtr rfbScreen, rfbSocket sock) |
|
{ |
|
@@ -364,16 +367,20 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec) |
|
tv.tv_usec = usec; |
|
nfds = select(rfbScreen->maxFd + 1, &fds, NULL, NULL /* &fds */, &tv); |
|
if (nfds == 0) { |
|
+ rfbBool hasPendingData = FALSE; |
|
+ |
|
/* timed out, check for async events */ |
|
i = rfbGetClientIterator(rfbScreen); |
|
while((cl = rfbClientIteratorNext(i))) { |
|
if (cl->onHold) |
|
continue; |
|
+ hasPendingData |= rfbHasPendingOnSocket(cl); |
|
if (FD_ISSET(cl->sock, &(rfbScreen->allFds))) |
|
rfbSendFileTransferChunk(cl); |
|
} |
|
rfbReleaseClientIterator(i); |
|
- return result; |
|
+ if (!hasPendingData) |
|
+ return result; |
|
} |
|
|
|
if (nfds < 0) { |
|
@@ -449,9 +456,11 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec) |
|
if (cl->onHold) |
|
continue; |
|
|
|
- if (FD_ISSET(cl->sock, &(rfbScreen->allFds))) |
|
+ if (rfbHasPendingOnSocket (cl) || |
|
+ FD_ISSET(cl->sock, &(rfbScreen->allFds))) |
|
{ |
|
- if (FD_ISSET(cl->sock, &fds)) |
|
+ if (rfbHasPendingOnSocket (cl) || |
|
+ FD_ISSET(cl->sock, &fds)) |
|
{ |
|
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS |
|
do { |
|
@@ -614,6 +623,30 @@ rfbConnect(rfbScreenInfoPtr rfbScreen, |
|
return sock; |
|
} |
|
|
|
+int |
|
+rfbDefaultReadFromSocket(rfbClientPtr cl, char *buf, int len) |
|
+{ |
|
+ return read(cl->sock, buf, len); |
|
+} |
|
+ |
|
+static int |
|
+rfbReadFromSocket(rfbClientPtr cl, char *buf, int len) |
|
+{ |
|
+ return cl->readFromSocket(cl, buf, len); |
|
+} |
|
+ |
|
+rfbBool |
|
+rfbDefaultHasPendingOnSocket(rfbClientPtr cl) |
|
+{ |
|
+ return FALSE; |
|
+} |
|
+ |
|
+static rfbBool |
|
+rfbHasPendingOnSocket(rfbClientPtr cl) |
|
+{ |
|
+ return cl->hasPendingOnSocket(cl); |
|
+} |
|
+ |
|
/* |
|
* ReadExact reads an exact number of bytes from a client. Returns 1 if |
|
* those bytes have been read, 0 if the other end has closed, or -1 if an error |
|
@@ -635,10 +668,10 @@ rfbReadExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout) |
|
} else if (cl->sslctx) { |
|
n = rfbssl_read(cl, buf, len); |
|
} else { |
|
- n = read(sock, buf, len); |
|
+ n = rfbReadFromSocket(cl, buf, len); |
|
} |
|
#else |
|
- n = read(sock, buf, len); |
|
+ n = rfbReadFromSocket(cl, buf, len); |
|
#endif |
|
|
|
if (n > 0) { |
|
@@ -670,6 +703,10 @@ rfbReadExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout) |
|
continue; |
|
} |
|
#endif |
|
+ |
|
+ if (rfbHasPendingOnSocket(cl)) |
|
+ continue; |
|
+ |
|
FD_ZERO(&fds); |
|
FD_SET(sock, &fds); |
|
tv.tv_sec = timeout / 1000; |
|
@@ -706,6 +743,18 @@ int rfbReadExact(rfbClientPtr cl,char* buf,int len) |
|
return(rfbReadExactTimeout(cl,buf,len,rfbMaxClientWait)); |
|
} |
|
|
|
+int |
|
+rfbDefaultPeekAtSocket(rfbClientPtr cl, char *buf, int len) |
|
+{ |
|
+ return recv(cl->sock, buf, len, MSG_PEEK); |
|
+} |
|
+ |
|
+int |
|
+rfbPeekAtSocket(rfbClientPtr cl, char *buf, int len) |
|
+{ |
|
+ cl->peekAtSocket(cl, buf, len); |
|
+} |
|
+ |
|
/* |
|
* PeekExact peeks at an exact number of bytes from a client. Returns 1 if |
|
* those bytes have been read, 0 if the other end has closed, or -1 if an |
|
@@ -726,7 +775,7 @@ rfbPeekExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout) |
|
n = rfbssl_peek(cl, buf, len); |
|
else |
|
#endif |
|
- n = recv(sock, buf, len, MSG_PEEK); |
|
+ n = rfbPeekAtSocket(cl, buf, len); |
|
|
|
if (n == len) { |
|
|
|
@@ -782,6 +831,22 @@ rfbPeekExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout) |
|
return 1; |
|
} |
|
|
|
+int |
|
+rfbDefaultWriteToSocket(rfbClientPtr cl, |
|
+ const char *buf, |
|
+ int len) |
|
+{ |
|
+ return write(cl->sock, buf, len); |
|
+} |
|
+ |
|
+static int |
|
+rfbWriteToSocket(rfbClientPtr cl, |
|
+ const char *buf, |
|
+ int len) |
|
+{ |
|
+ return cl->writeToSocket(cl, buf, len); |
|
+} |
|
+ |
|
/* |
|
* WriteExact writes an exact number of bytes to a client. Returns 1 if |
|
* those bytes have been written, or -1 if an error occurred (errno is set to |
|
@@ -826,7 +891,7 @@ rfbWriteExact(rfbClientPtr cl, |
|
n = rfbssl_write(cl, buf, len); |
|
else |
|
#endif |
|
- n = write(sock, buf, len); |
|
+ n = rfbWriteToSocket(cl, buf, len); |
|
|
|
if (n > 0) { |
|
|
|
diff --git a/rfb/rfb.h b/rfb/rfb.h |
|
index 5e9ba86f..3c0b25a3 100644 |
|
--- a/rfb/rfb.h |
|
+++ b/rfb/rfb.h |
|
@@ -387,6 +387,14 @@ typedef struct sraRegion* sraRegionPtr; |
|
typedef void (*ClientGoneHookPtr)(struct _rfbClientRec* cl); |
|
typedef void (*ClientFramebufferUpdateRequestHookPtr)(struct _rfbClientRec* cl, rfbFramebufferUpdateRequestMsg* furMsg); |
|
|
|
+typedef int (*ClientReadFromSocket)(struct _rfbClientRec* cl, |
|
+ char *buf, int len); |
|
+typedef int (*ClientPeekAtSocket)(struct _rfbClientRec* cl, |
|
+ char *buf, int len); |
|
+typedef rfbBool (*ClientHasPendingOnSocket)(struct _rfbClientRec* cl); |
|
+typedef int (*ClientWriteToSocket)(struct _rfbClientRec* cl, |
|
+ const char *buf, int len); |
|
+ |
|
typedef struct _rfbFileTransferData { |
|
int fd; |
|
int compressionEnabled; |
|
@@ -680,6 +688,11 @@ typedef struct _rfbClientRec { |
|
rfbBool useExtDesktopSize; |
|
int requestedDesktopSizeChange; |
|
int lastDesktopSizeChangeError; |
|
+ |
|
+ ClientReadFromSocket readFromSocket; /* Read data from socket */ |
|
+ ClientPeekAtSocket peekAtSocket; /* Peek at data from socket */ |
|
+ ClientHasPendingOnSocket hasPendingOnSocket; /* Peek at data from socket */ |
|
+ ClientWriteToSocket writeToSocket; /* Write data to socket */ |
|
} rfbClientRec, *rfbClientPtr; |
|
|
|
/** |
|
@@ -732,8 +745,12 @@ extern void rfbDisconnectUDPSock(rfbScreenInfoPtr rfbScreen); |
|
extern void rfbCloseClient(rfbClientPtr cl); |
|
extern int rfbReadExact(rfbClientPtr cl, char *buf, int len); |
|
extern int rfbReadExactTimeout(rfbClientPtr cl, char *buf, int len,int timeout); |
|
+extern int rfbDefaultReadFromSocket(rfbClientPtr cl, char *buf, int len); |
|
extern int rfbPeekExactTimeout(rfbClientPtr cl, char *buf, int len,int timeout); |
|
+extern int rfbDefaultPeekAtSocket(rfbClientPtr cl, char *buf, int len); |
|
+extern rfbBool rfbDefaultHasPendingOnSocket(rfbClientPtr cl); |
|
extern int rfbWriteExact(rfbClientPtr cl, const char *buf, int len); |
|
+extern int rfbDefaultWriteToSocket(rfbClientPtr cl, const char *buf, int len); |
|
extern int rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec); |
|
extern rfbSocket rfbConnect(rfbScreenInfoPtr rfbScreen, char* host, int port); |
|
extern rfbSocket rfbConnectToTcpAddr(char* host, int port); |
|
-- |
|
2.28.0 |
|
|
|
|