You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libtdevnc/libvncserver/sockets.c

1008 lines
25 KiB

24 years ago
/*
* sockets.c - deal with TCP & UDP sockets.
*
* This code should be independent of any changes in the RFB protocol. It just
* deals with the X server scheduling stuff, calling rfbNewClientConnection and
* rfbProcessClientMessage to actually deal with the protocol. If a socket
* needs to be closed for any reason then rfbCloseClient should be called, and
* this in turn will call rfbClientConnectionGone. To make an active
* connection out, call rfbConnect - note that this does _not_ call
* rfbNewClientConnection.
*
* This file is divided into two types of function. Those beginning with
* "rfb" are specific to sockets using the RFB protocol. Those without the
* "rfb" prefix are more general socket routines (which are used by the http
* code).
*
* Thanks to Karl Hakimian for pointing out that some platforms return EAGAIN
* not EWOULDBLOCK.
*/
/*
* Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin
24 years ago
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
* Original Xvnc code 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.
*/
#include <rfb/rfb.h>
#ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H
24 years ago
#include <sys/types.h>
#endif
#ifdef LIBVNCSERVER_HAVE_SYS_TIME_H
24 years ago
#include <sys/time.h>
#endif
#ifdef LIBVNCSERVER_HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef LIBVNCSERVER_HAVE_NETINET_IN_H
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <arpa/inet.h>
#endif
#ifdef LIBVNCSERVER_HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
#include "rfbssl.h"
#endif
24 years ago
#if defined(__linux__) && defined(NEED_TIMEVAL)
struct timeval
{
long int tv_sec,tv_usec;
}
;
#endif
#ifdef LIBVNCSERVER_HAVE_FCNTL_H
24 years ago
#include <fcntl.h>
#endif
24 years ago
#include <errno.h>
#ifdef USE_LIBWRAP
#include <syslog.h>
#include <tcpd.h>
int allow_severity=LOG_INFO;
int deny_severity=LOG_WARNING;
#endif
20 years ago
#if defined(WIN32)
#ifndef __MINGW32__
20 years ago
#pragma warning (disable: 4018 4761)
#endif
20 years ago
#define read(sock,buf,len) recv(sock,buf,len,0)
#define EWOULDBLOCK WSAEWOULDBLOCK
#define ETIMEDOUT WSAETIMEDOUT
#define write(sock,buf,len) send(sock,buf,len,0)
#else
#define closesocket close
#endif
24 years ago
int rfbMaxClientWait = 20000; /* time (ms) after which we decide client has
gone away - needed to stop us hanging */
/*
* rfbInitSockets sets up the TCP and UDP sockets to listen for RFB
* connections. It does nothing if called again.
*/
void
rfbInitSockets(rfbScreenInfoPtr rfbScreen)
{
in_addr_t iface = rfbScreen->listenInterface;
if (rfbScreen->socketState!=RFB_SOCKET_INIT)
24 years ago
return;
rfbScreen->socketState = RFB_SOCKET_READY;
24 years ago
if (rfbScreen->inetdSock != -1) {
const int one = 1;
if(!rfbSetNonBlocking(rfbScreen->inetdSock))
return;
24 years ago
if (setsockopt(rfbScreen->inetdSock, IPPROTO_TCP, TCP_NODELAY,
(char *)&one, sizeof(one)) < 0) {
rfbLogPerror("setsockopt");
return;
24 years ago
}
FD_ZERO(&(rfbScreen->allFds));
FD_SET(rfbScreen->inetdSock, &(rfbScreen->allFds));
rfbScreen->maxFd = rfbScreen->inetdSock;
return;
}
if(rfbScreen->autoPort) {
int i;
FD_ZERO(&(rfbScreen->allFds));
rfbLog("Autoprobing TCP port \n");
for (i = 5900; i < 6000; i++) {
if ((rfbScreen->listenSock = rfbListenOnTCPPort(i, iface)) >= 0) {
rfbScreen->port = i;
break;
}
}
if (i >= 6000) {
rfbLogPerror("Failure autoprobing");
return;
}
rfbLog("Autoprobing selected TCP port %d\n", rfbScreen->port);
FD_SET(rfbScreen->listenSock, &(rfbScreen->allFds));
rfbScreen->maxFd = rfbScreen->listenSock;
#ifdef LIBVNCSERVER_IPv6
rfbLog("Autoprobing TCP6 port \n");
for (i = 5900; i < 6000; i++) {
if ((rfbScreen->listen6Sock = rfbListenOnTCP6Port(i, rfbScreen->listen6Interface)) >= 0) {
rfbScreen->ipv6port = i;
break;
}
}
if (i >= 6000) {
rfbLogPerror("Failure autoprobing");
return;
}
rfbLog("Autoprobing selected TCP6 port %d\n", rfbScreen->ipv6port);
FD_SET(rfbScreen->listen6Sock, &(rfbScreen->allFds));
rfbScreen->maxFd = max((int)rfbScreen->listen6Sock,rfbScreen->maxFd);
#endif
}
else if(rfbScreen->port>0) {
FD_ZERO(&(rfbScreen->allFds));
24 years ago
if ((rfbScreen->listenSock = rfbListenOnTCPPort(rfbScreen->port, iface)) < 0) {
24 years ago
rfbLogPerror("ListenOnTCPPort");
return;
}
rfbLog("Listening for VNC connections on TCP port %d\n", rfbScreen->port);
FD_SET(rfbScreen->listenSock, &(rfbScreen->allFds));
rfbScreen->maxFd = rfbScreen->listenSock;
#ifdef LIBVNCSERVER_IPv6
if ((rfbScreen->listen6Sock = rfbListenOnTCP6Port(rfbScreen->ipv6port, rfbScreen->listen6Interface)) < 0) {
/* ListenOnTCP6Port has its own detailed error printout */
return;
}
rfbLog("Listening for VNC connections on TCP6 port %d\n", rfbScreen->ipv6port);
FD_SET(rfbScreen->listen6Sock, &(rfbScreen->allFds));
rfbScreen->maxFd = max((int)rfbScreen->listen6Sock,rfbScreen->maxFd);
#endif
}
24 years ago
if (rfbScreen->udpPort != 0) {
rfbLog("rfbInitSockets: listening for input on UDP port %d\n",rfbScreen->udpPort);
if ((rfbScreen->udpSock = rfbListenOnUDPPort(rfbScreen->udpPort, iface)) < 0) {
24 years ago
rfbLogPerror("ListenOnUDPPort");
return;
24 years ago
}
rfbLog("Listening for VNC connections on TCP port %d\n", rfbScreen->port);
24 years ago
FD_SET(rfbScreen->udpSock, &(rfbScreen->allFds));
rfbScreen->maxFd = max((int)rfbScreen->udpSock,rfbScreen->maxFd);
24 years ago
}
}
void rfbShutdownSockets(rfbScreenInfoPtr rfbScreen)
{
if (rfbScreen->socketState!=RFB_SOCKET_READY)
return;
rfbScreen->socketState = RFB_SOCKET_SHUTDOWN;
if(rfbScreen->inetdSock>-1) {
closesocket(rfbScreen->inetdSock);
FD_CLR(rfbScreen->inetdSock,&rfbScreen->allFds);
rfbScreen->inetdSock=-1;
}
if(rfbScreen->listenSock>-1) {
closesocket(rfbScreen->listenSock);
FD_CLR(rfbScreen->listenSock,&rfbScreen->allFds);
rfbScreen->listenSock=-1;
}
if(rfbScreen->listen6Sock>-1) {
closesocket(rfbScreen->listen6Sock);
FD_CLR(rfbScreen->listen6Sock,&rfbScreen->allFds);
rfbScreen->listen6Sock=-1;
}
if(rfbScreen->udpSock>-1) {
closesocket(rfbScreen->udpSock);
FD_CLR(rfbScreen->udpSock,&rfbScreen->allFds);
rfbScreen->udpSock=-1;
}
}
24 years ago
/*
* rfbCheckFds is called from ProcessInputEvents to check for input on the RFB
* socket(s). If there is input to process, the appropriate function in the
* RFB server code will be called (rfbNewClientConnection,
* rfbProcessClientMessage, etc).
*/
int
24 years ago
rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec)
{
int nfds;
fd_set fds;
struct timeval tv;
struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
24 years ago
char buf[6];
rfbClientIteratorPtr i;
rfbClientPtr cl;
int result = 0;
24 years ago
if (!rfbScreen->inetdInitDone && rfbScreen->inetdSock != -1) {
rfbNewClientConnection(rfbScreen,rfbScreen->inetdSock);
rfbScreen->inetdInitDone = TRUE;
}
do {
memcpy((char *)&fds, (char *)&(rfbScreen->allFds), sizeof(fd_set));
tv.tv_sec = 0;
tv.tv_usec = usec;
nfds = select(rfbScreen->maxFd + 1, &fds, NULL, NULL /* &fds */, &tv);
if (nfds == 0) {
/* timed out, check for async events */
i = rfbGetClientIterator(rfbScreen);
while((cl = rfbClientIteratorNext(i))) {
if (cl->onHold)
continue;
if (FD_ISSET(cl->sock, &(rfbScreen->allFds)))
rfbSendFileTransferChunk(cl);
}
rfbReleaseClientIterator(i);
return result;
}
if (nfds < 0) {
#ifdef WIN32
errno = WSAGetLastError();
#endif
if (errno != EINTR)
rfbLogPerror("rfbCheckFds: select");
return -1;
}
24 years ago
result += nfds;
if (rfbScreen->listenSock != -1 && FD_ISSET(rfbScreen->listenSock, &fds)) {
24 years ago
if (!rfbProcessNewConnection(rfbScreen))
return -1;
24 years ago
FD_CLR(rfbScreen->listenSock, &fds);
if (--nfds == 0)
return result;
}
if (rfbScreen->listen6Sock != -1 && FD_ISSET(rfbScreen->listen6Sock, &fds)) {
if (!rfbProcessNewConnection(rfbScreen))
return -1;
FD_CLR(rfbScreen->listen6Sock, &fds);
if (--nfds == 0)
return result;
}
if ((rfbScreen->udpSock != -1) && FD_ISSET(rfbScreen->udpSock, &fds)) {
if(!rfbScreen->udpClient)
rfbNewUDPClient(rfbScreen);
if (recvfrom(rfbScreen->udpSock, buf, 1, MSG_PEEK,
(struct sockaddr *)&addr, &addrlen) < 0) {
rfbLogPerror("rfbCheckFds: UDP: recvfrom");
rfbDisconnectUDPSock(rfbScreen);
rfbScreen->udpSockConnected = FALSE;
} else {
if (!rfbScreen->udpSockConnected ||
(memcmp(&addr, &rfbScreen->udpRemoteAddr, addrlen) != 0))
{
/* new remote end */
rfbLog("rfbCheckFds: UDP: got connection\n");
memcpy(&rfbScreen->udpRemoteAddr, &addr, addrlen);
rfbScreen->udpSockConnected = TRUE;
if (connect(rfbScreen->udpSock,
(struct sockaddr *)&addr, addrlen) < 0) {
rfbLogPerror("rfbCheckFds: UDP: connect");
rfbDisconnectUDPSock(rfbScreen);
return -1;
}
rfbNewUDPConnection(rfbScreen,rfbScreen->udpSock);
24 years ago
}
rfbProcessUDPInput(rfbScreen);
24 years ago
}
FD_CLR(rfbScreen->udpSock, &fds);
if (--nfds == 0)
return result;
24 years ago
}
i = rfbGetClientIterator(rfbScreen);
while((cl = rfbClientIteratorNext(i))) {
if (cl->onHold)
continue;
if (FD_ISSET(cl->sock, &(rfbScreen->allFds)))
{
if (FD_ISSET(cl->sock, &fds))
rfbProcessClientMessage(cl);
else
rfbSendFileTransferChunk(cl);
}
}
rfbReleaseClientIterator(i);
} while(rfbScreen->handleEventsEagerly);
return result;
24 years ago
}
rfbBool
rfbProcessNewConnection(rfbScreenInfoPtr rfbScreen)
{
const int one = 1;
int sock = -1;
struct sockaddr_storage addr;
socklen_t addrlen = sizeof(addr);
fd_set listen_fds;
int chosen_listen_sock = -1;
/* Do another select() call to find out which listen socket
has an incoming connection pending. We know that at least
one of them has, so this should not block for too long! */
FD_ZERO(&listen_fds);
if(rfbScreen->listenSock >= 0)
FD_SET(rfbScreen->listenSock, &listen_fds);
if(rfbScreen->listen6Sock >= 0)
FD_SET(rfbScreen->listen6Sock, &listen_fds);
if (select(rfbScreen->maxFd+1, &listen_fds, NULL, NULL, NULL) == -1) {
rfbLogPerror("rfbProcessNewConnection: error in select");
return FALSE;
}
if (FD_ISSET(rfbScreen->listenSock, &listen_fds))
chosen_listen_sock = rfbScreen->listenSock;
if (FD_ISSET(rfbScreen->listen6Sock, &listen_fds))
chosen_listen_sock = rfbScreen->listen6Sock;
if ((sock = accept(chosen_listen_sock,
(struct sockaddr *)&addr, &addrlen)) < 0) {
rfbLogPerror("rfbCheckFds: accept");
return FALSE;
}
if(!rfbSetNonBlocking(sock)) {
closesocket(sock);
return FALSE;
}
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
(char *)&one, sizeof(one)) < 0) {
rfbLogPerror("rfbCheckFds: setsockopt");
closesocket(sock);
return FALSE;
}
#ifdef USE_LIBWRAP
if(!hosts_ctl("vnc",STRING_UNKNOWN,inet_ntoa(addr.sin_addr),
STRING_UNKNOWN)) {
rfbLog("Rejected connection from client %s\n",
inet_ntoa(addr.sin_addr));
closesocket(sock);
return FALSE;
}
#endif
#ifdef LIBVNCSERVER_IPv6
char host[1024];
if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) {
rfbLogPerror("rfbProcessNewConnection: error in getnameinfo");
}
rfbLog("Got connection from client %s\n", host);
#else
rfbLog("Got connection from client %s\n", inet_ntoa(addr.sin_addr));
#endif
rfbNewClient(rfbScreen,sock);
return TRUE;
}
24 years ago
void
rfbDisconnectUDPSock(rfbScreenInfoPtr rfbScreen)
{
rfbScreen->udpSockConnected = FALSE;
24 years ago
}
void
rfbCloseClient(rfbClientPtr cl)
24 years ago
{
rfbExtensionData* extension;
for(extension=cl->extensions; extension; extension=extension->next)
if(extension->extension->close)
extension->extension->close(cl, extension->data);
LOCK(cl->updateMutex);
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
23 years ago
if (cl->sock != -1)
#endif
{
FD_CLR(cl->sock,&(cl->screen->allFds));
if(cl->sock==cl->screen->maxFd)
while(cl->screen->maxFd>0
&& !FD_ISSET(cl->screen->maxFd,&(cl->screen->allFds)))
23 years ago
cl->screen->maxFd--;
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
if (cl->sslctx)
rfbssl_destroy(cl);
free(cl->wspath);
#endif
20 years ago
#ifndef __MINGW32__
23 years ago
shutdown(cl->sock,SHUT_RDWR);
20 years ago
#endif
closesocket(cl->sock);
23 years ago
cl->sock = -1;
}
TSIGNAL(cl->updateCond);
UNLOCK(cl->updateMutex);
24 years ago
}
/*
* rfbConnect is called to make a connection out to a given TCP address.
*/
int
rfbConnect(rfbScreenInfoPtr rfbScreen,
char *host,
int port)
{
int sock;
int one = 1;
rfbLog("Making connection to client on host %s port %d\n",
host,port);
if ((sock = rfbConnectToTcpAddr(host, port)) < 0) {
rfbLogPerror("connection failed");
return -1;
}
if(!rfbSetNonBlocking(sock)) {
closesocket(sock);
return -1;
}
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
(char *)&one, sizeof(one)) < 0) {
rfbLogPerror("setsockopt failed");
closesocket(sock);
return -1;
}
/* AddEnabledDevice(sock); */
FD_SET(sock, &rfbScreen->allFds);
rfbScreen->maxFd = max(sock,rfbScreen->maxFd);
return sock;
}
24 years ago
/*
* ReadExact reads an exact number of bytes from a client. Returns 1 if
* those bytes have been read, 0 if the other end has closed, or -1 if an error
* occurred (errno is set to ETIMEDOUT if it timed out).
*/
int
rfbReadExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout)
24 years ago
{
int sock = cl->sock;
int n;
fd_set fds;
struct timeval tv;
while (len > 0) {
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
if (cl->wsctx) {
n = webSocketsDecode(cl, buf, len);
} else if (cl->sslctx) {
n = rfbssl_read(cl, buf, len);
} else {
n = read(sock, buf, len);
}
#else
24 years ago
n = read(sock, buf, len);
#endif
24 years ago
if (n > 0) {
buf += n;
len -= n;
} else if (n == 0) {
return 0;
} else {
#ifdef WIN32
20 years ago
errno = WSAGetLastError();
#endif
if (errno == EINTR)
continue;
#ifdef LIBVNCSERVER_ENOENT_WORKAROUND
if (errno != ENOENT)
#endif
24 years ago
if (errno != EWOULDBLOCK && errno != EAGAIN) {
return n;
}
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
if (cl->sslctx) {
if (rfbssl_pending(cl))
continue;
}
#endif
24 years ago
FD_ZERO(&fds);
FD_SET(sock, &fds);
23 years ago
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
n = select(sock+1, &fds, NULL, &fds, &tv);
24 years ago
if (n < 0) {
rfbLogPerror("ReadExact: select");
return n;
}
if (n == 0) {
rfbErr("ReadExact: select timeout\n");
24 years ago
errno = ETIMEDOUT;
return -1;
}
}
}
#undef DEBUG_READ_EXACT
#ifdef DEBUG_READ_EXACT
rfbLog("ReadExact %d bytes\n",len);
for(n=0;n<len;n++)
fprintf(stderr,"%02x ",(unsigned char)buf[n]);
fprintf(stderr,"\n");
#endif
24 years ago
return 1;
}
int rfbReadExact(rfbClientPtr cl,char* buf,int len)
23 years ago
{
/* favor the per-screen value if set */
if(cl->screen && cl->screen->maxClientWait)
return(rfbReadExactTimeout(cl,buf,len,cl->screen->maxClientWait));
else
return(rfbReadExactTimeout(cl,buf,len,rfbMaxClientWait));
23 years ago
}
24 years ago
/*
* PeekExact peeks at an exact number of bytes from a client. Returns 1 if
* those bytes have been read, 0 if the other end has closed, or -1 if an
* error occurred (errno is set to ETIMEDOUT if it timed out).
*/
int
rfbPeekExactTimeout(rfbClientPtr cl, char* buf, int len, int timeout)
{
int sock = cl->sock;
int n;
fd_set fds;
struct timeval tv;
while (len > 0) {
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
if (cl->sslctx)
n = rfbssl_peek(cl, buf, len);
else
#endif
n = recv(sock, buf, len, MSG_PEEK);
if (n == len) {
break;
} else if (n == 0) {
return 0;
} else {
#ifdef WIN32
errno = WSAGetLastError();
#endif
if (errno == EINTR)
continue;
#ifdef LIBVNCSERVER_ENOENT_WORKAROUND
if (errno != ENOENT)
#endif
if (errno != EWOULDBLOCK && errno != EAGAIN) {
return n;
}
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
if (cl->sslctx) {
if (rfbssl_pending(cl))
continue;
}
#endif
FD_ZERO(&fds);
FD_SET(sock, &fds);
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
n = select(sock+1, &fds, NULL, &fds, &tv);
if (n < 0) {
rfbLogPerror("PeekExact: select");
return n;
}
if (n == 0) {
errno = ETIMEDOUT;
return -1;
}
}
}
#undef DEBUG_READ_EXACT
#ifdef DEBUG_READ_EXACT
rfbLog("PeekExact %d bytes\n",len);
for(n=0;n<len;n++)
fprintf(stderr,"%02x ",(unsigned char)buf[n]);
fprintf(stderr,"\n");
#endif
return 1;
}
24 years ago
/*
* WriteExact writes an exact number of bytes to a client. Returns 1 if
* those bytes have been written, or -1 if an error occurred (errno is set to
* ETIMEDOUT if it timed out).
*/
int
rfbWriteExact(rfbClientPtr cl,
const char *buf,
int len)
24 years ago
{
int sock = cl->sock;
int n;
fd_set fds;
struct timeval tv;
int totalTimeWaited = 0;
const int timeout = (cl->screen && cl->screen->maxClientWait) ? cl->screen->maxClientWait : rfbMaxClientWait;
24 years ago
21 years ago
#undef DEBUG_WRITE_EXACT
#ifdef DEBUG_WRITE_EXACT
rfbLog("WriteExact %d bytes\n",len);
for(n=0;n<len;n++)
fprintf(stderr,"%02x ",(unsigned char)buf[n]);
fprintf(stderr,"\n");
#endif
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
if (cl->wsctx) {
char *tmp = NULL;
if ((len = webSocketsEncode(cl, buf, len, &tmp)) < 0) {
rfbErr("WriteExact: WebSockets encode error\n");
return -1;
}
buf = tmp;
}
#endif
LOCK(cl->outputMutex);
24 years ago
while (len > 0) {
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
if (cl->sslctx)
n = rfbssl_write(cl, buf, len);
else
#endif
n = write(sock, buf, len);
24 years ago
if (n > 0) {
buf += n;
len -= n;
} else if (n == 0) {
22 years ago
rfbErr("WriteExact: write returned 0?\n");
return 0;
24 years ago
} else {
#ifdef WIN32
errno = WSAGetLastError();
#endif
if (errno == EINTR)
continue;
24 years ago
if (errno != EWOULDBLOCK && errno != EAGAIN) {
UNLOCK(cl->outputMutex);
24 years ago
return n;
}
/* Retry every 5 seconds until we exceed timeout. We
24 years ago
need to do this because select doesn't necessarily return
immediately when the other end has gone away */
FD_ZERO(&fds);
FD_SET(sock, &fds);
tv.tv_sec = 5;
tv.tv_usec = 0;
n = select(sock+1, NULL, &fds, NULL /* &fds */, &tv);
if (n < 0) {
#ifdef WIN32
errno=WSAGetLastError();
#endif
if(errno==EINTR)
continue;
24 years ago
rfbLogPerror("WriteExact: select");
UNLOCK(cl->outputMutex);
24 years ago
return n;
}
if (n == 0) {
totalTimeWaited += 5000;
if (totalTimeWaited >= timeout) {
24 years ago
errno = ETIMEDOUT;
UNLOCK(cl->outputMutex);
24 years ago
return -1;
}
} else {
totalTimeWaited = 0;
}
}
}
UNLOCK(cl->outputMutex);
24 years ago
return 1;
}
/* currently private, called by rfbProcessArguments() */
int
rfbStringToAddr(char *str, in_addr_t *addr) {
if (str == NULL || *str == '\0' || strcmp(str, "any") == 0) {
*addr = htonl(INADDR_ANY);
} else if (strcmp(str, "localhost") == 0) {
*addr = htonl(INADDR_LOOPBACK);
} else {
struct hostent *hp;
if ((*addr = inet_addr(str)) == htonl(INADDR_NONE)) {
if (!(hp = gethostbyname(str))) {
return 0;
}
*addr = *(unsigned long *)hp->h_addr;
}
}
return 1;
}
24 years ago
int
rfbListenOnTCPPort(int port,
in_addr_t iface)
24 years ago
{
struct sockaddr_in addr;
int sock;
int one = 1;
memset(&addr, 0, sizeof(addr));
24 years ago
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = iface;
24 years ago
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
return -1;
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
(char *)&one, sizeof(one)) < 0) {
closesocket(sock);
24 years ago
return -1;
}
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
closesocket(sock);
24 years ago
return -1;
}
if (listen(sock, 32) < 0) {
closesocket(sock);
24 years ago
return -1;
}
return sock;
}
int
rfbListenOnTCP6Port(int port,
const char* iface)
{
#ifndef LIBVNCSERVER_IPv6
rfbLogPerror("This LibVNCServer does not have IPv6 support");
return -1;
#else
int sock;
int one = 1;
int rv;
struct addrinfo hints, *servinfo, *p;
char port_str[8];
snprintf(port_str, 8, "%d", port);
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; /* fill in wildcard address if iface == NULL */
if ((rv = getaddrinfo(iface, port_str, &hints, &servinfo)) != 0) {
rfbErr("rfbListenOnTCP6Port error in getaddrinfo: %s\n", gai_strerror(rv));
return -1;
}
/* loop through all the results and bind to the first we can */
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) {
continue;
}
#ifdef IPV6_V6ONLY
/* we have seperate IPv4 and IPv6 sockets since some OS's do not support dual binding */
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) < 0) {
rfbLogPerror("rfbListenOnTCP6Port error in setsockopt IPV6_V6ONLY");
closesocket(sock);
return -1;
}
#endif
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) {
rfbLogPerror("rfbListenOnTCP6Port: error in setsockopt SO_REUSEADDR");
closesocket(sock);
return -1;
}
if (bind(sock, p->ai_addr, p->ai_addrlen) < 0) {
closesocket(sock);
continue;
}
break;
}
if (p == NULL) {
rfbLogPerror("rfbListenOnTCP6Port: error in bind IPv6 socket");
return -1;
}
/* all done with this structure now */
freeaddrinfo(servinfo);
if (listen(sock, 32) < 0) {
rfbLogPerror("rfbListenOnTCP6Port: error in listen on IPv6 socket");
closesocket(sock);
return -1;
}
return sock;
#endif
}
int
rfbConnectToTcpAddr(char *host,
int port)
{
struct hostent *hp;
int sock;
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if ((addr.sin_addr.s_addr = inet_addr(host)) == htonl(INADDR_NONE))
{
if (!(hp = gethostbyname(host))) {
errno = EINVAL;
return -1;
}
addr.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
}
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
return -1;
}
if (connect(sock, (struct sockaddr *)&addr, (sizeof(addr))) < 0) {
closesocket(sock);
return -1;
}
return sock;
}
24 years ago
int
rfbListenOnUDPPort(int port,
in_addr_t iface)
24 years ago
{
struct sockaddr_in addr;
int sock;
int one = 1;
memset(&addr, 0, sizeof(addr));
24 years ago
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = iface;
24 years ago
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
return -1;
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
(char *)&one, sizeof(one)) < 0) {
return -1;
}
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
return -1;
}
return sock;
}
/*
* rfbSetNonBlocking sets a socket into non-blocking mode.
*/
rfbBool
rfbSetNonBlocking(int sock)
{
#ifdef WIN32
unsigned long block=1;
if(ioctlsocket(sock, FIONBIO, &block) == SOCKET_ERROR) {
errno=WSAGetLastError();
#else
int flags = fcntl(sock, F_GETFL);
if(flags < 0 || fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
#endif
rfbLogPerror("Setting socket to non-blocking failed");
return FALSE;
}
return TRUE;
}