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