Skip to content

Commit 1744db1

Browse files
committed
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.
1 parent a004c0c commit 1744db1

File tree

3 files changed

+93
-7
lines changed

3 files changed

+93
-7
lines changed

include/rfb/rfb.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,14 @@ typedef struct sraRegion* sraRegionPtr;
402402
typedef void (*ClientGoneHookPtr)(struct _rfbClientRec* cl);
403403
typedef void (*ClientFramebufferUpdateRequestHookPtr)(struct _rfbClientRec* cl, rfbFramebufferUpdateRequestMsg* furMsg);
404404

405+
typedef int (*ClientReadFromSocket)(struct _rfbClientRec* cl,
406+
char *buf, int len);
407+
typedef int (*ClientPeekAtSocket)(struct _rfbClientRec* cl,
408+
char *buf, int len);
409+
typedef rfbBool (*ClientHasPendingOnSocket)(struct _rfbClientRec* cl);
410+
typedef int (*ClientWriteToSocket)(struct _rfbClientRec* cl,
411+
const char *buf, int len);
412+
405413
typedef struct _rfbFileTransferData {
406414
int fd;
407415
int compressionEnabled;
@@ -715,6 +723,11 @@ typedef struct _rfbClientRec {
715723
int destPort;
716724
/** ID on repeater in case of an UltraVNC mode 2 repeater connection */
717725
char *repeaterId;
726+
727+
ClientReadFromSocket readFromSocket; /* Read data from socket */
728+
ClientPeekAtSocket peekAtSocket; /* Peek at data from socket */
729+
ClientHasPendingOnSocket hasPendingOnSocket; /* Has pending data on socket */
730+
ClientWriteToSocket writeToSocket; /* Write data to socket */
718731
} rfbClientRec, *rfbClientPtr;
719732

720733
/**
@@ -767,8 +780,12 @@ extern void rfbDisconnectUDPSock(rfbScreenInfoPtr rfbScreen);
767780
extern void rfbCloseClient(rfbClientPtr cl);
768781
extern int rfbReadExact(rfbClientPtr cl, char *buf, int len);
769782
extern int rfbReadExactTimeout(rfbClientPtr cl, char *buf, int len,int timeout);
783+
extern int rfbDefaultReadFromSocket(rfbClientPtr cl, char *buf, int len);
770784
extern int rfbPeekExactTimeout(rfbClientPtr cl, char *buf, int len,int timeout);
785+
extern int rfbDefaultPeekAtSocket(rfbClientPtr cl, char *buf, int len);
786+
extern rfbBool rfbDefaultHasPendingOnSocket(rfbClientPtr cl);
771787
extern int rfbWriteExact(rfbClientPtr cl, const char *buf, int len);
788+
extern int rfbDefaultWriteToSocket(rfbClientPtr cl, const char *buf, int len);
772789
extern int rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec);
773790
extern rfbSocket rfbConnect(rfbScreenInfoPtr rfbScreen, char* host, int port);
774791
extern rfbSocket rfbConnectToTcpAddr(char* host, int port);

src/libvncserver/rfbserver.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,10 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
376376

377377
cl->screen = rfbScreen;
378378
cl->sock = sock;
379+
cl->readFromSocket = rfbDefaultReadFromSocket;
380+
cl->peekAtSocket = rfbDefaultPeekAtSocket;
381+
cl->hasPendingOnSocket = rfbDefaultHasPendingOnSocket;
382+
cl->writeToSocket = rfbDefaultWriteToSocket;
379383
cl->viewOnly = FALSE;
380384
/* setup pseudo scaling */
381385
cl->scaledScreen = rfbScreen;

src/libvncserver/sockets.c

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ int deny_severity=LOG_WARNING;
101101
int rfbMaxClientWait = 20000; /* time (ms) after which we decide client has
102102
gone away - needed to stop us hanging */
103103

104+
static rfbBool
105+
rfbHasPendingOnSocket(rfbClientPtr cl);
106+
104107
static rfbBool
105108
rfbNewConnectionFromSock(rfbScreenInfoPtr rfbScreen, rfbSocket sock)
106109
{
@@ -364,16 +367,20 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec)
364367
tv.tv_usec = usec;
365368
nfds = select(rfbScreen->maxFd + 1, &fds, NULL, NULL /* &fds */, &tv);
366369
if (nfds == 0) {
370+
rfbBool hasPendingData = FALSE;
371+
367372
/* timed out, check for async events */
368373
i = rfbGetClientIterator(rfbScreen);
369374
while((cl = rfbClientIteratorNext(i))) {
370375
if (cl->onHold)
371376
continue;
377+
hasPendingData |= rfbHasPendingOnSocket(cl);
372378
if (FD_ISSET(cl->sock, &(rfbScreen->allFds)))
373379
rfbSendFileTransferChunk(cl);
374380
}
375381
rfbReleaseClientIterator(i);
376-
return result;
382+
if (!hasPendingData)
383+
return result;
377384
}
378385

379386
if (nfds < 0) {
@@ -449,9 +456,11 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec)
449456
if (cl->onHold)
450457
continue;
451458

452-
if (FD_ISSET(cl->sock, &(rfbScreen->allFds)))
459+
if (rfbHasPendingOnSocket (cl) ||
460+
FD_ISSET(cl->sock, &(rfbScreen->allFds)))
453461
{
454-
if (FD_ISSET(cl->sock, &fds))
462+
if (rfbHasPendingOnSocket (cl) ||
463+
FD_ISSET(cl->sock, &fds))
455464
{
456465
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
457466
do {
@@ -649,6 +658,30 @@ size_t fuzz_size;
649658
const uint8_t *fuzz_data;
650659
#endif
651660

661+
int
662+
rfbDefaultReadFromSocket(rfbClientPtr cl, char *buf, int len)
663+
{
664+
return read(cl->sock, buf, len);
665+
}
666+
667+
static int
668+
rfbReadFromSocket(rfbClientPtr cl, char *buf, int len)
669+
{
670+
return cl->readFromSocket(cl, buf, len);
671+
}
672+
673+
rfbBool
674+
rfbDefaultHasPendingOnSocket(rfbClientPtr cl)
675+
{
676+
return FALSE;
677+
}
678+
679+
static rfbBool
680+
rfbHasPendingOnSocket(rfbClientPtr cl)
681+
{
682+
return cl->hasPendingOnSocket(cl);
683+
}
684+
652685
/*
653686
* ReadExact reads an exact number of bytes from a client. Returns 1 if
654687
* those bytes have been read, 0 if the other end has closed, or -1 if an error
@@ -682,10 +715,10 @@ rfbReadExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout)
682715
} else if (cl->sslctx) {
683716
n = rfbssl_read(cl, buf, len);
684717
} else {
685-
n = read(sock, buf, len);
718+
n = rfbReadFromSocket(cl, buf, len);
686719
}
687720
#else
688-
n = read(sock, buf, len);
721+
n = rfbReadFromSocket(cl, buf, len);
689722
#endif
690723

691724
if (n > 0) {
@@ -717,6 +750,10 @@ rfbReadExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout)
717750
continue;
718751
}
719752
#endif
753+
754+
if (rfbHasPendingOnSocket(cl))
755+
continue;
756+
720757
FD_ZERO(&fds);
721758
FD_SET(sock, &fds);
722759
tv.tv_sec = timeout / 1000;
@@ -753,6 +790,18 @@ int rfbReadExact(rfbClientPtr cl,char* buf,int len)
753790
return(rfbReadExactTimeout(cl,buf,len,rfbMaxClientWait));
754791
}
755792

793+
int
794+
rfbDefaultPeekAtSocket(rfbClientPtr cl, char *buf, int len)
795+
{
796+
return recv(cl->sock, buf, len, MSG_PEEK);
797+
}
798+
799+
int
800+
rfbPeekAtSocket(rfbClientPtr cl, char *buf, int len)
801+
{
802+
return cl->peekAtSocket(cl, buf, len);
803+
}
804+
756805
/*
757806
* PeekExact peeks at an exact number of bytes from a client. Returns 1 if
758807
* those bytes have been read, 0 if the other end has closed, or -1 if an
@@ -785,7 +834,7 @@ rfbPeekExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout)
785834
n = rfbssl_peek(cl, buf, len);
786835
else
787836
#endif
788-
n = recv(sock, buf, len, MSG_PEEK);
837+
n = rfbPeekAtSocket(cl, buf, len);
789838

790839
if (n == len) {
791840

@@ -841,6 +890,22 @@ rfbPeekExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout)
841890
return 1;
842891
}
843892

893+
int
894+
rfbDefaultWriteToSocket(rfbClientPtr cl,
895+
const char *buf,
896+
int len)
897+
{
898+
return write(cl->sock, buf, len);
899+
}
900+
901+
static int
902+
rfbWriteToSocket(rfbClientPtr cl,
903+
const char *buf,
904+
int len)
905+
{
906+
return cl->writeToSocket(cl, buf, len);
907+
}
908+
844909
/*
845910
* WriteExact writes an exact number of bytes to a client. Returns 1 if
846911
* those bytes have been written, or -1 if an error occurred (errno is set to
@@ -905,7 +970,7 @@ rfbWriteExact(rfbClientPtr cl,
905970
n = rfbssl_write(cl, buf, len);
906971
else
907972
#endif
908-
n = write(sock, buf, len);
973+
n = rfbWriteToSocket(cl, buf, len);
909974

910975
if (n > 0) {
911976

0 commit comments

Comments
 (0)