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
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 Implementation of the Snap Communicator class.
22 : *
23 : * This class wraps the C poll() interface in a C++ object with many types
24 : * of objects:
25 : *
26 : * \li Server Connections; for software that want to offer a port to
27 : * which clients can connect to; the server will call accept()
28 : * once a new client connection is ready; this results in a
29 : * Server/Client connection object
30 : * \li Client Connections; for software that want to connect to
31 : * a server; these expect the IP address and port to connect to
32 : * \li Server/Client Connections; for the server when it accepts a new
33 : * connection; in this case the server gets a socket from accept()
34 : * and creates one of these objects to handle the connection
35 : *
36 : * Using the poll() function is the easiest and allows us to listen
37 : * on pretty much any number of sockets (on my server it is limited
38 : * at 16,768 and frankly over 1,000 we probably will start to have
39 : * real slowness issues on small VPN servers.)
40 : */
41 :
42 : // self
43 : //
44 : #include "eventdispatcher/tcp_server_client_connection.h"
45 :
46 : #include "eventdispatcher/exception.h"
47 :
48 :
49 : // snaplogger lib
50 : //
51 : #include <snaplogger/message.h>
52 :
53 :
54 : // C++ lib
55 : //
56 : #include <cstring>
57 :
58 :
59 : // C lib
60 : //
61 : #include <arpa/inet.h>
62 : #include <netdb.h>
63 :
64 :
65 : // last include
66 : //
67 : #include <snapdev/poison.h>
68 :
69 :
70 :
71 : namespace ed
72 : {
73 :
74 :
75 :
76 : /** \brief Create a client connection created from an accept().
77 : *
78 : * This constructor initializes a client connection from a socket
79 : * that we received from an accept() call.
80 : *
81 : * The destructor will automatically close that socket on destruction.
82 : *
83 : * \param[in] client The client that accept() returned.
84 : */
85 0 : tcp_server_client_connection::tcp_server_client_connection(tcp_bio_client::pointer_t client)
86 0 : : f_client(client)
87 : {
88 0 : }
89 :
90 :
91 : /** \brief Make sure the socket gets released.
92 : *
93 : * This destructor makes sure that the socket gets closed.
94 : */
95 0 : tcp_server_client_connection::~tcp_server_client_connection()
96 : {
97 0 : close();
98 0 : }
99 :
100 :
101 : /** \brief Read data from the TCP server client socket.
102 : *
103 : * This function reads as much data up to the specified amount
104 : * in \p count. The read data is saved in \p buf.
105 : *
106 : * \param[in,out] buf The buffer where the data gets read.
107 : * \param[in] count The maximum number of bytes to read in buf.
108 : *
109 : * \return The number of bytes read or -1 if an error occurred.
110 : */
111 0 : ssize_t tcp_server_client_connection::read(void * buf, size_t count)
112 : {
113 0 : if(!f_client)
114 : {
115 0 : errno = EBADF;
116 0 : return -1;
117 : }
118 0 : return f_client->read(reinterpret_cast<char *>(buf), count);
119 : }
120 :
121 :
122 : /** \brief Write data to this connection's socket.
123 : *
124 : * This function writes up to \p count bytes of data from \p buf
125 : * to this connection's socket.
126 : *
127 : * \warning
128 : * This write function may not always write all the data you are
129 : * trying to send to the remote connection. If you want to make
130 : * sure that all your data is written to the other connection,
131 : * you want to instead use the tcp_server_client_buffer_connection
132 : * which overloads the write() function and saves the data to be
133 : * written to the socket in a buffer. The communicator run
134 : * loop is then responsible for sending all the data.
135 : *
136 : * \param[in] buf The buffer of data to be written to the socket.
137 : * \param[in] count The number of bytes the caller wants to write to the
138 : * connection.
139 : *
140 : * \return The number of bytes written to the socket or -1 if an error occurred.
141 : */
142 0 : ssize_t tcp_server_client_connection::write(void const * buf, size_t count)
143 : {
144 0 : if(!f_client)
145 : {
146 0 : errno = EBADF;
147 0 : return -1;
148 : }
149 0 : return f_client->write(reinterpret_cast<char const *>(buf), count);
150 : }
151 :
152 :
153 : /** \brief Close the socket of this connection.
154 : *
155 : * This function is automatically called whenever the object gets
156 : * destroyed (see destructor) or detects that the client closed
157 : * the network connection.
158 : *
159 : * Connections cannot be reopened.
160 : */
161 0 : void tcp_server_client_connection::close()
162 : {
163 0 : f_client.reset();
164 0 : }
165 :
166 :
167 : /** \brief Retrieve the socket of this connection.
168 : *
169 : * This function returns the socket defined in this connection.
170 : *
171 : * \return The socket file descriptor or -1 if the connection is closed.
172 : */
173 0 : int tcp_server_client_connection::get_socket() const
174 : {
175 0 : if(f_client == nullptr)
176 : {
177 : // client connection was closed
178 : //
179 0 : return -1;
180 : }
181 0 : return f_client->get_socket();
182 : }
183 :
184 :
185 : /** \brief Tell that we are always a reader.
186 : *
187 : * This function always returns true meaning that the connection is
188 : * always of a reader. In most cases this is safe because if nothing
189 : * is being written to you then poll() never returns so you do not
190 : * waste much time in have a TCP connection always marked as a
191 : * reader.
192 : *
193 : * \return The events to listen to for this connection.
194 : */
195 0 : bool tcp_server_client_connection::is_reader() const
196 : {
197 0 : return true;
198 : }
199 :
200 :
201 : /** \brief Retrieve a copy of the client's address.
202 : *
203 : * This function makes a copy of the address of this client connection
204 : * to the \p address parameter and returns the length.
205 : *
206 : * If the function returns zero, then the \p address buffer is not
207 : * modified and no address is defined in this connection.
208 : *
209 : * \param[out] address The reference to an address variable where the
210 : * client's address gets copied.
211 : *
212 : * \return Return the length of the address which may be smaller than
213 : * sizeof(address). If zero, then no address is defined.
214 : *
215 : * \sa get_addr()
216 : */
217 0 : size_t tcp_server_client_connection::get_client_address(sockaddr_storage & address) const
218 : {
219 : // make sure the address is defined and the socket open
220 : //
221 0 : if(const_cast<tcp_server_client_connection *>(this)->define_address() != 0)
222 : {
223 0 : return 0;
224 : }
225 :
226 0 : address = f_address;
227 0 : return f_length;
228 : }
229 :
230 :
231 : /** \brief Retrieve the address in the form of a string.
232 : *
233 : * Like the get_addr() of the tcp client and server classes, this
234 : * function returns the address in the form of a string which can
235 : * easily be used to log information and other similar tasks.
236 : *
237 : * \todo
238 : * Look at using libaddr for the conversion.
239 : *
240 : * \return The client's address in the form of a string.
241 : */
242 0 : std::string tcp_server_client_connection::get_client_addr() const
243 : {
244 : // make sure the address is defined and the socket open
245 : //
246 0 : if(!const_cast<tcp_server_client_connection *>(this)->define_address())
247 : {
248 0 : return std::string();
249 : }
250 :
251 0 : size_t const max_length(std::max(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1);
252 :
253 : // in release mode this should not be dynamic (although the syntax is so
254 : // the warning would happen), but in debug it is likely an alloca()
255 : #pragma GCC diagnostic push
256 : #pragma GCC diagnostic ignored "-Wvla"
257 0 : char buf[max_length];
258 : #pragma GCC diagnostic pop
259 :
260 0 : char const * r(nullptr);
261 :
262 0 : if(f_address.ss_family == AF_INET)
263 : {
264 0 : r = inet_ntop(AF_INET, &reinterpret_cast<sockaddr_in const &>(f_address).sin_addr, buf, max_length);
265 : }
266 : else
267 : {
268 0 : r = inet_ntop(AF_INET6, &reinterpret_cast<sockaddr_in6 const &>(f_address).sin6_addr, buf, max_length);
269 : }
270 :
271 0 : if(r == nullptr)
272 : {
273 0 : int const e(errno);
274 0 : std::string err("inet_ntop() could not convert IP address (errno: ");
275 0 : err += std::to_string(e);
276 0 : err += " -- ";
277 0 : err += strerror(e);
278 0 : err += ").";
279 0 : SNAP_LOG_FATAL << err << SNAP_LOG_SEND;
280 0 : throw event_dispatcher_runtime_error(err);
281 : }
282 :
283 0 : return buf;
284 : }
285 :
286 :
287 : /** \brief Retrieve the port.
288 : *
289 : * This function returns the port of the socket on our side.
290 : *
291 : * If the port is not available (not connected?), then -1 is returned.
292 : *
293 : * \return The client's port in host order.
294 : */
295 0 : int tcp_server_client_connection::get_client_port() const
296 : {
297 : // make sure the address is defined and the socket open
298 : //
299 0 : if(!const_cast<tcp_server_client_connection *>(this)->define_address())
300 : {
301 0 : return -1;
302 : }
303 :
304 0 : if(f_address.ss_family == AF_INET)
305 : {
306 0 : return ntohs(reinterpret_cast<sockaddr_in const &>(f_address).sin_port);
307 : }
308 : else
309 : {
310 0 : return ntohs(reinterpret_cast<sockaddr_in6 const &>(f_address).sin6_port);
311 : }
312 : }
313 :
314 :
315 : /** \brief Retrieve the address in the form of a string.
316 : *
317 : * Like the get_addr() of the tcp client and server classes, this
318 : * function returns the address in the form of a string which can
319 : * easily be used to log information and other similar tasks.
320 : *
321 : * \todo
322 : * Look at using libaddr for the conversion.
323 : *
324 : * \return The client's address in the form of a string.
325 : */
326 0 : std::string tcp_server_client_connection::get_client_addr_port() const
327 : {
328 : // get the current address and port
329 0 : std::string const addr(get_client_addr());
330 0 : int const port(get_client_port());
331 :
332 : // make sure they are defined
333 0 : if(addr.empty()
334 0 : || port < 0)
335 : {
336 0 : return std::string();
337 : }
338 :
339 : // calculate the result
340 0 : std::string buf;
341 0 : buf.reserve(addr.length() + (3 + 5));
342 0 : if(f_address.ss_family == AF_INET)
343 : {
344 0 : buf += addr;
345 0 : buf += ':';
346 : }
347 : else
348 : {
349 0 : buf += '[';
350 0 : buf += addr;
351 0 : buf += "]:";
352 : }
353 0 : buf += std::to_string(port);
354 :
355 0 : return buf;
356 : }
357 :
358 :
359 : /** \brief Retrieve the socket address if we have not done so yet.
360 : *
361 : * This function make sure that the f_address and f_length parameters are
362 : * defined. This is done by calling the getsockname() function.
363 : *
364 : * If f_length is still zero, then it is expected that address was not
365 : * yet read.
366 : *
367 : * Note that the function returns -1 if the socket is now -1 (i.e. the
368 : * connection is closed) whether or not the function worked before.
369 : *
370 : * \return false if the address cannot be defined, true otherwise
371 : */
372 0 : bool tcp_server_client_connection::define_address()
373 : {
374 0 : int const s(get_socket());
375 0 : if(s == -1)
376 : {
377 0 : return false;
378 : }
379 :
380 0 : if(f_length == 0)
381 : {
382 : // address not defined yet, retrieve with with getsockname()
383 : //
384 0 : f_length = sizeof(f_address);
385 0 : if(getsockname(s, reinterpret_cast<struct sockaddr *>(&f_address), &f_length) != 0)
386 : {
387 0 : int const e(errno);
388 0 : SNAP_LOG_ERROR
389 0 : << "getsockname() failed retrieving IP address (errno: "
390 : << e
391 : << " -- "
392 0 : << strerror(e)
393 : << ")."
394 : << SNAP_LOG_SEND;
395 0 : f_length = 0;
396 0 : return false;
397 : }
398 0 : if(f_address.ss_family != AF_INET
399 0 : && f_address.ss_family != AF_INET6)
400 : {
401 0 : SNAP_LOG_ERROR
402 0 : << "address family ("
403 0 : << f_address.ss_family
404 : << ") returned by getsockname() is not understood, it is neither an IPv4 nor IPv6."
405 : << SNAP_LOG_SEND;
406 0 : f_length = 0;
407 0 : return false;
408 : }
409 0 : if(f_length < sizeof(f_address))
410 : {
411 : // reset the rest of the structure, just in case
412 : //
413 0 : memset(reinterpret_cast<char *>(&f_address) + f_length, 0, sizeof(f_address) - f_length);
414 : }
415 : }
416 :
417 0 : return true;
418 : }
419 :
420 :
421 :
422 : } // namespace ed
423 : // vim: ts=4 sw=4 et
|