606 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			606 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| #include <checks.h>
 | |
| #include <strings.h>
 | |
| 
 | |
| // 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 <iostream.h>
 | |
| #include <stdlib.h>
 | |
| 
 | |
| #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 <jcwang@csie.ntu.edu.tw>
 | |
| // 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 <stdio.h>
 | |
| #include <stdlib.h>
 | |
| 
 | |
| #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 <windows.h>
 | |
| 
 | |
| 
 | |
| 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;
 | |
|   }
 | |
| }
 |