Line data Source code
1 : // Copyright (c) 2012-2019 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 : // make sure we use OpenSSL with multi-thread support
27 : // (TODO: move to .cpp once we have the impl!)
28 : #define OPENSSL_THREAD_DEFINES
29 :
30 : // self
31 : //
32 : #include "eventdispatcher/tcp_bio_client.h"
33 :
34 : #include "eventdispatcher/exception.h"
35 : #include "eventdispatcher/tcp_private.h"
36 :
37 :
38 : // snaplogger lib
39 : //
40 : #include <snaplogger/message.h>
41 :
42 :
43 : // snapdev lib
44 : //
45 : #include <snapdev/not_reached.h>
46 :
47 :
48 : // OpenSSL lib
49 : //
50 : #include <openssl/bio.h>
51 : #include <openssl/err.h>
52 : #include <openssl/ssl.h>
53 :
54 :
55 : // C lib
56 : //
57 : #include <netdb.h>
58 : #include <arpa/inet.h>
59 :
60 :
61 : // last include
62 : //
63 : #include <snapdev/poison.h>
64 :
65 :
66 :
67 :
68 : #ifndef OPENSSL_THREADS
69 : #error "OPENSSL_THREADS is not defined. Snap! requires support for multiple threads in OpenSSL."
70 : #endif
71 :
72 : namespace ed
73 : {
74 :
75 :
76 :
77 : /** \class tcp_bio_client
78 : * \brief Create a BIO client and connect to a server, eventually with TLS.
79 : *
80 : * This class is a client socket implementation used to connect to a server.
81 : * The server is expected to be running at the time the client is created
82 : * otherwise it fails connecting.
83 : *
84 : * This class is not appropriate to connect to a server that may come and go
85 : * over time.
86 : *
87 : * The BIO extension is from the OpenSSL library and it allows the client
88 : * to connect using SSL. At this time connections are either secure or
89 : * not secure. If a secure connection fails, you may attempt again without
90 : * TLS or other encryption mechanism.
91 : */
92 :
93 :
94 : #if 0
95 : // code to do traces
96 : namespace
97 : {
98 :
99 :
100 : char const * tls_rt_type(int type)
101 : {
102 : switch(type)
103 : {
104 : #ifdef SSL3_RT_HEADER
105 : case SSL3_RT_HEADER:
106 : return "TLS header";
107 : #endif
108 : case SSL3_RT_CHANGE_CIPHER_SPEC:
109 : return "TLS change cipher";
110 : case SSL3_RT_ALERT:
111 : return "TLS alert";
112 : case SSL3_RT_HANDSHAKE:
113 : return "TLS handshake";
114 : case SSL3_RT_APPLICATION_DATA:
115 : return "TLS app data";
116 : default:
117 : return "TLS Unknown";
118 : }
119 : }
120 :
121 :
122 : char const * ssl_msg_type(int ssl_ver, int msg)
123 : {
124 : #ifdef SSL2_VERSION_MAJOR
125 : if(ssl_ver == SSL2_VERSION_MAJOR)
126 : {
127 : switch(msg)
128 : {
129 : case SSL2_MT_ERROR:
130 : return "Error";
131 : case SSL2_MT_CLIENT_HELLO:
132 : return "Client hello";
133 : case SSL2_MT_CLIENT_MASTER_KEY:
134 : return "Client key";
135 : case SSL2_MT_CLIENT_FINISHED:
136 : return "Client finished";
137 : case SSL2_MT_SERVER_HELLO:
138 : return "Server hello";
139 : case SSL2_MT_SERVER_VERIFY:
140 : return "Server verify";
141 : case SSL2_MT_SERVER_FINISHED:
142 : return "Server finished";
143 : case SSL2_MT_REQUEST_CERTIFICATE:
144 : return "Request CERT";
145 : case SSL2_MT_CLIENT_CERTIFICATE:
146 : return "Client CERT";
147 : }
148 : }
149 : else
150 : #endif
151 : if(ssl_ver == SSL3_VERSION_MAJOR)
152 : {
153 : switch(msg)
154 : {
155 : case SSL3_MT_HELLO_REQUEST:
156 : return "Hello request";
157 : case SSL3_MT_CLIENT_HELLO:
158 : return "Client hello";
159 : case SSL3_MT_SERVER_HELLO:
160 : return "Server hello";
161 : #ifdef SSL3_MT_NEWSESSION_TICKET
162 : case SSL3_MT_NEWSESSION_TICKET:
163 : return "Newsession Ticket";
164 : #endif
165 : case SSL3_MT_CERTIFICATE:
166 : return "Certificate";
167 : case SSL3_MT_SERVER_KEY_EXCHANGE:
168 : return "Server key exchange";
169 : case SSL3_MT_CLIENT_KEY_EXCHANGE:
170 : return "Client key exchange";
171 : case SSL3_MT_CERTIFICATE_REQUEST:
172 : return "Request CERT";
173 : case SSL3_MT_SERVER_DONE:
174 : return "Server finished";
175 : case SSL3_MT_CERTIFICATE_VERIFY:
176 : return "CERT verify";
177 : case SSL3_MT_FINISHED:
178 : return "Finished";
179 : #ifdef SSL3_MT_CERTIFICATE_STATUS
180 : case SSL3_MT_CERTIFICATE_STATUS:
181 : return "Certificate Status";
182 : #endif
183 : }
184 : }
185 : return "Unknown";
186 : }
187 :
188 :
189 : void ssl_trace(
190 : int direction,
191 : int ssl_ver,
192 : int content_type,
193 : void const * buf, size_t len,
194 : SSL * ssl,
195 : void * userp)
196 : {
197 : snap::NOTUSED(ssl);
198 : snap::NOTUSED(userp);
199 :
200 : std::stringstream out;
201 : char const * msg_name;
202 : int msg_type;
203 :
204 : // VERSION
205 : //
206 : out << SSL_get_version(ssl);
207 :
208 : // DIRECTION
209 : //
210 : out << (direction == 0 ? " (IN), " : " (OUT), ");
211 :
212 : // keep only major version
213 : //
214 : ssl_ver >>= 8;
215 :
216 : // TLS RT NAME
217 : //
218 : if(ssl_ver == SSL3_VERSION_MAJOR
219 : && content_type != 0)
220 : {
221 : out << tls_rt_type(content_type);
222 : }
223 : else
224 : {
225 : out << "(no tls_tr_type)";
226 : }
227 :
228 : if(len >= 1)
229 : {
230 : msg_type = * reinterpret_cast<unsigned char const *>(buf);
231 : msg_name = ssl_msg_type(ssl_ver, msg_type);
232 :
233 : out << ", ";
234 : out << msg_name;
235 : out << " (";
236 : out << std::to_string(msg_type);
237 : out << "):";
238 : }
239 :
240 : out << std::hex;
241 : for(size_t line(0); line < len; line += 16)
242 : {
243 : out << std::endl
244 : << (direction == 0 ? "<" : ">")
245 : << " "
246 : << std::setfill('0') << std::setw(4) << line
247 : << "- ";
248 : size_t idx;
249 : for(idx = 0; line + idx < len && idx < 16; ++idx)
250 : {
251 : if(idx == 8)
252 : {
253 : out << " ";
254 : }
255 : else
256 : {
257 : out << " ";
258 : }
259 : int const c(reinterpret_cast<unsigned char const *>(buf)[line + idx]);
260 : out << std::setfill('0') << std::setw(2) << static_cast<int>(c);
261 : }
262 : for(; idx < 16; ++idx)
263 : {
264 : if(idx == 8)
265 : {
266 : out << " ";
267 : }
268 : out << " ";
269 : }
270 : out << " ";
271 : for(idx = 0; line + idx < len && idx < 16; ++idx)
272 : {
273 : if(idx == 8)
274 : {
275 : out << " ";
276 : }
277 : char c(reinterpret_cast<char const *>(buf)[line + idx]);
278 : if(c < ' ' || c > '~')
279 : {
280 : c = '.';
281 : }
282 : out << c;
283 : }
284 : }
285 :
286 : std::cerr << out.str() << std::endl;
287 : }
288 :
289 :
290 : } // no name namespace
291 : #endif
292 :
293 :
294 :
295 :
296 :
297 :
298 :
299 :
300 :
301 :
302 :
303 : /** \brief Contruct a tcp_bio_client object.
304 : *
305 : * The tcp_bio_client constructor initializes a BIO connector and connects
306 : * to the specified server. The server is defined with the \p addr and
307 : * \p port specified as parameters. The connection tries to use TLS if
308 : * the \p mode parameter is set to MODE_SECURE. Note that you may force
309 : * a secure connection using MODE_SECURE_REQUIRED. With MODE_SECURE,
310 : * the connection to the server can be obtained even if a secure
311 : * connection could not be made to work.
312 : *
313 : * \todo
314 : * Create another client with BIO_new_socket() so one can create an SSL
315 : * connection with a socket retrieved from an accept() call.
316 : *
317 : * \exception tcp_client_server_parameter_error
318 : * This exception is raised if the \p port parameter is out of range or the
319 : * IP address is an empty string or otherwise an invalid address.
320 : *
321 : * \exception tcp_client_server_initialization_error
322 : * This exception is raised if the client cannot create the socket or it
323 : * cannot connect to the server.
324 : *
325 : * \param[in] addr The address of the server to connect to. It must be valid.
326 : * \param[in] port The port the server is listening on.
327 : * \param[in] mode Whether to use SSL when connecting.
328 : * \param[in] opt Additional options.
329 : */
330 0 : tcp_bio_client::tcp_bio_client(
331 : std::string const & addr
332 : , int port
333 : , mode_t mode
334 : , tcp_bio_options const & opt)
335 0 : : f_impl(new detail::tcp_bio_client_impl)
336 : {
337 0 : if(port < 0 || port >= 65536)
338 : {
339 0 : throw event_dispatcher_invalid_parameter("invalid port for a client socket");
340 : }
341 0 : if(addr.empty())
342 : {
343 0 : throw event_dispatcher_invalid_parameter("an empty address is not valid for a client socket");
344 : }
345 :
346 0 : detail::bio_initialize();
347 :
348 0 : switch(mode)
349 : {
350 : case mode_t::MODE_SECURE:
351 : case mode_t::MODE_ALWAYS_SECURE:
352 : {
353 : // Use TLS v1 only as all versions of SSL are flawed...
354 : // (see below the SSL_CTX_set_options() for additional details
355 : // about that since here it does indeed say SSLv23...)
356 : //
357 0 : std::shared_ptr<SSL_CTX> ssl_ctx; // use a reset(), see SNAP-507
358 0 : ssl_ctx.reset(SSL_CTX_new(SSLv23_client_method()), detail::ssl_ctx_deleter);
359 0 : if(ssl_ctx == nullptr)
360 : {
361 0 : detail::bio_log_errors();
362 0 : throw event_dispatcher_initialization_error("failed creating an SSL_CTX object");
363 : }
364 :
365 : // allow up to 4 certificates in the chain otherwise fail
366 : // (this is not a very strong security feature though)
367 : //
368 0 : SSL_CTX_set_verify_depth(ssl_ctx.get(), opt.get_verification_depth());
369 :
370 : // make sure SSL v2/3 is not used, also compression in SSL is
371 : // known to have security issues
372 : //
373 0 : SSL_CTX_set_options(ssl_ctx.get(), opt.get_ssl_options());
374 :
375 : // limit the number of ciphers the connection can use
376 0 : if(mode == mode_t::MODE_SECURE)
377 : {
378 : // this is used by local connections and we get a very strong
379 : // algorithm anyway, but at this point I do not know why it
380 : // does not work with the limited list below...
381 : //
382 : // TODO: test with adding DH support in the server then
383 : // maybe (probably) that the "HIGH" will work for
384 : // this entry too...
385 : //
386 0 : SSL_CTX_set_cipher_list(ssl_ctx.get(), "ALL");
387 : }
388 : else
389 : {
390 0 : SSL_CTX_set_cipher_list(ssl_ctx.get(), "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4");
391 : }
392 :
393 : // load root certificates (correct path for Ubuntu?)
394 : // TODO: allow client to set the path to certificates
395 0 : if(SSL_CTX_load_verify_locations(ssl_ctx.get(), nullptr, "/etc/ssl/certs") != 1)
396 : {
397 0 : detail::bio_log_errors();
398 0 : throw event_dispatcher_initialization_error("failed loading verification certificates in an SSL_CTX object");
399 : }
400 : //SSL_CTX_set_msg_callback(ssl_ctx.get(), ssl_trace);
401 : //SSL_CTX_set_msg_callback_arg(ssl_ctx.get(), this);
402 :
403 : // create a BIO connected to SSL ciphers
404 : //
405 0 : std::shared_ptr<BIO> bio;
406 0 : bio.reset(BIO_new_ssl_connect(ssl_ctx.get()), detail::bio_deleter);
407 0 : if(!bio)
408 : {
409 0 : detail::bio_log_errors();
410 0 : throw event_dispatcher_initialization_error("failed initializing a BIO object");
411 : }
412 :
413 : // verify that the connection worked
414 : //
415 0 : SSL * ssl(nullptr);
416 : #pragma GCC diagnostic push
417 : #pragma GCC diagnostic ignored "-Wold-style-cast"
418 0 : BIO_get_ssl(bio.get(), &ssl);
419 : #pragma GCC diagnostic pop
420 0 : if(ssl == nullptr)
421 : {
422 : // TBD: does this mean we would have a plain connection?
423 0 : detail::bio_log_errors();
424 0 : throw event_dispatcher_initialization_error("failed retrieving the SSL contact from BIO object");
425 : }
426 :
427 : // allow automatic retries in case the connection somehow needs
428 : // an SSL renegotiation (maybe we should turn that off for cases
429 : // where we connect to a secure payment gateway?)
430 : //
431 0 : SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
432 :
433 : // setup the Server Name Indication (SNI)
434 : //
435 0 : bool using_sni(false);
436 0 : if(opt.get_sni())
437 : {
438 0 : std::string host(opt.get_host());
439 : in6_addr ignore;
440 0 : if(host.empty()
441 0 : && inet_pton(AF_INET, addr.c_str(), &ignore) == 0 // must fail
442 0 : && inet_pton(AF_INET6, addr.c_str(), &ignore) == 0) // must fail
443 : {
444 : // addr is not an IP address written as is,
445 : // it must be a hostname
446 : //
447 0 : host = addr;
448 : }
449 0 : if(!host.empty())
450 : {
451 : #pragma GCC diagnostic push
452 : #pragma GCC diagnostic ignored "-Wold-style-cast"
453 : // not only old style cast (but it's C, so expected)
454 : // but they want a non-constant pointer!?
455 : //
456 0 : SSL_set_tlsext_host_name(ssl, const_cast<char *>(host.c_str()));
457 : #pragma GCC diagnostic pop
458 0 : using_sni = true;
459 : }
460 : }
461 :
462 : // TODO: other SSL initialization?
463 :
464 : #pragma GCC diagnostic push
465 : #pragma GCC diagnostic ignored "-Wold-style-cast"
466 0 : BIO_set_conn_hostname(bio.get(), const_cast<char *>(addr.c_str()));
467 0 : BIO_set_conn_port(bio.get(), const_cast<char *>(std::to_string(port).c_str()));
468 : #pragma GCC diagnostic pop
469 :
470 : // connect to the server (open the socket)
471 : //
472 0 : if(BIO_do_connect(bio.get()) <= 0)
473 : {
474 0 : if(!using_sni)
475 : {
476 : SNAP_LOG_WARNING
477 : << "the SNI feature is turned off,"
478 : " often failure to connect with SSL is because the"
479 : " SSL Hello message is missing the SNI (Server Name In)."
480 0 : " See the tcp_bio_client::options::set_sni().";
481 : }
482 0 : detail::bio_log_errors();
483 0 : throw event_dispatcher_initialization_error("SSL BIO_do_connect() failed connecting BIO object to server");
484 : }
485 :
486 : // encryption handshake
487 : //
488 0 : if(BIO_do_handshake(bio.get()) != 1)
489 : {
490 0 : if(!using_sni)
491 : {
492 : SNAP_LOG_WARNING
493 : << "the SNI feature is turned off,"
494 : " often failure to connect with SSL is because the"
495 : " SSL Hello message is missing the SNI (Server Name In)."
496 0 : " See the tcp_bio_client::options::set_sni().";
497 : }
498 0 : detail::bio_log_errors();
499 : throw event_dispatcher_initialization_error("failed establishing a secure BIO connection with server, handshake failed."
500 : " Often such failures to process SSL is because the SSL Hello message is missing the SNI (Server Name In)."
501 0 : " See the tcp_bio_client::options::set_sni().");
502 : }
503 :
504 : // verify that the peer certificate was signed by a
505 : // recognized root authority
506 : //
507 0 : if(SSL_get_peer_certificate(ssl) == nullptr)
508 : {
509 0 : detail::bio_log_errors();
510 0 : throw event_dispatcher_initialization_error("peer failed presenting a certificate for security verification");
511 : }
512 :
513 : // XXX: check that the call below is similar to the example
514 : // usage of SSL_CTX_set_verify() which checks the name
515 : // of the certificate, etc.
516 : //
517 0 : if(SSL_get_verify_result(ssl) != X509_V_OK)
518 : {
519 0 : if(mode != mode_t::MODE_SECURE)
520 : {
521 0 : detail::bio_log_errors();
522 0 : throw event_dispatcher_initialization_error("peer certificate could not be verified");
523 : }
524 : SNAP_LOG_WARNING
525 0 : << "connecting with SSL but certificate verification failed.";
526 : }
527 :
528 : // it worked, save the results
529 : //
530 0 : f_impl->f_ssl_ctx.swap(ssl_ctx);
531 0 : f_impl->f_bio.swap(bio);
532 :
533 : // secure connection ready
534 : //
535 0 : char const * cipher_name(SSL_get_cipher(ssl));
536 0 : int cipher_bits(0);
537 0 : SSL_get_cipher_bits(ssl, &cipher_bits);
538 : SNAP_LOG_DEBUG
539 0 : << "connected with SSL cipher \""
540 0 : << cipher_name
541 0 : << "\" representing "
542 0 : << cipher_bits
543 0 : << " bits of encryption.";
544 : }
545 0 : break;
546 :
547 : case mode_t::MODE_PLAIN:
548 : {
549 : // create a plain BIO connection
550 : //
551 0 : std::shared_ptr<BIO> bio; // use reset(), see SNAP-507
552 0 : bio.reset(BIO_new(BIO_s_connect()), detail::bio_deleter);
553 0 : if(!bio)
554 : {
555 0 : detail::bio_log_errors();
556 0 : throw event_dispatcher_initialization_error("failed initializing a BIO object");
557 : }
558 :
559 : #pragma GCC diagnostic push
560 : #pragma GCC diagnostic ignored "-Wold-style-cast"
561 0 : BIO_set_conn_hostname(bio.get(), const_cast<char *>(addr.c_str()));
562 0 : BIO_set_conn_port(bio.get(), const_cast<char *>(std::to_string(port).c_str()));
563 : #pragma GCC diagnostic pop
564 :
565 : // connect to the server (open the socket)
566 : //
567 0 : if(BIO_do_connect(bio.get()) <= 0)
568 : {
569 0 : detail::bio_log_errors();
570 0 : throw event_dispatcher_initialization_error("failed connecting BIO object to server");
571 : }
572 :
573 : // it worked, save the results
574 : //
575 0 : f_impl->f_bio.swap(bio);
576 :
577 : // plain connection ready
578 : }
579 0 : break;
580 :
581 : }
582 :
583 0 : if(opt.get_keepalive())
584 : {
585 : // retrieve the socket (we are still in the constructor so avoid
586 : // calling other functions...)
587 : //
588 0 : int socket(-1);
589 : #pragma GCC diagnostic push
590 : #pragma GCC diagnostic ignored "-Wold-style-cast"
591 0 : BIO_get_fd(f_impl->f_bio.get(), &socket);
592 : #pragma GCC diagnostic pop
593 0 : if(socket >= 0)
594 : {
595 : // if this call fails, we ignore the error, but still log the event
596 : //
597 0 : int optval(1);
598 0 : socklen_t const optlen(sizeof(optval));
599 0 : if(setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) != 0)
600 : {
601 : SNAP_LOG_WARNING
602 0 : << "an error occurred trying to mark client socket with SO_KEEPALIVE.";
603 : }
604 : }
605 : }
606 0 : }
607 :
608 :
609 : /** \brief Create a BIO client object from an actual BIO pointer.
610 : *
611 : * This function is called by the server whenever it accepts a new BIO
612 : * connection. The server then can return the tcp_bio_client object instead
613 : * of a BIO object.
614 : *
615 : * The BIO is saved directly in the f_impl class (the server is given access.)
616 : */
617 0 : tcp_bio_client::tcp_bio_client()
618 0 : : f_impl(new detail::tcp_bio_client_impl)
619 : {
620 0 : }
621 :
622 :
623 : /** \brief Clean up the BIO client object.
624 : *
625 : * This function cleans up the BIO client object by freeing the SSL_CTX
626 : * and the BIO objects.
627 : */
628 0 : tcp_bio_client::~tcp_bio_client()
629 : {
630 : // f_bio and f_ssl_ctx are allocated using shared pointers with
631 : // a deleter so we have nothing to do here.
632 0 : }
633 :
634 :
635 : /** \brief Close the connection.
636 : *
637 : * This function closes the connection by losing the f_bio object.
638 : *
639 : * As we are at it, we also lose the SSL context since we are not going
640 : * to use it anymore either.
641 : */
642 0 : void tcp_bio_client::close()
643 : {
644 0 : f_impl->f_bio.reset();
645 0 : f_impl->f_ssl_ctx.reset();
646 0 : }
647 :
648 :
649 : /** \brief Get the socket descriptor.
650 : *
651 : * This function returns the TCP client socket descriptor. This can be
652 : * used to change the descriptor behavior (i.e. make it non-blocking for
653 : * example.)
654 : *
655 : * \note
656 : * If the socket was closed, then the function returns -1.
657 : *
658 : * \warning
659 : * This socket is generally managed by the BIO library and thus it may
660 : * create unwanted side effects to change the socket under the feet of
661 : * the BIO library...
662 : *
663 : * \return The socket descriptor.
664 : */
665 0 : int tcp_bio_client::get_socket() const
666 : {
667 0 : if(f_impl->f_bio)
668 : {
669 : int c;
670 : #pragma GCC diagnostic push
671 : #pragma GCC diagnostic ignored "-Wold-style-cast"
672 0 : BIO_get_fd(f_impl->f_bio.get(), &c);
673 : #pragma GCC diagnostic pop
674 0 : return c;
675 : }
676 :
677 0 : return -1;
678 : }
679 :
680 :
681 : /** \brief Get the TCP client port.
682 : *
683 : * This function returns the port used when creating the TCP client.
684 : * Note that this is the port the server is listening to and not the port
685 : * the TCP client is currently connected to.
686 : *
687 : * \note
688 : * If the connection was closed, return -1.
689 : *
690 : * \return The TCP client port.
691 : */
692 0 : int tcp_bio_client::get_port() const
693 : {
694 0 : if(f_impl->f_bio)
695 : {
696 0 : return std::atoi(BIO_get_conn_port(f_impl->f_bio.get()));
697 : }
698 :
699 0 : return -1;
700 : }
701 :
702 :
703 : /** \brief Get the TCP server address.
704 : *
705 : * This function returns the address used when creating the TCP address as is.
706 : * Note that this is the address of the server where the client is connected
707 : * and not the address where the client is running (although it may be the
708 : * same.)
709 : *
710 : * Use the get_client_addr() function to retrieve the client's TCP address.
711 : *
712 : * \note
713 : * If the connection was closed, this function returns "".
714 : *
715 : * \return The TCP client address.
716 : */
717 0 : std::string tcp_bio_client::get_addr() const
718 : {
719 0 : if(f_impl->f_bio)
720 : {
721 0 : return BIO_get_conn_hostname(f_impl->f_bio.get());
722 : }
723 :
724 0 : return "";
725 : }
726 :
727 :
728 : /** \brief Get the TCP client port.
729 : *
730 : * This function retrieve the port of the client (used on your computer).
731 : * This is retrieved from the socket using the getsockname() function.
732 : *
733 : * \return The port or -1 if it cannot be determined.
734 : */
735 0 : int tcp_bio_client::get_client_port() const
736 : {
737 : // get_socket() returns -1 if f_bio is nullptr
738 : //
739 0 : int const s(get_socket());
740 0 : if(s < 0)
741 : {
742 0 : return -1;
743 : }
744 :
745 : sockaddr addr;
746 0 : socklen_t len(sizeof(addr));
747 0 : int const r(getsockname(s, &addr, &len));
748 0 : if(r != 0)
749 : {
750 0 : return -1;
751 : }
752 : // Note: I know the port is at the exact same location in both
753 : // structures in Linux but it could change on other Unices
754 0 : switch(addr.sa_family)
755 : {
756 : case AF_INET:
757 : // IPv4
758 0 : return reinterpret_cast<sockaddr_in *>(&addr)->sin_port;
759 :
760 : case AF_INET6:
761 : // IPv6
762 0 : return reinterpret_cast<sockaddr_in6 *>(&addr)->sin6_port;
763 :
764 : default:
765 0 : return -1;
766 :
767 : }
768 : snap::NOTREACHED();
769 : }
770 :
771 :
772 : /** \brief Get the TCP client address.
773 : *
774 : * This function retrieve the IP address of the client (your computer).
775 : * This is retrieved from the socket using the getsockname() function.
776 : *
777 : * \note
778 : * The function returns an empty string if the connection was lost
779 : * or purposefully closed.
780 : *
781 : * \return The IP address as a string.
782 : */
783 0 : std::string tcp_bio_client::get_client_addr() const
784 : {
785 : // the socket may be invalid, i.e. f_bio may have been deallocated.
786 : //
787 0 : int const s(get_socket());
788 0 : if(s < 0)
789 : {
790 0 : return std::string();
791 : }
792 :
793 : sockaddr addr;
794 0 : socklen_t len(sizeof(addr));
795 0 : int const r(getsockname(s, &addr, &len));
796 0 : if(r != 0)
797 : {
798 0 : throw event_dispatcher_runtime_error("failed reading address");
799 : }
800 : char buf[BUFSIZ];
801 0 : switch(addr.sa_family)
802 : {
803 : case AF_INET:
804 : // TODO: verify that 'r' >= sizeof(something)
805 0 : inet_ntop(AF_INET, &reinterpret_cast<struct sockaddr_in *>(&addr)->sin_addr, buf, sizeof(buf));
806 0 : break;
807 :
808 : case AF_INET6:
809 : // TODO: verify that 'r' >= sizeof(something)
810 0 : inet_ntop(AF_INET6, &reinterpret_cast<struct sockaddr_in6 *>(&addr)->sin6_addr, buf, sizeof(buf));
811 0 : break;
812 :
813 : default:
814 0 : throw event_dispatcher_runtime_error("unknown address family");
815 :
816 : }
817 0 : return buf;
818 : }
819 :
820 :
821 : /** \brief Read data from the socket.
822 : *
823 : * A TCP socket is a stream type of socket and one can read data from it
824 : * as if it were a regular file. This function reads \p size bytes and
825 : * returns. The function returns early if the server closes the connection.
826 : *
827 : * If your socket is blocking, \p size should be exactly what you are
828 : * expecting or this function will block forever or until the server
829 : * closes the connection.
830 : *
831 : * The function returns -1 if an error occurs. The error is available in
832 : * errno as expected in the POSIX interface.
833 : *
834 : * \note
835 : * If the connection was closed, this function returns -1.
836 : *
837 : * \warning
838 : * When the function returns zero, it is likely that the server closed
839 : * the connection. It may also be that the buffer was empty and that
840 : * the BIO decided to return early. Since we use a blocking mechanism
841 : * by default, that should not happen.
842 : *
843 : * \todo
844 : * At this point, I do not know for sure whether errno is properly set
845 : * or not. It is not unlikely that the BIO library does not keep a clean
846 : * errno error since they have their own error management.
847 : *
848 : * \param[in,out] buf The buffer where the data is read.
849 : * \param[in] size The size of the buffer.
850 : *
851 : * \return The number of bytes read from the socket, or -1 on errors.
852 : *
853 : * \sa read_line()
854 : * \sa write()
855 : */
856 0 : int tcp_bio_client::read(char * buf, size_t size)
857 : {
858 0 : if(!f_impl->f_bio)
859 : {
860 0 : errno = EBADF;
861 0 : return -1;
862 : }
863 :
864 0 : int const r(static_cast<int>(BIO_read(f_impl->f_bio.get(), buf, size)));
865 0 : if(r <= -2)
866 : {
867 : // the BIO is not implemented
868 : //
869 0 : detail::bio_log_errors();
870 0 : errno = EIO;
871 0 : return -1;
872 : }
873 0 : if(r == -1 || r == 0)
874 : {
875 0 : if(BIO_should_retry(f_impl->f_bio.get()))
876 : {
877 0 : errno = EAGAIN;
878 0 : return 0;
879 : }
880 : // did we reach the "end of the file"? i.e. did the server
881 : // close our connection? (this better replicates what a
882 : // normal socket does when reading from a closed socket)
883 : //
884 0 : if(BIO_eof(f_impl->f_bio.get()))
885 : {
886 0 : return 0;
887 : }
888 0 : if(r != 0)
889 : {
890 : // the BIO generated an error
891 0 : detail::bio_log_errors();
892 0 : errno = EIO;
893 0 : return -1;
894 : }
895 : }
896 0 : return r;
897 : }
898 :
899 :
900 : /** \brief Read one line.
901 : *
902 : * This function reads one line from the current location up to the next
903 : * '\\n' character. We do not have any special handling of the '\\r'
904 : * character.
905 : *
906 : * The function may return 0 (an empty string) when the server closes
907 : * the connection.
908 : *
909 : * \note
910 : * If the connection was closed then this function returns -1.
911 : *
912 : * \warning
913 : * A return value of zero can mean "empty line" and not end of file. It
914 : * is up to you to know whether your protocol allows for empty lines or
915 : * not. If so, you may not be able to make use of this function.
916 : *
917 : * \param[out] line The resulting line read from the server. The function
918 : * first clears the contents.
919 : *
920 : * \return The number of bytes read from the socket, or -1 on errors.
921 : * If the function returns 0 or more, then the \p line parameter
922 : * represents the characters read on the network without the '\n'.
923 : *
924 : * \sa read()
925 : */
926 0 : int tcp_bio_client::read_line(std::string & line)
927 : {
928 0 : line.clear();
929 0 : int len(0);
930 0 : for(;;)
931 : {
932 : char c;
933 0 : int r(read(&c, sizeof(c)));
934 0 : if(r <= 0)
935 : {
936 0 : return len == 0 && r < 0 ? -1 : len;
937 : }
938 0 : if(c == '\n')
939 : {
940 0 : return len;
941 : }
942 0 : ++len;
943 0 : line += c;
944 : }
945 : }
946 :
947 :
948 : /** \brief Write data to the socket.
949 : *
950 : * A BIO socket is a stream type of socket and one can write data to it
951 : * as if it were a regular file. This function writes \p size bytes to
952 : * the socket and then returns. This function returns early if the server
953 : * closes the connection.
954 : *
955 : * If your socket is not blocking, less than \p size bytes may be written
956 : * to the socket. In that case you are responsible for calling the function
957 : * again to write the remainder of the buffer until the function returns
958 : * a number of bytes written equal to \p size.
959 : *
960 : * The function returns -1 if an error occurs. The error is available in
961 : * errno as expected in the POSIX interface.
962 : *
963 : * \note
964 : * If the connection was closed, return -1.
965 : *
966 : * \todo
967 : * At this point, I do not know for sure whether errno is properly set
968 : * or not. It is not unlikely that the BIO library does not keep a clean
969 : * errno error since they have their own error management.
970 : *
971 : * \param[in] buf The buffer with the data to send over the socket.
972 : * \param[in] size The number of bytes in buffer to send over the socket.
973 : *
974 : * \return The number of bytes that were actually accepted by the socket
975 : * or -1 if an error occurs.
976 : *
977 : * \sa read()
978 : */
979 0 : int tcp_bio_client::write(char const * buf, size_t size)
980 : {
981 : #ifdef _DEBUG
982 : // This write is useful when developing APIs against 3rd party
983 : // servers, otherwise, it's just too much debug
984 : //SNAP_LOG_TRACE("tcp_bio_client::write(): buf=")(buf)(", size=")(size);
985 : #endif
986 0 : if(!f_impl->f_bio)
987 : {
988 0 : errno = EBADF;
989 0 : return -1;
990 : }
991 :
992 0 : int const r(static_cast<int>(BIO_write(f_impl->f_bio.get(), buf, size)));
993 0 : if(r <= -2)
994 : {
995 : // the BIO is not implemented
996 0 : detail::bio_log_errors();
997 0 : errno = EIO;
998 0 : return -1;
999 : }
1000 0 : if(r == -1 || r == 0)
1001 : {
1002 0 : if(BIO_should_retry(f_impl->f_bio.get()))
1003 : {
1004 0 : errno = EAGAIN;
1005 0 : return 0;
1006 : }
1007 : // the BIO generated an error (TBD should we check BIO_eof() too?)
1008 0 : detail::bio_log_errors();
1009 0 : errno = EIO;
1010 0 : return -1;
1011 : }
1012 0 : BIO_flush(f_impl->f_bio.get());
1013 0 : return r;
1014 : }
1015 :
1016 :
1017 :
1018 6 : } // namespace ed
1019 : // vim: ts=4 sw=4 et
|