diff options
Diffstat (limited to 'libvncserver')
-rw-r--r-- | libvncserver/cargs.c | 34 | ||||
-rw-r--r-- | libvncserver/httpd.c | 91 | ||||
-rw-r--r-- | libvncserver/main.c | 40 | ||||
-rw-r--r-- | libvncserver/rfbserver.c | 17 | ||||
-rw-r--r-- | libvncserver/sockets.c | 214 |
5 files changed, 362 insertions, 34 deletions
diff --git a/libvncserver/cargs.c b/libvncserver/cargs.c index 2e973e8..b9eb02b 100644 --- a/libvncserver/cargs.c +++ b/libvncserver/cargs.c @@ -22,6 +22,9 @@ rfbUsage(void) rfbProtocolExtension* extension; fprintf(stderr, "-rfbport port TCP port for RFB protocol\n"); +#ifdef LIBVNCSERVER_IPv6 + fprintf(stderr, "-rfbportv6 port TCP6 port for RFB protocol\n"); +#endif fprintf(stderr, "-rfbwait time max time in ms to wait for RFB client\n"); fprintf(stderr, "-rfbauth passwd-file use authentication on RFB protocol\n" " (use 'storepasswd' to create a password file)\n"); @@ -42,10 +45,17 @@ rfbUsage(void) "instead)\n"); fprintf(stderr, "-httpdir dir-path enable http server using dir-path home\n"); fprintf(stderr, "-httpport portnum use portnum for http connection\n"); +#ifdef LIBVNCSERVER_IPv6 + fprintf(stderr, "-httpportv6 portnum use portnum for IPv6 http connection\n"); +#endif fprintf(stderr, "-enablehttpproxy enable http proxy support\n"); fprintf(stderr, "-progressive height enable progressive updating for slow links\n"); fprintf(stderr, "-listen ipaddr listen for connections only on network interface with\n"); fprintf(stderr, " addr ipaddr. '-listen localhost' and hostname work too.\n"); +#ifdef LIBVNCSERVER_IPv6 + fprintf(stderr, "-listenv6 ipv6addr listen for IPv6 connections only on network interface with\n"); + fprintf(stderr, " addr ipv6addr. '-listen localhost' and hostname work too.\n"); +#endif for(extension=rfbGetExtensionIterator();extension;extension=extension->next) if(extension->usage) @@ -80,6 +90,14 @@ rfbProcessArguments(rfbScreenInfoPtr rfbScreen,int* argc, char *argv[]) return FALSE; } rfbScreen->port = atoi(argv[++i]); +#ifdef LIBVNCSERVER_IPv6 + } else if (strcmp(argv[i], "-rfbportv6") == 0) { /* -rfbportv6 port */ + if (i + 1 >= *argc) { + rfbUsage(); + return FALSE; + } + rfbScreen->ipv6port = atoi(argv[++i]); +#endif } else if (strcmp(argv[i], "-rfbwait") == 0) { /* -rfbwait ms */ if (i + 1 >= *argc) { rfbUsage(); @@ -147,6 +165,14 @@ rfbProcessArguments(rfbScreenInfoPtr rfbScreen,int* argc, char *argv[]) return FALSE; } rfbScreen->httpPort = atoi(argv[++i]); +#ifdef LIBVNCSERVER_IPv6 + } else if (strcmp(argv[i], "-httpportv6") == 0) { /* -httpportv6 portnum */ + if (i + 1 >= *argc) { + rfbUsage(); + return FALSE; + } + rfbScreen->http6Port = atoi(argv[++i]); +#endif } else if (strcmp(argv[i], "-enablehttpproxy") == 0) { rfbScreen->httpEnableProxyConnect = TRUE; } else if (strcmp(argv[i], "-progressive") == 0) { /* -httpport portnum */ @@ -163,6 +189,14 @@ rfbProcessArguments(rfbScreenInfoPtr rfbScreen,int* argc, char *argv[]) if (! rfbStringToAddr(argv[++i], &(rfbScreen->listenInterface))) { return FALSE; } +#ifdef LIBVNCSERVER_IPv6 + } else if (strcmp(argv[i], "-listenv6") == 0) { /* -listenv6 ipv6addr */ + if (i + 1 >= *argc) { + rfbUsage(); + return FALSE; + } + rfbScreen->listen6Interface = argv[++i]; +#endif #ifdef LIBVNCSERVER_WITH_WEBSOCKETS } else if (strcmp(argv[i], "-sslkeyfile") == 0) { /* -sslkeyfile sslkeyfile */ if (i + 1 >= *argc) { diff --git a/libvncserver/httpd.c b/libvncserver/httpd.c index 3025aae..ed91e46 100644 --- a/libvncserver/httpd.c +++ b/libvncserver/httpd.c @@ -3,6 +3,7 @@ */ /* + * Copyright (C) 2011-2012 Christian Beier <dontmind@freeshell.org> * Copyright (C) 2002 RealVNC Ltd. * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. * @@ -102,17 +103,27 @@ rfbHttpInitSockets(rfbScreenInfoPtr rfbScreen) rfbScreen->httpPort = rfbScreen->port-100; } - rfbLog("Listening for HTTP connections on TCP port %d\n", rfbScreen->httpPort); - - rfbLog(" URL http://%s:%d\n",rfbScreen->thisHost,rfbScreen->httpPort); - if ((rfbScreen->httpListenSock = rfbListenOnTCPPort(rfbScreen->httpPort, rfbScreen->listenInterface)) < 0) { rfbLogPerror("ListenOnTCPPort"); return; } + rfbLog("Listening for HTTP connections on TCP port %d\n", rfbScreen->httpPort); + rfbLog(" URL http://%s:%d\n",rfbScreen->thisHost,rfbScreen->httpPort); + +#ifdef LIBVNCSERVER_IPv6 + if (rfbScreen->http6Port == 0) { + rfbScreen->http6Port = rfbScreen->ipv6port-100; + } - /*AddEnabledDevice(httpListenSock);*/ + if ((rfbScreen->httpListen6Sock + = rfbListenOnTCP6Port(rfbScreen->http6Port, rfbScreen->listen6Interface)) < 0) { + /* ListenOnTCP6Port has its own detailed error printout */ + return; + } + rfbLog("Listening for HTTP connections on TCP6 port %d\n", rfbScreen->http6Port); + rfbLog(" URL http://%s:%d\n",rfbScreen->thisHost,rfbScreen->http6Port); +#endif } void rfbHttpShutdownSockets(rfbScreenInfoPtr rfbScreen) { @@ -121,6 +132,18 @@ void rfbHttpShutdownSockets(rfbScreenInfoPtr rfbScreen) { FD_CLR(rfbScreen->httpSock,&rfbScreen->allFds); rfbScreen->httpSock=-1; } + + if(rfbScreen->httpListenSock>-1) { + close(rfbScreen->httpListenSock); + FD_CLR(rfbScreen->httpListenSock,&rfbScreen->allFds); + rfbScreen->httpListenSock=-1; + } + + if(rfbScreen->httpListen6Sock>-1) { + close(rfbScreen->httpListen6Sock); + FD_CLR(rfbScreen->httpListen6Sock,&rfbScreen->allFds); + rfbScreen->httpListen6Sock=-1; + } } /* @@ -134,7 +157,11 @@ rfbHttpCheckFds(rfbScreenInfoPtr rfbScreen) int nfds; fd_set fds; struct timeval tv; +#ifdef LIBVNCSERVER_IPv6 + struct sockaddr_storage addr; +#else struct sockaddr_in addr; +#endif socklen_t addrlen = sizeof(addr); if (!rfbScreen->httpDir) @@ -145,12 +172,15 @@ rfbHttpCheckFds(rfbScreenInfoPtr rfbScreen) FD_ZERO(&fds); FD_SET(rfbScreen->httpListenSock, &fds); + if (rfbScreen->httpListen6Sock >= 0) { + FD_SET(rfbScreen->httpListen6Sock, &fds); + } if (rfbScreen->httpSock >= 0) { FD_SET(rfbScreen->httpSock, &fds); } tv.tv_sec = 0; tv.tv_usec = 0; - nfds = select(max(rfbScreen->httpSock,rfbScreen->httpListenSock) + 1, &fds, NULL, NULL, &tv); + nfds = select(max(rfbScreen->httpListen6Sock, max(rfbScreen->httpSock,rfbScreen->httpListenSock)) + 1, &fds, NULL, NULL, &tv); if (nfds == 0) { return; } @@ -167,19 +197,36 @@ rfbHttpCheckFds(rfbScreenInfoPtr rfbScreen) httpProcessInput(rfbScreen); } - if (FD_ISSET(rfbScreen->httpListenSock, &fds)) { + if (FD_ISSET(rfbScreen->httpListenSock, &fds) || FD_ISSET(rfbScreen->httpListen6Sock, &fds)) { if (rfbScreen->httpSock >= 0) close(rfbScreen->httpSock); - if ((rfbScreen->httpSock = accept(rfbScreen->httpListenSock, - (struct sockaddr *)&addr, &addrlen)) < 0) { - rfbLogPerror("httpCheckFds: accept"); - return; + if(FD_ISSET(rfbScreen->httpListenSock, &fds)) { + if ((rfbScreen->httpSock = accept(rfbScreen->httpListenSock, (struct sockaddr *)&addr, &addrlen)) < 0) { + rfbLogPerror("httpCheckFds: accept"); + return; + } } + else if(FD_ISSET(rfbScreen->httpListen6Sock, &fds)) { + if ((rfbScreen->httpSock = accept(rfbScreen->httpListen6Sock, (struct sockaddr *)&addr, &addrlen)) < 0) { + rfbLogPerror("httpCheckFds: accept"); + return; + } + } + #ifdef USE_LIBWRAP - if(!hosts_ctl("vnc",STRING_UNKNOWN,inet_ntoa(addr.sin_addr), + char host[1024]; +#ifdef LIBVNCSERVER_IPv6 + if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) { + rfbLogPerror("httpCheckFds: error in getnameinfo"); + host[0] = '\0'; + } +#else + memcpy(host, inet_ntoa(addr.sin_addr), sizeof(host)); +#endif + if(!hosts_ctl("vnc",STRING_UNKNOWN, host, STRING_UNKNOWN)) { rfbLog("Rejected HTTP connection from client %s\n", - inet_ntoa(addr.sin_addr)); + host); close(rfbScreen->httpSock); rfbScreen->httpSock=-1; return; @@ -212,7 +259,11 @@ static rfbClientRec cl; static void httpProcessInput(rfbScreenInfoPtr rfbScreen) { +#ifdef LIBVNCSERVER_IPv6 + struct sockaddr_storage addr; +#else struct sockaddr_in addr; +#endif socklen_t addrlen = sizeof(addr); char fullFname[512]; char params[1024]; @@ -335,8 +386,16 @@ httpProcessInput(rfbScreenInfoPtr rfbScreen) getpeername(rfbScreen->httpSock, (struct sockaddr *)&addr, &addrlen); +#ifdef LIBVNCSERVER_IPv6 + char host[1024]; + if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) { + rfbLogPerror("httpProcessInput: error in getnameinfo"); + } + rfbLog("httpd: get '%s' for %s\n", fname+1, host); +#else rfbLog("httpd: get '%s' for %s\n", fname+1, inet_ntoa(addr.sin_addr)); +#endif /* Extract parameters from the URL string if necessary */ @@ -562,7 +621,8 @@ parseParams(const char *request, char *result, int max_bytes) /* * Check if the string consists only of alphanumeric characters, '+' - * signs, underscores, and dots. Replace all '+' signs with spaces. + * signs, underscores, dots, colons and square brackets. + * Replace all '+' signs with spaces. */ static rfbBool @@ -571,7 +631,8 @@ validateString(char *str) char *ptr; for (ptr = str; *ptr != '\0'; ptr++) { - if (!isalnum(*ptr) && *ptr != '_' && *ptr != '.') { + if (!isalnum(*ptr) && *ptr != '_' && *ptr != '.' + && *ptr != ':' && *ptr != '[' && *ptr != ']' ) { if (*ptr == '+') { *ptr = ' '; } else { diff --git a/libvncserver/main.c b/libvncserver/main.c index 0edf994..4cb18ac 100644 --- a/libvncserver/main.c +++ b/libvncserver/main.c @@ -569,21 +569,37 @@ listenerRun(void *data) { rfbScreenInfoPtr screen=(rfbScreenInfoPtr)data; int client_fd; - struct sockaddr_in peer; - rfbClientPtr cl; + struct sockaddr_storage peer; + rfbClientPtr cl = NULL; socklen_t len; - - len = sizeof(peer); + fd_set listen_fds; /* temp file descriptor list for select() */ /* TODO: this thread wont die by restarting the server */ /* TODO: HTTP is not handled */ - while ((client_fd = accept(screen->listenSock, - (struct sockaddr*)&peer, &len)) >= 0) { - cl = rfbNewClient(screen,client_fd); - len = sizeof(peer); - + while (1) { + client_fd = -1; + FD_ZERO(&listen_fds); + if(screen->listenSock >= 0) + FD_SET(screen->listenSock, &listen_fds); + if(screen->listen6Sock >= 0) + FD_SET(screen->listen6Sock, &listen_fds); + + if (select(screen->maxFd+1, &listen_fds, NULL, NULL, NULL) == -1) { + rfbLogPerror("listenerRun: error in select"); + return NULL; + } + + /* there is something on the listening sockets, handle new connections */ + len = sizeof (peer); + if (FD_ISSET(screen->listenSock, &listen_fds)) + client_fd = accept(screen->listenSock, (struct sockaddr*)&peer, &len); + else if (FD_ISSET(screen->listen6Sock, &listen_fds)) + client_fd = accept(screen->listen6Sock, (struct sockaddr*)&peer, &len); + + if(client_fd >= 0) + cl = rfbNewClient(screen,client_fd); if (cl && !cl->onHold ) - rfbStartOnHoldClient(cl); + rfbStartOnHoldClient(cl); } return(NULL); } @@ -809,6 +825,7 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv, screen->clientHead=NULL; screen->pointerClient=NULL; screen->port=5900; + screen->ipv6port=5900; screen->socketState=RFB_SOCKET_INIT; screen->inetdInitDone = FALSE; @@ -821,12 +838,15 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv, screen->maxFd=0; screen->listenSock=-1; + screen->listen6Sock=-1; screen->httpInitDone=FALSE; screen->httpEnableProxyConnect=FALSE; screen->httpPort=0; + screen->http6Port=0; screen->httpDir=NULL; screen->httpListenSock=-1; + screen->httpListen6Sock=-1; screen->httpSock=-1; screen->desktopName = "LibVNCServer"; diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c index 9be255f..23c4d77 100644 --- a/libvncserver/rfbserver.c +++ b/libvncserver/rfbserver.c @@ -50,6 +50,7 @@ #ifdef LIBVNCSERVER_HAVE_NETINET_IN_H #include <netinet/in.h> #include <netinet/tcp.h> +#include <netdb.h> #include <arpa/inet.h> #endif #endif @@ -270,8 +271,12 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen, rfbProtocolVersionMsg pv; rfbClientIteratorPtr iterator; rfbClientPtr cl,cl_; +#ifdef LIBVNCSERVER_IPv6 + struct sockaddr_storage addr; +#else struct sockaddr_in addr; - socklen_t addrlen = sizeof(struct sockaddr_in); +#endif + socklen_t addrlen = sizeof(addr); rfbProtocolExtension* extension; cl = (rfbClientPtr)calloc(sizeof(rfbClientRec),1); @@ -294,7 +299,17 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen, int one=1; getpeername(sock, (struct sockaddr *)&addr, &addrlen); +#ifdef LIBVNCSERVER_IPv6 + char host[1024]; + if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) { + rfbLogPerror("rfbNewClient: error in getnameinfo"); + cl->host = strdup(""); + } + else + cl->host = strdup(host); +#else cl->host = strdup(inet_ntoa(addr.sin_addr)); +#endif rfbLog(" other clients:\n"); iterator = rfbGetClientIterator(rfbScreen); diff --git a/libvncserver/sockets.c b/libvncserver/sockets.c index 415f712..84c9c98 100644 --- a/libvncserver/sockets.c +++ b/libvncserver/sockets.c @@ -19,6 +19,7 @@ */ /* + * Copyright (C) 2011-2012 Christian Beier <dontmind@freeshell.org> * Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>. * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge. @@ -137,6 +138,8 @@ rfbInitSockets(rfbScreenInfoPtr rfbScreen) 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) { @@ -150,22 +153,52 @@ rfbInitSockets(rfbScreenInfoPtr rfbScreen) return; } - rfbLog("Autoprobing selected port %d\n", rfbScreen->port); - FD_ZERO(&(rfbScreen->allFds)); + 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) { - rfbLog("Listening for VNC connections on TCP port %d\n", rfbScreen->port); + FD_ZERO(&(rfbScreen->allFds)); if ((rfbScreen->listenSock = rfbListenOnTCPPort(rfbScreen->port, iface)) < 0) { rfbLogPerror("ListenOnTCPPort"); return; } - - FD_ZERO(&(rfbScreen->allFds)); + 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 + } if (rfbScreen->udpPort != 0) { @@ -175,6 +208,8 @@ rfbInitSockets(rfbScreenInfoPtr rfbScreen) rfbLogPerror("ListenOnUDPPort"); return; } + rfbLog("Listening for VNC connections on TCP port %d\n", rfbScreen->port); + FD_SET(rfbScreen->udpSock, &(rfbScreen->allFds)); rfbScreen->maxFd = max((int)rfbScreen->udpSock,rfbScreen->maxFd); } @@ -199,6 +234,12 @@ void rfbShutdownSockets(rfbScreenInfoPtr rfbScreen) 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); @@ -270,6 +311,16 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec) 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); @@ -330,10 +381,33 @@ rfbProcessNewConnection(rfbScreenInfoPtr rfbScreen) { const int one = 1; int sock = -1; +#ifdef LIBVNCSERVER_IPv6 + struct sockaddr_storage addr; +#else struct sockaddr_in addr; +#endif 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(rfbScreen->listenSock, + if ((sock = accept(chosen_listen_sock, (struct sockaddr *)&addr, &addrlen)) < 0) { rfbLogPerror("rfbCheckFds: accept"); return FALSE; @@ -361,7 +435,15 @@ rfbProcessNewConnection(rfbScreenInfoPtr rfbScreen) } #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); @@ -774,12 +856,128 @@ rfbListenOnTCPPort(int port, 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); + freeaddrinfo(servinfo); + return -1; + } +#endif + + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) { + rfbLogPerror("rfbListenOnTCP6Port: error in setsockopt SO_REUSEADDR"); + closesocket(sock); + freeaddrinfo(servinfo); + 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"); + freeaddrinfo(servinfo); + 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; +#ifdef LIBVNCSERVER_IPv6 + struct addrinfo hints, *servinfo, *p; + int rv; + char port_str[8]; + + snprintf(port_str, 8, "%d", port); + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if ((rv = getaddrinfo(host, port_str, &hints, &servinfo)) != 0) { + rfbErr("rfbConnectToTcpAddr: error in getaddrinfo: %s\n", gai_strerror(rv)); + return -1; + } + + /* loop through all the results and connect 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; + + if (connect(sock, p->ai_addr, p->ai_addrlen) < 0) { + closesocket(sock); + continue; + } + + break; + } + + /* all failed */ + if (p == NULL) { + rfbLogPerror("rfbConnectToTcoAddr: failed to connect\n"); + sock = -1; /* set return value */ + } + + /* all done with this structure now */ + freeaddrinfo(servinfo); +#else + struct hostent *hp; struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); @@ -803,7 +1001,7 @@ rfbConnectToTcpAddr(char *host, closesocket(sock); return -1; } - +#endif return sock; } |