Commit efcdab50 authored by Christian Beier's avatar Christian Beier

Merge branch 'server-ipv6'

parents ee459342 2d50fc84
......@@ -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 */
......
/*
* 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;
}
......
/*
* 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);
......
......@@ -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;
}
......
......@@ -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) {
......
......@@ -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 {
......
......@@ -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";
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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 */
......
......@@ -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>
......
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