summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Beier <dontmind@freeshell.org>2012-03-10 21:31:44 +0100
committerChristian Beier <dontmind@freeshell.org>2012-03-10 21:31:44 +0100
commit75bfb1f5d396b2908a9615cd02bebfc952baa045 (patch)
tree9f775fdd6b00f83cdaf7f0fc45601b825fd6521d
parentedc75fa4f4f0dbadf7cb21a7511626dd35a3c330 (diff)
downloadlibtdevnc-75bfb1f5.tar.gz
libtdevnc-75bfb1f5.zip
IPv6 support for LibVNCServer, part three: make reverse connections IPv6-capable.
Besided making libvncserver reverseVNC IPv6-aware, this introduces some changes on the client side as well to make clients listen on IPv6 sockets, too. Like the server side, this also uses a separate-socket approach.
-rw-r--r--client_examples/SDLvncviewer.c1
-rw-r--r--libvncclient/listen.c76
-rw-r--r--libvncclient/sockets.c63
-rw-r--r--libvncclient/vncviewer.c2
-rw-r--r--libvncserver/sockets.c42
-rw-r--r--rfb/rfbclient.h5
6 files changed, 174 insertions, 15 deletions
diff --git a/client_examples/SDLvncviewer.c b/client_examples/SDLvncviewer.c
index 5fa8f2c..c817941 100644
--- a/client_examples/SDLvncviewer.c
+++ b/client_examples/SDLvncviewer.c
@@ -518,6 +518,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..9e8fe99 100644
--- a/libvncclient/listen.c
+++ b/libvncclient/listen.c
@@ -50,7 +50,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 +65,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 +91,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 +120,7 @@ listenForIncomingConnections(rfbClient* client)
case 0:
/* child - return to caller */
close(listenSocket);
+ close(listen6Socket);
return;
default:
@@ -144,24 +168,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..01ec3a2 100644
--- a/libvncclient/sockets.c
+++ b/libvncclient/sockets.c
@@ -494,8 +494,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 +528,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/sockets.c b/libvncserver/sockets.c
index 723e769..1727eb0 100644
--- a/libvncserver/sockets.c
+++ b/libvncserver/sockets.c
@@ -937,8 +937,46 @@ 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));
@@ -962,7 +1000,7 @@ rfbConnectToTcpAddr(char *host,
closesocket(sock);
return -1;
}
-
+#endif
return 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 */