/* * Copyright (C) 2000-2002 Constantin Kaplinsky. All Rights Reserved. * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ /* * rfbproto.c - functions to deal with client side of RFB protocol. */ #ifdef __STRICT_ANSI__ #define _BSD_SOURCE #define _POSIX_SOURCE #endif #include #include #ifndef __MINGW32__ #include #endif #include #ifdef LIBVNCSERVER_HAVE_LIBZ #include #ifdef __CHECKER__ #undef Z_NULL #define Z_NULL NULL #endif #endif #ifdef LIBVNCSERVER_HAVE_LIBJPEG #include #endif #include #include /* * rfbClientLog prints a time-stamped message to the log file (stderr). */ rfbBool rfbEnableClientLogging=TRUE; static void rfbDefaultClientLog(const char *format, ...) { va_list args; char buf[256]; time_t log_clock; if(!rfbEnableClientLogging) return; va_start(args, format); time(&log_clock); strftime(buf, 255, "%d/%m/%Y %X ", localtime(&log_clock)); fprintf(stderr,buf); vfprintf(stderr, format, args); fflush(stderr); va_end(args); } rfbClientLogProc rfbClientLog=rfbDefaultClientLog; rfbClientLogProc rfbClientErr=rfbDefaultClientLog; /* extensions */ rfbClientProtocolExtension* rfbClientExtensions = NULL; void rfbClientRegisterExtension(rfbClientProtocolExtension* e) { e->next = rfbClientExtensions; rfbClientExtensions = e; } /* client data */ void rfbClientSetClientData(rfbClient* client, void* tag, void* data) { rfbClientData* clientData = client->clientData; while(clientData && clientData->tag != tag) clientData = clientData->next; if(clientData == NULL) { clientData = calloc(sizeof(rfbClientData), 1); clientData->next = client->clientData; client->clientData = clientData; clientData->tag = tag; } clientData->data = data; } void* rfbClientGetClientData(rfbClient* client, void* tag) { rfbClientData* clientData = client->clientData; while(clientData) { if(clientData->tag == tag) return clientData->data; clientData = clientData->next; } return NULL; } /* messages */ static void FillRectangle(rfbClient* client, int x, int y, int w, int h, uint32_t colour) { int i,j; #define FILL_RECT(BPP) \ for(j=y*client->width;j<(y+h)*client->width;j+=client->width) \ for(i=x;iframeBuffer)[j+i]=colour; switch(client->format.bitsPerPixel) { case 8: FILL_RECT(8); break; case 16: FILL_RECT(16); break; case 32: FILL_RECT(32); break; default: rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel); } } static void CopyRectangle(rfbClient* client, uint8_t* buffer, int x, int y, int w, int h) { int i,j; #define COPY_RECT(BPP) \ { \ uint##BPP##_t* _buffer=(uint##BPP##_t*)buffer; \ for(j=y*client->width;j<(y+h)*client->width;j+=client->width) { \ for(i=x;iframeBuffer)[j+i]=*_buffer; \ } \ } switch(client->format.bitsPerPixel) { case 8: COPY_RECT(8); break; case 16: COPY_RECT(16); break; case 32: COPY_RECT(32); break; default: rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel); } } /* TODO: test */ static void CopyRectangleFromRectangle(rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y) { int i,j; #define COPY_RECT_FROM_RECT(BPP) \ { \ uint##BPP##_t* _buffer=((uint##BPP##_t*)client->frameBuffer)+(src_y-dest_y)*client->width+src_x-dest_x; \ for(j=dest_y*client->width;j<(dest_y+h)*client->width;j+=client->width) { \ for(i=dest_x;iframeBuffer)[j+i]=_buffer[j+i]; \ } \ } switch(client->format.bitsPerPixel) { case 8: COPY_RECT_FROM_RECT(8); break; case 16: COPY_RECT_FROM_RECT(16); break; case 32: COPY_RECT_FROM_RECT(32); break; default: rfbClientLog("Unsupported bitsPerPixel: %d\n",client->format.bitsPerPixel); } } static rfbBool HandleRRE8(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleRRE16(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleRRE32(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleCoRRE8(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleCoRRE16(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleCoRRE32(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleHextile8(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleHextile16(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleHextile32(rfbClient* client, int rx, int ry, int rw, int rh); #ifdef LIBVNCSERVER_HAVE_LIBZ static rfbBool HandleZlib8(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleZlib16(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleZlib32(rfbClient* client, int rx, int ry, int rw, int rh); #ifdef LIBVNCSERVER_HAVE_LIBJPEG static rfbBool HandleTight8(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleTight16(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleTight32(rfbClient* client, int rx, int ry, int rw, int rh); static long ReadCompactLen (rfbClient* client); static void JpegInitSource(j_decompress_ptr cinfo); static boolean JpegFillInputBuffer(j_decompress_ptr cinfo); static void JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes); static void JpegTermSource(j_decompress_ptr cinfo); static void JpegSetSrcManager(j_decompress_ptr cinfo, uint8_t *compressedData, int compressedLen); #endif static rfbBool HandleZRLE8(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleZRLE16(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleZRLE24(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleZRLE24Up(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleZRLE24Down(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleZRLE32(rfbClient* client, int rx, int ry, int rw, int rh); #endif /* * ConnectToRFBServer. */ rfbBool ConnectToRFBServer(rfbClient* client,const char *hostname, int port) { unsigned int host; if (client->serverPort==-1) { /* serverHost is a file recorded by vncrec. */ const char* magic="vncLog0.0"; char buffer[10]; rfbVNCRec* rec = (rfbVNCRec*)malloc(sizeof(rfbVNCRec)); client->vncRec = rec; rec->file = fopen(client->serverHost,"rb"); rec->tv.tv_sec = 0; rec->readTimestamp = FALSE; rec->doNotSleep = FALSE; if (!rec->file) { rfbClientLog("Could not open %s.\n",client->serverHost); return FALSE; } setbuf(rec->file,NULL); fread(buffer,1,strlen(magic),rec->file); if (strncmp(buffer,magic,strlen(magic))) { rfbClientLog("File %s was not recorded by vncrec.\n",client->serverHost); fclose(rec->file); return FALSE; } client->sock = 0; return TRUE; } if (!StringToIPAddr(hostname, &host)) { rfbClientLog("Couldn't convert '%s' to host address\n", hostname); return FALSE; } client->sock = ConnectClientToTcpAddr(host, port); if (client->sock < 0) { rfbClientLog("Unable to connect to VNC server\n"); return FALSE; } return SetNonBlocking(client->sock); } extern void rfbClientEncryptBytes(unsigned char* bytes, char* passwd); /* * InitialiseRFBConnection. */ rfbBool InitialiseRFBConnection(rfbClient* client) { rfbProtocolVersionMsg pv; int major,minor; uint32_t authScheme, reasonLen, authResult; char *reason; uint8_t challenge[CHALLENGESIZE]; char *passwd=NULL; int i; rfbClientInitMsg ci; /* if the connection is immediately closed, don't report anything, so that pmw's monitor can make test connections */ if (client->listenSpecified) errorMessageOnReadFailure = FALSE; if (!ReadFromRFBServer(client, pv, sz_rfbProtocolVersionMsg)) return FALSE; pv[sz_rfbProtocolVersionMsg]=0; errorMessageOnReadFailure = TRUE; pv[sz_rfbProtocolVersionMsg] = 0; if (sscanf(pv,rfbProtocolVersionFormat,&major,&minor) != 2) { rfbClientLog("Not a valid VNC server (%s)\n",pv); return FALSE; } #if rfbProtocolMinorVersion == 7 /* work around LibVNCClient not yet speaking RFB 3.7 */ #undef rfbProtocolMinorVersion #define rfbProtocolMinorVersion 3 #endif rfbClientLog("VNC server supports protocol version %d.%d (viewer %d.%d)\n", major, minor, rfbProtocolMajorVersion, rfbProtocolMinorVersion); major = rfbProtocolMajorVersion; minor = rfbProtocolMinorVersion; sprintf(pv,rfbProtocolVersionFormat,major,minor); if (!WriteToRFBServer(client, pv, sz_rfbProtocolVersionMsg)) return FALSE; if (!ReadFromRFBServer(client, (char *)&authScheme, 4)) return FALSE; authScheme = rfbClientSwap32IfLE(authScheme); switch (authScheme) { case rfbConnFailed: if (!ReadFromRFBServer(client, (char *)&reasonLen, 4)) return FALSE; reasonLen = rfbClientSwap32IfLE(reasonLen); reason = malloc(reasonLen); if (!ReadFromRFBServer(client, reason, reasonLen)) return FALSE; rfbClientLog("VNC connection failed: %.*s\n",(int)reasonLen, reason); return FALSE; case rfbNoAuth: rfbClientLog("No authentication needed\n"); break; case rfbVncAuth: if (!ReadFromRFBServer(client, (char *)challenge, CHALLENGESIZE)) return FALSE; if (client->serverPort!=-1) { /* if not playing a vncrec file */ if (client->GetPassword) passwd = client->GetPassword(client); if ((!passwd) || (strlen(passwd) == 0)) { rfbClientLog("Reading password failed\n"); return FALSE; } if (strlen(passwd) > 8) { passwd[8] = '\0'; } rfbClientEncryptBytes(challenge, passwd); /* Lose the password from memory */ for (i = strlen(passwd); i >= 0; i--) { passwd[i] = '\0'; } free(passwd); if (!WriteToRFBServer(client, (char *)challenge, CHALLENGESIZE)) return FALSE; } if (!ReadFromRFBServer(client, (char *)&authResult, 4)) return FALSE; authResult = rfbClientSwap32IfLE(authResult); switch (authResult) { case rfbVncAuthOK: rfbClientLog("VNC authentication succeeded\n"); break; case rfbVncAuthFailed: rfbClientLog("VNC authentication failed\n"); return FALSE; case rfbVncAuthTooMany: rfbClientLog("VNC authentication failed - too many tries\n"); return FALSE; default: rfbClientLog("Unknown VNC authentication result: %d\n", (int)authResult); return FALSE; } break; default: rfbClientLog("Unknown authentication scheme from VNC server: %d\n", (int)authScheme); return FALSE; } ci.shared = (client->appData.shareDesktop ? 1 : 0); if (!WriteToRFBServer(client, (char *)&ci, sz_rfbClientInitMsg)) return FALSE; if (!ReadFromRFBServer(client, (char *)&client->si, sz_rfbServerInitMsg)) return FALSE; client->si.framebufferWidth = rfbClientSwap16IfLE(client->si.framebufferWidth); client->si.framebufferHeight = rfbClientSwap16IfLE(client->si.framebufferHeight); client->si.format.redMax = rfbClientSwap16IfLE(client->si.format.redMax); client->si.format.greenMax = rfbClientSwap16IfLE(client->si.format.greenMax); client->si.format.blueMax = rfbClientSwap16IfLE(client->si.format.blueMax); client->si.nameLength = rfbClientSwap32IfLE(client->si.nameLength); client->desktopName = malloc(client->si.nameLength + 1); if (!client->desktopName) { rfbClientLog("Error allocating memory for desktop name, %lu bytes\n", (unsigned long)client->si.nameLength); return FALSE; } if (!ReadFromRFBServer(client, client->desktopName, client->si.nameLength)) return FALSE; client->desktopName[client->si.nameLength] = 0; rfbClientLog("Desktop name \"%s\"\n",client->desktopName); rfbClientLog("Connected to VNC server, using protocol version %d.%d\n", rfbProtocolMajorVersion, rfbProtocolMinorVersion); rfbClientLog("VNC server default format:\n"); PrintPixelFormat(&client->si.format); return TRUE; } /* * SetFormatAndEncodings. */ rfbBool SetFormatAndEncodings(rfbClient* client) { rfbSetPixelFormatMsg spf; char buf[sz_rfbSetEncodingsMsg + MAX_ENCODINGS * 4]; rfbSetEncodingsMsg *se = (rfbSetEncodingsMsg *)buf; uint32_t *encs = (uint32_t *)(&buf[sz_rfbSetEncodingsMsg]); int len = 0; rfbBool requestCompressLevel = FALSE; rfbBool requestQualityLevel = FALSE; rfbBool requestLastRectEncoding = FALSE; rfbClientProtocolExtension* e; spf.type = rfbSetPixelFormat; spf.format = client->format; spf.format.redMax = rfbClientSwap16IfLE(spf.format.redMax); spf.format.greenMax = rfbClientSwap16IfLE(spf.format.greenMax); spf.format.blueMax = rfbClientSwap16IfLE(spf.format.blueMax); if (!WriteToRFBServer(client, (char *)&spf, sz_rfbSetPixelFormatMsg)) return FALSE; se->type = rfbSetEncodings; se->nEncodings = 0; if (client->appData.encodingsString) { const char *encStr = client->appData.encodingsString; int encStrLen; do { const char *nextEncStr = strchr(encStr, ' '); if (nextEncStr) { encStrLen = nextEncStr - encStr; nextEncStr++; } else { encStrLen = strlen(encStr); } if (strncasecmp(encStr,"raw",encStrLen) == 0) { encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingRaw); } else if (strncasecmp(encStr,"copyrect",encStrLen) == 0) { encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingCopyRect); #ifdef LIBVNCSERVER_HAVE_LIBZ #ifdef LIBVNCSERVER_HAVE_LIBJPEG } else if (strncasecmp(encStr,"tight",encStrLen) == 0) { encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingTight); requestLastRectEncoding = TRUE; if (client->appData.compressLevel >= 0 && client->appData.compressLevel <= 9) requestCompressLevel = TRUE; if (client->appData.enableJPEG) requestQualityLevel = TRUE; #endif #endif } else if (strncasecmp(encStr,"hextile",encStrLen) == 0) { encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingHextile); #ifdef LIBVNCSERVER_HAVE_LIBZ } else if (strncasecmp(encStr,"zlib",encStrLen) == 0) { encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingZlib); if (client->appData.compressLevel >= 0 && client->appData.compressLevel <= 9) requestCompressLevel = TRUE; } else if (strncasecmp(encStr,"zlibhex",encStrLen) == 0) { encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingZlibHex); if (client->appData.compressLevel >= 0 && client->appData.compressLevel <= 9) requestCompressLevel = TRUE; } else if (strncasecmp(encStr,"zrle",encStrLen) == 0) { encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingZRLE); #endif } else if (strncasecmp(encStr,"corre",encStrLen) == 0) { encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingCoRRE); } else if (strncasecmp(encStr,"rre",encStrLen) == 0) { encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingRRE); } else { rfbClientLog("Unknown encoding '%.*s'\n",encStrLen,encStr); } encStr = nextEncStr; } while (encStr && se->nEncodings < MAX_ENCODINGS); if (se->nEncodings < MAX_ENCODINGS && requestCompressLevel) { encs[se->nEncodings++] = rfbClientSwap32IfLE(client->appData.compressLevel + rfbEncodingCompressLevel0); } if (se->nEncodings < MAX_ENCODINGS && requestQualityLevel) { if (client->appData.qualityLevel < 0 || client->appData.qualityLevel > 9) client->appData.qualityLevel = 5; encs[se->nEncodings++] = rfbClientSwap32IfLE(client->appData.qualityLevel + rfbEncodingQualityLevel0); } if (client->appData.useRemoteCursor) { if (se->nEncodings < MAX_ENCODINGS) encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingXCursor); if (se->nEncodings < MAX_ENCODINGS) encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingRichCursor); if (se->nEncodings < MAX_ENCODINGS) encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingPointerPos); } /* Let's receive keyboard state encoding if available */ if (se->nEncodings < MAX_ENCODINGS) { encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingKeyboardLedState); } if (se->nEncodings < MAX_ENCODINGS && requestLastRectEncoding) { encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingLastRect); } } else { if (SameMachine(client->sock)) { /* TODO: if (!tunnelSpecified) { */ rfbClientLog("Same machine: preferring raw encoding\n"); encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingRaw); /* } else { rfbClientLog("Tunneling active: preferring tight encoding\n"); } */ } encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingCopyRect); #ifdef LIBVNCSERVER_HAVE_LIBZ #ifdef LIBVNCSERVER_HAVE_LIBJPEG encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingTight); #endif #endif encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingHextile); #ifdef LIBVNCSERVER_HAVE_LIBZ encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingZlib); encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingZRLE); #endif encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingCoRRE); encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingRRE); if (client->appData.compressLevel >= 0 && client->appData.compressLevel <= 9) { encs[se->nEncodings++] = rfbClientSwap32IfLE(client->appData.compressLevel + rfbEncodingCompressLevel0); } else /* if (!tunnelSpecified) */ { /* If -tunnel option was provided, we assume that server machine is not in the local network so we use default compression level for tight encoding instead of fast compression. Thus we are requesting level 1 compression only if tunneling is not used. */ encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingCompressLevel1); } if (client->appData.enableJPEG) { if (client->appData.qualityLevel < 0 || client->appData.qualityLevel > 9) client->appData.qualityLevel = 5; encs[se->nEncodings++] = rfbClientSwap32IfLE(client->appData.qualityLevel + rfbEncodingQualityLevel0); } if (client->appData.useRemoteCursor) { encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingXCursor); encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingRichCursor); encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingPointerPos); } /* Keyboard State Encodings */ if (se->nEncodings < MAX_ENCODINGS) { encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingKeyboardLedState); } encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingLastRect); } for(e = rfbClientExtensions; e; e = e->next) if(e->encodings) { int* enc; for(enc = e->encodings; *enc; enc++) encs[se->nEncodings++] = rfbClientSwap32IfLE(*enc); } len = sz_rfbSetEncodingsMsg + se->nEncodings * 4; se->nEncodings = rfbClientSwap16IfLE(se->nEncodings); if (!WriteToRFBServer(client, buf, len)) return FALSE; return TRUE; } /* * SendIncrementalFramebufferUpdateRequest. */ rfbBool SendIncrementalFramebufferUpdateRequest(rfbClient* client) { return SendFramebufferUpdateRequest(client, 0, 0, client->si.framebufferWidth, client->si.framebufferHeight, TRUE); } /* * SendFramebufferUpdateRequest. */ rfbBool SendFramebufferUpdateRequest(rfbClient* client, int x, int y, int w, int h, rfbBool incremental) { rfbFramebufferUpdateRequestMsg fur; fur.type = rfbFramebufferUpdateRequest; fur.incremental = incremental ? 1 : 0; fur.x = rfbClientSwap16IfLE(x); fur.y = rfbClientSwap16IfLE(y); fur.w = rfbClientSwap16IfLE(w); fur.h = rfbClientSwap16IfLE(h); if (!WriteToRFBServer(client, (char *)&fur, sz_rfbFramebufferUpdateRequestMsg)) return FALSE; return TRUE; } /* * SendPointerEvent. */ rfbBool SendPointerEvent(rfbClient* client,int x, int y, int buttonMask) { rfbPointerEventMsg pe; pe.type = rfbPointerEvent; pe.buttonMask = buttonMask; if (x < 0) x = 0; if (y < 0) y = 0; pe.x = rfbClientSwap16IfLE(x); pe.y = rfbClientSwap16IfLE(y); return WriteToRFBServer(client, (char *)&pe, sz_rfbPointerEventMsg); } /* * SendKeyEvent. */ rfbBool SendKeyEvent(rfbClient* client, uint32_t key, rfbBool down) { rfbKeyEventMsg ke; ke.type = rfbKeyEvent; ke.down = down ? 1 : 0; ke.key = rfbClientSwap32IfLE(key); return WriteToRFBServer(client, (char *)&ke, sz_rfbKeyEventMsg); } /* * SendClientCutText. */ rfbBool SendClientCutText(rfbClient* client, char *str, int len) { rfbClientCutTextMsg cct; if (client->serverCutText) free(client->serverCutText); client->serverCutText = NULL; cct.type = rfbClientCutText; cct.length = rfbClientSwap32IfLE(len); return (WriteToRFBServer(client, (char *)&cct, sz_rfbClientCutTextMsg) && WriteToRFBServer(client, str, len)); } /* * HandleRFBServerMessage. */ rfbBool HandleRFBServerMessage(rfbClient* client) { rfbServerToClientMsg msg; if (client->serverPort==-1) client->vncRec->readTimestamp = TRUE; if (!ReadFromRFBServer(client, (char *)&msg, 1)) return FALSE; switch (msg.type) { case rfbSetColourMapEntries: { /* TODO: int i; uint16_t rgb[3]; XColor xc; if (!ReadFromRFBServer(client, ((char *)&msg) + 1, sz_rfbSetColourMapEntriesMsg - 1)) return FALSE; msg.scme.firstColour = rfbClientSwap16IfLE(msg.scme.firstColour); msg.scme.nColours = rfbClientSwap16IfLE(msg.scme.nColours); for (i = 0; i < msg.scme.nColours; i++) { if (!ReadFromRFBServer(client, (char *)rgb, 6)) return FALSE; xc.pixel = msg.scme.firstColour + i; xc.red = rfbClientSwap16IfLE(rgb[0]); xc.green = rfbClientSwap16IfLE(rgb[1]); xc.blue = rfbClientSwap16IfLE(rgb[2]); xc.flags = DoRed|DoGreen|DoBlue; XStoreColor(dpy, cmap, &xc); } */ break; } case rfbFramebufferUpdate: { rfbFramebufferUpdateRectHeader rect; int linesToRead; int bytesPerLine; int i; if (!ReadFromRFBServer(client, ((char *)&msg.fu) + 1, sz_rfbFramebufferUpdateMsg - 1)) return FALSE; msg.fu.nRects = rfbClientSwap16IfLE(msg.fu.nRects); for (i = 0; i < msg.fu.nRects; i++) { if (!ReadFromRFBServer(client, (char *)&rect, sz_rfbFramebufferUpdateRectHeader)) return FALSE; rect.encoding = rfbClientSwap32IfLE(rect.encoding); if (rect.encoding == rfbEncodingLastRect) break; rect.r.x = rfbClientSwap16IfLE(rect.r.x); rect.r.y = rfbClientSwap16IfLE(rect.r.y); rect.r.w = rfbClientSwap16IfLE(rect.r.w); rect.r.h = rfbClientSwap16IfLE(rect.r.h); if (rect.encoding == rfbEncodingXCursor || rect.encoding == rfbEncodingRichCursor) { if (!HandleCursorShape(client, rect.r.x, rect.r.y, rect.r.w, rect.r.h, rect.encoding)) { return FALSE; } continue; } if (rect.encoding == rfbEncodingPointerPos) { if (!client->HandleCursorPos(client,rect.r.x, rect.r.y)) { return FALSE; } continue; } if (rect.encoding == rfbEncodingKeyboardLedState) { /* OK! We have received a keyboard state message!!! */ client->KeyboardLedStateEnabled = 1; if (client->HandleKeyboardLedState!=NULL) client->HandleKeyboardLedState(client, rect.r.x, 0); // stash it for the future client->CurrentKeyboardLedState = rect.r.x; continue; } if ((rect.r.x + rect.r.w > client->si.framebufferWidth) || (rect.r.y + rect.r.h > client->si.framebufferHeight)) { rfbClientLog("Rect too large: %dx%d at (%d, %d)\n", rect.r.w, rect.r.h, rect.r.x, rect.r.y); return FALSE; } if (rect.r.h * rect.r.w == 0) { rfbClientLog("Zero size rect - ignoring\n"); continue; } /* If RichCursor encoding is used, we should prevent collisions between framebuffer updates and cursor drawing operations. */ client->SoftCursorLockArea(client, rect.r.x, rect.r.y, rect.r.w, rect.r.h); switch (rect.encoding) { case rfbEncodingRaw: { int y=rect.r.y, h=rect.r.h; bytesPerLine = rect.r.w * client->format.bitsPerPixel / 8; linesToRead = RFB_BUFFER_SIZE / bytesPerLine; while (h > 0) { if (linesToRead > h) linesToRead = h; if (!ReadFromRFBServer(client, client->buffer,bytesPerLine * linesToRead)) return FALSE; CopyRectangle(client, client->buffer, rect.r.x, y, rect.r.w,linesToRead); h -= linesToRead; y += linesToRead; } } break; case rfbEncodingCopyRect: { rfbCopyRect cr; if (!ReadFromRFBServer(client, (char *)&cr, sz_rfbCopyRect)) return FALSE; cr.srcX = rfbClientSwap16IfLE(cr.srcX); cr.srcY = rfbClientSwap16IfLE(cr.srcY); /* If RichCursor encoding is used, we should extend our "cursor lock area" (previously set to destination rectangle) to the source rectangle as well. */ client->SoftCursorLockArea(client, cr.srcX, cr.srcY, rect.r.w, rect.r.h); CopyRectangleFromRectangle(client, cr.srcX, cr.srcY, rect.r.w, rect.r.h, rect.r.x, rect.r.y); break; } case rfbEncodingRRE: { switch (client->format.bitsPerPixel) { case 8: if (!HandleRRE8(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; case 16: if (!HandleRRE16(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; case 32: if (!HandleRRE32(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; } break; } case rfbEncodingCoRRE: { switch (client->format.bitsPerPixel) { case 8: if (!HandleCoRRE8(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; case 16: if (!HandleCoRRE16(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; case 32: if (!HandleCoRRE32(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; } break; } case rfbEncodingHextile: { switch (client->format.bitsPerPixel) { case 8: if (!HandleHextile8(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; case 16: if (!HandleHextile16(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; case 32: if (!HandleHextile32(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; } break; } #ifdef LIBVNCSERVER_HAVE_LIBZ case rfbEncodingZlib: { switch (client->format.bitsPerPixel) { case 8: if (!HandleZlib8(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; case 16: if (!HandleZlib16(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; case 32: if (!HandleZlib32(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; } break; } #ifdef LIBVNCSERVER_HAVE_LIBJPEG case rfbEncodingTight: { switch (client->format.bitsPerPixel) { case 8: if (!HandleTight8(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; case 16: if (!HandleTight16(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; case 32: if (!HandleTight32(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; } break; } #endif case rfbEncodingZRLE: { switch (client->format.bitsPerPixel) { case 8: if (!HandleZRLE8(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; case 16: if (!HandleZRLE16(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; case 32: { uint32_t maxColor=(client->format.redMax<format.redShift)| (client->format.greenMax<format.greenShift)| (client->format.blueMax<format.blueShift); if ((client->format.bigEndian && (maxColor&0xff)==0) || (!client->format.bigEndian && (maxColor&0xff000000)==0)) { if (!HandleZRLE24(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; } else if (!client->format.bigEndian && (maxColor&0xff)==0) { if (!HandleZRLE24Up(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; } else if (client->format.bigEndian && (maxColor&0xff000000)==0) { if (!HandleZRLE24Down(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; } else if (!HandleZRLE32(client, rect.r.x,rect.r.y,rect.r.w,rect.r.h)) return FALSE; break; } } break; } #endif default: { rfbBool handled = FALSE; rfbClientProtocolExtension* e; for(e = rfbClientExtensions; !handled && e; e = e->next) if(e->handleEncoding && e->handleEncoding(client, &rect)) handled = TRUE; if(!handled) { rfbClientLog("Unknown rect encoding %d\n", (int)rect.encoding); return FALSE; } } } /* Now we may discard "soft cursor locks". */ client->SoftCursorUnlockScreen(client); client->GotFrameBufferUpdate(client, rect.r.x, rect.r.y, rect.r.w, rect.r.h); } if (!SendIncrementalFramebufferUpdateRequest(client)) return FALSE; break; } case rfbBell: { client->Bell(client); break; } case rfbServerCutText: { if (!ReadFromRFBServer(client, ((char *)&msg) + 1, sz_rfbServerCutTextMsg - 1)) return FALSE; msg.sct.length = rfbClientSwap32IfLE(msg.sct.length); if (client->serverCutText) free(client->serverCutText); client->serverCutText = malloc(msg.sct.length+1); if (!ReadFromRFBServer(client, client->serverCutText, msg.sct.length)) return FALSE; client->serverCutText[msg.sct.length] = 0; client->newServerCutText = TRUE; break; } default: { rfbBool handled = FALSE; rfbClientProtocolExtension* e; for(e = rfbClientExtensions; !handled && e; e = e->next) if(e->handleMessage && e->handleMessage(client, &msg)) handled = TRUE; if(!handled) { char buffer[256]; ReadFromRFBServer(client, buffer, 256); rfbClientLog("Unknown message type %d from VNC server\n",msg.type); return FALSE; } } } return TRUE; } #define GET_PIXEL8(pix, ptr) ((pix) = *(ptr)++) #define GET_PIXEL16(pix, ptr) (((uint8_t*)&(pix))[0] = *(ptr)++, \ ((uint8_t*)&(pix))[1] = *(ptr)++) #define GET_PIXEL32(pix, ptr) (((uint8_t*)&(pix))[0] = *(ptr)++, \ ((uint8_t*)&(pix))[1] = *(ptr)++, \ ((uint8_t*)&(pix))[2] = *(ptr)++, \ ((uint8_t*)&(pix))[3] = *(ptr)++) /* CONCAT2 concatenates its two arguments. CONCAT2E does the same but also expands its arguments if they are macros */ #define CONCAT2(a,b) a##b #define CONCAT2E(a,b) CONCAT2(a,b) #define CONCAT3(a,b,c) a##b##c #define CONCAT3E(a,b,c) CONCAT3(a,b,c) #define BPP 8 #include "rre.c" #include "corre.c" #include "hextile.c" #include "zlib.c" #include "tight.c" #include "zrle.c" #undef BPP #define BPP 16 #include "rre.c" #include "corre.c" #include "hextile.c" #include "zlib.c" #include "tight.c" #include "zrle.c" #undef BPP #define BPP 32 #include "rre.c" #include "corre.c" #include "hextile.c" #include "zlib.c" #include "tight.c" #include "zrle.c" #define REALBPP 24 #include "zrle.c" #define REALBPP 24 #define UNCOMP 8 #include "zrle.c" #define REALBPP 24 #define UNCOMP -8 #include "zrle.c" #undef BPP /* * PrintPixelFormat. */ void PrintPixelFormat(rfbPixelFormat *format) { if (format->bitsPerPixel == 1) { rfbClientLog(" Single bit per pixel.\n"); rfbClientLog( " %s significant bit in each byte is leftmost on the screen.\n", (format->bigEndian ? "Most" : "Least")); } else { rfbClientLog(" %d bits per pixel.\n",format->bitsPerPixel); if (format->bitsPerPixel != 8) { rfbClientLog(" %s significant byte first in each pixel.\n", (format->bigEndian ? "Most" : "Least")); } if (format->trueColour) { rfbClientLog(" TRUE colour: max red %d green %d blue %d" ", shift red %d green %d blue %d\n", format->redMax, format->greenMax, format->blueMax, format->redShift, format->greenShift, format->blueShift); } else { rfbClientLog(" Colour map (not true colour).\n"); } } } /* avoid name clashes with LibVNCServer */ #define rfbEncryptBytes rfbClientEncryptBytes #define rfbDes rfbClientDes #define rfbDesKey rfbClientDesKey #define rfbUseKey rfbClientUseKey #define rfbCPKey rfbClientCPKey #include "../libvncserver/vncauth.c" #include "../libvncserver/d3des.c"