The TcpListener constructor now takes a 'struct sockaddr*' instead of a string, and the createTcpListeners function creates TcpListener instances for an address based on the results from getaddrinfo(). The XserverDesktop class now takes a list of TcpListener instances for each of the RFB and HTTP sockets. The TcpListener::closeFd member variable is not used and has been removed.tags/v1.4.90
@@ -34,7 +34,6 @@ | |||
#include <netinet/in.h> | |||
#include <netinet/tcp.h> | |||
#include <netdb.h> | |||
#include <unistd.h> | |||
#include <errno.h> | |||
#include <string.h> | |||
#include <signal.h> | |||
@@ -42,6 +41,7 @@ | |||
#endif | |||
#include <stdlib.h> | |||
#include <unistd.h> | |||
#include <network/TcpSocket.h> | |||
#include <rfb/util.h> | |||
#include <rfb/LogWriter.h> | |||
@@ -274,16 +274,17 @@ char* TcpSocket::getPeerAddress() { | |||
return rfb::strDup(""); | |||
} | |||
#if defined(HAVE_GETADDRINFO) && defined(HAVE_INET_PTON) | |||
#if defined(HAVE_GETADDRINFO) | |||
if (sa.u.sa.sa_family == AF_INET6) { | |||
char buffer[INET6_ADDRSTRLEN + 2]; | |||
const char *name; | |||
int ret; | |||
buffer[0] = '['; | |||
name = inet_ntop(sa.u.sa.sa_family, &sa.u.sin6.sin6_addr, | |||
buffer + 1, sizeof(buffer) - 2); | |||
if (name == NULL) { | |||
ret = getnameinfo(&sa.u.sa, sizeof(sa.u.sin6), | |||
buffer + 1, sizeof(buffer) - 2, NULL, 0, | |||
NI_NUMERICHOST); | |||
if (ret != 0) { | |||
vlog.error("unable to convert peer name to a string"); | |||
return rfb::strDup(""); | |||
} | |||
@@ -426,139 +427,77 @@ int TcpSocket::getSockPort(int sock) | |||
} | |||
} | |||
static int bindIPv6 (const char *listenaddr, | |||
int port, | |||
bool localhostOnly) | |||
TcpListener::TcpListener(int sock) | |||
{ | |||
#ifdef HAVE_GETADDRINFO | |||
struct sockaddr_in6 addr6; | |||
socklen_t sa_len; | |||
int fd; | |||
if (!UseIPv6) | |||
return -1; | |||
if ((fd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) | |||
return -1; | |||
#ifdef IPV6_V6ONLY | |||
// - We made an IPv6-capable socket, and we need it to do IPv4 too | |||
int opt = 0; | |||
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&opt, sizeof(opt)); | |||
#else | |||
vlog.error("IPV6_V6ONLY support is missing. " | |||
"IPv4 clients may not be able to connect."); | |||
#endif | |||
fd = sock; | |||
} | |||
memset(&addr6, 0, (sa_len = sizeof(addr6))); | |||
addr6.sin6_family = AF_INET6; | |||
addr6.sin6_port = htons(port); | |||
if (localhostOnly) | |||
addr6.sin6_addr = in6addr_loopback; | |||
else if (listenaddr != NULL) { | |||
#ifdef HAVE_INET_PTON | |||
if (inet_pton(AF_INET6, listenaddr, &addr6.sin6_addr) != 1) { | |||
closesocket(fd); | |||
return -1; | |||
} | |||
#else | |||
// Unable to parse without inet_pton | |||
closesocket(fd); | |||
return -1; | |||
#endif | |||
} | |||
TcpListener::TcpListener(const TcpListener& other) | |||
{ | |||
fd = dup (other.fd); | |||
// Hope TcpListener::shutdown(other) doesn't get called... | |||
} | |||
if (bind(fd, (struct sockaddr *) &addr6, sa_len) == -1) { | |||
closesocket(fd); | |||
return -1; | |||
TcpListener& TcpListener::operator= (const TcpListener& other) | |||
{ | |||
if (this != &other) | |||
{ | |||
closesocket (fd); | |||
fd = dup (other.fd); | |||
// Hope TcpListener::shutdown(other) doesn't get called... | |||
} | |||
return fd; | |||
#else | |||
return -1; | |||
#endif /* HAVE_GETADDRINFO */ | |||
return *this; | |||
} | |||
static int bindIPv4 (const char *listenaddr, | |||
int port, | |||
bool localhostOnly) | |||
TcpListener::TcpListener(const struct sockaddr *listenaddr, | |||
socklen_t listenaddrlen) | |||
{ | |||
struct sockaddr_in addr; | |||
socklen_t sa_len; | |||
int fd; | |||
if (!UseIPv4) | |||
return -1; | |||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) | |||
return -1; | |||
int one = 1; | |||
vnc_sockaddr_t sa; | |||
int sock; | |||
memset(&addr, 0, (sa_len = sizeof(addr))); | |||
addr.sin_family = AF_INET; | |||
addr.sin_port = htons(port); | |||
initSockets(); | |||
if (localhostOnly) | |||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | |||
else if (listenaddr != NULL) { | |||
#ifdef HAVE_INET_ATON | |||
if (inet_aton(listenaddr, &addr.sin_addr) == 0) | |||
#else | |||
/* Some systems (e.g. Windows) do not have inet_aton, sigh */ | |||
if ((addr.sin_addr.s_addr = inet_addr(listenaddr)) == INADDR_NONE) | |||
#endif | |||
{ | |||
closesocket(fd); | |||
throw Exception("invalid network interface address: %s", listenaddr); | |||
} | |||
} else | |||
/* Bind to 0.0.0.0 by default. */ | |||
addr.sin_addr.s_addr = htonl(INADDR_ANY); | |||
if ((sock = socket (listenaddr->sa_family, SOCK_STREAM, 0)) < 0) | |||
throw SocketException("unable to create listening socket", errorNumber); | |||
if (bind(fd, (struct sockaddr *) &addr, sa_len) == -1) { | |||
closesocket(fd); | |||
return -1; | |||
memcpy (&sa, listenaddr, listenaddrlen); | |||
#ifdef IPV6_V6ONLY | |||
if (listenaddr->sa_family == AF_INET6) { | |||
if (setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&one, sizeof(one))) | |||
throw SocketException("unable to set IPV6_V6ONLY", errorNumber); | |||
} | |||
#endif /* defined(IPV6_V6ONLY) */ | |||
return fd; | |||
} | |||
TcpListener::TcpListener(const char *listenaddr, int port, bool localhostOnly, | |||
int sock, bool close_) : closeFd(close_) | |||
{ | |||
if (sock != -1) { | |||
fd = sock; | |||
return; | |||
if (bind(sock, &sa.u.sa, listenaddrlen) == -1) { | |||
closesocket(sock); | |||
throw SocketException("failed to bind socket", errorNumber); | |||
} | |||
initSockets(); | |||
if ((fd = bindIPv6 (listenaddr, port, localhostOnly)) < 0) | |||
if ((fd = bindIPv4 (listenaddr, port, localhostOnly)) < 0) | |||
throw SocketException("unable to create listening socket", errorNumber); | |||
#ifndef WIN32 | |||
// - By default, close the socket on exec() | |||
fcntl(fd, F_SETFD, FD_CLOEXEC); | |||
fcntl(sock, F_SETFD, FD_CLOEXEC); | |||
int one = 1; | |||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, | |||
(char *)&one, sizeof(one)) < 0) { | |||
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, | |||
(char *)&one, sizeof(one)) < 0) { | |||
int e = errorNumber; | |||
closesocket(fd); | |||
closesocket(sock); | |||
throw SocketException("unable to create listening socket", e); | |||
} | |||
#endif | |||
// - Set it to be a listening socket | |||
if (listen(fd, 5) < 0) { | |||
if (listen(sock, 5) < 0) { | |||
int e = errorNumber; | |||
closesocket(fd); | |||
closesocket(sock); | |||
throw SocketException("unable to set socket to listening mode", e); | |||
} | |||
fd = sock; | |||
} | |||
TcpListener::~TcpListener() { | |||
if (closeFd) closesocket(fd); | |||
closesocket(fd); | |||
} | |||
void TcpListener::shutdown() | |||
@@ -596,46 +535,160 @@ TcpListener::accept() { | |||
return s; | |||
} | |||
void TcpListener::getMyAddresses(std::list<char*>* result) { | |||
#if defined(HAVE_GETADDRINFO) && defined(HAVE_INET_PTON) | |||
int TcpListener::getMyPort() { | |||
return TcpSocket::getSockPort(getFd()); | |||
} | |||
void network::createLocalTcpListeners(std::list<TcpListener> *listeners, | |||
int port) | |||
{ | |||
std::list<TcpListener> new_listeners; | |||
vnc_sockaddr_t sa; | |||
#ifdef HAVE_GETADDRINFO | |||
if (UseIPv6) { | |||
sa.u.sin6.sin6_family = AF_INET6; | |||
sa.u.sin6.sin6_port = htons (port); | |||
sa.u.sin6.sin6_addr = in6addr_loopback; | |||
try { | |||
new_listeners.push_back (TcpListener (&sa.u.sa, sizeof (sa.u.sin6))); | |||
} catch (SocketException& e) { | |||
// Ignore this if it is due to lack of address family support on | |||
// the interface or on the system | |||
if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) | |||
// Otherwise, report the error | |||
throw; | |||
} | |||
} | |||
#endif /* HAVE_GETADDRINFO */ | |||
if (UseIPv4) { | |||
sa.u.sin.sin_family = AF_INET; | |||
sa.u.sin.sin_port = htons (port); | |||
sa.u.sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | |||
try { | |||
new_listeners.push_back (TcpListener (&sa.u.sa, sizeof (sa.u.sin))); | |||
} catch (SocketException& e) { | |||
// Ignore this if it is due to lack of address family support on | |||
// the interface or on the system | |||
if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) | |||
// Otherwise, report the error | |||
throw; | |||
} | |||
} | |||
if (new_listeners.empty ()) | |||
throw SocketException("createLocalTcpListeners: no addresses available", | |||
EADDRNOTAVAIL); | |||
listeners->splice (listeners->end(), new_listeners); | |||
} | |||
void network::createTcpListeners(std::list<TcpListener> *listeners, | |||
const char *addr, | |||
int port) | |||
{ | |||
std::list<TcpListener> new_listeners; | |||
#ifdef HAVE_GETADDRINFO | |||
struct addrinfo *ai, *current, hints; | |||
char service[16]; | |||
memset(&hints, 0, sizeof(struct addrinfo)); | |||
hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV; | |||
hints.ai_family = AF_UNSPEC; | |||
hints.ai_socktype = SOCK_STREAM; | |||
hints.ai_canonname = NULL; | |||
hints.ai_addr = NULL; | |||
hints.ai_next = NULL; | |||
if ((getaddrinfo(NULL, NULL, &hints, &ai)) != 0) | |||
return; | |||
snprintf (service, sizeof (service) - 1, "%d", port); | |||
service[sizeof (service) - 1] = '\0'; | |||
if ((getaddrinfo(addr, service, &hints, &ai)) != 0) | |||
throw rdr::SystemException("getaddrinfo", errorNumber); | |||
for (current= ai; current != NULL; current = current->ai_next) { | |||
if (current->ai_family != AF_INET && current->ai_family != AF_INET6) | |||
for (current = ai; current != NULL; current = current->ai_next) { | |||
switch (current->ai_family) { | |||
case AF_INET: | |||
if (!UseIPv4) | |||
continue; | |||
break; | |||
case AF_INET6: | |||
if (!UseIPv6) | |||
continue; | |||
break; | |||
default: | |||
continue; | |||
} | |||
char *addr = new char[INET6_ADDRSTRLEN]; | |||
inet_ntop(current->ai_family, current->ai_addr, addr, INET6_ADDRSTRLEN); | |||
result->push_back(addr); | |||
try { | |||
new_listeners.push_back(TcpListener (current->ai_addr, | |||
current->ai_addrlen)); | |||
} catch (SocketException& e) { | |||
// Ignore this if it is due to lack of address family support on | |||
// the interface or on the system | |||
if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) { | |||
// Otherwise, report the error | |||
freeaddrinfo(ai); | |||
throw; | |||
} | |||
} | |||
} | |||
freeaddrinfo(ai); | |||
#else | |||
const hostent* addrs = gethostbyname(0); | |||
if (addrs == 0) | |||
throw rdr::SystemException("gethostbyname", errorNumber); | |||
if (addrs->h_addrtype != AF_INET) | |||
throw rdr::Exception("getMyAddresses: bad family"); | |||
for (int i=0; addrs->h_addr_list[i] != 0; i++) { | |||
const char* addrC = inet_ntoa(*((struct in_addr*)addrs->h_addr_list[i])); | |||
char* addr = new char[strlen(addrC)+1]; | |||
strcpy(addr, addrC); | |||
result->push_back(addr); | |||
const hostent* addrs; | |||
if (addr) { | |||
/* Bind to specific address */ | |||
addrs = gethostbyname(addr); | |||
if (addrs == 0) | |||
throw rdr::SystemException("gethostbyname", errorNumber); | |||
if (addrs->h_addrtype != AF_INET) | |||
throw rdr::Exception("createTcpListeners: bad family"); | |||
for (int i=0; addrs->h_addr_list[i] != 0; i++) { | |||
struct sockaddr_in addr; | |||
addr.sin_family = AF_INET; | |||
memcpy (&addr.sin_addr, addrs->h_addr_list[i], addrs->h_length); | |||
addr.sin_port = htons(port); | |||
try { | |||
new_listeners.push_back(TcpListener ((struct sockaddr*)&addr, | |||
addrs->h_length)); | |||
} catch (SocketException& e) { | |||
// Ignore this if it is due to lack of address family support | |||
// on the interface or on the system | |||
if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) { | |||
// Otherwise, report the error | |||
freeaddrinfo(ai); | |||
throw; | |||
} | |||
} | |||
} | |||
} else { | |||
/* Bind to any address */ | |||
struct sockaddr_in addr; | |||
addr.sin_family = AF_INET; | |||
addr.sin_addr.s_addr = htonl(INADDR_ANY); | |||
addr.sin_port = htons(port); | |||
try { | |||
new_listeners.push_back(TcpListener ((struct sockaddr*)&addr, | |||
sizeof (struct sockaddr_in))); | |||
} catch (SocketException& e) { | |||
// Ignore this if it is due to lack of address family support on | |||
// the interface or on the system | |||
if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) { | |||
// Otherwise, report the error | |||
freeaddrinfo(ai); | |||
throw; | |||
} | |||
} | |||
} | |||
#endif /* defined(HAVE_GETADDRINFO) && defined(HAVE_INET_PTON) */ | |||
} | |||
#endif /* defined(HAVE_GETADDRINFO) */ | |||
int TcpListener::getMyPort() { | |||
return TcpSocket::getSockPort(getFd()); | |||
if (new_listeners.empty ()) | |||
throw SocketException("createTcpListeners: no addresses available", | |||
EADDRNOTAVAIL); | |||
listeners->splice (listeners->end(), new_listeners); | |||
} | |||
@@ -29,6 +29,7 @@ | |||
#define __NETWORK_TCP_SOCKET_H__ | |||
#include <network/Socket.h> | |||
#include <sys/socket.h> | |||
#include <list> | |||
@@ -66,20 +67,24 @@ namespace network { | |||
class TcpListener : public SocketListener { | |||
public: | |||
TcpListener(const char *listenaddr, int port, bool localhostOnly=false, | |||
int sock=-1, bool close=true); | |||
TcpListener(const struct sockaddr *listenaddr, socklen_t listenaddrlen); | |||
TcpListener(int sock); | |||
TcpListener(const TcpListener& other); | |||
TcpListener& operator= (const TcpListener& other); | |||
virtual ~TcpListener(); | |||
virtual void shutdown(); | |||
virtual Socket* accept(); | |||
void getMyAddresses(std::list<char*>* addrs); | |||
int getMyPort(); | |||
private: | |||
bool closeFd; | |||
}; | |||
void createLocalTcpListeners(std::list<TcpListener> *listeners, | |||
int port); | |||
void createTcpListeners(std::list<TcpListener> *listeners, | |||
const char *addr, | |||
int port); | |||
class TcpFilter : public ConnectionFilter { | |||
public: | |||
TcpFilter(const char* filter); |
@@ -477,6 +477,8 @@ int main(int argc, char** argv) | |||
signal(SIGINT, CleanupSignalHandler); | |||
signal(SIGTERM, CleanupSignalHandler); | |||
std::list<TcpListener> listeners; | |||
try { | |||
TXWindow::init(dpy,"x0vncserver"); | |||
Geometry geo(DisplayWidth(dpy, DefaultScreen(dpy)), | |||
@@ -491,13 +493,16 @@ int main(int argc, char** argv) | |||
QueryConnHandler qcHandler(dpy, &server); | |||
server.setQueryConnectionHandler(&qcHandler); | |||
TcpListener listener(NULL, (int)rfbport); | |||
createTcpListeners(&listeners, 0, (int)rfbport); | |||
vlog.info("Listening on port %d", (int)rfbport); | |||
const char *hostsData = hostsFile.getData(); | |||
FileTcpFilter fileTcpFilter(hostsData); | |||
if (strlen(hostsData) != 0) | |||
listener.setFilter(&fileTcpFilter); | |||
for (std::list<TcpListener>::iterator i = listeners.begin(); | |||
i != listeners.end(); | |||
i++) | |||
(*i).setFilter(&fileTcpFilter); | |||
delete[] hostsData; | |||
PollingScheduler sched((int)pollingCycle, (int)maxProcessorUsage); | |||
@@ -513,7 +518,11 @@ int main(int argc, char** argv) | |||
FD_ZERO(&rfds); | |||
FD_SET(ConnectionNumber(dpy), &rfds); | |||
FD_SET(listener.getFd(), &rfds); | |||
for (std::list<TcpListener>::iterator i = listeners.begin(); | |||
i != listeners.end(); | |||
i++) | |||
FD_SET((*i).getFd(), &rfds); | |||
server.getSockets(&sockets); | |||
int clients_connected = 0; | |||
for (i = sockets.begin(); i != sockets.end(); i++) { | |||
@@ -558,12 +567,16 @@ int main(int argc, char** argv) | |||
} | |||
// Accept new VNC connections | |||
if (FD_ISSET(listener.getFd(), &rfds)) { | |||
Socket* sock = listener.accept(); | |||
if (sock) { | |||
server.addSocket(sock); | |||
} else { | |||
vlog.status("Client connection rejected"); | |||
for (std::list<TcpListener>::iterator i = listeners.begin(); | |||
i != listeners.end(); | |||
i++) { | |||
if (FD_ISSET((*i).getFd(), &rfds)) { | |||
Socket* sock = (*i).accept(); | |||
if (sock) { | |||
server.addSocket(sock); | |||
} else { | |||
vlog.status("Client connection rejected"); | |||
} | |||
} | |||
} | |||
@@ -187,7 +187,10 @@ int vncGetSocketPort(int fd) | |||
int vncIsTCPPortUsed(int port) | |||
{ | |||
try { | |||
network::TcpListener l(NULL, port); | |||
// Attempt to create TCPListeners on that port. | |||
// They go out of scope immediately and are destroyed. | |||
std::list<network::TcpListener> dummy; | |||
network::createTcpListeners (&dummy, 0, port); | |||
} catch (rdr::Exception& e) { | |||
return 0; | |||
} |
@@ -91,14 +91,14 @@ public: | |||
XserverDesktop::XserverDesktop(int screenIndex_, | |||
network::TcpListener* listener_, | |||
network::TcpListener* httpListener_, | |||
std::list<network::TcpListener> listeners_, | |||
std::list<network::TcpListener> httpListeners_, | |||
const char* name, const rfb::PixelFormat &pf, | |||
int width, int height, | |||
void* fbptr, int stride) | |||
: screenIndex(screenIndex_), | |||
server(0), httpServer(0), | |||
listener(listener_), httpListener(httpListener_), | |||
listeners(listeners_), httpListeners(httpListeners_), | |||
deferredUpdateTimerSet(false), directFbptr(true), | |||
queryConnectId(0) | |||
{ | |||
@@ -108,7 +108,7 @@ XserverDesktop::XserverDesktop(int screenIndex_, | |||
setFramebuffer(width, height, fbptr, stride); | |||
server->setQueryConnectionHandler(this); | |||
if (httpListener) | |||
if (!httpListeners.empty ()) | |||
httpServer = new FileHTTPServer(this); | |||
} | |||
@@ -222,7 +222,7 @@ char* XserverDesktop::substitute(const char* varName) | |||
} | |||
if (strcmp(varName, "$PORT") == 0) { | |||
char* str = new char[10]; | |||
sprintf(str, "%d", listener ? listener->getMyPort() : 0); | |||
sprintf(str, "%d", listeners.empty () ? 0 : (*listeners.begin ()).getMyPort()); | |||
return str; | |||
} | |||
if (strcmp(varName, "$WIDTH") == 0) { | |||
@@ -393,14 +393,18 @@ void XserverDesktop::readBlockHandler(fd_set* fds, struct timeval ** timeout) | |||
// Add all sockets we want read events for, after purging | |||
// any closed sockets. | |||
if (listener) | |||
FD_SET(listener->getFd(), fds); | |||
if (httpListener) | |||
FD_SET(httpListener->getFd(), fds); | |||
for (std::list<network::TcpListener>::iterator i = listeners.begin(); | |||
i != listeners.end(); | |||
i++) | |||
FD_SET((*i).getFd(), fds); | |||
for (std::list<network::TcpListener>::iterator i = httpListeners.begin(); | |||
i != httpListeners.end(); | |||
i++) | |||
FD_SET((*i).getFd(), fds); | |||
std::list<Socket*> sockets; | |||
server->getSockets(&sockets); | |||
std::list<Socket*>::iterator i; | |||
server->getSockets(&sockets); | |||
for (i = sockets.begin(); i != sockets.end(); i++) { | |||
int fd = (*i)->getFd(); | |||
if ((*i)->isShutdown()) { | |||
@@ -452,20 +456,24 @@ void XserverDesktop::readWakeupHandler(fd_set* fds, int nfds) | |||
// First check for file descriptors with something to do | |||
if (nfds >= 1) { | |||
if (listener) { | |||
if (FD_ISSET(listener->getFd(), fds)) { | |||
FD_CLR(listener->getFd(), fds); | |||
Socket* sock = listener->accept(); | |||
for (std::list<network::TcpListener>::iterator i = listeners.begin(); | |||
i != listeners.end(); | |||
i++) { | |||
if (FD_ISSET((*i).getFd(), fds)) { | |||
FD_CLR((*i).getFd(), fds); | |||
Socket* sock = (*i).accept(); | |||
sock->outStream().setBlocking(false); | |||
server->addSocket(sock); | |||
vlog.debug("new client, sock %d",sock->getFd()); | |||
} | |||
} | |||
if (httpListener) { | |||
if (FD_ISSET(httpListener->getFd(), fds)) { | |||
FD_CLR(httpListener->getFd(), fds); | |||
Socket* sock = httpListener->accept(); | |||
for (std::list<network::TcpListener>::iterator i = httpListeners.begin(); | |||
i != httpListeners.end(); | |||
i++) { | |||
if (FD_ISSET((*i).getFd(), fds)) { | |||
FD_CLR((*i).getFd(), fds); | |||
Socket* sock = (*i).accept(); | |||
sock->outStream().setBlocking(false); | |||
httpServer->addSocket(sock); | |||
vlog.debug("new http client, sock %d",sock->getFd()); |
@@ -50,8 +50,9 @@ class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer, | |||
public rfb::VNCServerST::QueryConnectionHandler { | |||
public: | |||
XserverDesktop(int screenIndex, network::TcpListener* listener, | |||
network::TcpListener* httpListener_, | |||
XserverDesktop(int screenIndex, | |||
std::list<network::TcpListener> listeners_, | |||
std::list<network::TcpListener> httpListeners_, | |||
const char* name, const rfb::PixelFormat &pf, | |||
int width, int height, void* fbptr, int stride); | |||
virtual ~XserverDesktop(); | |||
@@ -112,8 +113,8 @@ private: | |||
int screenIndex; | |||
rfb::VNCServerST* server; | |||
rfb::HTTPServer* httpServer; | |||
network::TcpListener* listener; | |||
network::TcpListener* httpListener; | |||
std::list<network::TcpListener> listeners; | |||
std::list<network::TcpListener> httpListeners; | |||
bool deferredUpdateTimerSet; | |||
bool directFbptr; | |||
struct timeval dixTimeout; |
@@ -134,33 +134,44 @@ void vncExtensionInit(void) | |||
for (int scr = 0; scr < vncGetScreenCount(); scr++) { | |||
if (!desktop[scr]) { | |||
network::TcpListener* listener = 0; | |||
network::TcpListener* httpListener = 0; | |||
std::list<network::TcpListener> listeners; | |||
std::list<network::TcpListener> httpListeners; | |||
if (scr == 0 && vncInetdSock != -1) { | |||
if (network::TcpSocket::isSocket(vncInetdSock) && | |||
!network::TcpSocket::isConnected(vncInetdSock)) | |||
{ | |||
listener = new network::TcpListener(NULL, 0, 0, vncInetdSock, true); | |||
listeners.push_back (network::TcpListener(vncInetdSock)); | |||
vlog.info("inetd wait"); | |||
} | |||
} else { | |||
const char *addr = interface; | |||
int port = rfbport; | |||
if (port == 0) port = 5900 + atoi(vncGetDisplay()); | |||
port += 1000 * scr; | |||
if (strcasecmp(interface, "all") == 0) | |||
listener = new network::TcpListener(NULL, port, localhostOnly); | |||
if (strcasecmp(addr, "all") == 0) | |||
addr = 0; | |||
if (localhostOnly) | |||
network::createLocalTcpListeners(&listeners, port); | |||
else | |||
listener = new network::TcpListener(interface, port, localhostOnly); | |||
network::createTcpListeners(&listeners, addr, port); | |||
vlog.info("Listening for VNC connections on %s interface(s), port %d", | |||
(const char*)interface, port); | |||
localhostOnly ? "local" : (const char*)interface, | |||
port); | |||
CharArray httpDirStr(httpDir.getData()); | |||
if (httpDirStr.buf[0]) { | |||
port = httpPort; | |||
if (port == 0) port = 5800 + atoi(vncGetDisplay()); | |||
port += 1000 * scr; | |||
httpListener = new network::TcpListener(interface, port, localhostOnly); | |||
if (localhostOnly) | |||
network::createLocalTcpListeners(&httpListeners, port); | |||
else | |||
network::createTcpListeners(&httpListeners, addr, port); | |||
vlog.info("Listening for HTTP connections on %s interface(s), port %d", | |||
(const char*)interface, port); | |||
localhostOnly ? "local" : (const char*)interface, | |||
port); | |||
} | |||
} | |||
@@ -168,8 +179,8 @@ void vncExtensionInit(void) | |||
PixelFormat pf = vncGetPixelFormat(scr); | |||
desktop[scr] = new XserverDesktop(scr, | |||
listener, | |||
httpListener, | |||
listeners, | |||
httpListeners, | |||
desktopNameStr.buf, | |||
pf, | |||
vncGetScreenWidth(scr), | |||
@@ -178,7 +189,7 @@ void vncExtensionInit(void) | |||
vncFbstride[scr]); | |||
vlog.info("created VNC server for screen %d", scr); | |||
if (scr == 0 && vncInetdSock != -1 && !listener) { | |||
if (scr == 0 && vncInetdSock != -1 && listeners.empty()) { | |||
network::Socket* sock = new network::TcpSocket(vncInetdSock); | |||
desktop[scr]->addClient(sock, false); | |||
vlog.info("added inetd sock"); |
@@ -534,15 +534,45 @@ int main(int argc, char** argv) | |||
#endif | |||
if (listenMode) { | |||
std::list<TcpListener> listeners; | |||
try { | |||
int port = 5500; | |||
if (isdigit(vncServerName[0])) | |||
port = atoi(vncServerName); | |||
TcpListener listener(NULL, port); | |||
createTcpListeners(&listeners, 0, port); | |||
vlog.info(_("Listening on port %d\n"), port); | |||
sock = listener.accept(); | |||
/* Wait for a connection */ | |||
while (sock == NULL) { | |||
fd_set rfds; | |||
FD_ZERO(&rfds); | |||
for (std::list<TcpListener>::iterator i = listeners.begin(); | |||
i != listeners.end(); | |||
i++) | |||
FD_SET((*i).getFd(), &rfds); | |||
int n = select(FD_SETSIZE, &rfds, 0, 0, 0); | |||
if (n < 0) { | |||
if (errno == EINTR) { | |||
vlog.debug("Interrupted select() system call"); | |||
continue; | |||
} else { | |||
throw rdr::SystemException("select", errno); | |||
} | |||
} | |||
for (std::list<TcpListener>::iterator i = listeners.begin (); | |||
i != listeners.end(); | |||
i++) | |||
if (FD_ISSET((*i).getFd(), &rfds)) { | |||
sock = (*i).accept(); | |||
if (sock) | |||
/* Got a connection */ | |||
break; | |||
} | |||
} | |||
} catch (rdr::Exception& e) { | |||
vlog.error("%s", e.str()); | |||
fl_alert("%s", e.str()); |