You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
230 lines
6.3 KiB
230 lines
6.3 KiB
/* |
|
* 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 |
|
* it under the terms of the GNU General Public License as published by |
|
* the Free Software Foundation; either version 2 of the License, or |
|
* (at your option) any later version. |
|
* |
|
* This software is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with this software; if not, write to the Free Software |
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
|
* USA. |
|
*/ |
|
|
|
/* |
|
* listen.c - listen for incoming connections |
|
*/ |
|
|
|
#ifdef __STRICT_ANSI__ |
|
#define _BSD_SOURCE |
|
#endif |
|
#if LIBVNCSERVER_HAVE_UNISTD_H |
|
#include <unistd.h> |
|
#endif |
|
#include <sys/types.h> |
|
#ifdef WIN32 |
|
#define close closesocket |
|
#include <winsock2.h> |
|
#else // #ifdef WIN32 |
|
#include <sys/wait.h> |
|
#include <sys/utsname.h> |
|
#endif |
|
#if LIBVNCSERVER_HAVE_SYS_TIME_H |
|
#include <sys/time.h> |
|
#endif |
|
#include <rfb/rfbclient.h> |
|
|
|
/* |
|
* listenForIncomingConnections() - listen for incoming connections from |
|
* servers, and fork a new process to deal with each connection. |
|
*/ |
|
|
|
void |
|
listenForIncomingConnections(rfbClient* client) |
|
{ |
|
#ifdef WIN32 |
|
/* FIXME */ |
|
rfbClientErr("listenForIncomingConnections on MinGW32 NOT IMPLEMENTED\n"); |
|
return; |
|
#else |
|
int listenSocket, listen6Socket = -1; |
|
fd_set fds; |
|
|
|
client->listenSpecified = TRUE; |
|
|
|
listenSocket = ListenAtTcpPortAndAddress(client->listenPort, client->listenAddress); |
|
|
|
if ((listenSocket < 0)) |
|
return; |
|
|
|
rfbClientLog("%s -listen: Listening on port %d\n", |
|
client->programName,client->listenPort); |
|
rfbClientLog("%s -listen: Command line errors are not reported until " |
|
"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) |
|
{ |
|
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= wait4(-1, &status, WNOHANG, (struct rusage *)0))>0); |
|
|
|
/* TODO: callback for discard any events (like X11 events) */ |
|
|
|
FD_ZERO(&fds); |
|
|
|
if(listenSocket >= 0) |
|
FD_SET(listenSocket, &fds); |
|
if(listen6Socket >= 0) |
|
FD_SET(listen6Socket, &fds); |
|
|
|
r = select(rfbMax(listenSocket, listen6Socket)+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 (client->sock < 0) |
|
return; |
|
if (!SetNonBlocking(client->sock)) |
|
return; |
|
|
|
/* Now fork off a new process to deal with it... */ |
|
|
|
switch (fork()) { |
|
|
|
case -1: |
|
rfbClientErr("fork\n"); |
|
return; |
|
|
|
case 0: |
|
/* child - return to caller */ |
|
close(listenSocket); |
|
close(listen6Socket); |
|
return; |
|
|
|
default: |
|
/* parent - go round and listen again */ |
|
close(client->sock); |
|
break; |
|
} |
|
} |
|
} |
|
#endif |
|
} |
|
|
|
|
|
|
|
/* |
|
* listenForIncomingConnectionsNoFork() - listen for incoming connections |
|
* from servers, but DON'T fork, instead just wait timeout microseconds. |
|
* If timeout is negative, block indefinitely. |
|
* Returns 1 on success (there was an incoming connection on the listen socket |
|
* and we accepted it successfully), -1 on error, 0 on timeout. |
|
*/ |
|
|
|
int |
|
listenForIncomingConnectionsNoFork(rfbClient* client, int timeout) |
|
{ |
|
fd_set fds; |
|
struct timeval to; |
|
int r; |
|
|
|
to.tv_sec= timeout / 1000000; |
|
to.tv_usec= timeout % 1000000; |
|
|
|
client->listenSpecified = TRUE; |
|
|
|
if (client->listenSock < 0) |
|
{ |
|
client->listenSock = ListenAtTcpPortAndAddress(client->listenPort, client->listenAddress); |
|
|
|
if (client->listenSock < 0) |
|
return -1; |
|
|
|
rfbClientLog("%s -listennofork: Listening on port %d\n", |
|
client->programName,client->listenPort); |
|
rfbClientLog("%s -listennofork: Command line errors are not reported until " |
|
"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); |
|
|
|
if(client->listenSock >= 0) |
|
FD_SET(client->listenSock, &fds); |
|
if(client->listen6Sock >= 0) |
|
FD_SET(client->listen6Sock, &fds); |
|
|
|
if (timeout < 0) |
|
r = select(rfbMax(client->listenSock, client->listen6Sock) +1, &fds, NULL, NULL, NULL); |
|
else |
|
r = select(rfbMax(client->listenSock, client->listen6Sock) +1, &fds, NULL, NULL, &to); |
|
|
|
if (r > 0) |
|
{ |
|
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; |
|
|
|
if(client->listenSock >= 0) { |
|
close(client->listenSock); |
|
client->listenSock = -1; |
|
} |
|
if(client->listen6Sock >= 0) { |
|
close(client->listen6Sock); |
|
client->listen6Sock = -1; |
|
} |
|
return r; |
|
} |
|
|
|
/* r is now either 0 (timeout) or -1 (error) */ |
|
return r; |
|
} |
|
|
|
|
|
|