LibVNCServer/LibVNCClient
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
listen.c
Go to the documentation of this file.
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
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
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  {
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