int main(int argc,char** argv) { rfbFontDataPtr font; rfbScreenInfoPtr s=rfbGetScreen(&argc,argv,640,480,8,3,3); int i,j; s->frameBuffer=(char*)malloc(640*480*3); rfbInitServer(s); for(j=0;j<480;j++) for(i=0;i<640;i++) { s->frameBuffer[(j*640+i)*3+0]=j*256/480; s->frameBuffer[(j*640+i)*3+1]=i*256/640; s->frameBuffer[(j*640+i)*3+2]=(i+j)*256/(480+640); } rfbScreen = s; font=rfbLoadConsoleFont(DEFAULTFONT); if(!font) { rfbErr("Couldn't find %s\n",DEFAULTFONT); exit(1); } for(j=0;j<0 && rfbIsActive(s);j++) rfbProcessEvents(s,900000); i = rfbSelectBox(s,font,fontlist,10,20,200,300,0xffdfdf,0x602040,2,showFont); rfbLog("Selection: %d: %s\n",i,(i>=0)?fontlist[i]:"cancelled"); rfbFreeFont(font); free(s->frameBuffer); rfbScreenCleanup(s); return(0); }
void FUNCNAME(rfbScreenInfoPtr screen) { if (screen->serverFormat.bitsPerPixel == 32) CONCAT2E(FUNCNAME,32)(screen); else if (screen->serverFormat.bitsPerPixel == 16) CONCAT2E(FUNCNAME,16)(screen); else if (screen->serverFormat.bitsPerPixel == 8) CONCAT2E(FUNCNAME,8)(screen); else { rfbErr("Unsupported pixel depth: %d\n", screen->serverFormat.bitsPerPixel); return; } }
/* * getBgColour() gets the most prevalent colour in a byte array. */ static uint32_t getBgColour(char *data, int size, int bpp) { #define NUMCLRS 256 static int counts[NUMCLRS]; int i,j,k; int maxcount = 0; uint8_t maxclr = 0; if (bpp != 8) { if (bpp == 16) { return ((uint16_t *)data)[0]; } else if (bpp == 32) { return ((uint32_t *)data)[0]; } else { rfbLog("getBgColour: bpp %d?\n",bpp); return 0; } } for (i=0; i<NUMCLRS; i++) { counts[i] = 0; } for (j=0; j<size; j++) { k = (int)(((uint8_t *)data)[j]); if (k >= NUMCLRS) { rfbErr("getBgColour: unusual colour = %d\n", k); return 0; } counts[k] += 1; if (counts[k] > maxcount) { maxcount = counts[k]; maxclr = ((uint8_t *)data)[j]; } } return maxclr; }
rfbBool sraRgnIteratorNext(sraRectangleIterator* i,sraRect* r) { /* is the subspan finished? */ while(sraNextSpan(i) == i->sPtrs[i->ptrPos+1]) { i->ptrPos -= 2; if(i->ptrPos < 0) /* the end */ return(0); } i->sPtrs[i->ptrPos] = sraNextSpan(i); /* is this a new subspan? */ while(i->sPtrs[i->ptrPos]->subspan) { if(i->ptrPos+2 > i->ptrSize) { /* array is too small */ i->ptrSize += DEFSTEP; i->sPtrs = (sraSpan**)realloc(i->sPtrs, sizeof(sraSpan*)*i->ptrSize); } i->ptrPos =+ 2; if(sraReverse(i)) { i->sPtrs[i->ptrPos] = i->sPtrs[i->ptrPos-2]->subspan->back._prev; i->sPtrs[i->ptrPos+1] = &(i->sPtrs[i->ptrPos-2]->subspan->front); } else { i->sPtrs[i->ptrPos] = i->sPtrs[i->ptrPos-2]->subspan->front._next; i->sPtrs[i->ptrPos+1] = &(i->sPtrs[i->ptrPos-2]->subspan->back); } } if((i->ptrPos%4)!=2) { rfbErr("sraRgnIteratorNext: offset is wrong (%d%%4!=2)\n",i->ptrPos); return FALSE; } r->y1 = i->sPtrs[i->ptrPos-2]->start; r->y2 = i->sPtrs[i->ptrPos-2]->end; r->x1 = i->sPtrs[i->ptrPos]->start; r->x2 = i->sPtrs[i->ptrPos]->end; return(-1); }
static int __rfbssl_read(rfbClientPtr cl, char *buf, int bufsize, int peek) { int ret = 0; struct rfbssl_ctx *ctx = (struct rfbssl_ctx *)cl->sslctx; rfbssl_gc_peekbuf(ctx, bufsize); if (ctx->peeklen) { /* If we have any peek data, simply return that. */ ret = bufsize < ctx->peeklen ? bufsize : ctx->peeklen; memcpy (buf, ctx->peekbuf + ctx->peekstart, ret); if (!peek) { ctx->peeklen -= ret; if (ctx->peeklen != 0) ctx->peekstart += ret; else ctx->peekstart = 0; } } if (ret < bufsize) { int n; /* read the remaining data */ if ((n = rfbssl_do_read(cl, buf + ret, bufsize - ret)) <= 0) { rfbErr("rfbssl_%s: %s error\n", __func__, peek ? "peek" : "read"); return n; } if (peek) { memcpy(ctx->peekbuf + ctx->peekstart + ctx->peeklen, buf + ret, n); ctx->peeklen += n; } ret += n; } return ret; }
static void httpProcessInput(rfbScreenInfoPtr rfbScreen) { #ifdef LIBVNCSERVER_IPv6 struct sockaddr_storage addr; char host[1024]; #else struct sockaddr_in addr; #endif socklen_t addrlen = sizeof(addr); char fullFname[512]; char params[1024]; char *ptr; char *fname; unsigned int maxFnameLen; FILE* fd; rfbBool performSubstitutions = FALSE; char str[256+32]; #ifndef WIN32 char* user=getenv("USER"); #endif cl.sock=rfbScreen->httpSock; if (strlen(rfbScreen->httpDir) > 255) { rfbErr("-httpd directory too long\n"); httpCloseSock(rfbScreen); return; } strcpy(fullFname, rfbScreen->httpDir); fname = &fullFname[strlen(fullFname)]; maxFnameLen = 511 - strlen(fullFname); buf_filled=0; /* Read data from the HTTP client until we get a complete request. */ while (1) { ssize_t got; if (buf_filled > sizeof (buf)) { rfbErr("httpProcessInput: HTTP request is too long\n"); httpCloseSock(rfbScreen); return; } got = read (rfbScreen->httpSock, buf + buf_filled, sizeof (buf) - buf_filled - 1); if (got <= 0) { if (got == 0) { rfbErr("httpd: premature connection close\n"); } else { #ifdef WIN32 errno=WSAGetLastError(); #endif if (errno == EAGAIN) { return; } rfbLogPerror("httpProcessInput: read"); } httpCloseSock(rfbScreen); return; } buf_filled += got; buf[buf_filled] = '\0'; /* Is it complete yet (is there a blank line)? */ if (strstr (buf, "\r\r") || strstr (buf, "\n\n") || strstr (buf, "\r\n\r\n") || strstr (buf, "\n\r\n\r")) break; } /* Process the request. */ if(rfbScreen->httpEnableProxyConnect) { const static char* PROXY_OK_STR = "HTTP/1.0 200 OK\r\nContent-Type: octet-stream\r\nPragma: no-cache\r\n\r\n"; if(!strncmp(buf, "CONNECT ", 8)) { if(atoi(strchr(buf, ':')+1)!=rfbScreen->port) { rfbErr("httpd: CONNECT format invalid.\n"); rfbWriteExact(&cl,INVALID_REQUEST_STR, strlen(INVALID_REQUEST_STR)); httpCloseSock(rfbScreen); return; } /* proxy connection */ rfbLog("httpd: client asked for CONNECT\n"); rfbWriteExact(&cl,PROXY_OK_STR,strlen(PROXY_OK_STR)); rfbNewClientConnection(rfbScreen,rfbScreen->httpSock); rfbScreen->httpSock = -1; return; } if (!strncmp(buf, "GET ",4) && !strncmp(strchr(buf,'/'),"/proxied.connection HTTP/1.", 27)) { /* proxy connection */ rfbLog("httpd: client asked for /proxied.connection\n"); rfbWriteExact(&cl,PROXY_OK_STR,strlen(PROXY_OK_STR)); rfbNewClientConnection(rfbScreen,rfbScreen->httpSock); rfbScreen->httpSock = -1; return; } } if (strncmp(buf, "GET ", 4)) { rfbErr("httpd: no GET line\n"); httpCloseSock(rfbScreen); return; } else { /* Only use the first line. */ buf[strcspn(buf, "\n\r")] = '\0'; } if (strlen(buf) > maxFnameLen) { rfbErr("httpd: GET line too long\n"); httpCloseSock(rfbScreen); return; } if (sscanf(buf, "GET %s HTTP/1.", fname) != 1) { rfbErr("httpd: couldn't parse GET line\n"); httpCloseSock(rfbScreen); return; } if (fname[0] != '/') { rfbErr("httpd: filename didn't begin with '/'\n"); rfbWriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR)); httpCloseSock(rfbScreen); return; } getpeername(rfbScreen->httpSock, (struct sockaddr *)&addr, &addrlen); #ifdef LIBVNCSERVER_IPv6 if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) { rfbLogPerror("httpProcessInput: error in getnameinfo"); } rfbLog("httpd: get '%s' for %s\n", fname+1, host); #else rfbLog("httpd: get '%s' for %s\n", fname+1, inet_ntoa(addr.sin_addr)); #endif /* Extract parameters from the URL string if necessary */ params[0] = '\0'; ptr = strchr(fname, '?'); if (ptr != NULL) { *ptr = '\0'; if (!parseParams(&ptr[1], params, 1024)) { params[0] = '\0'; rfbErr("httpd: bad parameters in the URL\n"); } } /* If we were asked for '/', actually read the file index.vnc */ if (strcmp(fname, "/") == 0) { strcpy(fname, "/index.vnc"); rfbLog("httpd: defaulting to '%s'\n", fname+1); } /* Substitutions are performed on files ending .vnc */ if (strlen(fname) >= 4 && strcmp(&fname[strlen(fname)-4], ".vnc") == 0) { performSubstitutions = TRUE; } /* Open the file */ if ((fd = fopen(fullFname, "r")) == 0) { rfbLogPerror("httpProcessInput: open"); rfbWriteExact(&cl, NOT_FOUND_STR, strlen(NOT_FOUND_STR)); httpCloseSock(rfbScreen); return; } if(performSubstitutions) /* is the 'index.vnc' file */ rfbWriteExact(&cl, OK_STR_HTML, strlen(OK_STR_HTML)); else rfbWriteExact(&cl, OK_STR, strlen(OK_STR)); while (1) { int n = fread(buf, 1, BUF_SIZE-1, fd); if (n < 0) { rfbLogPerror("httpProcessInput: read"); fclose(fd); httpCloseSock(rfbScreen); return; } if (n == 0) break; if (performSubstitutions) { /* Substitute $WIDTH, $HEIGHT, etc with the appropriate values. This won't quite work properly if the .vnc file is longer than BUF_SIZE, but it's reasonable to assume that .vnc files will always be short. */ char *ptr = buf; char *dollar; buf[n] = 0; /* make sure it's null-terminated */ while ((dollar = strchr(ptr, '$'))!=NULL) { rfbWriteExact(&cl, ptr, (dollar - ptr)); ptr = dollar; if (compareAndSkip(&ptr, "$WIDTH")) { sprintf(str, "%d", rfbScreen->width); rfbWriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$HEIGHT")) { sprintf(str, "%d", rfbScreen->height); rfbWriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$APPLETWIDTH")) { sprintf(str, "%d", rfbScreen->width); rfbWriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$APPLETHEIGHT")) { sprintf(str, "%d", rfbScreen->height + 32); rfbWriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$PORT")) { sprintf(str, "%d", rfbScreen->port); rfbWriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$DESKTOP")) { rfbWriteExact(&cl, rfbScreen->desktopName, strlen(rfbScreen->desktopName)); } else if (compareAndSkip(&ptr, "$DISPLAY")) { sprintf(str, "%s:%d", rfbScreen->thisHost, rfbScreen->port-5900); rfbWriteExact(&cl, str, strlen(str)); } else if (compareAndSkip(&ptr, "$USER")) { #ifndef WIN32 if (user) { rfbWriteExact(&cl, user, strlen(user)); } else #endif rfbWriteExact(&cl, "?", 1); } else if (compareAndSkip(&ptr, "$PARAMS")) { if (params[0] != '\0') rfbWriteExact(&cl, params, strlen(params)); } else { if (!compareAndSkip(&ptr, "$$")) ptr++; if (rfbWriteExact(&cl, "$", 1) < 0) { fclose(fd); httpCloseSock(rfbScreen); return; } } } if (rfbWriteExact(&cl, ptr, (&buf[n] - ptr)) < 0) break; } else { /* For files not ending .vnc, just write out the buffer */ if (rfbWriteExact(&cl, buf, n) < 0) break; } } fclose(fd); httpCloseSock(rfbScreen); }
int rfbWriteExact(rfbClientPtr cl, const char *buf, int len) { int sock = cl->sock; int n; fd_set fds; struct timeval tv; int totalTimeWaited = 0; #undef DEBUG_WRITE_EXACT #ifdef DEBUG_WRITE_EXACT rfbLog("WriteExact %d bytes\n",len); for(n=0; n<len; n++) fprintf(stderr,"%02x ",(unsigned char)buf[n]); fprintf(stderr,"\n"); #endif LOCK(cl->outputMutex); while (len > 0) { n = write(sock, buf, len); if (n > 0) { buf += n; len -= n; } else if (n == 0) { rfbErr("WriteExact: write returned 0?\n"); return 0; } else { #ifdef WIN32 errno = WSAGetLastError(); #endif if (errno == EINTR) continue; if (errno != EWOULDBLOCK && errno != EAGAIN) { UNLOCK(cl->outputMutex); return n; } /* Retry every 5 seconds until we exceed rfbMaxClientWait. We need to do this because select doesn't necessarily return immediately when the other end has gone away */ FD_ZERO(&fds); FD_SET(sock, &fds); tv.tv_sec = 5; tv.tv_usec = 0; n = select(sock+1, NULL, &fds, NULL /* &fds */, &tv); if (n < 0) { if(errno==EINTR) continue; rfbLogPerror("WriteExact: select"); UNLOCK(cl->outputMutex); return n; } if (n == 0) { totalTimeWaited += 5000; if (totalTimeWaited >= rfbMaxClientWait) { errno = ETIMEDOUT; UNLOCK(cl->outputMutex); return -1; } } else { totalTimeWaited = 0; } } } UNLOCK(cl->outputMutex); return 1; }
static void rfbssl_error(const char *msg, int e) { rfbErr("%s: %s (%ld)\n", msg, gnutls_strerror(e), e); }
void rfbssl_log_func(int level, const char *msg) { rfbErr("SSL: %s", msg); }
int rfbConnectToTcpAddr(char *host, int port) { int sock; #ifdef LIBVNCSERVER_IPv6 struct addrinfo hints, *servinfo, *p; int rv; char port_str[8]; snprintf(port_str, 8, "%d", port); memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if ((rv = getaddrinfo(host, port_str, &hints, &servinfo)) != 0) { rfbErr("rfbConnectToTcpAddr: error in getaddrinfo: %s\n", gai_strerror(rv)); return -1; } /* loop through all the results and connect to the first we can */ for(p = servinfo; p != NULL; p = p->ai_next) { if ((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) continue; if (connect(sock, p->ai_addr, p->ai_addrlen) < 0) { closesocket(sock); continue; } break; } /* all failed */ if (p == NULL) { rfbLogPerror("rfbConnectToTcoAddr: failed to connect\n"); sock = -1; /* set return value */ } /* all done with this structure now */ freeaddrinfo(servinfo); #else struct hostent *hp; struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); if ((addr.sin_addr.s_addr = inet_addr(host)) == htonl(INADDR_NONE)) { if (!(hp = gethostbyname(host))) { errno = EINVAL; return -1; } addr.sin_addr.s_addr = *(unsigned long *)hp->h_addr; } if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { return -1; } if (connect(sock, (struct sockaddr *)&addr, (sizeof(addr))) < 0) { closesocket(sock); return -1; } #endif return sock; }
int rfbListenOnTCP6Port(int port, const char* iface) { #ifndef LIBVNCSERVER_IPv6 rfbLogPerror("This LibVNCServer does not have IPv6 support"); return -1; #else int sock; int one = 1; int rv; struct addrinfo hints, *servinfo, *p; char port_str[8]; snprintf(port_str, 8, "%d", port); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; /* fill in wildcard address if iface == NULL */ if ((rv = getaddrinfo(iface, port_str, &hints, &servinfo)) != 0) { rfbErr("rfbListenOnTCP6Port error in getaddrinfo: %s\n", gai_strerror(rv)); return -1; } /* loop through all the results and bind to the first we can */ for(p = servinfo; p != NULL; p = p->ai_next) { if ((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) { continue; } #ifdef IPV6_V6ONLY /* we have seperate IPv4 and IPv6 sockets since some OS's do not support dual binding */ if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) < 0) { rfbLogPerror("rfbListenOnTCP6Port error in setsockopt IPV6_V6ONLY"); closesocket(sock); freeaddrinfo(servinfo); return -1; } #endif if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) { rfbLogPerror("rfbListenOnTCP6Port: error in setsockopt SO_REUSEADDR"); closesocket(sock); freeaddrinfo(servinfo); return -1; } if (bind(sock, p->ai_addr, p->ai_addrlen) < 0) { closesocket(sock); continue; } break; } if (p == NULL) { rfbLogPerror("rfbListenOnTCP6Port: error in bind IPv6 socket"); freeaddrinfo(servinfo); return -1; } /* all done with this structure now */ freeaddrinfo(servinfo); if (listen(sock, 32) < 0) { rfbLogPerror("rfbListenOnTCP6Port: error in listen on IPv6 socket"); closesocket(sock); return -1; } return sock; #endif }
int rfbReadExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout) { int sock = cl->sock; int n; fd_set fds; struct timeval tv; while (len > 0) { #ifdef LIBVNCSERVER_WITH_WEBSOCKETS if (cl->wsctx) { n = webSocketsDecode(cl, buf, len); } else if (cl->sslctx) { n = rfbssl_read(cl, buf, len); } else { n = read(sock, buf, len); } #else n = read(sock, buf, len); #endif if (n > 0) { buf += n; len -= n; } else if (n == 0) { return 0; } else { #ifdef WIN32 errno = WSAGetLastError(); #endif if (errno == EINTR) continue; #ifdef LIBVNCSERVER_ENOENT_WORKAROUND if (errno != ENOENT) #endif if (errno != EWOULDBLOCK && errno != EAGAIN) { return n; } #ifdef LIBVNCSERVER_WITH_WEBSOCKETS if (cl->sslctx) { if (rfbssl_pending(cl)) continue; } #endif FD_ZERO(&fds); FD_SET(sock, &fds); tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; n = select(sock+1, &fds, NULL, &fds, &tv); if (n < 0) { rfbLogPerror("ReadExact: select"); return n; } if (n == 0) { rfbErr("ReadExact: select timeout\n"); errno = ETIMEDOUT; return -1; } } } #undef DEBUG_READ_EXACT #ifdef DEBUG_READ_EXACT rfbLog("ReadExact %d bytes\n",len); for(n=0;n<len;n++) fprintf(stderr,"%02x ",(unsigned char)buf[n]); fprintf(stderr,"\n"); #endif return 1; }
void rfbHttpCheckFds(rfbScreenInfoPtr rfbScreen) { int nfds; fd_set fds; struct timeval tv; struct sockaddr_in addr; socklen_t addrlen = sizeof(addr); if (!rfbScreen->httpDir) return; if (rfbScreen->httpListenSock < 0) return; FD_ZERO(&fds); FD_SET(rfbScreen->httpListenSock, &fds); if (rfbScreen->httpSock >= 0) { FD_SET(rfbScreen->httpSock, &fds); } tv.tv_sec = 0; tv.tv_usec = 0; nfds = select(max(rfbScreen->httpSock,rfbScreen->httpListenSock) + 1, &fds, NULL, NULL, &tv); if (nfds == 0) { return; } if (nfds < 0) { #ifdef WIN32 errno = WSAGetLastError(); #endif if (errno != EINTR) rfbLogPerror("httpCheckFds: select"); return; } if ((rfbScreen->httpSock >= 0) && FD_ISSET(rfbScreen->httpSock, &fds)) { httpProcessInput(rfbScreen); } if (FD_ISSET(rfbScreen->httpListenSock, &fds)) { int flags; if (rfbScreen->httpSock >= 0) close(rfbScreen->httpSock); if ((rfbScreen->httpSock = accept(rfbScreen->httpListenSock, (struct sockaddr *)&addr, &addrlen)) < 0) { rfbLogPerror("httpCheckFds: accept"); return; } #ifdef __MINGW32__ rfbErr("O_NONBLOCK on MinGW32 NOT IMPLEMENTED"); #else #ifdef USE_LIBWRAP if(!hosts_ctl("vnc",STRING_UNKNOWN,inet_ntoa(addr.sin_addr), STRING_UNKNOWN)) { rfbLog("Rejected HTTP connection from client %s\n", inet_ntoa(addr.sin_addr)); #else flags = fcntl(rfbScreen->httpSock, F_GETFL); if (flags < 0 || fcntl(rfbScreen->httpSock, F_SETFL, flags | O_NONBLOCK) == -1) { rfbLogPerror("httpCheckFds: fcntl"); #endif close(rfbScreen->httpSock); rfbScreen->httpSock = -1; return; } flags=fcntl(rfbScreen->httpSock,F_GETFL); if(flags==-1 || fcntl(rfbScreen->httpSock,F_SETFL,flags|O_NONBLOCK)==-1) { rfbLogPerror("httpCheckFds: fcntl"); close(rfbScreen->httpSock); rfbScreen->httpSock=-1; return; } #endif /*AddEnabledDevice(httpSock);*/ } } static void httpCloseSock(rfbScreenInfoPtr rfbScreen) { close(rfbScreen->httpSock); rfbScreen->httpSock = -1; buf_filled = 0; }
static rfbBool rfbSendOneRectEncodingUltra(rfbClientPtr cl, int x, int y, int w, int h) { rfbFramebufferUpdateRectHeader rect; rfbZlibHeader hdr; int deflateResult; int i; char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y) + (x * (cl->scaledScreen->bitsPerPixel / 8))); int maxRawSize; lzo_uint maxCompSize; maxRawSize = (w * h * (cl->format.bitsPerPixel / 8)); if (cl->beforeEncBufSize < maxRawSize) { cl->beforeEncBufSize = maxRawSize; if (cl->beforeEncBuf == NULL) cl->beforeEncBuf = (char *)malloc(cl->beforeEncBufSize); else cl->beforeEncBuf = (char *)realloc(cl->beforeEncBuf, cl->beforeEncBufSize); } /* * lzo requires output buffer to be slightly larger than the input * buffer, in the worst case. */ maxCompSize = (maxRawSize + maxRawSize / 16 + 64 + 3); if (cl->afterEncBufSize < (int)maxCompSize) { cl->afterEncBufSize = maxCompSize; if (cl->afterEncBuf == NULL) cl->afterEncBuf = (char *)malloc(cl->afterEncBufSize); else cl->afterEncBuf = (char *)realloc(cl->afterEncBuf, cl->afterEncBufSize); } /* * Convert pixel data to client format. */ (*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat, &cl->format, fbptr, cl->beforeEncBuf, cl->scaledScreen->paddedWidthInBytes, w, h); if ( cl->compStreamInitedLZO == FALSE ) { cl->compStreamInitedLZO = TRUE; /* Work-memory needed for compression. Allocate memory in units * of `lzo_align_t' (instead of `char') to make sure it is properly aligned. */ cl->lzoWrkMem = malloc(sizeof(lzo_align_t) * (((LZO1X_1_MEM_COMPRESS) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t))); } /* Perform the compression here. */ deflateResult = lzo1x_1_compress((unsigned char *)cl->beforeEncBuf, (lzo_uint)(w * h * (cl->format.bitsPerPixel / 8)), (unsigned char *)cl->afterEncBuf, &maxCompSize, cl->lzoWrkMem); /* maxCompSize now contains the compressed size */ /* Find the total size of the resulting compressed data. */ cl->afterEncBufLen = maxCompSize; if ( deflateResult != LZO_E_OK ) { rfbErr("lzo deflation error: %d\n", deflateResult); return FALSE; } /* Update statics */ rfbStatRecordEncodingSent(cl, rfbEncodingUltra, sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader + cl->afterEncBufLen, maxRawSize); if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader > UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } rect.r.x = Swap16IfLE(x); rect.r.y = Swap16IfLE(y); rect.r.w = Swap16IfLE(w); rect.r.h = Swap16IfLE(h); rect.encoding = Swap32IfLE(rfbEncodingUltra); memcpy(&cl->updateBuf[cl->ublen], (char *)&rect, sz_rfbFramebufferUpdateRectHeader); cl->ublen += sz_rfbFramebufferUpdateRectHeader; hdr.nBytes = Swap32IfLE(cl->afterEncBufLen); memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbZlibHeader); cl->ublen += sz_rfbZlibHeader; /* We might want to try sending the data directly... */ for (i = 0; i < cl->afterEncBufLen;) { int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen; if (i + bytesToCopy > cl->afterEncBufLen) { bytesToCopy = cl->afterEncBufLen - i; } memcpy(&cl->updateBuf[cl->ublen], &cl->afterEncBuf[i], bytesToCopy); cl->ublen += bytesToCopy; i += bytesToCopy; if (cl->ublen == UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } } return TRUE; }