#define XVT_INCL_NATIVE #include #include #include #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 #ifdef INCSTR_H #include #endif #ifdef WIN32 #include "winsock.h" #else #include #include #include #include #include #include #define SOCKET int #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 #define SOCKADDR_IN sockaddr_in #define closesocket close #define BYTE byte #endif // // 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. #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 // // skstream // int skstream::init( void ) { // platform dependent initialization #ifdef WIN32 const WORD wMinVer = 0x0101; // request WinSock v1.1 (at least) WSADATA wsaData; if( 0 == WSAStartup( wMinVer, &wsaData ) ) return TRUE ; return FALSE ; #else return TRUE; #endif } int skstream::shutdown( void ) { // platform dependent shutdown #ifdef WIN32 if( 0 == WSACleanup() ) return TRUE ; return FALSE ; #else return TRUE; #endif } skstream::skstream( void ) : iostream( &_sockbuf ), _sockbuf( _socket ) { if( init() ) attach( INVALID_SOCKET ) ; } skstream::skstream( const char *addr, const service port, const role side ) : iostream( &_sockbuf ), _sockbuf( _socket ) { if( init() ) { attach( INVALID_SOCKET ) ; open( addr, port, side ) ; } } skstream::skstream( SOCKET sock ) : iostream( &_sockbuf ), _sockbuf( _socket ) { 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 ; #ifdef WIN32 sa.sin_addr.S_un.S_addr = INADDR_ANY ; #else sa.sin_addr.s_addr = INADDR_ANY ; #endif 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 ; memset(&sa,0,sizeof(sa)); sa.sin_family = AF_INET ; unsigned long indirizzo = 0xFFFFFFFF; int ip[4]; //e' un indirizzo numerico? //si... if (sscanf( addr, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]) == 4) { indirizzo = ::inet_addr(addr); } //no... else { hostent* he = ::gethostbyname( addr ); if( NULL != he ) indirizzo = *(unsigned long *)( he->h_addr_list[ 0 ] ); } if (indirizzo == 0 || indirizzo == 0xFFFFFFFF) { close(); return; } #ifdef WIN32 sa.sin_addr.S_un.S_addr = indirizzo; sa.sin_port = ::htons( port ) ; #else sa.sin_addr.s_addr = indirizzo; sa.sin_port = htons( port ) ; #endif 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 ) ; #ifdef WIN32 if( SOCKET_ERROR ==::getpeername( getsocket(), (sockaddr *)&sa, &sasize ) ) #else if( SOCKET_ERROR ==::getpeername( getsocket(), (sockaddr *)&sa, (socklen_t *) &sasize ) ) #endif // 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 ) ; #ifdef WIN32 if( SOCKET_ERROR ==::getpeername( getsocket(), (sockaddr *)&sa, &sasize ) ) // Cannot get peer port return ::ntohs( IPPORT_RESERVED ); return ::ntohs( sa.sin_port ) ; #else if( SOCKET_ERROR ==::getpeername( getsocket(), (sockaddr *)&sa, (socklen_t *) &sasize ) ) // Cannot get peer port return ntohs( IPPORT_RESERVED ); return ntohs( sa.sin_port ) ; #endif } // // sockbuf // sockbuf::sockbuf( SOCKET &sock ) : _socket( sock ) { 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 ) { _buffer = NULL ; if( this == setbuf( buf, length ) ) { 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 /////////////////////////////////////////////////////////// #include "netsock.h" class TSocket_connection : public TConnection { TString _server; skstream::service _service; skstream* _socket; protected: bool connect(); public: virtual bool Execute(const char* cmd); bool WriteLine(const char* cmd); bool ReadLine(TString& str); bool Read(byte* buf, size_t size); skstream* GetSocket(); TSocket_connection(TLanManager* lm, const char* service, const char* server); ~TSocket_connection(); }; bool TSocket_connection::Execute(const char* cmd) { skstream* calza = GetSocket(); bool ok = calza != NULL; if (ok) { const size_t buflen = strlen(cmd)+1; calza->sync(); calza->write(cmd, buflen); calza->flush(); ok = calza->good() != 0; } return ok; } bool TSocket_connection::WriteLine(const char* cmd) { skstream* calza = GetSocket(); bool ok = calza != NULL; if (ok) { const size_t buflen = strlen(cmd); // Unica differenza da Execute calza->sync(); calza->write(cmd, buflen); calza->flush(); ok = calza->good() != 0; } return ok; } bool TSocket_connection::ReadLine(TString& str) { skstream* calza = GetSocket(); bool ok = calza != NULL; if (ok) { char *buf = str.get_buffer(4096); calza->getline(buf, str.size(), '\n'); } return ok; } bool TSocket_connection::Read(byte* buf, size_t size) { skstream* calza = GetSocket(); bool ok = calza != NULL; if (ok) { calza->read((char *)buf, size); ok = calza->good() != 0; } return ok; } bool TSocket_connection::connect() { if (_socket != NULL) delete _socket; _socket = new skstream(_server, _service); if (_socket->is_open()) SetId((CONNID)_socket); else { delete _socket; _socket = NULL; SetId(0); } return _socket != NULL; } skstream* TSocket_connection::GetSocket() { if (_socket == NULL || !_socket->is_open()) connect(); return _socket; } TSocket_connection::TSocket_connection(TLanManager* lm, const char* service, const char* server) : TConnection(lm, 0), _socket(NULL) { _service = (skstream::service)((service && *service) ? atoi(service) : 0); _server = server; int pos = _server.find("://"); if (pos > 0) _server.ltrim(pos+3); pos = _server.rfind(':'); if (pos >= 0) { _service = (skstream::service)atoi(_server.mid(pos+1)); _server.cut(pos); } if (_server.blank() || xvt_str_compare_ignoring_case(_server, "localhost") == 0) _server = "127.0.0.1"; connect(); } TSocket_connection::~TSocket_connection() { if (_socket) delete _socket; } TSocketClient::TSocketClient() : m_pData(NULL), m_dwSize(0) { } TSocketClient::~TSocketClient() { ReleaseBuffer(); RemoveAllConnections(); } TConnection* TSocketClient::OnQueryConnection(const char* service, const char* server) { TSocket_connection* pConnection = new TSocket_connection(this, service, server); if (pConnection->Id() == 0) { delete pConnection; pConnection = NULL; } return pConnection; } bool TSocketClient::Request(CONNID id, const char* cmd) { static bool semaphore = FALSE; bool ok = FALSE; if (!semaphore) { semaphore = TRUE; ReleaseBuffer(); ok = Execute(id, cmd); if (ok) { TSocket_connection* conn = (TSocket_connection*)GetConnection(id); m_dwSize = 0; conn->Read((byte*)&m_dwSize, sizeof(m_dwSize)); ok = m_dwSize > 0; if (ok) { m_pData = new byte[m_dwSize]; ok = conn->Read(m_pData, m_dwSize); } } semaphore = FALSE; } return ok; } byte* TSocketClient::GetBuffer(size_t& dwSize) { dwSize = m_dwSize; return m_pData; } bool TSocketClient::WriteLine(CONNID id, const char* str) { TSocket_connection* conn = (TSocket_connection*)GetConnection(id); if (conn) return conn->WriteLine(str); return FALSE; } bool TSocketClient::ReadLine(CONNID id, TString& str) { TSocket_connection* conn = (TSocket_connection*)GetConnection(id); if (conn) return conn->ReadLine(str); return FALSE; } void TSocketClient::ReleaseBuffer() { if (m_pData) { delete m_pData; m_pData = NULL; m_dwSize = 0; } } bool TSocketClient::HttpGetFile(CONNID id, const char* remote, const char* local, const char* authorization) { bool ok = FALSE; TString buf(4096); buf << "GET " << remote << " HTTP/1.0\r\n" << "User-Agent: Campo\r\n"; if (authorization && *authorization) buf << "Authorization: " << authorization << "\r\n"; buf << "\r\n"; if (WriteLine(id, buf)) { long size = 0; for (int r = 0; ; r++) { ReadLine(id, buf); if (buf.blank()) break; if (r == 0 && buf.find("200 OK") < 0) return FALSE; // File not found if (buf.compare("Content-length:", 15, TRUE) == 0) { const int colon = buf.find(':'); size = atol(buf.mid(colon+1)); } } ofstream outfile(local, ios::out | ios::binary); if (outfile.good()) { buf.cut(0) << remote << " - " << (size / 1024 + 1) << " KBytes"; TProgind pi(size, buf, TRUE, TRUE); long total = 0; skstream* cur_socket = ((TSocket_connection*)GetConnection(id))->GetSocket(); while (!cur_socket->eof()) { cur_socket->read(buf.get_buffer(), buf.size()); const int count = cur_socket->gcount(); if (count > 0) { outfile.write(buf, count); total += count; pi.setstatus(total); if (pi.iscancelled()) break; } } ok = pi.isfinished(); } else error_box("Impossibile scrivere il file %s", local); } return ok; } HIDDEN int find_href(const TString& riga) { int href = -1; int img = riga.find("= 0) href = riga.find("href=", img+4); else { img = riga.find("= 0) href = riga.find("HREF=", img+4); } return href; } bool TSocketClient::HttpGetDir(CONNID id, const char* remote, TString_array& list) { TFilename local; local.temp(); const bool ok = HttpGetFile(id, remote, local); if (ok) { ifstream s(local); TString riga(256); while (!s.eof()) { s.getline(riga.get_buffer(), riga.size()); const int href = find_href(riga); if (href > 0) { const int start = riga.find('"', href) + 1; if (start > href && isalnum(riga[start + 1])) { const int stop = riga.find('"', start); if (stop > start) { const TString& name = riga.sub(start, stop); list.add(name); } } } } s.close(); ::remove(local); } return ok; } bool TSocketClient::HttpSoap(CONNID id, const char* cmd) { bool ok = false; TSocket_connection* conn = (TSocket_connection*)GetConnection(id); if (conn == NULL) return ok; if (cmd == NULL || *cmd == '\0') return ok; char hostname[256]; xvt_sys_get_host_name(hostname, sizeof(hostname)); TString content(256); content = cmd; if (content.find("\n\n"); content << "\n\r\n"; } TString buf(4096); buf << "POST / HTTP/1.1\n" << "User-Agent: Campo\n" << "Host: " << hostname << "\n" << "Content-Type: text/xml; charset=utf-8\n" << "Content-length: " << content.len() << "\n" << "SOAPAction: \"/\"\r\n\r\n" << content; if (conn->WriteLine(buf)) { skstream* cur_socket = conn->GetSocket(); unsigned long size = 0; for (int r = 0; !cur_socket->eof(); r++) { conn->ReadLine(buf); if (buf.blank()) break; if (buf.compare("Content-length:", 15, TRUE) == 0) { const int colon = buf.find(':'); size = atol(buf.mid(colon+1)); } } if (size > 0) { if (size >= m_dwSize) { ReleaseBuffer(); m_dwSize = size+1; m_pData = new BYTE[m_dwSize]; } memset(m_pData, 0, m_dwSize); cur_socket->read((char *) m_pData, size); ok = true; } } return ok; } bool TSocketClient::HttpPostFile(CONNID id, const char* remote, const char* local, const char* authorization) { bool ok = false; TSocket_connection* conn = (TSocket_connection*)GetConnection(id); if (conn == NULL) return ok; const char* const eol = "\r\n"; TString buf(4096); buf << "POST " << remote << " HTTP/1.0" << eol << "User-Agent: Campo/1.7" << eol << "Content-Type: text/plain" << eol << "Content-Length: " << fsize(local) << eol; if (authorization && *authorization) buf << "Authorization: " << authorization << eol; buf << eol; ok = conn->WriteLine(buf); if (ok) { #ifdef WIN32 ifstream input(local, ios::nocreate | ios::binary); #else ifstream input(local, ios::binary); #endif while (!input.eof()) { input.read(buf.get_buffer(), buf.size()); const size_t count = input.gcount(); if (count > 0) { skstream* cur_socket = conn->GetSocket(); cur_socket->sync(); cur_socket->write(buf, count); cur_socket->flush(); } else break; } conn->ReadLine(buf); ok = buf.find("200 OK") >= 0; if (ok) { skstream* cur_socket = conn->GetSocket(); unsigned long size = 0; for (int r = 0; !cur_socket->eof(); r++) { cur_socket->getline(buf.get_buffer(), buf.size(), '\n'); if (buf.blank()) break; if (buf.starts_with("Content-length:", true) == 0) { const int colon = buf.find(':'); size = atol(buf.mid(colon+1)); } } ReleaseBuffer(); ok = size > 0; if (ok) { m_dwSize = size; m_pData = new BYTE[m_dwSize+1]; memset(m_pData, 0, size_t(m_dwSize+1)); cur_socket->read((char *) m_pData, (size_t)m_dwSize); } } else { ReleaseBuffer(); m_dwSize = buf.len()+1; m_pData = new BYTE[m_dwSize]; memcpy(m_pData, buf, (size_t)m_dwSize); } } return ok; }