From 0fc57f2054f9e1b7d2efbe202fdaa4b8e39556f3 Mon Sep 17 00:00:00 2001 From: dscho Date: Sun, 27 Jul 2003 21:51:57 +0000 Subject: first alpha version of libvncclient --- libvncclient/sockets.c | 424 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 424 insertions(+) create mode 100644 libvncclient/sockets.c (limited to 'libvncclient/sockets.c') diff --git a/libvncclient/sockets.c b/libvncclient/sockets.c new file mode 100644 index 0000000..5e6cd69 --- /dev/null +++ b/libvncclient/sockets.c @@ -0,0 +1,424 @@ +/* + * 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. + */ + +/* + * sockets.c - functions to deal with sockets. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void PrintInHex(char *buf, int len); + +Bool errorMessageOnReadFailure = TRUE; + +#define BUF_SIZE 8192 +static char buf[BUF_SIZE]; +static char *bufoutptr = buf; +static int buffered = 0; + +/* + * ReadFromRFBServer is called whenever we want to read some data from the RFB + * server. It is non-trivial for two reasons: + * + * 1. For efficiency it performs some intelligent buffering, avoiding invoking + * the read() system call too often. For small chunks of data, it simply + * copies the data out of an internal buffer. For large amounts of data it + * reads directly into the buffer provided by the caller. + * + * 2. Whenever read() would block, it invokes the Xt event dispatching + * mechanism to process X events. In fact, this is the only place these + * events are processed, as there is no XtAppMainLoop in the program. + */ + +Bool +ReadFromRFBServer(rfbClient* client, char *out, unsigned int n) +{ + if (n <= buffered) { + memcpy(out, bufoutptr, n); + bufoutptr += n; + buffered -= n; + return TRUE; + } + + memcpy(out, bufoutptr, buffered); + + out += buffered; + n -= buffered; + + bufoutptr = buf; + buffered = 0; + + if (n <= BUF_SIZE) { + + while (buffered < n) { + int i = read(client->sock, buf + buffered, BUF_SIZE - buffered); + if (i <= 0) { + if (i < 0) { + if (errno == EWOULDBLOCK || errno == EAGAIN) { + /* TODO: + ProcessXtEvents(); + */ + i = 0; + } else { + perror("read"); + return FALSE; + } + } else { + if (errorMessageOnReadFailure) { + fprintf(stderr,"VNC server closed connection\n"); + } + return FALSE; + } + } + buffered += i; + } + + memcpy(out, bufoutptr, n); + bufoutptr += n; + buffered -= n; + return TRUE; + + } else { + + while (n > 0) { + int i = read(client->sock, out, n); + if (i <= 0) { + if (i < 0) { + if (errno == EWOULDBLOCK || errno == EAGAIN) { + /* TODO: + ProcessXtEvents(); + */ + i = 0; + } else { + perror("read"); + return FALSE; + } + } else { + if (errorMessageOnReadFailure) { + fprintf(stderr,"VNC server closed connection\n"); + } + return FALSE; + } + } + out += i; + n -= i; + } + + return TRUE; + } +} + + +/* + * Write an exact number of bytes, and don't return until you've sent them. + */ + +Bool +WriteExact(rfbClient* client, char *buf, int n) +{ + fd_set fds; + int i = 0; + int j; + + while (i < n) { + j = write(client->sock, buf + i, (n - i)); + if (j <= 0) { + if (j < 0) { + if (errno == EWOULDBLOCK || errno == EAGAIN) { + FD_ZERO(&fds); + FD_SET(client->sock,&fds); + + if (select(client->sock+1, NULL, &fds, NULL, NULL) <= 0) { + perror("select"); + return FALSE; + } + j = 0; + } else { + perror("write"); + return FALSE; + } + } else { + fprintf(stderr,"write failed\n"); + return FALSE; + } + } + i += j; + } + return TRUE; +} + + +/* + * ConnectToTcpAddr connects to the given TCP port. + */ + +int +ConnectToTcpAddr(unsigned int host, int port) +{ + int sock; + struct sockaddr_in addr; + int one = 1; + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = host; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + perror("ConnectToTcpAddr: socket"); + return -1; + } + + if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("ConnectToTcpAddr: connect"); + close(sock); + return -1; + } + + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, + (char *)&one, sizeof(one)) < 0) { + perror("ConnectToTcpAddr: setsockopt"); + close(sock); + return -1; + } + + return sock; +} + + + +/* + * FindFreeTcpPort tries to find unused TCP port in the range + * (TUNNEL_PORT_OFFSET, TUNNEL_PORT_OFFSET + 99]. Returns 0 on failure. + */ + +int +FindFreeTcpPort(void) +{ + int sock, port; + struct sockaddr_in addr; + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + perror(": FindFreeTcpPort: socket"); + return 0; + } + + for (port = TUNNEL_PORT_OFFSET + 99; port > TUNNEL_PORT_OFFSET; port--) { + addr.sin_port = htons((unsigned short)port); + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) { + close(sock); + return port; + } + } + + close(sock); + return 0; +} + + +/* + * ListenAtTcpPort starts listening at the given TCP port. + */ + +int +ListenAtTcpPort(int port) +{ + int sock; + struct sockaddr_in addr; + int one = 1; + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + perror("ListenAtTcpPort: socket"); + return -1; + } + + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + (const char *)&one, sizeof(one)) < 0) { + perror("ListenAtTcpPort: setsockopt"); + close(sock); + return -1; + } + + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("ListenAtTcpPort: bind"); + close(sock); + return -1; + } + + if (listen(sock, 5) < 0) { + perror("ListenAtTcpPort: listen"); + close(sock); + return -1; + } + + return sock; +} + + +/* + * AcceptTcpConnection accepts a TCP connection. + */ + +int +AcceptTcpConnection(int listenSock) +{ + int sock; + struct sockaddr_in addr; + int addrlen = sizeof(addr); + int one = 1; + + sock = accept(listenSock, (struct sockaddr *) &addr, &addrlen); + if (sock < 0) { + perror("AcceptTcpConnection: accept"); + return -1; + } + + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, + (char *)&one, sizeof(one)) < 0) { + perror("AcceptTcpConnection: setsockopt"); + close(sock); + return -1; + } + + return sock; +} + + +/* + * SetNonBlocking sets a socket into non-blocking mode. + */ + +Bool +SetNonBlocking(int sock) +{ + if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { + perror("AcceptTcpConnection: fcntl"); + return FALSE; + } + return TRUE; +} + + +/* + * StringToIPAddr - convert a host string to an IP address. + */ + +Bool +StringToIPAddr(const char *str, unsigned int *addr) +{ + struct hostent *hp; + + if (strcmp(str,"") == 0) { + *addr = 0; /* local */ + return TRUE; + } + + *addr = inet_addr(str); + + if (*addr != -1) + return TRUE; + + hp = gethostbyname(str); + + if (hp) { + *addr = *(unsigned int *)hp->h_addr; + return TRUE; + } + + return FALSE; +} + + +/* + * Test if the other end of a socket is on the same machine. + */ + +Bool +SameMachine(int sock) +{ + struct sockaddr_in peeraddr, myaddr; + int addrlen = sizeof(struct sockaddr_in); + + getpeername(sock, (struct sockaddr *)&peeraddr, &addrlen); + getsockname(sock, (struct sockaddr *)&myaddr, &addrlen); + + return (peeraddr.sin_addr.s_addr == myaddr.sin_addr.s_addr); +} + + +/* + * Print out the contents of a packet for debugging. + */ + +void +PrintInHex(char *buf, int len) +{ + int i, j; + char c, str[17]; + + str[16] = 0; + + fprintf(stderr,"ReadExact: "); + + for (i = 0; i < len; i++) + { + if ((i % 16 == 0) && (i != 0)) { + fprintf(stderr," "); + } + c = buf[i]; + str[i % 16] = (((c > 31) && (c < 127)) ? c : '.'); + fprintf(stderr,"%02x ",(unsigned char)c); + if ((i % 4) == 3) + fprintf(stderr," "); + if ((i % 16) == 15) + { + fprintf(stderr,"%s\n",str); + } + } + if ((i % 16) != 0) + { + for (j = i % 16; j < 16; j++) + { + fprintf(stderr," "); + if ((j % 4) == 3) fprintf(stderr," "); + } + str[i % 16] = 0; + fprintf(stderr,"%s\n",str); + } + + fflush(stderr); +} -- cgit v1.1