From 867dae89929a11a421ec21af71d494ad0ecc1963 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Thu, 14 Oct 2010 23:26:25 +0000 Subject: SharedCore has more features now, which is cool, including a test to see if another object of the parent type has the same core, and another to clone the parent object. That one is pretty cool, it means you can now get a real copy when you want to, great for multi-threaded stuff. Also, two more classes are now SharedCore: Hash and Heap! --- src/sharedcore.h | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'src/sharedcore.h') diff --git a/src/sharedcore.h b/src/sharedcore.h index 5a44df9..ac36606 100644 --- a/src/sharedcore.h +++ b/src/sharedcore.h @@ -15,10 +15,10 @@ namespace Bu { - template + template class SharedCore { - typedef class SharedCore _SharedType; + typedef class SharedCore _SharedType; public: SharedCore() : core( NULL ), @@ -54,6 +54,18 @@ namespace Bu return *iRefCount; } + Shell clone() const + { + Shell s( dynamic_cast(*this) ); + s._hardCopy(); + return s; + } + + bool isCoreShared( const Shell &rOther ) const + { + return rOther.core == core; + } + protected: Core *core; void _hardCopy() @@ -68,6 +80,20 @@ namespace Bu iRefCount = new int( 1 ); } + /** + * Reset core acts like a hard copy, except instead of providing a + * standalone copy of the shared core, it provides a brand new core. + * + * Very useful in functions used to reset the state of an object. + */ + void _resetCore() + { + if( core ) + _deref(); + core = _allocateCore(); + iRefCount = new int( 1 ); + } + virtual Core *_allocateCore() { return new Core(); -- cgit v1.2.3 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 (limited to 'src/sharedcore.h') 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