#include #include // skstream.h // Copyright (C) 1995, 1996 by John C. Wang. All Rights Reserved. // // You may distribute this file with your product in either of two ways: // IN SOURCE CODE FORM: You must include this file in its entirety. // IN OBJECT CODE FORM: You must give proper acknowledgements to the author(s) // of this program. This may take the form of credits on the start-up screen. // // IN ANYCASE, THIS SOFTWARE IS DISTRIBUTED WITHOUT ANY KIND OF EXPLICIT OR // IMPLICIT WARRANTIES AND THE AUTHORS ARE NOT RESPONSIBLE FOR ANY EVENTS THAT // OCCURS AS A RESULT OF USING THIS SOFTWARE. // // History: // [JCW 95-Dec-04] created // [JCW 95-Dec-20] comments added for distribution 95a // [JCW 96-Jan-01] removed UDP capabilities from skstream #include #include #include "winsock.h" // // sockbuf // class sockbuf : public streambuf { public: sockbuf( SOCKET & ); sockbuf( SOCKET &, char *, int ); virtual ~sockbuf(); virtual int overflow(int =EOF) ; virtual int underflow() ; virtual int sync(); protected: char *_buffer ; // sockbuf specific SOCKET &_socket ; } ; // // skstream // class skstream : public iostream { public: // constants enum service { ftp = 21, //tcp telnet = 23, //tcp smtp = 25, //tcp mail time = 37, //tcp timserver name = 42, //tcp nameserver nameserver = 53, //tcp domain # name-domain server finger = 79, //tcp http = 80, //tcp pop = 109, //tcp postoffice pop2 = 109, //tcp # Post Office pop3 = 110, //tcp postoffice nntp = 119 //tcp usenet # Network News Transfer } ; enum role { server , client } ; // methods skstream( void ); skstream( const char *addr, const service, const role = client ) ; skstream( SOCKET ); ~skstream( void ); void open( const char *addr, const service, const role = client ) ; void close( void ) ; int is_open( void ) const ; void attach( SOCKET = NULL ); SOCKET getsocket() const ; char *getpeername( char *, int ) const ; unsigned short getport( void ) const ; protected: SOCKET _socket ; sockbuf _sockbuf ; // platform dependent library housekeeping int init( void ) ; int shutdown( void ) ; }; // skstream.cpp // Copyright (C) 1996, 1995 by John C. Wang // All Rights Reserved. // // You may distribute this file with your product in either of two ways: // IN SOURCE CODE FORM: You must include this file in its entirety. // IN OBJECT CODE FORM: You must give proper acknowledgements to the author(s) // of this program. This may take the form of credits on the start-up screen. // // IN ANYCASE, THIS SOFTWARE IS DISTRIBUTED WITHOUT ANY KIND OF EXPLICIT OR // IMPLICIT WARRANTY AND THE AUTHOR(S) ARE NOT RESPONSIBLE FOR ANY EVENT THAT // OCCURS DUE TO THE USE OR MISUSE OF THIS SOFTWARE. // // History: // [JCW 95-Dec-04] created. // [JCW 95-Dec-20] comments added for distribution 95a. // [JCW 96-Jan-01] removed UDP capabilities from skstream. // [JCW 96-Mar-14] exceptions made optional. // [JCW 96-Oct-20] protected skstream::init and ::shutdown changed. // char( 255 ) == EOF bug fixed. #include #include #ifdef _UNIX #define INVALID_SOCKET -1 // Add definitions here #endif // Machine independent macros #ifdef DBG #define dassert(x) assert(x) #define debug(x) x #else #define dassert(x) #define debug(x) #endif //def _DEBUG #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE !FALSE #endif // // skstream // int skstream::init( void ) { // platform dependent initialization const WORD wMinVer = 0x0101; // request WinSock v1.1 (at least) WSADATA wsaData; if( 0 == WSAStartup( wMinVer, &wsaData ) ) return TRUE ; return FALSE ; } int skstream::shutdown( void ) { // platform dependent shutdown if( 0 == WSACleanup() ) return TRUE ; return FALSE ; } skstream::skstream( void ) : _sockbuf( _socket ), iostream( &_sockbuf ) { if( init() ) attach( INVALID_SOCKET ) ; } skstream::skstream( const char *addr, const service port, const role side ) : _sockbuf( _socket ), iostream( &_sockbuf ) { if( init() ) { attach( INVALID_SOCKET ) ; open( addr, port, side ) ; } } skstream::skstream( SOCKET sock ) : _sockbuf( _socket ), iostream( &_sockbuf ) { if( init() ) attach( sock ) ; } skstream::~skstream( void ) { close() ; shutdown() ; } int skstream::is_open( void ) const { return ( INVALID_SOCKET != getsocket() ) ; } void skstream::open( const char *addr, const service port, const role side ) { // in case of error condition, user finds out by testing is_open() if( is_open() ) close() ; // 1. Create socket if( INVALID_SOCKET == ( _socket = ::socket( PF_INET, SOCK_STREAM, 0 ) ) ) // Cannot create socket return ; // 2. Bind SOCKADDR_IN sa ; sa.sin_family = AF_INET ; sa.sin_addr.S_un.S_addr = INADDR_ANY ; sa.sin_port = side == client ? 0 : htons( (unsigned short)port ) ; // rationale: no client requires fixed port number, so let system assign if( SOCKET_ERROR == ::bind( _socket, (sockaddr *)&sa, sizeof( sa ) ) ) { // Cannot bind to the chosen port close() ; return ; } // From now on the two sides are very much different if( side == skstream::client ) { // 3(cli). Connect SOCKADDR_IN sa ; sa.sin_family = AF_INET ; hostent *he = NULL; int ip[4]; if (sscanf( addr, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]) == 4) { char ipaddr[4]; for (int i = 0; i < 4; i++) ipaddr[i] = (char)ip[i]; he = ::gethostbyaddr( ipaddr, 4, PF_INET ); } else he = ::gethostbyname( addr ); if( NULL == he ) { // Cannot resolve remote server ip close() ; return ; } sa.sin_addr.S_un.S_addr = *(unsigned long *)( he->h_addr_list[ 0 ] ) ; sa.sin_port = ::htons( port ) ; if( SOCKET_ERROR == ::connect( _socket, (sockaddr *)&sa, sizeof( sa ) ) ) { // Connection error close() ; return ; } } else { // 3(svr). Listen if( SOCKET_ERROR == ::listen( _socket, 5 ) ) // max backlog { // Error listening close() ; return ; } // 4. Accept SOCKET commsock ; if( INVALID_SOCKET == ( commsock = ::accept( _socket, NULL, NULL ) ) ) { // Accepting error close() ; return ; } // rationale: after we accept a connection, close the server port // so another process may become a server if( SOCKET_ERROR == ::closesocket( _socket ) ) { // Cannot close service port, resource may be occupied close() ; return ; } _socket = commsock ; } // success! } void skstream::close( void ) { if( is_open() ) { _sockbuf.sync() ; if( SOCKET_ERROR == ::closesocket( _socket ) ) // Cannot close. Leave _socket as it was return ; } _socket = INVALID_SOCKET ; } void skstream::attach( SOCKET sock ) { _socket = sock ; } SOCKET skstream::getsocket() const { return _socket ; } char *skstream::getpeername( char *buf, int size ) const { SOCKADDR_IN sa ; int sasize = sizeof( sa ) ; if( SOCKET_ERROR ==::getpeername( getsocket(), (sockaddr *)&sa, &sasize ) ) // Cannot get peer name return NULL ; strncpy( buf, ::inet_ntoa( sa.sin_addr ), size - 1 ) ; return buf ; } unsigned short skstream::getport( void ) const { SOCKADDR_IN sa ; int sasize = sizeof( sa ) ; if( SOCKET_ERROR ==::getpeername( getsocket(), (sockaddr *)&sa, &sasize ) ) // Cannot get peer port return ::ntohs( IPPORT_RESERVED ) ; return ::ntohs( sa.sin_port ) ; } // // sockbuf // sockbuf::sockbuf( SOCKET &sock ) : _socket( sock ), streambuf( NULL, 0 ) { const int insize = 0x2000 ; // allocate 16k buffer each for input and output const int outsize = 0x2000 ; const int bufsize = insize + outsize ; _buffer = new char [ bufsize ] ; if( this != setbuf( _buffer, bufsize ) ) _buffer = NULL ; else { setp( _buffer, _buffer + insize ) ; setg( _buffer + insize, _buffer + bufsize, _buffer + bufsize ) ; } } sockbuf::sockbuf( SOCKET &sock, char *buf, int length ) : _socket( sock ), streambuf( buf, length ) { _buffer = NULL ; setp( buf, buf + length / 2 ) ; setg( buf + length / 2, buf + length, buf + length ) ; } sockbuf::~sockbuf() { delete[] _buffer ; _buffer = NULL ; } int sockbuf::overflow( int nCh ) { // in case of error, user finds out by testing fail() if( _socket == INVALID_SOCKET ) // Invalid socket return EOF ; if( pptr() - pbase() <= 0 ) // nothing to send return 0 ; int size ; if( SOCKET_ERROR == ( size = ::send( _socket, pbase(), pptr() - pbase(), 0 ) ) ) // (TCP) Cannot send return EOF ; if( size == 0 ) // remote site has closed this connection return EOF ; if( nCh != EOF ) // size >= 1 at this point { size-- ; *( pbase() + size ) = nCh ; } // move remaining pbase() + size .. pptr() - 1 => pbase() .. pptr() - size - 1 for( char *p = pbase() + size; p < pptr(); p++ ) *( p - size ) = *p ; const int newlen = ( pptr() - pbase() ) - size ; setp( pbase(), epptr() ) ; pbump( newlen ) ; return 0 ; } int sockbuf::underflow() { // if get area not empty, return first character // else fill up get area and return 1st character // in case of error, user finds out by testing eof() if( _socket == INVALID_SOCKET ) // Invalid socket! return EOF ; if( egptr() - gptr() > 0 ) return (int)(unsigned char)(*gptr()) ; // fill up from eback to egptr int size ; if( SOCKET_ERROR == ( size = ::recv( _socket, eback(), egptr() - eback(), 0 ) ) ) // (TCP) Receive error return EOF ; if( size == 0 ) // remote site has closed this connection return EOF ; // move rcvd data from eback() .. eback() + size to egptr() - size .. egptr() const int delta = egptr() - ( eback() + size ) ; for( char *p = eback() + size - 1; p >= eback(); p-- ) { CHECK( p + delta >= eback(), "Socket underflow" ) ; CHECK( p + delta < egptr(), "Socket underflow" ) ; *( p + delta ) = *p ; } setg( eback(), egptr() - size, egptr() ) ; return (int)(unsigned char)(*gptr()) ; } int sockbuf::sync() { if( EOF == overflow() ) return EOF ; // ios will set the fail bit else { // empty put and get areas setp( pbase(), epptr() ) ; setg( eback(), egptr(), egptr() ) ; return 0 ; } } /////////////////////////////////////////////////////////// // end of skstreams /////////////////////////////////////////////////////////// #define NO_MFC #define CObject TObject #define CString TString #define CStringArray TString_array #include "NetSock.h" #define STRICT #include static TLanManager* pSocketManager = NULL; static skstream* cur_socket = NULL; TSocketClient::TSocketClient() : m_pData(NULL), m_dwSize(0) { } TSocketClient::~TSocketClient() { ReleaseBuffer(); RemoveAllConnections(); ShutDown(); } BOOL TSocketClient::Boot() { return TRUE; } BOOL TSocketClient::ShutDown() { pSocketManager = NULL; if (cur_socket) { delete cur_socket; cur_socket = NULL; } return TRUE; } BOOL TSocketClient::OnRemoveConnection(DWORD id) { if (cur_socket) { delete cur_socket; cur_socket = NULL; } return TRUE; } TConnection* TSocketClient::OnQueryConnection(const char* service, const char* server) { if (pSocketManager == NULL) Boot(); TConnection* pConnection = NULL; if (cur_socket == NULL) { TString strServer = server; if (strServer.empty()) strServer = "127.0.0.1"; cur_socket = new skstream(strServer, (skstream::service)atoi(service)); if (cur_socket->is_open()) pConnection = OnCreateConnection((DWORD)cur_socket); else { delete cur_socket; cur_socket = NULL; } } return pConnection; } BOOL TSocketClient::Execute(DWORD id, const char* cmd) { BOOL ok = cur_socket->is_open(); if (ok) { const int buflen = strlen(cmd)+1; cur_socket->sync(); cur_socket->write(cmd, buflen); cur_socket->flush(); ok = cur_socket->good(); } return ok; } BOOL TSocketClient::Request(DWORD id, const char* cmd) { static BOOL semaphore = FALSE; BOOL ok = FALSE; if (!semaphore) { semaphore = TRUE; ReleaseBuffer(); ok = Execute(id, cmd); if (ok) { m_dwSize = 0; cur_socket->read((char*)&m_dwSize, sizeof(m_dwSize)); ok = m_dwSize > 0; if (ok) { m_pData = new BYTE[m_dwSize]; cur_socket->read(m_pData, (int)m_dwSize); ok = cur_socket->good(); } } semaphore = FALSE; } return ok; } BYTE* TSocketClient::GetBuffer(DWORD& dwSize) { dwSize = m_dwSize; return m_pData; } void TSocketClient::ReleaseBuffer() { if (m_pData) { delete m_pData; m_pData = NULL; m_dwSize = 0; } }