• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (C) 2011-2012 Christian Beier <dontmind@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
listenForIncomingConnections(rfbClient * client)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
listenForIncomingConnectionsNoFork(rfbClient * client,int timeout)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