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