Home | History | Annotate | Download | only in libvncclient
      1 /*
      2  *  Copyright (C) 2011-2012 Christian Beier <dontmind (at) freeshell.org>
      3  *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
      4  *
      5  *  This is free software; you can redistribute it and/or modify
      6  *  it under the terms of the GNU General Public License as published by
      7  *  the Free Software Foundation; either version 2 of the License, or
      8  *  (at your option) any later version.
      9  *
     10  *  This software is distributed in the hope that it will be useful,
     11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  *  GNU General Public License for more details.
     14  *
     15  *  You should have received a copy of the GNU General Public License
     16  *  along with this software; if not, write to the Free Software
     17  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
     18  *  USA.
     19  */
     20 
     21 /*
     22  * listen.c - listen for incoming connections
     23  */
     24 
     25 #ifdef __STRICT_ANSI__
     26 #define _BSD_SOURCE
     27 #endif
     28 #include <unistd.h>
     29 #include <sys/types.h>
     30 #ifdef WIN32
     31 #define close closesocket
     32 #include <winsock2.h>
     33 #ifdef _MINGW32
     34 #undef max
     35 #endif // #ifdef _MINGW32
     36 #else // #ifdef WIN32
     37 #include <sys/wait.h>
     38 #include <sys/utsname.h>
     39 #endif
     40 #include <sys/time.h>
     41 #include <rfb/rfbclient.h>
     42 
     43 /*
     44  * listenForIncomingConnections() - listen for incoming connections from
     45  * servers, and fork a new process to deal with each connection.
     46  */
     47 
     48 void
     49 listenForIncomingConnections(rfbClient* client)
     50 {
     51 #ifdef WIN32
     52   /* FIXME */
     53   rfbClientErr("listenForIncomingConnections on MinGW32 NOT IMPLEMENTED\n");
     54   return;
     55 #else
     56   int listenSocket, listen6Socket = -1;
     57   fd_set fds;
     58 
     59   client->listenSpecified = TRUE;
     60 
     61   listenSocket = ListenAtTcpPortAndAddress(client->listenPort, client->listenAddress);
     62 
     63   if ((listenSocket < 0))
     64     return;
     65 
     66   rfbClientLog("%s -listen: Listening on port %d\n",
     67 	  client->programName,client->listenPort);
     68   rfbClientLog("%s -listen: Command line errors are not reported until "
     69 	  "a connection comes in.\n", client->programName);
     70 
     71 #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 */
     72   /* only do IPv6 listen of listen6Port is set */
     73   if (client->listen6Port > 0)
     74     {
     75       listen6Socket = ListenAtTcpPortAndAddress(client->listen6Port, client->listen6Address);
     76 
     77       if (listen6Socket < 0)
     78 	return;
     79 
     80       rfbClientLog("%s -listen: Listening on IPV6 port %d\n",
     81 		   client->programName,client->listenPort);
     82       rfbClientLog("%s -listen: Command line errors are not reported until "
     83 		   "a connection comes in.\n", client->programName);
     84     }
     85 #endif
     86 
     87   while (TRUE) {
     88     int r;
     89     /* reap any zombies */
     90     int status, pid;
     91     while ((pid= wait3(&status, WNOHANG, (struct rusage *)0))>0);
     92 
     93     /* TODO: callback for discard any events (like X11 events) */
     94 
     95     FD_ZERO(&fds);
     96 
     97     if(listenSocket >= 0)
     98       FD_SET(listenSocket, &fds);
     99     if(listen6Socket >= 0)
    100       FD_SET(listen6Socket, &fds);
    101 
    102     r = select(max(listenSocket, listen6Socket)+1, &fds, NULL, NULL, NULL);
    103 
    104     if (r > 0) {
    105       if (FD_ISSET(listenSocket, &fds))
    106 	client->sock = AcceptTcpConnection(client->listenSock);
    107       else if (FD_ISSET(listen6Socket, &fds))
    108 	client->sock = AcceptTcpConnection(client->listen6Sock);
    109 
    110       if (client->sock < 0)
    111 	return;
    112       if (!SetNonBlocking(client->sock))
    113 	return;
    114 
    115       /* Now fork off a new process to deal with it... */
    116 
    117       switch (fork()) {
    118 
    119       case -1:
    120 	rfbClientErr("fork\n");
    121 	return;
    122 
    123       case 0:
    124 	/* child - return to caller */
    125 	close(listenSocket);
    126 	close(listen6Socket);
    127 	return;
    128 
    129       default:
    130 	/* parent - go round and listen again */
    131 	close(client->sock);
    132 	break;
    133       }
    134     }
    135   }
    136 #endif
    137 }
    138 
    139 
    140 
    141 /*
    142  * listenForIncomingConnectionsNoFork() - listen for incoming connections
    143  * from servers, but DON'T fork, instead just wait timeout microseconds.
    144  * If timeout is negative, block indefinitly.
    145  * Returns 1 on success (there was an incoming connection on the listen socket
    146  * and we accepted it successfully), -1 on error, 0 on timeout.
    147  */
    148 
    149 int
    150 listenForIncomingConnectionsNoFork(rfbClient* client, int timeout)
    151 {
    152   fd_set fds;
    153   struct timeval to;
    154   int r;
    155 
    156   to.tv_sec= timeout / 1000000;
    157   to.tv_usec= timeout % 1000000;
    158 
    159   client->listenSpecified = TRUE;
    160 
    161   if (client->listenSock < 0)
    162     {
    163       client->listenSock = ListenAtTcpPortAndAddress(client->listenPort, client->listenAddress);
    164 
    165       if (client->listenSock < 0)
    166 	return -1;
    167 
    168       rfbClientLog("%s -listennofork: Listening on port %d\n",
    169 		   client->programName,client->listenPort);
    170       rfbClientLog("%s -listennofork: Command line errors are not reported until "
    171 		   "a connection comes in.\n", client->programName);
    172     }
    173 
    174 #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 */
    175   /* only do IPv6 listen of listen6Port is set */
    176   if (client->listen6Port > 0 && client->listen6Sock < 0)
    177     {
    178       client->listen6Sock = ListenAtTcpPortAndAddress(client->listen6Port, client->listen6Address);
    179 
    180       if (client->listen6Sock < 0)
    181 	return -1;
    182 
    183       rfbClientLog("%s -listennofork: Listening on IPV6 port %d\n",
    184 		   client->programName,client->listenPort);
    185       rfbClientLog("%s -listennofork: Command line errors are not reported until "
    186 		   "a connection comes in.\n", client->programName);
    187     }
    188 #endif
    189 
    190   FD_ZERO(&fds);
    191 
    192   if(client->listenSock >= 0)
    193     FD_SET(client->listenSock, &fds);
    194   if(client->listen6Sock >= 0)
    195     FD_SET(client->listen6Sock, &fds);
    196 
    197   if (timeout < 0)
    198     r = select(max(client->listenSock, client->listen6Sock) +1, &fds, NULL, NULL, NULL);
    199   else
    200     r = select(max(client->listenSock, client->listen6Sock) +1, &fds, NULL, NULL, &to);
    201 
    202   if (r > 0)
    203     {
    204       if (FD_ISSET(client->listenSock, &fds))
    205 	client->sock = AcceptTcpConnection(client->listenSock);
    206       else if (FD_ISSET(client->listen6Sock, &fds))
    207 	client->sock = AcceptTcpConnection(client->listen6Sock);
    208 
    209       if (client->sock < 0)
    210 	return -1;
    211       if (!SetNonBlocking(client->sock))
    212 	return -1;
    213 
    214       if(client->listenSock >= 0) {
    215 	close(client->listenSock);
    216 	client->listenSock = -1;
    217       }
    218       if(client->listen6Sock >= 0) {
    219 	close(client->listen6Sock);
    220 	client->listen6Sock = -1;
    221       }
    222       return r;
    223     }
    224 
    225   /* r is now either 0 (timeout) or -1 (error) */
    226   return r;
    227 }
    228 
    229 
    230