Line data Source code
1 : // Copyright (c) 2012-2022 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/eventdispatcher
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 :
20 : /** \file
21 : * \brief Handle an AF_UNIX socket as a server.
22 : *
23 : * This class is used to listen on a stream oriented connection using an
24 : * AF_UNIX type of socket.
25 : */
26 :
27 : // self
28 : //
29 : #include "eventdispatcher/local_stream_server_connection.h"
30 :
31 : #include "eventdispatcher/exception.h"
32 : #include "eventdispatcher/local_stream_client_connection.h"
33 :
34 :
35 : // snaplogger lib
36 : //
37 : #include <snaplogger/message.h>
38 :
39 :
40 : // C lib
41 : //
42 : #include <fcntl.h>
43 : #include <sys/stat.h>
44 :
45 :
46 : // last include
47 : //
48 : #include <snapdev/poison.h>
49 :
50 :
51 :
52 : namespace ed
53 : {
54 :
55 :
56 :
57 : /** \brief Initialize the local stream server.
58 : *
59 : * The server constructor creates a socket, binds it, and then listen on it.
60 : *
61 : * \todo
62 : * Fix docs.
63 : *
64 : * By default the server accepts a maximum of \p max_connections (set to
65 : * 0 or less to get the default tcp_server::MAX_CONNECTIONS) in its waiting queue.
66 : * If you use the server and expect a low connection rate, you may want to
67 : * reduce the count to 5. Although some very busy servers use larger numbers.
68 : * This value gets clamped to a minimum of 5 and a maximum of 1,000.
69 : *
70 : * Note that the maximum number of connections is actually limited to
71 : * /proc/sys/net/core/somaxconn connections. This number is generally 128
72 : * in 2016. So the super high limit of 1,000 is anyway going to be ignored
73 : * by the OS.
74 : *
75 : * The Unix socket is made non-reusable by default. It is possible to mark
76 : * the server address as reusable by setting the \p force_reuse_addr to true.
77 : * If not true, then the fact that the file exists prevents a new server from
78 : * being created. When true, the function first checks whether it can connect
79 : * to a server. It a connection succeeds, then the creation of the server
80 : * fails (i.e. the Unix socket is already in use). If the connection fails,
81 : * the function makes sure to delete the file if it exists.
82 : *
83 : * By default the server is marked as "keepalive". You can turn it off
84 : * using the keepalive() function with false.
85 : *
86 : * \note
87 : * The code here handles the file based sockets by attempting to delete
88 : * the file if it already exists. If you create services that could end
89 : * up using the exact same socket name, then it could be an issue. If
90 : * not then the code will do exactly what you expects. That being said.
91 : * If you want to increase your chance of proper clean up of a Unix
92 : * socket file, you would have to create a parent process which deletes
93 : * the file whenever the child dies. Then it can either restart the child
94 : * (on a crash) or just quit.
95 : *
96 : * \exception runtime_error
97 : * This exception is raised if the socket cannot be created, bound to
98 : * the specified Unix address, or listen() fails on the socket.
99 : *
100 : * \param[in] address The Unix address to listen on.
101 : * \param[in] max_connections The number of connections to keep in the listen queue.
102 : * \param[in] force_reuse_addr Whether to allow the deletion of a file
103 : * before the bind() call.
104 : * \param[in] close_on_exec Whether to close the server & client sockets
105 : * on an execve().
106 : */
107 1 : local_stream_server_connection::local_stream_server_connection(
108 : addr::unix const & address
109 : , int max_connections
110 : , bool force_reuse_addr
111 1 : , bool close_on_exec)
112 : : f_address(address)
113 : , f_max_connections(max_connections)
114 1 : , f_close_on_exec(close_on_exec)
115 : {
116 1 : if(f_max_connections < 5)
117 : {
118 0 : f_max_connections = 5;
119 : }
120 1 : else if(f_max_connections > 1000)
121 : {
122 0 : f_max_connections = 1000;
123 : }
124 :
125 1 : sockaddr_un un;
126 1 : f_address.get_un(un);
127 2 : f_socket.reset(socket(
128 1 : un.sun_family
129 : , SOCK_STREAM | SOCK_NONBLOCK | (close_on_exec ? SOCK_CLOEXEC : 0)
130 : , 0));
131 1 : if(f_socket == nullptr)
132 : {
133 0 : int const e(errno);
134 0 : SNAP_LOG_ERROR
135 : << "socket() failed creating a socket descriptor (errno: "
136 0 : << std::to_string(e)
137 : << " -- "
138 0 : << strerror(e)
139 : << "); cannot listen on address \""
140 0 : << f_address.to_uri()
141 : << "\"."
142 : << SNAP_LOG_SEND;
143 0 : throw runtime_error("could not create socket for AF_UNIX server");
144 : }
145 :
146 1 : if(f_address.is_unnamed())
147 : {
148 : // for an unnamed socket, we do not bind at all the user is
149 : // responsible for knowing where to read and where to write
150 : //
151 0 : return;
152 : }
153 :
154 1 : int r(-1);
155 1 : if(f_address.is_file())
156 : {
157 : // a Unix file socket must create a new socket file to prove unicity
158 : // if the file already exists, even if it isn't used, the bind() call
159 : // will fail; if the file exists and the force_reuse_addr is true this
160 : // this function attempts to delete the file if it is a socket and we
161 : // can't connect to it (i.e. "lost file")
162 : //
163 1 : struct stat st = {};
164 1 : if(stat(un.sun_path, &st) == 0)
165 : {
166 0 : if(!S_ISSOCK(st.st_mode))
167 : {
168 0 : SNAP_LOG_ERROR
169 : << "file \""
170 : << un.sun_path
171 : << "\" is not a socket; cannot listen on address \""
172 0 : << f_address.to_uri()
173 : << "\"."
174 : << SNAP_LOG_SEND;
175 0 : throw runtime_error("file already exists and it is not a socket, can't create an AF_UNIX server");
176 : }
177 :
178 0 : bool available(false);
179 0 : if(force_reuse_addr)
180 : {
181 0 : SNAP_LOG_WARNING
182 : << "attempting a contection to "
183 0 : << f_address.to_uri()
184 : << " as a client to see that the address is available for this server;"
185 : << " on success this generates an expected fatal error which we catch here."
186 : << SNAP_LOG_SEND;
187 : try
188 : {
189 : // TODO: this generates a fatal error in the log which can
190 : // be disturbing... we could look at adding a tag on
191 : // that error and here mark the messages associated
192 : // with that tag as hidden so that way we do not get
193 : // the error output.
194 : //
195 0 : local_stream_client_connection test_connection(f_address);
196 : }
197 0 : catch(runtime_error const & e)
198 : {
199 : // note: in Linux we can distinguish between a full
200 : // backlog (EAGAIN) and a disconnected socket
201 : // (ECONNREFUSED); we should not set available
202 : // to true on EAGAIN...
203 : //
204 0 : available = true;
205 : }
206 : }
207 0 : if(!available)
208 : {
209 0 : SNAP_LOG_ERROR
210 : << "file socket \""
211 : << un.sun_path
212 : << "\" already in use (errno: "
213 0 : << std::to_string(EADDRINUSE)
214 : << " -- "
215 0 : << strerror(EADDRINUSE)
216 : << "); cannot listen on address \""
217 0 : << f_address.to_uri()
218 : << "\"."
219 : << SNAP_LOG_SEND;
220 0 : throw runtime_error("socket already exists, can't create an AF_UNIX server");
221 : }
222 :
223 0 : r = f_address.unlink();
224 0 : if(r != 0
225 0 : && errno != ENOENT)
226 : {
227 0 : SNAP_LOG_ERROR
228 : << "not able to delete file socket \""
229 : << un.sun_path
230 : << "\"; socket already in use (errno: "
231 0 : << std::to_string(EADDRINUSE)
232 : << " -- "
233 0 : << strerror(EADDRINUSE)
234 : << "); cannot listen on address \""
235 0 : << f_address.to_uri()
236 : << "\"."
237 : << SNAP_LOG_SEND;
238 0 : throw runtime_error("could not unlink socket to reuse it as an AF_UNIX server");
239 : }
240 : }
241 2 : r = bind(
242 2 : f_socket.get()
243 : , reinterpret_cast<sockaddr const *>(&un)
244 : , sizeof(struct sockaddr_un));
245 : }
246 : else
247 : {
248 : // we want to limit the size because otherwise it would include
249 : // the '\0's after the specified name
250 : //
251 0 : std::size_t const size(sizeof(un.sun_family)
252 : + 1 // for the '\0' in sun_path[0]
253 0 : + strlen(un.sun_path + 1));
254 0 : r = bind(
255 0 : f_socket.get()
256 : , reinterpret_cast<sockaddr const *>(&un)
257 : , size);
258 : }
259 :
260 1 : if(r < 0)
261 : {
262 : throw runtime_error(
263 : "could not bind the socket to \""
264 0 : + f_address.to_uri()
265 0 : + "\"");
266 : }
267 :
268 : // start listening, we expect the caller to then call accept() to
269 : // acquire connections
270 : //
271 1 : if(listen(f_socket.get(), f_max_connections) < 0)
272 : {
273 : throw runtime_error(
274 : "could not listen to the socket bound to \""
275 0 : + f_address.to_uri()
276 0 : + "\"");
277 : }
278 : }
279 :
280 :
281 : /** \brief Clean up the server socket.
282 : *
283 : * This function deletes the socket file if this service used such a socket.
284 : *
285 : * \note
286 : * If the server crashes, that delete may not happen. In order to allow
287 : * for a restart, calling the constructor and setting the force_reuse_addr
288 : * to true is what will generally work best.
289 : */
290 2 : local_stream_server_connection::~local_stream_server_connection()
291 : {
292 1 : f_address.unlink();
293 1 : }
294 :
295 :
296 : /** \brief Check whether this connection is a listener.
297 : *
298 : * This function already returns true since a server is a listener.
299 : * This allows us to have our process_accept() function called instead
300 : * of the process_read().
301 : *
302 : * \return Always true since this is a listening server.
303 : */
304 10 : bool local_stream_server_connection::is_listener() const
305 : {
306 10 : return true;
307 : }
308 :
309 :
310 : /** \brief Retrieve the socket descriptor.
311 : *
312 : * This function returns the socket descriptor. It can be used to
313 : * tweak things on the socket such as making it non-blocking or
314 : * directly accessing the data.
315 : *
316 : * \return The socket descriptor.
317 : */
318 19 : int local_stream_server_connection::get_socket() const
319 : {
320 19 : return f_socket.get();
321 : }
322 :
323 :
324 : /** \brief Retrieve the maximum number of connections.
325 : *
326 : * This function returns the maximum number of connections that can
327 : * be accepted by the socket. This was set by the constructor and
328 : * it cannot be changed later.
329 : *
330 : * \return The maximum number of incoming connections.
331 : */
332 0 : int local_stream_server_connection::get_max_connections() const
333 : {
334 0 : return f_max_connections;
335 : }
336 :
337 :
338 : /** \brief Retrieve one new connection.
339 : *
340 : * This function will wait until a new connection arrives and returns a
341 : * new bio_client object for each new connection.
342 : *
343 : * If the socket is made non-blocking then the function may return without
344 : * a bio_client object (i.e. a null pointer instead.)
345 : *
346 : * \return A file descriptor representing the new connection socket.
347 : */
348 1 : snapdev::raii_fd_t local_stream_server_connection::accept()
349 : {
350 1 : struct sockaddr_un un;
351 1 : socklen_t len(sizeof(un));
352 : snapdev::raii_fd_t r(::accept(
353 2 : f_socket.get()
354 : , reinterpret_cast<sockaddr *>(&un)
355 2 : , &len));
356 1 : if(r == nullptr)
357 : {
358 0 : throw runtime_error("failed accepting a new AF_UNIX client");
359 : }
360 :
361 : // force a close on execve() to avoid sharing the socket in child
362 : // processes
363 : //
364 1 : if(f_close_on_exec)
365 : {
366 : // if this call fails, we ignore the error, but still log the event
367 : //
368 1 : if(fcntl(r.get(), F_SETFD, FD_CLOEXEC) != 0)
369 : {
370 0 : SNAP_LOG_WARNING
371 : << "::accept(): an error occurred trying"
372 : " to mark accepted AF_UNIX socket with FD_CLOEXEC."
373 : << SNAP_LOG_SEND;
374 : }
375 : }
376 :
377 1 : return r;
378 : }
379 :
380 :
381 : /** \brief Return the current state of the close-on-exec flag.
382 : *
383 : * This function returns the current state of the close-on-exec flag. This
384 : * is the flag as defined in the contructor or by the set_close_on_exec()
385 : * function. It does not represent the status of the server socket nor
386 : * of the clients that were accept()'ed by this class.
387 : *
388 : * It will, however, be used whenever the accept() is called in the future.
389 : *
390 : * \return The current status of the close-on-exec flag.
391 : */
392 0 : bool local_stream_server_connection::get_close_on_exec() const
393 : {
394 0 : return f_close_on_exec;
395 : }
396 :
397 :
398 : /** \brief Change the close-on-exec flag for future accept() calls.
399 : *
400 : * This function allows you to change the close-on-exec flag after
401 : * you created a Unix server. This means you may say that the server
402 : * needs to be closed, but not the connections or vice versa.
403 : *
404 : * \param[in] yes Whether the close-on-exec will be set on sockets
405 : * returned by the accept() function.
406 : */
407 0 : void local_stream_server_connection::set_close_on_exec(bool yes)
408 : {
409 0 : f_close_on_exec = yes;
410 0 : }
411 :
412 :
413 : /** \brief Retrieve the server IP address.
414 : *
415 : * This function returns the IP address used to bind the socket. This
416 : * is the address clients have to use to connect to the server unless
417 : * the address was set to all zeroes (0.0.0.0) in which case any user
418 : * can connect.
419 : *
420 : * The IP address cannot be changed.
421 : *
422 : * \return The server IP address.
423 : */
424 0 : addr::unix local_stream_server_connection::get_addr() const
425 : {
426 0 : return f_address;
427 : }
428 :
429 :
430 :
431 :
432 :
433 6 : } // namespace ed
434 : // vim: ts=4 sw=4 et
|