2015-08-26 15:51 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl)

* include/hbsocket.h
  * src/rtl/hbsockhb.c
    + added socket filters to standard socket API.
      At C level hb_sockex*() function with PHB_SOCKEX handler can be
      used to operate on socket filters. At PRG level standard hb_socket*()
      functions can be used.
      The following things has been changed in PRG hb_socket*() functions:
      hb_socketErorrString() can accept <pSocket> as 1-st or 2-nd parameter
      and redirect call to socket filter errorStr() method.
      hb_socketClose() executes automatically shutdown() for connected
      sockets - it is important in windows only where without explicit
      call to shutdown() before close transmitted data can be lost.
      hb_socketSend() and hb_socketRecv() can be redirected to filter
      streams if filter set such redirection. If filter does not redirect
      them then they operate on raw sockets. If hb_socketSend() is
      redirected then sent data is flushed automatically.
      The following new PRG functions has been added:
      Add/replace socket filter:
         hb_socketSetFilter( <pSocket>, [<cFilterName>], [<hParams>] )
               -> <pSocket> | NIL
            <cFilterName> is filter name, It's possible to set many filters
            in single hb_socketSetFilter() call separating filter names
            with "|" character, i.e.:
               pSock := hb_socketSetFilter( pSock, "ZSOCK|BFSOCK", hParams )
            <hParams> is hash array with initialization parameters used by
            given socket filter. The core implementation recognize the
            following settings:
               "readahead" - numeric value with size of read ahead buffer
               "flush" - numeric value with auto flush parameter (for more
                         information look at hb_socketAutoFlush() below)
               "redir" - logical value which can be use to enable/disable
                         hb_socketSend() and hb_socketRecv() redirection
                         to filter stream.
      Return filter name used by socket:
         hb_socketGetFilter( <pSocket> ) -> <cFilterName>
      Read from socket stream:
         hb_socketRead( <pSocket>, @<cData>, [<nLen> = Len( cData )],
                        [<nTimeout> = FOREVER] ) -> <nRead>
         this function is similar to hb_socketRecv() but is always
         redirected to socket stream filters.
      Write to socket stream:
         hb_socketWrite( <pSocket>, <cData>, [<nLen> = Len( cData )],
                         [<nTimeout> = FOREVER] ) -> <nWritten>
         this function is similar to hb_socketSend() but it is always
         redirected to socket stream filters. Written data is not flushed
         by default and it should be flushed explicitly by hb_socketFlush().
         Automatic flushing can be enabled by hb_socketAutoFlush() function.
      Flush data written to socket:
         hb_socketFlush( <pSocket>, [<nTimeout> = FOREVER], [<lSync>] )
                     -> <nNotFlushed>
            <lSync> parameter is logical value which can be used to force
            special synchronization method in some filters. Usually users
            do not have to use it in normal code.
      Enable/disable automatic flushing of written data.
         hb_socketAutoFlush( <pSocket>, [ <nTimeout> ] ) -> <nTimeout>
            <nTimeout> is timeout for automatic flush operation on written
            data in milliseconds. <nTimeout> = -1 means wait forever and
            <nTimeout> = 0 disables auto flush.
         automatic flushing can help in adopting existing code anyhow it
         may strongly reduce the performance in some filters, i.e.
         compression filters like ZSOCK have to add special data to the
         stream after each flush operation so it's suggested to call
         flush explicitly when we want to force delivering written data
         to the peer.

  * include/hbznet.h
  * src/rtl/hbznet.c
    + added ZNET socket filter - compressed and encrypted streams are
      compatible with hb_znet*() streams. The old hb_znet*() interface
      is obsolete for pure socket communication and if not used as
      hb_inet*() filter then should be replaced by hb_sockex*() in
      user programs.
      ZNET socket filter can be created by new PRG functions:
         hb_socketNewZNet( <pSocket>, [<cPass>], [<nCompressionLevel>], ;
                           [<nStrategy>] ) -> <pSocket> | NIL
      or by standard socket API with "ZNET" as filter name.
      ZNET filter recognize the following settings in initialization
      hash array:
         "key" or "pass" - string with encryption password
         "zlib" - numeric compression level (HB_ZLIB_COMPRESSION_*)
         "zs" - numeric ZLIB compression strategy (HB_ZLIB_STRATEGY_*)
      ZNET filter always disables any other filters and operates on raw
      socket.
      Please remember that it's optional module. If programmer does not
      use hb_socketNewZNet() explicitly and prefers using hb_socketNew()
      then he should force linking this module by REQUEST hb_socketNewZNet

    + added fSync parameter to hb_znetFlush()
      [INCOMPATIBLE]

  * src/rtl/hbinet.c
    * call flush filter function before socket is closed

  * src/rtl/Makefile
  + src/rtl/hbzsock.c
    + added ZSOCK socket filter - ZLIB and GZIP compression for socket
      streams.
      ZSOCK socket filter can be created by new PRG functions:
         hb_socketNewZSock( <pSocket>, [<hParams>] ) -> <pSocket> | NIL
      or by standard socket API with "ZSOCK" as filter name.
      Programmers using hb_socketNew() can force linking this module by
         REQUEST hb_socketNewZSock
      ZSOCK filter can be used with other filters.
      ZSOCK filter recognize the following settings in initialization
      hash array:
         "zlib" - numeric compression level (HB_ZLIB_COMPRESSION_*)
         "zs" - numeric ZLIB compression strategy (HB_ZLIB_STRATEGY_*)
         "zin" - logical value which allow to enable/disable ZLIB
                 decompression on input stream (default)
         "gzin" - logical value which allow to enable/disable GZIP
                  decompression on input stream - it's possible to
                  enable both ZLIB and GZIP decompression together
                  so both streams can be decompress
         "zout" - logical value which allow to enable/disable ZLIB
                  compression on output stream (default)
         "gzout" - logical value which allow to enable/disable GZIP
                   compression on output stream - if both "zout" and
                   "gzout" are enabled GZIP compression is used.

  * src/rtl/Makefile
  + src/rtl/hbbfsock.c
    + added BFSOCK socket filter - BlowFish input and output stream
      encryption in CTR mode.
      BFSOCK socket filter can be created by new PRG functions:
         hb_socketNewBFSock( <pSocket>, [<hParams>] ) -> <pSocket> | NIL
      or by standard socket API with "BFSOCK" as filter name.
      Programmers using hb_socketNew() can force linking this module by
         REQUEST hb_socketNewBFSock
      BFSOCK filter can be used with other filters, i.e. with ZSOCK.
      Please only remember that good encryption algorithms have to
      generate data which cannot be compressed so using "BFSOCK|ZSOCK"
      only wastes resources and correct filter order is "ZSOCK|BFSOCK".
      BFSOCK filter recognize the following settings in initialization
      hash array:
         "key" or "pass" - string with encryption password
         "iv" - string with initialization vector for CTR mode

  * contrib/hbssl/hbssl.ch
  * contrib/hbssl/hbssl.h
  * contrib/hbssl/hbssl.hbm
  * contrib/hbssl/hbssl.hbx
  * contrib/hbssl/ssl.c
  * contrib/hbssl/ssl_inet.c
  + contrib/hbssl/ssl_sock.c
    + added SSL socket filter
      SSL socket filter can be created by new PRG functions:
         hb_socketNewSSL_connect( <pSocket>, <pSSL> [, <nTimeout> ] )
               -> <pSocketSSL> | NIL
         hb_socketNewSSL_accept( <pSocket>, <pSSL> [, <nTimeout> ] )
               -> <pSocketSSL> | NIL
      or by standard socket API with "SSL" as filter name.
      Programmers using hb_socketNew() can force linking this module by
         REQUEST hb_socketNewSSL_connect
      or
         REQUEST hb_socketNewSSL_accept
      SSL filter always disables any other filters and operates on raw
      socket.
      SSL filter recognize the following settings in initialization hash
      array:
         "ctx" or "key" - pointer SSL item <pSSL>
         "timeout" - timeout (numeric)
         "client" - logical value indicating client mode (SSL_connect())
         "server" - logical value indicating server mode (SSL_accept())

  * contrib/hbssl/tests/inetssl.prg
    ! cleaned typo in local function name

  * contrib/hbnetio/netiocli.c
  * contrib/hbnetio/netiosrv.c
    * use new Harbour extended socket API (hb_sockex*()) instead of
      raw sockets and hb_znet*()

  * contrib/hbtcpio/tcpio.c
    * use new Harbour extended socket API (hb_sockex*()) instead of
      raw sockets
    + implemented hb_fileFlush()
This commit is contained in:
Przemysław Czerpak
2015-08-26 15:51:35 +02:00
parent 864a1a106e
commit 41b8ecb6c7
21 changed files with 3148 additions and 521 deletions

View File

@@ -10,6 +10,184 @@
* Change, ! Fix, % Optimization, + Addition, - Removal, ; Comment
*/
2015-08-26 15:51 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl)
* include/hbsocket.h
* src/rtl/hbsockhb.c
+ added socket filters to standard socket API.
At C level hb_sockex*() function with PHB_SOCKEX handler can be
used to operate on socket filters. At PRG level standard hb_socket*()
functions can be used.
The following things has been changed in PRG hb_socket*() functions:
hb_socketErorrString() can accept <pSocket> as 1-st or 2-nd parameter
and redirect call to socket filter errorStr() method.
hb_socketClose() executes automatically shutdown() for connected
sockets - it is important in windows only where without explicit
call to shutdown() before close transmitted data can be lost.
hb_socketSend() and hb_socketRecv() can be redirected to filter
streams if filter set such redirection. If filter does not redirect
them then they operate on raw sockets. If hb_socketSend() is
redirected then sent data is flushed automatically.
The following new PRG functions has been added:
Add/replace socket filter:
hb_socketSetFilter( <pSocket>, [<cFilterName>], [<hParams>] )
-> <pSocket> | NIL
<cFilterName> is filter name, It's possible to set many filters
in single hb_socketSetFilter() call separating filter names
with "|" character, i.e.:
pSock := hb_socketSetFilter( pSock, "ZSOCK|BFSOCK", hParams )
<hParams> is hash array with initialization parameters used by
given socket filter. The core implementation recognize the
following settings:
"readahead" - numeric value with size of read ahead buffer
"flush" - numeric value with auto flush parameter (for more
information look at hb_socketAutoFlush() below)
"redir" - logical value which can be use to enable/disable
hb_socketSend() and hb_socketRecv() redirection
to filter stream.
Return filter name used by socket:
hb_socketGetFilter( <pSocket> ) -> <cFilterName>
Read from socket stream:
hb_socketRead( <pSocket>, @<cData>, [<nLen> = Len( cData )],
[<nTimeout> = FOREVER] ) -> <nRead>
this function is similar to hb_socketRecv() but is always
redirected to socket stream filters.
Write to socket stream:
hb_socketWrite( <pSocket>, <cData>, [<nLen> = Len( cData )],
[<nTimeout> = FOREVER] ) -> <nWritten>
this function is similar to hb_socketSend() but it is always
redirected to socket stream filters. Written data is not flushed
by default and it should be flushed explicitly by hb_socketFlush().
Automatic flushing can be enabled by hb_socketAutoFlush() function.
Flush data written to socket:
hb_socketFlush( <pSocket>, [<nTimeout> = FOREVER], [<lSync>] )
-> <nNotFlushed>
<lSync> parameter is logical value which can be used to force
special synchronization method in some filters. Usually users
do not have to use it in normal code.
Enable/disable automatic flushing of written data.
hb_socketAutoFlush( <pSocket>, [ <nTimeout> ] ) -> <nTimeout>
<nTimeout> is timeout for automatic flush operation on written
data in milliseconds. <nTimeout> = -1 means wait forever and
<nTimeout> = 0 disables auto flush.
automatic flushing can help in adopting existing code anyhow it
may strongly reduce the performance in some filters, i.e.
compression filters like ZSOCK have to add special data to the
stream after each flush operation so it's suggested to call
flush explicitly when we want to force delivering written data
to the peer.
* include/hbznet.h
* src/rtl/hbznet.c
+ added ZNET socket filter - compressed and encrypted streams are
compatible with hb_znet*() streams. The old hb_znet*() interface
is obsolete for pure socket communication and if not used as
hb_inet*() filter then should be replaced by hb_sockex*() in
user programs.
ZNET socket filter can be created by new PRG functions:
hb_socketNewZNet( <pSocket>, [<cPass>], [<nCompressionLevel>], ;
[<nStrategy>] ) -> <pSocket> | NIL
or by standard socket API with "ZNET" as filter name.
ZNET filter recognize the following settings in initialization
hash array:
"key" or "pass" - string with encryption password
"zlib" - numeric compression level (HB_ZLIB_COMPRESSION_*)
"zs" - numeric ZLIB compression strategy (HB_ZLIB_STRATEGY_*)
ZNET filter always disables any other filters and operates on raw
socket.
Please remember that it's optional module. If programmer does not
use hb_socketNewZNet() explicitly and prefers using hb_socketNew()
then he should force linking this module by REQUEST hb_socketNewZNet
+ added fSync parameter to hb_znetFlush()
[INCOMPATIBLE]
* src/rtl/hbinet.c
* call flush filter function before socket is closed
* src/rtl/Makefile
+ src/rtl/hbzsock.c
+ added ZSOCK socket filter - ZLIB and GZIP compression for socket
streams.
ZSOCK socket filter can be created by new PRG functions:
hb_socketNewZSock( <pSocket>, [<hParams>] ) -> <pSocket> | NIL
or by standard socket API with "ZSOCK" as filter name.
Programmers using hb_socketNew() can force linking this module by
REQUEST hb_socketNewZSock
ZSOCK filter can be used with other filters.
ZSOCK filter recognize the following settings in initialization
hash array:
"zlib" - numeric compression level (HB_ZLIB_COMPRESSION_*)
"zs" - numeric ZLIB compression strategy (HB_ZLIB_STRATEGY_*)
"zin" - logical value which allow to enable/disable ZLIB
decompression on input stream (default)
"gzin" - logical value which allow to enable/disable GZIP
decompression on input stream - it's possible to
enable both ZLIB and GZIP decompression together
so both streams can be decompress
"zout" - logical value which allow to enable/disable ZLIB
compression on output stream (default)
"gzout" - logical value which allow to enable/disable GZIP
compression on output stream - if both "zout" and
"gzout" are enabled GZIP compression is used.
* src/rtl/Makefile
+ src/rtl/hbbfsock.c
+ added BFSOCK socket filter - BlowFish input and output stream
encryption in CTR mode.
BFSOCK socket filter can be created by new PRG functions:
hb_socketNewBFSock( <pSocket>, [<hParams>] ) -> <pSocket> | NIL
or by standard socket API with "BFSOCK" as filter name.
Programmers using hb_socketNew() can force linking this module by
REQUEST hb_socketNewBFSock
BFSOCK filter can be used with other filters, i.e. with ZSOCK.
Please only remember that good encryption algorithms have to
generate data which cannot be compressed so using "BFSOCK|ZSOCK"
only wastes resources and correct filter order is "ZSOCK|BFSOCK".
BFSOCK filter recognize the following settings in initialization
hash array:
"key" or "pass" - string with encryption password
"iv" - string with initialization vector for CTR mode
* contrib/hbssl/hbssl.ch
* contrib/hbssl/hbssl.h
* contrib/hbssl/hbssl.hbm
* contrib/hbssl/hbssl.hbx
* contrib/hbssl/ssl.c
* contrib/hbssl/ssl_inet.c
+ contrib/hbssl/ssl_sock.c
+ added SSL socket filter
SSL socket filter can be created by new PRG functions:
hb_socketNewSSL_connect( <pSocket>, <pSSL> [, <nTimeout> ] )
-> <pSocketSSL> | NIL
hb_socketNewSSL_accept( <pSocket>, <pSSL> [, <nTimeout> ] )
-> <pSocketSSL> | NIL
or by standard socket API with "SSL" as filter name.
Programmers using hb_socketNew() can force linking this module by
REQUEST hb_socketNewSSL_connect
or
REQUEST hb_socketNewSSL_accept
SSL filter always disables any other filters and operates on raw
socket.
SSL filter recognize the following settings in initialization hash
array:
"ctx" or "key" - pointer SSL item <pSSL>
"timeout" - timeout (numeric)
"client" - logical value indicating client mode (SSL_connect())
"server" - logical value indicating server mode (SSL_accept())
* contrib/hbssl/tests/inetssl.prg
! cleaned typo in local function name
* contrib/hbnetio/netiocli.c
* contrib/hbnetio/netiosrv.c
* use new Harbour extended socket API (hb_sockex*()) instead of
raw sockets and hb_znet*()
* contrib/hbtcpio/tcpio.c
* use new Harbour extended socket API (hb_sockex*()) instead of
raw sockets
+ implemented hb_fileFlush()
2015-08-17 15:39 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl)
* include/hbznet.h
+ include hbsocket.h

View File

@@ -115,8 +115,7 @@ typedef struct _HB_CONCLI
HB_ERRCODE errcode;
int timeout;
int port;
HB_SOCKET sd;
PHB_ZNETSTREAM zstream;
PHB_SOCKEX sock;
PHB_SRVDATA srvdata;
struct _HB_CONCLI * next;
int level;
@@ -189,10 +188,7 @@ static long s_fileRecvAll( PHB_CONCLI conn, void * buffer, long len )
while( lRead < len )
{
if( conn->zstream )
l = hb_znetRead( conn->zstream, conn->sd, ptr + lRead, len - lRead, conn->timeout );
else
l = hb_socketRecv( conn->sd, ptr + lRead, len - lRead, 0, conn->timeout );
l = hb_sockexRead( conn->sock, ptr + lRead, len - lRead, conn->timeout );
if( l <= 0 )
break;
lRead += l;
@@ -208,10 +204,7 @@ static long s_fileRecvTest( PHB_CONCLI conn, void * buffer, long len )
while( lRead < len )
{
if( conn->zstream )
l = hb_znetRead( conn->zstream, conn->sd, ptr + lRead, len - lRead, timeout );
else
l = hb_socketRecv( conn->sd, ptr + lRead, len - lRead, 0, timeout );
l = hb_sockexRead( conn->sock, ptr + lRead, len - lRead, timeout );
if( l <= 0 )
break;
lRead += l;
@@ -371,7 +364,7 @@ static HB_BOOL s_fileSendMsg( PHB_CONCLI conn, HB_BYTE * msgbuf,
{
HB_BYTE buffer[ 2048 ];
HB_BYTE * msg, * ptr = NULL;
HB_LONG lSent = 0, lLast = 1, l;
HB_LONG lSent = 0, l;
HB_BOOL fResult = HB_FALSE;
if( len == 0 )
@@ -392,14 +385,10 @@ static HB_BOOL s_fileSendMsg( PHB_CONCLI conn, HB_BYTE * msgbuf,
while( lSent < len )
{
if( conn->zstream )
l = hb_znetWrite( conn->zstream, conn->sd, msg + lSent, len - lSent, conn->timeout, &lLast );
else
l = lLast = hb_socketSend( conn->sd, msg + lSent, len - lSent, 0, conn->timeout );
if( l > 0 )
lSent += l;
if( lLast <= 0 )
l = hb_sockexWrite( conn->sock, msg + lSent, len - lSent, conn->timeout );
if( l <= 0 )
break;
lSent += l;
}
if( ptr )
@@ -407,8 +396,7 @@ static HB_BOOL s_fileSendMsg( PHB_CONCLI conn, HB_BYTE * msgbuf,
if( lSent == len )
{
if( conn->zstream &&
hb_znetFlush( conn->zstream, conn->sd, conn->timeout ) != 0 )
if( hb_sockexFlush( conn->sock, conn->timeout, HB_FALSE ) != 0 )
{
conn->errcode = hb_socketGetError();
if( ! fNoError )
@@ -527,6 +515,24 @@ static HB_BOOL s_fileProcessData( PHB_CONCLI conn )
return fResult;
}
static void s_fileConFree( PHB_CONCLI conn )
{
hb_sockexClose( conn->sock, HB_TRUE );
while( conn->srvdata )
{
PHB_SRVDATA pSrvData = conn->srvdata;
conn->srvdata = pSrvData->next;
if( pSrvData->array )
hb_itemRelease( pSrvData->array );
if( pSrvData->data )
hb_xfree( pSrvData->data );
hb_xfree( pSrvData );
}
if( conn->mutex )
hb_itemRelease( conn->mutex );
hb_xfree( conn );
}
static PHB_CONCLI s_fileConNew( HB_SOCKET sd, const char * pszServer,
int iPort, int iTimeOut,
const char * pszPasswd, int iPassLen,
@@ -541,8 +547,6 @@ static PHB_CONCLI s_fileConNew( HB_SOCKET sd, const char * pszServer,
hb_atomic_set( &conn->usrcount, 0 );
conn->mutex = hb_threadMutexCreate();
conn->errcode = 0;
conn->sd = sd;
conn->zstream = NULL;
conn->srvdata = NULL;
conn->next = NULL;
conn->timeout = iTimeOut;
@@ -554,28 +558,21 @@ static PHB_CONCLI s_fileConNew( HB_SOCKET sd, const char * pszServer,
if( iPassLen )
memcpy( conn->passwd, pszPasswd, iPassLen );
return conn;
}
if( iLevel == HB_ZLIB_COMPRESSION_DISABLE )
conn->sock = hb_sockexNew( sd, NULL, NULL );
else
conn->sock = hb_sockexNewZNet( sd, pszPasswd, iPassLen,
iLevel, iStrategy );
static void s_fileConFree( PHB_CONCLI conn )
{
hb_socketShutdown( conn->sd, HB_SOCKET_SHUT_RDWR );
hb_socketClose( conn->sd );
while( conn->srvdata )
if( conn->sock == NULL )
{
PHB_SRVDATA pSrvData = conn->srvdata;
conn->srvdata = pSrvData->next;
if( pSrvData->array )
hb_itemRelease( pSrvData->array );
if( pSrvData->data )
hb_xfree( pSrvData->data );
hb_xfree( pSrvData );
s_fileConFree( conn );
conn = NULL;
}
if( conn->zstream )
hb_znetClose( conn->zstream );
if( conn->mutex )
hb_itemRelease( conn->mutex );
hb_xfree( conn );
else
hb_sockexSetShutDown( conn->sock, HB_TRUE );
return conn;
}
static void s_fileConRegister( PHB_CONCLI conn )
@@ -842,7 +839,6 @@ static PHB_CONCLI s_fileConnect( const char ** pFileName,
int iLevel, int iStrategy )
{
PHB_CONCLI conn;
HB_SOCKET sd;
char server[ NETIO_SERVERNAME_MAX ];
char * pszIpAddres;
@@ -863,7 +859,7 @@ static PHB_CONCLI s_fileConnect( const char ** pFileName,
conn = s_fileConFind( pszIpAddres, iPort );
if( conn == NULL )
{
sd = hb_socketOpen( HB_SOCKET_PF_INET, HB_SOCKET_PT_STREAM, 0 );
HB_SOCKET sd = hb_socketOpen( HB_SOCKET_PF_INET, HB_SOCKET_PT_STREAM, 0 );
if( sd != HB_NO_SOCKET )
{
void * pSockAddr;
@@ -874,35 +870,18 @@ static PHB_CONCLI s_fileConnect( const char ** pFileName,
hb_socketSetKeepAlive( sd, HB_TRUE );
if( hb_socketConnect( sd, pSockAddr, uiLen, iTimeOut ) == 0 )
{
HB_BYTE msgbuf[ NETIO_MSGLEN ];
HB_U16 len = ( HB_U16 ) strlen( NETIO_LOGINSTRID );
HB_PUT_LE_UINT32( &msgbuf[ 0 ], NETIO_LOGIN );
HB_PUT_LE_UINT16( &msgbuf[ 4 ], len );
memset( msgbuf + 6, '\0', sizeof( msgbuf ) - 6 );
hb_socketSetNoDelay( sd, HB_TRUE );
conn = s_fileConNew( sd, pszIpAddres, iPort, iTimeOut,
pszPasswd, iPassLen, iLevel, iStrategy );
sd = HB_NO_SOCKET;
if( iLevel != HB_ZLIB_COMPRESSION_DISABLE )
{
conn->zstream = hb_znetOpen( iLevel, iStrategy );
if( conn->zstream != NULL )
{
if( iPassLen )
hb_znetEncryptKey( conn->zstream, pszPasswd, iPassLen );
}
else
{
s_fileConFree( conn );
conn = NULL;
}
}
if( conn )
{
HB_BYTE msgbuf[ NETIO_MSGLEN ];
HB_U16 len = ( HB_U16 ) strlen( NETIO_LOGINSTRID );
HB_PUT_LE_UINT32( &msgbuf[ 0 ], NETIO_LOGIN );
HB_PUT_LE_UINT16( &msgbuf[ 4 ], len );
memset( msgbuf + 6, '\0', sizeof( msgbuf ) - 6 );
if( ! s_fileSendMsg( conn, msgbuf, NETIO_LOGINSTRID, len,
HB_TRUE, fNoError ) ||
HB_GET_LE_UINT32( &msgbuf[ 4 ] ) != NETIO_CONNECTED )
@@ -912,6 +891,8 @@ static PHB_CONCLI s_fileConnect( const char ** pFileName,
}
else
s_fileConRegister( conn );
sd = HB_NO_SOCKET;
}
}
hb_xfree( pSockAddr );
@@ -2517,7 +2498,7 @@ static HB_BOOL s_fileConfigure( PHB_FILE pFile, int iIndex, PHB_ITEM pValue )
static HB_FHANDLE s_fileHandle( PHB_FILE pFile )
{
return pFile ? pFile->conn->sd : HB_NO_SOCKET;
return pFile ? hb_sockexGetHandle( pFile->conn->sock ) : HB_NO_SOCKET;
}
static const HB_FILE_FUNCS * s_fileMethods( void )

View File

@@ -101,8 +101,7 @@ HB_CONSTREAM, * PHB_CONSTREAM;
typedef struct _HB_CONSRV
{
HB_SOCKET sd;
PHB_ZNETSTREAM zstream;
PHB_SOCKEX sock;
PHB_FILE fileTable[ NETIO_FILES_MAX ];
int filesCount;
int firstFree;
@@ -236,17 +235,10 @@ static PHB_FILE s_srvFileGet( PHB_CONSRV conn, int iFile )
static void s_consrv_disconnect( PHB_CONSRV conn )
{
if( conn->sd != HB_NO_SOCKET )
if( conn->sock )
{
hb_socketShutdown( conn->sd, HB_SOCKET_SHUT_RDWR );
hb_socketClose( conn->sd );
conn->sd = HB_NO_SOCKET;
}
if( conn->zstream )
{
hb_znetClose( conn->zstream );
conn->zstream = NULL;
hb_sockexClose( conn->sock, HB_TRUE );
conn->sock = NULL;
}
}
@@ -267,14 +259,8 @@ static void s_consrv_close( PHB_CONSRV conn )
if( conn->mutex )
hb_itemRelease( conn->mutex );
if( conn->sd != HB_NO_SOCKET )
{
hb_socketShutdown( conn->sd, HB_SOCKET_SHUT_RDWR );
hb_socketClose( conn->sd );
}
if( conn->zstream )
hb_znetClose( conn->zstream );
if( conn->sock )
hb_sockexClose( conn->sock, HB_TRUE );
while( conn->filesCount > 0 )
{
@@ -343,12 +329,12 @@ static void s_consrvRet( PHB_CONSRV conn )
hb_ret();
}
static PHB_CONSRV s_consrvNew( HB_SOCKET connsd, const char * szRootPath, HB_BOOL rpc )
static PHB_CONSRV s_consrvNew( PHB_SOCKEX sock, const char * szRootPath, HB_BOOL rpc )
{
PHB_CONSRV conn = ( PHB_CONSRV ) memset( hb_xgrab( sizeof( HB_CONSRV ) ),
0, sizeof( HB_CONSRV ) );
conn->sd = connsd;
conn->sock = sock;
conn->rpc = rpc;
conn->timeout = -1;
if( szRootPath )
@@ -370,10 +356,7 @@ static HB_BOOL s_srvRecvAll( PHB_CONSRV conn, void * buffer, long len )
while( lRead < len && ! conn->stop )
{
if( conn->zstream )
l = hb_znetRead( conn->zstream, conn->sd, ptr + lRead, len - lRead, 1000 );
else
l = hb_socketRecv( conn->sd, ptr + lRead, len - lRead, 0, 1000 );
l = hb_sockexRead( conn->sock, ptr + lRead, len - lRead, 1000 );
if( l <= 0 )
{
if( l == 0 ||
@@ -395,7 +378,7 @@ static HB_BOOL s_srvRecvAll( PHB_CONSRV conn, void * buffer, long len )
static HB_BOOL s_srvSendAll( PHB_CONSRV conn, void * buffer, long len )
{
HB_BYTE * ptr = ( HB_BYTE * ) buffer;
long lSent = 0, lLast = 1, l;
long lSent = 0, l;
HB_MAXUINT end_timer;
if( ! conn->mutex || hb_threadMutexLock( conn->mutex ) )
@@ -404,16 +387,13 @@ static HB_BOOL s_srvSendAll( PHB_CONSRV conn, void * buffer, long len )
while( lSent < len && ! conn->stop )
{
if( conn->zstream )
l = hb_znetWrite( conn->zstream, conn->sd, ptr + lSent, len - lSent, 1000, &lLast );
else
l = lLast = hb_socketSend( conn->sd, ptr + lSent, len - lSent, 0, 1000 );
l = hb_sockexWrite( conn->sock, ptr + lSent, len - lSent, 1000 );
if( l > 0 )
{
lSent += l;
conn->wr_count += l;
}
if( lLast <= 0 )
else
{
if( hb_socketGetError() != HB_SOCKET_ERR_TIMEOUT ||
hb_vmRequestQuery() != 0 ||
@@ -421,10 +401,10 @@ static HB_BOOL s_srvSendAll( PHB_CONSRV conn, void * buffer, long len )
break;
}
}
if( conn->zstream && lLast > 0 && ! conn->stop )
if( lSent == len && ! conn->stop )
{
if( hb_znetFlush( conn->zstream, conn->sd,
conn->timeout > 0 ? conn->timeout : -1 ) != 0 )
if( hb_sockexFlush( conn->sock, conn->timeout > 0 ? conn->timeout : -1,
HB_FALSE ) != 0 )
lSent = -1;
}
@@ -659,25 +639,20 @@ HB_FUNC( NETIO_ACCEPT )
if( connsd != HB_NO_SOCKET )
{
PHB_SOCKEX sock;
hb_socketSetKeepAlive( connsd, HB_TRUE );
hb_socketSetNoDelay( connsd, HB_TRUE );
conn = s_consrvNew( connsd, lsd->rootPath, lsd->rpc );
if( iLevel != HB_ZLIB_COMPRESSION_DISABLE )
{
conn->zstream = hb_znetOpen( iLevel, iStrategy );
if( conn->zstream != NULL )
{
if( keylen )
hb_znetEncryptKey( conn->zstream, hb_parc( 3 ), keylen );
}
else
{
s_consrv_close( conn );
conn = NULL;
}
}
if( iLevel == HB_ZLIB_COMPRESSION_DISABLE )
sock = hb_sockexNew( connsd, NULL, NULL );
else
sock = hb_sockexNewZNet( connsd, hb_parc( 3 ), keylen,
iLevel, iStrategy );
if( sock != NULL )
conn = s_consrvNew( sock, lsd->rootPath, lsd->rpc );
else
hb_socketClose( connsd );
}
}
@@ -691,9 +666,10 @@ HB_FUNC( NETIO_COMPRESS )
{
PHB_CONSRV conn = s_consrvParam( 1 );
if( conn && conn->sd != HB_NO_SOCKET && ! conn->stop )
if( conn && conn->sock && ! conn->stop )
{
int iLevel, iStrategy, keylen = ( int ) hb_parclen( 2 );
PHB_SOCKEX sock;
if( keylen > NETIO_PASSWD_MAX )
keylen = NETIO_PASSWD_MAX;
@@ -702,31 +678,21 @@ HB_FUNC( NETIO_COMPRESS )
iStrategy = hb_parnidef( 4, HB_ZLIB_STRATEGY_DEFAULT );
if( iLevel == HB_ZLIB_COMPRESSION_DISABLE )
{
if( conn->zstream )
{
hb_znetClose( conn->zstream );
conn->zstream = NULL;
}
}
sock = hb_sockexNew( hb_sockexGetHandle( conn->sock ), NULL, NULL );
else
sock = hb_sockexNewZNet( hb_sockexGetHandle( conn->sock ), hb_parc( 2 ), keylen,
iLevel, iStrategy );
if( sock )
{
PHB_ZNETSTREAM zstream = hb_znetOpen( iLevel, iStrategy );
if( zstream != NULL )
{
if( conn->zstream )
hb_znetClose( conn->zstream );
conn->zstream = zstream;
if( keylen )
hb_znetEncryptKey( zstream, hb_parc( 2 ), keylen );
}
hb_sockexClose( conn->sock, HB_FALSE );
conn->sock = sock;
}
}
}
static HB_BOOL s_netio_login_accept( PHB_CONSRV conn )
{
if( conn && conn->sd != HB_NO_SOCKET && ! conn->stop && ! conn->login )
if( conn && conn->sock && ! conn->stop && ! conn->login )
{
HB_BYTE msgbuf[ NETIO_MSGLEN ];
@@ -1677,7 +1643,7 @@ HB_FUNC( NETIO_SRVSENDITEM )
PHB_ITEM pItem = hb_param( 3, HB_IT_ANY );
HB_BOOL fResult = HB_FALSE;
if( conn && conn->sd != HB_NO_SOCKET && ! conn->stop && conn->mutex &&
if( conn && conn->sock && ! conn->stop && conn->mutex &&
iStreamID && pItem )
{
char * itmData, * msg;
@@ -1722,7 +1688,7 @@ HB_FUNC( NETIO_SRVSENDDATA )
long lLen = ( long ) hb_parclen( 3 );
HB_BOOL fResult = HB_FALSE;
if( conn && conn->sd != HB_NO_SOCKET && ! conn->stop && conn->mutex &&
if( conn && conn->sock && ! conn->stop && conn->mutex &&
iStreamID && lLen > 0 )
{
char * msg;
@@ -1770,7 +1736,7 @@ HB_FUNC( NETIO_SRVSTATUS )
if( ! conn )
iStatus = NETIO_SRVSTAT_WRONGHANDLE;
else if( conn->sd == HB_NO_SOCKET )
else if( conn->sock == NULL )
iStatus = NETIO_SRVSTAT_CLOSED;
else if( conn->stop )
iStatus = NETIO_SRVSTAT_STOPPED;
@@ -1811,7 +1777,7 @@ HB_FUNC( NETIO_SRVSTATUS )
unsigned int len;
PHB_ITEM pItem = NULL;
if( hb_socketGetPeerName( conn->sd, &addr, &len ) == 0 )
if( hb_socketGetPeerName( hb_sockexGetHandle( conn->sock ), &addr, &len ) == 0 )
{
pItem = hb_socketAddrToItem( addr, len );
if( addr )

View File

@@ -82,6 +82,8 @@
#define HB_SSL_ERROR_WANT_CONNECT 7
#define HB_SSL_ERROR_WANT_ACCEPT 8
#define HB_SSL_SOCK_ERROR_BASE 100
#define HB_SSL_OP_MICROSOFT_SESS_ID_BUG 0x00000001
#define HB_SSL_OP_NETSCAPE_CHALLENGE_BUG 0x00000002
#define HB_SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 0x00000008

View File

@@ -50,6 +50,7 @@
#define HBSSL_H_
#include "hbapi.h"
#include "hbsocket.h"
#if defined( HB_OS_WIN )
#if ! defined( HB_OPENSSL_STATIC )
@@ -167,6 +168,21 @@
HB_EXTERN_BEGIN
struct _HB_SSLSTREAM;
typedef struct _HB_SSLSTREAM * PHB_SSLSTREAM;
extern PHB_SOCKEX hb_sockexNewSSL( HB_SOCKET sd, SSL * ssl, HB_BOOL fServer,
HB_MAXINT timeout );
extern PHB_SSLSTREAM hb_ssl_socketNew( HB_SOCKET sd, SSL * ssl, HB_BOOL fServer,
HB_MAXINT timeout, int * piResult );
extern void hb_ssl_socketClose( PHB_SSLSTREAM pStream );
extern const char * hb_ssl_socketErrorStr( int iError );
extern long hb_ssl_socketRead( PHB_SSLSTREAM pStream, HB_SOCKET sd,
void * buffer, long len, HB_MAXINT timeout );
extern long hb_ssl_socketWrite( PHB_SSLSTREAM pStream, HB_SOCKET sd,
const void * buffer, long len,
HB_MAXINT timeout, long * plast );
extern const SSL_METHOD * hb_ssl_method_id_to_ptr( int n );
extern void * hb_BIO_is( int iParam );
@@ -177,6 +193,7 @@ extern SSL_CTX * hb_SSL_CTX_par( int iParam );
extern void * hb_SSL_is( int iParam );
extern SSL * hb_SSL_par( int iParam );
extern SSL * hb_SSL_itemGet( PHB_ITEM pItem );
extern void * hb_SSL_SESSION_is( int iParam );
extern SSL_SESSION * hb_SSL_SESSION_par( int iParam );

View File

@@ -40,6 +40,7 @@ hbssl.hbx
ssl_hb.c
ssl_inet.c
ssl_sock.c
bio.c
err.c
evp.c

View File

@@ -174,6 +174,8 @@ DYNAMIC hb_EVP_CIPHER_ctx_create
DYNAMIC hb_EVP_ENCODE_ctx_create
DYNAMIC hb_inetSSL_accept
DYNAMIC hb_inetSSL_connect
DYNAMIC hb_socketNewSSL_accept
DYNAMIC hb_socketNewSSL_connect
DYNAMIC hb_SSL_read_all
DYNAMIC hb_SSL_read_line
DYNAMIC OpenSSL_add_all_algorithms

View File

@@ -145,6 +145,13 @@ SSL * hb_SSL_par( int iParam )
return ph ? ( SSL * ) *ph : NULL;
}
SSL * hb_SSL_itemGet( PHB_ITEM pItem )
{
void ** ph = ( void ** ) hb_itemGetPtrGC( pItem, &s_gcSSL_funcs );
return ph ? ( SSL * ) *ph : NULL;
}
HB_FUNC( SSL_NEW )
{
if( hb_SSL_CTX_is( 1 ) )

View File

@@ -56,238 +56,47 @@
#include "hbznet.h"
#include "hbssl.h"
#define HB_ZNET_SSL_ERROR_BASE 100
typedef struct _HB_ZNETSTREAM
{
SSL * ssl;
PHB_ITEM pSSL;
int error;
HB_BOOL blocking;
}
HB_ZNETSTREAM;
static long hb_inetReadSSL( PHB_ZNETSTREAM pStream, HB_SOCKET sd,
void * buffer, long len, HB_MAXINT timeout )
{
HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds();
long lRead = -1;
int iToRead = -1;
/* sd = SSL_get_rfd( pStream->ssl ); */
#if LONG_MAX > INT_MAX
if( len > INT_MAX )
len = INT_MAX;
#endif
#if 0
while( ERR_get_error() != 0 ) { /* eat pending errors */ }
#endif
if( pStream->blocking ? timeout >= 0 : timeout < 0 )
{
if( hb_socketSetBlockingIO( sd, timeout < 0 ) >= 0 )
pStream->blocking = !pStream->blocking;
}
pStream->error = 0;
if( len > 0 )
{
iToRead = SSL_pending( pStream->ssl );
if( iToRead <= 0 )
{
iToRead = timeout < 0 ? 1 : hb_socketSelectRead( sd, timeout );
if( iToRead <= 0 )
pStream->error = iToRead == 0 ?
HB_SOCKET_ERR_TIMEOUT : hb_socketGetError();
else
iToRead = ( int ) len;
}
else if( iToRead > len )
iToRead = ( int ) len;
}
while( iToRead > 0 )
{
lRead = SSL_read( pStream->ssl, buffer, iToRead );
if( lRead > 0 )
pStream->error = 0;
else
{
int iError = SSL_get_error( pStream->ssl, ( int ) lRead );
switch( iError )
{
case SSL_ERROR_ZERO_RETURN:
pStream->error = HB_SOCKET_ERR_PIPE;
lRead = 0;
break;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
if( timeout > 0 )
{
HB_MAXUINT timecurr = hb_dateMilliSeconds();
if( timecurr > timer )
timeout -= timecurr - timer;
if( timeout > 0 )
{
timer = timecurr;
if( iError == SSL_ERROR_WANT_READ )
iError = hb_socketSelectRead( sd, timeout );
else
iError = hb_socketSelectWrite( sd, timeout );
if( iError > 0 )
continue;
else if( iError < 0 )
{
pStream->error = hb_socketGetError();
break;
}
}
}
pStream->error = HB_SOCKET_ERR_TIMEOUT;
break;
default:
pStream->error = HB_ZNET_SSL_ERROR_BASE + iError;
}
}
break;
}
return lRead;
return hb_ssl_socketRead( ( PHB_SSLSTREAM ) pStream, sd, buffer, len, timeout );
}
static long hb_inetWriteSSL( PHB_ZNETSTREAM pStream, HB_SOCKET sd,
const void * buffer, long len, HB_MAXINT timeout,
long * plast )
{
HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds();
long lWritten = 0, lWr = 0;
/* sd = SSL_get_wfd( pStream->ssl ); */
#if LONG_MAX > INT_MAX
if( len > INT_MAX )
len = INT_MAX;
#endif
#if 0
while( ERR_get_error() != 0 ) { /* eat pending errors */ }
#endif
if( pStream->blocking ? timeout >= 0 : timeout < 0 )
{
if( hb_socketSetBlockingIO( sd, timeout < 0 ) >= 0 )
pStream->blocking = !pStream->blocking;
}
while( len > 0 )
{
lWr = SSL_write( pStream->ssl, buffer, ( int ) len );
if( plast )
*plast = lWr;
if( lWr > 0 )
{
lWritten += lWr;
len -= lWr;
buffer = ( const char * ) buffer + lWr;
pStream->error = 0;
}
else
{
int iError = SSL_get_error( pStream->ssl, ( int ) lWr );
switch( iError )
{
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
if( timeout > 0 )
{
HB_MAXUINT timecurr = hb_dateMilliSeconds();
if( timecurr > timer )
timeout -= timecurr - timer;
if( timeout > 0 )
{
timer = timecurr;
if( iError == SSL_ERROR_WANT_READ )
iError = hb_socketSelectRead( sd, timeout );
else
iError = hb_socketSelectWrite( sd, timeout );
if( iError > 0 )
continue;
if( lWritten == 0 )
pStream->error = iError < 0 ? hb_socketGetError() :
HB_SOCKET_ERR_TIMEOUT;
break;
}
}
if( lWritten == 0 )
pStream->error = HB_SOCKET_ERR_TIMEOUT;
break;
default:
pStream->error = HB_ZNET_SSL_ERROR_BASE + iError;
}
break;
}
}
return lWritten != 0 ? lWritten : lWr;
}
static long hb_inetFlushSSL( PHB_ZNETSTREAM pStream, HB_SOCKET sd,
HB_MAXINT timeout )
{
HB_SYMBOL_UNUSED( pStream );
HB_SYMBOL_UNUSED( sd );
HB_SYMBOL_UNUSED( timeout );
return 0;
return hb_ssl_socketWrite( ( PHB_SSLSTREAM ) pStream, sd, buffer, len, timeout, plast );
}
static void hb_inetCloseSSL( PHB_ZNETSTREAM pStream )
{
SSL_shutdown( pStream->ssl );
hb_itemRelease( pStream->pSSL );
hb_xfree( pStream );
hb_ssl_socketClose( ( PHB_SSLSTREAM ) pStream );
}
static long hb_inetFlushSSL( PHB_ZNETSTREAM pStream, HB_SOCKET sd,
HB_MAXINT timeout, HB_BOOL fSync )
{
HB_SYMBOL_UNUSED( pStream );
HB_SYMBOL_UNUSED( sd );
HB_SYMBOL_UNUSED( timeout );
HB_SYMBOL_UNUSED( fSync );
return 0;
}
static int hb_inetErrorSSL( PHB_ZNETSTREAM pStream )
{
return pStream->error;
HB_SYMBOL_UNUSED( pStream );
return hb_socketGetError();
}
static const char * hb_inetErrStrSSL( PHB_ZNETSTREAM pStream, int iError )
{
HB_SYMBOL_UNUSED( pStream );
if( iError >= HB_ZNET_SSL_ERROR_BASE )
{
switch( iError - HB_ZNET_SSL_ERROR_BASE )
{
case SSL_ERROR_NONE:
return "SSL_ERROR_NONE";
case SSL_ERROR_ZERO_RETURN:
return "SSL_ERROR_ZERO_RETURN";
case SSL_ERROR_WANT_READ:
return "SSL_ERROR_WANT_READ";
case SSL_ERROR_WANT_WRITE:
return "SSL_ERROR_WANT_WRITE";
case SSL_ERROR_WANT_CONNECT:
return "SSL_ERROR_WANT_CONNECT";
case SSL_ERROR_WANT_ACCEPT:
return "SSL_ERROR_WANT_ACCEPT";
case SSL_ERROR_WANT_X509_LOOKUP:
return "SSL_ERROR_WANT_X509_LOOKUP";
case SSL_ERROR_SYSCALL:
return "SSL_ERROR_SYSCALL";
case SSL_ERROR_SSL:
return "SSL_ERROR_SSL";
}
}
return hb_socketErrorStr( iError );
return hb_ssl_socketErrorStr( iError );
}
static void hb_inetStartSSL( HB_BOOL fServer )
@@ -304,79 +113,21 @@ static void hb_inetStartSSL( HB_BOOL fServer )
if( ssl )
{
PHB_ZNETSTREAM pStream = ( HB_ZNETSTREAM * ) hb_xgrabz( sizeof( HB_ZNETSTREAM ) );
HB_MAXINT timeout;
HB_MAXUINT timer;
timeout = HB_ISNUM( 3 ) ? hb_parnint( 3 ) :
hb_znetInetTimeout( pItem, HB_FALSE );
timer = timeout <= 0 ? 0 : hb_dateMilliSeconds();
pStream->ssl = ssl;
pStream->pSSL = hb_itemNew( hb_param( 2, HB_IT_POINTER ) );
pStream->blocking = timeout < 0;
if( hb_socketSetBlockingIO( sd, pStream->blocking ) < 0 )
pStream->blocking = !pStream->blocking;
SSL_set_mode( ssl, HB_SSL_MODE_AUTO_RETRY );
iResult = SSL_set_fd( ssl, sd );
while( iResult == 1 )
HB_MAXINT timeout = HB_ISNUM( 3 ) ? hb_parnint( 3 ) :
hb_znetInetTimeout( pItem, HB_FALSE );
PHB_SSLSTREAM pStream = hb_ssl_socketNew( sd, ssl, fServer,
timeout, &iResult );
if( pStream )
{
if( fServer )
iResult = SSL_accept( ssl );
else
iResult = SSL_connect( ssl );
if( iResult != 1 )
if( ! hb_znetInetInitialize( pItem, ( PHB_ZNETSTREAM ) pStream,
hb_inetReadSSL, hb_inetWriteSSL,
hb_inetFlushSSL, hb_inetCloseSSL,
hb_inetErrorSSL, hb_inetErrStrSSL ) )
{
int iError = SSL_get_error( ssl, iResult );
if( iError == SSL_ERROR_WANT_READ ||
iError == SSL_ERROR_WANT_WRITE )
{
if( timeout < 0 )
{
iResult = 1;
continue;
}
else if( timeout > 0 )
{
HB_MAXUINT timecurr = hb_dateMilliSeconds();
if( timecurr > timer )
{
timeout -= timecurr - timer;
timer = timecurr;
}
if( timeout > 0 )
{
if( iError == SSL_ERROR_WANT_READ )
iError = hb_socketSelectRead( sd, timeout );
else
iError = hb_socketSelectWrite( sd, timeout );
if( iError > 0 )
{
iResult = 1;
continue;
}
}
}
iResult = -5;
break;
}
iResult = -4;
}
else if( hb_znetInetInitialize( pItem, pStream,
hb_inetReadSSL, hb_inetWriteSSL,
hb_inetFlushSSL, hb_inetCloseSSL,
hb_inetErrorSSL, hb_inetErrStrSSL ) )
break;
else
hb_ssl_socketClose( pStream );
iResult = -3;
}
}
if( iResult != 1 )
hb_inetCloseSSL( pStream );
else
pStream->blocking = hb_socketSetBlockingIO( sd, HB_FALSE ) < 0;
}
hb_retni( iResult );
}

596
contrib/hbssl/ssl_sock.c Normal file
View File

@@ -0,0 +1,596 @@
/*
* Harbour Project source code:
* Harbour extended socket filter with SSL encryption
*
* Copyright 2015 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
* www - http://harbour-project.org
*
* 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 software; see the file COPYING.txt. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
*
* 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.
*
*/
/* this has to be declared before hbsocket.h is included */
#define _HB_SOCKEX_IMPLEMENTATION_
#include "hbapiitm.h"
#include "hbapierr.h"
#include "hbvm.h"
#include "hbsocket.h"
#include "hbdate.h"
#include "hbssl.h"
#include "hbinit.h"
typedef struct _HB_SSLSTREAM
{
SSL * ssl;
PHB_ITEM pSSL;
HB_BOOL blocking;
}
HB_SSLSTREAM;
const char * hb_ssl_socketErrorStr( int iError )
{
if( iError >= HB_SSL_SOCK_ERROR_BASE )
{
switch( iError - HB_SSL_SOCK_ERROR_BASE )
{
case SSL_ERROR_NONE:
return "SSL_ERROR_NONE";
case SSL_ERROR_ZERO_RETURN:
return "SSL_ERROR_ZERO_RETURN";
case SSL_ERROR_WANT_READ:
return "SSL_ERROR_WANT_READ";
case SSL_ERROR_WANT_WRITE:
return "SSL_ERROR_WANT_WRITE";
case SSL_ERROR_WANT_CONNECT:
return "SSL_ERROR_WANT_CONNECT";
case SSL_ERROR_WANT_ACCEPT:
return "SSL_ERROR_WANT_ACCEPT";
case SSL_ERROR_WANT_X509_LOOKUP:
return "SSL_ERROR_WANT_X509_LOOKUP";
case SSL_ERROR_SYSCALL:
return "SSL_ERROR_SYSCALL";
case SSL_ERROR_SSL:
return "SSL_ERROR_SSL";
}
}
return hb_socketErrorStr( iError );
}
long hb_ssl_socketRead( PHB_SSLSTREAM pStream, HB_SOCKET sd,
void * buffer, long len, HB_MAXINT timeout )
{
HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds();
long lRead = -1;
int iToRead = -1;
/* sd = SSL_get_rfd( pStream->ssl ); */
#if LONG_MAX > INT_MAX
if( len > INT_MAX )
len = INT_MAX;
#endif
#if 0
while( ERR_get_error() != 0 ) { /* eat pending errors */ }
#endif
if( pStream->blocking ? timeout >= 0 : timeout < 0 )
{
if( hb_socketSetBlockingIO( sd, timeout < 0 ) >= 0 )
pStream->blocking = !pStream->blocking;
}
if( len > 0 )
{
iToRead = SSL_pending( pStream->ssl );
if( iToRead <= 0 )
{
iToRead = timeout < 0 ? 1 : hb_socketSelectRead( sd, timeout );
if( iToRead > 0 )
iToRead = ( int ) len;
}
else if( iToRead > len )
iToRead = ( int ) len;
}
while( iToRead > 0 )
{
lRead = SSL_read( pStream->ssl, buffer, iToRead );
if( lRead > 0 )
hb_socketSetError( 0 );
else
{
int iError = SSL_get_error( pStream->ssl, ( int ) lRead );
switch( iError )
{
case SSL_ERROR_ZERO_RETURN:
hb_socketSetError( HB_SOCKET_ERR_PIPE );
lRead = 0;
break;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
if( hb_vmRequestQuery() == 0 )
{
if( timeout > 0 )
{
HB_MAXUINT timecurr = hb_dateMilliSeconds();
if( timecurr > timer )
timeout -= timecurr - timer;
if( timeout > 0 )
{
timer = timecurr;
if( iError == SSL_ERROR_WANT_READ )
iError = hb_socketSelectRead( sd, timeout );
else
iError = hb_socketSelectWrite( sd, timeout );
if( iError > 0 )
continue;
else if( iError < 0 )
break;
}
}
hb_socketSetError( HB_SOCKET_ERR_TIMEOUT );
break;
}
default:
hb_socketSetError( HB_SSL_SOCK_ERROR_BASE + iError );
}
}
break;
}
return lRead;
}
long hb_ssl_socketWrite( PHB_SSLSTREAM pStream, HB_SOCKET sd,
const void * buffer, long len, HB_MAXINT timeout,
long * plast )
{
HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds();
long lWritten = 0, lWr = 0;
/* sd = SSL_get_wfd( pStream->ssl ); */
#if LONG_MAX > INT_MAX
if( len > INT_MAX )
len = INT_MAX;
#endif
#if 0
while( ERR_get_error() != 0 ) { /* eat pending errors */ }
#endif
if( pStream->blocking ? timeout >= 0 : timeout < 0 )
{
if( hb_socketSetBlockingIO( sd, timeout < 0 ) >= 0 )
pStream->blocking = !pStream->blocking;
}
while( len > 0 )
{
lWr = SSL_write( pStream->ssl, buffer, ( int ) len );
if( plast )
*plast = lWr;
if( lWr > 0 )
{
lWritten += lWr;
len -= lWr;
buffer = ( const char * ) buffer + lWr;
hb_socketSetError( 0 );
}
else
{
int iError = SSL_get_error( pStream->ssl, ( int ) lWr );
switch( iError )
{
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
if( hb_vmRequestQuery() == 0 )
{
iError = 0;
if( timeout > 0 )
{
HB_MAXUINT timecurr = hb_dateMilliSeconds();
if( timecurr > timer )
timeout -= timecurr - timer;
if( timeout > 0 )
{
timer = timecurr;
if( iError == SSL_ERROR_WANT_READ )
iError = hb_socketSelectRead( sd, timeout );
else
iError = hb_socketSelectWrite( sd, timeout );
if( iError > 0 )
continue;
}
}
if( lWritten == 0 && iError == 0 )
hb_socketSetError( HB_SOCKET_ERR_TIMEOUT );
break;
}
default:
hb_socketSetError( HB_SSL_SOCK_ERROR_BASE + iError );
}
break;
}
}
return lWritten != 0 ? lWritten : lWr;
}
void hb_ssl_socketClose( PHB_SSLSTREAM pStream )
{
SSL_shutdown( pStream->ssl );
hb_itemRelease( pStream->pSSL );
hb_xfree( pStream );
}
PHB_SSLSTREAM hb_ssl_socketNew( HB_SOCKET sd, SSL * ssl, HB_BOOL fServer,
HB_MAXINT timeout, int * piResult )
{
int iResult;
PHB_SSLSTREAM pStream;
HB_MAXUINT timer;
pStream = ( HB_SSLSTREAM * ) hb_xgrabz( sizeof( HB_SSLSTREAM ) );
timer = timeout <= 0 ? 0 : hb_dateMilliSeconds();
pStream->ssl = ssl;
pStream->pSSL = hb_itemNew( hb_param( 2, HB_IT_POINTER ) );
pStream->blocking = timeout < 0;
if( hb_socketSetBlockingIO( sd, pStream->blocking ) < 0 )
pStream->blocking = !pStream->blocking;
SSL_set_mode( ssl, HB_SSL_MODE_AUTO_RETRY );
iResult = SSL_set_fd( ssl, sd );
while( iResult == 1 )
{
if( fServer )
iResult = SSL_accept( ssl );
else
iResult = SSL_connect( ssl );
if( iResult != 1 && hb_vmRequestQuery() == 0 )
{
int iError = SSL_get_error( ssl, iResult );
if( iError == SSL_ERROR_WANT_READ ||
iError == SSL_ERROR_WANT_WRITE )
{
if( timeout < 0 )
{
iResult = 1;
continue;
}
else if( timeout > 0 )
{
HB_MAXUINT timecurr = hb_dateMilliSeconds();
if( timecurr > timer )
{
timeout -= timecurr - timer;
timer = timecurr;
}
if( timeout > 0 )
{
if( iError == SSL_ERROR_WANT_READ )
iError = hb_socketSelectRead( sd, timeout );
else
iError = hb_socketSelectWrite( sd, timeout );
if( iError > 0 )
{
iResult = 1;
continue;
}
}
}
hb_socketSetError( HB_SOCKET_ERR_TIMEOUT );
}
}
break;
}
if( iResult != 1 )
{
hb_ssl_socketClose( pStream );
pStream = NULL;
}
else
pStream->blocking = hb_socketSetBlockingIO( sd, HB_FALSE ) < 0;
if( piResult )
*piResult = iResult;
return pStream;
}
/* socket filter */
#define HB_SSLSOCK_GET( p ) ( ( PHB_SSLSTREAM ) p->cargo )
#define HB_SSLSOCK_READAHEAD 0x40
static PHB_SOCKEX s_sockexNew( HB_SOCKET sd, PHB_ITEM pParams )
{
PHB_SOCKEX pSock;
HB_BOOL fServer = HB_FALSE;
HB_MAXINT timeout = -1;
SSL * ssl = NULL;
if( pParams && HB_IS_HASH( pParams ) )
{
PHB_ITEM pItem;
if( ssl == NULL && ( pItem = hb_hashGetCItemPtr( pParams, "ctx" ) ) != NULL )
ssl = hb_SSL_itemGet( pItem );
if( ssl == NULL && ( pItem = hb_hashGetCItemPtr( pParams, "key" ) ) != NULL )
ssl = hb_SSL_itemGet( pItem );
if( ( pItem = hb_hashGetCItemPtr( pParams, "timeout" ) ) != NULL &&
HB_IS_NUMERIC( pItem ) )
timeout = hb_itemGetNInt( pItem );
if( ( pItem = hb_hashGetCItemPtr( pParams, "server" ) ) != NULL &&
HB_IS_LOGICAL( pItem ) )
fServer = hb_itemGetL( pItem );
else if( ( pItem = hb_hashGetCItemPtr( pParams, "client" ) ) != NULL &&
HB_IS_LOGICAL( pItem ) )
fServer = ! hb_itemGetL( pItem );
}
pSock = hb_sockexNewSSL( sd, ssl, fServer, timeout );
if( pSock )
hb_socekxParamsInit( pSock, pParams );
return pSock;
}
/* this wrapper does not support multilevel filtering so
it destroys previous wrappers if any and create new one.
*/
static PHB_SOCKEX s_sockexNext( PHB_SOCKEX pSock, PHB_ITEM pParams )
{
PHB_SOCKEX pSockNew = NULL;
if( pSock && pSock->sd != HB_NO_SOCKET )
{
pSockNew = s_sockexNew( pSock->sd, pParams );
if( pSockNew )
hb_sockexClose( pSock, HB_FALSE );
}
return pSockNew;
}
static int s_sockexClose( PHB_SOCKEX pSock, HB_BOOL fClose )
{
int iResult;
if( pSock->cargo )
{
SSL_shutdown( HB_SSLSOCK_GET( pSock )->ssl );
hb_itemRelease( HB_SSLSOCK_GET( pSock )->pSSL );
hb_xfree( pSock->cargo );
}
iResult = hb_sockexRawClear( pSock, fClose );
hb_xfree( pSock );
return iResult;
}
static long s_sockexRead( PHB_SOCKEX pSock, void * data, long len, HB_MAXINT timeout )
{
long lRead = HB_MIN( pSock->inbuffer, len );
if( lRead > 0 )
{
memcpy( data, pSock->buffer + pSock->posbuffer, lRead );
pSock->inbuffer -= lRead;
if( pSock->inbuffer )
pSock->posbuffer += lRead;
else
pSock->posbuffer = 0;
return lRead;
}
else if( pSock->sd == HB_NO_SOCKET )
{
hb_socketSetError( HB_SOCKET_ERR_INVALIDHANDLE );
return -1;
}
return hb_ssl_socketRead( HB_SSLSOCK_GET( pSock ), pSock->sd, data, len, timeout );
}
static long s_sockexWrite( PHB_SOCKEX pSock, const void * data, long len, HB_MAXINT timeout )
{
if( pSock->sd == HB_NO_SOCKET )
{
hb_socketSetError( HB_SOCKET_ERR_INVALIDHANDLE );
return -1;
}
return hb_ssl_socketWrite( HB_SSLSOCK_GET( pSock ), pSock->sd, data, len, timeout, NULL );
}
static long s_sockexFlush( PHB_SOCKEX pSock, HB_MAXINT timeout, HB_BOOL fSync )
{
HB_SYMBOL_UNUSED( pSock );
HB_SYMBOL_UNUSED( timeout );
HB_SYMBOL_UNUSED( fSync );
return 0;
}
static int s_sockexCanRead( PHB_SOCKEX pSock, HB_BOOL fBuffer, HB_MAXINT timeout )
{
if( pSock->inbuffer )
return 1;
else if( pSock->sd == HB_NO_SOCKET )
{
hb_socketSetError( HB_SOCKET_ERR_INVALIDHANDLE );
return -1;
}
else if( SSL_pending( HB_SSLSOCK_GET( pSock )->ssl ) )
{
long len;
if( pSock->buffer == NULL )
{
if( pSock->readahead <= 0 )
pSock->readahead = HB_SSLSOCK_READAHEAD;
pSock->buffer = ( HB_BYTE * ) hb_xgrab( pSock->readahead );
}
len = hb_ssl_socketRead( HB_SSLSOCK_GET( pSock ), pSock->sd,
pSock->buffer, pSock->readahead, 0 );
if( len > 0 )
{
pSock->inbuffer = len;
len = 1;
}
return ( int ) len;
}
return fBuffer ? 0 : hb_socketSelectRead( pSock->sd, timeout );
}
static int s_sockexCanWrite( PHB_SOCKEX pSock, HB_BOOL fBuffer, HB_MAXINT timeout )
{
if( pSock->sd == HB_NO_SOCKET )
{
hb_socketSetError( HB_SOCKET_ERR_INVALIDHANDLE );
return -1;
}
return fBuffer ? 0 : hb_socketSelectWrite( pSock->sd, timeout );
}
static char * s_sockexName( PHB_SOCKEX pSock )
{
return hb_strdup( pSock->pFilter->pszName );
}
static const char * s_sockexErrorStr( PHB_SOCKEX pSock, int iError )
{
HB_SYMBOL_UNUSED( pSock );
return hb_ssl_socketErrorStr( iError );
}
static const HB_SOCKET_FILTER s_sockFilter =
{
"SSL",
s_sockexNew,
s_sockexNext,
s_sockexClose,
s_sockexRead,
s_sockexWrite,
s_sockexFlush,
s_sockexCanRead,
s_sockexCanWrite,
s_sockexName,
s_sockexErrorStr
};
PHB_SOCKEX hb_sockexNewSSL( HB_SOCKET sd, SSL * ssl, HB_BOOL fServer,
HB_MAXINT timeout )
{
PHB_SOCKEX pSock = NULL;
if( sd != HB_NO_SOCKET && ssl )
{
PHB_SSLSTREAM pStream = hb_ssl_socketNew( sd, ssl, fServer, timeout, NULL );
if( pStream )
{
pSock = ( PHB_SOCKEX ) hb_xgrabz( sizeof( HB_SOCKEX ) );
pSock->sd = sd;
pSock->fRedirAll = HB_TRUE;
pSock->fShutDown = HB_TRUE;
pSock->pFilter = &s_sockFilter;
pSock->cargo = ( void * ) pStream;
}
}
return pSock;
}
static void s_sslSocketNew( HB_BOOL fServer )
{
HB_SOCKET sd = hb_socketParam( 1 );
if( sd != HB_NO_SOCKET )
{
PHB_SOCKEX pSock = NULL;
SSL * ssl = hb_SSL_par( 2 );
if( ssl )
pSock = hb_sockexNewSSL( sd, ssl, fServer, hb_parnintdef( 3, - 1 ) );
else if( HB_ISHASH( 2 ) )
pSock = hb_sockexNew( sd, s_sockFilter.pszName, hb_param( 2, HB_IT_ANY ) );
else
hb_errRT_BASE( EG_ARG, 2010, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
if( pSock )
{
hb_socketItemClear( hb_param( 1, HB_IT_POINTER ) );
hb_sockexItemPut( hb_param( -1, HB_IT_ANY ), pSock );
}
}
}
/* hb_socketNewSSL_connect( <pSocket>, <pSSL> [, <nTimeout> ] ) */
HB_FUNC( HB_SOCKETNEWSSL_CONNECT )
{
s_sslSocketNew( HB_FALSE );
}
/* hb_socketNewSSL_accept( <pSocket>, <pSSL> [, <nTimeout> ] ) */
HB_FUNC( HB_SOCKETNEWSSL_ACCEPT )
{
s_sslSocketNew( HB_TRUE );
}
HB_CALL_ON_STARTUP_BEGIN( _hb_sslsock_init_ )
hb_sockexRegister( &s_sockFilter );
HB_CALL_ON_STARTUP_END( _hb_sslsock_init_ )
#if defined( HB_PRAGMA_STARTUP )
#pragma startup _hb_sslsock_init_
#elif defined( HB_DATASEG_STARTUP )
#define HB_DATASEG_BODY HB_DATASEG_FUNC( _hb_sslsock_init_ )
#include "hbiniseg.h"
#endif

View File

@@ -81,7 +81,7 @@ STATIC FUNCTION Client()
ERR_error_string( nErr ) )
IF nResult == 1
? "CLIENT: connected with", SSL_get_cipher( ssl ), "encryption."
DipsCertInfo( ssl, "CLIENT: " )
DispCertInfo( ssl, "CLIENT: " )
hb_inetSendAll( sock, hb_TSToStr( hb_DateTime() ) + EOL )
DO WHILE ! Empty( cLine := hb_inetRecvLine( sock ) )
@@ -184,7 +184,7 @@ STATIC FUNCTION LoadCertificates( ssl_ctx, cCertFile, cKeyFile )
RETURN NIL
STATIC FUNCTION DipsCertInfo( ssl, cWho )
STATIC FUNCTION DispCertInfo( ssl, cWho )
LOCAL cert
IF ! Empty( cert := SSL_get_peer_certificate( ssl ) )

View File

@@ -62,13 +62,13 @@
typedef struct _HB_FILE
{
const HB_FILE_FUNCS * pFuncs;
HB_SOCKET sd;
PHB_SOCKEX sock;
HB_BOOL fEof;
int timeout;
}
HB_FILE;
static PHB_FILE s_fileNew( HB_SOCKET sd, int timeout );
static PHB_FILE s_fileNew( PHB_SOCKEX sock, int timeout );
static HB_BOOL s_fileAccept( PHB_FILE_FUNCS pFuncs, const char * pszFileName )
{
@@ -133,6 +133,8 @@ static PHB_FILE s_fileOpen( PHB_FILE_FUNCS pFuncs, const char * pszName,
hb_socketSetKeepAlive( sd, HB_TRUE );
if( hb_socketConnect( sd, pSockAddr, uiLen, timeout ) == 0 )
{
PHB_SOCKEX sock;
switch( nExFlags & ( FO_READ | FO_WRITE | FO_READWRITE ) )
{
case FO_READ:
@@ -142,8 +144,14 @@ static PHB_FILE s_fileOpen( PHB_FILE_FUNCS pFuncs, const char * pszName,
hb_socketShutdown( sd, HB_SOCKET_SHUT_RD );
break;
}
pFile = s_fileNew( sd, timeout );
sd = HB_NO_SOCKET;
sock = hb_sockexNew( sd, NULL, NULL );
if( sock )
{
hb_sockexSetShutDown( sock, HB_TRUE );
hb_sockexSetAutoFlush( sock, HB_TRUE );
pFile = s_fileNew( sock, timeout );
sd = HB_NO_SOCKET;
}
}
hb_xfree( pSockAddr );
}
@@ -178,8 +186,7 @@ static PHB_FILE s_fileOpen( PHB_FILE_FUNCS pFuncs, const char * pszName,
static void s_fileClose( PHB_FILE pFile )
{
hb_socketShutdown( pFile->sd, HB_SOCKET_SHUT_RDWR );
hb_socketClose( pFile->sd );
hb_sockexClose( pFile->sock, HB_TRUE );
hb_fsSetError( hb_socketGetError() );
hb_xfree( pFile );
}
@@ -195,7 +202,7 @@ static HB_SIZE s_fileRead( PHB_FILE pFile, void * data,
lRead = nSize > LONG_MAX ? LONG_MAX : ( long ) nSize;
if( timeout == -1 )
timeout = pFile->timeout;
lRead = hb_socketRecv( pFile->sd, data, lRead, 0, timeout );
lRead = hb_sockexRead( pFile->sock, data, lRead, timeout );
errcode = hb_socketGetError();
@@ -226,7 +233,7 @@ static HB_SIZE s_fileWrite( PHB_FILE pFile, const void * data,
if( timeout == -1 )
timeout = pFile->timeout;
lSend = hb_socketSend( pFile->sd, data, lSend, 0, timeout );
lSend = hb_sockexWrite( pFile->sock, data, lSend, timeout );
hb_fsSetError( hb_socketGetError() );
if( lSend < 0 )
@@ -241,6 +248,13 @@ static HB_BOOL s_fileEof( PHB_FILE pFile )
return pFile->fEof;
}
static void s_fileFlush( PHB_FILE pFile, HB_BOOL fDirty )
{
HB_SYMBOL_UNUSED( fDirty );
hb_sockexFlush( pFile->sock, pFile->timeout, HB_FALSE );
}
static HB_BOOL s_fileConfigure( PHB_FILE pFile, int iIndex, PHB_ITEM pValue )
{
HB_SYMBOL_UNUSED( pFile );
@@ -252,7 +266,7 @@ static HB_BOOL s_fileConfigure( PHB_FILE pFile, int iIndex, PHB_ITEM pValue )
static HB_FHANDLE s_fileHandle( PHB_FILE pFile )
{
return ( HB_FHANDLE ) ( pFile ? pFile->sd : HB_NO_SOCKET );
return ( HB_FHANDLE ) ( pFile ? hb_sockexGetHandle( pFile->sock ) : HB_NO_SOCKET );
}
static HB_FILE_FUNCS s_fileFuncs =
@@ -291,37 +305,37 @@ static HB_FILE_FUNCS s_fileFuncs =
NULL, /* s_fileSeek */
NULL, /* s_fileSize */
s_fileEof,
NULL, /* s_fileFlush */
s_fileFlush,
NULL, /* s_fileCommit */
s_fileConfigure,
s_fileHandle
};
static PHB_FILE s_fileNew( HB_SOCKET sd, int timeout )
static PHB_FILE s_fileNew( PHB_SOCKEX sock, int timeout )
{
PHB_FILE pFile = ( PHB_FILE ) hb_xgrab( sizeof( HB_FILE ) );
pFile->pFuncs = &s_fileFuncs;
pFile->sd = sd;
pFile->sock = sock;
pFile->fEof = HB_FALSE;
pFile->timeout = timeout;
return pFile;
}
static PHB_FILE hb_fileFromSocket( HB_SOCKET sd )
static PHB_FILE hb_fileFromSocket( PHB_SOCKEX sock, HB_MAXINT timeout )
{
return sd != HB_NO_SOCKET ? s_fileNew( sd, -1 ) : NULL;
return sock && hb_sockexGetHandle( sock ) != HB_NO_SOCKET ? s_fileNew( sock, timeout ) : NULL;
}
HB_FUNC( HB_VFFROMSOCKET )
{
HB_SOCKET sd = hb_socketParam( 1 );
PHB_FILE pFile = hb_fileFromSocket( sd );
PHB_SOCKEX sock = hb_sockexParam( 1 );
PHB_FILE pFile = hb_fileFromSocket( sock, hb_parnintdef( 2, -1 ) );
if( pFile )
{
hb_socketItemClear( hb_param( 1, HB_IT_POINTER ) );
hb_sockexItemClear( hb_param( 1, HB_IT_POINTER ) );
hb_fileItemPut( hb_param( -1, HB_IT_ANY ), pFile );
}
}

View File

@@ -783,12 +783,15 @@ DYNAMIC hb_SHA384
DYNAMIC hb_SHA512
DYNAMIC hb_Shadow
DYNAMIC hb_socketAccept
DYNAMIC hb_socketAutoFlush
DYNAMIC hb_socketBind
DYNAMIC hb_socketClose
DYNAMIC hb_socketConnect
DYNAMIC hb_socketErrorString
DYNAMIC hb_socketFlush
DYNAMIC hb_socketGetError
DYNAMIC hb_socketGetFD
DYNAMIC hb_socketGetFilter
DYNAMIC hb_socketGetHostName
DYNAMIC hb_socketGetHosts
DYNAMIC hb_socketGetIFaces
@@ -798,7 +801,11 @@ DYNAMIC hb_socketGetRcvBufSize
DYNAMIC hb_socketGetSndBufSize
DYNAMIC hb_socketGetSockName
DYNAMIC hb_socketListen
DYNAMIC hb_socketNewBFSock
DYNAMIC hb_socketNewZNet
DYNAMIC hb_socketNewZSock
DYNAMIC hb_socketOpen
DYNAMIC hb_socketRead
DYNAMIC hb_socketRecv
DYNAMIC hb_socketRecvFrom
DYNAMIC hb_socketResolveAddr
@@ -812,6 +819,7 @@ DYNAMIC hb_socketSendTo
DYNAMIC hb_socketSetBlockingIO
DYNAMIC hb_socketSetBroadcast
DYNAMIC hb_socketSetExclusiveAddr
DYNAMIC hb_socketSetFilter
DYNAMIC hb_socketSetKeepAlive
DYNAMIC hb_socketSetMulticast
DYNAMIC hb_socketSetNoDelay
@@ -819,6 +827,7 @@ DYNAMIC hb_socketSetRcvBufSize
DYNAMIC hb_socketSetReuseAddr
DYNAMIC hb_socketSetSndBufSize
DYNAMIC hb_socketShutdown
DYNAMIC hb_socketWrite
DYNAMIC hb_SToD
DYNAMIC hb_SToT
DYNAMIC hb_StrCDecode

View File

@@ -123,6 +123,84 @@ extern HB_EXPORT HB_SOCKET hb_socketItemGet( PHB_ITEM pItem );
extern HB_EXPORT PHB_ITEM hb_socketItemPut( PHB_ITEM pItem, HB_SOCKET sd );
extern HB_EXPORT void hb_socketItemClear( PHB_ITEM pItem );
#define HB_SOCKET_FILTER_MAX 128
struct _HB_SOCKEX;
typedef struct _HB_SOCKEX * PHB_SOCKEX;
#if defined( _HB_SOCKEX_IMPLEMENTATION_ )
typedef struct
{
const char * pszName;
PHB_SOCKEX ( * New ) ( HB_SOCKET sd, PHB_ITEM pParams );
PHB_SOCKEX ( * Next ) ( PHB_SOCKEX pSock, PHB_ITEM pParams );
int ( * Close ) ( PHB_SOCKEX pSock, HB_BOOL fClose );
long ( * Read ) ( PHB_SOCKEX pSock, void * data, long len, HB_MAXINT timeout );
long ( * Write ) ( PHB_SOCKEX pSock, const void * data, long len, HB_MAXINT timeout );
long ( * Flush ) ( PHB_SOCKEX pSock, HB_MAXINT timeout, HB_BOOL fSync );
int ( * CanRead ) ( PHB_SOCKEX pSock, HB_BOOL fBuffer, HB_MAXINT timeout );
int ( * CanWrite ) ( PHB_SOCKEX pSock, HB_BOOL fBuffer, HB_MAXINT timeout );
char * ( * Name ) ( PHB_SOCKEX pSock );
const char *( * ErrorStr ) ( PHB_SOCKEX pSock, int iError );
}
HB_SOCKET_FILTER, * PHB_SOCKET_FILTER;
typedef struct _HB_SOCKEX
{
HB_SOCKET sd;
HB_BOOL fRedirAll;
HB_BOOL fShutDown;
int iAutoFlush;
long inbuffer;
long posbuffer;
long readahead;
HB_BYTE * buffer;
void * cargo;
const HB_SOCKET_FILTER * pFilter;
}
HB_SOCKEX;
extern HB_EXPORT int hb_sockexRegister( const HB_SOCKET_FILTER * pFilter );
#endif /* _HB_SOCKEX_IMPLEMENTATION_ */
extern HB_EXPORT int hb_sockexClose( PHB_SOCKEX pSock, HB_BOOL fClose );
extern HB_EXPORT long hb_sockexRead ( PHB_SOCKEX pSock, void * data, long len, HB_MAXINT timeout );
extern HB_EXPORT long hb_sockexWrite( PHB_SOCKEX pSock, const void * data, long len, HB_MAXINT timeout );
extern HB_EXPORT long hb_sockexFlush( PHB_SOCKEX pSock, HB_MAXINT timeout, HB_BOOL fSync );
extern HB_EXPORT int hb_sockexCanRead ( PHB_SOCKEX pSock, HB_BOOL fBuffer, HB_MAXINT timeout );
extern HB_EXPORT int hb_sockexCanWrite( PHB_SOCKEX pSock, HB_BOOL fBuffer, HB_MAXINT timeout );
extern HB_EXPORT int hb_sockexSelect( PHB_ITEM pArrayRD, HB_BOOL fSetRD,
PHB_ITEM pArrayWR, HB_BOOL fSetWR,
PHB_ITEM pArrayEX, HB_BOOL fSetEX,
HB_MAXINT timeout, HB_SOCKET_FUNC pFunc );
extern HB_EXPORT HB_BOOL hb_sockexIsRaw( PHB_SOCKEX pSock );
extern HB_EXPORT int hb_sockexRawClear( PHB_SOCKEX pSock, HB_BOOL fClear );
extern HB_EXPORT HB_SOCKET hb_sockexGetHandle( PHB_SOCKEX pSock );
extern HB_EXPORT void hb_sockexClearHandle( PHB_SOCKEX pSock );
extern HB_EXPORT void hb_sockexSetShutDown( PHB_SOCKEX pSock, HB_BOOL fShutDown );
extern HB_EXPORT HB_BOOL hb_sockexGetShutDown( PHB_SOCKEX pSock );
extern HB_EXPORT void hb_sockexSetAutoFlush( PHB_SOCKEX pSock, int iAutoFlush );
extern HB_EXPORT int hb_sockexGetAutoFlush( PHB_SOCKEX pSock );
extern HB_EXPORT void hb_socekxParamsInit( PHB_SOCKEX pSock, PHB_ITEM pParams );
extern HB_EXPORT void hb_socekxParamsGetStd( PHB_ITEM pParams,
const void ** pKeydata, int * pKeylen,
const void ** pIV, int * pIVlen,
int * pLevel, int * pStrategy );
extern HB_EXPORT PHB_SOCKEX hb_sockexNew( HB_SOCKET sd, const char * pszFilter, PHB_ITEM pParams );
extern HB_EXPORT PHB_SOCKEX hb_sockexNext( PHB_SOCKEX pSock, const char * pszFilter, PHB_ITEM pParams );
extern HB_EXPORT char * hb_sockexName( PHB_SOCKEX pSock );
extern HB_EXPORT const char * hb_sockexErrorStr( PHB_SOCKEX pSock, int iError );
extern HB_EXPORT PHB_SOCKEX hb_sockexParam( int iParam );
extern HB_EXPORT PHB_SOCKEX hb_sockexItemGet( PHB_ITEM pItem );
extern HB_EXPORT PHB_ITEM hb_sockexItemPut( PHB_ITEM pItem, PHB_SOCKEX pSock );
extern HB_EXPORT void hb_sockexItemClear( PHB_ITEM pItem );
extern HB_EXPORT HB_BOOL hb_sockexItemSetFilter( PHB_ITEM pItem, const char * pszFilter, PHB_ITEM pParams );
HB_EXTERN_END
#endif /* HB_SOCKET_H_ */

View File

@@ -60,6 +60,8 @@ HB_EXTERN_BEGIN
#define HB_INET_ERR_BUFFOVERRUN ( -3 )
#define HB_INET_ERR_CLOSEDSOCKET ( -4 )
#define HB_ZNET_SOCK_ERROR_BASE 100
#if defined( _HB_ZNET_INTERNAL_ )
struct _HB_ZNETSTREAM;
typedef struct _HB_ZNETSTREAM * PHB_ZNETSTREAM;
@@ -69,7 +71,7 @@ HB_EXTERN_BEGIN
typedef long ( * HB_INET_RDFUNC ) ( PHB_ZNETSTREAM, HB_SOCKET, void *, long, HB_MAXINT );
typedef long ( * HB_INET_WRFUNC ) ( PHB_ZNETSTREAM, HB_SOCKET, const void *, long, HB_MAXINT, long * );
typedef long ( * HB_INET_FLFUNC ) ( PHB_ZNETSTREAM, HB_SOCKET, HB_MAXINT );
typedef long ( * HB_INET_FLFUNC ) ( PHB_ZNETSTREAM, HB_SOCKET, HB_MAXINT, HB_BOOL );
typedef void ( * HB_INET_CLFUNC ) ( PHB_ZNETSTREAM );
typedef int ( * HB_INET_ERFUNC ) ( PHB_ZNETSTREAM );
typedef const char * ( * HB_INET_ESFUNC ) ( PHB_ZNETSTREAM, int );
@@ -79,7 +81,7 @@ extern HB_EXPORT void hb_znetEncryptKey( PHB_ZNETSTREAM pStream, const void *
extern HB_EXPORT void hb_znetClose( PHB_ZNETSTREAM pStream );
extern HB_EXPORT int hb_znetError( PHB_ZNETSTREAM pStream );
extern HB_EXPORT long hb_znetRead( PHB_ZNETSTREAM pStream, HB_SOCKET sd, void * buffer, long len, HB_MAXINT timeout );
extern HB_EXPORT long hb_znetFlush( PHB_ZNETSTREAM pStream, HB_SOCKET sd, HB_MAXINT timeout );
extern HB_EXPORT long hb_znetFlush( PHB_ZNETSTREAM pStream, HB_SOCKET sd, HB_MAXINT timeout, HB_BOOL fSync );
extern HB_EXPORT long hb_znetWrite( PHB_ZNETSTREAM pStream, HB_SOCKET sd, const void * buffer, long len, HB_MAXINT timeout, long * plast );
extern HB_EXPORT HB_SOCKET hb_znetInetFD( PHB_ITEM pItem, HB_BOOL fError );
@@ -92,6 +94,9 @@ extern HB_EXPORT HB_BOOL hb_znetInetInitialize( PHB_ITEM, PHB_ZNETSTREAM,
HB_INET_ERFUNC,
HB_INET_ESFUNC );
extern HB_EXPORT PHB_SOCKEX hb_sockexNewZNet( HB_SOCKET sd, const void * keydata, int keylen,
int level, int strategy );
HB_EXTERN_END
#endif /* HB_ZNET_H_ */

View File

@@ -75,6 +75,7 @@ C_SOURCES := \
hbascii.c \
hbbffnc.c \
hbbfish.c \
hbbfsock.c \
hbbit.c \
hbbyte.c \
hbcom.c \
@@ -117,6 +118,7 @@ C_SOURCES := \
hbzlibc.c \
hbzlibgz.c \
hbznet.c \
hbzsock.c \
idle.c \
inkey.c \
inkeyapi.c \

370
src/rtl/hbbfsock.c Normal file
View File

@@ -0,0 +1,370 @@
/*
* Harbour Project source code:
* Harbour extended socket filter with ZLIB compression
*
* Copyright 2015 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
* www - http://harbour-project.org
*
* 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 software; see the file COPYING.txt. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
*
* 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.
*
*/
/* this has to be declared before hbsocket.h is included */
#define _HB_SOCKEX_IMPLEMENTATION_
#include "hbapiitm.h"
#include "hbapierr.h"
#include "hbsocket.h"
#include "hbbfish.h"
#include "hbinit.h"
#define HB_BFSOCK_READAHEAD 0x40
#define HB_BFSOCK_WRBUFSIZE 4096
#define HB_BFSOCK_GET( p ) ( ( PHB_SOCKEX_BF ) p->cargo )
typedef struct
{
PHB_SOCKEX sock;
HB_BLOWFISH bf;
HB_BYTE encryptkey[ HB_BF_CIPHERBLOCK ];
HB_BYTE decryptkey[ HB_BF_CIPHERBLOCK ];
HB_BYTE encounter[ HB_BF_CIPHERBLOCK ];
HB_BYTE decounter[ HB_BF_CIPHERBLOCK ];
HB_BYTE buffer[ HB_BFSOCK_WRBUFSIZE ];
long inbuffer;
int encoded;
int decoded;
}
HB_SOCKEX_BF, * PHB_SOCKEX_BF;
static void s_bf_hash( const HB_BLOWFISH * bf,
HB_BYTE * vect, HB_BYTE * counter )
{
HB_U32 xl, xr, cl, cr;
cl = xl = HB_GET_BE_UINT32( &counter[ 0 ] );
cr = xr = HB_GET_BE_UINT32( &counter[ 4 ] );
++cr;
HB_PUT_BE_UINT32( &counter[ 4 ], cr );
if( cr == 0 )
{
++cl;
HB_PUT_BE_UINT32( &counter[ 0 ], cl );
}
hb_blowfishEncrypt( bf, &xl, &xr );
HB_PUT_BE_UINT32( &vect[ 0 ], xl );
HB_PUT_BE_UINT32( &vect[ 4 ], xr );
}
static long s_bf_send( PHB_SOCKEX_BF pBF, HB_MAXINT timeout )
{
long lSent = 0, len = pBF->inbuffer;
while( lSent < len )
{
long l = hb_sockexWrite( pBF->sock, pBF->buffer + lSent, len - lSent, timeout );
if( l <= 0 )
{
switch( hb_socketGetError() )
{
case HB_SOCKET_ERR_TIMEOUT:
case HB_SOCKET_ERR_AGAIN:
case HB_SOCKET_ERR_TRYAGAIN:
break;
default:
lSent = -1;
break;
}
break;
}
lSent += l;
if( timeout > 0 )
timeout = 0;
}
if( lSent > 0 )
{
if( lSent < len )
memmove( pBF->buffer, pBF->buffer + lSent, len - lSent );
pBF->inbuffer -= lSent;
}
return lSent;
}
/* socket filter */
static long s_sockexRead( PHB_SOCKEX pSock, void * data, long len, HB_MAXINT timeout )
{
PHB_SOCKEX_BF pBF = HB_BFSOCK_GET( pSock );
long lRecv;
if( pSock->inbuffer > 0 && len > 0 )
{
lRecv = HB_MIN( pSock->inbuffer, len );
memcpy( data, pSock->buffer + pSock->posbuffer, lRecv );
if( ( pSock->inbuffer -= lRecv ) > 0 )
pSock->posbuffer += lRecv;
else
pSock->posbuffer = 0;
}
else
{
lRecv = hb_sockexRead( pBF->sock, data, len, timeout );
if( lRecv > 0 )
{
HB_BYTE * pData = ( HB_BYTE * ) data;
long l;
for( l = 0; l < lRecv; ++l )
{
if( ( pBF->decoded & ( HB_BF_CIPHERBLOCK - 1 ) ) == 0 )
{
s_bf_hash( &pBF->bf, pBF->decryptkey, pBF->decounter );
pBF->decoded = 0;
}
pData[ l ] ^= pBF->decryptkey[ pBF->decoded++ ];
}
}
}
return lRecv;
}
static long s_sockexWrite( PHB_SOCKEX pSock, const void * data, long len, HB_MAXINT timeout )
{
PHB_SOCKEX_BF pBF = HB_BFSOCK_GET( pSock );
const HB_BYTE * pData = ( const HB_BYTE * ) data;
long lWritten = 0, lDone;
for( lDone = 0; lDone < len; ++lDone )
{
if( pBF->inbuffer == HB_BFSOCK_WRBUFSIZE )
{
lWritten = s_bf_send( pBF, timeout );
if( lWritten <= 0 )
break;
timeout = 0;
}
if( ( pBF->encoded & ( HB_BF_CIPHERBLOCK - 1 ) ) == 0 )
{
s_bf_hash( &pBF->bf, pBF->encryptkey, pBF->encounter );
pBF->encoded = 0;
}
pBF->buffer[ pBF->inbuffer++ ] = pData[ lDone ] ^ pBF->encryptkey[ pBF->encoded++ ];
}
return lWritten >= 0 ? lDone : lWritten;
}
static long s_sockexFlush( PHB_SOCKEX pSock, HB_MAXINT timeout, HB_BOOL fSync )
{
PHB_SOCKEX_BF pBF = HB_BFSOCK_GET( pSock );
while( pBF->inbuffer > 0 )
{
if( s_bf_send( pBF, timeout ) <= 0 )
break;
}
return pBF->inbuffer + hb_sockexFlush( pBF->sock, timeout, fSync );
}
static int s_sockexCanRead( PHB_SOCKEX pSock, HB_BOOL fBuffer, HB_MAXINT timeout )
{
return pSock->inbuffer > 0 ? 1 :
hb_sockexCanRead( HB_BFSOCK_GET( pSock )->sock, fBuffer, timeout );
}
static int s_sockexCanWrite( PHB_SOCKEX pSock, HB_BOOL fBuffer, HB_MAXINT timeout )
{
return hb_sockexCanWrite( HB_BFSOCK_GET( pSock )->sock, fBuffer, timeout );
}
static char * s_sockexName( PHB_SOCKEX pSock )
{
char * pszName = hb_sockexIsRaw( HB_BFSOCK_GET( pSock )->sock ) ? NULL :
hb_sockexName( HB_BFSOCK_GET( pSock )->sock );
if( pszName )
{
char * pszFree = pszName;
pszName = hb_xstrcpy( NULL, pSock->pFilter->pszName, "|", pszName, NULL );
hb_xfree( pszFree );
}
else
pszName = hb_strdup( pSock->pFilter->pszName );
return pszName;
}
static const char * s_sockexErrorStr( PHB_SOCKEX pSock, int iError )
{
return hb_sockexErrorStr( HB_BFSOCK_GET( pSock )->sock, iError );
}
static int s_sockexClose( PHB_SOCKEX pSock, HB_BOOL fClose )
{
PHB_SOCKEX_BF pBF = HB_BFSOCK_GET( pSock );
int iResult = 0;
if( pBF )
{
if( pBF->sock )
s_sockexFlush( pSock, HB_MAX( 15000, pSock->iAutoFlush ), HB_TRUE );
if( pBF->sock )
{
if( pSock->fShutDown )
pBF->sock->fShutDown = HB_TRUE;
if( pSock->iAutoFlush != 0 && pBF->sock->iAutoFlush == 0 )
pBF->sock->iAutoFlush = pSock->iAutoFlush;
iResult = hb_sockexClose( pBF->sock, fClose );
}
memset( pBF, 0, sizeof( *pBF ) );
hb_xfree( pBF );
}
/* call hb_sockexRawClear() with fClose = HB_FALSE because
hb_sockexClose() already closed real socket */
hb_sockexRawClear( pSock, HB_FALSE );
hb_xfree( pSock );
return iResult;
}
static PHB_SOCKEX s_sockexNext( PHB_SOCKEX pSock, PHB_ITEM pParams );
static PHB_SOCKEX s_sockexNew( HB_SOCKET sd, PHB_ITEM pParams )
{
PHB_SOCKEX pSock, pSockNew = NULL;
pSock = hb_sockexNew( sd, NULL, pParams );
if( pSock )
{
pSockNew = s_sockexNext( pSock, pParams );
if( pSockNew == NULL )
hb_sockexClose( pSock, HB_FALSE );
}
return pSockNew;
}
static const HB_SOCKET_FILTER s_sockFilter =
{
"BFSOCK",
s_sockexNew,
s_sockexNext,
s_sockexClose,
s_sockexRead,
s_sockexWrite,
s_sockexFlush,
s_sockexCanRead,
s_sockexCanWrite,
s_sockexName,
s_sockexErrorStr
};
static PHB_SOCKEX s_sockexNext( PHB_SOCKEX pSock, PHB_ITEM pParams )
{
PHB_SOCKEX pSockNew = NULL;
if( pSock )
{
const void * keydata = NULL, * iv = NULL;
int keylen = 0, ivlen = 0;
hb_socekxParamsGetStd( pParams, &keydata, &keylen, &iv, &ivlen, NULL, NULL );
if( keylen > 0 )
{
PHB_SOCKEX_BF pBF = ( PHB_SOCKEX_BF ) hb_xgrabz( sizeof( HB_SOCKEX_BF ) );
HB_BYTE * pVect = ( HB_BYTE * ) ( ivlen > 0 ? iv : NULL );
int i;
hb_blowfishInit( &pBF->bf, keydata, keylen );
for( i = 0; i < HB_BF_CIPHERBLOCK; ++i )
{
if( pVect && ivlen > 0 )
pBF->encounter[ i ] =
pBF->decounter[ i ] = pVect[ i % ivlen ];
else
pBF->encounter[ i ] =
pBF->decounter[ i ] = ( HB_BYTE ) i;
}
pSockNew = ( PHB_SOCKEX ) hb_xgrabz( sizeof( HB_SOCKEX ) );
pSockNew->sd = pSock->sd;
pSockNew->fRedirAll = HB_TRUE;
pSockNew->fShutDown = pSock->fShutDown;
pSockNew->iAutoFlush = pSock->iAutoFlush;
pSockNew->pFilter = &s_sockFilter;
pSockNew->cargo = ( void * ) pBF;
pBF->sock = pSock;
hb_socekxParamsInit( pSockNew, pParams );
}
}
return pSockNew;
}
/* hb_socketNewBFSock( <pSocket>, [<hParams>] ) -> <pSocket> */
HB_FUNC( HB_SOCKETNEWBFSOCK )
{
PHB_SOCKEX pSock = hb_sockexParam( 1 );
if( pSock )
{
pSock = s_sockexNext( pSock, hb_param( 2, HB_IT_HASH ) );
if( pSock )
{
hb_sockexItemClear( hb_param( 1, HB_IT_POINTER ) );
hb_sockexItemPut( hb_param( -1, HB_IT_ANY ), pSock );
}
}
}
HB_CALL_ON_STARTUP_BEGIN( _hb_bfsock_init_ )
hb_sockexRegister( &s_sockFilter );
HB_CALL_ON_STARTUP_END( _hb_bfsock_init_ )
#if defined( HB_PRAGMA_STARTUP )
#pragma startup _hb_bfsock_init_
#elif defined( HB_DATASEG_STARTUP )
#define HB_DATASEG_BODY HB_DATASEG_FUNC( _hb_bfsock_init_ )
#include "hbiniseg.h"
#endif

View File

@@ -164,6 +164,10 @@ static void hb_inetGetError( PHB_SOCKET_STRUCT socket )
static void hb_inetCloseStream( PHB_SOCKET_STRUCT socket )
{
if( socket->flushFunc && socket->sd != HB_NO_SOCKET )
socket->flushFunc( socket->stream, socket->sd,
HB_MAX( socket->iTimeout, 10000 ), HB_TRUE );
if( socket->cleanFunc )
socket->cleanFunc( socket->stream );
@@ -1081,7 +1085,8 @@ static void s_inetSendInternal( HB_BOOL lAll )
/* TODO: safe information about unflushed data and try to call
flush before entering receive wait sate */
socket->flushFunc( socket->stream, socket->sd, socket->iTimeout < 0 ?
socket->iTimeout : HB_MAX( socket->iTimeout, 10000 ) );
socket->iTimeout : HB_MAX( socket->iTimeout, 10000 ),
HB_FALSE );
}
hb_retni( iSent > 0 ? iSent : iLen );

File diff suppressed because it is too large Load Diff

View File

@@ -46,11 +46,15 @@
*
*/
/* this has to be declared before hbsocket.h is included */
#define _HB_SOCKEX_IMPLEMENTATION_
/* this has to be declared before hbznet.h is included */
#define _HB_ZNET_INTERNAL_
#include "hbznet.h"
#include "hbbfish.h"
#include "hbzlib.ch"
#include "hbinit.h"
#include <zlib.h>
@@ -72,6 +76,7 @@ typedef struct _HB_ZNETSTREAM
HB_ZNETSTREAM;
#define HB_ZNET_BUFSIZE 0x4000
#define HB_ZNET_READAHEAD 0x40
#if MAX_MEM_LEVEL >= 8
# define HB_ZNET_MEM_LEVEL 8
@@ -277,7 +282,8 @@ long hb_znetRead( PHB_ZNETSTREAM pStream, HB_SOCKET sd, void * buffer, long len,
if( pStream->err != Z_OK &&
! ( pStream->err == Z_BUF_ERROR && pStream->rd.avail_in == 0 ) )
{
hb_socketSetError( HB_SOCKET_ERR_OTHER );
hb_socketSetError( HB_ZNET_SOCK_ERROR_BASE - pStream->err );
rec = -1;
break;
}
}
@@ -357,12 +363,18 @@ static long hb_znetStreamWrite( PHB_ZNETSTREAM pStream, HB_SOCKET sd, HB_MAXINT
/* flush data in stream structure - return number of bytes left in the
* buffer which were not sent
*/
long hb_znetFlush( PHB_ZNETSTREAM pStream, HB_SOCKET sd, HB_MAXINT timeout )
long hb_znetFlush( PHB_ZNETSTREAM pStream, HB_SOCKET sd, HB_MAXINT timeout,
HB_BOOL fSync )
{
uInt uiSize = HB_ZNET_BUFSIZE - ( pStream->crypt ? 2 : 0 );
if( fSync && pStream->wr.avail_out == uiSize &&
pStream->wr.total_in == 0 && pStream->wr.total_out == 0 )
return 0;
if( pStream->wr.avail_out > 0 )
pStream->err = deflate( &pStream->wr, Z_PARTIAL_FLUSH );
pStream->err = deflate( &pStream->wr,
fSync ? Z_FULL_FLUSH : Z_PARTIAL_FLUSH );
else
pStream->err = Z_OK;
@@ -372,9 +384,16 @@ long hb_znetFlush( PHB_ZNETSTREAM pStream, HB_SOCKET sd, HB_MAXINT timeout )
break;
if( pStream->err == Z_OK )
pStream->err = deflate( &pStream->wr, Z_PARTIAL_FLUSH );
pStream->err = deflate( &pStream->wr,
fSync ? Z_FULL_FLUSH : Z_PARTIAL_FLUSH );
}
if( pStream->err == Z_BUF_ERROR )
pStream->err = Z_OK;
if( pStream->err != Z_OK )
hb_socketSetError( HB_ZNET_SOCK_ERROR_BASE - pStream->err );
return uiSize - pStream->wr.avail_out;
}
@@ -401,10 +420,298 @@ long hb_znetWrite( PHB_ZNETSTREAM pStream, HB_SOCKET sd, const void * buffer, lo
}
pStream->err = deflate( &pStream->wr, Z_NO_FLUSH );
if( pStream->err != Z_OK )
{
if( pStream->err == Z_BUF_ERROR )
pStream->err = Z_OK;
else
{
hb_socketSetError( HB_ZNET_SOCK_ERROR_BASE - pStream->err );
snd = -1;
}
break;
}
}
len -= pStream->wr.avail_in;
return len == 0 ? snd : len;
}
/* socket filter */
#define HB_ZNET_GET( p ) ( ( PHB_ZNETSTREAM ) p->cargo )
static PHB_SOCKEX s_sockexNew( HB_SOCKET sd, PHB_ITEM pParams )
{
PHB_SOCKEX pSock;
const void * keydata = NULL;
int keylen = 0,
level = HB_ZLIB_COMPRESSION_DEFAULT,
strategy = HB_ZLIB_STRATEGY_DEFAULT;
hb_socekxParamsGetStd( pParams, &keydata, &keylen, NULL, NULL,
&level, &strategy );
pSock = hb_sockexNewZNet( sd, keydata, keylen, level, strategy );
if( pSock )
hb_socekxParamsInit( pSock, pParams );
return pSock;
}
/* this wrapper does not support multilevel filtering so
it destroys previous wrappers if any and create new one.
*/
static PHB_SOCKEX s_sockexNext( PHB_SOCKEX pSock, PHB_ITEM pParams )
{
PHB_SOCKEX pSockNew = NULL;
if( pSock && pSock->sd != HB_NO_SOCKET )
{
pSockNew = s_sockexNew( pSock->sd, pParams );
if( pSockNew )
hb_sockexClose( pSock, HB_FALSE );
}
return pSockNew;
}
static int s_sockexClose( PHB_SOCKEX pSock, HB_BOOL fClose )
{
int iResult;
if( pSock->cargo )
{
if( pSock->sd != HB_NO_SOCKET )
hb_znetFlush( HB_ZNET_GET( pSock ), pSock->sd,
HB_MAX( 15000, pSock->iAutoFlush ), HB_TRUE );
hb_znetClose( HB_ZNET_GET( pSock ) );
}
iResult = hb_sockexRawClear( pSock, fClose );
hb_xfree( pSock );
return iResult;
}
static long s_sockexRead( PHB_SOCKEX pSock, void * data, long len, HB_MAXINT timeout )
{
long lRead = HB_MIN( pSock->inbuffer, len );
if( lRead > 0 )
{
memcpy( data, pSock->buffer + pSock->posbuffer, lRead );
pSock->inbuffer -= lRead;
if( pSock->inbuffer )
pSock->posbuffer += lRead;
else
pSock->posbuffer = 0;
len -= lRead;
if( len == 0 || pSock->sd == HB_NO_SOCKET )
return lRead;
data = ( HB_BYTE * ) data + lRead;
timeout = 0;
}
else if( pSock->sd == HB_NO_SOCKET )
{
hb_socketSetError( HB_SOCKET_ERR_INVALIDHANDLE );
return -1;
}
len = pSock->cargo ? hb_znetRead( HB_ZNET_GET( pSock ), pSock->sd, data, len, timeout ) :
hb_socketRecv( pSock->sd, data, len, 0, timeout );
return lRead > 0 ? HB_MAX( len, 0 ) + lRead : len;
}
static long s_sockexWrite( PHB_SOCKEX pSock, const void * data, long len, HB_MAXINT timeout )
{
if( pSock->sd == HB_NO_SOCKET )
{
hb_socketSetError( HB_SOCKET_ERR_INVALIDHANDLE );
return -1;
}
return pSock->cargo ? hb_znetWrite( HB_ZNET_GET( pSock ), pSock->sd, data, len, timeout, NULL ) :
hb_socketSend( pSock->sd, data, len, 0, timeout );
}
static long s_sockexFlush( PHB_SOCKEX pSock, HB_MAXINT timeout, HB_BOOL fSync )
{
if( pSock->sd == HB_NO_SOCKET )
{
hb_socketSetError( HB_SOCKET_ERR_INVALIDHANDLE );
return -1;
}
return pSock->cargo ? hb_znetFlush( HB_ZNET_GET( pSock ), pSock->sd, timeout, fSync ) : 0;
}
static int s_sockexCanRead( PHB_SOCKEX pSock, HB_BOOL fBuffer, HB_MAXINT timeout )
{
if( pSock->inbuffer )
return 1;
else if( pSock->sd == HB_NO_SOCKET )
{
hb_socketSetError( HB_SOCKET_ERR_INVALIDHANDLE );
return -1;
}
else if( pSock->cargo )
{
long len;
if( pSock->buffer == NULL )
{
if( pSock->readahead <= 0 )
pSock->readahead = HB_ZNET_READAHEAD;
pSock->buffer = ( HB_BYTE * ) hb_xgrab( pSock->readahead );
}
len = hb_znetRead( HB_ZNET_GET( pSock ), pSock->sd, pSock->buffer,
pSock->readahead, 0 );
if( len > 0 )
{
pSock->inbuffer = len;
len = 1;
}
return ( int ) len;
}
return fBuffer ? 0 : hb_socketSelectRead( pSock->sd, timeout );
}
static int s_sockexCanWrite( PHB_SOCKEX pSock, HB_BOOL fBuffer, HB_MAXINT timeout )
{
if( pSock->sd == HB_NO_SOCKET )
{
hb_socketSetError( HB_SOCKET_ERR_INVALIDHANDLE );
return -1;
}
else if( fBuffer && pSock->cargo && /* HB_ZNET_GET( pSock )->wr.avail_out > 0 && */
( uInt ) ( HB_ZNET_BUFSIZE - ( HB_ZNET_GET( pSock )->crypt ? 2 : 0 ) ) <=
HB_ZNET_GET( pSock )->wr.avail_out )
return 1;
else
return fBuffer ? 0 : hb_socketSelectWrite( pSock->sd, timeout );
}
static char * s_sockexName( PHB_SOCKEX pSock )
{
return hb_strdup( pSock->pFilter->pszName );
}
static const char * s_sockexErrorStr( PHB_SOCKEX pSock, int iError )
{
HB_SYMBOL_UNUSED( pSock );
switch( HB_ZNET_SOCK_ERROR_BASE - iError )
{
case Z_STREAM_END:
return "Z_STREAM_END";
case Z_NEED_DICT:
return "Z_NEED_DICT";
case Z_ERRNO:
return "Z_ERRNO";
case Z_STREAM_ERROR:
return "Z_STREAM_ERROR";
case Z_DATA_ERROR:
return "Z_DATA_ERROR";
case Z_MEM_ERROR:
return "Z_MEM_ERROR";
case Z_BUF_ERROR:
return "Z_BUF_ERROR";
case Z_VERSION_ERROR:
return "Z_VERSION_ERROR";
}
return hb_socketErrorStr( iError );
}
static const HB_SOCKET_FILTER s_sockFilter =
{
"znet",
s_sockexNew,
s_sockexNext,
s_sockexClose,
s_sockexRead,
s_sockexWrite,
s_sockexFlush,
s_sockexCanRead,
s_sockexCanWrite,
s_sockexName,
s_sockexErrorStr
};
PHB_SOCKEX hb_sockexNewZNet( HB_SOCKET sd, const void * keydata, int keylen,
int level, int strategy )
{
PHB_SOCKEX pSock = NULL;
if( sd != HB_NO_SOCKET )
{
PHB_ZNETSTREAM pStream = NULL;
if( level != HB_ZLIB_COMPRESSION_DISABLE )
{
pStream = hb_znetOpen( level, strategy );
if( pStream )
{
if( keydata && keylen > 0 )
hb_znetEncryptKey( pStream, keydata, keylen );
}
else
sd = HB_NO_SOCKET;
}
if( sd != HB_NO_SOCKET )
{
pSock = ( PHB_SOCKEX ) hb_xgrabz( sizeof( HB_SOCKEX ) );
pSock->sd = sd;
pSock->fRedirAll = HB_TRUE;
pSock->fShutDown = HB_TRUE;
pSock->pFilter = &s_sockFilter;
pSock->cargo = ( void * ) pStream;
}
}
return pSock;
}
/* hb_socketNewZNet( <pSocket>, [<cPass>], ;
[<nCompressionLevel>], [<nStrategy>] ) -> <pSocket>
*/
HB_FUNC( HB_SOCKETNEWZNET )
{
HB_SOCKET sd = hb_socketParam( 1 );
if( sd != HB_NO_SOCKET )
{
PHB_SOCKEX pSock;
if( HB_ISHASH( 2 ) )
{
pSock = hb_sockexNew( sd, s_sockFilter.pszName, hb_param( 2, HB_IT_ANY ) );
}
else
{
const char * keydata = hb_parc( 2 );
int keylen = ( int ) hb_parclen( 2 ),
level = hb_parnidef( 3, HB_ZLIB_COMPRESSION_DEFAULT ),
strategy = hb_parnidef( 4, HB_ZLIB_STRATEGY_DEFAULT );
pSock = hb_sockexNewZNet( sd, keydata, keylen, level, strategy );
}
if( pSock )
{
hb_socketItemClear( hb_param( 1, HB_IT_POINTER ) );
hb_sockexItemPut( hb_param( -1, HB_IT_ANY ), pSock );
}
}
}
HB_CALL_ON_STARTUP_BEGIN( _hb_znet_init_ )
hb_sockexRegister( &s_sockFilter );
HB_CALL_ON_STARTUP_END( _hb_znet_init_ )
#if defined( HB_PRAGMA_STARTUP )
#pragma startup _hb_znet_init_
#elif defined( HB_DATASEG_STARTUP )
#define HB_DATASEG_BODY HB_DATASEG_FUNC( _hb_znet_init_ )
#include "hbiniseg.h"
#endif

575
src/rtl/hbzsock.c Normal file
View File

@@ -0,0 +1,575 @@
/*
* Harbour Project source code:
* Harbour extended socket filter with ZLIB compression
*
* Copyright 2015 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
* www - http://harbour-project.org
*
* 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 software; see the file COPYING.txt. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
*
* 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.
*
*/
/* this has to be declared before hbsocket.h is included */
#define _HB_SOCKEX_IMPLEMENTATION_
#include "hbapiitm.h"
#include "hbapierr.h"
#include "hbsocket.h"
#include "hbinit.h"
#include "hbzlib.ch"
#include <zlib.h>
#define HB_ZSOCK_ERROR_BASE 100
#define HB_ZSOCK_READAHEAD 0x40
#define HB_ZSOCK_RDBUFSIZE 4096
#define HB_ZSOCK_WRBUFSIZE 4096
#if MAX_MEM_LEVEL >= 8
# define HB_ZSOCK_MEM_LEVEL 8
#else
# define HB_ZSOCK_MEM_LEVEL MAX_MEM_LEVEL
#endif
#define HB_ZSOCK_GET( p ) ( ( PHB_SOCKEX_Z ) p->cargo )
typedef struct
{
PHB_SOCKEX sock;
HB_BOOL fDecompressIn;
HB_BOOL fCompressOut;
z_stream z_read;
z_stream z_write;
HB_BYTE * rdbuf;
HB_BYTE * wrbuf;
}
HB_SOCKEX_Z, * PHB_SOCKEX_Z;
static voidpf s_zsock_zalloc( voidpf opaque, uInt items, uInt size )
{
HB_SYMBOL_UNUSED( opaque );
return hb_xalloc( ( HB_SIZE ) items * size );
}
static void s_zsock_zfree( voidpf opaque, voidpf address )
{
HB_SYMBOL_UNUSED( opaque );
hb_xfree( address );
}
static long s_zsock_write( PHB_SOCKEX_Z pZ, HB_MAXINT timeout )
{
long lSent = 0, len = HB_ZSOCK_WRBUFSIZE - pZ->z_write.avail_out;
while( lSent < len )
{
long l = hb_sockexWrite( pZ->sock, pZ->wrbuf + lSent, len - lSent, timeout );
if( l <= 0 )
{
switch( hb_socketGetError() )
{
case HB_SOCKET_ERR_TIMEOUT:
case HB_SOCKET_ERR_AGAIN:
case HB_SOCKET_ERR_TRYAGAIN:
break;
default:
lSent = -1;
break;
}
break;
}
lSent += l;
if( timeout > 0 )
timeout = 0;
}
if( lSent > 0 )
{
if( lSent < len )
memmove( pZ->wrbuf, pZ->wrbuf + lSent, len - lSent );
pZ->z_write.avail_out += lSent;
pZ->z_write.next_out -= lSent;
}
return lSent;
}
static int s_zsock_inbuffer( PHB_SOCKEX pSock )
{
PHB_SOCKEX_Z pZ = HB_ZSOCK_GET( pSock );
if( pSock->inbuffer == 0 && pZ->fDecompressIn )
{
int err;
if( pSock->buffer == NULL )
{
if( pSock->readahead <= 0 )
pSock->readahead = HB_ZSOCK_READAHEAD;
pSock->buffer = ( HB_BYTE * ) hb_xgrab( pSock->readahead );
}
pZ->z_read.next_out = ( Bytef * ) pSock->buffer;
pZ->z_read.avail_out = ( uInt ) pSock->readahead;
err = inflate( &pZ->z_read, Z_SYNC_FLUSH );
if( err != Z_OK && err != Z_BUF_ERROR )
hb_socketSetError( HB_ZSOCK_ERROR_BASE - err );
pSock->inbuffer = pSock->readahead - pZ->z_read.avail_out;
}
return pSock->inbuffer > 0 ? 1 : 0;
}
/* socket filter */
static long s_sockexRead( PHB_SOCKEX pSock, void * data, long len, HB_MAXINT timeout )
{
PHB_SOCKEX_Z pZ = HB_ZSOCK_GET( pSock );
long lRecv = 0;
if( pSock->inbuffer > 0 && len > 0 )
{
lRecv = HB_MIN( pSock->inbuffer, len );
memcpy( data, pSock->buffer + pSock->posbuffer, lRecv );
if( ( pSock->inbuffer -= lRecv ) > 0 )
pSock->posbuffer += lRecv;
else
pSock->posbuffer = 0;
return lRecv;
}
else if( pZ->fDecompressIn )
{
int err = Z_OK;
pZ->z_read.next_out = ( Bytef * ) data;
pZ->z_read.avail_out = ( uInt ) len;
pZ->z_read.total_out = 0;
while( pZ->z_read.avail_out )
{
if( err == Z_BUF_ERROR && pZ->z_read.avail_in == 0 )
{
lRecv = hb_sockexRead( pZ->sock, pZ->rdbuf, HB_ZSOCK_RDBUFSIZE,
pZ->z_read.total_out == 0 ? timeout : 0 );
if( lRecv <= 0 )
break;
pZ->z_read.next_in = ( Bytef * ) pZ->rdbuf;
pZ->z_read.avail_in = ( uInt ) lRecv;
}
else if( err != Z_OK )
{
hb_socketSetError( HB_ZSOCK_ERROR_BASE - err );
lRecv = -1;
break;
}
err = inflate( &pZ->z_read, Z_SYNC_FLUSH );
}
if( pZ->z_read.total_out != 0 )
lRecv = ( long ) pZ->z_read.total_out;
return pZ->z_read.total_out != 0 ? ( long ) pZ->z_read.total_out : lRecv;
}
else
return hb_sockexRead( pZ->sock, data, len, timeout );
}
static long s_sockexWrite( PHB_SOCKEX pSock, const void * data, long len, HB_MAXINT timeout )
{
PHB_SOCKEX_Z pZ = HB_ZSOCK_GET( pSock );
if( pZ->fCompressOut )
{
long lWritten = 0;
pZ->z_write.next_in = ( Bytef * ) data;
pZ->z_write.avail_in = ( uInt ) len;
while( pZ->z_write.avail_in )
{
int err;
if( pZ->z_write.avail_out == 0 )
{
lWritten = s_zsock_write( pZ, timeout );
if( lWritten <= 0 )
break;
timeout = 0;
}
err = deflate( &pZ->z_write, Z_NO_FLUSH );
if( err != Z_OK )
{
if( err != Z_BUF_ERROR )
{
hb_socketSetError( HB_ZSOCK_ERROR_BASE - err );
lWritten = -1;
}
break;
}
}
return lWritten >= 0 ? len - pZ->z_write.avail_in : lWritten;
}
else
return hb_sockexWrite( pSock, data, len, timeout );
}
static long s_sockexFlush( PHB_SOCKEX pSock, HB_MAXINT timeout, HB_BOOL fSync )
{
PHB_SOCKEX_Z pZ = HB_ZSOCK_GET( pSock );
long lResult = 0;
if( pZ->fCompressOut &&
( ! fSync || pZ->z_write.avail_out != HB_ZSOCK_WRBUFSIZE ||
pZ->z_write.total_in != 0 || pZ->z_write.total_out != 0 ) )
{
int err;
if( pZ->z_write.avail_out > 0 )
err = deflate( &pZ->z_write, fSync ? Z_FULL_FLUSH : Z_PARTIAL_FLUSH );
else
err = Z_OK;
while( pZ->z_write.avail_out < HB_ZSOCK_WRBUFSIZE )
{
if( s_zsock_write( pZ, timeout ) <= 0 )
break;
if( err == Z_OK )
err = deflate( &pZ->z_write, fSync ? Z_FULL_FLUSH : Z_PARTIAL_FLUSH );
}
if( err != Z_OK && err != Z_BUF_ERROR )
hb_socketSetError( HB_ZSOCK_ERROR_BASE - err );
lResult = HB_ZSOCK_WRBUFSIZE - pZ->z_write.avail_out;
}
return lResult + hb_sockexFlush( HB_ZSOCK_GET( pSock )->sock, timeout, fSync );
}
static int s_sockexCanRead( PHB_SOCKEX pSock, HB_BOOL fBuffer, HB_MAXINT timeout )
{
return s_zsock_inbuffer( pSock ) ? 1 :
hb_sockexCanRead( HB_ZSOCK_GET( pSock )->sock, fBuffer, timeout );
}
static int s_sockexCanWrite( PHB_SOCKEX pSock, HB_BOOL fBuffer, HB_MAXINT timeout )
{
return hb_sockexCanWrite( HB_ZSOCK_GET( pSock )->sock, fBuffer, timeout );
}
static char * s_sockexName( PHB_SOCKEX pSock )
{
char * pszName = hb_sockexIsRaw( HB_ZSOCK_GET( pSock )->sock ) ? NULL :
hb_sockexName( HB_ZSOCK_GET( pSock )->sock );
if( pszName )
{
char * pszFree = pszName;
pszName = hb_xstrcpy( NULL, pSock->pFilter->pszName, "|", pszName, NULL );
hb_xfree( pszFree );
}
else
pszName = hb_strdup( pSock->pFilter->pszName );
return pszName;
}
static const char * s_sockexErrorStr( PHB_SOCKEX pSock, int iError )
{
switch( HB_ZSOCK_ERROR_BASE - iError )
{
case Z_STREAM_END:
return "Z_STREAM_END";
case Z_NEED_DICT:
return "Z_NEED_DICT";
case Z_ERRNO:
return "Z_ERRNO";
case Z_STREAM_ERROR:
return "Z_STREAM_ERROR";
case Z_DATA_ERROR:
return "Z_DATA_ERROR";
case Z_MEM_ERROR:
return "Z_MEM_ERROR";
case Z_BUF_ERROR:
return "Z_BUF_ERROR";
case Z_VERSION_ERROR:
return "Z_VERSION_ERROR";
}
return hb_sockexErrorStr( HB_ZSOCK_GET( pSock )->sock, iError );
}
static int s_sockexClose( PHB_SOCKEX pSock, HB_BOOL fClose )
{
PHB_SOCKEX_Z pZ = HB_ZSOCK_GET( pSock );
int iResult = 0;
if( pZ )
{
if( pZ->sock )
s_sockexFlush( pSock, HB_MAX( 15000, pSock->iAutoFlush ), HB_TRUE );
if( pZ->fDecompressIn )
inflateEnd( &pZ->z_read );
if( pZ->rdbuf )
hb_xfree( pZ->rdbuf );
if( pZ->fCompressOut )
deflateEnd( &pZ->z_write );
if( pZ->wrbuf )
hb_xfree( pZ->wrbuf );
if( pZ->sock )
{
if( pSock->fShutDown )
pZ->sock->fShutDown = HB_TRUE;
if( pSock->iAutoFlush != 0 && pZ->sock->iAutoFlush == 0 )
pZ->sock->iAutoFlush = pSock->iAutoFlush;
iResult = hb_sockexClose( pZ->sock, fClose );
}
hb_xfree( pZ );
}
/* call hb_sockexRawClear() with fClose = HB_FALSE because
hb_sockexClose() already closed real socket */
hb_sockexRawClear( pSock, HB_FALSE );
hb_xfree( pSock );
return iResult;
}
static PHB_SOCKEX s_sockexNext( PHB_SOCKEX pSock, PHB_ITEM pParams );
static PHB_SOCKEX s_sockexNew( HB_SOCKET sd, PHB_ITEM pParams )
{
PHB_SOCKEX pSock, pSockNew = NULL;
pSock = hb_sockexNew( sd, NULL, pParams );
if( pSock )
{
pSockNew = s_sockexNext( pSock, pParams );
if( pSockNew == NULL )
hb_sockexClose( pSock, HB_FALSE );
}
return pSockNew;
}
static const HB_SOCKET_FILTER s_sockFilter =
{
"ZSOCK",
s_sockexNew,
s_sockexNext,
s_sockexClose,
s_sockexRead,
s_sockexWrite,
s_sockexFlush,
s_sockexCanRead,
s_sockexCanWrite,
s_sockexName,
s_sockexErrorStr
};
static PHB_SOCKEX s_sockexNext( PHB_SOCKEX pSock, PHB_ITEM pParams )
{
PHB_SOCKEX pSockNew = NULL;
if( pSock )
{
HB_BOOL fDecompressIn = HB_TRUE, fCompressOut = HB_TRUE;
int level = HB_ZLIB_COMPRESSION_DEFAULT,
strategy = HB_ZLIB_STRATEGY_DEFAULT,
windowBitsIn = MAX_WBITS, windowBitsOut = MAX_WBITS;
if( pParams && HB_IS_HASH( pParams ) )
{
PHB_ITEM pItem;
if( ( pItem = hb_hashGetCItemPtr( pParams, "zlib" ) ) != NULL &&
HB_IS_NUMERIC( pItem ) )
level = hb_itemGetNI( pItem );
if( ( pItem = hb_hashGetCItemPtr( pParams, "zs" ) ) != NULL &&
HB_IS_NUMERIC( pItem ) )
strategy = hb_itemGetNI( pItem );
if( ( pItem = hb_hashGetCItemPtr( pParams, "gzin" ) ) != NULL &&
HB_IS_LOGICAL( pItem ) )
{
fDecompressIn = hb_itemGetL( pItem );
if( fDecompressIn )
windowBitsIn += 16;
}
if( ( pItem = hb_hashGetCItemPtr( pParams, "zin" ) ) != NULL &&
HB_IS_LOGICAL( pItem ) )
{
if( windowBitsIn == MAX_WBITS )
fDecompressIn = hb_itemGetL( pItem );
else if( hb_itemGetL( pItem ) )
windowBitsIn += 16;
}
if( ( pItem = hb_hashGetCItemPtr( pParams, "gzout" ) ) != NULL &&
HB_IS_LOGICAL( pItem ) )
{
fCompressOut = hb_itemGetL( pItem );
if( fCompressOut )
windowBitsOut += 16;
}
if( ( pItem = hb_hashGetCItemPtr( pParams, "zout" ) ) != NULL &&
HB_IS_LOGICAL( pItem ) && windowBitsOut == MAX_WBITS )
fCompressOut = hb_itemGetL( pItem );
}
if( level != HB_ZLIB_COMPRESSION_DISABLE &&
( fDecompressIn || fCompressOut ) )
{
PHB_SOCKEX_Z pZ = ( PHB_SOCKEX_Z ) hb_xgrabz( sizeof( HB_SOCKEX_Z ) );
pSockNew = ( PHB_SOCKEX ) hb_xgrabz( sizeof( HB_SOCKEX ) );
pSockNew->sd = HB_NO_SOCKET;
pSockNew->fRedirAll = HB_TRUE;
pSockNew->pFilter = &s_sockFilter;
pSockNew->cargo = ( void * ) pZ;
pZ->z_read.zalloc = s_zsock_zalloc;
pZ->z_read.zfree = s_zsock_zfree;
pZ->z_read.opaque = Z_NULL;
pZ->z_write.zalloc = s_zsock_zalloc;
pZ->z_write.zfree = s_zsock_zfree;
pZ->z_write.opaque = Z_NULL;
pZ->z_read.next_in = NULL;
pZ->z_read.avail_in = 0;
if( level != Z_DEFAULT_COMPRESSION &&
!( level >= Z_NO_COMPRESSION && level <= Z_BEST_COMPRESSION ) )
level = Z_DEFAULT_COMPRESSION;
if( strategy != Z_FILTERED &&
#if defined( Z_RLE )
strategy != Z_RLE &&
#endif
#if defined( Z_FIXED )
strategy != Z_FIXED &&
#endif
strategy != Z_HUFFMAN_ONLY )
strategy = Z_DEFAULT_STRATEGY;
if( fDecompressIn && level != HB_ZLIB_COMPRESSION_DISABLE )
{
/* MAX_WBITS=15, decompression - support for formats:
* -15: raw, 15: ZLIB, 31: GZIP, 47: ZLIB+GZIP
*/
if( inflateInit2( &pZ->z_read, windowBitsIn ) == Z_OK )
{
pZ->fDecompressIn = HB_TRUE;
pZ->rdbuf = ( HB_BYTE * ) hb_xgrab( HB_ZSOCK_RDBUFSIZE );
}
else
level = HB_ZLIB_COMPRESSION_DISABLE;
}
if( fCompressOut && level != HB_ZLIB_COMPRESSION_DISABLE )
{
/* MAX_WBITS=15, compression format:
* -15: raw, 15: ZLIB (+6 bytes), 31: GZIP(+18 bytes)
*/
if( deflateInit2( &pZ->z_write, level,
Z_DEFLATED, windowBitsOut, HB_ZSOCK_MEM_LEVEL,
strategy ) == Z_OK )
{
pZ->fCompressOut = HB_TRUE;
pZ->wrbuf = ( HB_BYTE * ) hb_xgrab( HB_ZSOCK_WRBUFSIZE );
pZ->z_write.next_out = ( Bytef * ) pZ->wrbuf;
pZ->z_write.avail_out = HB_ZSOCK_WRBUFSIZE;
}
else
level = HB_ZLIB_COMPRESSION_DISABLE;
}
if( level != HB_ZLIB_COMPRESSION_DISABLE )
{
pSockNew->sd = pSock->sd;
pSockNew->fShutDown = pSock->fShutDown;
pSockNew->iAutoFlush = pSock->iAutoFlush;
pZ->sock = pSock;
hb_socekxParamsInit( pSockNew, pParams );
}
else
{
s_sockexClose( pSockNew, HB_FALSE );
pSockNew = NULL;
}
}
}
return pSockNew;
}
/* hb_socketNewZSock( <pSocket>, [<hParams>] ) -> <pSocket> */
HB_FUNC( HB_SOCKETNEWZSOCK )
{
PHB_SOCKEX pSock = hb_sockexParam( 1 );
if( pSock )
{
pSock = s_sockexNext( pSock, hb_param( 2, HB_IT_HASH ) );
if( pSock )
{
hb_sockexItemClear( hb_param( 1, HB_IT_POINTER ) );
hb_sockexItemPut( hb_param( -1, HB_IT_ANY ), pSock );
}
}
}
HB_CALL_ON_STARTUP_BEGIN( _hb_zsock_init_ )
hb_sockexRegister( &s_sockFilter );
HB_CALL_ON_STARTUP_END( _hb_zsock_init_ )
#if defined( HB_PRAGMA_STARTUP )
#pragma startup _hb_zsock_init_
#elif defined( HB_DATASEG_STARTUP )
#define HB_DATASEG_BODY HB_DATASEG_FUNC( _hb_zsock_init_ )
#include "hbiniseg.h"
#endif