Skip to content

Commit b7d57ea

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 a9f95d8 commit b7d57ea

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
@@ -324,6 +324,10 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
324324

325325
cl->screen = rfbScreen;
326326
cl->sock = sock;
327+
cl->readFromSocket = rfbDefaultReadFromSocket;
328+
cl->peekAtSocket = rfbDefaultPeekAtSocket;
329+
cl->hasPendingOnSocket = rfbDefaultHasPendingOnSocket;
330+
cl->writeToSocket = rfbDefaultWriteToSocket;
327331
cl->viewOnly = FALSE;
328332
/* setup pseudo scaling */
329333
cl->scaledScreen = rfbScreen;

libvncserver/sockets.c

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

138+
static rfbBool
139+
rfbHasPendingOnSocket(rfbClientPtr cl);
140+
138141
static rfbBool
139142
rfbNewConnectionFromSock(rfbScreenInfoPtr rfbScreen, int sock)
140143
{
@@ -379,16 +382,20 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec)
379382
tv.tv_usec = usec;
380383
nfds = select(rfbScreen->maxFd + 1, &fds, NULL, NULL /* &fds */, &tv);
381384
if (nfds == 0) {
385+
rfbBool hasPendingData = FALSE;
386+
382387
/* timed out, check for async events */
383388
i = rfbGetClientIterator(rfbScreen);
384389
while((cl = rfbClientIteratorNext(i))) {
385390
if (cl->onHold)
386391
continue;
392+
hasPendingData |= rfbHasPendingOnSocket(cl);
387393
if (FD_ISSET(cl->sock, &(rfbScreen->allFds)))
388394
rfbSendFileTransferChunk(cl);
389395
}
390396
rfbReleaseClientIterator(i);
391-
return result;
397+
if (!hasPendingData)
398+
return result;
392399
}
393400

394401
if (nfds < 0) {
@@ -464,9 +471,11 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec)
464471
if (cl->onHold)
465472
continue;
466473

467-
if (FD_ISSET(cl->sock, &(rfbScreen->allFds)))
474+
if (rfbHasPendingOnSocket (cl) ||
475+
FD_ISSET(cl->sock, &(rfbScreen->allFds)))
468476
{
469-
if (FD_ISSET(cl->sock, &fds))
477+
if (rfbHasPendingOnSocket (cl) ||
478+
FD_ISSET(cl->sock, &fds))
470479
{
471480
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
472481
do {
@@ -629,6 +638,30 @@ rfbConnect(rfbScreenInfoPtr rfbScreen,
629638
return sock;
630639
}
631640

641+
int
642+
rfbDefaultReadFromSocket(rfbClientPtr cl, char *buf, int len)
643+
{
644+
return read(cl->sock, buf, len);
645+
}
646+
647+
static int
648+
rfbReadFromSocket(rfbClientPtr cl, char *buf, int len)
649+
{
650+
return cl->readFromSocket(cl, buf, len);
651+
}
652+
653+
rfbBool
654+
rfbDefaultHasPendingOnSocket(rfbClientPtr cl)
655+
{
656+
return FALSE;
657+
}
658+
659+
static rfbBool
660+
rfbHasPendingOnSocket(rfbClientPtr cl)
661+
{
662+
return cl->hasPendingOnSocket(cl);
663+
}
664+
632665
/*
633666
* ReadExact reads an exact number of bytes from a client. Returns 1 if
634667
* those bytes have been read, 0 if the other end has closed, or -1 if an error
@@ -650,10 +683,10 @@ rfbReadExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout)
650683
} else if (cl->sslctx) {
651684
n = rfbssl_read(cl, buf, len);
652685
} else {
653-
n = read(sock, buf, len);
686+
n = rfbReadFromSocket(cl, buf, len);
654687
}
655688
#else
656-
n = read(sock, buf, len);
689+
n = rfbReadFromSocket(cl, buf, len);
657690
#endif
658691

659692
if (n > 0) {
@@ -685,6 +718,10 @@ rfbReadExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout)
685718
continue;
686719
}
687720
#endif
721+
722+
if (rfbHasPendingOnSocket(cl))
723+
continue;
724+
688725
FD_ZERO(&fds);
689726
FD_SET(sock, &fds);
690727
tv.tv_sec = timeout / 1000;
@@ -721,6 +758,18 @@ int rfbReadExact(rfbClientPtr cl,char* buf,int len)
721758
return(rfbReadExactTimeout(cl,buf,len,rfbMaxClientWait));
722759
}
723760

761+
int
762+
rfbDefaultPeekAtSocket(rfbClientPtr cl, char *buf, int len)
763+
{
764+
return recv(cl->sock, buf, len, MSG_PEEK);
765+
}
766+
767+
int
768+
rfbPeekAtSocket(rfbClientPtr cl, char *buf, int len)
769+
{
770+
cl->peekAtSocket(cl, buf, len);
771+
}
772+
724773
/*
725774
* PeekExact peeks at an exact number of bytes from a client. Returns 1 if
726775
* those bytes have been read, 0 if the other end has closed, or -1 if an
@@ -741,7 +790,7 @@ rfbPeekExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout)
741790
n = rfbssl_peek(cl, buf, len);
742791
else
743792
#endif
744-
n = recv(sock, buf, len, MSG_PEEK);
793+
n = rfbPeekAtSocket(cl, buf, len);
745794

746795
if (n == len) {
747796

@@ -797,6 +846,22 @@ rfbPeekExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout)
797846
return 1;
798847
}
799848

849+
int
850+
rfbDefaultWriteToSocket(rfbClientPtr cl,
851+
const char *buf,
852+
int len)
853+
{
854+
return write(cl->sock, buf, len);
855+
}
856+
857+
static int
858+
rfbWriteToSocket(rfbClientPtr cl,
859+
const char *buf,
860+
int len)
861+
{
862+
return cl->writeToSocket(cl, buf, len);
863+
}
864+
800865
/*
801866
* WriteExact writes an exact number of bytes to a client. Returns 1 if
802867
* those bytes have been written, or -1 if an error occurred (errno is set to
@@ -841,7 +906,7 @@ rfbWriteExact(rfbClientPtr cl,
841906
n = rfbssl_write(cl, buf, len);
842907
else
843908
#endif
844-
n = write(sock, buf, len);
909+
n = rfbWriteToSocket(cl, buf, len);
845910

846911
if (n > 0) {
847912

rfb/rfb.h

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

431+
typedef int (*ClientReadFromSocket)(struct _rfbClientRec* cl,
432+
char *buf, int len);
433+
typedef int (*ClientPeekAtSocket)(struct _rfbClientRec* cl,
434+
char *buf, int len);
435+
typedef rfbBool (*ClientHasPendingOnSocket)(struct _rfbClientRec* cl);
436+
typedef int (*ClientWriteToSocket)(struct _rfbClientRec* cl,
437+
const char *buf, int len);
438+
431439
typedef struct _rfbFileTransferData {
432440
int fd;
433441
int compressionEnabled;
@@ -719,6 +727,11 @@ typedef struct _rfbClientRec {
719727
rfbBool useExtDesktopSize;
720728
int requestedDesktopSizeChange;
721729
int lastDesktopSizeChangeError;
730+
731+
ClientReadFromSocket readFromSocket; /* Read data from socket */
732+
ClientPeekAtSocket peekAtSocket; /* Peek at data from socket */
733+
ClientHasPendingOnSocket hasPendingOnSocket; /* Peek at data from socket */
734+
ClientWriteToSocket writeToSocket; /* Write data to socket */
722735
} rfbClientRec, *rfbClientPtr;
723736

724737
/**
@@ -771,8 +784,12 @@ extern void rfbDisconnectUDPSock(rfbScreenInfoPtr rfbScreen);
771784
extern void rfbCloseClient(rfbClientPtr cl);
772785
extern int rfbReadExact(rfbClientPtr cl, char *buf, int len);
773786
extern int rfbReadExactTimeout(rfbClientPtr cl, char *buf, int len,int timeout);
787+
extern int rfbDefaultReadFromSocket(rfbClientPtr cl, char *buf, int len);
774788
extern int rfbPeekExactTimeout(rfbClientPtr cl, char *buf, int len,int timeout);
789+
extern int rfbDefaultPeekAtSocket(rfbClientPtr cl, char *buf, int len);
790+
extern rfbBool rfbDefaultHasPendingOnSocket(rfbClientPtr cl);
775791
extern int rfbWriteExact(rfbClientPtr cl, const char *buf, int len);
792+
extern int rfbDefaultWriteToSocket(rfbClientPtr cl, const char *buf, int len);
776793
extern int rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec);
777794
extern int rfbConnect(rfbScreenInfoPtr rfbScreen, char* host, int port);
778795
extern int rfbConnectToTcpAddr(char* host, int port);

0 commit comments

Comments
 (0)