Commit 75bfb1f5 authored by Christian Beier's avatar Christian Beier

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.
parent edc75fa4
......@@ -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 */
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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 */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment