1 /* 2 * Copyright (C) 2011-2012 Christian Beier <dontmind (at) freeshell.org> 3 * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 4 * 5 * This is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This software is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this software; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 18 * USA. 19 */ 20 21 /* 22 * sockets.c - functions to deal with sockets. 23 */ 24 25 #ifdef __STRICT_ANSI__ 26 #define _BSD_SOURCE 27 #ifdef __linux__ 28 /* Setting this on other systems hides definitions such as INADDR_LOOPBACK. 29 * The check should be for __GLIBC__ in fact. */ 30 # define _POSIX_SOURCE 31 #endif 32 #endif 33 #include <unistd.h> 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <assert.h> 37 #include <rfb/rfbclient.h> 38 #ifdef WIN32 39 #undef SOCKET 40 #include <winsock2.h> 41 #ifdef MINGW32 42 #define EWOULDBLOCK WSAEWOULDBLOCK 43 #endif 44 #define close closesocket 45 #define read(sock,buf,len) recv(sock,buf,len,0) 46 #define write(sock,buf,len) send(sock,buf,len,0) 47 #define socklen_t int 48 #ifdef LIBVNCSERVER_HAVE_WS2TCPIP_H 49 #undef socklen_t 50 #include <ws2tcpip.h> 51 #endif 52 #else 53 #include <sys/socket.h> 54 #include <netinet/in.h> 55 #include <sys/un.h> 56 #include <netinet/tcp.h> 57 #include <arpa/inet.h> 58 #include <netdb.h> 59 #endif 60 #include "tls.h" 61 62 #ifdef _MSC_VER 63 # define snprintf _snprintf 64 #endif 65 66 void PrintInHex(char *buf, int len); 67 68 rfbBool errorMessageOnReadFailure = TRUE; 69 70 /* 71 * ReadFromRFBServer is called whenever we want to read some data from the RFB 72 * server. It is non-trivial for two reasons: 73 * 74 * 1. For efficiency it performs some intelligent buffering, avoiding invoking 75 * the read() system call too often. For small chunks of data, it simply 76 * copies the data out of an internal buffer. For large amounts of data it 77 * reads directly into the buffer provided by the caller. 78 * 79 * 2. Whenever read() would block, it invokes the Xt event dispatching 80 * mechanism to process X events. In fact, this is the only place these 81 * events are processed, as there is no XtAppMainLoop in the program. 82 */ 83 84 rfbBool 85 ReadFromRFBServer(rfbClient* client, char *out, unsigned int n) 86 { 87 #undef DEBUG_READ_EXACT 88 #ifdef DEBUG_READ_EXACT 89 char* oout=out; 90 int nn=n; 91 rfbClientLog("ReadFromRFBServer %d bytes\n",n); 92 #endif 93 94 /* Handle attempts to write to NULL out buffer that might occur 95 when an outside malloc() fails. For instance, memcpy() to NULL 96 results in undefined behaviour and probably memory corruption.*/ 97 if(!out) 98 return FALSE; 99 100 if (client->serverPort==-1) { 101 /* vncrec playing */ 102 rfbVNCRec* rec = client->vncRec; 103 struct timeval tv; 104 105 if (rec->readTimestamp) { 106 rec->readTimestamp = FALSE; 107 if (!fread(&tv,sizeof(struct timeval),1,rec->file)) 108 return FALSE; 109 110 tv.tv_sec = rfbClientSwap32IfLE (tv.tv_sec); 111 tv.tv_usec = rfbClientSwap32IfLE (tv.tv_usec); 112 113 if (rec->tv.tv_sec!=0 && !rec->doNotSleep) { 114 struct timeval diff; 115 diff.tv_sec = tv.tv_sec - rec->tv.tv_sec; 116 diff.tv_usec = tv.tv_usec - rec->tv.tv_usec; 117 if(diff.tv_usec<0) { 118 diff.tv_sec--; 119 diff.tv_usec+=1000000; 120 } 121 #ifndef WIN32 122 sleep (diff.tv_sec); 123 usleep (diff.tv_usec); 124 #else 125 Sleep (diff.tv_sec * 1000 + diff.tv_usec/1000); 126 #endif 127 } 128 129 rec->tv=tv; 130 } 131 132 return (fread(out,1,n,rec->file) != n ? FALSE : TRUE); 133 } 134 135 if (n <= client->buffered) { 136 memcpy(out, client->bufoutptr, n); 137 client->bufoutptr += n; 138 client->buffered -= n; 139 #ifdef DEBUG_READ_EXACT 140 goto hexdump; 141 #endif 142 return TRUE; 143 } 144 145 memcpy(out, client->bufoutptr, client->buffered); 146 147 out += client->buffered; 148 n -= client->buffered; 149 150 client->bufoutptr = client->buf; 151 client->buffered = 0; 152 153 if (n <= RFB_BUF_SIZE) { 154 155 while (client->buffered < n) { 156 int i; 157 if (client->tlsSession) { 158 i = ReadFromTLS(client, client->buf + client->buffered, RFB_BUF_SIZE - client->buffered); 159 } else { 160 i = read(client->sock, client->buf + client->buffered, RFB_BUF_SIZE - client->buffered); 161 } 162 if (i <= 0) { 163 if (i < 0) { 164 #ifdef WIN32 165 errno=WSAGetLastError(); 166 #endif 167 if (errno == EWOULDBLOCK || errno == EAGAIN) { 168 /* TODO: 169 ProcessXtEvents(); 170 */ 171 WaitForMessage(client, 100000); 172 i = 0; 173 } else { 174 rfbClientErr("read (%d: %s)\n",errno,strerror(errno)); 175 return FALSE; 176 } 177 } else { 178 if (errorMessageOnReadFailure) { 179 rfbClientLog("VNC server closed connection\n"); 180 } 181 return FALSE; 182 } 183 } 184 client->buffered += i; 185 } 186 187 memcpy(out, client->bufoutptr, n); 188 client->bufoutptr += n; 189 client->buffered -= n; 190 191 } else { 192 193 while (n > 0) { 194 int i; 195 if (client->tlsSession) { 196 i = ReadFromTLS(client, out, n); 197 } else { 198 i = read(client->sock, out, n); 199 } 200 201 if (i <= 0) { 202 if (i < 0) { 203 #ifdef WIN32 204 errno=WSAGetLastError(); 205 #endif 206 if (errno == EWOULDBLOCK || errno == EAGAIN) { 207 /* TODO: 208 ProcessXtEvents(); 209 */ 210 WaitForMessage(client, 100000); 211 i = 0; 212 } else { 213 rfbClientErr("read (%s)\n",strerror(errno)); 214 return FALSE; 215 } 216 } else { 217 if (errorMessageOnReadFailure) { 218 rfbClientLog("VNC server closed connection\n"); 219 } 220 return FALSE; 221 } 222 } 223 out += i; 224 n -= i; 225 } 226 } 227 228 #ifdef DEBUG_READ_EXACT 229 hexdump: 230 { int ii; 231 for(ii=0;ii<nn;ii++) 232 fprintf(stderr,"%02x ",(unsigned char)oout[ii]); 233 fprintf(stderr,"\n"); 234 } 235 #endif 236 237 return TRUE; 238 } 239 240 241 /* 242 * Write an exact number of bytes, and don't return until you've sent them. 243 */ 244 245 rfbBool 246 WriteToRFBServer(rfbClient* client, char *buf, int n) 247 { 248 fd_set fds; 249 int i = 0; 250 int j; 251 252 if (client->serverPort==-1) 253 return TRUE; /* vncrec playing */ 254 255 if (client->tlsSession) { 256 /* WriteToTLS() will guarantee either everything is written, or error/eof returns */ 257 i = WriteToTLS(client, buf, n); 258 if (i <= 0) return FALSE; 259 260 return TRUE; 261 } 262 263 while (i < n) { 264 j = write(client->sock, buf + i, (n - i)); 265 if (j <= 0) { 266 if (j < 0) { 267 #ifdef WIN32 268 errno=WSAGetLastError(); 269 #endif 270 if (errno == EWOULDBLOCK || 271 #ifdef LIBVNCSERVER_ENOENT_WORKAROUND 272 errno == ENOENT || 273 #endif 274 errno == EAGAIN) { 275 FD_ZERO(&fds); 276 FD_SET(client->sock,&fds); 277 278 if (select(client->sock+1, NULL, &fds, NULL, NULL) <= 0) { 279 rfbClientErr("select\n"); 280 return FALSE; 281 } 282 j = 0; 283 } else { 284 rfbClientErr("write\n"); 285 return FALSE; 286 } 287 } else { 288 rfbClientLog("write failed\n"); 289 return FALSE; 290 } 291 } 292 i += j; 293 } 294 return TRUE; 295 } 296 297 298 299 static int initSockets() { 300 #ifdef WIN32 301 WSADATA trash; 302 static rfbBool WSAinitted=FALSE; 303 if(!WSAinitted) { 304 int i=WSAStartup(MAKEWORD(2,0),&trash); 305 if(i!=0) { 306 rfbClientErr("Couldn't init Windows Sockets\n"); 307 return 0; 308 } 309 WSAinitted=TRUE; 310 } 311 #endif 312 return 1; 313 } 314 315 /* 316 * ConnectToTcpAddr connects to the given TCP port. 317 */ 318 319 int 320 ConnectClientToTcpAddr(unsigned int host, int port) 321 { 322 int sock; 323 struct sockaddr_in addr; 324 int one = 1; 325 326 if (!initSockets()) 327 return -1; 328 329 addr.sin_family = AF_INET; 330 addr.sin_port = htons(port); 331 addr.sin_addr.s_addr = host; 332 333 sock = socket(AF_INET, SOCK_STREAM, 0); 334 if (sock < 0) { 335 #ifdef WIN32 336 errno=WSAGetLastError(); 337 #endif 338 rfbClientErr("ConnectToTcpAddr: socket (%s)\n",strerror(errno)); 339 return -1; 340 } 341 342 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 343 rfbClientErr("ConnectToTcpAddr: connect\n"); 344 close(sock); 345 return -1; 346 } 347 348 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, 349 (char *)&one, sizeof(one)) < 0) { 350 rfbClientErr("ConnectToTcpAddr: setsockopt\n"); 351 close(sock); 352 return -1; 353 } 354 355 return sock; 356 } 357 358 int 359 ConnectClientToTcpAddr6(const char *hostname, int port) 360 { 361 #ifdef LIBVNCSERVER_IPv6 362 int sock; 363 int n; 364 struct addrinfo hints, *res, *ressave; 365 char port_s[10]; 366 int one = 1; 367 368 if (!initSockets()) 369 return -1; 370 371 snprintf(port_s, 10, "%d", port); 372 memset(&hints, 0, sizeof(struct addrinfo)); 373 hints.ai_family = AF_UNSPEC; 374 hints.ai_socktype = SOCK_STREAM; 375 if ((n = getaddrinfo(hostname, port_s, &hints, &res))) 376 { 377 rfbClientErr("ConnectClientToTcpAddr6: getaddrinfo (%s)\n", gai_strerror(n)); 378 return -1; 379 } 380 381 ressave = res; 382 sock = -1; 383 while (res) 384 { 385 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 386 if (sock >= 0) 387 { 388 if (connect(sock, res->ai_addr, res->ai_addrlen) == 0) 389 break; 390 close(sock); 391 sock = -1; 392 } 393 res = res->ai_next; 394 } 395 freeaddrinfo(ressave); 396 397 if (sock == -1) 398 { 399 rfbClientErr("ConnectClientToTcpAddr6: connect\n"); 400 return -1; 401 } 402 403 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, 404 (char *)&one, sizeof(one)) < 0) { 405 rfbClientErr("ConnectToTcpAddr: setsockopt\n"); 406 close(sock); 407 return -1; 408 } 409 410 return sock; 411 412 #else 413 414 rfbClientErr("ConnectClientToTcpAddr6: IPv6 disabled\n"); 415 return -1; 416 417 #endif 418 } 419 420 int 421 ConnectClientToUnixSock(const char *sockFile) 422 { 423 #ifdef WIN32 424 rfbClientErr("Windows doesn't support UNIX sockets\n"); 425 return -1; 426 #else 427 int sock; 428 struct sockaddr_un addr; 429 addr.sun_family = AF_UNIX; 430 strcpy(addr.sun_path, sockFile); 431 432 sock = socket(AF_UNIX, SOCK_STREAM, 0); 433 if (sock < 0) { 434 rfbClientErr("ConnectToUnixSock: socket (%s)\n",strerror(errno)); 435 return -1; 436 } 437 438 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr.sun_family) + strlen(addr.sun_path)) < 0) { 439 rfbClientErr("ConnectToUnixSock: connect\n"); 440 close(sock); 441 return -1; 442 } 443 444 return sock; 445 #endif 446 } 447 448 449 450 /* 451 * FindFreeTcpPort tries to find unused TCP port in the range 452 * (TUNNEL_PORT_OFFSET, TUNNEL_PORT_OFFSET + 99]. Returns 0 on failure. 453 */ 454 455 int 456 FindFreeTcpPort(void) 457 { 458 int sock, port; 459 struct sockaddr_in addr; 460 461 addr.sin_family = AF_INET; 462 addr.sin_addr.s_addr = htonl(INADDR_ANY); 463 464 if (!initSockets()) 465 return -1; 466 467 sock = socket(AF_INET, SOCK_STREAM, 0); 468 if (sock < 0) { 469 rfbClientErr(": FindFreeTcpPort: socket\n"); 470 return 0; 471 } 472 473 for (port = TUNNEL_PORT_OFFSET + 99; port > TUNNEL_PORT_OFFSET; port--) { 474 addr.sin_port = htons((unsigned short)port); 475 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) { 476 close(sock); 477 return port; 478 } 479 } 480 481 close(sock); 482 return 0; 483 } 484 485 486 /* 487 * ListenAtTcpPort starts listening at the given TCP port. 488 */ 489 490 int 491 ListenAtTcpPort(int port) 492 { 493 return ListenAtTcpPortAndAddress(port, NULL); 494 } 495 496 497 498 /* 499 * ListenAtTcpPortAndAddress starts listening at the given TCP port on 500 * the given IP address 501 */ 502 503 int 504 ListenAtTcpPortAndAddress(int port, const char *address) 505 { 506 int sock; 507 int one = 1; 508 #ifndef LIBVNCSERVER_IPv6 509 struct sockaddr_in addr; 510 511 addr.sin_family = AF_INET; 512 addr.sin_port = htons(port); 513 if (address) { 514 addr.sin_addr.s_addr = inet_addr(address); 515 } else { 516 addr.sin_addr.s_addr = htonl(INADDR_ANY); 517 } 518 519 if (!initSockets()) 520 return -1; 521 522 sock = socket(AF_INET, SOCK_STREAM, 0); 523 if (sock < 0) { 524 rfbClientErr("ListenAtTcpPort: socket\n"); 525 return -1; 526 } 527 528 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 529 (const char *)&one, sizeof(one)) < 0) { 530 rfbClientErr("ListenAtTcpPort: setsockopt\n"); 531 close(sock); 532 return -1; 533 } 534 535 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 536 rfbClientErr("ListenAtTcpPort: bind\n"); 537 close(sock); 538 return -1; 539 } 540 541 #else 542 int rv; 543 struct addrinfo hints, *servinfo, *p; 544 char port_str[8]; 545 546 snprintf(port_str, 8, "%d", port); 547 548 memset(&hints, 0, sizeof(hints)); 549 hints.ai_family = AF_UNSPEC; 550 hints.ai_socktype = SOCK_STREAM; 551 hints.ai_flags = AI_PASSIVE; /* fill in wildcard address if address == NULL */ 552 553 if (!initSockets()) 554 return -1; 555 556 if ((rv = getaddrinfo(address, port_str, &hints, &servinfo)) != 0) { 557 rfbClientErr("ListenAtTcpPortAndAddress: error in getaddrinfo: %s\n", gai_strerror(rv)); 558 return -1; 559 } 560 561 /* loop through all the results and bind to the first we can */ 562 for(p = servinfo; p != NULL; p = p->ai_next) { 563 if ((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) { 564 continue; 565 } 566 567 #ifdef IPV6_V6ONLY 568 /* we have seperate IPv4 and IPv6 sockets since some OS's do not support dual binding */ 569 if (p->ai_family == AF_INET6 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) < 0) { 570 rfbClientErr("ListenAtTcpPortAndAddress: error in setsockopt IPV6_V6ONLY: %s\n", strerror(errno)); 571 close(sock); 572 freeaddrinfo(servinfo); 573 return -1; 574 } 575 #endif 576 577 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) { 578 rfbClientErr("ListenAtTcpPortAndAddress: error in setsockopt SO_REUSEADDR: %s\n", strerror(errno)); 579 close(sock); 580 freeaddrinfo(servinfo); 581 return -1; 582 } 583 584 if (bind(sock, p->ai_addr, p->ai_addrlen) < 0) { 585 close(sock); 586 continue; 587 } 588 589 break; 590 } 591 592 if (p == NULL) { 593 rfbClientErr("ListenAtTcpPortAndAddress: error in bind: %s\n", strerror(errno)); 594 return -1; 595 } 596 597 /* all done with this structure now */ 598 freeaddrinfo(servinfo); 599 #endif 600 601 if (listen(sock, 5) < 0) { 602 rfbClientErr("ListenAtTcpPort: listen\n"); 603 close(sock); 604 return -1; 605 } 606 607 return sock; 608 } 609 610 611 /* 612 * AcceptTcpConnection accepts a TCP connection. 613 */ 614 615 int 616 AcceptTcpConnection(int listenSock) 617 { 618 int sock; 619 struct sockaddr_in addr; 620 socklen_t addrlen = sizeof(addr); 621 int one = 1; 622 623 sock = accept(listenSock, (struct sockaddr *) &addr, &addrlen); 624 if (sock < 0) { 625 rfbClientErr("AcceptTcpConnection: accept\n"); 626 return -1; 627 } 628 629 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, 630 (char *)&one, sizeof(one)) < 0) { 631 rfbClientErr("AcceptTcpConnection: setsockopt\n"); 632 close(sock); 633 return -1; 634 } 635 636 return sock; 637 } 638 639 640 /* 641 * SetNonBlocking sets a socket into non-blocking mode. 642 */ 643 644 rfbBool 645 SetNonBlocking(int sock) 646 { 647 #ifdef WIN32 648 unsigned long block=1; 649 if(ioctlsocket(sock, FIONBIO, &block) == SOCKET_ERROR) { 650 errno=WSAGetLastError(); 651 #else 652 int flags = fcntl(sock, F_GETFL); 653 if(flags < 0 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) { 654 #endif 655 rfbClientErr("Setting socket to non-blocking failed: %s\n",strerror(errno)); 656 return FALSE; 657 } 658 return TRUE; 659 } 660 661 662 663 /* 664 * SetDSCP sets a socket's IP QoS parameters aka Differentiated Services Code Point field 665 */ 666 667 rfbBool 668 SetDSCP(int sock, int dscp) 669 { 670 #ifdef WIN32 671 rfbClientErr("Setting of QoS IP DSCP not implemented for Windows\n"); 672 return TRUE; 673 #else 674 int level, cmd; 675 struct sockaddr addr; 676 socklen_t addrlen = sizeof(addr); 677 678 if(getsockname(sock, &addr, &addrlen) != 0) { 679 rfbClientErr("Setting socket QoS failed while getting socket address: %s\n",strerror(errno)); 680 return FALSE; 681 } 682 683 switch(addr.sa_family) 684 { 685 #if defined LIBVNCSERVER_IPv6 && defined IPV6_TCLASS 686 case AF_INET6: 687 level = IPPROTO_IPV6; 688 cmd = IPV6_TCLASS; 689 break; 690 #endif 691 case AF_INET: 692 level = IPPROTO_IP; 693 cmd = IP_TOS; 694 break; 695 default: 696 rfbClientErr("Setting socket QoS failed: Not bound to IP address"); 697 return FALSE; 698 } 699 700 if(setsockopt(sock, level, cmd, (void*)&dscp, sizeof(dscp)) != 0) { 701 rfbClientErr("Setting socket QoS failed: %s\n", strerror(errno)); 702 return FALSE; 703 } 704 705 return TRUE; 706 #endif 707 } 708 709 710 711 /* 712 * StringToIPAddr - convert a host string to an IP address. 713 */ 714 715 rfbBool 716 StringToIPAddr(const char *str, unsigned int *addr) 717 { 718 struct hostent *hp; 719 720 if (strcmp(str,"") == 0) { 721 *addr = htonl(INADDR_LOOPBACK); /* local */ 722 return TRUE; 723 } 724 725 *addr = inet_addr(str); 726 727 if (*addr != -1) 728 return TRUE; 729 730 if (!initSockets()) 731 return -1; 732 733 hp = gethostbyname(str); 734 735 if (hp) { 736 *addr = *(unsigned int *)hp->h_addr; 737 return TRUE; 738 } 739 740 return FALSE; 741 } 742 743 744 /* 745 * Test if the other end of a socket is on the same machine. 746 */ 747 748 rfbBool 749 SameMachine(int sock) 750 { 751 struct sockaddr_in peeraddr, myaddr; 752 socklen_t addrlen = sizeof(struct sockaddr_in); 753 754 getpeername(sock, (struct sockaddr *)&peeraddr, &addrlen); 755 getsockname(sock, (struct sockaddr *)&myaddr, &addrlen); 756 757 return (peeraddr.sin_addr.s_addr == myaddr.sin_addr.s_addr); 758 } 759 760 761 /* 762 * Print out the contents of a packet for debugging. 763 */ 764 765 void 766 PrintInHex(char *buf, int len) 767 { 768 int i, j; 769 char c, str[17]; 770 771 str[16] = 0; 772 773 rfbClientLog("ReadExact: "); 774 775 for (i = 0; i < len; i++) 776 { 777 if ((i % 16 == 0) && (i != 0)) { 778 rfbClientLog(" "); 779 } 780 c = buf[i]; 781 str[i % 16] = (((c > 31) && (c < 127)) ? c : '.'); 782 rfbClientLog("%02x ",(unsigned char)c); 783 if ((i % 4) == 3) 784 rfbClientLog(" "); 785 if ((i % 16) == 15) 786 { 787 rfbClientLog("%s\n",str); 788 } 789 } 790 if ((i % 16) != 0) 791 { 792 for (j = i % 16; j < 16; j++) 793 { 794 rfbClientLog(" "); 795 if ((j % 4) == 3) rfbClientLog(" "); 796 } 797 str[i % 16] = 0; 798 rfbClientLog("%s\n",str); 799 } 800 801 fflush(stderr); 802 } 803 804 int WaitForMessage(rfbClient* client,unsigned int usecs) 805 { 806 fd_set fds; 807 struct timeval timeout; 808 int num; 809 810 if (client->serverPort==-1) 811 /* playing back vncrec file */ 812 return 1; 813 814 timeout.tv_sec=(usecs/1000000); 815 timeout.tv_usec=(usecs%1000000); 816 817 FD_ZERO(&fds); 818 FD_SET(client->sock,&fds); 819 820 num=select(client->sock+1, &fds, NULL, NULL, &timeout); 821 if(num<0) { 822 #ifdef WIN32 823 errno=WSAGetLastError(); 824 #endif 825 rfbClientLog("Waiting for message failed: %d (%s)\n",errno,strerror(errno)); 826 } 827 828 return num; 829 } 830 831 832