LibVNCServer/LibVNCClient
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vncviewer.c
Go to the documentation of this file.
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 __STRICT_ANSI__
25 #define _BSD_SOURCE
26 #define _POSIX_SOURCE
27 #endif
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32 #include <rfb/rfbclient.h>
33 #include "tls.h"
34 
35 static void Dummy(rfbClient* client) {
36 }
37 static rfbBool DummyPoint(rfbClient* client, int x, int y) {
38  return TRUE;
39 }
40 static void DummyRect(rfbClient* client, int x, int y, int w, int h) {
41 }
42 
43 #ifdef __MINGW32__
44 static char* NoPassword(rfbClient* client) {
45  return strdup("");
46 }
47 #undef SOCKET
48 #include <winsock2.h>
49 #define close closesocket
50 #else
51 #include <stdio.h>
52 #include <termios.h>
53 #endif
54 
55 static char* ReadPassword(rfbClient* client) {
56 #ifdef __MINGW32__
57  /* FIXME */
58  rfbClientErr("ReadPassword on MinGW32 NOT IMPLEMENTED\n");
59  return NoPassword(client);
60 #else
61  int i;
62  char* p=malloc(9);
63  struct termios save,noecho;
64  p[0]=0;
65  if(tcgetattr(fileno(stdin),&save)!=0) return p;
66  noecho=save; noecho.c_lflag &= ~ECHO;
67  if(tcsetattr(fileno(stdin),TCSAFLUSH,&noecho)!=0) return p;
68  fprintf(stderr,"Password: ");
69  i=0;
70  while(1) {
71  int c=fgetc(stdin);
72  if(c=='\n')
73  break;
74  if(i<8) {
75  p[i]=c;
76  i++;
77  p[i]=0;
78  }
79  }
80  tcsetattr(fileno(stdin),TCSAFLUSH,&save);
81  return p;
82 #endif
83 }
84 static rfbBool MallocFrameBuffer(rfbClient* client) {
85  if(client->frameBuffer)
86  free(client->frameBuffer);
87  client->frameBuffer=malloc(client->width*client->height*client->format.bitsPerPixel/8);
88  return client->frameBuffer?TRUE:FALSE;
89 }
90 
91 static void initAppData(AppData* data) {
92  data->shareDesktop=TRUE;
93  data->viewOnly=FALSE;
94  data->encodingsString="tight zrle ultra copyrect hextile zlib corre rre raw";
95  data->useBGR233=FALSE;
96  data->nColours=0;
97  data->forceOwnCmap=FALSE;
98  data->forceTrueColour=FALSE;
99  data->requestedDepth=0;
100  data->compressLevel=3;
101  data->qualityLevel=5;
102 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
103  data->enableJPEG=TRUE;
104 #else
105  data->enableJPEG=FALSE;
106 #endif
107  data->useRemoteCursor=FALSE;
108 }
109 
110 rfbClient* rfbGetClient(int bitsPerSample,int samplesPerPixel,
111  int bytesPerPixel) {
112  rfbClient* client=(rfbClient*)calloc(sizeof(rfbClient),1);
113  if(!client) {
114  rfbClientErr("Couldn't allocate client structure!\n");
115  return NULL;
116  }
117  initAppData(&client->appData);
118  client->endianTest = 1;
119  client->programName="";
120  client->serverHost=strdup("");
121  client->serverPort=5900;
122 
123  client->destHost = NULL;
124  client->destPort = 5900;
125 
126  client->CurrentKeyboardLedState = 0;
128 
129  /* default: use complete frame buffer */
130  client->updateRect.x = -1;
131 
132  client->format.bitsPerPixel = bytesPerPixel*8;
133  client->format.depth = bitsPerSample*samplesPerPixel;
134  client->appData.requestedDepth=client->format.depth;
135  client->format.bigEndian = *(char *)&client->endianTest?FALSE:TRUE;
136  client->format.trueColour = TRUE;
137 
138  if (client->format.bitsPerPixel == 8) {
139  client->format.redMax = 7;
140  client->format.greenMax = 7;
141  client->format.blueMax = 3;
142  client->format.redShift = 0;
143  client->format.greenShift = 3;
144  client->format.blueShift = 6;
145  } else {
146  client->format.redMax = (1 << bitsPerSample) - 1;
147  client->format.greenMax = (1 << bitsPerSample) - 1;
148  client->format.blueMax = (1 << bitsPerSample) - 1;
149  if(!client->format.bigEndian) {
150  client->format.redShift = 0;
151  client->format.greenShift = bitsPerSample;
152  client->format.blueShift = bitsPerSample * 2;
153  } else {
154  if(client->format.bitsPerPixel==8*3) {
155  client->format.redShift = bitsPerSample*2;
156  client->format.greenShift = bitsPerSample*1;
157  client->format.blueShift = 0;
158  } else {
159  client->format.redShift = bitsPerSample*3;
160  client->format.greenShift = bitsPerSample*2;
161  client->format.blueShift = bitsPerSample;
162  }
163  }
164  }
165 
166  client->bufoutptr=client->buf;
167  client->buffered=0;
168 
169 #ifdef LIBVNCSERVER_HAVE_LIBZ
170  client->raw_buffer_size = -1;
171  client->decompStreamInited = FALSE;
172 
173 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
174  memset(client->zlibStreamActive,0,sizeof(rfbBool)*4);
175  client->jpegSrcManager = NULL;
176 #endif
177 #endif
178 
179  client->HandleCursorPos = DummyPoint;
180  client->SoftCursorLockArea = DummyRect;
181  client->SoftCursorUnlockScreen = Dummy;
182  client->GotFrameBufferUpdate = DummyRect;
183  client->FinishedFrameBufferUpdate = NULL;
184  client->GetPassword = ReadPassword;
185  client->MallocFrameBuffer = MallocFrameBuffer;
186  client->Bell = Dummy;
187  client->CurrentKeyboardLedState = 0;
189  client->QoS_DSCP = 0;
190 
191  client->authScheme = 0;
192  client->subAuthScheme = 0;
193  client->GetCredential = NULL;
194  client->tlsSession = NULL;
195  client->sock = -1;
196  client->listenSock = -1;
197  client->listenAddress = NULL;
198  client->listen6Sock = -1;
199  client->listen6Address = NULL;
200  client->clientAuthSchemes = NULL;
201  return client;
202 }
203 
204 static rfbBool rfbInitConnection(rfbClient* client)
205 {
206  /* Unless we accepted an incoming connection, make a TCP connection to the
207  given VNC server */
208 
209  if (!client->listenSpecified) {
210  if (!client->serverHost)
211  return FALSE;
212  if (client->destHost) {
213  if (!ConnectToRFBRepeater(client,client->serverHost,client->serverPort,client->destHost,client->destPort))
214  return FALSE;
215  } else {
216  if (!ConnectToRFBServer(client,client->serverHost,client->serverPort))
217  return FALSE;
218  }
219  }
220 
221  /* Initialise the VNC connection, including reading the password */
222 
223  if (!InitialiseRFBConnection(client))
224  return FALSE;
225 
226  client->width=client->si.framebufferWidth;
227  client->height=client->si.framebufferHeight;
228  client->MallocFrameBuffer(client);
229 
230  if (!SetFormatAndEncodings(client))
231  return FALSE;
232 
233  if (client->updateRect.x < 0) {
234  client->updateRect.x = client->updateRect.y = 0;
235  client->updateRect.w = client->width;
236  client->updateRect.h = client->height;
237  }
238 
239  if (client->appData.scaleSetting>1)
240  {
241  if (!SendScaleSetting(client, client->appData.scaleSetting))
242  return FALSE;
243  if (!SendFramebufferUpdateRequest(client,
244  client->updateRect.x / client->appData.scaleSetting,
245  client->updateRect.y / client->appData.scaleSetting,
246  client->updateRect.w / client->appData.scaleSetting,
247  client->updateRect.h / client->appData.scaleSetting,
248  FALSE))
249  return FALSE;
250  }
251  else
252  {
253  if (!SendFramebufferUpdateRequest(client,
254  client->updateRect.x, client->updateRect.y,
255  client->updateRect.w, client->updateRect.h,
256  FALSE))
257  return FALSE;
258  }
259 
260  return TRUE;
261 }
262 
263 rfbBool rfbInitClient(rfbClient* client,int* argc,char** argv) {
264  int i,j;
265 
266  if(argv && argc && *argc) {
267  if(client->programName==0)
268  client->programName=argv[0];
269 
270  for (i = 1; i < *argc; i++) {
271  j = i;
272  if (strcmp(argv[i], "-listen") == 0) {
274  break;
275  } else if (strcmp(argv[i], "-listennofork") == 0) {
277  break;
278  } else if (strcmp(argv[i], "-play") == 0) {
279  client->serverPort = -1;
280  j++;
281  } else if (i+1<*argc && strcmp(argv[i], "-encodings") == 0) {
282  client->appData.encodingsString = argv[i+1];
283  j+=2;
284  } else if (i+1<*argc && strcmp(argv[i], "-compress") == 0) {
285  client->appData.compressLevel = atoi(argv[i+1]);
286  j+=2;
287  } else if (i+1<*argc && strcmp(argv[i], "-quality") == 0) {
288  client->appData.qualityLevel = atoi(argv[i+1]);
289  j+=2;
290  } else if (i+1<*argc && strcmp(argv[i], "-scale") == 0) {
291  client->appData.scaleSetting = atoi(argv[i+1]);
292  j+=2;
293  } else if (i+1<*argc && strcmp(argv[i], "-qosdscp") == 0) {
294  client->QoS_DSCP = atoi(argv[i+1]);
295  j+=2;
296  } else if (i+1<*argc && strcmp(argv[i], "-repeaterdest") == 0) {
297  char* colon=strchr(argv[i+1],':');
298 
299  if(client->destHost)
300  free(client->destHost);
301  client->destPort = 5900;
302 
303  client->destHost = strdup(argv[i+1]);
304  if(colon) {
305  client->destHost[(int)(colon-argv[i+1])] = '\0';
306  client->destPort = atoi(colon+1);
307  }
308  j+=2;
309  } else {
310  char* colon=strchr(argv[i],':');
311 
312  if(client->serverHost)
313  free(client->serverHost);
314 
315  if(colon) {
316  client->serverHost = strdup(argv[i]);
317  client->serverHost[(int)(colon-argv[i])] = '\0';
318  client->serverPort = atoi(colon+1);
319  } else {
320  client->serverHost = strdup(argv[i]);
321  }
322  if(client->serverPort >= 0 && client->serverPort < 5900)
323  client->serverPort += 5900;
324  }
325  /* purge arguments */
326  if (j>i) {
327  *argc-=j-i;
328  memmove(argv+i,argv+j,(*argc-i)*sizeof(char*));
329  i--;
330  }
331  }
332  }
333 
334  if(!rfbInitConnection(client)) {
335  rfbClientCleanup(client);
336  return FALSE;
337  }
338 
339  return TRUE;
340 }
341 
343 #ifdef LIBVNCSERVER_HAVE_LIBZ
344 #ifdef LIBVNCSERVER_HAVE_LIBJPEG
345  int i;
346 
347  for ( i = 0; i < 4; i++ ) {
348  if (client->zlibStreamActive[i] == TRUE ) {
349  if (inflateEnd (&client->zlibStream[i]) != Z_OK &&
350  client->zlibStream[i].msg != NULL)
351  rfbClientLog("inflateEnd: %s\n", client->zlibStream[i].msg);
352  }
353  }
354 
355  if ( client->decompStreamInited == TRUE ) {
356  if (inflateEnd (&client->decompStream) != Z_OK &&
357  client->decompStream.msg != NULL)
358  rfbClientLog("inflateEnd: %s\n", client->decompStream.msg );
359  }
360 
361  if (client->jpegSrcManager)
362  free(client->jpegSrcManager);
363 #endif
364 #endif
365 
366  FreeTLS(client);
367 
368  if (client->sock >= 0)
369  close(client->sock);
370  if (client->listenSock >= 0)
371  close(client->listenSock);
372  free(client->desktopName);
373  free(client->serverHost);
374  if (client->destHost)
375  free(client->destHost);
376  if (client->clientAuthSchemes)
377  free(client->clientAuthSchemes);
378  free(client);
379 }