/* */ #include "SocketCore.h" #include #include #include #include #include #include #include #include #include #include "DlRetryEx.h" #include "DlAbortEx.h" #include #include "message.h" SocketCore::SocketCore():sockfd(-1), use(1), secure(false) #ifdef HAVE_LIBSSL // for SSL , sslCtx(NULL), ssl(NULL) #endif // HAVE_LIBSSL {} SocketCore::~SocketCore() { closeConnection(); } void SocketCore::establishConnection(string host, int port) { sockfd = socket(AF_INET, SOCK_STREAM, 0); if(sockfd >= 0) { socklen_t sockopt = 1; if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) < 0) { close(sockfd); sockfd = -1; throw new DlAbortEx(strerror(errno)); } } else { throw new DlAbortEx(strerror(errno)); } struct sockaddr_in sockaddr; memset((char*)&sockaddr, 0, sizeof(sockaddr)); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(port); if(inet_aton(host.c_str(), &sockaddr.sin_addr)) { // ok } else { struct addrinfo ai; ai.ai_flags = 0; ai.ai_family = PF_INET; ai.ai_socktype = SOCK_STREAM; ai.ai_protocol = 0; ai.ai_addr = (struct sockaddr*)&sockaddr; struct addrinfo* res; int ec; if((ec = getaddrinfo(host.c_str(), NULL, &ai, &res)) != 0) { throw new DlAbortEx(gai_strerror(ec)); } sockaddr.sin_addr = ((struct sockaddr_in*)res->ai_addr)->sin_addr; freeaddrinfo(res); } // make socket non-blocking mode int flags = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, flags|O_NONBLOCK); if(connect(sockfd, (struct sockaddr*)&sockaddr, (socklen_t)sizeof(sockaddr)) == -1 && errno != EINPROGRESS) { throw new DlAbortEx(strerror(errno)); } } void SocketCore::setNonBlockingMode() { int flags = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, flags&~O_NONBLOCK); } void SocketCore::closeConnection() { #ifdef HAVE_LIBSSL // for SSL if(secure) { SSL_shutdown(ssl); } #endif // HAVE_LIBSSL if(sockfd != -1) { close(sockfd); sockfd = -1; } #ifdef HAVE_LIBSSL // for SSL if(secure) { SSL_free(ssl); SSL_CTX_free(sslCtx); ssl = NULL; sslCtx = NULL; } #endif // HAVE_LIBSSL } bool SocketCore::isWritable(int timeout) { fd_set fds; FD_ZERO(&fds); FD_SET(sockfd, &fds); struct timeval tv; tv.tv_sec = timeout; tv.tv_usec = 0; int r = select(sockfd+1, NULL, &fds, NULL, &tv); if(r == 1) { return true; } else if(r == 0) { // time out return false; } else { throw new DlRetryEx(strerror(errno)); } } bool SocketCore::isReadable(int timeout) { fd_set fds; FD_ZERO(&fds); FD_SET(sockfd, &fds); struct timeval tv; tv.tv_sec = timeout; tv.tv_usec = 0; int r = select(sockfd+1, &fds, NULL, NULL, &tv); if(r == 1) { return true; } else if(r == 0) { // time out return false; } else { throw new DlRetryEx(strerror(errno)); } } void SocketCore::writeData(const char* data, int len, int timeout) { if(!isWritable(timeout) || !secure && send(sockfd, data, (size_t)len, 0) != len #ifdef HAVE_LIBSSL // for SSL // TODO handling len == 0 case required || secure && SSL_write(ssl, data, len) != len #endif // HAVE_LIBSSL ) { throw new DlRetryEx(strerror(errno)); } } void SocketCore::readData(char* data, int& len, int timeout) { if(!isReadable(timeout) || !secure && (len = recv(sockfd, data, (size_t)len, 0)) < 0 #ifdef HAVE_LIBSSL // for SSL // TODO handling len == 0 case required || secure && (len = SSL_read(ssl, data, len)) < 0 #endif // HAVE_LIBSSL ) { throw new DlRetryEx(strerror(errno)); } } void SocketCore::peekData(char* data, int& len, int timeout) { if(!isReadable(timeout) || !secure && (len = recv(sockfd, data, (size_t)len, MSG_PEEK)) < 0 #ifdef HAVE_LIBSSL // for SSL // TODO handling len == 0 case required || secure && (len == SSL_peek(ssl, data, len)) < 0 #endif // HAVE_LIBSSL ) { throw new DlRetryEx(strerror(errno)); } } #ifdef HAVE_LIBSSL // for SSL void SocketCore::initiateSecureConnection() { if(!secure) { sslCtx = SSL_CTX_new(SSLv23_client_method()); if(sslCtx == NULL) { throw new DlAbortEx(EX_SSL_INIT_FAILURE); } SSL_CTX_set_mode(sslCtx, SSL_MODE_AUTO_RETRY); ssl = SSL_new(sslCtx); if(ssl == NULL) { throw new DlAbortEx(EX_SSL_INIT_FAILURE); } if(SSL_set_fd(ssl, sockfd) == 0) { throw new DlAbortEx(EX_SSL_INIT_FAILURE); } // TODO handling return value == 0 case required if(SSL_connect(ssl) <= 0) { throw new DlAbortEx(EX_SSL_INIT_FAILURE); } secure = true; } } #endif // HAVE_LIBSSL