From 9031e2af7dd4e65ec70890ee78a7cf600d1b2cc5 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sat, 16 Oct 2010 03:02:11 +0000 Subject: Many, many changes. Documentation changes, renamed the socket class to TcpSocket, fixed many other things, and finally removed ParamProc. Anything that needs it will now have to switch to OptParser. --- src/array.h | 2 + src/client.cpp | 9 +- src/client.h | 8 +- src/fastcgi.cpp | 22 +- src/fastcgi.h | 18 +- src/fbasicstring.h | 2 + src/hash.h | 2 + src/heap.h | 2 + src/httpget.h | 4 +- src/itoserver.cpp | 12 +- src/itoserver.h | 6 +- src/newline.h | 2 +- src/paramproc.cpp | 523 ---------------------------------------------- src/paramproc.h | 163 --------------- src/ringbuffer.h | 2 + src/server.cpp | 14 +- src/server.h | 6 +- src/serversocket.cpp | 249 ---------------------- src/serversocket.h | 64 ------ src/sharedcore.h | 47 +++++ src/socket.cpp | 446 --------------------------------------- src/socket.h | 115 ---------- src/tcpserversocket.cpp | 249 ++++++++++++++++++++++ src/tcpserversocket.h | 64 ++++++ src/tcpsocket.cpp | 450 +++++++++++++++++++++++++++++++++++++++ src/tcpsocket.h | 116 ++++++++++ src/tests/socket.cpp | 73 ------- src/tests/socketblock.cpp | 10 +- src/tests/socketbreak.cpp | 10 +- src/tests/tcpsocket.cpp | 73 +++++++ src/variant.h | 18 +- 31 files changed, 1087 insertions(+), 1694 deletions(-) delete mode 100644 src/paramproc.cpp delete mode 100644 src/paramproc.h delete mode 100644 src/serversocket.cpp delete mode 100644 src/serversocket.h delete mode 100644 src/socket.cpp delete mode 100644 src/socket.h create mode 100644 src/tcpserversocket.cpp create mode 100644 src/tcpserversocket.h create mode 100644 src/tcpsocket.cpp create mode 100644 src/tcpsocket.h delete mode 100644 src/tests/socket.cpp create mode 100644 src/tests/tcpsocket.cpp diff --git a/src/array.h b/src/array.h index fc4fb12..f225c97 100644 --- a/src/array.h +++ b/src/array.h @@ -20,6 +20,7 @@ namespace Bu template class Array; + /** @cond DEVEL */ template class ArrayCore { @@ -107,6 +108,7 @@ namespace Bu long iSize; long iCapacity; }; + /** @endcond */ /** * Array type container, just like a normal array only flexible and keeps diff --git a/src/client.cpp b/src/client.cpp index becd1bd..b635c8b 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -6,7 +6,7 @@ */ #include "bu/client.h" -#include "bu/socket.h" +#include "bu/tcpsocket.h" #include #include #include "bu/protocol.h" @@ -16,7 +16,8 @@ /** Read buffer size. */ #define RBS (1024*2) -Bu::Client::Client( Bu::Socket *pSocket, class Bu::ClientLinkFactory *pfLink ) : +Bu::Client::Client( Bu::TcpSocket *pSocket, + class Bu::ClientLinkFactory *pfLink ) : pTopStream( pSocket ), pSocket( pSocket ), pProto( NULL ), @@ -59,7 +60,7 @@ void Bu::Client::processInput() break; } } - catch( Bu::SocketException &e ) + catch( Bu::TcpSocketException &e ) { pTopStream->close(); bWantsDisconnect = true; @@ -195,7 +196,7 @@ long Bu::Client::getOutputSize() return qbWrite.getSize(); } -const Bu::Socket *Bu::Client::getSocket() const +const Bu::TcpSocket *Bu::Client::getSocket() const { return pSocket; } diff --git a/src/client.h b/src/client.h index f336524..096df2f 100644 --- a/src/client.h +++ b/src/client.h @@ -17,7 +17,7 @@ namespace Bu { class Protocol; class Stream; - class Socket; + class TcpSocket; class ClientLinkFactory; /** @@ -26,7 +26,7 @@ namespace Bu class Client : public Bu::Stream { public: - Client( Bu::Socket *pSocket, Bu::ClientLinkFactory *pfLink ); + Client( Bu::TcpSocket *pSocket, Bu::ClientLinkFactory *pfLink ); virtual ~Client(); void processInput(); @@ -58,7 +58,7 @@ namespace Bu void close(); void tick(); - const Bu::Socket *getSocket() const; + const Bu::TcpSocket *getSocket() const; void disconnect(); bool wantsDisconnect(); @@ -117,7 +117,7 @@ namespace Bu typedef Bu::List FilterList; FilterList lFilts; Bu::Stream *pTopStream; - Bu::Socket *pSocket; + Bu::TcpSocket *pSocket; Bu::Protocol *pProto; Bu::QueueBuf qbRead; Bu::QueueBuf qbWrite; diff --git a/src/fastcgi.cpp b/src/fastcgi.cpp index 8168928..ca3010e 100644 --- a/src/fastcgi.cpp +++ b/src/fastcgi.cpp @@ -24,14 +24,14 @@ Bu::FastCgi::FastCgi() : pSrv( NULL ), bRunning( true ) { - pSrv = new Bu::ServerSocket( STDIN_FILENO, false ); + pSrv = new Bu::TcpServerSocket( STDIN_FILENO, false ); } Bu::FastCgi::FastCgi( int iPort ) : pSrv( NULL ), bRunning( true ) { - pSrv = new Bu::ServerSocket( iPort ); + pSrv = new Bu::TcpServerSocket( iPort ); } Bu::FastCgi::~FastCgi() @@ -64,17 +64,17 @@ bool Bu::FastCgi::isEmbedded() #endif } -void Bu::FastCgi::read( Bu::Socket &s, Bu::FastCgi::Record &r ) +void Bu::FastCgi::read( Bu::TcpSocket &s, Bu::FastCgi::Record &r ) { int iRead = s.read( &r, sizeof(Record) ); if( iRead != sizeof(Record) ) - throw Bu::SocketException("Hey, the size %d is wrong for Record. (%s)", + throw Bu::TcpSocketException("Hey, the size %d is wrong for Record. (%s)", iRead, strerror( errno ) ); r.uRequestId = ntohs( r.uRequestId ); r.uContentLength = ntohs( r.uContentLength ); } -void Bu::FastCgi::write( Bu::Socket &s, Bu::FastCgi::Record r ) +void Bu::FastCgi::write( Bu::TcpSocket &s, Bu::FastCgi::Record r ) { // sio << "Out -> " << r << sio.nl; r.uRequestId = htons( r.uRequestId ); @@ -82,19 +82,19 @@ void Bu::FastCgi::write( Bu::Socket &s, Bu::FastCgi::Record r ) s.write( &r, sizeof(Record) ); } -void Bu::FastCgi::read( Bu::Socket &s, Bu::FastCgi::BeginRequestBody &b ) +void Bu::FastCgi::read( Bu::TcpSocket &s, Bu::FastCgi::BeginRequestBody &b ) { s.read( &b, sizeof(BeginRequestBody) ); b.uRole = ntohs( b.uRole ); } -void Bu::FastCgi::write( Bu::Socket &s, Bu::FastCgi::EndRequestBody b ) +void Bu::FastCgi::write( Bu::TcpSocket &s, Bu::FastCgi::EndRequestBody b ) { b.uStatus = htonl( b.uStatus ); s.write( &b, sizeof(b) ); } -uint32_t Bu::FastCgi::readLen( Bu::Socket &s, uint16_t &uRead ) +uint32_t Bu::FastCgi::readLen( Bu::TcpSocket &s, uint16_t &uRead ) { uint8_t uByte[4]; s.read( uByte, 1 ); @@ -107,7 +107,7 @@ uint32_t Bu::FastCgi::readLen( Bu::Socket &s, uint16_t &uRead ) return ((uByte[0]&0x7f)<<24)|(uByte[1]<<16)|(uByte[2]<<8)|(uByte[3]); } -void Bu::FastCgi::readPair( Bu::Socket &s, StrHash &hParams, uint16_t &uRead ) +void Bu::FastCgi::readPair( Bu::TcpSocket &s, StrHash &hParams, uint16_t &uRead ) { uint32_t uName = readLen( s, uRead ); uint32_t uValue = readLen( s, uRead ); @@ -162,7 +162,7 @@ void Bu::FastCgi::run() if( iSock < 0 ) continue; - Bu::Socket s( iSock ); + Bu::TcpSocket s( iSock ); s.setBlocking( true ); // sio << "Got connection, blocking? " << s.isBlocking() << sio.nl; try @@ -362,7 +362,7 @@ void Bu::FastCgi::run() } } } - catch( Bu::SocketException &e ) + catch( Bu::TcpSocketException &e ) { // sio << "Bu::SocketException: " << e.what() << sio.nl << // "\tSocket open: " << s.isOpen() << sio.nl; diff --git a/src/fastcgi.h b/src/fastcgi.h index 262872c..7c1c04c 100644 --- a/src/fastcgi.h +++ b/src/fastcgi.h @@ -11,8 +11,8 @@ #include "bu/fstring.h" #include "bu/hash.h" #include "bu/array.h" -#include "bu/socket.h" -#include "bu/serversocket.h" +#include "bu/tcpsocket.h" +#include "bu/tcpserversocket.h" namespace Bu { @@ -109,18 +109,18 @@ namespace Bu virtual void onUninit() { }; private: - void read( Bu::Socket &s, Record &r ); - void read( Bu::Socket &s, BeginRequestBody &b ); - uint32_t readLen( Bu::Socket &s, uint16_t &uUsed ); - void readPair( Bu::Socket &s, StrHash &hParams, uint16_t &uUsed ); + void read( Bu::TcpSocket &s, Record &r ); + void read( Bu::TcpSocket &s, BeginRequestBody &b ); + uint32_t readLen( Bu::TcpSocket &s, uint16_t &uUsed ); + void readPair( Bu::TcpSocket &s, StrHash &hParams, uint16_t &uUsed ); - void write( Bu::Socket &s, Record r ); - void write( Bu::Socket &s, EndRequestBody b ); + void write( Bu::TcpSocket &s, Record r ); + void write( Bu::TcpSocket &s, EndRequestBody b ); bool hasChannel( int iChan ); private: - Bu::ServerSocket *pSrv; + Bu::TcpServerSocket *pSrv; bool bRunning; Bu::Array aChannel; }; diff --git a/src/fbasicstring.h b/src/fbasicstring.h index 82c5137..7167f4a 100644 --- a/src/fbasicstring.h +++ b/src/fbasicstring.h @@ -25,6 +25,7 @@ namespace Bu { + /** @cond DEVEL */ template< typename chr > struct FStringChunk { @@ -166,6 +167,7 @@ namespace Bu nLength += pNewChunk->nLength; } }; + /** @endcond */ /** * Flexible String class. This class was designed with string passing and diff --git a/src/hash.h b/src/hash.h index 714a7f7..d251c46 100644 --- a/src/hash.h +++ b/src/hash.h @@ -54,6 +54,7 @@ namespace Bu typename valuealloc, typename challoc> class Hash; + /** @cond DEVEL */ template class HashCore @@ -399,6 +400,7 @@ namespace Bu challoc ca; sizecalc szCalc; }; + /** @endcond */ /** * Libbu++ Template Hash Table. This is your average hash table, that uses diff --git a/src/heap.h b/src/heap.h index 1dac69b..31c2435 100644 --- a/src/heap.h +++ b/src/heap.h @@ -22,6 +22,7 @@ namespace Bu template class Heap; + /** @cond DEVEL */ template class HeapCore { @@ -183,6 +184,7 @@ namespace Bu cmpfunc cmp; itemalloc ia; }; + /** @endcond */ /** * A priority queue that allows for an unlimited number of priorities. All diff --git a/src/httpget.h b/src/httpget.h index 410914c..783f880 100644 --- a/src/httpget.h +++ b/src/httpget.h @@ -11,7 +11,7 @@ #include "bu/stream.h" #include "bu/fstring.h" #include "bu/url.h" -#include "bu/socket.h" +#include "bu/tcpsocket.h" #include "bu/hash.h" namespace Bu @@ -52,7 +52,7 @@ namespace Bu private: Bu::Url uSrc; Bu::FString sMethod; - Bu::Socket sSrv; + Bu::TcpSocket sSrv; typedef Bu::Hash MimeHash; MimeHash hMimeIn; MimeHash hMimeOut; diff --git a/src/itoserver.cpp b/src/itoserver.cpp index a1d804a..ea737bf 100644 --- a/src/itoserver.cpp +++ b/src/itoserver.cpp @@ -7,9 +7,9 @@ #include "bu/itoserver.h" #include -#include "bu/serversocket.h" +#include "bu/tcpserversocket.h" #include "bu/client.h" -#include "bu/socket.h" +#include "bu/tcpsocket.h" #include "bu/config.h" @@ -41,7 +41,7 @@ Bu::ItoServer::~ItoServer() void Bu::ItoServer::addPort( int nPort, int nPoolSize ) { - ServerSocket *s = new ServerSocket( nPort, nPoolSize ); + TcpServerSocket *s = new TcpServerSocket( nPort, nPoolSize ); int nSocket = s->getSocket(); FD_SET( nSocket, &fdActive ); hServers.insert( nSocket, s ); @@ -49,7 +49,7 @@ void Bu::ItoServer::addPort( int nPort, int nPoolSize ) void Bu::ItoServer::addPort( const FString &sAddr, int nPort, int nPoolSize ) { - ServerSocket *s = new ServerSocket( sAddr, nPort, nPoolSize ); + TcpServerSocket *s = new TcpServerSocket( sAddr, nPort, nPoolSize ); int nSocket = s->getSocket(); FD_SET( nSocket, &fdActive ); hServers.insert( nSocket, s ); @@ -92,7 +92,7 @@ void Bu::ItoServer::run() { if( FD_ISSET( i.getKey(), &fdRead ) ) { - ServerSocket *pSrv = i.getValue(); + TcpServerSocket *pSrv = i.getValue(); addClient( pSrv->accept(), pSrv->getPort() ); } } @@ -126,7 +126,7 @@ Bu::ItoServer::ItoClient::ItoClient( ItoServer &rSrv, int iSocket, int iPort, FD_SET( iSocket, &fdActive ); pClient = new Client( - new Bu::Socket( iSocket ), + new Bu::TcpSocket( iSocket ), new SrvClientLinkFactory( rSrv ) ); } diff --git a/src/itoserver.h b/src/itoserver.h index c08d453..81e42cc 100644 --- a/src/itoserver.h +++ b/src/itoserver.h @@ -26,8 +26,8 @@ namespace Bu { - class ServerSocket; - class Socket; + class TcpServerSocket; + class TcpSocket; class Client; /** @@ -126,7 +126,7 @@ namespace Bu int nTimeoutSec; int nTimeoutUSec; fd_set fdActive; - typedef Hash ServerHash; + typedef Hash ServerHash; ServerHash hServers; typedef Hash ClientHash; typedef ItoQueue ClientQueue; diff --git a/src/newline.h b/src/newline.h index b69cdb5..243c876 100644 --- a/src/newline.h +++ b/src/newline.h @@ -14,7 +14,7 @@ namespace Bu { /** * Converts new-line characters from any standard convention into linefeeds - * (\n) on reading, and converts them to either your OS's standard or a + * (\\n) on reading, and converts them to either your OS's standard or a * specified standard, depending on how you construct the class. * * If you're reading in a text file, then this filter is practically diff --git a/src/paramproc.cpp b/src/paramproc.cpp deleted file mode 100644 index f4fd36e..0000000 --- a/src/paramproc.cpp +++ /dev/null @@ -1,523 +0,0 @@ -/* - * Copyright (C) 2007-2010 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#include "bu/paramproc.h" -#include -#include -#include - -#define ptrtype( iitype, iiname ) \ - Bu::ParamProc::ParamPtr::ParamPtr( iitype *iiname ) : \ - type( vt ##iiname ) { val.iiname = iiname; } - -Bu::ParamProc::ParamPtr::ParamPtr() -{ - val.str = NULL; - type = vtunset; -} - -ptrtype( Bu::FString, str ); -ptrtype( uint64_t, uint64 ); -ptrtype( uint32_t, uint32 ); -ptrtype( uint16_t, uint16 ); -ptrtype( uint8_t, uint8 ); -ptrtype( int64_t, int64 ); -ptrtype( int32_t, int32 ); -ptrtype( int16_t, int16 ); -ptrtype( int8_t, int8 ); -ptrtype( float, float32 ); -ptrtype( double, float64 ); -ptrtype( long double, float96 ); -ptrtype( bool, bln ); - -Bu::ParamProc::ParamPtr &Bu::ParamProc::ParamPtr::operator=( ParamProc::ParamPtr &ptr ) -{ - val = ptr.val; - type = ptr.type; - - return *this; -} - -bool Bu::ParamProc::ParamPtr::isSet() -{ - return type != vtunset; -} - -Bu::ParamProc::ParamPtr &Bu::ParamProc::ParamPtr::operator=( const char *str ) -{ - if( !isSet() ) return *this; - switch( type ) - { - case vtstr: - (*val.str) = str; - break; - - case vtuint64: - (*val.uint64) = strtoull( str, NULL, 10 ); - break; - - case vtuint32: - (*val.uint32) = strtoul( str, NULL, 10 ); - break; - - case vtuint16: - (*val.uint16) = (uint16_t)strtoul( str, NULL, 10 ); - break; - - case vtuint8: - (*val.uint8) = (uint8_t)strtoul( str, NULL, 10 ); - break; - - case vtint64: - (*val.int64) = strtoll( str, NULL, 10 ); - break; - - case vtint32: - (*val.int32) = strtol( str, NULL, 10 ); - break; - - case vtint16: - (*val.int16) = (int16_t)strtol( str, NULL, 10 ); - break; - - case vtint8: - (*val.int8) = (int8_t)strtol( str, NULL, 10 ); - break; - - case vtfloat32: - (*val.float32) = strtof( str, NULL ); - break; - - case vtfloat64: - (*val.float64) = strtod( str, NULL ); - break; - - case vtfloat96: - (*val.float96) = strtold( str, NULL ); - break; - - case vtbln: - if( strcasecmp("yes", str ) == 0 || - strcasecmp("true", str ) == 0 ) - { - (*val.bln) = true; - } - else - { - (*val.bln) = false; - } - break; - } - - return *this; -} - -Bu::ParamProc::ParamProc() -{ -} - -Bu::ParamProc::~ParamProc() -{ - for( Bu::List::iterator i = lArg.begin(); - i != lArg.end(); i++ ) - { - delete *i; - } - - for( Bu::List::iterator i = lBan.begin(); - i != lBan.end(); i++ ) - { - delete *i; - } - -} -/* -void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val ) -{ - printf("Calling callback...\n"); - val = "Hello there, this is set in the ParamProc"; - (this->*proc)(); -}*/ - -void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, - ParamPtr val, const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - ArgSpec *as = new ArgSpec; - if( lpWord ) - as->sWord = lpWord; - - as->cChar = cChar; - as->proc = proc; - as->val = val; - if( lpDesc ) - as->sDesc = lpDesc; - if( lpExtra ) - as->sExtra = lpExtra; - if( lpValue ) - as->sValue = lpValue; - - lArg.append( as ); - - if( !lBan.isEmpty() ) - { - if( lBan.last()->pBefore == NULL ) - lBan.last()->pBefore = as; - } -} - -void Bu::ParamProc::addParam( const char *lpWord, char cChar, Proc proc, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( lpWord, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); -} - -void Bu::ParamProc::addParam( const char *lpWord, char cChar, ParamPtr val, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( lpWord, cChar, NULL, val, lpDesc, lpExtra, lpValue ); -} - -void Bu::ParamProc::addParam( const char *lpWord, Proc proc, ParamPtr val, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( lpWord, '\0', proc, val, lpDesc, lpExtra, lpValue ); -} - -void Bu::ParamProc::addParam( const char *lpWord, Proc proc, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( lpWord, '\0', proc, ParamPtr(), lpDesc, lpExtra, lpValue ); -} - -void Bu::ParamProc::addParam( const char *lpWord, ParamPtr val, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( lpWord, '\0', NULL, val, lpDesc, lpExtra, lpValue ); -} - -void Bu::ParamProc::addParam( char cChar, Proc proc, ParamPtr val, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( NULL, cChar, proc, val, lpDesc, lpExtra, lpValue ); -} - -void Bu::ParamProc::addParam( char cChar, Proc proc, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( NULL, cChar, proc, ParamPtr(), lpDesc, lpExtra, lpValue ); -} - -void Bu::ParamProc::addParam( char cChar, ParamPtr val, - const char *lpDesc, const char *lpExtra, - const char *lpValue ) -{ - addParam( NULL, cChar, NULL, val, lpDesc, lpExtra, lpValue ); -} - -void Bu::ParamProc::process( int argc, char *argv[] ) -{ - for( int arg = 1; arg < argc; arg++ ) - { - //printf(":::%d:::%s\n", arg, argv[arg] ); - if( argv[arg][0] == '-' ) - { - if( argv[arg][1] == '-' ) - { - ArgSpec *s = checkWord( argv[arg]+2 ); - if( s ) - { - if( argv[arg][s->sWord.getSize()+2] == '=' ) - { - if( s->val.isSet() ) - { - if( s->sValue == "" ) - { - s->val = argv[arg]+s->sWord.getSize()+3; - } - else - { - s->val = s->sValue.getStr(); - } - } - if( s->proc ) - { - char **tmp = new char*[argc-arg]; - tmp[0] = argv[arg]+s->sWord.getSize()+3; - for( int k = 1; k < argc-arg; k++ ) - tmp[k] = argv[arg+k]; - int ret = (this->*s->proc)( argc-arg, tmp ); - if( ret > 0 ) - { - arg += ret-1; - } - delete tmp; - } - } - else - { - int add = 0; - if( s->val.isSet() ) - { - if( s->sValue == "" ) - { - if( arg+1 >= argc ) - { - return; - } - s->val = argv[arg+1]; - add++; - } - else - { - s->val = s->sValue.getStr(); - } - } - if( s->proc ) - { - int ret = (this->*s->proc)( - argc-arg-1, argv+arg+1 ); - - if( ret > add ) - add = 0; - else - add -= ret; - arg += ret; - } - arg += add; - } - continue; - } - else - { - unknownParam( argc-arg, argv+arg ); - } - } - else - { - for( int chr = 1; argv[arg][chr]; chr++ ) - { - ArgSpec *s = checkLetr( argv[arg][chr] ); - if( s ) - { - if( argv[arg][chr+1] != '\0' ) - { - bool bUsed = false; - if( s->val.isSet() ) - { - if( s->sValue == "" ) - { - s->val = argv[arg]+chr+1; - bUsed = true; - } - else - { - s->val = s->sValue.getStr(); - } - } - if( s->proc ) - { - char **tmp = new char*[argc-arg]; - tmp[0] = argv[arg]+chr+1; - for( int k = 1; k < argc-arg; k++ ) - tmp[k] = argv[arg+k]; - int ret = (this->*s->proc)( argc-arg, tmp ); - if( ret > 0 ) - { - arg += ret - 1; - delete tmp; - break; - } - delete tmp; - } - if( bUsed ) - { - break; - } - } - else - { - bool bUsed = false; - if( s->val.isSet() ) - { - if( s->sValue == "" ) - { - s->val = argv[arg+1]; - bUsed = true; - } - else - { - s->val = s->sValue.getStr(); - } - } - if( s->proc ) - { - int ret = (this->*s->proc)( - argc-arg-1, argv+arg+1 - ); - if( ret > 0 ) - { - arg += ret; - break; - } - } - if( bUsed ) - { - arg++; - break; - } - } - } - else - { - unknownParam( argc-arg, argv+arg ); - } - } - } - } - else - { - cmdParam( argc-arg, argv+arg ); - } - } -} - -Bu::ParamProc::ArgSpec *Bu::ParamProc::checkWord( const char *arg ) -{ - //printf("Checking \"%s\"...\n", arg ); - Bu::List::const_iterator i = lArg.begin(); - for( ; i != lArg.end(); i++ ) - { - if( (*i)->sWord == "" ) - continue; - - if( !strcmp( (*i)->sWord.getStr(), arg ) ) - return *i; - - if( (*i)->val.isSet() ) - { - if( !strncmp( (*i)->sWord.getStr(), arg, (*i)->sWord.getSize() ) && - arg[(*i)->sWord.getSize()] == '=' ) - { - return *i; - } - } - } - - return NULL; -} - -Bu::ParamProc::ArgSpec *Bu::ParamProc::checkLetr( const char arg ) -{ - //printf("Checking \'%c\'...\n", arg ); - Bu::List::const_iterator i = lArg.begin(); - for( ; i != lArg.end(); i++ ) - { - if( (*i)->cChar == '\0' ) - continue; - - if( (*i)->cChar == arg ) - { - return *i; - } - } - - return NULL; -} - -int Bu::ParamProc::cmdParam( int /*argc*/, char *argv[] ) -{ - printf("Unhandled command parameter \"%s\" found!\n", argv[0] ); - return 0; -} - -int Bu::ParamProc::unknownParam( int /*argc*/, char *argv[] ) -{ - printf("Unknown parameter \"%s\" found!\n", argv[0] ); - return 0; -} - -int Bu::ParamProc::help( int /*argc*/, char * /*argv*/ [] ) -{ - Bu::List::const_iterator b = lBan.begin(); - Bu::List::const_iterator i = lArg.begin(); - int len=0; - for( ; i != lArg.end(); i++ ) - { - if( len < (*i)->sWord.getSize() + (*i)->sExtra.getSize() ) - len = (*i)->sWord.getSize() + (*i)->sExtra.getSize(); - } - char fmt[10]; - sprintf( fmt, "%%-%ds ", len ); - - for( i = lArg.begin(); i != lArg.end(); i++ ) - { - if( b != lBan.end() ) - { - if( (*b)->pBefore == (*i) ) - { - printf( (*b)->sBanner.getStr() ); - b++; - } - } - printf(" "); - if( (*i)->cChar ) - { - if( (*i)->sWord.getStr() ) - { - printf("-%c, ", (*i)->cChar ); - } - else - { - printf("-%c ", (*i)->cChar ); - } - } - else - { - printf(" "); - } - if( (*i)->sWord.getStr() ) - { - printf("--"); - Bu::FString sTmp = (*i)->sWord.getStr(); - if( (*i)->sExtra.getStr() ) - sTmp += (*i)->sExtra.getStr(); - printf( fmt, sTmp.getStr() ); - } - else - { - printf(" "); - printf(fmt, "" ); - } - printf("%s\n", (*i)->sDesc.getStr() ); - } - if( b != lBan.end() ) - { - if( (*b)->pBefore == NULL ) - { - printf( (*b)->sBanner.getStr() ); - } - } - - exit( 0 ); -} - -void Bu::ParamProc::addHelpBanner( const char *sHelpBanner ) -{ - Banner *pBan = new Banner; - pBan->sBanner = sHelpBanner; - pBan->pBefore = NULL; - lBan.append( pBan ); -} - diff --git a/src/paramproc.h b/src/paramproc.h deleted file mode 100644 index ddc1876..0000000 --- a/src/paramproc.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2007-2010 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#ifndef BU_PARAM_PROC_H -#define BU_PARAM_PROC_H - -#include -#include "bu/list.h" -#include "bu/fstring.h" - -namespace Bu -{ - class ParamProc - { - public: - class ParamPtr - { - public: - ParamPtr(); - ParamPtr( Bu::FString *str ); - ParamPtr( uint64_t *uint64 ); - ParamPtr( uint32_t *uint32 ); - ParamPtr( uint16_t *uint16 ); - ParamPtr( uint8_t *uint8 ); - ParamPtr( int64_t *int64 ); - ParamPtr( int32_t *int32 ); - ParamPtr( int16_t *int16 ); - ParamPtr( int8_t *int8 ); - ParamPtr( float *float32 ); - ParamPtr( double *float64 ); - ParamPtr( long double *float96 ); - ParamPtr( bool *bln ); - - enum - { - vtunset, - vtstr, - vtuint64, - vtuint32, - vtuint16, - vtuint8, - vtint64, - vtint32, - vtint16, - vtint8, - vtfloat32, - vtfloat64, - vtfloat96, - vtbln, - }; - ParamPtr &operator=( ParamPtr &ptr ); - ParamPtr &operator=( const char *str ); - - bool isSet(); - - private: - int type; - union - { - Bu::FString *str; - uint64_t *uint64; - uint32_t *uint32; - uint16_t *uint16; - uint8_t *uint8; - int64_t *int64; - int32_t *int32; - int16_t *int16; - int8_t *int8; - float *float32; - double *float64; - long double *float96; - bool *bln; - } val; - }; - - typedef int (ParamProc::*Proc)( int, char *[] ); - - typedef struct ArgSpec - { - uint8_t nFlags; - Bu::FString sWord; - char cChar; - Proc proc; - ParamProc::ParamPtr val; - Bu::FString sExtra; - Bu::FString sDesc; - Bu::FString sValue; - } ArgSpec; - - public: - DEPRECATED - ParamProc(); - virtual ~ParamProc(); - - void addParam( const char *lpWord, char cChar, Proc proc, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( const char *lpWord, char cChar, Proc proc, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( const char *lpWord, char cChar, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - - void addParam( const char *lpWord, Proc proc, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( const char *lpWord, Proc proc, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( const char *lpWord, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - - void addParam( char cChar, Proc proc, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( char cChar, Proc proc, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - void addParam( char cChar, ParamPtr val, - const char *lpDesc=NULL, const char *lpExtra=NULL, - const char *lpValue=NULL - ); - - void process( int argc, char *argv[] ); - void addHelpBanner( const char *sHelpBanner ); - - private: - ArgSpec *checkWord( const char *arg ); - ArgSpec *checkLetr( const char arg ); - - public: - virtual int cmdParam( int argc, char *argv[] ); - virtual int unknownParam( int argc, char *argv[] ); - virtual int help( int argc, char *argv[] ); - - private: - typedef struct Banner - { - Bu::FString sBanner; - ArgSpec *pBefore; - } Banner; - Bu::List lBan; - Bu::List lArg; - }; -} - -#define mkproc( cls ) static_cast(&cls) - -#endif diff --git a/src/ringbuffer.h b/src/ringbuffer.h index 04add42..f4fd58c 100644 --- a/src/ringbuffer.h +++ b/src/ringbuffer.h @@ -17,6 +17,7 @@ namespace Bu { template class RingBuffer; + /** @cond DEVEL */ template class RingBufferCore { @@ -119,6 +120,7 @@ namespace Bu value *aData; valuealloc va; }; + /** @endcond */ /** *@ingroup Containers diff --git a/src/server.cpp b/src/server.cpp index 51c056a..e701a69 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -8,9 +8,9 @@ #include "bu/server.h" #include #include -#include "bu/serversocket.h" +#include "bu/tcpserversocket.h" #include "bu/client.h" -#include "bu/socket.h" +#include "bu/tcpsocket.h" #include "bu/config.h" Bu::Server::Server() : @@ -28,7 +28,7 @@ Bu::Server::~Server() void Bu::Server::addPort( int nPort, int nPoolSize ) { - ServerSocket *s = new ServerSocket( nPort, nPoolSize ); + TcpServerSocket *s = new TcpServerSocket( nPort, nPoolSize ); int nSocket = s->getSocket(); FD_SET( nSocket, &fdActive ); hServers.insert( nSocket, s ); @@ -36,7 +36,7 @@ void Bu::Server::addPort( int nPort, int nPoolSize ) void Bu::Server::addPort( const FString &sAddr, int nPort, int nPoolSize ) { - ServerSocket *s = new ServerSocket( sAddr, nPort, nPoolSize ); + TcpServerSocket *s = new TcpServerSocket( sAddr, nPort, nPoolSize ); int nSocket = s->getSocket(); FD_SET( nSocket, &fdActive ); hServers.insert( nSocket, s ); @@ -75,7 +75,7 @@ void Bu::Server::scan() { if( hServers.has( j ) ) { - ServerSocket *pSrv = hServers.get( j ); + TcpServerSocket *pSrv = hServers.get( j ); addClient( pSrv->accept(), pSrv->getPort() ); } else @@ -97,7 +97,7 @@ void Bu::Server::scan() { pClient->processOutput(); } - catch( Bu::SocketException &e ) + catch( Bu::TcpSocketException &e ) { closeClient( j ); } @@ -136,7 +136,7 @@ void Bu::Server::addClient( int nSocket, int nPort ) FD_SET( nSocket, &fdActive ); Client *c = new Client( - new Bu::Socket( nSocket ), + new Bu::TcpSocket( nSocket ), new SrvClientLinkFactory() ); hClients.insert( nSocket, c ); diff --git a/src/server.h b/src/server.h index 74ee99a..d6726fd 100644 --- a/src/server.h +++ b/src/server.h @@ -25,8 +25,8 @@ namespace Bu { - class ServerSocket; - class Socket; + class TcpServerSocket; + class TcpSocket; class Client; /** @@ -97,7 +97,7 @@ namespace Bu int nTimeoutSec; int nTimeoutUSec; fd_set fdActive; - typedef Hash SrvHash; + typedef Hash SrvHash; SrvHash hServers; typedef Hash ClientHash; ClientHash hClients; diff --git a/src/serversocket.cpp b/src/serversocket.cpp deleted file mode 100644 index 87d0035..0000000 --- a/src/serversocket.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (C) 2007-2010 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#ifndef WIN32 - #include - #include - #include - #include -#endif - -#include -#include -#include -#include -#include -#include -#include -//#include -#include -#include "bu/serversocket.h" - -#include "bu/config.h" - -namespace Bu { subExceptionDef( ServerSocketException ) } - -Bu::ServerSocket::ServerSocket( int nPort, int nPoolSize ) : - nPort( nPort ) -{ -#ifdef WIN32 - Bu::Winsock2::getInstance(); -#endif - - /* Create the socket and set it up to accept connections. */ - struct sockaddr_in name; - - /* Give the socket a name. */ - name.sin_family = AF_INET; - name.sin_port = bu_htons( nPort ); - - // I think this specifies who we will accept connections from, - // a good thing to make configurable later on - name.sin_addr.s_addr = bu_htonl( INADDR_ANY ); - - startServer( name, nPoolSize ); -} - -Bu::ServerSocket::ServerSocket(const FString &sAddr,int nPort, int nPoolSize) : - nPort( nPort ) -{ -#ifdef WIN32 - Bu::Winsock2::getInstance(); -#endif - - /* Create the socket and set it up to accept connections. */ - struct sockaddr_in name; - - /* Give the socket a name. */ - name.sin_family = AF_INET; - - name.sin_port = bu_htons( nPort ); - -#ifdef WIN32 - name.sin_addr.s_addr = bu_inet_addr( sAddr.getStr() ); -#else - inet_aton( sAddr.getStr(), &name.sin_addr ); -#endif - - startServer( name, nPoolSize ); -} - -Bu::ServerSocket::ServerSocket( int nServer, bool bInit, int nPoolSize ) : - nServer( nServer ), - nPort( 0 ) -{ -#ifdef WIN32 - Bu::Winsock2::getInstance(); -#endif - - if( bInit ) - { - struct sockaddr name; - socklen_t namelen = sizeof(name); - getpeername( nServer, &name, &namelen ); - - initServer( *((sockaddr_in *)&name), nPoolSize ); - } - else - { - FD_ZERO( &fdActive ); - FD_SET( nServer, &fdActive ); - } -} - -Bu::ServerSocket::ServerSocket( const ServerSocket &rSrc ) -{ -#ifdef WIN32 - Bu::Winsock2::getInstance(); -#endif - - nServer = dup( rSrc.nServer ); - nPort = rSrc.nPort; - FD_ZERO( &fdActive ); - FD_SET( nServer, &fdActive ); -} - -Bu::ServerSocket::~ServerSocket() -{ - if( nServer > -1 ) - ::close( nServer ); -} - -void Bu::ServerSocket::startServer( struct sockaddr_in &name, int nPoolSize ) -{ - /* Create the socket. */ - nServer = bu_socket( PF_INET, SOCK_STREAM, 0 ); - - if( nServer < 0 ) - { - throw Bu::ServerSocketException("Couldn't create a listen socket."); - } - - int opt = 1; - bu_setsockopt( - nServer, - SOL_SOCKET, - SO_REUSEADDR, - (char *)&opt, - sizeof( opt ) - ); - - initServer( name, nPoolSize ); -} - -void Bu::ServerSocket::initServer( struct sockaddr_in &name, int nPoolSize ) -{ - if( bu_bind( nServer, (struct sockaddr *) &name, sizeof(name) ) < 0 ) - { - throw Bu::ServerSocketException("Couldn't bind to the listen socket."); - } - - if( bu_listen( nServer, nPoolSize ) < 0 ) - { - throw Bu::ServerSocketException( - "Couldn't begin listening to the server socket." - ); - } - - FD_ZERO( &fdActive ); - /* Initialize the set of active sockets. */ - FD_SET( nServer, &fdActive ); -} - -int Bu::ServerSocket::getSocket() -{ - return nServer; -} - -int Bu::ServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) -{ - fd_set fdRead = fdActive; - - struct timeval xT; - - xT.tv_sec = nTimeoutSec; - xT.tv_usec = nTimeoutUSec; - - if( TEMP_FAILURE_RETRY( - bu_select( nServer+1, &fdRead, NULL, NULL, &xT )) < 0 ) - { - throw Bu::ServerSocketException( - "Error scanning for new connections: %s", strerror( errno ) - ); - } - - if( FD_ISSET( nServer, &fdRead ) ) - { - struct sockaddr_in clientname; - socklen_t size; - int nClient; - - size = sizeof( clientname ); -#ifdef WIN32 - nClient = bu_accept( nServer, (struct sockaddr *)&clientname, &size); -#else /* not-WIN32 */ -#ifdef __CYGWIN__ - nClient = ::accept( nServer, (struct sockaddr *)&clientname, - (int *)&size - ); -#else /* not-cygwin */ -#ifdef __APPLE__ - nClient = ::accept( nServer, (struct sockaddr *)&clientname, (socklen_t*)&size ); -#else /* linux */ - nClient = ::accept( nServer, (struct sockaddr *)&clientname, &size ); -#endif /* __APPLE__ */ -#endif /* __CYGWIN__ */ -#endif /* WIN32 */ - if( nClient < 0 ) - { - throw Bu::ServerSocketException( - "Error accepting a new connection: %s", strerror( errno ) - ); - } - -#ifndef WIN32 - char tmpa[20]; - inet_ntop( AF_INET, (void *)&clientname.sin_addr, tmpa, 20 ); - //"New connection from host %s, port %hd.", - // tmpa, ntohs (clientname.sin_port) ); -#endif - - { -#ifndef WIN32 - int flags; - flags = fcntl( nClient, F_GETFL, 0 ); - flags |= O_NONBLOCK; - if( fcntl( nClient, F_SETFL, flags ) < 0) - { - throw Bu::ServerSocketException( - "Error setting option on client socket: %s", - strerror( errno ) - ); - } -#else - //------------------------- - // Set the socket I/O mode: In this case FIONBIO - // enables or disables the blocking mode for the - // socket based on the numerical value of iMode. - // If iMode = 0, blocking is enabled; - // If iMode != 0, non-blocking mode is enabled. - u_long iMode = 1; - bu_ioctlsocket(nClient, FIONBIO, &iMode); -#endif - } - - return nClient; - } - - return -1; -} - -int Bu::ServerSocket::getPort() -{ - return nPort; -} - diff --git a/src/serversocket.h b/src/serversocket.h deleted file mode 100644 index ee357a4..0000000 --- a/src/serversocket.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2007-2010 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#ifndef BU_SERVER_SOCKET_H -#define BU_SERVER_SOCKET_H - -#include -#include "bu/fstring.h" -#include "bu/exceptionbase.h" - -#ifdef WIN32 - #include -#else - #include -#endif - -namespace Bu -{ - subExceptionDecl( ServerSocketException ); - - /** - * A single tcp/ip server socket. When created the server socket will bind - * to the specified interface and port, and immediately begin listening for - * connections. When connections come in they are pooled by the networking - * drivers in the kernel until they are accepted, this means that failure - * to keep space in the connection pool will result in connection refusals. - * - * Although the accept function returns an integral file descriptor, it is - * designed to be used with the Socket class. - * - *@ingroup Serving - */ - class ServerSocket - { - public: - ServerSocket( int nPort, int nPoolSize=40 ); - ServerSocket( const FString &sAddr, int nPort, int nPoolSize=40 ); - ServerSocket( int nSocket, bool bInit, int nPoolSize=40 ); - ServerSocket( const ServerSocket &rSrc ); - virtual ~ServerSocket(); - - int accept( int nTimeoutSec=0, int nTimeoutUSec=0 ); - int getSocket(); - int getPort(); - - private: - void startServer( struct sockaddr_in &name, int nPoolSize ); - void initServer( struct sockaddr_in &name, int nPoolSize ); - - fd_set fdActive; -#ifdef WIN32 - unsigned int nServer; -#else - int nServer; -#endif - int nPort; - }; -} - -#endif diff --git a/src/sharedcore.h b/src/sharedcore.h index ac36606..1887ca2 100644 --- a/src/sharedcore.h +++ b/src/sharedcore.h @@ -15,6 +15,53 @@ namespace Bu { + /** + * A mechanism for creating classes that perform lazy copies. The concept + * behind this is that instead of copying a large object when it is assigned + * or passed into a copy constructor we simply copy a pointer internally. + * The assumption is that many times when an object is passed by value we + * don't really want to keep the object around, we want the recipient to + * take ownership without allocating a new object. This allows that to + * happen. + * + * When used properly this makes object copying essentially free (O(1), + * that is) and performs the actual copy when a user tries to modify the + * object. + * + * For example, lets look at something like the getKeys function in + * Bu::Hash. When this function is called it creates a Bu::List of + * appropriate type, fills it with keys, and returns it. This is a good + * way for this function to behave, there may be additional issues if the + * List object were allocated with new and not on the stack. However, + * returning the List at the end of the function could potentially take + * a very long time depending on the size of the list and the type of the + * key. In this case the getKeys function doesn't want ownership of the + * List object, and when it returns it, it's local copy will be destroyed. + * + * However, List inherits from SharedCore, which means that when it is + * returned all we do is copy a pointer to the "core" of the list, which + * is a very fast operatorion. For a brief moment, before anyone can do + * anything else, there are two objects referencing the core of that single + * list. However, the getKeys() function will destroy it's local copy + * before the calling function can use it's new copy. That means that by + * the time the calling function can use it's new List of keys it is the + * only one with a reference to the core, and no copy will need to happen. + * + * Using SharedCore on your own classes is fairly straight forward. There + * are only a couple of steps. First, break the class into two classes. + * Move every variable from the original class (generally everything that's + * private) into the new class. Then make the original class inherit from + * SharedCore. The SharedCore template takes 2 parameters, first is the + * class it's inheriting from, second is the new core class. Now, in your + * original class you will have one class variable, a pointer named core. + * All of your original variables will be accessable through core. The next + * step is to access everything you used to through core, and to find + * every function that may change data in the core. At the top of every + * function that may change data you want to call _hardCopy(). + * + * That's more or less it. A more detailed guide will be written soon. + * @todo Write a guide for this. + */ template class SharedCore { diff --git a/src/socket.cpp b/src/socket.cpp deleted file mode 100644 index baf3be3..0000000 --- a/src/socket.cpp +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright (C) 2007-2010 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bu/socket.h" - -#include "bu/config.h" - -#ifndef WIN32 - #include - #include - #include - #include -#else - #include -#endif - -#define RBS (1024*2) - -namespace Bu { subExceptionDef( SocketException ) } - -Bu::Socket::Socket( int nSocket ) : - nSocket( nSocket ), - bActive( true ), - bBlocking( true ) -{ -#ifdef WIN32 - Bu::Winsock2::getInstance(); -#endif - setAddress(); -} - -Bu::Socket::Socket( const Bu::FString &sAddr, int nPort, int nTimeout ) : - nSocket( 0 ), - bActive( false ), - bBlocking( true ) -{ -#ifdef WIN32 - Bu::Winsock2::getInstance(); -#endif - - /* Create the socket. */ - nSocket = bu_socket( PF_INET, SOCK_STREAM, 0 ); - - if( nSocket < 0 ) - { - throw ExceptionBase("Couldn't create socket.\n"); - } - - setBlocking( false ); - - /* Connect to the server. */ - //printf("Resolving hostname (%s)...\n", sAddr ); - { - struct addrinfo *pAddr = NULL; - struct addrinfo aiHints; - memset( &aiHints, 0, sizeof(addrinfo) ); - aiHints.ai_flags = AI_CANONNAME; - aiHints.ai_family = AF_INET; - aiHints.ai_socktype = SOCK_STREAM; - char ibuf[10]; - sprintf( ibuf, "%d", nPort ); - - int ret; - if( (ret = bu_getaddrinfo( - sAddr.getStr(), ibuf, &aiHints, &pAddr )) != 0 ) - { - close(); - throw Bu::SocketException("Couldn't resolve hostname %s (%s).\n", - sAddr.getStr(), bu_gai_strerror(ret)); - } - - bu_connect( - nSocket, - pAddr->ai_addr, - pAddr->ai_addrlen - ); - - sAddress = pAddr->ai_canonname; - - bu_freeaddrinfo( pAddr ); - } - - bActive = true; - - if( nTimeout > 0 ) - { - fd_set rfds, wfds, efds; - int retval; - - FD_ZERO(&rfds); - FD_SET(nSocket, &rfds); - FD_ZERO(&wfds); - FD_SET(nSocket, &wfds); - FD_ZERO(&efds); - FD_SET(nSocket, &efds); - - struct timeval tv; - tv.tv_sec = nTimeout; - tv.tv_usec = 0; - - retval = bu_select( nSocket+1, &rfds, &wfds, &efds, &tv ); - - if( retval == 0 ) - { - close(); - throw ExceptionBase("Connection timeout.\n"); - } - read( NULL, 0 ); // See if we can get any errors out of the way early. - } -} - -Bu::Socket::~Socket() -{ - close(); -} - -void Bu::Socket::close() -{ - if( bActive ) - { -#ifndef WIN32 - fsync( nSocket ); -#endif -#ifdef WIN32 - #ifndef SHUT_RDWR - #define SHUT_RDWR (SD_BOTH) - #endif -#endif - bu_shutdown( nSocket, SHUT_RDWR ); - ::close( nSocket ); - } - bActive = false; -} - -size_t Bu::Socket::read( void *pBuf, size_t nBytes ) -{ - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(nSocket, &rfds); - struct timeval tv = {0, 0}; - if( bu_select( nSocket+1, &rfds, NULL, NULL, &tv ) < 0 ) - { - int iErr = errno; - close(); - throw SocketException( SocketException::cRead, strerror(iErr) ); - } - if( FD_ISSET( nSocket, &rfds ) || bBlocking ) - { - int nRead = TEMP_FAILURE_RETRY( - bu_recv( nSocket, (char *) pBuf, nBytes, 0 ) ); - if( nRead == 0 ) - { - close(); - throw SocketException( SocketException::cClosed, "Socket closed."); - } - if( nRead < 0 ) - { -#ifdef WIN32 - int iWSAError = bu_WSAGetLastError(); - if( iWSAError == WSAEWOULDBLOCK ) - return 0; -#else - if( errno == ENETRESET || errno == ECONNRESET ) - { - close(); - throw SocketException( SocketException::cClosed, - strerror(errno) ); - } - if( errno == EAGAIN ) - return 0; - int iErr = errno; - close(); - throw SocketException( SocketException::cRead, strerror(iErr) ); -#endif - } - return nRead; - } - return 0; -} - -size_t Bu::Socket::read( void *pBuf, size_t nBytes, - uint32_t nSec, uint32_t nUSec ) -{ - struct timeval tv; - size_t nRead = 0; - - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(nSocket, &rfds); - -#ifdef WIN32 - DWORD dwStart = GetTickCount(); - uint64_t uOver = dwStart + ((nUSec / 1000) * (nSec * 1000)); - DWORD dwEnd = uOver>4294967295U?uOver-4294967295U:uOver; -#else - struct timeval nt, ct; - gettimeofday( &nt, NULL ); - nt.tv_sec += nSec; - nt.tv_usec += nUSec; -#endif - - for(;;) - { - tv.tv_sec = nSec; - tv.tv_usec = nUSec; - bu_select( nSocket+1, &rfds, NULL, NULL, &tv ); - nRead += read( ((char *)pBuf)+nRead, nBytes-nRead ); - if( nRead >= nBytes ) - break; -#ifdef WIN32 - DWORD dwNow = GetTickCount(); - if( dwNow > dwEnd ) - break; -#else - gettimeofday( &ct, NULL ); - if( (ct.tv_sec > nt.tv_sec) || - (ct.tv_sec == nt.tv_sec && - ct.tv_usec >= nt.tv_usec) ) - break; -#endif - } - return nRead; -} - -size_t Bu::Socket::write( const void *pBuf, size_t nBytes ) -{ -//#ifdef WIN32 - int nWrote = TEMP_FAILURE_RETRY( - bu_send( nSocket, (const char *) pBuf, nBytes, 0 ) ); -//#else -// int nWrote = TEMP_FAILURE_RETRY( ::write( nSocket, pBuf, nBytes ) ); -//#endif - if( nWrote < 0 ) - { -#ifdef WIN32 - int iWSAError = bu_WSAGetLastError(); - if( iWSAError == WSAEWOULDBLOCK ) - return 0; -#else - if( errno == EAGAIN ) return 0; -#endif - throw SocketException( SocketException::cWrite, strerror(errno) ); - } - return nWrote; -} - -size_t Bu::Socket::write( const void *pBuf, size_t nBytes, uint32_t nSec, uint32_t nUSec ) -{ - struct timeval tv; - size_t nWrote = 0; - - fd_set wfds; - FD_ZERO(&wfds); - FD_SET(nSocket, &wfds); - -#ifdef WIN32 - DWORD dwStart = GetTickCount(); - uint64_t uOver = dwStart + ((nUSec / 1000) * (nSec * 1000)); - DWORD dwEnd = uOver>4294967295U?uOver-4294967295U:uOver; -#else - struct timeval nt, ct; - gettimeofday( &nt, NULL ); - nt.tv_sec += nSec; - nt.tv_usec += nUSec; -#endif - - for(;;) - { - tv.tv_sec = nSec; - tv.tv_usec = nUSec; - bu_select( nSocket+1, NULL, &wfds, NULL, &tv ); - nWrote += write( ((char *)pBuf)+nWrote, nBytes-nWrote ); - if( nWrote >= nBytes ) - break; -#ifdef WIN32 - DWORD dwNow = GetTickCount(); - if( dwNow > dwEnd ) - break; -#else - gettimeofday( &ct, NULL ); - if( (ct.tv_sec > nt.tv_sec) || - (ct.tv_sec == nt.tv_sec && - ct.tv_usec >= nt.tv_usec) ) - break; -#endif - } - return nWrote; -} - -long Bu::Socket::tell() -{ - throw UnsupportedException(); -} - -void Bu::Socket::seek( long ) -{ - throw UnsupportedException(); -} - -void Bu::Socket::setPos( long ) -{ - throw UnsupportedException(); -} - -void Bu::Socket::setPosEnd( long ) -{ - throw UnsupportedException(); -} - -bool Bu::Socket::isEos() -{ - return !bActive; -} - -bool Bu::Socket::canRead() -{ - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(nSocket, &rfds); - struct timeval tv = { 0, 0 }; - int retval = bu_select( nSocket+1, &rfds, NULL, NULL, &tv ); - if( retval == -1 ) - throw SocketException( - SocketException::cBadRead, - "Bad Read error" - ); - - if( !FD_ISSET( nSocket, &rfds ) ) - return false; - return true; -} - -bool Bu::Socket::canWrite() -{ - fd_set wfds; - FD_ZERO(&wfds); - FD_SET(nSocket, &wfds); - struct timeval tv = { 0, 0 }; - int retval = bu_select( nSocket+1, NULL, &wfds, NULL, &tv ); - if( retval == -1 ) - throw SocketException( - SocketException::cBadRead, - "Bad Read error" - ); - if( !FD_ISSET( nSocket, &wfds ) ) - return false; - return true; -} - -bool Bu::Socket::isReadable() -{ - return true; -} - -bool Bu::Socket::isWritable() -{ - return true; -} - -bool Bu::Socket::isSeekable() -{ - return false; -} - -bool Bu::Socket::isBlocking() -{ -#ifndef WIN32 - return ((fcntl( nSocket, F_GETFL, 0 ) & O_NONBLOCK) != O_NONBLOCK); -#else - return false; -#endif -} - -void Bu::Socket::setBlocking( bool bBlocking ) -{ - this->bBlocking = bBlocking; -#ifndef WIN32 - if( bBlocking ) - { - fcntl( nSocket, F_SETFL, fcntl( nSocket, F_GETFL, 0 ) & (~O_NONBLOCK) ); - } - else - { - fcntl( nSocket, F_SETFL, fcntl( nSocket, F_GETFL, 0 ) | O_NONBLOCK ); - } -#else - u_long iMode; - if( bBlocking ) - iMode = 0; - else - iMode = 1; - //------------------------- - // Set the socket I/O mode: In this case FIONBIO - // enables or disables the blocking mode for the - // socket based on the numerical value of iMode. - // If iMode = 0, blocking is enabled; - // If iMode != 0, non-blocking mode is enabled. - bu_ioctlsocket(nSocket, FIONBIO, &iMode); -#endif -} - -void Bu::Socket::setSize( long ) -{ -} - -void Bu::Socket::flush() -{ -} - -bool Bu::Socket::isOpen() -{ - return bActive; -} - -void Bu::Socket::setAddress() -{ - struct sockaddr_in addr; - socklen_t len = sizeof(addr); - addr.sin_family = AF_INET; - bu_getpeername( nSocket, (sockaddr *)(&addr), &len ); - sAddress = bu_inet_ntoa( addr.sin_addr ); -} - -Bu::FString Bu::Socket::getAddress() const -{ - return sAddress; -} - -Bu::Socket::operator int() const -{ - return nSocket; -} - diff --git a/src/socket.h b/src/socket.h deleted file mode 100644 index c8f78f0..0000000 --- a/src/socket.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2007-2010 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#ifndef BU_SOCKET_H -#define BU_SOCKET_H - -#include - -#include "bu/stream.h" -#include "bu/fstring.h" -#include "bu/exceptionbase.h" - -namespace Bu -{ - subExceptionDeclBegin( SocketException ); - enum { - cRead, - cWrite, - cBadRead, - cClosed, - cTimeout - }; - subExceptionDeclEnd(); - - /** - * Network socket stream class. This class provides a mechanism for - * communicating over a network using TCP/IP. It will provide other low - * level protocol and addressing support later on, but for now it's just - * standard STREAM TCP/IP sockets. - * - * Unlike system sockets, these sockets are opened by default in - * non-blocking mode, you can specify your own timeout for opening a socket, - * and a number of non-fatal error messages have been automatically handled - * and treated as standard no-data-available-yet situations on read. - * - * Please note that there is a condition that will occur eventually (at - * least on *nix systems) that will trigger a SIGPIPE condition. This - * will terminate your program immediately unless handled properly. Most - * people doing any connections with Socket will want to put this in their - * program somewhere before they use it: - *@code - #include - ... - ... - ... - sigset( SIGPIPE, SIG_IGN ); // do this before you use a Bu::Socket - @endcode - * When this is done, Bu::Socket will simply throw a broken pipe exception - * just like every other error condition, allowing your program to handle - * it sanely. - * - *@ingroup Serving - *@ingroup Streams - */ - class Socket : public Stream - { - public: - Socket( int nSocket ); - Socket( const FString &sAddr, int nPort, int nTimeout=30 ); - virtual ~Socket(); - - virtual void close(); - //virtual void read(); - virtual size_t read( void *pBuf, size_t nBytes ); - virtual size_t read( void *pBuf, size_t nBytes, - uint32_t nSec, uint32_t nUSec=0 ); - virtual size_t write( const void *pBuf, size_t nBytes ); - virtual size_t write( const void *pBuf, size_t nBytes, - uint32_t nSec, uint32_t nUSec=0 ); - using Stream::write; - - virtual long tell(); - virtual void seek( long offset ); - virtual void setPos( long pos ); - virtual void setPosEnd( long pos ); - virtual bool isEos(); - virtual bool isOpen(); - - virtual void flush(); - - virtual bool canRead(); - virtual bool canWrite(); - - virtual bool isReadable(); - virtual bool isWritable(); - virtual bool isSeekable(); - - virtual bool isBlocking(); - virtual void setBlocking( bool bBlocking=true ); - - virtual void setSize( long iSize ); - - Bu::FString getAddress() const; - operator int() const; - - private: - void setAddress(); - -#ifdef WIN32 - unsigned int nSocket; -#else - int nSocket; -#endif - bool bActive; - bool bBlocking; - FString sReadBuf; - FString sAddress; - }; -} - -#endif diff --git a/src/tcpserversocket.cpp b/src/tcpserversocket.cpp new file mode 100644 index 0000000..7d7f6e4 --- /dev/null +++ b/src/tcpserversocket.cpp @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2007-2010 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#ifndef WIN32 + #include + #include + #include + #include +#endif + +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include "bu/tcpserversocket.h" + +#include "bu/config.h" + +namespace Bu { subExceptionDef( TcpServerSocketException ) } + +Bu::TcpServerSocket::TcpServerSocket( int nPort, int nPoolSize ) : + nPort( nPort ) +{ +#ifdef WIN32 + Bu::Winsock2::getInstance(); +#endif + + /* Create the socket and set it up to accept connections. */ + struct sockaddr_in name; + + /* Give the socket a name. */ + name.sin_family = AF_INET; + name.sin_port = bu_htons( nPort ); + + // I think this specifies who we will accept connections from, + // a good thing to make configurable later on + name.sin_addr.s_addr = bu_htonl( INADDR_ANY ); + + startServer( name, nPoolSize ); +} + +Bu::TcpServerSocket::TcpServerSocket(const FString &sAddr,int nPort, int nPoolSize) : + nPort( nPort ) +{ +#ifdef WIN32 + Bu::Winsock2::getInstance(); +#endif + + /* Create the socket and set it up to accept connections. */ + struct sockaddr_in name; + + /* Give the socket a name. */ + name.sin_family = AF_INET; + + name.sin_port = bu_htons( nPort ); + +#ifdef WIN32 + name.sin_addr.s_addr = bu_inet_addr( sAddr.getStr() ); +#else + inet_aton( sAddr.getStr(), &name.sin_addr ); +#endif + + startServer( name, nPoolSize ); +} + +Bu::TcpServerSocket::TcpServerSocket( int nServer, bool bInit, int nPoolSize ) : + nServer( nServer ), + nPort( 0 ) +{ +#ifdef WIN32 + Bu::Winsock2::getInstance(); +#endif + + if( bInit ) + { + struct sockaddr name; + socklen_t namelen = sizeof(name); + getpeername( nServer, &name, &namelen ); + + initServer( *((sockaddr_in *)&name), nPoolSize ); + } + else + { + FD_ZERO( &fdActive ); + FD_SET( nServer, &fdActive ); + } +} + +Bu::TcpServerSocket::TcpServerSocket( const TcpServerSocket &rSrc ) +{ +#ifdef WIN32 + Bu::Winsock2::getInstance(); +#endif + + nServer = dup( rSrc.nServer ); + nPort = rSrc.nPort; + FD_ZERO( &fdActive ); + FD_SET( nServer, &fdActive ); +} + +Bu::TcpServerSocket::~TcpServerSocket() +{ + if( nServer > -1 ) + ::close( nServer ); +} + +void Bu::TcpServerSocket::startServer( struct sockaddr_in &name, int nPoolSize ) +{ + /* Create the socket. */ + nServer = bu_socket( PF_INET, SOCK_STREAM, 0 ); + + if( nServer < 0 ) + { + throw Bu::TcpServerSocketException("Couldn't create a listen socket."); + } + + int opt = 1; + bu_setsockopt( + nServer, + SOL_SOCKET, + SO_REUSEADDR, + (char *)&opt, + sizeof( opt ) + ); + + initServer( name, nPoolSize ); +} + +void Bu::TcpServerSocket::initServer( struct sockaddr_in &name, int nPoolSize ) +{ + if( bu_bind( nServer, (struct sockaddr *) &name, sizeof(name) ) < 0 ) + { + throw Bu::TcpServerSocketException("Couldn't bind to the listen socket."); + } + + if( bu_listen( nServer, nPoolSize ) < 0 ) + { + throw Bu::TcpServerSocketException( + "Couldn't begin listening to the server socket." + ); + } + + FD_ZERO( &fdActive ); + /* Initialize the set of active sockets. */ + FD_SET( nServer, &fdActive ); +} + +int Bu::TcpServerSocket::getSocket() +{ + return nServer; +} + +int Bu::TcpServerSocket::accept( int nTimeoutSec, int nTimeoutUSec ) +{ + fd_set fdRead = fdActive; + + struct timeval xT; + + xT.tv_sec = nTimeoutSec; + xT.tv_usec = nTimeoutUSec; + + if( TEMP_FAILURE_RETRY( + bu_select( nServer+1, &fdRead, NULL, NULL, &xT )) < 0 ) + { + throw Bu::TcpServerSocketException( + "Error scanning for new connections: %s", strerror( errno ) + ); + } + + if( FD_ISSET( nServer, &fdRead ) ) + { + struct sockaddr_in clientname; + socklen_t size; + int nClient; + + size = sizeof( clientname ); +#ifdef WIN32 + nClient = bu_accept( nServer, (struct sockaddr *)&clientname, &size); +#else /* not-WIN32 */ +#ifdef __CYGWIN__ + nClient = ::accept( nServer, (struct sockaddr *)&clientname, + (int *)&size + ); +#else /* not-cygwin */ +#ifdef __APPLE__ + nClient = ::accept( nServer, (struct sockaddr *)&clientname, (socklen_t*)&size ); +#else /* linux */ + nClient = ::accept( nServer, (struct sockaddr *)&clientname, &size ); +#endif /* __APPLE__ */ +#endif /* __CYGWIN__ */ +#endif /* WIN32 */ + if( nClient < 0 ) + { + throw Bu::TcpServerSocketException( + "Error accepting a new connection: %s", strerror( errno ) + ); + } + +#ifndef WIN32 + char tmpa[20]; + inet_ntop( AF_INET, (void *)&clientname.sin_addr, tmpa, 20 ); + //"New connection from host %s, port %hd.", + // tmpa, ntohs (clientname.sin_port) ); +#endif + + { +#ifndef WIN32 + int flags; + flags = fcntl( nClient, F_GETFL, 0 ); + flags |= O_NONBLOCK; + if( fcntl( nClient, F_SETFL, flags ) < 0) + { + throw Bu::TcpServerSocketException( + "Error setting option on client socket: %s", + strerror( errno ) + ); + } +#else + //------------------------- + // Set the socket I/O mode: In this case FIONBIO + // enables or disables the blocking mode for the + // socket based on the numerical value of iMode. + // If iMode = 0, blocking is enabled; + // If iMode != 0, non-blocking mode is enabled. + u_long iMode = 1; + bu_ioctlsocket(nClient, FIONBIO, &iMode); +#endif + } + + return nClient; + } + + return -1; +} + +int Bu::TcpServerSocket::getPort() +{ + return nPort; +} + diff --git a/src/tcpserversocket.h b/src/tcpserversocket.h new file mode 100644 index 0000000..b1d7e02 --- /dev/null +++ b/src/tcpserversocket.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2007-2010 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#ifndef BU_TCP_SERVER_SOCKET_H +#define BU_TCP_SERVER_SOCKET_H + +#include +#include "bu/fstring.h" +#include "bu/exceptionbase.h" + +#ifdef WIN32 + #include +#else + #include +#endif + +namespace Bu +{ + subExceptionDecl( TcpServerSocketException ); + + /** + * A single tcp/ip server socket. When created the server socket will bind + * to the specified interface and port, and immediately begin listening for + * connections. When connections come in they are pooled by the networking + * drivers in the kernel until they are accepted, this means that failure + * to keep space in the connection pool will result in connection refusals. + * + * Although the accept function returns an integral file descriptor, it is + * designed to be used with the Socket class. + * + *@ingroup Serving + */ + class TcpServerSocket + { + public: + TcpServerSocket( int nPort, int nPoolSize=40 ); + TcpServerSocket( const FString &sAddr, int nPort, int nPoolSize=40 ); + TcpServerSocket( int nSocket, bool bInit, int nPoolSize=40 ); + TcpServerSocket( const TcpServerSocket &rSrc ); + virtual ~TcpServerSocket(); + + int accept( int nTimeoutSec=0, int nTimeoutUSec=0 ); + int getSocket(); + int getPort(); + + private: + void startServer( struct sockaddr_in &name, int nPoolSize ); + void initServer( struct sockaddr_in &name, int nPoolSize ); + + fd_set fdActive; +#ifdef WIN32 + unsigned int nServer; +#else + int nServer; +#endif + int nPort; + }; +} + +#endif diff --git a/src/tcpsocket.cpp b/src/tcpsocket.cpp new file mode 100644 index 0000000..bbd9cf5 --- /dev/null +++ b/src/tcpsocket.cpp @@ -0,0 +1,450 @@ +/* + * Copyright (C) 2007-2010 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bu/tcpsocket.h" + +#include "bu/config.h" + +#ifndef WIN32 + #include + #include + #include + #include +#else + #include +#endif + +#define RBS (1024*2) + +namespace Bu { subExceptionDef( TcpSocketException ) } + +Bu::TcpSocket::TcpSocket( int nTcpSocket ) : + nTcpSocket( nTcpSocket ), + bActive( true ), + bBlocking( true ) +{ +#ifdef WIN32 + Bu::Winsock2::getInstance(); +#endif + setAddress(); +} + +Bu::TcpSocket::TcpSocket( const Bu::FString &sAddr, int nPort, int nTimeout, + bool bBlocking ) : + nTcpSocket( 0 ), + bActive( false ), + bBlocking( true ) +{ +#ifdef WIN32 + Bu::Winsock2::getInstance(); +#endif + + /* Create the socket. */ + nTcpSocket = bu_socket( PF_INET, SOCK_STREAM, 0 ); + + if( nTcpSocket < 0 ) + { + throw ExceptionBase("Couldn't create socket.\n"); + } + + setBlocking( false ); + + /* Connect to the server. */ + //printf("Resolving hostname (%s)...\n", sAddr ); + { + struct addrinfo *pAddr = NULL; + struct addrinfo aiHints; + memset( &aiHints, 0, sizeof(addrinfo) ); + aiHints.ai_flags = AI_CANONNAME; + aiHints.ai_family = AF_INET; + aiHints.ai_socktype = SOCK_STREAM; + char ibuf[10]; + sprintf( ibuf, "%d", nPort ); + + int ret; + if( (ret = bu_getaddrinfo( + sAddr.getStr(), ibuf, &aiHints, &pAddr )) != 0 ) + { + close(); + throw Bu::TcpSocketException("Couldn't resolve hostname %s (%s).\n", + sAddr.getStr(), bu_gai_strerror(ret)); + } + + bu_connect( + nTcpSocket, + pAddr->ai_addr, + pAddr->ai_addrlen + ); + + sAddress = pAddr->ai_canonname; + + bu_freeaddrinfo( pAddr ); + } + + bActive = true; + + if( nTimeout > 0 ) + { + fd_set rfds, wfds, efds; + int retval; + + FD_ZERO(&rfds); + FD_SET(nTcpSocket, &rfds); + FD_ZERO(&wfds); + FD_SET(nTcpSocket, &wfds); + FD_ZERO(&efds); + FD_SET(nTcpSocket, &efds); + + struct timeval tv; + tv.tv_sec = nTimeout; + tv.tv_usec = 0; + + retval = bu_select( nTcpSocket+1, &rfds, &wfds, &efds, &tv ); + + if( retval == 0 ) + { + close(); + throw ExceptionBase("Connection timeout.\n"); + } + read( NULL, 0 ); // See if we can get any errors out of the way early. + } + + if( bBlocking ) + setBlocking( bBlocking ); +} + +Bu::TcpSocket::~TcpSocket() +{ + close(); +} + +void Bu::TcpSocket::close() +{ + if( bActive ) + { +#ifndef WIN32 + fsync( nTcpSocket ); +#endif +#ifdef WIN32 + #ifndef SHUT_RDWR + #define SHUT_RDWR (SD_BOTH) + #endif +#endif + bu_shutdown( nTcpSocket, SHUT_RDWR ); + ::close( nTcpSocket ); + } + bActive = false; +} + +size_t Bu::TcpSocket::read( void *pBuf, size_t nBytes ) +{ + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(nTcpSocket, &rfds); + struct timeval tv = {0, 0}; + if( bu_select( nTcpSocket+1, &rfds, NULL, NULL, &tv ) < 0 ) + { + int iErr = errno; + close(); + throw TcpSocketException( TcpSocketException::cRead, strerror(iErr) ); + } + if( FD_ISSET( nTcpSocket, &rfds ) || bBlocking ) + { + int nRead = TEMP_FAILURE_RETRY( + bu_recv( nTcpSocket, (char *) pBuf, nBytes, 0 ) ); + if( nRead == 0 ) + { + close(); + throw TcpSocketException( TcpSocketException::cClosed, "TcpSocket closed."); + } + if( nRead < 0 ) + { +#ifdef WIN32 + int iWSAError = bu_WSAGetLastError(); + if( iWSAError == WSAEWOULDBLOCK ) + return 0; +#else + if( errno == ENETRESET || errno == ECONNRESET ) + { + close(); + throw TcpSocketException( TcpSocketException::cClosed, + strerror(errno) ); + } + if( errno == EAGAIN ) + return 0; + int iErr = errno; + close(); + throw TcpSocketException( TcpSocketException::cRead, strerror(iErr) ); +#endif + } + return nRead; + } + return 0; +} + +size_t Bu::TcpSocket::read( void *pBuf, size_t nBytes, + uint32_t nSec, uint32_t nUSec ) +{ + struct timeval tv; + size_t nRead = 0; + + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(nTcpSocket, &rfds); + +#ifdef WIN32 + DWORD dwStart = GetTickCount(); + uint64_t uOver = dwStart + ((nUSec / 1000) * (nSec * 1000)); + DWORD dwEnd = uOver>4294967295U?uOver-4294967295U:uOver; +#else + struct timeval nt, ct; + gettimeofday( &nt, NULL ); + nt.tv_sec += nSec; + nt.tv_usec += nUSec; +#endif + + for(;;) + { + tv.tv_sec = nSec; + tv.tv_usec = nUSec; + bu_select( nTcpSocket+1, &rfds, NULL, NULL, &tv ); + nRead += read( ((char *)pBuf)+nRead, nBytes-nRead ); + if( nRead >= nBytes ) + break; +#ifdef WIN32 + DWORD dwNow = GetTickCount(); + if( dwNow > dwEnd ) + break; +#else + gettimeofday( &ct, NULL ); + if( (ct.tv_sec > nt.tv_sec) || + (ct.tv_sec == nt.tv_sec && + ct.tv_usec >= nt.tv_usec) ) + break; +#endif + } + return nRead; +} + +size_t Bu::TcpSocket::write( const void *pBuf, size_t nBytes ) +{ +//#ifdef WIN32 + int nWrote = TEMP_FAILURE_RETRY( + bu_send( nTcpSocket, (const char *) pBuf, nBytes, 0 ) ); +//#else +// int nWrote = TEMP_FAILURE_RETRY( ::write( nTcpSocket, pBuf, nBytes ) ); +//#endif + if( nWrote < 0 ) + { +#ifdef WIN32 + int iWSAError = bu_WSAGetLastError(); + if( iWSAError == WSAEWOULDBLOCK ) + return 0; +#else + if( errno == EAGAIN ) return 0; +#endif + throw TcpSocketException( TcpSocketException::cWrite, strerror(errno) ); + } + return nWrote; +} + +size_t Bu::TcpSocket::write( const void *pBuf, size_t nBytes, uint32_t nSec, uint32_t nUSec ) +{ + struct timeval tv; + size_t nWrote = 0; + + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(nTcpSocket, &wfds); + +#ifdef WIN32 + DWORD dwStart = GetTickCount(); + uint64_t uOver = dwStart + ((nUSec / 1000) * (nSec * 1000)); + DWORD dwEnd = uOver>4294967295U?uOver-4294967295U:uOver; +#else + struct timeval nt, ct; + gettimeofday( &nt, NULL ); + nt.tv_sec += nSec; + nt.tv_usec += nUSec; +#endif + + for(;;) + { + tv.tv_sec = nSec; + tv.tv_usec = nUSec; + bu_select( nTcpSocket+1, NULL, &wfds, NULL, &tv ); + nWrote += write( ((char *)pBuf)+nWrote, nBytes-nWrote ); + if( nWrote >= nBytes ) + break; +#ifdef WIN32 + DWORD dwNow = GetTickCount(); + if( dwNow > dwEnd ) + break; +#else + gettimeofday( &ct, NULL ); + if( (ct.tv_sec > nt.tv_sec) || + (ct.tv_sec == nt.tv_sec && + ct.tv_usec >= nt.tv_usec) ) + break; +#endif + } + return nWrote; +} + +long Bu::TcpSocket::tell() +{ + throw UnsupportedException(); +} + +void Bu::TcpSocket::seek( long ) +{ + throw UnsupportedException(); +} + +void Bu::TcpSocket::setPos( long ) +{ + throw UnsupportedException(); +} + +void Bu::TcpSocket::setPosEnd( long ) +{ + throw UnsupportedException(); +} + +bool Bu::TcpSocket::isEos() +{ + return !bActive; +} + +bool Bu::TcpSocket::canRead() +{ + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(nTcpSocket, &rfds); + struct timeval tv = { 0, 0 }; + int retval = bu_select( nTcpSocket+1, &rfds, NULL, NULL, &tv ); + if( retval == -1 ) + throw TcpSocketException( + TcpSocketException::cBadRead, + "Bad Read error" + ); + + if( !FD_ISSET( nTcpSocket, &rfds ) ) + return false; + return true; +} + +bool Bu::TcpSocket::canWrite() +{ + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(nTcpSocket, &wfds); + struct timeval tv = { 0, 0 }; + int retval = bu_select( nTcpSocket+1, NULL, &wfds, NULL, &tv ); + if( retval == -1 ) + throw TcpSocketException( + TcpSocketException::cBadRead, + "Bad Read error" + ); + if( !FD_ISSET( nTcpSocket, &wfds ) ) + return false; + return true; +} + +bool Bu::TcpSocket::isReadable() +{ + return true; +} + +bool Bu::TcpSocket::isWritable() +{ + return true; +} + +bool Bu::TcpSocket::isSeekable() +{ + return false; +} + +bool Bu::TcpSocket::isBlocking() +{ +#ifndef WIN32 + return ((fcntl( nTcpSocket, F_GETFL, 0 ) & O_NONBLOCK) != O_NONBLOCK); +#else + return false; +#endif +} + +void Bu::TcpSocket::setBlocking( bool bBlocking ) +{ + this->bBlocking = bBlocking; +#ifndef WIN32 + if( bBlocking ) + { + fcntl( nTcpSocket, F_SETFL, fcntl( nTcpSocket, F_GETFL, 0 ) & (~O_NONBLOCK) ); + } + else + { + fcntl( nTcpSocket, F_SETFL, fcntl( nTcpSocket, F_GETFL, 0 ) | O_NONBLOCK ); + } +#else + u_long iMode; + if( bBlocking ) + iMode = 0; + else + iMode = 1; + //------------------------- + // Set the socket I/O mode: In this case FIONBIO + // enables or disables the blocking mode for the + // socket based on the numerical value of iMode. + // If iMode = 0, blocking is enabled; + // If iMode != 0, non-blocking mode is enabled. + bu_ioctlsocket(nTcpSocket, FIONBIO, &iMode); +#endif +} + +void Bu::TcpSocket::setSize( long ) +{ +} + +void Bu::TcpSocket::flush() +{ +} + +bool Bu::TcpSocket::isOpen() +{ + return bActive; +} + +void Bu::TcpSocket::setAddress() +{ + struct sockaddr_in addr; + socklen_t len = sizeof(addr); + addr.sin_family = AF_INET; + bu_getpeername( nTcpSocket, (sockaddr *)(&addr), &len ); + sAddress = bu_inet_ntoa( addr.sin_addr ); +} + +Bu::FString Bu::TcpSocket::getAddress() const +{ + return sAddress; +} + +Bu::TcpSocket::operator int() const +{ + return nTcpSocket; +} + diff --git a/src/tcpsocket.h b/src/tcpsocket.h new file mode 100644 index 0000000..3361e84 --- /dev/null +++ b/src/tcpsocket.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2007-2010 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#ifndef BU_TCP_SOCKET_H +#define BU_TCP_SOCKET_H + +#include + +#include "bu/stream.h" +#include "bu/fstring.h" +#include "bu/exceptionbase.h" + +namespace Bu +{ + subExceptionDeclBegin( TcpSocketException ); + enum { + cRead, + cWrite, + cBadRead, + cClosed, + cTimeout + }; + subExceptionDeclEnd(); + + /** + * Network socket stream class. This class provides a mechanism for + * communicating over a network using TCP/IP. It will provide other low + * level protocol and addressing support later on, but for now it's just + * standard STREAM TCP/IP sockets. + * + * Unlike system sockets, these sockets are opened by default in + * non-blocking mode, you can specify your own timeout for opening a socket, + * and a number of non-fatal error messages have been automatically handled + * and treated as standard no-data-available-yet situations on read. + * + * Please note that there is a condition that will occur eventually (at + * least on *nix systems) that will trigger a SIGPIPE condition. This + * will terminate your program immediately unless handled properly. Most + * people doing any connections with TcpSocket will want to put this in + * their program somewhere before they use it: + *@code + #include + ... + ... + ... + sigset( SIGPIPE, SIG_IGN ); // do this before you use a Bu::TcpSocket + @endcode + * When this is done, Bu::TcpSocket will simply throw a broken pipe + * exception just like every other error condition, allowing your program + * to handle it sanely. + * + *@ingroup Serving + *@ingroup Streams + */ + class TcpSocket : public Stream + { + public: + TcpSocket( int nTcpSocket ); + TcpSocket( const FString &sAddr, int nPort, int nTimeout=30, + bool bBlocking=true ); + virtual ~TcpSocket(); + + virtual void close(); + //virtual void read(); + virtual size_t read( void *pBuf, size_t nBytes ); + virtual size_t read( void *pBuf, size_t nBytes, + uint32_t nSec, uint32_t nUSec=0 ); + virtual size_t write( const void *pBuf, size_t nBytes ); + virtual size_t write( const void *pBuf, size_t nBytes, + uint32_t nSec, uint32_t nUSec=0 ); + using Stream::write; + + virtual long tell(); + virtual void seek( long offset ); + virtual void setPos( long pos ); + virtual void setPosEnd( long pos ); + virtual bool isEos(); + virtual bool isOpen(); + + virtual void flush(); + + virtual bool canRead(); + virtual bool canWrite(); + + virtual bool isReadable(); + virtual bool isWritable(); + virtual bool isSeekable(); + + virtual bool isBlocking(); + virtual void setBlocking( bool bBlocking=true ); + + virtual void setSize( long iSize ); + + Bu::FString getAddress() const; + operator int() const; + + private: + void setAddress(); + +#ifdef WIN32 + unsigned int nTcpSocket; +#else + int nTcpSocket; +#endif + bool bActive; + bool bBlocking; + FString sReadBuf; + FString sAddress; + }; +} + +#endif diff --git a/src/tests/socket.cpp b/src/tests/socket.cpp deleted file mode 100644 index ba4e9b9..0000000 --- a/src/tests/socket.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2007-2010 Xagasoft, All rights reserved. - * - * This file is part of the libbu++ library and is released under the - * terms of the license contained in the file LICENSE. - */ - -#include -#include - -#include -#include - -using namespace Bu; - -bool isUp() -{ - try - { - Socket s("xagasoft.com", 9898, 1 ); - - char buf[5]; - buf[s.read(buf, 2, 1, 0)] = '\0'; - - if( !strcmp( buf, "hi" ) ) - return true; - else - return false; - } - catch(...) - { - return false; - } -} - -int main() -{ - uint32_t uUp = 0; - uint32_t uDown = 0; - uint32_t uTotal = 0; - struct timeval tv; - - for(;;) - { - gettimeofday( &tv, NULL ); - time_t goal = ((tv.tv_sec/5)+1)*5; - tv.tv_sec = goal-tv.tv_sec; - tv.tv_usec = 0-tv.tv_usec; - if( tv.tv_usec < 0 ) - { - tv.tv_sec--; - tv.tv_usec = 1000000+tv.tv_usec; - } - select( 0, NULL, NULL, NULL, &tv ); - gettimeofday( &tv, NULL ); - if( isUp() ) - { - uUp++; - sio << "status: up "; - } - else - { - uDown++; - sio << "status: down "; - } - uTotal++; - - sio << "(up=" << (uUp*5) << "s, down=" << (uDown*5) << ") up for " - << uUp*100/uTotal << "% of " << uTotal*5 << "s" << sio.nl - << sio.flush; - } -} - diff --git a/src/tests/socketblock.cpp b/src/tests/socketblock.cpp index a1ea18d..793ef96 100644 --- a/src/tests/socketblock.cpp +++ b/src/tests/socketblock.cpp @@ -6,8 +6,8 @@ */ #include "bu/ito.h" -#include "bu/socket.h" -#include "bu/serversocket.h" +#include "bu/tcpsocket.h" +#include "bu/tcpserversocket.h" #include #include @@ -21,7 +21,7 @@ public: virtual void run() { - Bu::Socket c = s.accept( 45, 0 ); + Bu::TcpSocket c = s.accept( 45, 0 ); printf("TstServer: Accetped connection.\n"); fflush( stdout ); sleep( 1 ); @@ -35,7 +35,7 @@ public: c.close(); } - Bu::ServerSocket s; + Bu::TcpServerSocket s; }; int main() @@ -45,7 +45,7 @@ int main() ts.start(); printf("main: Connecting to server.\n"); fflush( stdout ); - Bu::Socket s( "localhost", 55678 ); + Bu::TcpSocket s( "localhost", 55678 ); printf("main: Sending 4 bytes.\n"); fflush( stdout ); s.write( "aoeu", 4 ); diff --git a/src/tests/socketbreak.cpp b/src/tests/socketbreak.cpp index 8339630..7d3c71a 100644 --- a/src/tests/socketbreak.cpp +++ b/src/tests/socketbreak.cpp @@ -5,17 +5,17 @@ * terms of the license contained in the file LICENSE. */ -#include "bu/serversocket.h" -#include "bu/socket.h" +#include "bu/tcpserversocket.h" +#include "bu/tcpsocket.h" #include int main() { - Bu::ServerSocket sSrv( 9987 ); + Bu::TcpServerSocket sSrv( 9987 ); - Bu::Socket sSend("localhost", 9987 ); + Bu::TcpSocket sSend("localhost", 9987 ); - Bu::Socket sRecv( sSrv.accept() ); + Bu::TcpSocket sRecv( sSrv.accept() ); printf("Connected sockets.\n"); diff --git a/src/tests/tcpsocket.cpp b/src/tests/tcpsocket.cpp new file mode 100644 index 0000000..30dd22f --- /dev/null +++ b/src/tests/tcpsocket.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2007-2010 Xagasoft, All rights reserved. + * + * This file is part of the libbu++ library and is released under the + * terms of the license contained in the file LICENSE. + */ + +#include +#include + +#include +#include + +using namespace Bu; + +bool isUp() +{ + try + { + TcpSocket s("xagasoft.com", 9898, 1 ); + + char buf[5]; + buf[s.read(buf, 2, 1, 0)] = '\0'; + + if( !strcmp( buf, "hi" ) ) + return true; + else + return false; + } + catch(...) + { + return false; + } +} + +int main() +{ + uint32_t uUp = 0; + uint32_t uDown = 0; + uint32_t uTotal = 0; + struct timeval tv; + + for(;;) + { + gettimeofday( &tv, NULL ); + time_t goal = ((tv.tv_sec/5)+1)*5; + tv.tv_sec = goal-tv.tv_sec; + tv.tv_usec = 0-tv.tv_usec; + if( tv.tv_usec < 0 ) + { + tv.tv_sec--; + tv.tv_usec = 1000000+tv.tv_usec; + } + select( 0, NULL, NULL, NULL, &tv ); + gettimeofday( &tv, NULL ); + if( isUp() ) + { + uUp++; + sio << "status: up "; + } + else + { + uDown++; + sio << "status: down "; + } + uTotal++; + + sio << "(up=" << (uUp*5) << "s, down=" << (uDown*5) << ") up for " + << uUp*100/uTotal << "% of " << uTotal*5 << "s" << sio.nl + << sio.flush; + } +} + diff --git a/src/variant.h b/src/variant.h index 5482ee3..9819f2c 100644 --- a/src/variant.h +++ b/src/variant.h @@ -17,6 +17,7 @@ namespace Bu { class Formatter; class Variant; + /** @cond DEVEL */ template class VariantType; class VariantTypeRoot @@ -92,7 +93,22 @@ namespace Bu private: t data; }; - + /** @endcond */ + + /** + * Store any data type and access it safely. Variant gives you a way to + * pass arbitrary data types around without having to worry about what + * type a variable is. It allows code to be easily extended and to manage + * data without having to know what type it is ahead of time. + * + * Because of the generic method that this class was implemented it may seem + * to have some drawbacks compared to other Variant classes you may have + * seen, however it is fairly easy to get it to do just about anything you + * may need. It is also very low overhead. On most compilers the class + * itself has only 3 words of overhead + the size of the variable you store + * in it. And, since many parts of it are templatized they can often be + * optimized quite a bit. + */ class Variant { public: -- cgit v1.2.3