From ca4c07089731f34e76f6514fd88ff2a09280e2dc Mon Sep 17 00:00:00 2001 From: Brian Aker Date: Sun, 28 Oct 2012 21:01:47 -0400 Subject: [PATCH] Add in missing files. --- libtest/client.cc | 298 +++++++++++++++++++++++++++++++++++++++++++++ libtest/client.hpp | 77 ++++++++++++ 2 files changed, 375 insertions(+) create mode 100644 libtest/client.cc create mode 100644 libtest/client.hpp diff --git a/libtest/client.cc b/libtest/client.cc new file mode 100644 index 00000000..d8378191 --- /dev/null +++ b/libtest/client.cc @@ -0,0 +1,298 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Data Differential YATL (i.e. libtest) library + * + * Copyright (C) 2012 Data Differential, http://datadifferential.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "mem_config.h" + +#include + +#ifdef HAVE_POLL_H +# include +#endif + +#include +#include +#include +#include + + +namespace libtest { + +SimpleClient::SimpleClient(const std::string& hostname_, in_port_t port_) : + _hostname(hostname_), + _port(port_), + sock_fd(INVALID_SOCKET), + requested_message(1) + { + } + +bool SimpleClient::ready(int event_) +{ + struct pollfd fds[1]; + fds[0].fd= sock_fd; + fds[0].events= event_; + fds[0].revents= 0; + + int ready_fds= poll(fds, 1, 5000); + + if (ready_fds == -1) + { + _error= strerror(errno); + return false; + } + else if (ready_fds == 1) + { + if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) + { + int err; + socklen_t len= sizeof (err); + // We replace errno with err if getsockopt() passes, but err has been + // set. + if (getsockopt(fds[0].fd, SOL_SOCKET, SO_ERROR, &err, &len) == 0) + { + // We check the value to see what happened wth the socket. + if (err == 0) + { + _error= "getsockopt() returned no error but poll() indicated one existed"; + return false; + } + errno= err; + } + _error= strerror(errno); + + return false; + } + + if (fds[0].revents & event_) + { + return true; + } + } + + fatal_assert(ready_fds == 0); + _error= "TIMEOUT"; + + return false; +} + +struct addrinfo* SimpleClient::lookup() +{ + struct addrinfo *ai= NULL; + struct addrinfo hints; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_socktype= SOCK_STREAM; + hints.ai_protocol= IPPROTO_TCP; + + char service[NI_MAXSERV]; + (void)snprintf(service, NI_MAXSERV, "%d", _port); + + int getaddrinfo_error; + if ((getaddrinfo_error= getaddrinfo(_hostname.c_str(), service, &hints, &ai)) != 0) + { + if (getaddrinfo_error != EAI_SYSTEM) + { + _error= gai_strerror(getaddrinfo_error); + return NULL; + } + else + { + _error= strerror(getaddrinfo_error); + return NULL; + } + } + + return ai; +} + +SimpleClient::~SimpleClient() +{ + close_socket(); +} + +void SimpleClient::close_socket() +{ + close(sock_fd); + sock_fd= INVALID_SOCKET; +} + +bool SimpleClient::instance_connect() +{ + struct addrinfo *ai; + if ((ai= lookup())) + { + { + struct addrinfo* address_info_next= ai; + + while (address_info_next and sock_fd == INVALID_SOCKET) + { + if ((sock_fd= socket(address_info_next->ai_family, address_info_next->ai_socktype, address_info_next->ai_protocol)) != SOCKET_ERROR) + { + if (connect(sock_fd, address_info_next->ai_addr, address_info_next->ai_addrlen) == SOCKET_ERROR) + { + close_socket(); + _error= strerror(errno); + } + } + else + { + fatal_message(strerror(errno)); + } + address_info_next= address_info_next->ai_next; + } + + freeaddrinfo(ai); + } + + if (sock_fd == INVALID_SOCKET) + { + fatal_assert(_error.size()); + } + + return bool(sock_fd != INVALID_SOCKET); + } + + return false; +} + +bool SimpleClient::is_valid() +{ + _error.clear(); + if (sock_fd == INVALID_SOCKET) + { + return instance_connect(); + } + + return true; +} + +bool SimpleClient::message(const std::string& arg) +{ + if (is_valid()) + { + if (ready(POLLOUT)) + { + off_t offset= 0; + const char* ptr= arg.c_str(); + size_t len= arg.size(); + + do + { + ssize_t nw= send(sock_fd, ptr + offset, len - offset, MSG_NOSIGNAL); + if (nw == -1) + { + if (errno != EINTR) + { + _error= strerror(errno); + return false; + } + } + else + { + offset += nw; + } + } while (offset < ssize_t(len)); + + return true; + } + } + + fatal_assert(_error.size()); + + return false; +} + +bool SimpleClient::send_message(const std::string& arg) +{ + if (message(arg) == true) + { + return message("\r\n"); + } + + return false; +} + +bool SimpleClient::send_message(const std::string& message_, std::string& response_) +{ + requested_message++; + if (send_message(message_)) + { + return response(response_); + } + + return false; +} + +bool SimpleClient::response(std::string& response_) +{ + response_.clear(); + + if (is_valid()) + { + if (ready(POLLIN)) + { + bool more= true; + char buffer[2]; + buffer[1]= 0; + do + { + ssize_t nr= recv(sock_fd, buffer, 1, MSG_NOSIGNAL); + if (nr == -1) + { + if (errno != EINTR) + { + _error= strerror(errno); + return false; + } + } + else + { + fatal_assert(nr == 1); + if (buffer[0] == '\n') + { + more= false; + } + response_.append(buffer); + } + } while (more); + + return response_.size(); + } + } + + fatal_assert(_error.size()); + return false; +} + +} // namespace libtest diff --git a/libtest/client.hpp b/libtest/client.hpp new file mode 100644 index 00000000..25d0992f --- /dev/null +++ b/libtest/client.hpp @@ -0,0 +1,77 @@ +/* vim:expandtab:shiftwidth=2:tabstop=2:smarttab: + * + * Data Differential YATL (i.e. libtest) library + * + * Copyright (C) 2012 Data Differential, http://datadifferential.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * The names of its contributors may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#pragma once + +namespace libtest { + +class SimpleClient { +public: + SimpleClient(const std::string& hostname_, in_port_t port_); + ~SimpleClient(); + + bool send_message(const std::string& arg); + bool send_message(const std::string& message_, std::string& response_); + bool response(std::string&); + + bool is_valid(); + + const std::string& error() const + { + return _error; + } + + bool is_error() const + { + return _error.size(); + } + +private: // Methods + void close_socket(); + bool instance_connect(); + struct addrinfo* lookup(); + bool message(const std::string&); + bool ready(int event_); + +private: + std::string _hostname; + in_port_t _port; + int sock_fd; + std::string _error; + int requested_message; +}; + +} // namespace libtest -- 2.30.2