summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Beier <dontmind@freeshell.org>2012-04-02 16:30:53 +0200
committerChristian Beier <dontmind@freeshell.org>2012-04-02 16:30:53 +0200
commitefcdab50cc10ad121653bfff0da441495af461d3 (patch)
tree4a758a7c8caaf070ac14efa80411d00aac1ab3b7
parentee4593425f63821280162d4e66a091479038a652 (diff)
parent2d50fc84f7ba869767ce052aa2aa9b11a104e0de (diff)
downloadlibtdevnc-efcdab50cc10ad121653bfff0da441495af461d3.tar.gz
libtdevnc-efcdab50cc10ad121653bfff0da441495af461d3.zip
Merge branch 'server-ipv6'
-rw-r--r--client_examples/SDLvncviewer.c1
-rw-r--r--libvncclient/listen.c77
-rw-r--r--libvncclient/sockets.c64
-rw-r--r--libvncclient/vncviewer.c2
-rw-r--r--libvncserver/cargs.c34
-rw-r--r--libvncserver/httpd.c91
-rw-r--r--libvncserver/main.c40
-rw-r--r--libvncserver/rfbserver.c17
-rw-r--r--libvncserver/sockets.c214
-rw-r--r--rfb/rfb.h9
-rw-r--r--rfb/rfbclient.h5
-rw-r--r--webclients/index.vnc10
12 files changed, 516 insertions, 48 deletions
diff --git a/client_examples/SDLvncviewer.c b/client_examples/SDLvncviewer.c
index 4cf22f5..8fe6f57 100644
--- a/client_examples/SDLvncviewer.c
+++ b/client_examples/SDLvncviewer.c
@@ -524,6 +524,7 @@ int main(int argc,char** argv) {
cl->HandleTextChat=text_chat;
cl->GotXCutText = got_selection;
cl->listenPort = LISTEN_PORT_OFFSET;
+ cl->listen6Port = LISTEN_PORT_OFFSET;
if(!rfbInitClient(cl,&argc,argv))
{
cl = NULL; /* rfbInitClient has already freed the client struct */
diff --git a/libvncclient/listen.c b/libvncclient/listen.c
index 2e9fafb..c91ad6e 100644
--- a/libvncclient/listen.c
+++ b/libvncclient/listen.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2011-2012 Christian Beier <dontmind@freeshell.org>
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
@@ -50,7 +51,7 @@ listenForIncomingConnections(rfbClient* client)
rfbClientErr("listenForIncomingConnections on MinGW32 NOT IMPLEMENTED\n");
return;
#else
- int listenSocket;
+ int listenSocket, listen6Socket = -1;
fd_set fds;
client->listenSpecified = TRUE;
@@ -65,8 +66,24 @@ listenForIncomingConnections(rfbClient* client)
rfbClientLog("%s -listen: Command line errors are not reported until "
"a connection comes in.\n", client->programName);
- while (TRUE) {
+#ifdef LIBVNCSERVER_IPv6 /* only try that if we're IPv6-capable, otherwise we may try to bind to the same port which would make all that listening fail */
+ /* only do IPv6 listen of listen6Port is set */
+ if (client->listen6Port > 0)
+ {
+ listen6Socket = ListenAtTcpPortAndAddress(client->listen6Port, client->listen6Address);
+
+ if (listen6Socket < 0)
+ return;
+
+ rfbClientLog("%s -listen: Listening on IPV6 port %d\n",
+ client->programName,client->listenPort);
+ rfbClientLog("%s -listen: Command line errors are not reported until "
+ "a connection comes in.\n", client->programName);
+ }
+#endif
+ while (TRUE) {
+ int r;
/* reap any zombies */
int status, pid;
while ((pid= wait3(&status, WNOHANG, (struct rusage *)0))>0);
@@ -75,12 +92,19 @@ listenForIncomingConnections(rfbClient* client)
FD_ZERO(&fds);
- FD_SET(listenSocket, &fds);
+ if(listenSocket >= 0)
+ FD_SET(listenSocket, &fds);
+ if(listen6Socket >= 0)
+ FD_SET(listen6Socket, &fds);
+
+ r = select(max(listenSocket, listen6Socket)+1, &fds, NULL, NULL, NULL);
- select(listenSocket+1, &fds, NULL, NULL, NULL);
+ if (r > 0) {
+ if (FD_ISSET(listenSocket, &fds))
+ client->sock = AcceptTcpConnection(client->listenSock);
+ else if (FD_ISSET(listen6Socket, &fds))
+ client->sock = AcceptTcpConnection(client->listen6Sock);
- if (FD_ISSET(listenSocket, &fds)) {
- client->sock = AcceptTcpConnection(listenSocket);
if (client->sock < 0)
return;
if (!SetNonBlocking(client->sock))
@@ -97,6 +121,7 @@ listenForIncomingConnections(rfbClient* client)
case 0:
/* child - return to caller */
close(listenSocket);
+ close(listen6Socket);
return;
default:
@@ -144,24 +169,54 @@ listenForIncomingConnectionsNoFork(rfbClient* client, int timeout)
"a connection comes in.\n", client->programName);
}
+#ifdef LIBVNCSERVER_IPv6 /* only try that if we're IPv6-capable, otherwise we may try to bind to the same port which would make all that listening fail */
+ /* only do IPv6 listen of listen6Port is set */
+ if (client->listen6Port > 0 && client->listen6Sock < 0)
+ {
+ client->listen6Sock = ListenAtTcpPortAndAddress(client->listen6Port, client->listen6Address);
+
+ if (client->listen6Sock < 0)
+ return -1;
+
+ rfbClientLog("%s -listennofork: Listening on IPV6 port %d\n",
+ client->programName,client->listenPort);
+ rfbClientLog("%s -listennofork: Command line errors are not reported until "
+ "a connection comes in.\n", client->programName);
+ }
+#endif
+
FD_ZERO(&fds);
- FD_SET(client->listenSock, &fds);
+ if(client->listenSock >= 0)
+ FD_SET(client->listenSock, &fds);
+ if(client->listen6Sock >= 0)
+ FD_SET(client->listen6Sock, &fds);
if (timeout < 0)
- r = select(client->listenSock+1, &fds, NULL, NULL, NULL);
+ r = select(max(client->listenSock, client->listen6Sock) +1, &fds, NULL, NULL, NULL);
else
- r = select(client->listenSock+1, &fds, NULL, NULL, &to);
+ r = select(max(client->listenSock, client->listen6Sock) +1, &fds, NULL, NULL, &to);
if (r > 0)
{
- client->sock = AcceptTcpConnection(client->listenSock);
+ if (FD_ISSET(client->listenSock, &fds))
+ client->sock = AcceptTcpConnection(client->listenSock);
+ else if (FD_ISSET(client->listen6Sock, &fds))
+ client->sock = AcceptTcpConnection(client->listen6Sock);
+
if (client->sock < 0)
return -1;
if (!SetNonBlocking(client->sock))
return -1;
- close(client->listenSock);
+ if(client->listenSock >= 0) {
+ close(client->listenSock);
+ client->listenSock = -1;
+ }
+ if(client->listen6Sock >= 0) {
+ close(client->listen6Sock);
+ client->listen6Sock = -1;
+ }
return r;
}
diff --git a/libvncclient/sockets.c b/libvncclient/sockets.c
index be9924a..1a8df56 100644
--- a/libvncclient/sockets.c
+++ b/libvncclient/sockets.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2011-2012 Christian Beier <dontmind@freeshell.org>
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
@@ -494,8 +495,9 @@ int
ListenAtTcpPortAndAddress(int port, const char *address)
{
int sock;
- struct sockaddr_in addr;
int one = 1;
+#ifndef LIBVNCSERVER_IPv6
+ struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
@@ -527,6 +529,66 @@ ListenAtTcpPortAndAddress(int port, const char *address)
return -1;
}
+#else
+ 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_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE; /* fill in wildcard address if address == NULL */
+
+ if (!initSockets())
+ return -1;
+
+ if ((rv = getaddrinfo(address, port_str, &hints, &servinfo)) != 0) {
+ rfbClientErr("ListenAtTcpPortAndAddress: 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 (p->ai_family == AF_INET6 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) < 0) {
+ rfbClientErr("ListenAtTcpPortAndAddress: error in setsockopt IPV6_V6ONLY: %s\n", strerror(errno));
+ close(sock);
+ freeaddrinfo(servinfo);
+ return -1;
+ }
+#endif
+
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) {
+ rfbClientErr("ListenAtTcpPortAndAddress: error in setsockopt SO_REUSEADDR: %s\n", strerror(errno));
+ close(sock);
+ freeaddrinfo(servinfo);
+ return -1;
+ }
+
+ if (bind(sock, p->ai_addr, p->ai_addrlen) < 0) {
+ close(sock);
+ continue;
+ }
+
+ break;
+ }
+
+ if (p == NULL) {
+ rfbClientErr("ListenAtTcpPortAndAddress: error in bind: %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* all done with this structure now */
+ freeaddrinfo(servinfo);
+#endif
+
if (listen(sock, 5) < 0) {
rfbClientErr("ListenAtTcpPort: listen\n");
close(sock);
diff --git a/libvncclient/vncviewer.c b/libvncclient/vncviewer.c
index 10b430f..6a4f006 100644
--- a/libvncclient/vncviewer.c
+++ b/libvncclient/vncviewer.c
@@ -197,6 +197,8 @@ rfbClient* rfbGetClient(int bitsPerSample,int samplesPerPixel,
client->sock = -1;
client->listenSock = -1;
client->listenAddress = NULL;
+ client->listen6Sock = -1;
+ client->listen6Address = NULL;
client->clientAuthSchemes = NULL;
return client;
}
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;
}
diff --git a/rfb/rfb.h b/rfb/rfb.h
index e068e76..bf4e011 100644
--- a/rfb/rfb.h
+++ b/rfb/rfb.h
@@ -377,6 +377,14 @@ typedef struct _rfbScreenInfo
char *sslkeyfile;
char *sslcertfile;
#endif
+ int ipv6port; /**< The port to listen on when using IPv6. */
+ char* listen6Interface;
+ /* We have an additional IPv6 listen socket since there are systems that
+ don't support dual binding sockets under *any* circumstances, for
+ instance OpenBSD */
+ SOCKET listen6Sock;
+ int http6Port;
+ SOCKET httpListen6Sock;
} rfbScreenInfo, *rfbScreenInfoPtr;
@@ -738,6 +746,7 @@ extern int rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec);
extern int rfbConnect(rfbScreenInfoPtr rfbScreen, char* host, int port);
extern int rfbConnectToTcpAddr(char* host, int port);
extern int rfbListenOnTCPPort(int port, in_addr_t iface);
+extern int rfbListenOnTCP6Port(int port, const char* iface);
extern int rfbListenOnUDPPort(int port, in_addr_t iface);
extern int rfbStringToAddr(char* string,in_addr_t* addr);
extern rfbBool rfbSetNonBlocking(int sock);
diff --git a/rfb/rfbclient.h b/rfb/rfbclient.h
index 36ffe13..36c109e 100644
--- a/rfb/rfbclient.h
+++ b/rfb/rfbclient.h
@@ -347,7 +347,10 @@ typedef struct _rfbClient {
FinishedFrameBufferUpdateProc FinishedFrameBufferUpdate;
char *listenAddress;
-
+ /* IPv6 listen socket, address and port*/
+ int listen6Sock;
+ char* listen6Address;
+ int listen6Port;
} rfbClient;
/* cursor.c */
diff --git a/webclients/index.vnc b/webclients/index.vnc
index 8254a70..0a92bd4 100644
--- a/webclients/index.vnc
+++ b/webclients/index.vnc
@@ -22,7 +22,15 @@ If the above Java applet does not work, you can also try the new JavaScript-only
<script language="JavaScript">
<!--
function start_novnc(){
- open("novnc/vnc_auto.html?host=" + document.location.hostname + "&port=$PORT&true_color=1");
+ var host = document.location.hostname;
+ // If there are at least two colons in there, it is likely an IPv6 address. Check for square brackets and add them if missing.
+ if(host.search(/^.*:.*:.*$/) != -1) {
+ if(host.charAt(0) != "[")
+ host = "[" + host;
+ if(host.charAt(host.length-1) != "]")
+ host = host + "]";
+ }
+ open("novnc/vnc_auto.html?host=" + host + "&port=$PORT&true_color=1");
}
-->
</script>