Skip to content

Commit 450f4a5

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 38fd347 commit 450f4a5

File tree

3 files changed

+93
-7
lines changed

3 files changed

+93
-7
lines changed

libvncserver/rfbserver.c

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

320320
cl->screen = rfbScreen;
321321
cl->sock = sock;
322+
cl->readFromSocket = rfbDefaultReadFromSocket;
323+
cl->peekAtSocket = rfbDefaultPeekAtSocket;
324+
cl->hasPendingOnSocket = rfbDefaultHasPendingOnSocket;
325+
cl->writeToSocket = rfbDefaultWriteToSocket;
322326
cl->viewOnly = FALSE;
323327
/* setup pseudo scaling */
324328
cl->scaledScreen = rfbScreen;

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 {
@@ -614,6 +623,30 @@ rfbConnect(rfbScreenInfoPtr rfbScreen,
614623
return sock;
615624
}
616625

626+
int
627+
rfbDefaultReadFromSocket(rfbClientPtr cl, char *buf, int len)
628+
{
629+
return read(cl->sock, buf, len);
630+
}
631+
632+
static int
633+
rfbReadFromSocket(rfbClientPtr cl, char *buf, int len)
634+
{
635+
return cl->readFromSocket(cl, buf, len);
636+
}
637+
638+
rfbBool
639+
rfbDefaultHasPendingOnSocket(rfbClientPtr cl)
640+
{
641+
return FALSE;
642+
}
643+
644+
static rfbBool
645+
rfbHasPendingOnSocket(rfbClientPtr cl)
646+
{
647+
return cl->hasPendingOnSocket(cl);
648+
}
649+
617650
/*
618651
* ReadExact reads an exact number of bytes from a client. Returns 1 if
619652
* 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)
635668
} else if (cl->sslctx) {
636669
n = rfbssl_read(cl, buf, len);
637670
} else {
638-
n = read(sock, buf, len);
671+
n = rfbReadFromSocket(cl, buf, len);
639672
}
640673
#else
641-
n = read(sock, buf, len);
674+
n = rfbReadFromSocket(cl, buf, len);
642675
#endif
643676

644677
if (n > 0) {
@@ -670,6 +703,10 @@ rfbReadExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout)
670703
continue;
671704
}
672705
#endif
706+
707+
if (rfbHasPendingOnSocket(cl))
708+
continue;
709+
673710
FD_ZERO(&fds);
674711
FD_SET(sock, &fds);
675712
tv.tv_sec = timeout / 1000;
@@ -706,6 +743,18 @@ int rfbReadExact(rfbClientPtr cl,char* buf,int len)
706743
return(rfbReadExactTimeout(cl,buf,len,rfbMaxClientWait));
707744
}
708745

746+
int
747+
rfbDefaultPeekAtSocket(rfbClientPtr cl, char *buf, int len)
748+
{
749+
return recv(cl->sock, buf, len, MSG_PEEK);
750+
}
751+
752+
int
753+
rfbPeekAtSocket(rfbClientPtr cl, char *buf, int len)
754+
{
755+
cl->peekAtSocket(cl, buf, len);
756+
}
757+
709758
/*
710759
* PeekExact peeks at an exact number of bytes from a client. Returns 1 if
711760
* 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)
726775
n = rfbssl_peek(cl, buf, len);
727776
else
728777
#endif
729-
n = recv(sock, buf, len, MSG_PEEK);
778+
n = rfbPeekAtSocket(cl, buf, len);
730779

731780
if (n == len) {
732781

@@ -782,6 +831,22 @@ rfbPeekExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout)
782831
return 1;
783832
}
784833

834+
int
835+
rfbDefaultWriteToSocket(rfbClientPtr cl,
836+
const char *buf,
837+
int len)
838+
{
839+
return write(cl->sock, buf, len);
840+
}
841+
842+
static int
843+
rfbWriteToSocket(rfbClientPtr cl,
844+
const char *buf,
845+
int len)
846+
{
847+
return cl->writeToSocket(cl, buf, len);
848+
}
849+
785850
/*
786851
* WriteExact writes an exact number of bytes to a client. Returns 1 if
787852
* those bytes have been written, or -1 if an error occurred (errno is set to
@@ -826,7 +891,7 @@ rfbWriteExact(rfbClientPtr cl,
826891
n = rfbssl_write(cl, buf, len);
827892
else
828893
#endif
829-
n = write(sock, buf, len);
894+
n = rfbWriteToSocket(cl, buf, len);
830895

831896
if (n > 0) {
832897

rfb/rfb.h

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

390+
typedef int (*ClientReadFromSocket)(struct _rfbClientRec* cl,
391+
char *buf, int len);
392+
typedef int (*ClientPeekAtSocket)(struct _rfbClientRec* cl,
393+
char *buf, int len);
394+
typedef rfbBool (*ClientHasPendingOnSocket)(struct _rfbClientRec* cl);
395+
typedef int (*ClientWriteToSocket)(struct _rfbClientRec* cl,
396+
const char *buf, int len);
397+
390398
typedef struct _rfbFileTransferData {
391399
int fd;
392400
int compressionEnabled;
@@ -680,6 +688,11 @@ typedef struct _rfbClientRec {
680688
rfbBool useExtDesktopSize;
681689
int requestedDesktopSizeChange;
682690
int lastDesktopSizeChangeError;
691+
692+
ClientReadFromSocket readFromSocket; /* Read data from socket */
693+
ClientPeekAtSocket peekAtSocket; /* Peek at data from socket */
694+
ClientHasPendingOnSocket hasPendingOnSocket; /* Peek at data from socket */
695+
ClientWriteToSocket writeToSocket; /* Write data to socket */
683696
} rfbClientRec, *rfbClientPtr;
684697

685698
/**
@@ -732,8 +745,12 @@ extern void rfbDisconnectUDPSock(rfbScreenInfoPtr rfbScreen);
732745
extern void rfbCloseClient(rfbClientPtr cl);
733746
extern int rfbReadExact(rfbClientPtr cl, char *buf, int len);
734747
extern int rfbReadExactTimeout(rfbClientPtr cl, char *buf, int len,int timeout);
748+
extern int rfbDefaultReadFromSocket(rfbClientPtr cl, char *buf, int len);
735749
extern int rfbPeekExactTimeout(rfbClientPtr cl, char *buf, int len,int timeout);
750+
extern int rfbDefaultPeekAtSocket(rfbClientPtr cl, char *buf, int len);
751+
extern rfbBool rfbDefaultHasPendingOnSocket(rfbClientPtr cl);
736752
extern int rfbWriteExact(rfbClientPtr cl, const char *buf, int len);
753+
extern int rfbDefaultWriteToSocket(rfbClientPtr cl, const char *buf, int len);
737754
extern int rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec);
738755
extern rfbSocket rfbConnect(rfbScreenInfoPtr rfbScreen, char* host, int port);
739756
extern rfbSocket rfbConnectToTcpAddr(char* host, int port);

0 commit comments

Comments
 (0)