From 62f50a2f7986a0a634ada8623ed24f2f17e341d8 Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Sat, 21 Nov 2009 01:11:05 +0000 Subject: [PATCH] cpp utils files, network and a smal util class --- net/serversocket.cpp | 27 ++++++++ net/serversocket.h | 18 +++++ net/socket.cpp | 69 +++++++++++++++++++ net/socket.h | 30 +++++++++ net/socketexception.h | 22 ++++++ net/socketio.cpp | 151 ++++++++++++++++++++++++++++++++++++++++++ net/socketio.h | 53 +++++++++++++++ net/socketstream.cpp | 47 +++++++++++++ net/socketstream.h | 36 ++++++++++ net/test_client.cpp | 24 +++++++ net/test_server.cpp | 37 +++++++++++ util.cpp | 48 ++++++++++++++ util.h | 48 ++++++++++++++ 13 files changed, 610 insertions(+) create mode 100644 net/serversocket.cpp create mode 100644 net/serversocket.h create mode 100644 net/socket.cpp create mode 100644 net/socket.h create mode 100644 net/socketexception.h create mode 100644 net/socketio.cpp create mode 100644 net/socketio.h create mode 100644 net/socketstream.cpp create mode 100644 net/socketstream.h create mode 100644 net/test_client.cpp create mode 100644 net/test_server.cpp create mode 100644 util.cpp create mode 100644 util.h diff --git a/net/serversocket.cpp b/net/serversocket.cpp new file mode 100644 index 0000000..f0e57b4 --- /dev/null +++ b/net/serversocket.cpp @@ -0,0 +1,27 @@ +#include "serversocket.h" +using namespace zutil; + + +ServerSocket::ServerSocket( int port ){ + if ( !SocketIO::create() ){ + throw SocketException ( "Could not create server socket." ); + } + if ( !Socket::bind( port ) ){ + throw SocketException ( "Could not bind to port." ); + } + if ( !Socket::listen() ){ + throw SocketException ( "Could not listen to socket." ); + } + +} + +Socket* ServerSocket::accept( ){ + Socket *sock = new Socket(); + accept(*sock); + return sock; +} +void ServerSocket::accept( Socket& sock ){ + if ( !SocketIO::accept( sock ) ){ + throw SocketException ( "Could not accept socket." ); + } +} diff --git a/net/serversocket.h b/net/serversocket.h new file mode 100644 index 0000000..cba809d --- /dev/null +++ b/net/serversocket.h @@ -0,0 +1,18 @@ +#ifndef ZUTIL_NET_SERVERSOCKET +#define ZUTIL_NET_SERVERSOCKET + +#include "socket.h" +using namespace std; + +namespace zutil{ + class ServerSocket : protected Socket{ + public: + ServerSocket( int port ); + virtual ~ServerSocket(){}; + + Socket* accept( ); + void accept( Socket& ); + }; +} + +#endif diff --git a/net/socket.cpp b/net/socket.cpp new file mode 100644 index 0000000..a757dd2 --- /dev/null +++ b/net/socket.cpp @@ -0,0 +1,69 @@ +#include "socket.h" +using namespace zutil; + +Socket::Socket(){ + streambuf = NULL; + in = NULL; + out = NULL; +} +Socket::Socket( string host, int port ){ + streambuf = NULL; + in = NULL; + out = NULL; + + if ( !SocketIO::create() ){ + throw SocketException ( "Could not create client socket." ); + } + + if ( !SocketIO::connect ( host, port ) ){ + throw SocketException ( "Could not bind to port." ); + } +} +Socket::~Socket(){ + delete in; + delete out; + delete streambuf; +} + +istream& Socket::get_istream(){ + if(streambuf == NULL) + streambuf = new SocketStreamBuffer( *this ); + if(in == NULL) + in = new istream( streambuf ); + return *in; +} +ostream& Socket::get_ostream(){ + if(streambuf == NULL) + streambuf = new SocketStreamBuffer( *this ); + if(out == NULL) + out = new ostream( streambuf ); + return *out; +} + + +const Socket& Socket::operator<<( const string &s ) const{ + if ( !SocketIO::write( s ) ){ + throw SocketException ( "Could not write string to socket." ); + } + return *this; +} +const Socket& Socket::operator<<( const char c ) const{ + if ( !SocketIO::write( c ) ){ + throw SocketException ( "Could not write char to socket." ); + } + return *this; +} + + +const Socket& Socket::operator>>( string &s ) const{ + if ( !SocketIO::read( s ) ){ + throw SocketException ( "Could not read string from socket." ); + } + return *this; +} +const Socket& Socket::operator>>( char &c ) const{ + if ( !(c = SocketIO::read( )) ){ + throw SocketException ( "Could not read char from socket." ); + } + return *this; +} diff --git a/net/socket.h b/net/socket.h new file mode 100644 index 0000000..4bf386a --- /dev/null +++ b/net/socket.h @@ -0,0 +1,30 @@ +#ifndef ZUTIL_NET_SOCKET +#define ZUTIL_NET_SOCKET + +#include "socketio.h" +#include "socketexception.h" +#include "socketstream.h" +using namespace std; + +namespace zutil{ + class Socket : public SocketIO{ + protected: + SocketStreamBuffer *streambuf; + istream *in; + ostream *out; + public: + Socket( string host, int port ); + explicit Socket(); + virtual ~Socket(); + + istream& get_istream(); + ostream& get_ostream(); + + const Socket& operator<<( const string& ) const; + const Socket& operator<<( const char ) const; + const Socket& operator>>( string& ) const; + const Socket& operator>>( char& ) const; + }; +} + +#endif diff --git a/net/socketexception.h b/net/socketexception.h new file mode 100644 index 0000000..425b0a9 --- /dev/null +++ b/net/socketexception.h @@ -0,0 +1,22 @@ +#ifndef SOCKETEXCEPTION +#define SOCKETEXCEPTION + +#include +using namespace std; + +namespace zutil{ + class SocketException{ + public: + SocketException(const string &s ) : msg(s) {}; + ~SocketException(){}; + + string description() const{ + return msg; + } + + private: + const string msg; + }; +} + +#endif diff --git a/net/socketio.cpp b/net/socketio.cpp new file mode 100644 index 0000000..774ef53 --- /dev/null +++ b/net/socketio.cpp @@ -0,0 +1,151 @@ +#include "socketio.h" +#include +#include +using namespace zutil; + +SocketIO::SocketIO() : socket_id(-1){ + memset( &address, 0, sizeof( address ) ); +} + +SocketIO::~SocketIO(){ + if( is_valid() ) + close( socket_id ); +} + +bool SocketIO::create(){ + socket_id = socket( AF_INET, SOCK_STREAM, 0 ); + + if( !is_valid() ) + return false; + + + // TIME_WAIT - argh + int on = 1; + if( setsockopt( socket_id, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on) ) == -1 ) + return false; + + return true; +} + +bool SocketIO::bind( const int port ){ + if ( !is_valid() ) { + return false; + } + + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons( port ); + + int bind_return = ::bind( socket_id, (struct sockaddr*)&address, sizeof( address ) ); + + if( bind_return == -1 ){ + return false; + } + + return true; +} + +bool SocketIO::listen() const{ + if ( !is_valid() ){ + return false; + } + + int listen_return = ::listen( socket_id, MAX_CONNECTIONS ); + + if ( listen_return == -1 ){ + return false; + } + + return true; +} + + +bool SocketIO::accept( SocketIO& new_socket ) const{ + int addr_length = sizeof( address ); + new_socket.socket_id = ::accept( socket_id, (sockaddr*)&address, (socklen_t*) &addr_length ); + + if( new_socket.socket_id <= 0 ) + return false; + else + return true; +} + +bool SocketIO::write( const char c ) const{ + return write( &c, 1 ); +} +bool SocketIO::write( const string s ) const{ + return write( s.c_str(), s.size() ); +} +bool SocketIO::write( const char* buf, size_t len ) const{ + int sent_bytes = send( socket_id, buf, len, MSG_PRIO); + if ( sent_bytes == -1 ) + return false; + else + return true; +} + +char SocketIO::read( ) const{ + char c; + read( &c, 1 ); + return c; +} +int SocketIO::read( string &s ) const{ + s = ""; + char buf [ SOCKET_BUFFER + 1 ]; + + int recv_bytes = read( buf, SOCKET_BUFFER ); + if(recv_bytes > 0) + s = buf; + return recv_bytes; +} +int SocketIO::read( char* buf, size_t len ) const{ + memset( buf, 0, len ); + int recv_bytes = recv( socket_id, buf, len, 0 ); + + if( recv_bytes == -1 ){ + cout << "status == -1 errno == " << errno << " in Socket::read\n"; + return 0; + } + else if( recv_bytes == 0 ){ + return 0; + } + else{ + return recv_bytes; + } +} + +bool SocketIO::connect( const string host, const int port ){ + if ( !is_valid() ) return false; + + address.sin_family = AF_INET; + address.sin_port = htons( port ); + + int status = inet_pton( AF_INET, host.c_str(), &address.sin_addr ); + + if ( errno == EAFNOSUPPORT ) + return false; + + status = ::connect( socket_id, (sockaddr*)&address, sizeof ( address ) ); + + if( status == 0 ) + return true; + else + return false; +} + +void SocketIO::set_non_blocking( const bool b ){ + int opts; + opts = fcntl( socket_id, F_GETFL ); + + if( opts < 0 ){ + return; + } + + if( b ) + opts = ( opts | O_NONBLOCK ); + else + opts = ( opts & ~O_NONBLOCK ); + + fcntl ( socket_id, F_SETFL,opts ); + +} diff --git a/net/socketio.h b/net/socketio.h new file mode 100644 index 0000000..ee6a857 --- /dev/null +++ b/net/socketio.h @@ -0,0 +1,53 @@ +#ifndef ZUTIL_NET_SOCKET_IO +#define ZUTIL_NET_SOCKET_IO + +#include +#include +#include +#include +#include +#include +#include +#include +#include "socketexception.h" +using namespace std; + +//const int MAXHOSTNAME = 200; +const int MAX_CONNECTIONS = 5; +const int SOCKET_BUFFER = 500; +const int MSG_PRIO = 0; // defined by dgame + +namespace zutil{ + class SocketIO{ + private: + int socket_id; + sockaddr_in address; + public: + SocketIO(); + virtual ~SocketIO(); + + // Server initialization + bool create(); + bool bind( const int port ); + bool listen() const; + bool accept( SocketIO& ) const; + + // Client initialization + bool connect( const string host, const int port ); + + // Data Transimission + bool write( const char c ) const; + bool write( const string ) const; + bool write( const char* buf, const size_t len ) const; + + char read( ) const; + int read( string& ) const; + int read( char* buf, const size_t len ) const; + + + void set_non_blocking( const bool ); + bool is_valid() const { return socket_id != -1; } + }; +} + +#endif diff --git a/net/socketstream.cpp b/net/socketstream.cpp new file mode 100644 index 0000000..e2de50f --- /dev/null +++ b/net/socketstream.cpp @@ -0,0 +1,47 @@ +#include "socketstream.h" +using namespace zutil; + +SocketStreamBuffer::SocketStreamBuffer(SocketIO &s) : soc(s){ + pBeg = pBuffer; + pCur = pBuffer; + pEnd = pBuffer; + //pEnd = pBuffer + BUFFER_SIZE; + streambuf::setp(pBeg, pEnd); + + gBeg = gBuffer; + gCur = gBuffer; + gEnd = gBuffer + BUFFER_SIZE; + streambuf::setg(gBeg, gCur, gEnd); +} + +int SocketStreamBuffer::underflow() { + int recv_bytes = soc.read(gBuffer, BUFFER_SIZE); + + if(recv_bytes > 0){ + gCur = gBuffer; + gEnd = gBuffer+recv_bytes; + streambuf::setg(gBeg, gCur, gEnd); + + return Tr::not_eof( *gCur ); + } + return Tr::eof(); +} + +int SocketStreamBuffer::overflow(int c) { + if(c == Tr::eof()) + return Tr::not_eof(c); + soc.write(c); + return c; + /*if(sync() >= 0) + return c; + return Tr::eof();*/ +}/* +int SocketStreamBuffer::sync() { + if( soc.write( pBuffer, pCur-pBeg )){ + pCur = pBuffer; + streambuf::setp(pBeg, pEnd); + return 0; + } + return -1; +}*/ + diff --git a/net/socketstream.h b/net/socketstream.h new file mode 100644 index 0000000..7db7076 --- /dev/null +++ b/net/socketstream.h @@ -0,0 +1,36 @@ +#ifndef ZUTIL_NET_SOCKETSTREAM +#define ZUTIL_NET_SOCKETSTREAM + +#include +#include "socketio.h" +using namespace std; + +const size_t BUFFER_SIZE = 100; + +namespace zutil{ + class SocketStreamBuffer : public streambuf{ + private: + SocketIO &soc; + + char pBuffer[BUFFER_SIZE]; + char gBuffer[BUFFER_SIZE]; + char *pBeg, *pCur, *pEnd; + char *gBeg, *gCur, *gEnd; + + typedef char_traits Tr; + protected: + //virtual int uflow(); + virtual int underflow(); + //virtual streamsize xsgetn(char_type *s, streamsize n); + + virtual int overflow(int = Tr::eof()); + //virtual streamsize xsputn(const char_type *s, streamsize n); + //virtual int sync(); + + public: + SocketStreamBuffer(SocketIO &s); + }; +} + +#endif + diff --git a/net/test_client.cpp b/net/test_client.cpp new file mode 100644 index 0000000..2d5c593 --- /dev/null +++ b/net/test_client.cpp @@ -0,0 +1,24 @@ +#include +#include +#include "socket.h" +#include "socketexception.h" +using namespace std; + +int main ( int argc, int argv[] ){ + try{ + Socket socket ( "localhost", 30000 ); + std::string reply; + + try{ + socket << "Test message."; + socket >> reply; + } + catch ( SocketException& ) {} + cout << "We received this response from the server:\n\"" << reply << "\"\n"; + + }catch ( SocketException& e ){ + cout << "Exception was caught:" << e.description() << "\n"; + } + + return 0; +} diff --git a/net/test_server.cpp b/net/test_server.cpp new file mode 100644 index 0000000..9e3ef01 --- /dev/null +++ b/net/test_server.cpp @@ -0,0 +1,37 @@ +#include +#include +#include "socket.h" +#include "serversocket.h" +#include "socketexception.h" +using namespace std; +using namespace zutil; + +int main ( int argc, int argv[] ){ + cout << "running....\n"; + + try{ + // Create the socket + ServerSocket server ( 30000 ); + + while ( true ){ + Socket new_sock; + server.accept ( new_sock ); + + istream &in = new_sock.get_istream(); + ostream &out = new_sock.get_ostream(); + + try{ + while ( true ){ + string data; + in >> data; + cout << data << endl; + out << data; + } + }catch ( SocketException& ) {} + } + }catch ( SocketException& e ){ + cout << "Exception was caught:" << e.description() << "\nExiting.\n"; + } + + return 0; +} diff --git a/util.cpp b/util.cpp new file mode 100644 index 0000000..36f83e8 --- /dev/null +++ b/util.cpp @@ -0,0 +1,48 @@ +#include "util.h" + + +void zutil::tolower(string &s){ + for(size_t i=0; s[i] ;++i){ + s[i] = std::tolower(s[i]); + } +} + +void zutil::trim(string &str){ + size_t s = str.find_first_not_of(" \n\r\t"); + size_t e = str.find_last_not_of (" \n\r\t"); + + if( string::npos != s && string::npos != e) + str = str.substr(s, e-s+1); +} + + +vector zutil::parseLine(istream &in, char separator, char endl){ + vector parsed; + string line; + getline(in, line, endl); + + return split( line, separator ); +} + +vector zutil::split(const string &line, char separator){ + vector parsed; + + string tmp; + for(size_t i=0; i +#include +#include +#include +using namespace std; + + +namespace zutil{ + + void tolower(string &s); + void trim(string &str); + vector parseLine(istream &in, char separator, char endl); + vector split(const string &s, char separator); + + template + bool remove(vector &v, const T &item){ + typename vector::iterator it; + it = find(v.begin(), v.end(), item); + + if(it != v.end()){ + v.erase(it); + return true; + } + return false; + } + + template + bool contains(const vector &v, const T &item){ + typename vector::const_iterator it; + it = find(v.begin(), v.end(), item); + if(it != v.end()) + return true; + return false; + } + + template + string to_string(const T &t){ + stringstream ss; + ss << t; + return ss.str(); + } + +} +#endif +