Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-14 09:07:59

0001 // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
0002 // Distributed under the MIT License (http://opensource.org/licenses/MIT)
0003 
0004 #pragma once
0005 
0006 #ifdef _WIN32
0007     #error include tcp_client-windows.h instead
0008 #endif
0009 
0010 // tcp client helper
0011 #include <spdlog/common.h>
0012 #include <spdlog/details/os.h>
0013 
0014 #include <arpa/inet.h>
0015 #include <netdb.h>
0016 #include <netinet/in.h>
0017 #include <netinet/tcp.h>
0018 #include <sys/socket.h>
0019 #include <unistd.h>
0020 
0021 #include <string>
0022 
0023 namespace spdlog {
0024 namespace details {
0025 class tcp_client {
0026     int socket_ = -1;
0027 
0028 public:
0029     bool is_connected() const { return socket_ != -1; }
0030 
0031     void close() {
0032         if (is_connected()) {
0033             ::close(socket_);
0034             socket_ = -1;
0035         }
0036     }
0037 
0038     int fd() const { return socket_; }
0039 
0040     ~tcp_client() { close(); }
0041 
0042     // try to connect or throw on failure
0043     void connect(const std::string &host, int port) {
0044         close();
0045         struct addrinfo hints {};
0046         memset(&hints, 0, sizeof(struct addrinfo));
0047         hints.ai_family = AF_UNSPEC;      // To work with IPv4, IPv6, and so on
0048         hints.ai_socktype = SOCK_STREAM;  // TCP
0049         hints.ai_flags = AI_NUMERICSERV;  // port passed as as numeric value
0050         hints.ai_protocol = 0;
0051 
0052         auto port_str = std::to_string(port);
0053         struct addrinfo *addrinfo_result;
0054         auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result);
0055         if (rv != 0) {
0056             throw_spdlog_ex(fmt_lib::format("::getaddrinfo failed: {}", gai_strerror(rv)));
0057         }
0058 
0059         // Try each address until we successfully connect(2).
0060         int last_errno = 0;
0061         for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) {
0062 #if defined(SOCK_CLOEXEC)
0063             const int flags = SOCK_CLOEXEC;
0064 #else
0065             const int flags = 0;
0066 #endif
0067             socket_ = ::socket(rp->ai_family, rp->ai_socktype | flags, rp->ai_protocol);
0068             if (socket_ == -1) {
0069                 last_errno = errno;
0070                 continue;
0071             }
0072             rv = ::connect(socket_, rp->ai_addr, rp->ai_addrlen);
0073             if (rv == 0) {
0074                 break;
0075             }
0076             last_errno = errno;
0077             ::close(socket_);
0078             socket_ = -1;
0079         }
0080         ::freeaddrinfo(addrinfo_result);
0081         if (socket_ == -1) {
0082             throw_spdlog_ex("::connect failed", last_errno);
0083         }
0084 
0085         // set TCP_NODELAY
0086         int enable_flag = 1;
0087         ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *>(&enable_flag),
0088                      sizeof(enable_flag));
0089 
0090         // prevent sigpipe on systems where MSG_NOSIGNAL is not available
0091 #if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
0092         ::setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast<char *>(&enable_flag),
0093                      sizeof(enable_flag));
0094 #endif
0095 
0096 #if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
0097     #error "tcp_sink would raise SIGPIPE since neither SO_NOSIGPIPE nor MSG_NOSIGNAL are available"
0098 #endif
0099     }
0100 
0101     // Send exactly n_bytes of the given data.
0102     // On error close the connection and throw.
0103     void send(const char *data, size_t n_bytes) {
0104         size_t bytes_sent = 0;
0105         while (bytes_sent < n_bytes) {
0106 #if defined(MSG_NOSIGNAL)
0107             const int send_flags = MSG_NOSIGNAL;
0108 #else
0109             const int send_flags = 0;
0110 #endif
0111             auto write_result =
0112                 ::send(socket_, data + bytes_sent, n_bytes - bytes_sent, send_flags);
0113             if (write_result < 0) {
0114                 close();
0115                 throw_spdlog_ex("write(2) failed", errno);
0116             }
0117 
0118             if (write_result == 0)  // (probably should not happen but in any case..)
0119             {
0120                 break;
0121             }
0122             bytes_sent += static_cast<size_t>(write_result);
0123         }
0124     }
0125 };
0126 }  // namespace details
0127 }  // namespace spdlog