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.
pull/1/head
Christian Beier 12 years ago
parent edc75fa4f4
commit 75bfb1f5d3

@ -518,6 +518,7 @@ int main(int argc,char** argv) {
cl->HandleTextChat=text_chat; cl->HandleTextChat=text_chat;
cl->GotXCutText = got_selection; cl->GotXCutText = got_selection;
cl->listenPort = LISTEN_PORT_OFFSET; cl->listenPort = LISTEN_PORT_OFFSET;
cl->listen6Port = LISTEN_PORT_OFFSET;
if(!rfbInitClient(cl,&argc,argv)) if(!rfbInitClient(cl,&argc,argv))
{ {
cl = NULL; /* rfbInitClient has already freed the client struct */ cl = NULL; /* rfbInitClient has already freed the client struct */

@ -50,7 +50,7 @@ listenForIncomingConnections(rfbClient* client)
rfbClientErr("listenForIncomingConnections on MinGW32 NOT IMPLEMENTED\n"); rfbClientErr("listenForIncomingConnections on MinGW32 NOT IMPLEMENTED\n");
return; return;
#else #else
int listenSocket; int listenSocket, listen6Socket = -1;
fd_set fds; fd_set fds;
client->listenSpecified = TRUE; client->listenSpecified = TRUE;
@ -65,8 +65,24 @@ listenForIncomingConnections(rfbClient* client)
rfbClientLog("%s -listen: Command line errors are not reported until " rfbClientLog("%s -listen: Command line errors are not reported until "
"a connection comes in.\n", client->programName); "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 */ /* reap any zombies */
int status, pid; int status, pid;
while ((pid= wait3(&status, WNOHANG, (struct rusage *)0))>0); while ((pid= wait3(&status, WNOHANG, (struct rusage *)0))>0);
@ -75,12 +91,19 @@ listenForIncomingConnections(rfbClient* client)
FD_ZERO(&fds); 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) if (client->sock < 0)
return; return;
if (!SetNonBlocking(client->sock)) if (!SetNonBlocking(client->sock))
@ -97,6 +120,7 @@ listenForIncomingConnections(rfbClient* client)
case 0: case 0:
/* child - return to caller */ /* child - return to caller */
close(listenSocket); close(listenSocket);
close(listen6Socket);
return; return;
default: default:
@ -144,24 +168,54 @@ listenForIncomingConnectionsNoFork(rfbClient* client, int timeout)
"a connection comes in.\n", client->programName); "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_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) 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 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) 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) if (client->sock < 0)
return -1; return -1;
if (!SetNonBlocking(client->sock)) if (!SetNonBlocking(client->sock))
return -1; 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; return r;
} }

@ -494,8 +494,9 @@ int
ListenAtTcpPortAndAddress(int port, const char *address) ListenAtTcpPortAndAddress(int port, const char *address)
{ {
int sock; int sock;
struct sockaddr_in addr;
int one = 1; int one = 1;
#ifndef LIBVNCSERVER_IPv6
struct sockaddr_in addr;
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_port = htons(port); addr.sin_port = htons(port);
@ -527,6 +528,66 @@ ListenAtTcpPortAndAddress(int port, const char *address)
return -1; 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) { if (listen(sock, 5) < 0) {
rfbClientErr("ListenAtTcpPort: listen\n"); rfbClientErr("ListenAtTcpPort: listen\n");
close(sock); close(sock);

@ -197,6 +197,8 @@ rfbClient* rfbGetClient(int bitsPerSample,int samplesPerPixel,
client->sock = -1; client->sock = -1;
client->listenSock = -1; client->listenSock = -1;
client->listenAddress = NULL; client->listenAddress = NULL;
client->listen6Sock = -1;
client->listen6Address = NULL;
client->clientAuthSchemes = NULL; client->clientAuthSchemes = NULL;
return client; return client;
} }

@ -937,8 +937,46 @@ int
rfbConnectToTcpAddr(char *host, rfbConnectToTcpAddr(char *host,
int port) int port)
{ {
struct hostent *hp;
int sock; 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; struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
@ -962,7 +1000,7 @@ rfbConnectToTcpAddr(char *host,
closesocket(sock); closesocket(sock);
return -1; return -1;
} }
#endif
return sock; return sock;
} }

@ -347,7 +347,10 @@ typedef struct _rfbClient {
FinishedFrameBufferUpdateProc FinishedFrameBufferUpdate; FinishedFrameBufferUpdateProc FinishedFrameBufferUpdate;
char *listenAddress; char *listenAddress;
/* IPv6 listen socket, address and port*/
int listen6Sock;
char* listen6Address;
int listen6Port;
} rfbClient; } rfbClient;
/* cursor.c */ /* cursor.c */

Loading…
Cancel
Save