From 870739f8a80cc6730c3f03c8df7ceffa7786223b Mon Sep 17 00:00:00 2001 From: Denes Matetelki Date: Wed, 9 Nov 2011 11:38:09 +0100 Subject: [PATCH] TcpClient, not yet multithreaded --- include/Common.hpp | 9 + include/TcpClient.hpp | 45 +++++ other/client | Bin 0 -> 132305 bytes {src => other}/inetSocketClient.cpp | 0 {include => other}/inetSocketClient.hpp | 0 {src => other}/localSocketClient.cpp | 0 {include => other}/localSocketClient.hpp | 0 other/socketClient.cpp | 75 ++++++++ {include => other}/socketClient.hpp | 2 +- other/tcpclient_main.cpp | 32 ++++ src/TcpClient.cpp | 226 +++++++++++++++++++++++ src/socketClient.cpp | 2 +- test/test_ArgParse.hpp | 58 +++++- 13 files changed, 446 insertions(+), 3 deletions(-) create mode 100644 include/TcpClient.hpp create mode 100755 other/client rename {src => other}/inetSocketClient.cpp (100%) rename {include => other}/inetSocketClient.hpp (100%) rename {src => other}/localSocketClient.cpp (100%) rename {include => other}/localSocketClient.hpp (100%) create mode 100644 other/socketClient.cpp rename {include => other}/socketClient.hpp (91%) create mode 100644 other/tcpclient_main.cpp create mode 100644 src/TcpClient.cpp diff --git a/include/Common.hpp b/include/Common.hpp index 668251a..76d3f81 100644 --- a/include/Common.hpp +++ b/include/Common.hpp @@ -13,6 +13,9 @@ #include // runtime_error #include // ostringstream +#include // errno +#include // strerror + const long NANO = 1000000000L; // 10^9 @@ -112,4 +115,10 @@ inline void StrToT( T &t, const std::string s ) ss >> t; } + +inline std::string errnoToString(const char *s) +{ + return std::string(s).append(strerror(errno)); +} + #endif // COMMON_HPP diff --git a/include/TcpClient.hpp b/include/TcpClient.hpp new file mode 100644 index 0000000..1aa07a4 --- /dev/null +++ b/include/TcpClient.hpp @@ -0,0 +1,45 @@ +#ifndef TCP_CLIENT_HPP +#define TCP_CLIENT_HPP + +#include + +#include +#include +#include + + +class TcpClient +{ + +public: + + TcpClient ( const std::string host, + const std::string port ); + + ~TcpClient(); + + bool connect(); + bool disconnect(); + + bool send(const std::string msg); + bool receive(std::string &reply); + + +private: + + bool openSocket(); + bool closeSocket(); + + bool connectToHost(); + bool getHostInfo(struct addrinfo **servinfo); + void printHostDetails(struct addrinfo *servinfo); + bool connectToFirstAddress(struct addrinfo *servinfo); + + int m_socket; + std::string m_host; + std::string m_port; + bool m_connected; + +}; + +#endif // TCP_CLIENT_HPP diff --git a/other/client b/other/client new file mode 100755 index 0000000000000000000000000000000000000000..d2a786c7baa59b44834d2acd898f51641a8d782a GIT binary patch literal 132305 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�!wvT5kX|ci>jbdXhwljokZNe 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 literal 0 HcmV?d00001 diff --git a/src/inetSocketClient.cpp b/other/inetSocketClient.cpp similarity index 100% rename from src/inetSocketClient.cpp rename to other/inetSocketClient.cpp diff --git a/include/inetSocketClient.hpp b/other/inetSocketClient.hpp similarity index 100% rename from include/inetSocketClient.hpp rename to other/inetSocketClient.hpp diff --git a/src/localSocketClient.cpp b/other/localSocketClient.cpp similarity index 100% rename from src/localSocketClient.cpp rename to other/localSocketClient.cpp diff --git a/include/localSocketClient.hpp b/other/localSocketClient.hpp similarity index 100% rename from include/localSocketClient.hpp rename to other/localSocketClient.hpp diff --git a/other/socketClient.cpp b/other/socketClient.cpp new file mode 100644 index 0000000..21c410f --- /dev/null +++ b/other/socketClient.cpp @@ -0,0 +1,75 @@ +#include "socketClient.hpp" + +#include // errno +#include // strerror + +#include + + +SocketClient::SocketClient( const int addrDomain, + const int socketType ) + : m_connected(false) + , m_addrDomain(addrDomain) + , m_socketType(socketType) + , m_socketfd(0) +{ +} + + +SocketClient::~SocketClient() +{ + if ( m_connected && close(m_socketfd) == -1 ) + std::cerr << errorToString("ERROR closing socket. ") << std::endl; +} + + +bool SocketClient::send(const std::string msg) +{ + if ( !m_connected && !this->connect() ) + return false; + + ssize_t n = write(m_socketfd, msg.c_str(), msg.length()); + if (n == -1) { + std::cerr << errorToString("ERROR writing to socket. ") << std::endl; + return false; + } else if ( n < (ssize_t)msg.length() ) { + std::cerr << "Only a part of msg has been written to socket. " << std::endl; + return false; + } + + return true; +} + + +bool SocketClient::receive(std::string &reply) +{ + if ( !m_connected && !this->connect() ) + return false; + + char buffer[256]; + ssize_t n = read(m_socketfd, buffer, 255); + if (n == -1) { + std::cerr << errorToString("ERROR reading from socket. ") << std::endl; + return false; + } + reply = std::string(buffer, n); + + return true; +} + + +bool SocketClient::connect(void) +{ + m_socketfd = socket(m_addrDomain, m_socketType, 0); + if ( m_socketfd == -1 ) { + std::cerr << errorToString("ERROR opening socket. ") << std::endl; + return false; + } + + return connectToPeer(); +} + +std::string SocketClient::errnoToString(const char *s) const +{ + return std::string(s).append(strerror(errno)); +} \ No newline at end of file diff --git a/include/socketClient.hpp b/other/socketClient.hpp similarity index 91% rename from include/socketClient.hpp rename to other/socketClient.hpp index c6b4ac9..6551969 100644 --- a/include/socketClient.hpp +++ b/other/socketClient.hpp @@ -24,7 +24,7 @@ protected: bool connect(void); virtual bool connectToPeer(void) = 0; - std::string errorToString(const char *s) const; + std::string errnoToString(const char *s) const; bool m_connected; int m_addrDomain; diff --git a/other/tcpclient_main.cpp b/other/tcpclient_main.cpp new file mode 100644 index 0000000..6acfbb0 --- /dev/null +++ b/other/tcpclient_main.cpp @@ -0,0 +1,32 @@ +// gpp tcpclient_main.cpp -o client -I../include ../src/Logger.cpp ../src/TcpClient.cpp + +#include "TcpClient.hpp" + +#include "Logger.hpp" + +#include +#include + +int main( int argc, char * argv[] ) +{ + Logger::createInstance(); + Logger::init(std::cout); + Logger::setLogLevel(Logger::FINEST); + + TcpClient tcpclient("localhost", "4455"); + + tcpclient.connect(); + + tcpclient.send("madao"); + + std::string reply; + tcpclient.receive(reply); + std::cout << "got reply \"" << reply << "\"" << std::endl; + + tcpclient.disconnect(); + + + + Logger::destroy(); + return 0; +} \ No newline at end of file diff --git a/src/TcpClient.cpp b/src/TcpClient.cpp new file mode 100644 index 0000000..0e2e2c7 --- /dev/null +++ b/src/TcpClient.cpp @@ -0,0 +1,226 @@ +#include "TcpClient.hpp" + +#include "Logger.hpp" +#include "Common.hpp" + +#include +#include +#include // inet_ntop + + +TcpClient::TcpClient( const std::string host, + const std::string port ) + : m_socket(-1) + , m_host(host) + , m_port(port) + , m_connected(false) +{ + TRACE; +} + +TcpClient::~TcpClient() +{ + TRACE; + + disconnect(); +} + + +bool TcpClient::connect() +{ + TRACE; + + if ( !openSocket() ) + return false; + + if ( !connectToHost() ) + return false; + + m_connected = true; + return true; +} + + +bool TcpClient::disconnect() +{ + TRACE; + + if ( !closeSocket() ) + return false; + + return true; +} + + +bool TcpClient::send(const std::string msg) +{ + TRACE; + + ssize_t n = write(m_socket, msg.c_str(), msg.length()); + if (n == -1) { + LOG( Logger::ERR, errnoToString("ERROR writing to socket. ").c_str() ); + return false; + } + + return true; +} + + +bool TcpClient::receive(std::string &reply) +{ + TRACE; + + char buffer[256]; + ssize_t n = read(m_socket, buffer, 255); + if (n == -1) { + LOG( Logger::ERR, errnoToString("ERROR reading from socket. ").c_str() ); + return false; + } + reply = std::string(buffer, n); + + return true; +} + + +bool TcpClient::openSocket() +{ + TRACE; + + m_socket = socket(AF_INET, SOCK_STREAM, 0); + if ( m_socket == -1 ) { + LOG( Logger::ERR, errnoToString("ERROR opening socket. ").c_str() ); + return false; + } + + return true; +} + + +bool TcpClient::closeSocket() +{ + TRACE; + + /// @note are the return values of shutdown and close meaningful? + // if ( shutdown(m_socket, SHUT_RDWR) == -1 ) { + // LOG( Logger::ERR, errnoToString("ERROR shuting down socket. ").c_str() ); + // return false; + // } + // + // if ( close(m_socket) == -1 ) { + // LOG( Logger::ERR, errnoToString("ERROR closing socket. ").c_str() ); + // return false; + // } + + shutdown(m_socket, SHUT_RDWR); + close(m_socket); + m_socket = -1; + + return true; +} + +bool TcpClient::connectToHost() +{ + TRACE; + + struct addrinfo *results(0); + if ( !getHostInfo(&results) ) + return false; + + printHostDetails(results); + + if ( !connectToFirstAddress(results) ) + return false; + + freeaddrinfo(results); + return true; +} + + +bool TcpClient::getHostInfo(struct addrinfo **servinfo) +{ + TRACE; + + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6 + hints.ai_socktype = SOCK_DGRAM; // Datagram socket + hints.ai_flags = AI_PASSIVE; // For wildcard IP address + hints.ai_protocol = 0; // Any protocol + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + + struct addrinfo *results; + int status = getaddrinfo(m_host.c_str(), m_port.c_str(), &hints, &results); + + if (status != 0) { + LOG( Logger::ERR, std::string("Error at network address translation: "). + append(gai_strerror(status)).c_str() ) ; + return false; + } + + *servinfo = results; + return true; +} + + +void TcpClient::printHostDetails(struct addrinfo *servinfo) +{ + TRACE; + + int counter(0); + for ( struct addrinfo *it = servinfo; it != 0; it = it->ai_next) { + + counter++; + void *addr; + std::string ipver; + + if ( it->ai_family == AF_INET) { // IPv4 + struct sockaddr_in *ipv4 = (struct sockaddr_in *)it->ai_addr; + addr = &(ipv4->sin_addr); + ipver = "IPv4"; + } else { // IPv6 + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)it->ai_addr; + addr = &(ipv6->sin6_addr); + ipver = "IPv6"; + } + char ipstr[INET6_ADDRSTRLEN]; + inet_ntop( it->ai_family, addr, ipstr, sizeof ipstr ); + + LOG( Logger::DEBUG, std::string(TToStr(counter)).append(". address is "). + append(ipver).append(": "). + append(ipstr).c_str() ); + } +} + + +bool TcpClient::connectToFirstAddress(struct addrinfo *servinfo) +{ + TRACE; + + for ( struct addrinfo *it = servinfo; it != 0; it = it->ai_next) + if (::connect(m_socket, it->ai_addr, it->ai_addrlen) != -1) { + char hostBuffer[256]; + char serviceBuffer[256]; + int status = getnameinfo( it->ai_addr, it->ai_addrlen, + hostBuffer, sizeof(hostBuffer), + serviceBuffer, sizeof(serviceBuffer), + NI_NAMEREQD ); + + if ( status != 0 ) { + LOG( Logger::WARNING, std::string("Could not resolve hostname. "). + append(gai_strerror(status)).c_str() ); + } else { + LOG( Logger::DEBUG, std::string("Connected to "). + append(hostBuffer).append(":"). + append(serviceBuffer).c_str() ); + } + return true; + } + + LOG( Logger::ERR, std::string("Could not connect to host," + " connection refused.").c_str() ); + return false; +} diff --git a/src/socketClient.cpp b/src/socketClient.cpp index 2cab8e1..424eba4 100644 --- a/src/socketClient.cpp +++ b/src/socketClient.cpp @@ -69,7 +69,7 @@ bool SocketClient::connect(void) return connectToPeer(); } -std::string SocketClient::errorToString(const char *s) const +std::string SocketClient::errnoToString(const char *s) { return std::string(s).append(strerror(errno)); } \ No newline at end of file diff --git a/test/test_ArgParse.hpp b/test/test_ArgParse.hpp index 1da40d0..1323044 100644 --- a/test/test_ArgParse.hpp +++ b/test/test_ArgParse.hpp @@ -8,6 +8,7 @@ #include "ArgParse.hpp" #include +#include class TestArgParseSuite : public CxxTest::TestSuite { @@ -46,7 +47,7 @@ public: TS_ASSERT_EQUALS( argParse.findKeyinArgMap("-r"), argParse.m_params.end() ); } - void asdtestAddArgs( void ) + void testAddArgs( void ) { TEST_HEADER; @@ -70,4 +71,59 @@ public: TS_ASSERT_EQUALS( argParse.foundArg("-u, --user"), true ); } + void testBadAddArgs( void ) + { + TEST_HEADER; + + ArgParse argParse("intro", "outro"); + + TS_ASSERT_THROWS( argParse.addArgument("s", "no dash"), + std::logic_error); + + TS_ASSERT_THROWS( argParse.addArgument("-i", "bad range", ArgParse::INT, + ArgParse::OPTIONAL, ArgParse::OPTIONAL, "", "12..forever"), + std::logic_error); + + TS_ASSERT_THROWS( argParse.addArgument("-i", "bad range", ArgParse::FLOAT, + ArgParse::OPTIONAL, ArgParse::OPTIONAL, "", "12.34..forever"), + std::logic_error); + } + + void testgetArgs( void ) + { + TEST_HEADER; + + ArgParse argParse("intro", "outro"); + + argParse.addArgument("-i", "int", ArgParse::INT); + argParse.addArgument("-f", "float", ArgParse::FLOAT); + argParse.addArgument("-n", "none", ArgParse::NONE); + argParse.addArgument("-s", "string", ArgParse::STRING); + argParse.addArgument("-b", "bool", ArgParse::BOOL); + + int argc = 10; + char *argv[] = { (char*)"test", + (char*)"-i", (char*)"12", + (char*)"-f", (char*)"12.12", + (char*)"-n", + (char*)"-s", (char*)"forever", + (char*)"-b", (char*)"false" }; + + argParse.parseArgs(argc, argv); + + int i; + float f; + std::string s; + bool b; + + TS_ASSERT_EQUALS( argParse.argAsInt("-i", i), true ); + TS_ASSERT_EQUALS( argParse.argAsFloat("-f", f), true ); + TS_ASSERT_EQUALS( argParse.argAsString("-s", s), true ); + TS_ASSERT_EQUALS( argParse.argAsBool("-b", b), true ); + + TS_ASSERT_EQUALS(i, 12 ); + TS_ASSERT_DELTA(f, 12.12, 0.01 ); + TS_ASSERT_EQUALS(s, std::string("forever") ); + TS_ASSERT_EQUALS(b, false ); + } };