1 /* 2 * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 3 * 4 * This is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This software is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this software; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 17 * USA. 18 */ 19 20 /* 21 * vncviewer.c - the Xt-based VNC viewer. 22 */ 23 24 #ifdef WIN32 25 #undef SOCKET 26 #include <winsock2.h> 27 #endif 28 29 #ifdef _MSC_VER 30 #define strdup _strdup /* Prevent POSIX deprecation warnings */ 31 #endif 32 33 #ifdef __STRICT_ANSI__ 34 #define _BSD_SOURCE 35 #define _POSIX_SOURCE 36 #endif 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <time.h> 41 #include <rfb/rfbclient.h> 42 #include "tls.h" 43 44 static void Dummy(rfbClient* client) { 45 } 46 static rfbBool DummyPoint(rfbClient* client, int x, int y) { 47 return TRUE; 48 } 49 static void DummyRect(rfbClient* client, int x, int y, int w, int h) { 50 } 51 52 #ifdef WIN32 53 static char* NoPassword(rfbClient* client) { 54 return strdup(""); 55 } 56 #define close closesocket 57 #else 58 #include <stdio.h> 59 #include <termios.h> 60 #endif 61 62 static char* ReadPassword(rfbClient* client) { 63 #ifdef WIN32 64 /* FIXME */ 65 rfbClientErr("ReadPassword on Windows NOT IMPLEMENTED\n"); 66 return NoPassword(client); 67 #else 68 int i; 69 char* p=malloc(9); 70 struct termios save,noecho; 71 p[0]=0; 72 if(tcgetattr(fileno(stdin),&save)!=0) return p; 73 noecho=save; noecho.c_lflag &= ~ECHO; 74 if(tcsetattr(fileno(stdin),TCSAFLUSH,&noecho)!=0) return p; 75 fprintf(stderr,"Password: "); 76 i=0; 77 while(1) { 78 int c=fgetc(stdin); 79 if(c=='\n') 80 break; 81 if(i<8) { 82 p[i]=c; 83 i++; 84 p[i]=0; 85 } 86 } 87 tcsetattr(fileno(stdin),TCSAFLUSH,&save); 88 return p; 89 #endif 90 } 91 static rfbBool MallocFrameBuffer(rfbClient* client) { 92 uint64_t allocSize; 93 94 if(client->frameBuffer) 95 free(client->frameBuffer); 96 97 /* SECURITY: promote 'width' into uint64_t so that the multiplication does not overflow 98 'width' and 'height' are 16-bit integers per RFB protocol design 99 SIZE_MAX is the maximum value that can fit into size_t 100 */ 101 allocSize = (uint64_t)client->width * client->height * client->format.bitsPerPixel/8; 102 103 if (allocSize >= SIZE_MAX) { 104 rfbClientErr("CRITICAL: cannot allocate frameBuffer, requested size is too large\n"); 105 return FALSE; 106 } 107 108 client->frameBuffer=malloc( (size_t)allocSize ); 109 110 if (client->frameBuffer == NULL) 111 rfbClientErr("CRITICAL: frameBuffer allocation failed, requested size too large or not enough memory?\n"); 112 113 return client->frameBuffer?TRUE:FALSE; 114 } 115 116 static void initAppData(AppData* data) { 117 data->shareDesktop=TRUE; 118 data->viewOnly=FALSE; 119 #ifdef LIBVNCSERVER_CONFIG_LIBVA 120 data->encodingsString="h264 tight zrle ultra copyrect hextile zlib corre rre raw"; 121 #else 122 data->encodingsString="tight zrle ultra copyrect hextile zlib corre rre raw"; 123 #endif 124 data->useBGR233=FALSE; 125 data->nColours=0; 126 data->forceOwnCmap=FALSE; 127 data->forceTrueColour=FALSE; 128 data->requestedDepth=0; 129 data->compressLevel=3; 130 data->qualityLevel=5; 131 #ifdef LIBVNCSERVER_HAVE_LIBJPEG 132 data->enableJPEG=TRUE; 133 #else 134 data->enableJPEG=FALSE; 135 #endif 136 data->useRemoteCursor=FALSE; 137 } 138 139 rfbClient* rfbGetClient(int bitsPerSample,int samplesPerPixel, 140 int bytesPerPixel) { 141 rfbClient* client=(rfbClient*)calloc(sizeof(rfbClient),1); 142 if(!client) { 143 rfbClientErr("Couldn't allocate client structure!\n"); 144 return NULL; 145 } 146 initAppData(&client->appData); 147 client->endianTest = 1; 148 client->programName=""; 149 client->serverHost=strdup(""); 150 client->serverPort=5900; 151 152 client->destHost = NULL; 153 client->destPort = 5900; 154 155 client->CurrentKeyboardLedState = 0; 156 client->HandleKeyboardLedState = (HandleKeyboardLedStateProc)DummyPoint; 157 158 /* default: use complete frame buffer */ 159 client->updateRect.x = -1; 160 161 client->frameBuffer = NULL; 162 client->outputWindow = 0; 163 164 client->format.bitsPerPixel = bytesPerPixel*8; 165 client->format.depth = bitsPerSample*samplesPerPixel; 166 client->appData.requestedDepth=client->format.depth; 167 client->format.bigEndian = *(char *)&client->endianTest?FALSE:TRUE; 168 client->format.trueColour = TRUE; 169 170 if (client->format.bitsPerPixel == 8) { 171 client->format.redMax = 7; 172 client->format.greenMax = 7; 173 client->format.blueMax = 3; 174 client->format.redShift = 0; 175 client->format.greenShift = 3; 176 client->format.blueShift = 6; 177 } else { 178 client->format.redMax = (1 << bitsPerSample) - 1; 179 client->format.greenMax = (1 << bitsPerSample) - 1; 180 client->format.blueMax = (1 << bitsPerSample) - 1; 181 if(!client->format.bigEndian) { 182 client->format.redShift = 0; 183 client->format.greenShift = bitsPerSample; 184 client->format.blueShift = bitsPerSample * 2; 185 } else { 186 if(client->format.bitsPerPixel==8*3) { 187 client->format.redShift = bitsPerSample*2; 188 client->format.greenShift = bitsPerSample*1; 189 client->format.blueShift = 0; 190 } else { 191 client->format.redShift = bitsPerSample*3; 192 client->format.greenShift = bitsPerSample*2; 193 client->format.blueShift = bitsPerSample; 194 } 195 } 196 } 197 198 client->bufoutptr=client->buf; 199 client->buffered=0; 200 201 #ifdef LIBVNCSERVER_HAVE_LIBZ 202 client->raw_buffer_size = -1; 203 client->decompStreamInited = FALSE; 204 205 #ifdef LIBVNCSERVER_HAVE_LIBJPEG 206 memset(client->zlibStreamActive,0,sizeof(rfbBool)*4); 207 client->jpegSrcManager = NULL; 208 #endif 209 #endif 210 211 client->HandleCursorPos = DummyPoint; 212 client->SoftCursorLockArea = DummyRect; 213 client->SoftCursorUnlockScreen = Dummy; 214 client->GotFrameBufferUpdate = DummyRect; 215 client->FinishedFrameBufferUpdate = NULL; 216 client->GetPassword = ReadPassword; 217 client->MallocFrameBuffer = MallocFrameBuffer; 218 client->Bell = Dummy; 219 client->CurrentKeyboardLedState = 0; 220 client->HandleKeyboardLedState = (HandleKeyboardLedStateProc)DummyPoint; 221 client->QoS_DSCP = 0; 222 223 client->authScheme = 0; 224 client->subAuthScheme = 0; 225 client->GetCredential = NULL; 226 client->tlsSession = NULL; 227 client->sock = -1; 228 client->listenSock = -1; 229 client->listenAddress = NULL; 230 client->listen6Sock = -1; 231 client->listen6Address = NULL; 232 client->clientAuthSchemes = NULL; 233 return client; 234 } 235 236 static rfbBool rfbInitConnection(rfbClient* client) 237 { 238 /* Unless we accepted an incoming connection, make a TCP connection to the 239 given VNC server */ 240 241 if (!client->listenSpecified) { 242 if (!client->serverHost) 243 return FALSE; 244 if (client->destHost) { 245 if (!ConnectToRFBRepeater(client,client->serverHost,client->serverPort,client->destHost,client->destPort)) 246 return FALSE; 247 } else { 248 if (!ConnectToRFBServer(client,client->serverHost,client->serverPort)) 249 return FALSE; 250 } 251 } 252 253 /* Initialise the VNC connection, including reading the password */ 254 255 if (!InitialiseRFBConnection(client)) 256 return FALSE; 257 258 client->width=client->si.framebufferWidth; 259 client->height=client->si.framebufferHeight; 260 if (!client->MallocFrameBuffer(client)) 261 return FALSE; 262 263 if (!SetFormatAndEncodings(client)) 264 return FALSE; 265 266 if (client->updateRect.x < 0) { 267 client->updateRect.x = client->updateRect.y = 0; 268 client->updateRect.w = client->width; 269 client->updateRect.h = client->height; 270 } 271 272 if (client->appData.scaleSetting>1) 273 { 274 if (!SendScaleSetting(client, client->appData.scaleSetting)) 275 return FALSE; 276 if (!SendFramebufferUpdateRequest(client, 277 client->updateRect.x / client->appData.scaleSetting, 278 client->updateRect.y / client->appData.scaleSetting, 279 client->updateRect.w / client->appData.scaleSetting, 280 client->updateRect.h / client->appData.scaleSetting, 281 FALSE)) 282 return FALSE; 283 } 284 else 285 { 286 if (!SendFramebufferUpdateRequest(client, 287 client->updateRect.x, client->updateRect.y, 288 client->updateRect.w, client->updateRect.h, 289 FALSE)) 290 return FALSE; 291 } 292 293 return TRUE; 294 } 295 296 rfbBool rfbInitClient(rfbClient* client,int* argc,char** argv) { 297 int i,j; 298 299 if(argv && argc && *argc) { 300 if(client->programName==0) 301 client->programName=argv[0]; 302 303 for (i = 1; i < *argc; i++) { 304 j = i; 305 if (strcmp(argv[i], "-listen") == 0) { 306 listenForIncomingConnections(client); 307 break; 308 } else if (strcmp(argv[i], "-listennofork") == 0) { 309 listenForIncomingConnectionsNoFork(client, -1); 310 break; 311 } else if (strcmp(argv[i], "-play") == 0) { 312 client->serverPort = -1; 313 j++; 314 } else if (i+1<*argc && strcmp(argv[i], "-encodings") == 0) { 315 client->appData.encodingsString = argv[i+1]; 316 j+=2; 317 } else if (i+1<*argc && strcmp(argv[i], "-compress") == 0) { 318 client->appData.compressLevel = atoi(argv[i+1]); 319 j+=2; 320 } else if (i+1<*argc && strcmp(argv[i], "-quality") == 0) { 321 client->appData.qualityLevel = atoi(argv[i+1]); 322 j+=2; 323 } else if (i+1<*argc && strcmp(argv[i], "-scale") == 0) { 324 client->appData.scaleSetting = atoi(argv[i+1]); 325 j+=2; 326 } else if (i+1<*argc && strcmp(argv[i], "-qosdscp") == 0) { 327 client->QoS_DSCP = atoi(argv[i+1]); 328 j+=2; 329 } else if (i+1<*argc && strcmp(argv[i], "-repeaterdest") == 0) { 330 char* colon=strchr(argv[i+1],':'); 331 332 if(client->destHost) 333 free(client->destHost); 334 client->destPort = 5900; 335 336 client->destHost = strdup(argv[i+1]); 337 if(colon) { 338 client->destHost[(int)(colon-argv[i+1])] = '\0'; 339 client->destPort = atoi(colon+1); 340 } 341 j+=2; 342 } else { 343 char* colon=strchr(argv[i],':'); 344 345 if(client->serverHost) 346 free(client->serverHost); 347 348 if(colon) { 349 client->serverHost = strdup(argv[i]); 350 client->serverHost[(int)(colon-argv[i])] = '\0'; 351 client->serverPort = atoi(colon+1); 352 } else { 353 client->serverHost = strdup(argv[i]); 354 } 355 if(client->serverPort >= 0 && client->serverPort < 5900) 356 client->serverPort += 5900; 357 } 358 /* purge arguments */ 359 if (j>i) { 360 *argc-=j-i; 361 memmove(argv+i,argv+j,(*argc-i)*sizeof(char*)); 362 i--; 363 } 364 } 365 } 366 367 if(!rfbInitConnection(client)) { 368 rfbClientCleanup(client); 369 return FALSE; 370 } 371 372 return TRUE; 373 } 374 375 void rfbClientCleanup(rfbClient* client) { 376 #ifdef LIBVNCSERVER_HAVE_LIBZ 377 #ifdef LIBVNCSERVER_HAVE_LIBJPEG 378 int i; 379 380 for ( i = 0; i < 4; i++ ) { 381 if (client->zlibStreamActive[i] == TRUE ) { 382 if (inflateEnd (&client->zlibStream[i]) != Z_OK && 383 client->zlibStream[i].msg != NULL) 384 rfbClientLog("inflateEnd: %s\n", client->zlibStream[i].msg); 385 } 386 } 387 388 if ( client->decompStreamInited == TRUE ) { 389 if (inflateEnd (&client->decompStream) != Z_OK && 390 client->decompStream.msg != NULL) 391 rfbClientLog("inflateEnd: %s\n", client->decompStream.msg ); 392 } 393 394 if (client->jpegSrcManager) 395 free(client->jpegSrcManager); 396 #endif 397 #endif 398 399 FreeTLS(client); 400 401 while (client->clientData) { 402 rfbClientData* next = client->clientData->next; 403 free(client->clientData); 404 client->clientData = next; 405 } 406 407 if (client->sock >= 0) 408 close(client->sock); 409 if (client->listenSock >= 0) 410 close(client->listenSock); 411 free(client->desktopName); 412 free(client->serverHost); 413 if (client->destHost) 414 free(client->destHost); 415 if (client->clientAuthSchemes) 416 free(client->clientAuthSchemes); 417 free(client); 418 } 419