* contrib/hbexpat/3rd/expat/loadlibr.c
! define _UNICODE macro when UNICODE is also defined - it should be fixed
in EXPAT core code. It fixes Windows builds.
* contrib/hbexpat/3rd/expat/xmlparse.c
! restored fix for WINCE builds
* contrib/hbtip/client.prg
! restored #undef __HBEXTREQ__ before #include "hbssl.hbx".
It fixes non SSL builds and binding HBTIP with all HBSSL
functions.
* contrib/hbexpat/hbexpat.hbc
* added /usr/local/opt/expat/lib library path to darwin builds
(synced with Viktor's 3.4 branch)
853 lines
22 KiB
Plaintext
853 lines
22 KiB
Plaintext
/*
|
|
* TIP Class oriented Internet protocol library
|
|
*
|
|
* Copyright 2003 Giancarlo Niccolai <gian@niccolai.ws>
|
|
* Copyright 2007 Hannes Ziegler (INetErrorDesc(), lastErrorCode(), lastErrorMessage())
|
|
* Copyright 2007 Toninho@fwi (::nWrite to work like ::nRead)
|
|
* Copyright 2009 Luiz Rafael Culik (luiz at xharbour dot com dot br) (Proxy connection)
|
|
* Copyright 2009 Viktor Szakats (vszakats.net/harbour) (SSL support)
|
|
* Copyright 2015 Jean Lefebvre (STARTTLS support)
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file LICENSE.txt. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301 USA (or visit https://www.gnu.org/licenses/).
|
|
*
|
|
* As a special exception, the Harbour Project gives permission for
|
|
* additional uses of the text contained in its release of Harbour.
|
|
*
|
|
* The exception is that, if you link the Harbour libraries with other
|
|
* files to produce an executable, this does not by itself cause the
|
|
* resulting executable to be covered by the GNU General Public License.
|
|
* Your use of that executable is in no way restricted on account of
|
|
* linking the Harbour library code into it.
|
|
*
|
|
* This exception does not however invalidate any other reasons why
|
|
* the executable file might be covered by the GNU General Public License.
|
|
*
|
|
* This exception applies only to the code released by the Harbour
|
|
* Project under the name Harbour. If you copy code from other
|
|
* Harbour Project or Free Software Foundation releases into a copy of
|
|
* Harbour, as the General Public License permits, the exception does
|
|
* not apply to the code that you add in this way. To avoid misleading
|
|
* anyone as to the status of such modified files, you must delete
|
|
* this exception notice from them.
|
|
*
|
|
* If you write modifications of your own for Harbour, it is your choice
|
|
* whether to permit this exception to apply to your modifications.
|
|
* If you do not wish that, delete this exception notice.
|
|
*
|
|
*/
|
|
|
|
#include "hbclass.ch"
|
|
|
|
#include "error.ch"
|
|
#include "fileio.ch"
|
|
|
|
#if defined( _SSL_DEBUG_TEMP )
|
|
#include "simpleio.ch"
|
|
#endif
|
|
|
|
#include "hbssl.ch"
|
|
#undef __HBEXTREQ__
|
|
#include "hbssl.hbx"
|
|
|
|
#define RCV_BUF_SIZE Int( ::InetRcvBufSize( ::SocketCon ) / 2 )
|
|
#define SND_BUF_SIZE Int( ::InetSndBufSize( ::SocketCon ) / 2 )
|
|
|
|
/* Inet Client class */
|
|
CREATE CLASS TIPClient
|
|
|
|
CLASS VAR bInitSocks INIT .F.
|
|
CLASS VAR cCRLF INIT tip_CRLF()
|
|
|
|
VAR oUrl /* URL to which to connect */
|
|
VAR oCredentials /* credential needed to access the service */
|
|
VAR nStatus INIT 0 /* basic status */
|
|
VAR SocketCon
|
|
VAR bTrace
|
|
|
|
VAR nDefaultRcvBuffSize
|
|
VAR nDefaultSndBuffSize
|
|
|
|
VAR nLength INIT -1 /* Input stream length */
|
|
VAR nRead INIT 0 /* Input stream data read by the app*/
|
|
VAR nLastRead INIT 0 /* Last physical read amount */
|
|
|
|
VAR nDefaultPort
|
|
VAR nConnTimeout
|
|
VAR bInitialized INIT .F.
|
|
|
|
VAR cReply
|
|
VAR nAccessMode
|
|
VAR nWrite INIT 0
|
|
VAR nLastWrite INIT 0
|
|
|
|
VAR bEof INIT .F.
|
|
VAR isOpen INIT .F.
|
|
|
|
VAR exGauge /* Gauge control; it can be a codeblock or a function pointer. */
|
|
|
|
VAR lSSL INIT .F.
|
|
|
|
VAR lHasSSL INIT tip_SSL()
|
|
VAR ssl_ctx
|
|
VAR ssl
|
|
VAR nSSLError INIT 0
|
|
|
|
VAR Cargo
|
|
|
|
/* Data for proxy connection */
|
|
VAR cProxyHost INIT ""
|
|
VAR nProxyPort INIT 0
|
|
VAR cProxyUser
|
|
VAR cProxyPassword
|
|
VAR lProxyXferSSL INIT .F. /* SSL should only be enabled after proxy connection
|
|
NOTE: I've only checked HTTP POST / GET, unsure if
|
|
there are other functions with this issue. */
|
|
|
|
METHOD New( oUrl, xTrace, oCredentials )
|
|
METHOD Open( cUrl )
|
|
|
|
METHOD EnableSSL( lEnable )
|
|
|
|
METHOD Read( nLen )
|
|
METHOD ReadToFile( cFile, nMode, nSize )
|
|
METHOD Write( cData, nLen, lCommit )
|
|
METHOD Commit()
|
|
METHOD WriteFromFile( cFile )
|
|
METHOD Reset()
|
|
METHOD Close()
|
|
|
|
METHOD SetProxy( cProxyHost, nProxyPort, cProxyUser, cProxyPassword )
|
|
|
|
METHOD lastErrorCode() INLINE ::nLastError
|
|
METHOD lastErrorMessage( SocketCon ) INLINE ::inetErrorDesc( SocketCon )
|
|
|
|
METHOD InetRcvBufSize( SocketCon, nSizeBuff )
|
|
METHOD InetSndBufSize( SocketCon, nSizeBuff )
|
|
|
|
METHOD InetTimeOut( SocketCon, nConnTimeout )
|
|
|
|
METHOD HasSSL() INLINE ::lHasSSL
|
|
|
|
PROTECTED:
|
|
|
|
VAR nLastError INIT 0
|
|
|
|
METHOD OpenProxy( cServer, nPort, cProxy, nProxyPort, cResp, cUserName, cPassword, cUserAgent )
|
|
METHOD ReadHTTPProxyResponse( cResponse )
|
|
|
|
/* Methods to log data if needed */
|
|
METHOD inetRecv( SocketCon, cStr1, len )
|
|
METHOD inetRecvLine( SocketCon, nRet, size )
|
|
METHOD inetRecvAll( SocketCon, cRet, size )
|
|
METHOD inetCount( SocketCon )
|
|
METHOD inetSendAll( SocketCon, cData, nLen )
|
|
METHOD inetErrorCode( SocketCon )
|
|
METHOD inetErrorDesc( SocketCon )
|
|
METHOD inetConnect( cServer, nPort, SocketCon )
|
|
|
|
METHOD Log( ... )
|
|
|
|
ENDCLASS
|
|
|
|
METHOD New( oUrl, xTrace, oCredentials ) CLASS TIPClient
|
|
|
|
LOCAL oErr
|
|
LOCAL oLog
|
|
LOCAL lSSL
|
|
|
|
DO CASE
|
|
CASE HB_ISSTRING( xTrace ) .OR. hb_defaultValue( xTrace, .F. )
|
|
oLog := TIPLog():New( iif( HB_ISSTRING( xTrace ), xTrace, NIL ) )
|
|
::bTrace := {| cMsg | iif( PCount() > 0, oLog:Add( cMsg ), oLog:Close() ) }
|
|
CASE HB_ISEVALITEM( xTrace )
|
|
::bTrace := xTrace
|
|
ENDCASE
|
|
|
|
IF HB_ISSTRING( oUrl )
|
|
oUrl := TUrl():New( oUrl )
|
|
ENDIF
|
|
|
|
SWITCH oURL:cProto
|
|
CASE "ftp"
|
|
CASE "http"
|
|
CASE "pop"
|
|
CASE "smtp"
|
|
lSSL := .F.
|
|
EXIT
|
|
CASE "ftps"
|
|
CASE "https"
|
|
CASE "pop3s"
|
|
CASE "pops"
|
|
CASE "smtps"
|
|
IF ::lHasSSL
|
|
lSSL := .T.
|
|
EXIT
|
|
ENDIF
|
|
OTHERWISE
|
|
oErr := ErrorNew()
|
|
oErr:Args := { Self, oURL:cProto }
|
|
oErr:CanDefault := .F.
|
|
oErr:CanRetry := .F.
|
|
oErr:CanSubstitute := .T.
|
|
oErr:Description := "unsupported protocol"
|
|
oErr:GenCode := EG_UNSUPPORTED
|
|
oErr:Operation := ::className() + ":new()"
|
|
oErr:Severity := ES_ERROR
|
|
oErr:SubCode := 1081
|
|
oErr:SubSystem := "BASE"
|
|
Eval( ErrorBlock(), oErr )
|
|
ENDSWITCH
|
|
|
|
IF ! ::bInitSocks
|
|
hb_inetInit()
|
|
IF ::lHasSSL
|
|
SSL_init()
|
|
RAND_seed( hb_randStr( 20 ) + hb_TToS( hb_DateTime() ) + NetName() )
|
|
ENDIF
|
|
::bInitSocks := .T.
|
|
ENDIF
|
|
|
|
IF ::lHasSSL .AND. lSSL
|
|
::EnableSSL( .T. )
|
|
ENDIF
|
|
|
|
::oUrl := oUrl
|
|
::oCredentials := oCredentials
|
|
|
|
RETURN Self
|
|
|
|
METHOD Open( cUrl ) CLASS TIPClient
|
|
|
|
LOCAL nPort
|
|
|
|
IF HB_ISSTRING( cUrl )
|
|
::oUrl := TUrl():New( cUrl )
|
|
ENDIF
|
|
|
|
nPort := iif( ::oUrl:nPort == -1, ::nDefaultPort, ::oUrl:nPort )
|
|
|
|
::SocketCon := hb_inetCreate()
|
|
|
|
::InetTimeOut( ::SocketCon )
|
|
|
|
IF ::cProxyHost == ""
|
|
::inetConnect( ::oUrl:cServer, nPort, ::SocketCon )
|
|
IF ::inetErrorCode( ::SocketCon ) != 0
|
|
RETURN .F.
|
|
ENDIF
|
|
ELSEIF ! ::OpenProxy( ::oUrl:cServer, nPort, ::cProxyHost, ::nProxyPort,, ::cProxyUser, ::cProxyPassword, "Mozilla/3.0 compatible" )
|
|
RETURN .F.
|
|
ENDIF
|
|
::isOpen := .T.
|
|
|
|
RETURN .T.
|
|
|
|
METHOD EnableSSL( lEnable ) CLASS TIPClient
|
|
|
|
LOCAL lSuccess
|
|
|
|
IF ::lSSL == lEnable
|
|
RETURN .T.
|
|
ENDIF
|
|
|
|
::lProxyXferSSL := .F.
|
|
|
|
IF lEnable
|
|
IF ::lHasSSL
|
|
::ssl_ctx := SSL_CTX_new()
|
|
::ssl := SSL_new( ::ssl_ctx )
|
|
::lSSL := .T.
|
|
lSuccess := .T.
|
|
ELSE
|
|
lSuccess := .F.
|
|
ENDIF
|
|
ELSE
|
|
IF ::lHasSSL
|
|
::lSSL := .F.
|
|
lSuccess := .T.
|
|
ELSE
|
|
lSuccess := .T.
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN lSuccess
|
|
|
|
METHOD OpenProxy( cServer, nPort, cProxy, nProxyPort, cResp, cUserName, cPassword, cUserAgent ) CLASS TIPClient
|
|
|
|
LOCAL cRequest
|
|
LOCAL lRet := .F.
|
|
LOCAL tmp
|
|
|
|
::inetConnect( cProxy, nProxyPort, ::SocketCon )
|
|
|
|
IF ( tmp := ::inetErrorCode( ::SocketCon ) ) == 0
|
|
cRequest := ;
|
|
"CONNECT " + cServer + ":" + hb_ntos( nPort ) + " HTTP/1.1" + Chr( 13 ) + Chr( 10 ) + ;
|
|
"Proxy-Connection: Keep-Alive" + Chr( 13 ) + Chr( 10 )
|
|
IF HB_ISSTRING( cUserAgent ) .AND. ! cUserAgent == ""
|
|
cRequest += "User-Agent: " + cUserAgent + Chr( 13 ) + Chr( 10 )
|
|
ENDIF
|
|
IF HB_ISSTRING( cUserName ) .AND. ! cUserName == ""
|
|
cRequest += "Proxy-Authorization: Basic " + hb_base64Encode( cUserName + ":" + hb_defaultValue( cPassword, "" ) ) + Chr( 13 ) + Chr( 10 )
|
|
ENDIF
|
|
cRequest += Chr( 13 ) + Chr( 10 )
|
|
::inetSendAll( ::SocketCon, cRequest )
|
|
cResp := ""
|
|
IF ::ReadHTTPProxyResponse( @cResp ) .AND. ;
|
|
( tmp := At( " ", cResp ) ) > 0 .AND. ;
|
|
Val( SubStr( cResp, tmp + 1 ) ) == 200
|
|
lRet := .T.
|
|
ELSE
|
|
::close()
|
|
ENDIF
|
|
ELSE
|
|
cResp := hb_ntos( tmp )
|
|
ENDIF
|
|
|
|
/* Enable SSL after proxy connection is OK */
|
|
IF lRet .AND. ::lSSL .AND. ::lHasSSL
|
|
__tip_SSLConnectFD( ::ssl, ::SocketCon )
|
|
::lProxyXferSSL := .T.
|
|
ELSE
|
|
::lProxyXferSSL := .F.
|
|
ENDIF
|
|
|
|
RETURN lRet
|
|
|
|
METHOD ReadHTTPProxyResponse( /* @ */ cResponse ) CLASS TIPClient
|
|
|
|
LOCAL cBuffer
|
|
|
|
DO WHILE .T.
|
|
cBuffer := Space( 1 )
|
|
IF ::inetRecv( ::SocketCon, @cBuffer, hb_BLen( cBuffer ) ) <= 0
|
|
RETURN .F.
|
|
ENDIF
|
|
cResponse += cBuffer
|
|
IF hb_BRight( cResponse, 4 ) == e"\r\n\r\n"
|
|
EXIT
|
|
ENDIF
|
|
ENDDO
|
|
|
|
RETURN .T.
|
|
|
|
METHOD Close() CLASS TIPClient
|
|
|
|
LOCAL nRet
|
|
|
|
IF Empty( ::SocketCon )
|
|
nRet := -1
|
|
ELSE
|
|
nRet := hb_inetClose( ::SocketCon )
|
|
|
|
IF ::lSSL .AND. ::lHasSSL
|
|
SSL_shutdown( ::ssl )
|
|
::ssl := NIL
|
|
::ssl_ctx := NIL
|
|
ENDIF
|
|
|
|
::SocketCon := NIL
|
|
::isOpen := .F.
|
|
::lProxyXferSSL := .F.
|
|
ENDIF
|
|
|
|
IF HB_ISEVALITEM( ::bTrace )
|
|
/* Call with no parameter to signal end of logging session */
|
|
Eval( ::bTrace )
|
|
ENDIF
|
|
|
|
RETURN nRet
|
|
|
|
METHOD Reset() CLASS TIPClient
|
|
|
|
::bInitialized := .F.
|
|
::bEof := .F.
|
|
|
|
RETURN .T.
|
|
|
|
METHOD Commit() CLASS TIPClient
|
|
RETURN .T.
|
|
|
|
METHOD Read( nLen ) CLASS TIPClient
|
|
|
|
LOCAL cStr0
|
|
LOCAL cStr1
|
|
|
|
IF ::nLength > 0 .AND. ::nLength == ::nRead
|
|
RETURN NIL
|
|
ENDIF
|
|
|
|
IF ! HB_ISNUMERIC( nLen ) .OR. nLen <= 0 .OR. ( ::nLength > 0 .AND. nLen > ::nLength - ::nRead )
|
|
nLen := ::nLength - ::nRead
|
|
ENDIF
|
|
|
|
IF nLen <= 0
|
|
// read till end of stream
|
|
cStr1 := Space( RCV_BUF_SIZE )
|
|
cStr0 := ""
|
|
DO WHILE ( ::nLastRead := ::inetRecv( ::SocketCon, @cStr1, RCV_BUF_SIZE ) ) > 0
|
|
::nRead += ::nLastRead
|
|
cStr0 += hb_BLeft( cStr1, ::nLastRead )
|
|
ENDDO
|
|
::bEof := .T.
|
|
ELSE
|
|
// read an amount of data
|
|
cStr0 := Space( nLen )
|
|
|
|
IF ::lSSL .AND. ::lHasSSL
|
|
/* Getting around implementing the hack used in non-SSL branch for now.
|
|
IMO the proper fix would have been done to hb_inetRecvAll(). [vszakats] */
|
|
::nLastRead := ::inetRecvAll( ::SocketCon, @cStr0, nLen )
|
|
ELSE
|
|
// S.R. if length of file is less than RCV_BUF_SIZE hb_inetRecvAll() returns 0
|
|
// ::nLastRead := ::InetRecvAll( ::SocketCon, @cStr0, nLen )
|
|
::inetRecvAll( ::SocketCon, @cStr0, nLen )
|
|
::nLastRead := ::inetCount( ::SocketCon )
|
|
ENDIF
|
|
::nRead += ::nLastRead
|
|
|
|
IF ::nLastRead != nLen
|
|
::bEof := .T.
|
|
cStr0 := hb_BLeft( cStr0, ::nLastRead )
|
|
#if 0
|
|
RETURN NIL
|
|
#endif
|
|
ENDIF
|
|
|
|
IF ::nRead == ::nLength
|
|
::bEof := .T.
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN cStr0
|
|
|
|
METHOD ReadToFile( /* @ */ cFile, nMode, nSize ) CLASS TIPClient
|
|
|
|
LOCAL hFile
|
|
LOCAL cData
|
|
LOCAL nSent := 0
|
|
|
|
LOCAL lToMemory := hb_PIsByRef( 1 )
|
|
|
|
hb_default( @nSize, 0 )
|
|
|
|
IF lToMemory
|
|
cFile := ""
|
|
ENDIF
|
|
|
|
IF HB_ISEVALITEM( ::exGauge ) .AND. ;
|
|
! hb_defaultValue( Eval( ::exGauge, nSent, nSize, Self ), .T. )
|
|
RETURN .F.
|
|
ENDIF
|
|
|
|
::nRead := 0
|
|
::nStatus := 1
|
|
|
|
DO WHILE ::inetErrorCode( ::SocketCon ) == 0 .AND. ! ::bEof
|
|
IF ( cData := ::Read( RCV_BUF_SIZE ) ) == NIL
|
|
IF hFile != NIL
|
|
hb_vfClose( hFile )
|
|
ENDIF
|
|
RETURN ::inetErrorCode( ::SocketCon ) == 0
|
|
ENDIF
|
|
IF ! lToMemory .AND. hFile == NIL
|
|
IF ( hFile := hb_vfOpen( cFile, hb_bitOr( FO_CREAT + FO_TRUNC + FO_WRITE, hb_defaultValue( nMode, 0 ) ) ) ) == NIL
|
|
::nStatus := 0
|
|
RETURN .F.
|
|
ENDIF
|
|
ENDIF
|
|
|
|
IF lToMemory
|
|
cFile += cData
|
|
ELSEIF hb_vfWrite( hFile, cData ) != hb_BLen( cData )
|
|
hb_vfClose( hFile )
|
|
RETURN .F.
|
|
ENDIF
|
|
|
|
nSent += hb_BLen( cData )
|
|
|
|
IF HB_ISEVALITEM( ::exGauge ) .AND. ;
|
|
! hb_defaultValue( Eval( ::exGauge, nSent, nSize, Self ), .T. )
|
|
IF hFile != NIL
|
|
hb_vfClose( hFile )
|
|
ENDIF
|
|
RETURN .F.
|
|
ENDIF
|
|
ENDDO
|
|
|
|
IF nSent > 0
|
|
::Commit()
|
|
ENDIF
|
|
|
|
::nStatus := 2
|
|
IF hFile != NIL
|
|
hb_vfClose( hFile )
|
|
ENDIF
|
|
|
|
RETURN ::inetErrorCode( ::SocketCon ) == 0
|
|
|
|
METHOD WriteFromFile( cFile ) CLASS TIPClient
|
|
|
|
LOCAL nFIn
|
|
LOCAL cData
|
|
LOCAL nLen
|
|
LOCAL nSize, nSent, nBufSize
|
|
|
|
::nWrite := 0
|
|
::nStatus := 0
|
|
IF ( nFIn := hb_vfOpen( cFile, FO_READ ) ) == NIL
|
|
RETURN .F.
|
|
ENDIF
|
|
nSize := hb_vfSize( nFIn )
|
|
hb_vfSeek( nFIn, 0 )
|
|
|
|
nBufSize := SND_BUF_SIZE
|
|
|
|
// allow initialization of the gauge
|
|
nSent := 0
|
|
|
|
IF HB_ISEVALITEM( ::exGauge ) .AND. ;
|
|
! hb_defaultValue( Eval( ::exGauge, nSent, nSize, Self ), .T. )
|
|
hb_vfClose( nFIn )
|
|
RETURN .F.
|
|
ENDIF
|
|
|
|
::nStatus := 1
|
|
cData := Space( nBufSize )
|
|
DO WHILE ( nLen := hb_vfRead( nFIn, @cData, nBufSize ) ) > 0
|
|
IF ::Write( @cData, nLen ) != nLen
|
|
hb_vfClose( nFIn )
|
|
RETURN .F.
|
|
ENDIF
|
|
nSent += nLen
|
|
IF HB_ISEVALITEM( ::exGauge ) .AND. ;
|
|
! hb_defaultValue( Eval( ::exGauge, nSent, nSize, Self ), .T. )
|
|
hb_vfClose( nFIn )
|
|
RETURN .F.
|
|
ENDIF
|
|
ENDDO
|
|
|
|
// it may happen that the file has length 0
|
|
IF nSent > 0
|
|
::Commit()
|
|
ENDIF
|
|
|
|
::nStatus := 2
|
|
hb_vfClose( nFIn )
|
|
|
|
RETURN .T.
|
|
|
|
METHOD Write( cData, nLen, lCommit ) CLASS TIPClient
|
|
|
|
IF ! HB_ISNUMERIC( nLen ) .OR. nLen <= 0
|
|
nLen := hb_BLen( cData )
|
|
ENDIF
|
|
|
|
::nLastWrite := ::inetSendAll( ::SocketCon, cData, nLen )
|
|
|
|
IF hb_defaultValue( lCommit, .F. )
|
|
::Commit()
|
|
ENDIF
|
|
|
|
::nWrite += ::nLastWrite
|
|
|
|
RETURN ::nLastWrite
|
|
|
|
METHOD inetSendAll( SocketCon, cData, nLen ) CLASS TIPClient
|
|
|
|
LOCAL nRet
|
|
|
|
IF ! HB_ISNUMERIC( nLen ) .OR. nLen <= 0
|
|
nLen := hb_BLen( cData )
|
|
ENDIF
|
|
|
|
IF ::lSSL .AND. ( ::cProxyHost == "" .OR. ::lProxyXferSSL )
|
|
IF ::lHasSSL
|
|
#if defined( _SSL_DEBUG_TEMP )
|
|
? "SSL_write()", cData
|
|
#endif
|
|
nRet := SSL_write( ::ssl, cData, nLen )
|
|
::nSSLError := iif( nRet < 0, nRet, 0 )
|
|
ELSE
|
|
nRet := 0
|
|
ENDIF
|
|
ELSE
|
|
nRet := hb_inetSendAll( SocketCon, cData, nLen )
|
|
ENDIF
|
|
|
|
IF HB_ISEVALITEM( ::bTrace )
|
|
::Log( SocketCon, nlen, cData, nRet )
|
|
ENDIF
|
|
|
|
RETURN nRet
|
|
|
|
METHOD inetCount( SocketCon ) CLASS TIPClient
|
|
|
|
LOCAL nRet := hb_inetCount( SocketCon )
|
|
|
|
IF HB_ISEVALITEM( ::bTrace )
|
|
::Log( SocketCon, nRet )
|
|
ENDIF
|
|
|
|
RETURN nRet
|
|
|
|
METHOD inetRecv( SocketCon, cStr1, len ) CLASS TIPClient
|
|
|
|
LOCAL nRet
|
|
|
|
IF ::lSSL .AND. ( ::cProxyHost == "" .OR. ::lProxyXferSSL )
|
|
IF ::lHasSSL
|
|
#if defined( _SSL_DEBUG_TEMP )
|
|
? "SSL_read()"
|
|
#endif
|
|
nRet := SSL_read( ::ssl, @cStr1, len )
|
|
::nSSLError := iif( nRet < 0, nRet, 0 )
|
|
ELSE
|
|
nRet := 0
|
|
ENDIF
|
|
ELSE
|
|
nRet := hb_inetRecv( SocketCon, @cStr1, len )
|
|
ENDIF
|
|
|
|
IF HB_ISEVALITEM( ::bTrace )
|
|
::Log( SocketCon, "", len, iif( nRet >= 0, cStr1, nRet ) )
|
|
ENDIF
|
|
|
|
RETURN nRet
|
|
|
|
METHOD inetRecvLine( SocketCon, nRet, size ) CLASS TIPClient
|
|
|
|
LOCAL cRet
|
|
|
|
IF ::lSSL
|
|
IF ::lHasSSL
|
|
nRet := hb_SSL_read_line( ::ssl, @cRet, size, ::nConnTimeout )
|
|
#if defined( _SSL_DEBUG_TEMP )
|
|
? "hb_SSL_read_line()", cRet
|
|
#endif
|
|
IF nRet == 0 .OR. cRet == ""
|
|
cRet := NIL
|
|
ENDIF
|
|
::nSSLError := iif( nRet < 0, nRet, 0 )
|
|
ELSE
|
|
cRet := ""
|
|
nRet := 0
|
|
ENDIF
|
|
ELSE
|
|
cRet := hb_inetRecvLine( SocketCon, @nRet, size )
|
|
ENDIF
|
|
|
|
IF HB_ISEVALITEM( ::bTrace )
|
|
::Log( SocketCon, "", size, cRet )
|
|
ENDIF
|
|
|
|
RETURN cRet
|
|
|
|
METHOD inetRecvAll( SocketCon, cRet, size ) CLASS TIPClient
|
|
|
|
LOCAL nRet
|
|
|
|
IF ::lSSL
|
|
IF ::lHasSSL
|
|
nRet := hb_SSL_read_all( ::ssl, @cRet, size, ::nConnTimeout )
|
|
#if defined( _SSL_DEBUG_TEMP )
|
|
? "hb_SSL_read_all()", cRet
|
|
#endif
|
|
IF nRet == 0 .OR. cRet == ""
|
|
cRet := NIL
|
|
ENDIF
|
|
::nSSLError := iif( nRet < 0, nRet, 0 )
|
|
ELSE
|
|
cRet := ""
|
|
nRet := 0
|
|
ENDIF
|
|
ELSE
|
|
nRet := hb_inetRecvAll( SocketCon, @cRet, size )
|
|
ENDIF
|
|
|
|
IF HB_ISEVALITEM( ::bTrace )
|
|
::Log( SocketCon, "", size, iif( nRet >= 0, cRet, nRet ) )
|
|
ENDIF
|
|
|
|
RETURN nRet
|
|
|
|
METHOD inetErrorCode( SocketCon ) CLASS TIPClient
|
|
|
|
LOCAL nRet
|
|
|
|
IF ::lSSL
|
|
IF ::lHasSSL
|
|
nRet := iif( ::nSSLError == 0, 0, SSL_get_error( ::ssl, ::nSSLError ) )
|
|
ELSE
|
|
nRet := 0
|
|
ENDIF
|
|
ELSE
|
|
nRet := hb_inetErrorCode( SocketCon )
|
|
ENDIF
|
|
|
|
::nLastError := nRet
|
|
|
|
IF HB_ISEVALITEM( ::bTrace )
|
|
::Log( SocketCon, nRet )
|
|
ENDIF
|
|
|
|
RETURN nRet
|
|
|
|
METHOD inetErrorDesc( SocketCon ) CLASS TIPClient
|
|
|
|
hb_default( @SocketCon, ::SocketCon )
|
|
|
|
IF ! Empty( SocketCon )
|
|
IF ::lSSL
|
|
IF ::lHasSSL .AND. ::nSSLError != 0
|
|
RETURN ERR_error_string( SSL_get_error( ::ssl, ::nSSLError ) )
|
|
ENDIF
|
|
ELSE
|
|
RETURN hb_inetErrorDesc( SocketCon )
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN ""
|
|
|
|
/* BROKEN, should test number of parameters and act accordingly, see doc/inet.txt */
|
|
METHOD PROCEDURE inetConnect( cServer, nPort, SocketCon ) CLASS TIPClient
|
|
|
|
hb_inetConnect( cServer, nPort, SocketCon )
|
|
|
|
/* IMPORTANT: if internet connection is off and address is not
|
|
resolved and it is SSL compliant, then RTE must
|
|
be avoided [pritpal] */
|
|
IF hb_inetStatus( SocketCon ) == -1
|
|
RETURN
|
|
ENDIF
|
|
|
|
IF hb_defaultValue( ::nDefaultSndBuffSize, 0 ) > 0
|
|
::InetSndBufSize( SocketCon, ::nDefaultSndBuffSize )
|
|
ENDIF
|
|
|
|
IF hb_defaultValue( ::nDefaultRcvBuffSize, 0 ) > 0
|
|
::InetRcvBufSize( SocketCon, ::nDefaultRcvBuffSize )
|
|
ENDIF
|
|
|
|
IF ::lSSL .AND. ::lHasSSL .AND. ::cProxyHost == ""
|
|
__tip_SSLConnectFD( ::ssl, SocketCon ) /* Proxy will do this in OpenProxy() */
|
|
::lProxyXferSSL := .T.
|
|
ELSE
|
|
::lProxyXferSSL := .F.
|
|
ENDIF
|
|
|
|
IF HB_ISEVALITEM( ::bTrace )
|
|
::Log( cServer, nPort, SocketCon )
|
|
ENDIF
|
|
|
|
RETURN
|
|
|
|
/* Methods to manage buffers */
|
|
METHOD InetRcvBufSize( SocketCon, nSizeBuff ) CLASS TIPClient
|
|
|
|
IF HB_ISNUMERIC( nSizeBuff ) .AND. nSizeBuff > 0
|
|
hb_inetSetRcvBufSize( SocketCon, nSizeBuff )
|
|
ENDIF
|
|
|
|
RETURN hb_inetGetRcvBufSize( SocketCon )
|
|
|
|
METHOD InetSndBufSize( SocketCon, nSizeBuff ) CLASS TIPClient
|
|
|
|
IF HB_ISNUMERIC( nSizeBuff ) .AND. nSizeBuff > 0
|
|
hb_inetSetSndBufSize( SocketCon, nSizeBuff )
|
|
ENDIF
|
|
|
|
RETURN hb_inetGetSndBufSize( SocketCon )
|
|
|
|
METHOD InetTimeOut( SocketCon, nConnTimeout ) CLASS TIPClient
|
|
|
|
IF HB_ISNUMERIC( nConnTimeout )
|
|
::nConnTimeout := nConnTimeout
|
|
ENDIF
|
|
IF HB_ISNUMERIC( ::nConnTimeout )
|
|
RETURN hb_inetTimeout( SocketCon, ::nConnTimeout )
|
|
ENDIF
|
|
|
|
RETURN NIL
|
|
|
|
/* Called from another method with list of parameters and, as last parameter, return code
|
|
of function being logged.
|
|
Example, I want to log MyFunc( a, b, c ) which returns m,
|
|
::Log( a, b, c, m ) */
|
|
METHOD Log( ... ) CLASS TIPClient
|
|
|
|
LOCAL xVar
|
|
LOCAL cMsg
|
|
|
|
IF HB_ISEVALITEM( ::bTrace )
|
|
|
|
cMsg := DToS( Date() ) + "-" + Time() + Space( 2 ) + ;
|
|
SubStr( ProcName( 1 ), RAt( ":", ProcName( 1 ) ) ) + ;
|
|
"( "
|
|
|
|
FOR EACH xVar IN hb_AParams()
|
|
|
|
// Preserves CRLF on result
|
|
IF xVar:__enumIsLast()
|
|
cMsg += hb_CStr( xVar )
|
|
ELSE
|
|
cMsg += hb_StrReplace( AllTrim( hb_CStr( xVar ) ), Chr( 13 ) + Chr( 10 ), { "<cr>", "<lf>" } )
|
|
ENDIF
|
|
|
|
DO CASE
|
|
CASE xVar:__enumIsLast()
|
|
cMsg += " <<" + hb_eol() + hb_eol()
|
|
CASE xVar:__enumIndex() == PCount() - 1
|
|
cMsg += " )" + hb_eol() + ">> "
|
|
OTHERWISE
|
|
cMsg += ", "
|
|
ENDCASE
|
|
NEXT
|
|
|
|
Eval( ::bTrace, cMsg )
|
|
ENDIF
|
|
|
|
RETURN Self
|
|
|
|
METHOD SetProxy( cProxyHost, nProxyPort, cProxyUser, cProxyPassword ) CLASS TIPClient
|
|
|
|
IF __clsParent( cProxyHost:classH(), "TURL" )
|
|
::cProxyHost := cProxyHost:cServer
|
|
::nProxyPort := cProxyHost:nPort
|
|
::cProxyUser := cProxyHost:cUserid
|
|
::cProxyPassword := cProxyHost:cPassword
|
|
ELSE
|
|
::cProxyHost := hb_defaultValue( cProxyHost, "" )
|
|
::nProxyPort := hb_defaultValue( nProxyPort, 0 )
|
|
::cProxyUser := hb_defaultValue( cProxyUser, "" )
|
|
::cProxyPassword := hb_defaultValue( cProxyPassword, "" )
|
|
ENDIF
|
|
|
|
RETURN Self
|
|
|
|
FUNCTION tip_SSL()
|
|
RETURN hb_IsFunction( "__HBEXTERN__HBSSL__" )
|
|
|
|
FUNCTION __tip_SSLConnectFD( ssl, SocketCon )
|
|
|
|
SSL_set_mode( ssl, HB_SSL_MODE_AUTO_RETRY )
|
|
SSL_set_fd( ssl, hb_inetFD( SocketCon ) )
|
|
SSL_connect( ssl )
|
|
|
|
/* TODO: Add error handling */
|
|
|
|
RETURN .T.
|