Thread safety for zrle, zlib, tight.

Proposed tight security type fix for debian bug 517422.
pull/1/head
runge 15 years ago
parent 2cd48332e0
commit 804335f9d2

@ -1,3 +1,16 @@
2009-05-21 Karl Runge <runge@karlrunge.com>
* configure.ac: check for __thread.
* libvncserver/main.c, libvncserver/rfbserver.c: various
thread safe corrections including sendMutex guard.
* libvncserver/zrle.c, libvncserver/zrleencodetemplate.c:
thread safety via per-client buffers.
* libvncserver/tight.c, libvncserver/zlib.c: thread safety
corrections via thread local storage using __thread.
* rfb/rfb.h: new members for threaded usage.
* tightvnc-filetransfer/rfbtightserver.c: fix (currently disabled)
for tight security type for RFB 3.8 (debian bug 517422.)
NEEDS AUDIT.
2009-03-12 Johannes E. Schindelin <Johannes.Schindelin@gmx.de> 2009-03-12 Johannes E. Schindelin <Johannes.Schindelin@gmx.de>
* client_examples/SDLvncviewer.c: support mouse wheel operations * client_examples/SDLvncviewer.c: support mouse wheel operations

@ -628,6 +628,13 @@ if test "x$with_pthread" != "xno"; then
fi fi
AM_CONDITIONAL(HAVE_LIBPTHREAD, test ! -z "$HAVE_LIBPTHREAD") AM_CONDITIONAL(HAVE_LIBPTHREAD, test ! -z "$HAVE_LIBPTHREAD")
AC_MSG_CHECKING([for __thread])
AC_LINK_IFELSE([AC_LANG_PROGRAM(, [static __thread int p = 0])],
[AC_DEFINE(HAVE_TLS, 1,
Define to 1 if compiler supports __thread)
AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])])
# tightvnc-filetransfer implemented using threads: # tightvnc-filetransfer implemented using threads:
if test -z "$HAVE_LIBPTHREAD"; then if test -z "$HAVE_LIBPTHREAD"; then
with_tightvnc_filetransfer="" with_tightvnc_filetransfer=""

@ -444,22 +444,34 @@ clientOutput(void *data)
while (1) { while (1) {
haveUpdate = false; haveUpdate = false;
while (!haveUpdate) { while (!haveUpdate) {
if (cl->sock == -1) { if (cl->sock == -1) {
/* Client has disconnected. */ /* Client has disconnected. */
return NULL; return NULL;
} }
LOCK(cl->updateMutex); if (cl->state != RFB_NORMAL || cl->onHold) {
haveUpdate = FB_UPDATE_PENDING(cl); /* just sleep until things get normal */
if(!haveUpdate) { usleep(cl->screen->deferUpdateTime * 1000);
updateRegion = sraRgnCreateRgn(cl->modifiedRegion); continue;
haveUpdate = sraRgnAnd(updateRegion,cl->requestedRegion); }
sraRgnDestroy(updateRegion);
} LOCK(cl->updateMutex);
if (!haveUpdate) { if (sraRgnEmpty(cl->requestedRegion)) {
WAIT(cl->updateCond, cl->updateMutex); ; /* always require a FB Update Request (otherwise can crash.) */
} } else {
UNLOCK(cl->updateMutex); haveUpdate = FB_UPDATE_PENDING(cl);
if(!haveUpdate) {
updateRegion = sraRgnCreateRgn(cl->modifiedRegion);
haveUpdate = sraRgnAnd(updateRegion,cl->requestedRegion);
sraRgnDestroy(updateRegion);
}
}
if (!haveUpdate) {
WAIT(cl->updateCond, cl->updateMutex);
}
UNLOCK(cl->updateMutex);
} }
/* OK, now, to save bandwidth, wait a little while for more /* OK, now, to save bandwidth, wait a little while for more
@ -476,7 +488,9 @@ clientOutput(void *data)
/* Now actually send the update. */ /* Now actually send the update. */
rfbIncrClientRef(cl); rfbIncrClientRef(cl);
LOCK(cl->sendMutex);
rfbSendFramebufferUpdate(cl, updateRegion); rfbSendFramebufferUpdate(cl, updateRegion);
UNLOCK(cl->sendMutex);
rfbDecrClientRef(cl); rfbDecrClientRef(cl);
sraRgnDestroy(updateRegion); sraRgnDestroy(updateRegion);

@ -327,6 +327,7 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
INIT_MUTEX(cl->outputMutex); INIT_MUTEX(cl->outputMutex);
INIT_MUTEX(cl->refCountMutex); INIT_MUTEX(cl->refCountMutex);
INIT_MUTEX(cl->sendMutex);
INIT_COND(cl->deleteCond); INIT_COND(cl->deleteCond);
cl->state = RFB_PROTOCOL_VERSION; cl->state = RFB_PROTOCOL_VERSION;
@ -550,6 +551,10 @@ rfbClientConnectionGone(rfbClientPtr cl)
UNLOCK(cl->outputMutex); UNLOCK(cl->outputMutex);
TINI_MUTEX(cl->outputMutex); TINI_MUTEX(cl->outputMutex);
LOCK(cl->sendMutex);
UNLOCK(cl->sendMutex);
TINI_MUTEX(cl->sendMutex);
#ifdef CORBA #ifdef CORBA
destroyConnection(cl); destroyConnection(cl);
#endif #endif
@ -1102,9 +1107,11 @@ rfbBool rfbSendFileTransferMessage(rfbClientPtr cl, uint8_t contentType, uint8_t
/* /*
rfbLog("rfbSendFileTransferMessage( %dtype, %dparam, %dsize, %dlen, %p)\n", contentType, contentParam, size, length, buffer); rfbLog("rfbSendFileTransferMessage( %dtype, %dparam, %dsize, %dlen, %p)\n", contentType, contentParam, size, length, buffer);
*/ */
LOCK(cl->sendMutex);
if (rfbWriteExact(cl, (char *)&ft, sz_rfbFileTransferMsg) < 0) { if (rfbWriteExact(cl, (char *)&ft, sz_rfbFileTransferMsg) < 0) {
rfbLogPerror("rfbSendFileTransferMessage: write"); rfbLogPerror("rfbSendFileTransferMessage: write");
rfbCloseClient(cl); rfbCloseClient(cl);
UNLOCK(cl->sendMutex);
return FALSE; return FALSE;
} }
@ -1113,9 +1120,11 @@ rfbBool rfbSendFileTransferMessage(rfbClientPtr cl, uint8_t contentType, uint8_t
if (rfbWriteExact(cl, buffer, length) < 0) { if (rfbWriteExact(cl, buffer, length) < 0) {
rfbLogPerror("rfbSendFileTransferMessage: write"); rfbLogPerror("rfbSendFileTransferMessage: write");
rfbCloseClient(cl); rfbCloseClient(cl);
UNLOCK(cl->sendMutex);
return FALSE; return FALSE;
} }
} }
UNLOCK(cl->sendMutex);
rfbStatRecordMessageSent(cl, rfbFileTransfer, sz_rfbFileTransferMsg+length, sz_rfbFileTransferMsg+length); rfbStatRecordMessageSent(cl, rfbFileTransfer, sz_rfbFileTransferMsg+length, sz_rfbFileTransferMsg+length);
@ -1525,12 +1534,15 @@ rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t con
/* TODO: finish 64-bit file size support */ /* TODO: finish 64-bit file size support */
sizeHtmp = 0; sizeHtmp = 0;
LOCK(cl->sendMutex);
if (rfbWriteExact(cl, (char *)&sizeHtmp, 4) < 0) { if (rfbWriteExact(cl, (char *)&sizeHtmp, 4) < 0) {
rfbLogPerror("rfbProcessFileTransfer: write"); rfbLogPerror("rfbProcessFileTransfer: write");
rfbCloseClient(cl); rfbCloseClient(cl);
UNLOCK(cl->sendMutex);
if (buffer!=NULL) free(buffer); if (buffer!=NULL) free(buffer);
return FALSE; return FALSE;
} }
UNLOCK(cl->sendMutex);
break; break;
case rfbFileHeader: case rfbFileHeader:
@ -2122,6 +2134,7 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
if (!cl->format.trueColour) { if (!cl->format.trueColour) {
if (!rfbSetClientColourMap(cl, 0, 0)) { if (!rfbSetClientColourMap(cl, 0, 0)) {
sraRgnDestroy(tmpRegion); sraRgnDestroy(tmpRegion);
TSIGNAL(cl->updateCond);
UNLOCK(cl->updateMutex); UNLOCK(cl->updateMutex);
return; return;
} }
@ -3103,12 +3116,15 @@ rfbSendSetColourMapEntries(rfbClientPtr cl,
len += nColours * 3 * 2; len += nColours * 3 * 2;
LOCK(cl->sendMutex);
if (rfbWriteExact(cl, wbuf, len) < 0) { if (rfbWriteExact(cl, wbuf, len) < 0) {
rfbLogPerror("rfbSendSetColourMapEntries: write"); rfbLogPerror("rfbSendSetColourMapEntries: write");
rfbCloseClient(cl); rfbCloseClient(cl);
if (wbuf != buf) free(wbuf); if (wbuf != buf) free(wbuf);
UNLOCK(cl->sendMutex);
return FALSE; return FALSE;
} }
UNLOCK(cl->sendMutex);
rfbStatRecordMessageSent(cl, rfbSetColourMapEntries, len, len); rfbStatRecordMessageSent(cl, rfbSetColourMapEntries, len, len);
if (wbuf != buf) free(wbuf); if (wbuf != buf) free(wbuf);
@ -3129,10 +3145,12 @@ rfbSendBell(rfbScreenInfoPtr rfbScreen)
i = rfbGetClientIterator(rfbScreen); i = rfbGetClientIterator(rfbScreen);
while((cl=rfbClientIteratorNext(i))) { while((cl=rfbClientIteratorNext(i))) {
b.type = rfbBell; b.type = rfbBell;
LOCK(cl->sendMutex);
if (rfbWriteExact(cl, (char *)&b, sz_rfbBellMsg) < 0) { if (rfbWriteExact(cl, (char *)&b, sz_rfbBellMsg) < 0) {
rfbLogPerror("rfbSendBell: write"); rfbLogPerror("rfbSendBell: write");
rfbCloseClient(cl); rfbCloseClient(cl);
} }
UNLOCK(cl->sendMutex);
} }
rfbStatRecordMessageSent(cl, rfbBell, sz_rfbBellMsg, sz_rfbBellMsg); rfbStatRecordMessageSent(cl, rfbBell, sz_rfbBellMsg, sz_rfbBellMsg);
rfbReleaseClientIterator(i); rfbReleaseClientIterator(i);
@ -3154,16 +3172,19 @@ rfbSendServerCutText(rfbScreenInfoPtr rfbScreen,char *str, int len)
while ((cl = rfbClientIteratorNext(iterator)) != NULL) { while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
sct.type = rfbServerCutText; sct.type = rfbServerCutText;
sct.length = Swap32IfLE(len); sct.length = Swap32IfLE(len);
LOCK(cl->sendMutex);
if (rfbWriteExact(cl, (char *)&sct, if (rfbWriteExact(cl, (char *)&sct,
sz_rfbServerCutTextMsg) < 0) { sz_rfbServerCutTextMsg) < 0) {
rfbLogPerror("rfbSendServerCutText: write"); rfbLogPerror("rfbSendServerCutText: write");
rfbCloseClient(cl); rfbCloseClient(cl);
UNLOCK(cl->sendMutex);
continue; continue;
} }
if (rfbWriteExact(cl, str, len) < 0) { if (rfbWriteExact(cl, str, len) < 0) {
rfbLogPerror("rfbSendServerCutText: write"); rfbLogPerror("rfbSendServerCutText: write");
rfbCloseClient(cl); rfbCloseClient(cl);
} }
UNLOCK(cl->sendMutex);
rfbStatRecordMessageSent(cl, rfbServerCutText, sz_rfbServerCutTextMsg+len, sz_rfbServerCutTextMsg+len); rfbStatRecordMessageSent(cl, rfbServerCutText, sz_rfbServerCutTextMsg+len, sz_rfbServerCutTextMsg+len);
} }
rfbReleaseClientIterator(iterator); rfbReleaseClientIterator(iterator);

@ -47,9 +47,20 @@
/* May be set to TRUE with "-lazytight" Xvnc option. */ /* May be set to TRUE with "-lazytight" Xvnc option. */
rfbBool rfbTightDisableGradient = FALSE; rfbBool rfbTightDisableGradient = FALSE;
/* This variable is set on every rfbSendRectEncodingTight() call. */ /*
static rfbBool usePixelFormat24; * There is so much access of the Tight encoding static data buffers
* that we resort to using thread local storage instead of having
* per-client data.
*/
#if LIBVNCSERVER_HAVE_LIBPTHREAD && LIBVNCSERVER_HAVE_TLS && !defined(TLS) && defined(__linux__)
#define TLS __thread
#endif
#ifndef TLS
#define TLS
#endif
/* This variable is set on every rfbSendRectEncodingTight() call. */
static TLS rfbBool usePixelFormat24 = FALSE;
/* Compression level stuff. The following array contains various /* Compression level stuff. The following array contains various
encoder parameters for each of 10 compression levels (0..9). encoder parameters for each of 10 compression levels (0..9).
@ -77,8 +88,8 @@ static TIGHT_CONF tightConf[10] = {
{ 65536, 2048, 32, 8192, 9, 9, 9, 6, 200, 500, 96, 80, 200, 500 } { 65536, 2048, 32, 8192, 9, 9, 9, 6, 200, 500, 96, 80, 200, 500 }
}; };
static int compressLevel; static TLS int compressLevel = 0;
static int qualityLevel; static TLS int qualityLevel = 0;
/* Stuff dealing with palettes. */ /* Stuff dealing with palettes. */
@ -100,29 +111,33 @@ typedef struct PALETTE_s {
} PALETTE; } PALETTE;
/* TODO: move into rfbScreen struct */ /* TODO: move into rfbScreen struct */
static int paletteNumColors, paletteMaxColors; static TLS int paletteNumColors = 0;
static uint32_t monoBackground, monoForeground; static TLS int paletteMaxColors = 0;
static PALETTE palette; static TLS uint32_t monoBackground = 0;
static TLS uint32_t monoForeground = 0;
static TLS PALETTE palette;
/* Pointers to dynamically-allocated buffers. */ /* Pointers to dynamically-allocated buffers. */
static int tightBeforeBufSize = 0; static TLS int tightBeforeBufSize = 0;
static char *tightBeforeBuf = NULL; static TLS char *tightBeforeBuf = NULL;
static int tightAfterBufSize = 0; static TLS int tightAfterBufSize = 0;
static char *tightAfterBuf = NULL; static TLS char *tightAfterBuf = NULL;
static int *prevRowBuf = NULL; static TLS int *prevRowBuf = NULL;
void rfbTightCleanup(rfbScreenInfoPtr screen) void rfbTightCleanup(rfbScreenInfoPtr screen)
{ {
if(tightBeforeBufSize) { if(tightBeforeBufSize) {
free(tightBeforeBuf); free(tightBeforeBuf);
tightBeforeBufSize=0; tightBeforeBufSize=0;
tightBeforeBuf = NULL;
} }
if(tightAfterBufSize) { if(tightAfterBufSize) {
free(tightAfterBuf); free(tightAfterBuf);
tightAfterBufSize=0; tightAfterBufSize=0;
tightAfterBuf = NULL;
} }
} }
@ -1627,9 +1642,9 @@ DEFINE_DETECT_FUNCTION(32)
* JPEG compression stuff. * JPEG compression stuff.
*/ */
static struct jpeg_destination_mgr jpegDstManager; static TLS struct jpeg_destination_mgr jpegDstManager;
static rfbBool jpegError; static TLS rfbBool jpegError = FALSE;
static int jpegDstDataLen; static TLS int jpegDstDataLen = 0;
static rfbBool static rfbBool
SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h, int quality) SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h, int quality)

@ -74,6 +74,24 @@ rfbVncAuthSendChallenge(rfbClientPtr cl)
} }
/*
* LibVNCServer has a bug WRT Tight SecurityType and RFB 3.8
* It should send auth result even for rfbAuthNone.
* See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=517422
* For testing set USE_SECTYPE_TIGHT_FOR_RFB_3_8 when compiling
* or set it here.
*/
#define SECTYPE_TIGHT_FOR_RFB_3_8 \
if (cl->protocolMajorVersion==3 && cl->protocolMinorVersion > 7) { \
uint32_t authResult; \
rfbLog("rfbProcessClientSecurityType: returning securityResult for client rfb version >= 3.8\n"); \
authResult = Swap32IfLE(rfbVncAuthOK); \
if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) { \
rfbLogPerror("rfbAuthProcessClientMessage: write"); \
rfbCloseClient(cl); \
return; \
} \
}
/* /*
* Read client's preferred authentication type (protocol 3.7t). * Read client's preferred authentication type (protocol 3.7t).
*/ */
@ -117,6 +135,9 @@ rfbProcessClientAuthType(rfbClientPtr cl)
switch (auth_type) { switch (auth_type) {
case rfbAuthNone: case rfbAuthNone:
/* Dispatch client input to rfbProcessClientInitMessage. */ /* Dispatch client input to rfbProcessClientInitMessage. */
#ifdef USE_SECTYPE_TIGHT_FOR_RFB_3_8
SECTYPE_TIGHT_FOR_RFB_3_8
#endif
cl->state = RFB_INITIALISATION; cl->state = RFB_INITIALISATION;
break; break;
case rfbAuthVNC: case rfbAuthVNC:
@ -188,6 +209,9 @@ rfbSendAuthCaps(rfbClientPtr cl)
/* Call the function for authentication from here */ /* Call the function for authentication from here */
rfbProcessClientAuthType(cl); rfbProcessClientAuthType(cl);
} else { } else {
#ifdef USE_SECTYPE_TIGHT_FOR_RFB_3_8
SECTYPE_TIGHT_FOR_RFB_3_8
#endif
/* Dispatch client input to rfbProcessClientInitMessage. */ /* Dispatch client input to rfbProcessClientInitMessage. */
cl->state = RFB_INITIALISATION; cl->state = RFB_INITIALISATION;
} }

@ -40,12 +40,24 @@
* raw encoding is used instead. * raw encoding is used instead.
*/ */
static int zlibBeforeBufSize = 0; /*
static char *zlibBeforeBuf = NULL; * Out of lazyiness, we use thread local storage for zlib as we did for
* tight. N.B. ZRLE does it the traditional way with per-client storage
static int zlibAfterBufSize = 0; * (and so at least ZRLE will work threaded on older systems.)
static char *zlibAfterBuf = NULL; */
static int zlibAfterBufLen; #if LIBVNCSERVER_HAVE_LIBPTHREAD && LIBVNCSERVER_HAVE_TLS && !defined(TLS) && defined(__linux__)
#define TLS __thread
#endif
#ifndef TLS
#define TLS
#endif
static TLS int zlibBeforeBufSize = 0;
static TLS char *zlibBeforeBuf = NULL;
static TLS int zlibAfterBufSize = 0;
static TLS char *zlibAfterBuf = NULL;
static TLS int zlibAfterBufLen = 0;
void rfbZlibCleanup(rfbScreenInfoPtr screen) void rfbZlibCleanup(rfbScreenInfoPtr screen)
{ {

@ -97,21 +97,25 @@
*/ */
/* TODO: put into rfbClient struct */ /* TODO: put into rfbClient struct */
static char zrleBeforeBuf[rfbZRLETileWidth * rfbZRLETileHeight * 4 + 4];
static char zrleBeforeBuf[rfbZRLETileWidth * rfbZRLETileHeight * 4 + 4];
/* /*
* rfbSendRectEncodingZRLE - send a given rectangle using ZRLE encoding. * rfbSendRectEncodingZRLE - send a given rectangle using ZRLE encoding.
*/ */
rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h) rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h)
{ {
zrleOutStream* zos; zrleOutStream* zos;
rfbFramebufferUpdateRectHeader rect; rfbFramebufferUpdateRectHeader rect;
rfbZRLEHeader hdr; rfbZRLEHeader hdr;
int i; int i;
char *zrleBeforeBuf;
if (cl->zrleBeforeBuf == NULL) {
cl->zrleBeforeBuf = (char *) malloc(rfbZRLETileWidth * rfbZRLETileHeight * 4 + 4);
}
zrleBeforeBuf = cl->zrleBeforeBuf;
if (cl->preferredEncoding == rfbEncodingZYWRLE) { if (cl->preferredEncoding == rfbEncodingZYWRLE) {
if (cl->tightQualityLevel < 0) { if (cl->tightQualityLevel < 0) {
@ -238,8 +242,19 @@ rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h)
void rfbFreeZrleData(rfbClientPtr cl) void rfbFreeZrleData(rfbClientPtr cl)
{ {
if (cl->zrleData) if (cl->zrleData) {
zrleOutStreamFree(cl->zrleData); zrleOutStreamFree(cl->zrleData);
cl->zrleData = NULL; }
cl->zrleData = NULL;
if (cl->zrleBeforeBuf) {
free(cl->zrleBeforeBuf);
}
cl->zrleBeforeBuf = NULL;
if (cl->paletteHelper) {
free(cl->paletteHelper);
}
cl->paletteHelper = NULL;
} }

@ -89,7 +89,7 @@ static zrlePaletteHelper paletteHelper;
#endif /* ZRLE_ONCE */ #endif /* ZRLE_ONCE */
void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os, void ZRLE_ENCODE_TILE (PIXEL_T* data, int w, int h, zrleOutStream* os,
int zywrle_level, int *zywrleBuf); int zywrle_level, int *zywrleBuf, void *paletteHelper);
#if BPP!=8 #if BPP!=8
#define ZYWRLE_ENCODE #define ZYWRLE_ENCODE
@ -111,8 +111,12 @@ static void ZRLE_ENCODE (int x, int y, int w, int h,
GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf); GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf);
if (cl->paletteHelper == NULL) {
cl->paletteHelper = (void *) calloc(sizeof(zrlePaletteHelper), 1);
}
ZRLE_ENCODE_TILE((PIXEL_T*)buf, tw, th, os, ZRLE_ENCODE_TILE((PIXEL_T*)buf, tw, th, os,
cl->zywrleLevel, cl->zywrleBuf); cl->zywrleLevel, cl->zywrleBuf, cl->paletteHelper);
} }
} }
zrleOutStreamFlush(os); zrleOutStreamFlush(os);
@ -120,7 +124,7 @@ static void ZRLE_ENCODE (int x, int y, int w, int h,
void ZRLE_ENCODE_TILE(PIXEL_T* data, int w, int h, zrleOutStream* os, void ZRLE_ENCODE_TILE(PIXEL_T* data, int w, int h, zrleOutStream* os,
int zywrle_level, int *zywrleBuf) int zywrle_level, int *zywrleBuf, void *paletteHelper)
{ {
/* First find the palette and the number of runs */ /* First find the palette and the number of runs */
@ -140,7 +144,11 @@ void ZRLE_ENCODE_TILE(PIXEL_T* data, int w, int h, zrleOutStream* os,
PIXEL_T* end = ptr + h * w; PIXEL_T* end = ptr + h * w;
*end = ~*(end-1); /* one past the end is different so the while loop ends */ *end = ~*(end-1); /* one past the end is different so the while loop ends */
#if 0
ph = &paletteHelper; ph = &paletteHelper;
#else
ph = (zrlePaletteHelper *) paletteHelper;
#endif
zrlePaletteHelperInit(ph); zrlePaletteHelperInit(ph);
while (ptr < end) { while (ptr < end) {
@ -289,7 +297,7 @@ void ZRLE_ENCODE_TILE(PIXEL_T* data, int w, int h, zrleOutStream* os,
#if BPP!=8 #if BPP!=8
if (zywrle_level > 0 && !(zywrle_level & 0x80)) { if (zywrle_level > 0 && !(zywrle_level & 0x80)) {
ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, zywrleBuf); ZYWRLE_ANALYZE(data, data, w, h, w, zywrle_level, zywrleBuf);
ZRLE_ENCODE_TILE(data, w, h, os, zywrle_level | 0x80, zywrleBuf); ZRLE_ENCODE_TILE(data, w, h, os, zywrle_level | 0x80, zywrleBuf, paletteHelper);
} }
else else
#endif #endif

@ -589,6 +589,17 @@ typedef struct _rfbClientRec {
int progressiveSliceY; int progressiveSliceY;
rfbExtensionData* extensions; rfbExtensionData* extensions;
/* for threaded zrle */
char *zrleBeforeBuf;
void *paletteHelper;
/* for thread safety for rfbSendFBUpdate() */
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
#define LIBVNCSERVER_SEND_MUTEX
MUTEX(sendMutex);
#endif
} rfbClientRec, *rfbClientPtr; } rfbClientRec, *rfbClientPtr;
/* /*

Loading…
Cancel
Save