22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
31 #include "glog/logging.h"
32 #include "socket_wrapper.h"
38 SocketWrapper::SocketWrapper(
const std::string& host,
int port,
bool use_ssl,
bool nonblocking)
39 : ctx_(nullptr), ssl_(nullptr), host_(host), port_(port), nonblocking_(nonblocking), fd_(-1) {
43 OpenSSL_add_all_algorithms();
44 ctx_ = SSL_CTX_new(SSLv23_client_method());
47 throw std::runtime_error(
"Failed Setting up SSL environment.");
48 SSL_set_mode(ssl_, SSL_MODE_AUTO_RETRY);
51 SocketWrapper::~SocketWrapper() {
53 LOG(INFO) <<
"Not connected so no cleanup needed";
55 LOG(INFO) <<
"Closing socket with fd " << fd_;
57 PLOG(ERROR) <<
"Error closing socket fd " << fd_;
60 if(ssl_) SSL_free(ssl_);
61 if(ctx_) SSL_CTX_free(ctx_);
65 LOG(INFO) <<
"Connecting to " << host_ <<
":" << port_;
67 struct addrinfo hints;
68 memset(&hints, 0,
sizeof(
struct addrinfo));
71 hints.ai_family = PF_UNSPEC;
72 hints.ai_socktype = SOCK_STREAM;
73 hints.ai_protocol = IPPROTO_TCP;
74 hints.ai_flags = AI_NUMERICSERV;
76 struct addrinfo* result;
78 string port_str = std::to_string(port_);
80 if (
int res = getaddrinfo(host_.c_str(), port_str.c_str(), &hints, &result) != 0) {
81 LOG(ERROR) <<
"Could not resolve host " << host_ <<
" port " << port_ <<
": "
88 for (ai = result; ai != NULL; ai = ai->ai_next) {
89 char host[NI_MAXHOST];
90 char service[NI_MAXSERV];
91 if (
int res = getnameinfo(ai->ai_addr, ai->ai_addrlen, host,
sizeof(host), service,
92 sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
93 LOG(ERROR) <<
"Could not get name info: " << gai_strerror(res);
96 LOG(INFO) <<
"Trying to connect to " << string(host) <<
" on " << string(service);
99 socket_fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
101 if (socket_fd == -1) {
102 LOG(WARNING) <<
"Could not create socket";
107 int current_fd_flags = fcntl(socket_fd, F_GETFD);
108 if (current_fd_flags == -1) {
109 PLOG(ERROR) <<
"Failed to get socket fd flags";
113 if (fcntl(socket_fd, F_SETFD, current_fd_flags | FD_CLOEXEC) == -1) {
114 PLOG(ERROR) <<
"Failed to set socket close-on-exit";
124 int setsockopt_result = setsockopt(socket_fd, SOL_SOCKET, SO_NOSIGPIPE, &set,
sizeof(set));
126 if (setsockopt_result != 0 && setsockopt_result != ENOTSOCK) {
127 PLOG(ERROR) <<
"Failed to set SO_NOSIGPIPE on socket";
133 if (connect(socket_fd, ai->ai_addr, ai->ai_addrlen) == -1) {
134 PLOG(WARNING) <<
"Unable to connect";
139 if (nonblocking_ && fcntl(socket_fd, F_SETFL, O_NONBLOCK) != 0) {
140 PLOG(ERROR) <<
"Failed to set socket nonblocking";
148 freeaddrinfo(result);
152 LOG(ERROR) <<
"Could not connect to " << host_ <<
" on port " << port_;
157 if(ssl_)
return ConnectSSL();
161 #include <openssl/err.h>
163 bool SocketWrapper::ConnectSSL()
165 SSL_set_fd(ssl_,fd_);
166 int rtn = SSL_connect(ssl_);
170 int err = SSL_get_error(ssl_, rtn);
171 if( err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE ){
172 fd_set read_fds, write_fds;
173 FD_ZERO(&read_fds); FD_ZERO(&write_fds);
174 if(err == SSL_ERROR_WANT_READ) FD_SET(fd_, &read_fds);
175 if(err == SSL_ERROR_WANT_WRITE) FD_SET(fd_, &write_fds);
176 struct timeval tv = {1,1};
177 select(fd_+1, &read_fds, &write_fds, NULL, &tv);
SSL * getSSL()
Returns nullptr if SSL hasn't been initialized.
bool Connect()
Actually open the connection to the socket. The details of the host/port/protocol to connect on depen...