It is easier to control object life time and avoid magical socket duplication by having a single TcpListener object to pass around. We have to be more careful about deleting the object though.tags/v1.5.90
@@ -118,23 +118,6 @@ static void initSockets() { | |||
} | |||
// -=- Socket duplication help for Windows | |||
static int dupsocket(int fd) | |||
{ | |||
#ifdef WIN32 | |||
int ret; | |||
WSAPROTOCOL_INFO info; | |||
ret = WSADuplicateSocket(fd, GetCurrentProcessId(), &info); | |||
if (ret != 0) | |||
throw SocketException("unable to duplicate socket", errorNumber); | |||
return WSASocket(info.iAddressFamily, info.iSocketType, info.iProtocol, | |||
&info, 0, 0); | |||
#else | |||
return dup(fd); | |||
#endif | |||
} | |||
// -=- TcpSocket | |||
TcpSocket::TcpSocket(int sock, bool close) | |||
@@ -411,23 +394,6 @@ TcpListener::TcpListener(int sock) | |||
fd = sock; | |||
} | |||
TcpListener::TcpListener(const TcpListener& other) | |||
{ | |||
fd = dupsocket (other.fd); | |||
// Hope TcpListener::shutdown(other) doesn't get called... | |||
} | |||
TcpListener& TcpListener::operator= (const TcpListener& other) | |||
{ | |||
if (this != &other) | |||
{ | |||
closesocket (fd); | |||
fd = dupsocket (other.fd); | |||
// Hope TcpListener::shutdown(other) doesn't get called... | |||
} | |||
return *this; | |||
} | |||
TcpListener::TcpListener(const struct sockaddr *listenaddr, | |||
socklen_t listenaddrlen) | |||
{ | |||
@@ -570,57 +536,41 @@ int TcpListener::getMyPort() { | |||
} | |||
void network::createLocalTcpListeners(std::list<TcpListener> *listeners, | |||
void network::createLocalTcpListeners(std::list<TcpListener*> *listeners, | |||
int port) | |||
{ | |||
std::list<TcpListener> new_listeners; | |||
vnc_sockaddr_t sa; | |||
struct addrinfo ai[2]; | |||
vnc_sockaddr_t sa[2]; | |||
initSockets(); | |||
memset(ai, 0, sizeof(ai)); | |||
memset(sa, 0, sizeof(sa)); | |||
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; | |||
} | |||
} | |||
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; | |||
} | |||
} | |||
sa[0].u.sin.sin_family = AF_INET; | |||
sa[0].u.sin.sin_port = htons (port); | |||
sa[0].u.sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | |||
if (new_listeners.empty ()) | |||
throw SocketException("createLocalTcpListeners: no addresses available", | |||
EADDRNOTAVAIL); | |||
ai[0].ai_family = sa[0].u.sin.sin_family; | |||
ai[0].ai_addr = &sa[0].u.sa; | |||
ai[0].ai_addrlen = sizeof(sa[0].u.sin); | |||
ai[0].ai_next = &ai[1]; | |||
listeners->splice (listeners->end(), new_listeners); | |||
sa[1].u.sin6.sin6_family = AF_INET6; | |||
sa[1].u.sin6.sin6_port = htons (port); | |||
sa[1].u.sin6.sin6_addr = in6addr_loopback; | |||
ai[1].ai_family = sa[1].u.sin6.sin6_family; | |||
ai[1].ai_addr = &sa[1].u.sa; | |||
ai[1].ai_addrlen = sizeof(sa[1].u.sin6); | |||
ai[1].ai_next = NULL; | |||
createTcpListeners(listeners, ai); | |||
} | |||
void network::createTcpListeners(std::list<TcpListener> *listeners, | |||
void network::createTcpListeners(std::list<TcpListener*> *listeners, | |||
const char *addr, | |||
int port) | |||
{ | |||
std::list<TcpListener> new_listeners; | |||
struct addrinfo *ai, *current, hints; | |||
struct addrinfo *ai, hints; | |||
char service[16]; | |||
int result; | |||
@@ -640,6 +590,22 @@ void network::createTcpListeners(std::list<TcpListener> *listeners, | |||
throw rdr::Exception("unable to resolve listening address: %s", | |||
gai_strerror(result)); | |||
try { | |||
createTcpListeners(listeners, ai); | |||
} catch(...) { | |||
freeaddrinfo(ai); | |||
throw; | |||
} | |||
} | |||
void network::createTcpListeners(std::list<TcpListener*> *listeners, | |||
const struct addrinfo *ai) | |||
{ | |||
const struct addrinfo *current; | |||
std::list<TcpListener*> new_listeners; | |||
initSockets(); | |||
for (current = ai; current != NULL; current = current->ai_next) { | |||
switch (current->ai_family) { | |||
case AF_INET: | |||
@@ -657,19 +623,21 @@ void network::createTcpListeners(std::list<TcpListener> *listeners, | |||
} | |||
try { | |||
new_listeners.push_back(TcpListener (current->ai_addr, | |||
current->ai_addrlen)); | |||
new_listeners.push_back(new 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); | |||
while (!new_listeners.empty()) { | |||
delete new_listeners.back(); | |||
new_listeners.pop_back(); | |||
} | |||
throw; | |||
} | |||
} | |||
} | |||
freeaddrinfo(ai); | |||
if (new_listeners.empty ()) | |||
throw SocketException("createTcpListeners: no addresses available", |
@@ -76,8 +76,6 @@ namespace network { | |||
public: | |||
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(); | |||
@@ -87,11 +85,13 @@ namespace network { | |||
int getMyPort(); | |||
}; | |||
void createLocalTcpListeners(std::list<TcpListener> *listeners, | |||
void createLocalTcpListeners(std::list<TcpListener*> *listeners, | |||
int port); | |||
void createTcpListeners(std::list<TcpListener> *listeners, | |||
void createTcpListeners(std::list<TcpListener*> *listeners, | |||
const char *addr, | |||
int port); | |||
void createTcpListeners(std::list<TcpListener*> *listeners, | |||
const struct addrinfo *ai); | |||
typedef struct vnc_sockaddr { | |||
union { |
@@ -477,7 +477,7 @@ int main(int argc, char** argv) | |||
signal(SIGINT, CleanupSignalHandler); | |||
signal(SIGTERM, CleanupSignalHandler); | |||
std::list<TcpListener> listeners; | |||
std::list<TcpListener*> listeners; | |||
try { | |||
TXWindow::init(dpy,"x0vncserver"); | |||
@@ -499,10 +499,10 @@ int main(int argc, char** argv) | |||
const char *hostsData = hostsFile.getData(); | |||
FileTcpFilter fileTcpFilter(hostsData); | |||
if (strlen(hostsData) != 0) | |||
for (std::list<TcpListener>::iterator i = listeners.begin(); | |||
for (std::list<TcpListener*>::iterator i = listeners.begin(); | |||
i != listeners.end(); | |||
i++) | |||
(*i).setFilter(&fileTcpFilter); | |||
(*i)->setFilter(&fileTcpFilter); | |||
delete[] hostsData; | |||
PollingScheduler sched((int)pollingCycle, (int)maxProcessorUsage); | |||
@@ -518,10 +518,10 @@ int main(int argc, char** argv) | |||
FD_ZERO(&rfds); | |||
FD_SET(ConnectionNumber(dpy), &rfds); | |||
for (std::list<TcpListener>::iterator i = listeners.begin(); | |||
for (std::list<TcpListener*>::iterator i = listeners.begin(); | |||
i != listeners.end(); | |||
i++) | |||
FD_SET((*i).getFd(), &rfds); | |||
FD_SET((*i)->getFd(), &rfds); | |||
server.getSockets(&sockets); | |||
int clients_connected = 0; | |||
@@ -567,11 +567,11 @@ int main(int argc, char** argv) | |||
} | |||
// Accept new VNC connections | |||
for (std::list<TcpListener>::iterator i = listeners.begin(); | |||
for (std::list<TcpListener*>::iterator i = listeners.begin(); | |||
i != listeners.end(); | |||
i++) { | |||
if (FD_ISSET((*i).getFd(), &rfds)) { | |||
Socket* sock = (*i).accept(); | |||
if (FD_ISSET((*i)->getFd(), &rfds)) { | |||
Socket* sock = (*i)->accept(); | |||
if (sock) { | |||
server.addSocket(sock); | |||
} else { |
@@ -190,9 +190,12 @@ int vncIsTCPPortUsed(int port) | |||
{ | |||
try { | |||
// Attempt to create TCPListeners on that port. | |||
// They go out of scope immediately and are destroyed. | |||
std::list<network::TcpListener> dummy; | |||
std::list<network::TcpListener*> dummy; | |||
network::createTcpListeners (&dummy, 0, port); | |||
while (!dummy.empty()) { | |||
delete dummy.back(); | |||
dummy.pop_back(); | |||
} | |||
} catch (rdr::Exception& e) { | |||
return 1; | |||
} |
@@ -91,8 +91,8 @@ public: | |||
XserverDesktop::XserverDesktop(int screenIndex_, | |||
std::list<network::TcpListener> listeners_, | |||
std::list<network::TcpListener> httpListeners_, | |||
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) | |||
@@ -114,6 +114,14 @@ XserverDesktop::XserverDesktop(int screenIndex_, | |||
XserverDesktop::~XserverDesktop() | |||
{ | |||
while (!listeners.empty()) { | |||
delete listeners.back(); | |||
listeners.pop_back(); | |||
} | |||
while (!httpListeners.empty()) { | |||
delete httpListeners.back(); | |||
httpListeners.pop_back(); | |||
} | |||
if (!directFbptr) | |||
delete [] data; | |||
delete httpServer; | |||
@@ -222,7 +230,7 @@ char* XserverDesktop::substitute(const char* varName) | |||
} | |||
if (strcmp(varName, "$PORT") == 0) { | |||
char* str = new char[10]; | |||
sprintf(str, "%d", listeners.empty () ? 0 : (*listeners.begin ()).getMyPort()); | |||
sprintf(str, "%d", listeners.empty () ? 0 : (*listeners.begin ())->getMyPort()); | |||
return str; | |||
} | |||
if (strcmp(varName, "$WIDTH") == 0) { | |||
@@ -393,14 +401,14 @@ void XserverDesktop::readBlockHandler(fd_set* fds, struct timeval ** timeout) | |||
// Add all sockets we want read events for, after purging | |||
// any closed sockets. | |||
for (std::list<network::TcpListener>::iterator i = listeners.begin(); | |||
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(); | |||
FD_SET((*i)->getFd(), fds); | |||
for (std::list<network::TcpListener*>::iterator i = httpListeners.begin(); | |||
i != httpListeners.end(); | |||
i++) | |||
FD_SET((*i).getFd(), fds); | |||
FD_SET((*i)->getFd(), fds); | |||
std::list<Socket*> sockets; | |||
std::list<Socket*>::iterator i; | |||
@@ -456,24 +464,24 @@ void XserverDesktop::readWakeupHandler(fd_set* fds, int nfds) | |||
// First check for file descriptors with something to do | |||
if (nfds >= 1) { | |||
for (std::list<network::TcpListener>::iterator i = listeners.begin(); | |||
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(); | |||
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()); | |||
} | |||
} | |||
for (std::list<network::TcpListener>::iterator i = httpListeners.begin(); | |||
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(); | |||
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()); |
@@ -51,8 +51,8 @@ class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer, | |||
public: | |||
XserverDesktop(int screenIndex, | |||
std::list<network::TcpListener> listeners_, | |||
std::list<network::TcpListener> httpListeners_, | |||
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(); | |||
@@ -113,8 +113,8 @@ private: | |||
int screenIndex; | |||
rfb::VNCServerST* server; | |||
rfb::HTTPServer* httpServer; | |||
std::list<network::TcpListener> listeners; | |||
std::list<network::TcpListener> httpListeners; | |||
std::list<network::TcpListener*> listeners; | |||
std::list<network::TcpListener*> httpListeners; | |||
bool deferredUpdateTimerSet; | |||
bool directFbptr; | |||
struct timeval dixTimeout; |
@@ -134,13 +134,13 @@ void vncExtensionInit(void) | |||
for (int scr = 0; scr < vncGetScreenCount(); scr++) { | |||
if (!desktop[scr]) { | |||
std::list<network::TcpListener> listeners; | |||
std::list<network::TcpListener> httpListeners; | |||
std::list<network::TcpListener*> listeners; | |||
std::list<network::TcpListener*> httpListeners; | |||
if (scr == 0 && vncInetdSock != -1) { | |||
if (network::TcpSocket::isSocket(vncInetdSock) && | |||
!network::TcpSocket::isConnected(vncInetdSock)) | |||
{ | |||
listeners.push_back (network::TcpListener(vncInetdSock)); | |||
listeners.push_back(new network::TcpListener(vncInetdSock)); | |||
vlog.info("inetd wait"); | |||
} | |||
} else { |
@@ -525,7 +525,7 @@ int main(int argc, char** argv) | |||
#endif | |||
if (listenMode) { | |||
std::list<TcpListener> listeners; | |||
std::list<TcpListener*> listeners; | |||
try { | |||
int port = 5500; | |||
if (isdigit(vncServerName[0])) | |||
@@ -539,10 +539,10 @@ int main(int argc, char** argv) | |||
while (sock == NULL) { | |||
fd_set rfds; | |||
FD_ZERO(&rfds); | |||
for (std::list<TcpListener>::iterator i = listeners.begin(); | |||
for (std::list<TcpListener*>::iterator i = listeners.begin(); | |||
i != listeners.end(); | |||
i++) | |||
FD_SET((*i).getFd(), &rfds); | |||
FD_SET((*i)->getFd(), &rfds); | |||
int n = select(FD_SETSIZE, &rfds, 0, 0, 0); | |||
if (n < 0) { | |||
@@ -554,11 +554,11 @@ int main(int argc, char** argv) | |||
} | |||
} | |||
for (std::list<TcpListener>::iterator i = listeners.begin (); | |||
for (std::list<TcpListener*>::iterator i = listeners.begin (); | |||
i != listeners.end(); | |||
i++) | |||
if (FD_ISSET((*i).getFd(), &rfds)) { | |||
sock = (*i).accept(); | |||
if (FD_ISSET((*i)->getFd(), &rfds)) { | |||
sock = (*i)->accept(); | |||
if (sock) | |||
/* Got a connection */ | |||
break; | |||
@@ -571,6 +571,10 @@ int main(int argc, char** argv) | |||
return 1; | |||
} | |||
while (!listeners.empty()) { | |||
delete listeners.back(); | |||
listeners.pop_back(); | |||
} | |||
} else { | |||
if (vncServerName[0] == '\0') { | |||
ServerDialog::run(defaultServerName, vncServerName); |
@@ -31,9 +31,9 @@ ManagedListener::ManagedListener(SocketManager* mgr) | |||
ManagedListener::~ManagedListener() { | |||
if (!sockets.empty()) { | |||
std::list<network::TcpListener>::iterator iter; | |||
std::list<network::TcpListener*>::iterator iter; | |||
for (iter = sockets.begin(); iter != sockets.end(); ++iter) | |||
manager->remListener(&*iter); | |||
manager->remListener(*iter); | |||
sockets.clear(); | |||
} | |||
delete filter; | |||
@@ -62,9 +62,9 @@ void ManagedListener::setFilter(const char* filterStr) { | |||
delete filter; | |||
filter = new network::TcpFilter(filterStr); | |||
if (!sockets.empty() && !localOnly) { | |||
std::list<network::TcpListener>::iterator iter; | |||
std::list<network::TcpListener*>::iterator iter; | |||
for (iter = sockets.begin(); iter != sockets.end(); ++iter) | |||
iter->setFilter(filter); | |||
(*iter)->setFilter(filter); | |||
} | |||
} | |||
@@ -80,10 +80,10 @@ bool ManagedListener::isListening() { | |||
} | |||
void ManagedListener::refresh() { | |||
std::list<network::TcpListener>::iterator iter; | |||
std::list<network::TcpListener*>::iterator iter; | |||
if (!sockets.empty()) { | |||
for (iter = sockets.begin(); iter != sockets.end(); ++iter) | |||
manager->remListener(&*iter); | |||
manager->remListener(*iter); | |||
sockets.clear(); | |||
} | |||
if (!server) | |||
@@ -101,11 +101,11 @@ void ManagedListener::refresh() { | |||
if (!sockets.empty()) { | |||
if (!localOnly) { | |||
for (iter = sockets.begin(); iter != sockets.end(); ++iter) | |||
iter->setFilter(filter); | |||
(*iter)->setFilter(filter); | |||
} | |||
try { | |||
for (iter = sockets.begin(); iter != sockets.end(); ++iter) | |||
manager->addListener(&*iter, server, addrChangeNotifier); | |||
manager->addListener(*iter, server, addrChangeNotifier); | |||
} catch (...) { | |||
// FIXME: Should unwind what we've added | |||
sockets.clear(); |
@@ -45,7 +45,7 @@ namespace winvnc { | |||
protected: | |||
void refresh(); | |||
std::list<network::TcpListener> sockets; | |||
std::list<network::TcpListener*> sockets; | |||
network::TcpFilter* filter; | |||
rfb::win32::SocketManager* manager; | |||
rfb::win32::SocketManager::AddressChangeNotifier* addrChangeNotifier; |