campo-sirio/include/netsock.cpp
guy 6bac6177c4 Patch level : 2.0 nopatch
Files correlati     :
Ricompilazione Demo : [ ]
Commento            :

Aggiunte utili per gestione dizionario
assoc.cpp    Aggiunta possibilita' di selezionare un elemento causale di un assoc
controls.cpp Corretta gestione scrollbar dei listbox
diction.cpp  Migliorata selezione caratteri da trimmare dalle traduzioni
isam.cpp     Corretto azzeramento dei memo (non azzerava il TString_array corrispondente)
msksheet.cpp Resa personalizzabile la larghezza della colonna col numero di riga
netsock.cpp  Migliorata gestione "a capo" in protocollo soap
progind.cpp  Corretto posizionamento progind sovrapposte
relapp.cpp   Cambiato un messaggio di richiesta annullamento


git-svn-id: svn://10.65.10.50/trunk@11651 c028cbd2-c16b-5b4b-a496-9718f37d4682
2003-12-03 09:41:16 +00:00

929 lines
21 KiB
C++
Executable File
Raw Blame History

#define XVT_INCL_NATIVE
#include <progind.h>
#include <config.h>
#include <agasys.h>
#include <utility.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 <fstream.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.
#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
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 ; 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;
}
sa.sin_addr.S_un.S_addr = indirizzo;
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
///////////////////////////////////////////////////////////
#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(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() || stricmp(_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))
{
const clock_t start = clock();
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("<img");
if (img >= 0)
href = riga.find("href=", img+4);
else
{
img = riga.find("<IMG");
if (img >= 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[64];
xvt_sys_get_host_name(hostname, sizeof(hostname));
TString content(256);
content = cmd;
if (content.find("<SOAP-ENV") < 0) // Controllo se c'<27> tutto
{
content.insert("<SOAP-ENV:Envelope>\n<SOAP-ENV:Body>\n");
content << "</SOAP-ENV:Body>\n</SOAP-ENV:Envelope>\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(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)
{
ifstream input(local, ios::nocreate | ios::binary);
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(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;
}