LibVNCServer/LibVNCClient
httpd.c
Go to the documentation of this file.
1 /*
2  * httpd.c - a simple HTTP server
3  */
4 
5 /*
6  * Copyright (C) 2011-2012 Christian Beier <dontmind@freeshell.org>
7  * Copyright (C) 2002 RealVNC Ltd.
8  * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
9  *
10  * This is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This software is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this software; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
23  * USA.
24  */
25 
26 #ifdef __STRICT_ANSI__
27 #define _BSD_SOURCE
28 #define _POSIX_SOURCE
29 #endif
30 
31 #include <rfb/rfb.h>
32 
33 #include <ctype.h>
34 #ifdef LIBVNCSERVER_HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 #ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H
38 #include <sys/types.h>
39 #endif
40 #ifdef LIBVNCSERVER_HAVE_FCNTL_H
41 #include <fcntl.h>
42 #endif
43 #include <errno.h>
44 #ifdef LIBVNCSERVER_HAVE_SYS_TIME_H
45 #include <sys/time.h>
46 #endif
47 
48 #ifdef WIN32
49 #include <io.h>
50 #define strcasecmp _stricmp
51 #if defined(_MSC_VER)
52 #include <BaseTsd.h> /* For the missing ssize_t */
53 #define ssize_t SSIZE_T
54 #define read _read /* Prevent POSIX deprecation warnings */
55 #endif
56 #else
57 #include <pwd.h>
58 #endif
59 
60 #include "sockets.h"
61 
62 #ifdef USE_LIBWRAP
63 #include <tcpd.h>
64 #endif
65 
66 
67 #define NOT_FOUND_STR "HTTP/1.0 404 Not found\r\nConnection: close\r\n\r\n" \
68  "<HEAD><TITLE>File Not Found</TITLE></HEAD>\n" \
69  "<BODY><H1>File Not Found</H1></BODY>\n"
70 
71 #define INVALID_REQUEST_STR "HTTP/1.0 400 Invalid Request\r\nConnection: close\r\n\r\n" \
72  "<HEAD><TITLE>Invalid Request</TITLE></HEAD>\n" \
73  "<BODY><H1>Invalid request</H1></BODY>\n"
74 
75 #define OK_STR "HTTP/1.0 200 OK\r\nConnection: close\r\n"
76 
77 
78 static void httpProcessInput(rfbScreenInfoPtr screen);
79 static rfbBool compareAndSkip(char **ptr, const char *str);
80 static rfbBool parseParams(const char *request, char *result, int max_bytes);
81 static rfbBool validateString(char *str);
82 
83 #define BUF_SIZE 32768
84 
85 static char buf[BUF_SIZE];
86 static size_t buf_filled=0;
87 
88 /*
89  * httpInitSockets sets up the TCP socket to listen for HTTP connections.
90  */
91 
92 void
93 rfbHttpInitSockets(rfbScreenInfoPtr rfbScreen)
94 {
95  if (rfbScreen->httpInitDone)
96  return;
97 
98  rfbScreen->httpInitDone = TRUE;
99 
100  if (!rfbScreen->httpDir)
101  return;
102 
103  if (rfbScreen->httpPort == 0) {
104  rfbScreen->httpPort = rfbScreen->port-100;
105  }
106 
107  if ((rfbScreen->httpListenSock =
108  rfbListenOnTCPPort(rfbScreen->httpPort, rfbScreen->listenInterface)) == RFB_INVALID_SOCKET) {
109  rfbLogPerror("ListenOnTCPPort");
110  return;
111  }
112  rfbLog("Listening for HTTP connections on TCP port %d\n", rfbScreen->httpPort);
113  rfbLog(" URL http://%s:%d\n",rfbScreen->thisHost,rfbScreen->httpPort);
114 
115 #ifdef LIBVNCSERVER_IPv6
116  if (rfbScreen->http6Port == 0) {
117  rfbScreen->http6Port = rfbScreen->ipv6port-100;
118  }
119 
120  if ((rfbScreen->httpListen6Sock
121  = rfbListenOnTCP6Port(rfbScreen->http6Port, rfbScreen->listen6Interface)) == RFB_INVALID_SOCKET) {
122  /* ListenOnTCP6Port has its own detailed error printout */
123  return;
124  }
125  rfbLog("Listening for HTTP connections on TCP6 port %d\n", rfbScreen->http6Port);
126  rfbLog(" URL http://%s:%d\n",rfbScreen->thisHost,rfbScreen->http6Port);
127 #endif
128 }
129 
130 void rfbHttpShutdownSockets(rfbScreenInfoPtr rfbScreen) {
131  if(rfbScreen->httpSock>-1) {
132  rfbCloseSocket(rfbScreen->httpSock);
133  FD_CLR(rfbScreen->httpSock,&rfbScreen->allFds);
134  rfbScreen->httpSock=RFB_INVALID_SOCKET;
135  }
136 
137  if(rfbScreen->httpListenSock>-1) {
138  rfbCloseSocket(rfbScreen->httpListenSock);
139  FD_CLR(rfbScreen->httpListenSock,&rfbScreen->allFds);
140  rfbScreen->httpListenSock=RFB_INVALID_SOCKET;
141  }
142 
143  if(rfbScreen->httpListen6Sock>-1) {
144  rfbCloseSocket(rfbScreen->httpListen6Sock);
145  FD_CLR(rfbScreen->httpListen6Sock,&rfbScreen->allFds);
146  rfbScreen->httpListen6Sock=RFB_INVALID_SOCKET;
147  }
148 }
149 
150 /*
151  * httpCheckFds is called from ProcessInputEvents to check for input on the
152  * HTTP socket(s). If there is input to process, httpProcessInput is called.
153  */
154 
155 void
156 rfbHttpCheckFds(rfbScreenInfoPtr rfbScreen)
157 {
158  int nfds;
159  fd_set fds;
160  struct timeval tv;
161 #ifdef LIBVNCSERVER_IPv6
162  struct sockaddr_storage addr;
163 #else
164  struct sockaddr_in addr;
165 #endif
166  socklen_t addrlen = sizeof(addr);
167 
168  if (!rfbScreen->httpDir)
169  return;
170 
171  if (rfbScreen->httpListenSock == RFB_INVALID_SOCKET)
172  return;
173 
174  FD_ZERO(&fds);
175  FD_SET(rfbScreen->httpListenSock, &fds);
176  if (rfbScreen->httpListen6Sock != RFB_INVALID_SOCKET) {
177  FD_SET(rfbScreen->httpListen6Sock, &fds);
178  }
179  if (rfbScreen->httpSock != RFB_INVALID_SOCKET) {
180  FD_SET(rfbScreen->httpSock, &fds);
181  }
182  tv.tv_sec = 0;
183  tv.tv_usec = 0;
184  nfds = select(rfbMax(rfbScreen->httpListen6Sock, rfbMax(rfbScreen->httpSock,rfbScreen->httpListenSock)) + 1, &fds, NULL, NULL, &tv);
185  if (nfds == 0) {
186  return;
187  }
188  if (nfds < 0) {
189 #ifdef WIN32
190  errno = WSAGetLastError();
191 #endif
192  if (errno != EINTR)
193  rfbLogPerror("httpCheckFds: select");
194  return;
195  }
196 
197  if ((rfbScreen->httpSock != RFB_INVALID_SOCKET) && FD_ISSET(rfbScreen->httpSock, &fds)) {
198  httpProcessInput(rfbScreen);
199  }
200 
201  if (FD_ISSET(rfbScreen->httpListenSock, &fds) || FD_ISSET(rfbScreen->httpListen6Sock, &fds)) {
202  if (rfbScreen->httpSock != RFB_INVALID_SOCKET) rfbCloseSocket(rfbScreen->httpSock);
203 
204  if(FD_ISSET(rfbScreen->httpListenSock, &fds)) {
205  if ((rfbScreen->httpSock = accept(rfbScreen->httpListenSock, (struct sockaddr *)&addr, &addrlen)) == RFB_INVALID_SOCKET) {
206  rfbLogPerror("httpCheckFds: accept");
207  return;
208  }
209  }
210  else if(FD_ISSET(rfbScreen->httpListen6Sock, &fds)) {
211  if ((rfbScreen->httpSock = accept(rfbScreen->httpListen6Sock, (struct sockaddr *)&addr, &addrlen)) == RFB_INVALID_SOCKET) {
212  rfbLogPerror("httpCheckFds: accept");
213  return;
214  }
215  }
216 
217 #ifdef USE_LIBWRAP
218  char host[1024];
219 #ifdef LIBVNCSERVER_IPv6
220  if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) {
221  rfbLogPerror("httpCheckFds: error in getnameinfo");
222  host[0] = '\0';
223  }
224 #else
225  memcpy(host, inet_ntoa(addr.sin_addr), sizeof(host));
226 #endif
227  if(!hosts_ctl("vnc",STRING_UNKNOWN, host,
228  STRING_UNKNOWN)) {
229  rfbLog("Rejected HTTP connection from client %s\n",
230  host);
231  rfbCloseSocket(rfbScreen->httpSock);
232  rfbScreen->httpSock=RFB_INVALID_SOCKET;
233  return;
234  }
235 #endif
236  if(!rfbSetNonBlocking(rfbScreen->httpSock)) {
237  rfbCloseSocket(rfbScreen->httpSock);
238  rfbScreen->httpSock=RFB_INVALID_SOCKET;
239  return;
240  }
241  /*AddEnabledDevice(httpSock);*/
242  }
243 }
244 
245 
246 static void
247 httpCloseSock(rfbScreenInfoPtr rfbScreen)
248 {
249  rfbCloseSocket(rfbScreen->httpSock);
250  rfbScreen->httpSock = RFB_INVALID_SOCKET;
251  buf_filled = 0;
252 }
253 
254 static rfbClientRec cl;
255 
256 /*
257  * httpProcessInput is called when input is received on the HTTP socket.
258  */
259 
260 static void
261 httpProcessInput(rfbScreenInfoPtr rfbScreen)
262 {
263 #ifdef LIBVNCSERVER_IPv6
264  struct sockaddr_storage addr;
265 #else
266  struct sockaddr_in addr;
267 #endif
268  socklen_t addrlen = sizeof(addr);
269  char fullFname[512];
270  char params[1024];
271  char *ptr;
272  char *fname;
273  unsigned int maxFnameLen;
274  FILE* fd;
275  rfbBool performSubstitutions = FALSE;
276  char str[256+32];
277 #ifndef WIN32
278  char* user=getenv("USER");
279 #endif
280 
281  cl.sock=rfbScreen->httpSock;
282 
283  if (strlen(rfbScreen->httpDir) > 255) {
284  rfbErr("-httpd directory too long\n");
285  httpCloseSock(rfbScreen);
286  return;
287  }
288  strcpy(fullFname, rfbScreen->httpDir);
289  fname = &fullFname[strlen(fullFname)];
290  maxFnameLen = 511 - strlen(fullFname);
291 
292  buf_filled=0;
293 
294  /* Read data from the HTTP client until we get a complete request. */
295  while (1) {
296  ssize_t got;
297 
298  if (buf_filled > sizeof (buf)) {
299  rfbErr("httpProcessInput: HTTP request is too long\n");
300  httpCloseSock(rfbScreen);
301  return;
302  }
303 
304  got = read (rfbScreen->httpSock, buf + buf_filled,
305  sizeof (buf) - buf_filled - 1);
306 
307  if (got <= 0) {
308  if (got == 0) {
309  rfbErr("httpd: premature connection close\n");
310  } else {
311 #ifdef WIN32
312  errno=WSAGetLastError();
313 #endif
314  if (errno == EAGAIN) {
315  return;
316  }
317  rfbLogPerror("httpProcessInput: read");
318  }
319  httpCloseSock(rfbScreen);
320  return;
321  }
322 
323  buf_filled += got;
324  buf[buf_filled] = '\0';
325 
326  /* Is it complete yet (is there a blank line)? */
327  if (strstr (buf, "\r\r") || strstr (buf, "\n\n") ||
328  strstr (buf, "\r\n\r\n") || strstr (buf, "\n\r\n\r"))
329  break;
330  }
331 
332 
333  /* Process the request. */
334  if(rfbScreen->httpEnableProxyConnect) {
335  const static char* PROXY_OK_STR = "HTTP/1.0 200 OK\r\nContent-Type: octet-stream\r\nPragma: no-cache\r\n\r\n";
336  if(!strncmp(buf, "CONNECT ", 8)) {
337  if(atoi(strchr(buf, ':')+1)!=rfbScreen->port) {
338  rfbErr("httpd: CONNECT format invalid.\n");
340  httpCloseSock(rfbScreen);
341  return;
342  }
343  /* proxy connection */
344  rfbLog("httpd: client asked for CONNECT\n");
345  rfbWriteExact(&cl,PROXY_OK_STR,strlen(PROXY_OK_STR));
346  rfbNewClientConnection(rfbScreen,rfbScreen->httpSock);
347  rfbScreen->httpSock = RFB_INVALID_SOCKET;
348  return;
349  }
350  if (!strncmp(buf, "GET ",4) && !strncmp(strchr(buf,'/'),"/proxied.connection HTTP/1.", 27)) {
351  /* proxy connection */
352  rfbLog("httpd: client asked for /proxied.connection\n");
353  rfbWriteExact(&cl,PROXY_OK_STR,strlen(PROXY_OK_STR));
354  rfbNewClientConnection(rfbScreen,rfbScreen->httpSock);
355  rfbScreen->httpSock = RFB_INVALID_SOCKET;
356  return;
357  }
358  }
359 
360  if (strncmp(buf, "GET ", 4)) {
361  rfbErr("httpd: no GET line\n");
362  httpCloseSock(rfbScreen);
363  return;
364  } else {
365  /* Only use the first line. */
366  buf[strcspn(buf, "\n\r")] = '\0';
367  }
368 
369  if (strlen(buf) > maxFnameLen) {
370  rfbErr("httpd: GET line too long\n");
371  httpCloseSock(rfbScreen);
372  return;
373  }
374 
375  if (sscanf(buf, "GET %s HTTP/1.", fname) != 1) {
376  rfbErr("httpd: couldn't parse GET line\n");
377  httpCloseSock(rfbScreen);
378  return;
379  }
380 
381  if (fname[0] != '/') {
382  rfbErr("httpd: filename didn't begin with '/'\n");
384  httpCloseSock(rfbScreen);
385  return;
386  }
387 
388 
389  getpeername(rfbScreen->httpSock, (struct sockaddr *)&addr, &addrlen);
390 #ifdef LIBVNCSERVER_IPv6
391  {
392  char host[1024];
393  if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) {
394  rfbLogPerror("httpProcessInput: error in getnameinfo");
395  }
396  rfbLog("httpd: get '%s' for %s\n", fname+1, host);
397  }
398 #else
399  rfbLog("httpd: get '%s' for %s\n", fname+1,
400  inet_ntoa(addr.sin_addr));
401 #endif
402 
403  /* Extract parameters from the URL string if necessary */
404 
405  params[0] = '\0';
406  ptr = strchr(fname, '?');
407  if (ptr != NULL) {
408  *ptr = '\0';
409  if (!parseParams(&ptr[1], params, 1024)) {
410  params[0] = '\0';
411  rfbErr("httpd: bad parameters in the URL\n");
412  }
413  }
414 
415  /* Basic protection against directory traversal outside webroot */
416 
417  if (strstr(fname, "..")) {
418  rfbErr("httpd: URL should not contain '..'\n");
420  httpCloseSock(rfbScreen);
421  return;
422  }
423 
424  /* If we were asked for '/', actually read the file index.vnc */
425 
426  if (strcmp(fname, "/") == 0) {
427  strcpy(fname, "/index.vnc");
428  rfbLog("httpd: defaulting to '%s'\n", fname+1);
429  }
430 
431  /* Substitutions are performed on files ending .vnc */
432 
433  if (strlen(fname) >= 4 && strcmp(&fname[strlen(fname)-4], ".vnc") == 0) {
434  performSubstitutions = TRUE;
435  }
436 
437  /* Open the file */
438 
439  if ((fd = fopen(fullFname, "r")) == 0) {
440  rfbLogPerror("httpProcessInput: open");
442  httpCloseSock(rfbScreen);
443  return;
444  }
445 
446  rfbWriteExact(&cl, OK_STR, strlen(OK_STR));
447  char *ext = strrchr(fname, '.');
448  char *contentType = "";
449  if(ext && strcasecmp(ext, ".vnc") == 0)
450  contentType = "Content-Type: text/html\r\n";
451  else if(ext && strcasecmp(ext, ".css") == 0)
452  contentType = "Content-Type: text/css\r\n";
453  else if(ext && strcasecmp(ext, ".svg") == 0)
454  contentType = "Content-Type: image/svg+xml\r\n";
455  else if(ext && strcasecmp(ext, ".js") == 0)
456  contentType = "Content-Type: application/javascript\r\n";
457  rfbWriteExact(&cl, contentType, strlen(contentType));
458  /* end the header */
459  rfbWriteExact(&cl, "\r\n", 2);
460 
461  while (1) {
462  int n = fread(buf, 1, BUF_SIZE-1, fd);
463  if (n < 0) {
464  rfbLogPerror("httpProcessInput: read");
465  fclose(fd);
466  httpCloseSock(rfbScreen);
467  return;
468  }
469 
470  if (n == 0)
471  break;
472 
473  if (performSubstitutions) {
474 
475  /* Substitute $WIDTH, $HEIGHT, etc with the appropriate values.
476  This won't quite work properly if the .vnc file is longer than
477  BUF_SIZE, but it's reasonable to assume that .vnc files will
478  always be short. */
479 
480  char *ptr = buf;
481  char *dollar;
482  buf[n] = 0; /* make sure it's null-terminated */
483 
484  while ((dollar = strchr(ptr, '$'))!=NULL) {
485  rfbWriteExact(&cl, ptr, (dollar - ptr));
486 
487  ptr = dollar;
488 
489  if (compareAndSkip(&ptr, "$WIDTH")) {
490 
491  sprintf(str, "%d", rfbScreen->width);
492  rfbWriteExact(&cl, str, strlen(str));
493 
494  } else if (compareAndSkip(&ptr, "$HEIGHT")) {
495 
496  sprintf(str, "%d", rfbScreen->height);
497  rfbWriteExact(&cl, str, strlen(str));
498 
499  } else if (compareAndSkip(&ptr, "$APPLETWIDTH")) {
500 
501  sprintf(str, "%d", rfbScreen->width);
502  rfbWriteExact(&cl, str, strlen(str));
503 
504  } else if (compareAndSkip(&ptr, "$APPLETHEIGHT")) {
505 
506  sprintf(str, "%d", rfbScreen->height + 32);
507  rfbWriteExact(&cl, str, strlen(str));
508 
509  } else if (compareAndSkip(&ptr, "$PORT")) {
510 
511  sprintf(str, "%d", rfbScreen->port);
512  rfbWriteExact(&cl, str, strlen(str));
513 
514  } else if (compareAndSkip(&ptr, "$DESKTOP")) {
515 
516  rfbWriteExact(&cl, rfbScreen->desktopName, strlen(rfbScreen->desktopName));
517 
518  } else if (compareAndSkip(&ptr, "$DISPLAY")) {
519 
520  sprintf(str, "%s:%d", rfbScreen->thisHost, rfbScreen->port-5900);
521  rfbWriteExact(&cl, str, strlen(str));
522 
523  } else if (compareAndSkip(&ptr, "$USER")) {
524 #ifndef WIN32
525  if (user) {
526  rfbWriteExact(&cl, user,
527  strlen(user));
528  } else
529 #endif
530  rfbWriteExact(&cl, "?", 1);
531  } else if (compareAndSkip(&ptr, "$PARAMS")) {
532  if (params[0] != '\0')
533  rfbWriteExact(&cl, params, strlen(params));
534  } else {
535  if (!compareAndSkip(&ptr, "$$"))
536  ptr++;
537 
538  if (rfbWriteExact(&cl, "$", 1) < 0) {
539  fclose(fd);
540  httpCloseSock(rfbScreen);
541  return;
542  }
543  }
544  }
545  if (rfbWriteExact(&cl, ptr, (&buf[n] - ptr)) < 0)
546  break;
547 
548  } else {
549 
550  /* For files not ending .vnc, just write out the buffer */
551 
552  if (rfbWriteExact(&cl, buf, n) < 0)
553  break;
554  }
555  }
556 
557  fclose(fd);
558  httpCloseSock(rfbScreen);
559 }
560 
561 
562 static rfbBool
563 compareAndSkip(char **ptr, const char *str)
564 {
565  if (strncmp(*ptr, str, strlen(str)) == 0) {
566  *ptr += strlen(str);
567  return TRUE;
568  }
569 
570  return FALSE;
571 }
572 
573 /*
574  * Parse the request tail after the '?' character, and format a sequence
575  * of <param> tags for inclusion into an HTML page with embedded applet.
576  */
577 
578 static rfbBool
579 parseParams(const char *request, char *result, int max_bytes)
580 {
581  char param_request[128];
582  char param_formatted[196];
583  const char *tail;
584  char *delim_ptr;
585  char *value_str;
586  int cur_bytes, len;
587 
588  result[0] = '\0';
589  cur_bytes = 0;
590 
591  tail = request;
592  for (;;) {
593  /* Copy individual "name=value" string into a buffer */
594  delim_ptr = strchr((char *)tail, '&');
595  if (delim_ptr == NULL) {
596  if (strlen(tail) >= sizeof(param_request)) {
597  return FALSE;
598  }
599  strcpy(param_request, tail);
600  } else {
601  len = delim_ptr - tail;
602  if (len >= sizeof(param_request)) {
603  return FALSE;
604  }
605  memcpy(param_request, tail, len);
606  param_request[len] = '\0';
607  }
608 
609  /* Split the request into parameter name and value */
610  value_str = strchr(&param_request[1], '=');
611  if (value_str == NULL) {
612  return FALSE;
613  }
614  *value_str++ = '\0';
615  if (strlen(value_str) == 0) {
616  return FALSE;
617  }
618 
619  /* Validate both parameter name and value */
620  if (!validateString(param_request) || !validateString(value_str)) {
621  return FALSE;
622  }
623 
624  /* Prepare HTML-formatted representation of the name=value pair */
625  len = sprintf(param_formatted,
626  "<PARAM NAME=\"%s\" VALUE=\"%s\">\n",
627  param_request, value_str);
628  if (cur_bytes + len + 1 > max_bytes) {
629  return FALSE;
630  }
631  strcat(result, param_formatted);
632  cur_bytes += len;
633 
634  /* Go to the next parameter */
635  if (delim_ptr == NULL) {
636  break;
637  }
638  tail = delim_ptr + 1;
639  }
640  return TRUE;
641 }
642 
643 /*
644  * Check if the string consists only of alphanumeric characters, '+'
645  * signs, underscores, dots, colons and square brackets.
646  * Replace all '+' signs with spaces.
647  */
648 
649 static rfbBool
650 validateString(char *str)
651 {
652  char *ptr;
653 
654  for (ptr = str; *ptr != '\0'; ptr++) {
655  if (!isalnum(*ptr) && *ptr != '_' && *ptr != '.'
656  && *ptr != ':' && *ptr != '[' && *ptr != ']' ) {
657  if (*ptr == '+') {
658  *ptr = ' ';
659  } else {
660  return FALSE;
661  }
662  }
663  }
664  return TRUE;
665 }
666 
rfbLogProc rfbErr
Definition: main.c:264
void rfbNewClientConnection(rfbScreenInfoPtr rfbScreen, rfbSocket sock)
Definition: rfbserver.c:247
#define TRUE
Definition: rfbproto.h:112
void rfbHttpShutdownSockets(rfbScreenInfoPtr rfbScreen)
Definition: httpd.c:130
int8_t rfbBool
Definition: rfbproto.h:108
#define RFB_INVALID_SOCKET
Definition: rfbproto.h:106
rfbSocket sock
Definition: rfb.h:434
int rfbWriteExact(rfbClientPtr cl, const char *buf, int len)
Definition: sockets.c:792
rfbBool rfbSetNonBlocking(rfbSocket sock)
Definition: sockets.c:1121
#define INVALID_REQUEST_STR
Definition: httpd.c:71
#define rfbMax(a, b)
Definition: rfbproto.h:92
#define BUF_SIZE
Definition: httpd.c:83
void rfbLogPerror(const char *str)
Definition: main.c:266
void rfbHttpInitSockets(rfbScreenInfoPtr rfbScreen)
Definition: httpd.c:93
void rfbHttpCheckFds(rfbScreenInfoPtr rfbScreen)
Definition: httpd.c:156
rfbLogProc rfbLog
Definition: main.c:263
rfbSocket rfbListenOnTCPPort(int port, in_addr_t iface)
Definition: sockets.c:909
#define OK_STR
Definition: httpd.c:75
#define FALSE
Definition: rfbproto.h:110
rfbSocket rfbListenOnTCP6Port(int port, const char *iface)
Definition: sockets.c:943
#define NOT_FOUND_STR
Definition: httpd.c:67
#define rfbCloseSocket
Definition: rfbproto.h:107