Line data Source code
1 : // Copyright (c) 2012-2021 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
17 : // along with this program; if not, write to the Free Software
18 : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 :
20 : /** \file
21 : * \brief Event dispatch class.
22 : *
23 : * Class used to handle events.
24 : */
25 :
26 : // to get the POLLRDHUP definition
27 : #ifndef _GNU_SOURCE
28 : #define _GNU_SOURCE
29 : #endif
30 :
31 :
32 : // self
33 : //
34 : #include "eventdispatcher/local_dgram_server.h"
35 :
36 : #include "eventdispatcher/exception.h"
37 :
38 :
39 : // snapwebsites lib
40 : //
41 : #include <snaplogger/message.h>
42 :
43 :
44 : // C lib
45 : //
46 : #include <sys/stat.h>
47 : #include <poll.h>
48 : //#include <string.h>
49 :
50 :
51 : // last include
52 : //
53 : #include <snapdev/poison.h>
54 :
55 :
56 :
57 :
58 : namespace ed
59 : {
60 :
61 :
62 :
63 : /** \brief Initialize a UDP server object.
64 : *
65 : * This function initializes a UDP server object making it ready to
66 : * receive messages.
67 : *
68 : * The server address and port are specified in the constructor so
69 : * if you need to receive messages from several different addresses
70 : * and/or port, you'll have to create a server for each.
71 : *
72 : * The address is a string and it can represent an IPv4 or IPv6
73 : * address.
74 : *
75 : * Note that this function calls bind() to listen to the socket
76 : * at the specified address. To accept data on different UDP addresses
77 : * and ports, multiple UDP servers must be created.
78 : *
79 : * \note
80 : * The socket is open in this process. If you fork() or exec() then the
81 : * socket will be closed by the operating system.
82 : *
83 : * \warning
84 : * We only make use of the first address found by getaddrinfo(). All
85 : * the other addresses are ignored.
86 : *
87 : * \warning
88 : * Remember that the multicast feature under Linux is shared by all
89 : * processes running on that server. Any one process can listen for
90 : * any and all multicast messages from any other process. Our
91 : * implementation limits the multicast from a specific IP. However.
92 : * other processes can also receive your packets and there is nothing
93 : * you can do to prevent that.
94 : *
95 : * \exception udp_client_server_runtime_error
96 : * The udp_client_server_runtime_error exception is raised when the address
97 : * and port combination cannot be resolved or if the socket cannot be
98 : * opened.
99 : *
100 : * \param[in] address The address to connect/listen to.
101 : * \param[in] sequential Whether the packets have to be 100% sequential.
102 : * \param[in] close_on_exec Whether the socket has to be closed on execve().
103 : */
104 2 : local_dgram_server::local_dgram_server(
105 : addr::unix const & address
106 : , bool sequential
107 : , bool close_on_exec
108 2 : , bool force_reuse_addr)
109 2 : : local_dgram_base(address, sequential, close_on_exec)
110 : {
111 2 : if(f_address.is_unnamed())
112 : {
113 : // for an unnamed socket, we do not bind at all the user is
114 : // responsible for knowing where to read and where to write
115 : //
116 0 : return;
117 : }
118 :
119 2 : sockaddr_un un;
120 2 : f_address.get_un(un);
121 :
122 : // bind to the first address
123 : //
124 2 : int r(-1);
125 2 : if(f_address.is_file())
126 : {
127 : // TODO: this is common code to the local_stream_server_connection.cpp
128 : //
129 : // a Unix file socket must create a new socket file to prove unicity
130 : // if the file already exists, even if it isn't used, the bind() call
131 : // will fail; if the file exists and the force_reuse_addr is true this
132 : // this function attempts to delete the file if it is a socket and we
133 : // can't connect to it (i.e. "lost file")
134 : //
135 2 : struct stat st = {};
136 2 : if(stat(un.sun_path, &st) == 0)
137 : {
138 0 : if(!S_ISSOCK(st.st_mode))
139 : {
140 0 : SNAP_LOG_ERROR
141 0 : << "file \""
142 : << un.sun_path
143 : << "\" is not a socket; cannot listen on address \""
144 0 : << f_address.to_uri()
145 : << "\"."
146 : << SNAP_LOG_SEND;
147 0 : throw event_dispatcher_runtime_error("file already exists and it is not a socket, can't create an AF_UNIX server");
148 : }
149 :
150 0 : if(!force_reuse_addr)
151 : {
152 0 : SNAP_LOG_ERROR
153 0 : << "file socket \""
154 : << un.sun_path
155 : << "\" already in use (errno: "
156 0 : << std::to_string(EADDRINUSE)
157 : << " -- "
158 0 : << strerror(EADDRINUSE)
159 : << "); cannot listen on address \""
160 0 : << f_address.to_uri()
161 : << "\"."
162 : << SNAP_LOG_SEND;
163 0 : throw event_dispatcher_runtime_error("socket already exists, can't create an AF_UNIX server");
164 : }
165 :
166 0 : r = f_address.unlink();
167 0 : if(r != 0
168 0 : && errno != ENOENT)
169 : {
170 0 : SNAP_LOG_ERROR
171 0 : << "not able to delete file socket \""
172 : << un.sun_path
173 : << "\"; socket already in use (errno: "
174 0 : << std::to_string(EADDRINUSE)
175 : << " -- "
176 0 : << strerror(EADDRINUSE)
177 : << "); cannot listen on address \""
178 0 : << f_address.to_uri()
179 : << "\"."
180 : << SNAP_LOG_SEND;
181 0 : throw event_dispatcher_runtime_error("could not unlink socket to reuse it as an AF_UNIX server");
182 : }
183 : }
184 4 : r = bind(
185 4 : f_socket.get()
186 : , reinterpret_cast<sockaddr const *>(&un)
187 : , sizeof(struct sockaddr_un));
188 : }
189 : else
190 : {
191 : // we want to limit the size because otherwise it would include
192 : // the '\0's after the specified name
193 : //
194 0 : std::size_t const size(sizeof(un.sun_family)
195 : + 1 // for the '\0' in sun_path[0]
196 0 : + strlen(un.sun_path + 1));
197 0 : r = bind(
198 0 : f_socket.get()
199 : , reinterpret_cast<sockaddr const *>(&un)
200 : , size);
201 : }
202 :
203 2 : if(r != 0)
204 : {
205 0 : int const e(errno);
206 0 : SNAP_LOG_ERROR
207 0 : << "the bind() function failed with errno: "
208 : << e
209 : << " ("
210 0 : << strerror(e)
211 : << "); Unix address \""
212 0 : << f_address.to_uri()
213 : << "\"."
214 : << SNAP_LOG_SEND;
215 : throw event_dispatcher_runtime_error(
216 : "could not bind AF_UNIX datagram socket to \""
217 0 : + f_address.to_uri()
218 0 : + "\"");
219 : }
220 : }
221 :
222 :
223 : /** \brief Wait on a message.
224 : *
225 : * This function waits until a message is received on this UDP server.
226 : * There are no means to return from this function except by receiving
227 : * a message. Remember that UDP does not have a connect state so whether
228 : * another process quits does not change the status of this UDP server
229 : * and thus it continues to wait forever.
230 : *
231 : * Note that you may change the type of socket by making it non-blocking
232 : * (use the get_socket() to retrieve the socket identifier) in which
233 : * case this function will not block if no message is available. Instead
234 : * it returns immediately.
235 : *
236 : * \param[in] msg The buffer where the message is saved.
237 : * \param[in] max_size The maximum size the message (i.e. size of the \p msg buffer.)
238 : *
239 : * \return The number of bytes read or -1 if an error occurs.
240 : */
241 6 : int local_dgram_server::recv(char * msg, size_t max_size)
242 : {
243 6 : return static_cast<int>(::recv(f_socket.get(), msg, max_size, 0));
244 : }
245 :
246 :
247 : /** \brief Wait for data to come in.
248 : *
249 : * This function waits for a given amount of time for data to come in. If
250 : * no data comes in after max_wait_ms, the function returns with -1 and
251 : * errno set to EAGAIN.
252 : *
253 : * The socket is expected to be a blocking socket (the default,) although
254 : * it is possible to setup the socket as non-blocking if necessary for
255 : * some other reason.
256 : *
257 : * This function blocks for a maximum amount of time as defined by
258 : * max_wait_ms. It may return sooner with an error or a message.
259 : *
260 : * \param[in] msg The buffer where the message will be saved.
261 : * \param[in] max_size The size of the \p msg buffer in bytes.
262 : * \param[in] max_wait_ms The maximum number of milliseconds to wait for a message.
263 : *
264 : * \return -1 if an error occurs or the function timed out, the number of bytes received otherwise.
265 : */
266 0 : int local_dgram_server::timed_recv(char * msg, size_t const max_size, int const max_wait_ms)
267 : {
268 0 : pollfd fd;
269 0 : fd.events = POLLIN | POLLPRI | POLLRDHUP;
270 0 : fd.fd = f_socket.get();
271 0 : int const retval(poll(&fd, 1, max_wait_ms));
272 0 : if(retval == -1)
273 : {
274 : // poll() sets errno accordingly
275 0 : return -1;
276 : }
277 0 : if(retval > 0)
278 : {
279 : // our socket has data
280 0 : return static_cast<int>(::recv(f_socket.get(), msg, max_size, 0));
281 : }
282 :
283 : // our socket has no data
284 0 : errno = EAGAIN;
285 0 : return -1;
286 : }
287 :
288 :
289 : /** \brief Wait for data to come in, but return a std::string.
290 : *
291 : * This function waits for a given amount of time for data to come in. If
292 : * no data comes in after max_wait_ms, the function returns with -1 and
293 : * errno set to EAGAIN.
294 : *
295 : * The socket is expected to be a blocking socket (the default,) although
296 : * it is possible to setup the socket as non-blocking if necessary for
297 : * some other reason.
298 : *
299 : * This function blocks for a maximum amount of time as defined by
300 : * max_wait_ms. It may return sooner with an error or a message.
301 : *
302 : * \param[in] bufsize The maximum size of the returned string in bytes.
303 : * \param[in] max_wait_ms The maximum number of milliseconds to wait for a message.
304 : *
305 : * \return received string. an empty string if not data received or error.
306 : *
307 : * \sa timed_recv()
308 : */
309 0 : std::string local_dgram_server::timed_recv(int const bufsize, int const max_wait_ms)
310 : {
311 0 : std::vector<char> buf;
312 0 : buf.resize( bufsize + 1, '\0' ); // +1 for ending \0
313 0 : int const r(timed_recv(&buf[0], bufsize, max_wait_ms));
314 0 : if(r <= -1)
315 : {
316 : // Timed out, so return empty string.
317 : // TBD: could std::string() smash errno?
318 : //
319 0 : return std::string();
320 : }
321 :
322 : // Resize the buffer, then convert to std string
323 : //
324 0 : buf.resize(r + 1, '\0');
325 :
326 0 : std::string word;
327 0 : word.resize(r);
328 0 : std::copy(buf.begin(), buf.end(), word.begin());
329 :
330 0 : return word;
331 : }
332 :
333 :
334 :
335 :
336 6 : } // namespace ed
337 : // vim: ts=4 sw=4 et
|