diff --git a/include/Socket.hpp b/include/Socket.hpp index 55efc5a..821cc9c 100644 --- a/include/Socket.hpp +++ b/include/Socket.hpp @@ -21,19 +21,35 @@ public: bool connectToHost(const std::string host, const std::string port); - bool getHostInfo(const std::string host, - const std::string port, - struct addrinfo **servinfo) const; - void printHostDetails(struct addrinfo *servinfo) const; - bool connectToFirstAddress(struct addrinfo *servinfo) const; + bool bindToHost(const std::string host, + const std::string port ); + protected: - int m_socket; + int m_socket; + + int m_domain; + int m_type; + int m_protocol; + + sockaddr m_addr; + socklen_t m_addrLen; + + static bool convertNameInfo( sockaddr* addr, + socklen_t addrLen, + std::string &retAddr, + std::string &retService); + +private: + + bool connectToFirstAddress(struct addrinfo *servinfo); + bool bindToFirstAddress(struct addrinfo *servinfo); - int m_domain; - int m_type; - int m_protocol; + static bool getHostInfo(const std::string host, + const std::string port, + struct addrinfo **servinfo); + static void printHostDetails(struct addrinfo *servinfo); }; diff --git a/include/TcpServer.hpp b/include/TcpServer.hpp new file mode 100644 index 0000000..a776ba9 --- /dev/null +++ b/include/TcpServer.hpp @@ -0,0 +1,45 @@ +#ifndef TCP_SERVER_HPP +#define TCP_SERVER_HPP + +#include "Socket.hpp" + +#include +#include + +class TcpServer : public Socket +{ +public: + + TcpServer ( const std::string host, + const std::string port, + const int maxClients = 5 ); + + virtual ~TcpServer(); + + bool start(); + void stop(); + + virtual void msgArrived(const int clientSocket, + const std::string msg) = 0; + +private: + + TcpServer(const TcpServer&); + TcpServer& operator=(const TcpServer&); + + bool receive(const int clientSocket); + + void addFd( int fd, short events ); + void removeFd( int fd ); + + std::string m_host; + std::string m_port; + nfds_t m_maxclients; + bool m_running; + pollfd *m_fds; + nfds_t m_num_of_fds; + sockaddr m_addr; + socklen_t m_addrLen; +}; + +#endif // TCP_SERVER_HPP diff --git a/include/Thread.hpp b/include/Thread.hpp index 69d70d7..bb9957b 100644 --- a/include/Thread.hpp +++ b/include/Thread.hpp @@ -15,6 +15,7 @@ public: void* join() const; virtual void stop(); void sendSignal( const int nSignal ) const; + bool isRunning() const; private: diff --git a/other/tcpserver_main.cpp b/other/tcpserver_main.cpp new file mode 100644 index 0000000..f7cd81b --- /dev/null +++ b/other/tcpserver_main.cpp @@ -0,0 +1,49 @@ +// gpp tcpServer_main.cpp -o client -I../include ../src/Logger.cpp ../src/TcpClient.cpp + +#include "TcpServer.hpp" + +#include "Logger.hpp" + +#include +#include + +class EchoTcpServer : public TcpServer +{ +public: + + EchoTcpServer ( const std::string host, + const std::string port, + const int maxClients = 5 ) + : TcpServer(host, port, maxClients) + { + TRACE; + } + + void msgArrived(const int clientSocket, + const std::string msg) + { + TRACE; + + LOG( Logger::DEBUG, std::string("Got msg: ").append(msg).c_str() ); + } + +}; + + +int main( int argc, char * argv[] ) +{ + Logger::createInstance(); + Logger::init(std::cout); + Logger::setLogLevel(Logger::FINEST); + + EchoTcpServer tcpServer("localhost", "4455"); + + tcpServer.start(); + + sleep(10); + + tcpServer.stop(); + + Logger::destroy(); + return 0; +} \ No newline at end of file diff --git a/src/Socket.cpp b/src/Socket.cpp index e0406fb..c73a97d 100644 --- a/src/Socket.cpp +++ b/src/Socket.cpp @@ -7,6 +7,7 @@ #include #include // inet_ntop + Socket::Socket(const int domain, const int type, const int protocol) @@ -14,6 +15,8 @@ Socket::Socket(const int domain, , m_domain(domain) , m_type(type) , m_protocol(protocol) + , m_addr() + , m_addrLen(0) { TRACE; @@ -51,16 +54,16 @@ void Socket::closeSocket() } -bool Socket::connectToHost(const std::string host, - const std::string port ) +bool Socket::connectToHost( const std::string host, + const std::string port ) { TRACE; struct addrinfo *results(0); - if ( !getHostInfo(host, port, &results) ) + if ( !Socket::getHostInfo(host, port, &results) ) return false; - printHostDetails(results); + Socket::printHostDetails(results); if ( !connectToFirstAddress(results) ) return false; @@ -70,11 +73,74 @@ bool Socket::connectToHost(const std::string host, } +bool Socket::bindToHost( const std::string host, + const std::string port ) +{ + TRACE; + + struct addrinfo *results(0); + if ( !Socket::getHostInfo(host, port, &results) ) + return false; + + Socket::printHostDetails(results); + + if ( !bindToFirstAddress(results) ) + return false; + + freeaddrinfo(results); + return true; +} + + +bool Socket::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) { + std::string address, service; + if ( convertNameInfo( it->ai_addr, it->ai_addrlen, address, service) ) { + LOG( Logger::DEBUG, std::string("Connected to "). + append(address).append(":"). + append(service).c_str() ); + } + return true; + } + + LOG( Logger::ERR, "Could not connect to host, connection refused." ); + return false; +} + + +bool Socket::bindToFirstAddress(struct addrinfo *servinfo ) +{ + TRACE; + + for ( struct addrinfo *it = servinfo; it != 0; it = it->ai_next) + if (bind(m_socket, it->ai_addr, it->ai_addrlen) == 0) { + memcpy(&m_addr, it->ai_addr, it->ai_addrlen); + m_addrLen = it->ai_addrlen; + + std::string address, service; + if ( Socket::convertNameInfo( &m_addr, m_addrLen, address, service) ) { + LOG( Logger::DEBUG, std::string("Binded to "). + append(address).append(":"). + append(service).c_str() ); + } + return true; + } + + LOG( Logger::ERR, "Could not bind to host. Address already in use." ); + + return false; +} + + bool Socket::getHostInfo( const std::string host, const std::string port, - struct addrinfo **servinfo) const + struct addrinfo **servinfo) { - TRACE; + TRACE_STATIC; struct addrinfo hints; @@ -102,9 +168,9 @@ bool Socket::getHostInfo( const std::string host, } -void Socket::printHostDetails(struct addrinfo *servinfo) const +void Socket::printHostDetails(struct addrinfo *servinfo) { - TRACE; + TRACE_STATIC; int counter(0); for ( struct addrinfo *it = servinfo; it != 0; it = it->ai_next) { @@ -132,31 +198,28 @@ void Socket::printHostDetails(struct addrinfo *servinfo) const } -bool Socket::connectToFirstAddress(struct addrinfo *servinfo) const +bool Socket::convertNameInfo(sockaddr* addr, + socklen_t addrLen, + std::string &retAddr, + std::string &retService) { - TRACE; + TRACE_STATIC; - 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; - } + char hostBuffer[256]; + char serviceBuffer[256]; - LOG( Logger::ERR, std::string("Could not connect to host," - " connection refused.").c_str() ); - return false; + int status = getnameinfo( addr, 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() ); + return false; + } + + retAddr.assign(hostBuffer); + retService.assign(serviceBuffer); + return true; } \ No newline at end of file diff --git a/src/TcpClient.cpp b/src/TcpClient.cpp index 14138c9..f004c32 100644 --- a/src/TcpClient.cpp +++ b/src/TcpClient.cpp @@ -8,7 +8,7 @@ #include // inet_ntop #include - +#include TcpClient::TcpClient( const std::string host, const std::string port ) @@ -55,8 +55,10 @@ void TcpClient::disconnect() closeSocket(); m_connected = false; - m_watcher.stop(); - m_watcher.join(); + if ( m_watcher.isRunning() ) { + m_watcher.stop(); + m_watcher.join(); + } } @@ -64,6 +66,9 @@ bool TcpClient::send(const std::string msg) { TRACE; + if ( !m_connected ) + return false; + ssize_t n = write(m_socket, msg.c_str(), msg.length()); if (n == -1) { LOG( Logger::ERR, errnoToString("ERROR writing to socket. ").c_str() ); @@ -85,20 +90,20 @@ void* TcpClient::WatcherThread::run() { TRACE; + struct timespec tm = {0,1000}; while ( m_isRunning ) { - struct timespec tm = {0,1000}; nanosleep(&tm, &tm) ; if ( m_tcpClient.m_connected ) { - pollfd fds[1] ; + pollfd fds[1]; fds[0].fd = m_tcpClient.m_socket ; fds[0].events = POLLIN | POLLPRI ; fds[0].revents = 0 ; int ret = poll( fds , 1, 1000) ; if ( ret == -1 ) { - LOG( Logger::ERR, errnoToString("ERROR at polling. ").c_str() ); + LOG( Logger::ERR, errnoToString("ERROR polling. ").c_str() ); m_tcpClient.m_connected = false; m_tcpClient.onDisconnect(); } diff --git a/src/TcpServer.cpp b/src/TcpServer.cpp new file mode 100644 index 0000000..c3fda77 --- /dev/null +++ b/src/TcpServer.cpp @@ -0,0 +1,170 @@ +#include "TcpServer.hpp" + +#include "Logger.hpp" +#include "Common.hpp" + +#include +#include + +TcpServer::TcpServer( const std::string host, + const std::string port, + const int maxClients ) + : Socket(AF_INET, SOCK_STREAM) + , m_host(host) + , m_port(port) + , m_maxclients(maxClients) + , m_running(false) + , m_fds(0) + , m_num_of_fds(0) + , m_addr() + , m_addrLen(0) +{ + TRACE; + m_fds = (pollfd*) malloc (sizeof(struct pollfd)*m_maxclients); +} + + +TcpServer::~TcpServer() +{ + TRACE; + free(m_fds); +} + + +bool TcpServer::start() +{ + TRACE; + + if ( !openSocket() ) + return false; + + if ( !bindToHost(m_host, m_port) ) + return false; + + if ( listen(m_socket, 64) == -1 ) { + LOG( Logger::ERR, errnoToString("ERROR listening. ").c_str() ); + return false; + } + + + addFd( m_socket, POLLIN | POLLPRI ) ; + + m_running = true; + + struct timespec tm = {0,1000}; + + while ( m_running ) { + + nanosleep(&tm, &tm) ; + int ret = poll( m_fds , m_maxclients, 1000); + + if ( ret == -1 ) { + LOG( Logger::ERR, errnoToString("ERROR polling. ").c_str() ); + return false; + } + + if ( ret == 0 ) // timeout + continue; + + for ( nfds_t i = 0; i < m_num_of_fds; ++i ) { + if ( m_fds[i].revents != 0 ) { + + if ( m_fds[i].fd == m_socket ) { + + sockaddr clientAddr; + socklen_t clientAddrLen; + int client_socket = accept( m_socket, &clientAddr, &clientAddrLen ) ; + + if ( client_socket == -1 ) { + LOG( Logger::ERR, errnoToString("ERROR accepting. ").c_str() ); + } else { + + std::string clientAddress, clientService; + if ( Socket::convertNameInfo(&clientAddr, clientAddrLen, + clientAddress, clientService ) ) { + LOG( Logger::DEBUG, std::string("New client connected: "). + append(clientAddress).append(":"). + append(clientService).c_str() ); + } + addFd( client_socket, POLLIN | POLLPRI ); + } + } + else { + if ( !receive( m_fds[i].fd ) ) { + removeFd(m_fds[i].fd); + } + } + } + } + + } + + + return true; +} + + +void TcpServer::stop() +{ + TRACE; + + m_running = false; + + closeSocket(); +} + + +bool TcpServer::receive(const int clientSocket) +{ + TRACE; + + char buffer[256]; + int len = recv( clientSocket, buffer , 256, 0) ; + + if (len == -1) { + LOG( Logger::ERR, errnoToString("ERROR reading from socket. ").c_str() ); + return false; + } + + if (len == 0) { + LOG( Logger::DEBUG, "Connection closed by peer." ); + return false; + } + + std::string msg(buffer, len); + msgArrived(clientSocket, msg); + + return true; +} + + +void TcpServer::addFd( int fd, short events ) +{ + TRACE; + + if (m_num_of_fds < m_maxclients ) + { + m_fds[m_num_of_fds].fd = fd ; + m_fds[m_num_of_fds].events = events ; + m_fds[m_num_of_fds].revents = 0 ; + ++m_num_of_fds ; + } +} + +void TcpServer::removeFd( int fd ) +{ + TRACE; + + unsigned int i = 0 ; + while (i < m_maxclients && m_fds[i].fd != fd ) ++i ; + + if ( i != m_maxclients ) { + for ( ; i < m_maxclients - 1; ++i ) + m_fds[i] = m_fds[i+1] ; + + m_fds[i].fd = 0 ; + m_fds[i].events = 0 ; + m_fds[i].revents = 0 ; + --m_num_of_fds ; + } +} \ No newline at end of file diff --git a/src/Thread.cpp b/src/Thread.cpp index ceeb773..2f735d0 100644 --- a/src/Thread.cpp +++ b/src/Thread.cpp @@ -53,6 +53,12 @@ void Thread::sendSignal( const int nSignal ) const } +bool Thread::isRunning() const +{ + return m_isRunning; +} + + void* Thread::threadStarter( void* pData ) { TRACE_STATIC; diff --git a/src/socketClient.cpp b/src/socketClient.cpp deleted file mode 100644 index 424eba4..0000000 --- a/src/socketClient.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#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) -{ - return std::string(s).append(strerror(errno)); -} \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 47ee911..0b0bfe3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -18,7 +18,7 @@ if(CXXTEST_FOUND) generated_main.cpp Fixture.hpp - test_ArgParse.hpp +# test_ArgParse.hpp # test_Singelton_call_once.hpp # test_Singleton.hpp # test_Singleton_meyers.hpp @@ -26,7 +26,7 @@ if(CXXTEST_FOUND) # test_Mutex.hpp # test_ScopedLock.hpp # test_ConditionalVariable.hpp -# test_Thread.hpp + test_Thread.hpp # test_ThreadPool.hpp # test_Semaphore.hpp # test_Timer.hpp diff --git a/test/test_Thread.hpp b/test/test_Thread.hpp index 503fa90..7b2a00f 100644 --- a/test/test_Thread.hpp +++ b/test/test_Thread.hpp @@ -111,4 +111,31 @@ public: delete m2; } + +private: + + class EmptyThreadClass : public Thread + { + + private: + + void* run( void ) { + TRACE; + return 0; + } + }; + +public: + + void testEmpty( void ) + { + TEST_HEADER; + + EmptyThreadClass e; + e.start(); + + e.stop(); + void *retVal = e.join(); + TS_ASSERT_EQUALS ( retVal , (void *)0 ); + } };