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 __MINGW32__
31 #define close closesocket
32 #include <winsock2.h>
33 #undef max
34 #else
35 #include <sys/wait.h>
36 #include <sys/utsname.h>
37 #endif
38 #include <sys/time.h>
39 #include <rfb/rfbclient.h>
40
41 /*
42 * listenForIncomingConnections() - listen for incoming connections from
43 * servers, and fork a new process to deal with each connection.
44 */
45
46 void
listenForIncomingConnections(rfbClient * client)47 listenForIncomingConnections(rfbClient* client)
48 {
49 #ifdef __MINGW32__
50 /* FIXME */
51 rfbClientErr("listenForIncomingConnections on MinGW32 NOT IMPLEMENTED\n");
52 return;
53 #else
54 int listenSocket, listen6Socket = -1;
55 fd_set fds;
56
57 client->listenSpecified = TRUE;
58
59 listenSocket = ListenAtTcpPortAndAddress(client->listenPort, client->listenAddress);
60
61 if ((listenSocket < 0))
62 return;
63
64 rfbClientLog("%s -listen: Listening on port %d\n",
65 client->programName,client->listenPort);
66 rfbClientLog("%s -listen: Command line errors are not reported until "
67 "a connection comes in.\n", client->programName);
68
69 #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 */
70 /* only do IPv6 listen of listen6Port is set */
71 if (client->listen6Port > 0)
72 {
73 listen6Socket = ListenAtTcpPortAndAddress(client->listen6Port, client->listen6Address);
74
75 if (listen6Socket < 0)
76 return;
77
78 rfbClientLog("%s -listen: Listening on IPV6 port %d\n",
79 client->programName,client->listenPort);
80 rfbClientLog("%s -listen: Command line errors are not reported until "
81 "a connection comes in.\n", client->programName);
82 }
83 #endif
84
85 while (TRUE) {
86 int r;
87 /* reap any zombies */
88 int status, pid;
89 while ((pid= wait3(&status, WNOHANG, (struct rusage *)0))>0);
90
91 /* TODO: callback for discard any events (like X11 events) */
92
93 FD_ZERO(&fds);
94
95 if(listenSocket >= 0)
96 FD_SET(listenSocket, &fds);
97 if(listen6Socket >= 0)
98 FD_SET(listen6Socket, &fds);
99
100 r = select(max(listenSocket, listen6Socket)+1, &fds, NULL, NULL, NULL);
101
102 if (r > 0) {
103 if (FD_ISSET(listenSocket, &fds))
104 client->sock = AcceptTcpConnection(client->listenSock);
105 else if (FD_ISSET(listen6Socket, &fds))
106 client->sock = AcceptTcpConnection(client->listen6Sock);
107
108 if (client->sock < 0)
109 return;
110 if (!SetNonBlocking(client->sock))
111 return;
112
113 /* Now fork off a new process to deal with it... */
114
115 switch (fork()) {
116
117 case -1:
118 rfbClientErr("fork\n");
119 return;
120
121 case 0:
122 /* child - return to caller */
123 close(listenSocket);
124 close(listen6Socket);
125 return;
126
127 default:
128 /* parent - go round and listen again */
129 close(client->sock);
130 break;
131 }
132 }
133 }
134 #endif
135 }
136
137
138
139 /*
140 * listenForIncomingConnectionsNoFork() - listen for incoming connections
141 * from servers, but DON'T fork, instead just wait timeout microseconds.
142 * If timeout is negative, block indefinitly.
143 * Returns 1 on success (there was an incoming connection on the listen socket
144 * and we accepted it successfully), -1 on error, 0 on timeout.
145 */
146
147 int
listenForIncomingConnectionsNoFork(rfbClient * client,int timeout)148 listenForIncomingConnectionsNoFork(rfbClient* client, int timeout)
149 {
150 fd_set fds;
151 struct timeval to;
152 int r;
153
154 to.tv_sec= timeout / 1000000;
155 to.tv_usec= timeout % 1000000;
156
157 client->listenSpecified = TRUE;
158
159 if (client->listenSock < 0)
160 {
161 client->listenSock = ListenAtTcpPortAndAddress(client->listenPort, client->listenAddress);
162
163 if (client->listenSock < 0)
164 return -1;
165
166 rfbClientLog("%s -listennofork: Listening on port %d\n",
167 client->programName,client->listenPort);
168 rfbClientLog("%s -listennofork: Command line errors are not reported until "
169 "a connection comes in.\n", client->programName);
170 }
171
172 #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 */
173 /* only do IPv6 listen of listen6Port is set */
174 if (client->listen6Port > 0 && client->listen6Sock < 0)
175 {
176 client->listen6Sock = ListenAtTcpPortAndAddress(client->listen6Port, client->listen6Address);
177
178 if (client->listen6Sock < 0)
179 return -1;
180
181 rfbClientLog("%s -listennofork: Listening on IPV6 port %d\n",
182 client->programName,client->listenPort);
183 rfbClientLog("%s -listennofork: Command line errors are not reported until "
184 "a connection comes in.\n", client->programName);
185 }
186 #endif
187
188 FD_ZERO(&fds);
189
190 if(client->listenSock >= 0)
191 FD_SET(client->listenSock, &fds);
192 if(client->listen6Sock >= 0)
193 FD_SET(client->listen6Sock, &fds);
194
195 if (timeout < 0)
196 r = select(max(client->listenSock, client->listen6Sock) +1, &fds, NULL, NULL, NULL);
197 else
198 r = select(max(client->listenSock, client->listen6Sock) +1, &fds, NULL, NULL, &to);
199
200 if (r > 0)
201 {
202 if (FD_ISSET(client->listenSock, &fds))
203 client->sock = AcceptTcpConnection(client->listenSock);
204 else if (FD_ISSET(client->listen6Sock, &fds))
205 client->sock = AcceptTcpConnection(client->listen6Sock);
206
207 if (client->sock < 0)
208 return -1;
209 if (!SetNonBlocking(client->sock))
210 return -1;
211
212 if(client->listenSock >= 0) {
213 close(client->listenSock);
214 client->listenSock = -1;
215 }
216 if(client->listen6Sock >= 0) {
217 close(client->listen6Sock);
218 client->listen6Sock = -1;
219 }
220 return r;
221 }
222
223 /* r is now either 0 (timeout) or -1 (error) */
224 return r;
225 }
226
227
228