Files
harbour-core/harbour/source/rtl/hbinet.c
Viktor Szakats 3edb418b26 2009-08-01 14:43 UTC+0200 Viktor Szakats (harbour.01 syenar.hu)
* config/global.cf
    + Minor improvements.
    ; NOTE:
      I was experimenting how to return HB_COMPILER
      and HB_ARCHITECTURE values from GNU Make to caller batch/script.
      So far no success.
      Help/ideas would be much appreciated. This would be needed
      to fully switch to GNU Make level arch/comp detection, since
      these values are also needed by make_gnu*.*, mpkg_gnu.* scripts.

  * source/rtl/hbinet.c
    * Renamed iErrorCode to iError.
2009-08-01 12:47:55 +00:00

1341 lines
33 KiB
C

/*
* $Id$
*/
/*
* xHarbour Project source code:
* The internet protocol / TCP support
*
* Copyright 2002 Giancarlo Niccolai [gian@niccolai.ws]
* Ron Pinkas [Ron@RonPinkas.com]
* Marcelo Lombardo [marcelo.lombardo@newage-software.com.br]
* www - http://www.xharbour.org
*
* Copyright 2007 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
* updated and ported to Harbour
* www - http://www.harbour-project.org
*
* Copyright 2008 Miguel Angel marchuet <miguelangel@marchuet.net>
* added dinamic system buffer
* www - http://www.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. 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.
*
*/
#include "hbapi.h"
#include "hbapiitm.h"
#include "hbsocket.h"
#include "hbapierr.h"
#include "hbvm.h"
#include "hbthread.h"
#define HB_INET_ERR_OK 0
#define HB_INET_ERR_TIMEOUT ( -1 )
#define HB_INET_ERR_CLOSEDCONN ( -2 )
#define HB_INET_ERR_BUFFOVERRUN ( -3 )
#define HB_INET_ERR_CLOSEDSOCKET ( -4 )
typedef struct
{
HB_SOCKET sd;
void * remote;
unsigned remotelen;
char * buffer;
long inbuffer;
long posbuffer;
long readahead;
int iError;
int iCount;
int iTimeout;
int iTimeLimit;
PHB_ITEM pPeriodicBlock;
} HB_SOCKET_STRUCT, * PHB_SOCKET_STRUCT;
#define HB_INET_BUFFER_LEN 256
#define HB_INET_INITIALIZE() if( s_initialize ) hb_inetAutoInit()
#define HB_PARSOCKET( n ) ( ( PHB_SOCKET_STRUCT ) hb_parptrGC( hb_inetSocketFinalize, n ) )
#define HB_SOCKET_INIT( s, p ) \
do { \
HB_INET_INITIALIZE(); \
s = ( PHB_SOCKET_STRUCT ) hb_gcAlloc( sizeof( HB_SOCKET_STRUCT ), hb_inetSocketFinalize ); \
memset( s, 0, sizeof( HB_SOCKET_STRUCT ) ); \
s->sd = HB_NO_SOCKET; \
s->readahead = HB_INET_BUFFER_LEN; \
s->iTimeout = -1; \
s->iTimeLimit = -1; \
s->iError = HB_INET_ERR_OK; \
p = hb_itemPutPtrGC( p, s ); \
} while( 0 )
static const char * s_inetCRLF = "\r\n";
static HB_COUNTER s_initialize = 1;
#if defined( HB_OS_LINUX )
/* #define HB_INET_LINUX_INTERRUPT SIGUSR1 + 90 */
# ifdef HB_INET_LINUX_INTERRUPT
# include <signal.h>
static void hb_inetLinuxSigusrHandle( int sig )
{
/* nothing to do */
HB_SYMBOL_UNUSED( sig );
}
# endif
#endif
static void hb_inetErrRT( void )
{
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
static BOOL hb_inetIsOpen( PHB_SOCKET_STRUCT socket )
{
if( socket->sd == HB_NO_SOCKET )
{
socket->iError = HB_INET_ERR_CLOSEDSOCKET;
return FALSE;
}
return TRUE;
}
static int hb_inetCloseSocket( PHB_SOCKET_STRUCT socket )
{
int ret = hb_socketClose( socket->sd );
socket->sd = HB_NO_SOCKET;
socket->inbuffer = 0;
return ret;
}
static HB_GARBAGE_FUNC( hb_inetSocketFinalize )
{
PHB_SOCKET_STRUCT socket = ( PHB_SOCKET_STRUCT ) Cargo;
if( socket->sd != HB_NO_SOCKET )
{
hb_socketShutdown( socket->sd, HB_SOCKET_SHUT_RDWR );
hb_inetCloseSocket( socket );
}
if( socket->pPeriodicBlock )
{
hb_itemRelease( socket->pPeriodicBlock );
socket->pPeriodicBlock = NULL;
}
if( socket->remote )
{
hb_xfree( socket->remote );
socket->remote = NULL;
}
if( socket->buffer )
{
hb_xfree( socket->buffer );
socket->buffer = NULL;
}
}
/*****************************************************
* Socket Initialization
***/
static void hb_inetAutoInit( void )
{
if( s_initialize )
{
if( hb_atomic_dec( &s_initialize ) )
{
hb_socketInit();
#if defined( HB_INET_LINUX_INTERRUPT )
signal( HB_INET_LINUX_INTERRUPT, hb_inetLinuxSigusrHandle );
#endif
}
}
}
HB_FUNC( HB_INETINIT )
{
hb_atomic_set( &s_initialize, 0 );
hb_socketInit();
#if defined( HB_INET_LINUX_INTERRUPT )
signal( HB_INET_LINUX_INTERRUPT, hb_inetLinuxSigusrHandle );
#endif
}
HB_FUNC( HB_INETCLEANUP )
{
hb_socketCleanup();
}
/*****************************************************
* Socket Creation and destruction
***/
HB_FUNC( HB_INETCREATE )
{
PHB_ITEM pSocket = NULL;
PHB_SOCKET_STRUCT socket;
HB_SOCKET_INIT( socket, pSocket );
if( HB_ISNUM( 1 ) )
socket->iTimeout = hb_parni( 1 );
hb_itemReturnRelease( pSocket );
}
HB_FUNC( HB_INETCLOSE )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
{
if( socket->sd != HB_NO_SOCKET )
{
hb_socketShutdown( socket->sd, HB_SOCKET_SHUT_RDWR );
hb_retni( hb_inetCloseSocket( socket ) );
#ifdef HB_INET_LINUX_INTERRUPT
kill( 0, HB_INET_LINUX_INTERRUPT );
#endif
}
else
hb_retni( -1 );
}
else
hb_inetErrRT();
}
HB_FUNC( HB_INETFD )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
{
hb_retnint( socket->sd );
if( hb_parl( 2 ) )
socket->sd = HB_NO_SOCKET;
}
else
hb_inetErrRT();
}
/************************************************
* Socket data access & management
***/
HB_FUNC( HB_INETSTATUS )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
hb_retni( socket->sd == HB_NO_SOCKET ? -1 : 1 ); /* TODO: hb_retni( socket->status ); */
else
hb_inetErrRT();
}
/* Prepared, but still not used; being in wait for comments
HB_FUNC( HB_INETSTATUSDESC )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
{
switch( socket->status )
{
case 0: hb_retc_const( "Connection not opened" ); return;
case 1: hb_retc_const( "Connection alive" ); return;
case 2: hb_retc_const( "Last operation error" ); return;
case 3: hb_retc_const( "Last operation timeout" ); return;
default: hb_retc_const( "unknown" );
}
}
else
hb_inetErrRT();
}
*/
HB_FUNC( HB_INETERRORCODE )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
hb_retni( socket->iError );
else
hb_inetErrRT();
}
HB_FUNC( HB_INETERRORDESC )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
{
switch( socket->iError )
{
case HB_INET_ERR_OK : hb_retc_null(); return;
case HB_INET_ERR_TIMEOUT : hb_retc_const( "Timeout" ); return;
case HB_INET_ERR_CLOSEDCONN : hb_retc_const( "Connection closed" ); return;
case HB_INET_ERR_CLOSEDSOCKET : hb_retc_const( "Closed socket" ); return;
case HB_INET_ERR_BUFFOVERRUN : hb_retc_const( "Buffer overrun" ); return;
default:
hb_retc( hb_socketErrorStr( socket->iError ) );
}
}
else
hb_inetErrRT();
}
HB_FUNC( HB_INETCLEARERROR )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
socket->iError = HB_INET_ERR_OK;
else
hb_inetErrRT();
}
HB_FUNC( HB_INETCOUNT )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
hb_retni( socket->iCount );
else
hb_inetErrRT();
}
HB_FUNC( HB_INETADDRESS )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
{
char * szAddr = socket->remote ?
hb_socketAddrGetName( socket->remote, socket->remotelen ) : NULL;
if( szAddr )
hb_retc_buffer( szAddr );
else
hb_retc_null();
}
else
hb_inetErrRT();
}
HB_FUNC( HB_INETPORT )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
hb_retni( socket->remote ?
hb_socketAddrGetPort( socket->remote, socket->remotelen ) : 0 );
else
hb_inetErrRT();
}
HB_FUNC( HB_INETTIMEOUT )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
{
hb_retni( socket->iTimeout );
if( HB_ISNUM( 2 ) )
socket->iTimeout = hb_parni( 2 );
}
else
hb_inetErrRT();
}
HB_FUNC( HB_INETCLEARTIMEOUT )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
socket->iTimeout = -1;
else
hb_inetErrRT();
}
HB_FUNC( HB_INETTIMELIMIT )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
{
hb_retnl( socket->iTimeLimit );
if( HB_ISNUM( 2 ) )
socket->iTimeLimit = hb_parnl( 2 );
}
else
hb_inetErrRT();
}
HB_FUNC( HB_INETCLEARTIMELIMIT )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
socket->iTimeLimit = -1;
else
hb_inetErrRT();
}
HB_FUNC( HB_INETPERIODCALLBACK )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
{
PHB_ITEM pExec = hb_param( 2, HB_IT_ARRAY | HB_IT_BLOCK | HB_IT_SYMBOL );
if( socket->pPeriodicBlock )
hb_itemReturn( socket->pPeriodicBlock );
if( pExec )
{
if( socket->pPeriodicBlock )
hb_itemRelease( socket->pPeriodicBlock );
socket->pPeriodicBlock = hb_itemClone( pExec );
}
}
else
hb_inetErrRT();
}
HB_FUNC( HB_INETCLEARPERIODCALLBACK )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
{
if( socket->pPeriodicBlock )
{
hb_itemRelease( socket->pPeriodicBlock );
socket->pPeriodicBlock = NULL;
}
}
else
hb_inetErrRT();
}
HB_FUNC( HB_INETGETSNDBUFSIZE )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
{
int iSize = -1;
if( hb_inetIsOpen( socket ) )
{
if( hb_socketGetSndBufSize( socket->sd, &iSize ) != 0 )
iSize = -1;
}
hb_retni( iSize );
}
else
hb_inetErrRT();
}
HB_FUNC( HB_INETGETRCVBUFSIZE )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
{
int iSize = -1;
if( hb_inetIsOpen( socket ) )
{
if( hb_socketGetRcvBufSize( socket->sd, &iSize ) != 0 )
iSize = -1;
}
hb_retni( iSize );
}
else
hb_inetErrRT();
}
HB_FUNC( HB_INETSETSNDBUFSIZE )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
{
int iSize = -1;
if( hb_inetIsOpen( socket ) )
{
iSize = hb_parni( 2 );
hb_socketSetSndBufSize( socket->sd, iSize );
}
hb_retni( iSize );
}
else
hb_inetErrRT();
}
HB_FUNC( HB_INETSETRCVBUFSIZE )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket )
{
int iSize = -1;
if( hb_inetIsOpen( socket ) )
{
iSize = hb_parni( 2 );
hb_socketSetRcvBufSize( socket->sd, iSize );
}
hb_retni( iSize );
}
else
hb_inetErrRT();
}
/********************************************************************
* TCP receive and send functions
***/
static long s_inetRecv( PHB_SOCKET_STRUCT socket, char * buffer, long size, BOOL readahead )
{
long rec = 0;
if( readahead && socket->inbuffer == 0 && socket->readahead > size )
{
if( socket->buffer == NULL )
socket->buffer = ( char * ) hb_xgrab( socket->readahead );
socket->posbuffer = 0;
rec = hb_socketRecv( socket->sd, socket->buffer, socket->readahead,
0, socket->iTimeout );
socket->inbuffer = HB_MAX( 0, rec );
}
else
readahead = FALSE;
if( socket->inbuffer > 0 )
{
rec = HB_MIN( size, socket->inbuffer );
memcpy( buffer, socket->buffer + socket->posbuffer, rec );
socket->posbuffer += rec;
socket->inbuffer -= rec;
if( size > rec && !readahead )
{
size = hb_socketRecv( socket->sd, buffer + rec, size - rec, 0, 0 );
if( size > 0 )
rec += size;
}
}
else if( !readahead )
rec = hb_socketRecv( socket->sd, buffer, size, 0, socket->iTimeout );
return rec;
}
static void s_inetRecvInternal( int iMode )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
PHB_ITEM pBuffer = hb_param( 2, HB_IT_STRING );
char * buffer;
ULONG ulLen;
int iLen, iMaxLen, iReceived;
int iTimeElapsed;
if( socket == NULL || pBuffer == NULL || ! HB_ISBYREF( 2 ) )
hb_inetErrRT();
else if( ! hb_inetIsOpen( socket ) )
hb_retni( -1 );
else
{
if( hb_itemGetWriteCL( pBuffer, &buffer, &ulLen ) )
iLen = ( int ) ulLen;
else
{
iLen = 0;
buffer = NULL;
}
if( HB_ISNUM( 3 ) )
{
iMaxLen = hb_parni( 3 );
if( iMaxLen < 0 )
iMaxLen = 0;
else if( iLen < iMaxLen )
iMaxLen = iLen;
}
else
iMaxLen = iLen;
iReceived = 0;
iTimeElapsed = 0;
socket->iError = HB_INET_ERR_OK;
do
{
iLen = s_inetRecv( socket, buffer + iReceived, iMaxLen - iReceived, FALSE );
if( iLen >= 0 )
{
iReceived += iLen;
if( iMode == 0 ) /* Called from InetRecv()? */
break;
}
else if( iLen == -1 && hb_socketGetError() == HB_SOCKET_ERR_TIMEOUT )
{
/* timed out; let's see if we have to run a cb routine */
iTimeElapsed += socket->iTimeout;
/* if we have a pPeriodicBlock, timeLimit is our REAL timeout */
if( socket->pPeriodicBlock )
{
hb_execFromArray( socket->pPeriodicBlock );
/* do we continue? */
if( hb_parl( -1 ) && hb_vmRequestQuery() == 0 &&
( socket->iTimeLimit == -1 || iTimeElapsed < socket->iTimeLimit ) )
iLen = 1; /* Declare success to continue loop */
}
}
}
while( iReceived < iMaxLen && iLen > 0 );
socket->iCount = iReceived;
if( iLen == 0 )
socket->iError = HB_INET_ERR_CLOSEDCONN;
else if( iLen < 0 )
{
if( hb_socketGetError() == HB_SOCKET_ERR_TIMEOUT )
socket->iError = HB_INET_ERR_TIMEOUT;
else
socket->iError = hb_socketGetError();
}
hb_retni( iReceived > 0 ? iReceived : iLen );
}
}
HB_FUNC( HB_INETRECV )
{
s_inetRecvInternal( 0 );
}
HB_FUNC( HB_INETRECVALL )
{
s_inetRecvInternal( 1 );
}
static void s_inetRecvPattern( const char ** patterns, int * patternsizes,
int iPatternsCount, int iParam )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
PHB_ITEM pResult = hb_param( iParam, HB_IT_BYREF );
PHB_ITEM pMaxSize = hb_param( iParam + 1, HB_IT_NUMERIC );
PHB_ITEM pBufferSize = hb_param( iParam + 2, HB_IT_NUMERIC );
char cChar = '\0';
char * buffer;
int iPaternFound = 0;
int iTimeElapsed = 0;
int iPos = 0;
int iLen;
int iAllocated, iBufferSize, iMax;
int i;
if( socket == NULL )
{
hb_inetErrRT();
return;
}
else if( ! hb_inetIsOpen( socket ) )
{
if( pResult )
hb_itemPutNI( pResult, -1 );
hb_retc_null();
return;
}
iBufferSize = pBufferSize ? hb_itemGetNI( pBufferSize ) : 80;
iMax = pMaxSize ? hb_itemGetNI( pMaxSize ) : 0;
socket->iError = HB_INET_ERR_OK;
buffer = ( char * ) hb_xgrab( iBufferSize );
iAllocated = iBufferSize;
do
{
if( iPos == iAllocated - 1 )
{
iAllocated += iBufferSize;
buffer = ( char * ) hb_xrealloc( buffer, iAllocated );
}
iLen = s_inetRecv( socket, &cChar, 1, TRUE );
if( iLen == -1 && hb_socketGetError() == HB_SOCKET_ERR_TIMEOUT )
{
iLen = -2; /* this signals timeout */
iTimeElapsed += socket->iTimeout;
if( socket->pPeriodicBlock )
{
BOOL fResult;
hb_execFromArray( socket->pPeriodicBlock );
fResult = hb_parl( -1 ) && hb_vmRequestQuery() == 0;
if( fResult &&
( socket->iTimeLimit == -1 || iTimeElapsed < socket->iTimeLimit ) )
iLen = 1;
}
}
else if( iLen > 0 )
{
buffer[ iPos++ ] = cChar;
for( i = 0; i < iPatternsCount; ++i )
{
if( patternsizes[ i ] <= iPos &&
cChar == patterns[ i ][ patternsizes[ i ] - 1 ] )
{
if( memcmp( buffer + iPos - patternsizes[ i ],
patterns[ i ], patternsizes[ i ] ) == 0 )
{
iPaternFound = i + 1;
break;
}
}
}
}
}
while( iLen > 0 && iPaternFound == 0 && ( iMax == 0 || iPos < iMax ) );
if( iPaternFound )
{
socket->iCount = iPos;
if( pResult )
hb_itemPutNI( pResult, iPos );
hb_retclen_buffer( buffer, iPos - patternsizes[ iPaternFound - 1 ] );
}
else
{
if( iLen == 0 )
socket->iError = HB_INET_ERR_CLOSEDCONN;
else if( iLen < 0 )
{
if( hb_socketGetError() == HB_SOCKET_ERR_TIMEOUT )
socket->iError = HB_INET_ERR_TIMEOUT;
else
socket->iError = hb_socketGetError();
}
else
{
socket->iError = HB_INET_ERR_BUFFOVERRUN;
iLen = -1;
}
if( pResult )
hb_itemPutNI( pResult, iLen );
hb_xfree( buffer );
hb_retc_null();
}
}
HB_FUNC( HB_INETRECVLINE )
{
int iEolLen = ( int ) strlen( s_inetCRLF );
s_inetRecvPattern( &s_inetCRLF, &iEolLen, 1, 2 );
}
#define HB_PATERN_BUF_SIZE 16
HB_FUNC( HB_INETRECVENDBLOCK )
{
PHB_ITEM pProto = hb_param( 2, HB_IT_ARRAY | HB_IT_STRING );
const char * patterns_buf[ HB_PATERN_BUF_SIZE ];
const char ** patterns = patterns_buf;
int patternsizes_buf[ HB_PATERN_BUF_SIZE ];
int * patternsizes = patternsizes_buf;
int iPatternsCount = 0;
int iLen;
if( pProto && HB_IS_ARRAY( pProto ) )
{
int iPatternsMax = ( int ) hb_arrayLen( pProto ), i;
for( i = 1; i <= iPatternsMax; i++ )
{
iLen = ( int ) hb_arrayGetCLen( pProto, i );
if( iLen > 0 )
++iPatternsCount;
}
if( iPatternsCount > 0 )
{
if( iPatternsCount > HB_PATERN_BUF_SIZE )
{
patterns = ( const char ** ) hb_xgrab( sizeof( char * ) * iPatternsCount );
patternsizes = ( int * ) hb_xgrab( sizeof( int ) * iPatternsCount );
}
iPatternsCount = 0;
for( i = 1; i <= iPatternsMax; i++ )
{
iLen = ( int ) hb_arrayGetCLen( pProto, i );
if( iLen > 0 )
{
patterns[ iPatternsCount ] = hb_arrayGetCPtr( pProto, i );
patternsizes[ iPatternsCount ] = iLen;
++iPatternsCount;
}
}
}
}
if( iPatternsCount == 0 )
{
iLen = ( int ) hb_itemGetCLen( pProto );
if( iLen > 0 )
{
patterns[ 0 ] = hb_itemGetCPtr( pProto );
patternsizes[ 0 ] = iLen;
}
else
{
patterns[ 0 ] = s_inetCRLF;
patternsizes[ 0 ] = strlen( s_inetCRLF );
}
iPatternsCount = 1;
}
s_inetRecvPattern( patterns, patternsizes, iPatternsCount, 3 );
if( iPatternsCount > HB_PATERN_BUF_SIZE )
{
hb_xfree( patterns );
hb_xfree( patternsizes );
}
}
HB_FUNC( HB_INETDATAREADY )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
int iVal;
if( socket == NULL || ( hb_pcount() >= 2 && ! HB_ISNUM( 2 ) ) )
hb_inetErrRT();
else if( ! hb_inetIsOpen( socket ) )
hb_retni( -1 );
else
{
socket->iError = HB_INET_ERR_OK;
if( socket->inbuffer > 0 )
iVal = 1;
else
{
iVal = hb_socketSelectRead( socket->sd, HB_ISNUM( 2 ) ? hb_parnint( 2 ) : 0 );
if( iVal < 0 )
socket->iError = hb_socketGetError();
}
hb_retni( iVal );
}
}
static void s_inetSendInternal( BOOL lAll )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
PHB_ITEM pBuffer = hb_param( 2, HB_IT_STRING );
const char * buffer;
int iLen, iSent, iSend;
if( socket == NULL || pBuffer == NULL )
hb_inetErrRT();
else if( ! hb_inetIsOpen( socket ) )
hb_retni( -1 );
else
{
buffer = hb_itemGetCPtr( pBuffer );
iSend = ( int ) hb_itemGetCLen( pBuffer );
if( HB_ISNUM( 3 ) )
{
iLen = hb_parni( 3 );
if( iLen < iSend )
iSend = iLen;
}
socket->iError = HB_INET_ERR_OK;
iSent = iLen = 0;
while( iSent < iSend )
{
iLen = hb_socketSend( socket->sd, buffer + iSent, iSend - iSent, 0,
socket->iTimeout );
if( iLen > 0 )
{
iSent += iLen;
if( ! lAll )
break;
}
else
{
if( iLen == -1 && hb_socketGetError() == HB_SOCKET_ERR_TIMEOUT )
socket->iError = HB_INET_ERR_TIMEOUT;
else
socket->iError = hb_socketGetError();
break;
}
}
socket->iCount = iSent;
hb_retni( iSent > 0 ? iSent : iLen );
}
}
HB_FUNC( HB_INETSEND )
{
s_inetSendInternal( FALSE );
}
HB_FUNC( HB_INETSENDALL )
{
s_inetSendInternal( TRUE );
}
/*******************************************
* Name resolution interface functions
***/
HB_FUNC( HB_INETGETHOSTS )
{
const char * szHost = hb_parc( 1 );
if( szHost )
{
PHB_ITEM pHosts;
HB_INET_INITIALIZE();
pHosts = hb_socketGetHosts( szHost, HB_SOCKET_PF_INET );
if( pHosts )
hb_itemReturnRelease( pHosts );
else
hb_reta( 0 );
}
else
hb_inetErrRT();
}
HB_FUNC( HB_INETGETALIAS )
{
const char * szHost = hb_parc( 1 );
if( szHost )
{
PHB_ITEM pHosts;
HB_INET_INITIALIZE();
pHosts = hb_socketGetAliases( szHost, HB_SOCKET_PF_INET );
if( pHosts )
hb_itemReturnRelease( pHosts );
else
hb_reta( 0 );
}
else
hb_inetErrRT();
}
/**********************************************
* Server Specific functions
****/
HB_FUNC( HB_INETSERVER )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 2 );
PHB_ITEM pSocket = NULL;
if( ! HB_ISNUM( 1 ) || ( socket == NULL && ! HB_ISNIL( 2 ) ) )
{
hb_inetErrRT();
return;
}
if( !socket )
HB_SOCKET_INIT( socket, pSocket );
else if( socket->sd != HB_NO_SOCKET )
hb_inetCloseSocket( socket );
socket->sd = hb_socketOpen( HB_SOCKET_PF_INET, HB_SOCKET_PT_STREAM, 0 );
if( socket->sd == HB_NO_SOCKET )
socket->iError = hb_socketGetError();
else
{
int iPort = hb_parni( 1 );
const char * szAddress = hb_parc( 2 );
int iListen = hb_parnidef( 3, 10 );
if( socket->remote )
hb_xfree( socket->remote );
if( !hb_socketInetAddr( &socket->remote, &socket->remotelen, szAddress, iPort ) ||
hb_socketBind( socket->sd, socket->remote, socket->remotelen ) != 0 ||
hb_socketListen( socket->sd, iListen ) != 0 )
{
socket->iError = hb_socketGetError();
hb_inetCloseSocket( socket );
}
else
socket->iError = HB_INET_ERR_OK;
}
if( pSocket )
hb_itemReturnRelease( pSocket );
else
hb_itemReturn( hb_param( 2, HB_IT_ANY ) );
}
HB_FUNC( HB_INETACCEPT )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
if( socket == NULL )
hb_inetErrRT();
else if( hb_inetIsOpen( socket ) )
{
void * sa;
unsigned len;
HB_SOCKET incoming = hb_socketAccept( socket->sd, &sa, &len, socket->iTimeout );
if( incoming == HB_NO_SOCKET )
{
if( hb_socketGetError() == HB_SOCKET_ERR_TIMEOUT )
socket->iError = HB_INET_ERR_TIMEOUT;
else
socket->iError = hb_socketGetError();
}
else
{
PHB_SOCKET_STRUCT new_socket;
PHB_ITEM pSocket = NULL;
HB_SOCKET_INIT( new_socket, pSocket );
new_socket->remote = sa;
new_socket->remotelen = len;
new_socket->sd = incoming;
hb_itemReturnRelease( pSocket );
socket->iError = HB_INET_ERR_OK;
}
}
}
/**********************************************
* Client specific (connection functions)
****/
static void hb_inetConnectInternal( BOOL fResolve )
{
const char * szHost = hb_parc( 1 );
char * szAddr = NULL;
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 3 );
PHB_ITEM pSocket = NULL;
int iPort = hb_parni( 2 );
if( szHost == NULL || iPort == 0 || ( socket == NULL && ! HB_ISNIL( 3 ) ) )
hb_inetErrRT();
else
{
if( !socket )
HB_SOCKET_INIT( socket, pSocket );
else if( socket->sd != HB_NO_SOCKET )
hb_inetCloseSocket( socket );
if( fResolve )
szHost = szAddr = hb_socketResolveAddr( szHost, HB_SOCKET_AF_INET );
if( fResolve && !szAddr )
socket->iError = hb_socketGetError();
else
{
/* Creates comm socket */
socket->sd = hb_socketOpen( HB_SOCKET_PF_INET, HB_SOCKET_PT_STREAM, 0 );
if( socket->sd == HB_NO_SOCKET )
socket->iError = hb_socketGetError();
else
{
if( socket->remote )
hb_xfree( socket->remote );
if( hb_socketInetAddr( &socket->remote, &socket->remotelen,
szHost, iPort ) )
{
hb_socketSetKeepAlive( socket->sd, TRUE );
if( hb_socketConnect( socket->sd, socket->remote, socket->remotelen,
socket->iTimeout ) != 0 )
socket->iError = hb_socketGetError();
else
socket->iError = HB_INET_ERR_OK;
}
else
socket->iError = hb_socketGetError();
}
if( szAddr )
hb_xfree( szAddr );
}
if( pSocket )
hb_itemReturnRelease( pSocket );
else
hb_itemReturn( hb_param( 3, HB_IT_ANY ) );
}
}
HB_FUNC( HB_INETCONNECT )
{
hb_inetConnectInternal( TRUE );
}
HB_FUNC( HB_INETCONNECTIP )
{
hb_inetConnectInternal( FALSE );
}
/***********************************************************
* Datagram functions
************************************************************/
HB_FUNC( HB_INETDGRAMBIND )
{
PHB_SOCKET_STRUCT socket;
PHB_ITEM pSocket = NULL;
int iPort = hb_parni( 1 );
const char * szAddress;
/* Parameter error checking */
if( iPort == 0 || ( hb_pcount() >= 4 && ! HB_ISCHAR( 4 ) ) )
{
hb_inetErrRT();
return;
}
HB_SOCKET_INIT( socket, pSocket );
/* Creates comm socket */
socket->sd = hb_socketOpen( HB_SOCKET_PF_INET, HB_SOCKET_PT_DGRAM, HB_SOCKET_IPPROTO_UDP );
if( socket->sd == HB_NO_SOCKET )
{
socket->iError = hb_socketGetError();
hb_itemReturnRelease( pSocket );
return;
}
/* Setting broadcast if needed. */
if( hb_parl( 3 ) )
hb_socketSetBroadcast( socket->sd, TRUE );
szAddress = hb_parc( 2 );
if( socket->remote )
hb_xfree( socket->remote );
if( !hb_socketInetAddr( &socket->remote, &socket->remotelen,
szAddress, iPort ) ||
hb_socketBind( socket->sd, socket->remote, socket->remotelen ) != 0 )
{
socket->iError = hb_socketGetError();
hb_inetCloseSocket( socket );
}
else if( hb_pcount() >= 4 )
{
if( hb_socketSetMulticast( socket->sd, HB_SOCKET_PF_INET, hb_parc( 4 ) ) != 0 )
socket->iError = hb_socketGetError();
}
hb_itemReturnRelease( pSocket );
}
HB_FUNC( HB_INETDGRAM )
{
PHB_SOCKET_STRUCT socket;
PHB_ITEM pSocket = NULL;
HB_SOCKET_INIT( socket, pSocket );
/* Creates comm socket */
socket->sd = hb_socketOpen( HB_SOCKET_PF_INET, HB_SOCKET_PT_DGRAM, HB_SOCKET_IPPROTO_UDP );
if( socket->sd == HB_NO_SOCKET )
{
socket->iError = hb_socketGetError();
hb_itemReturnRelease( pSocket );
return;
}
/* Setting broadcast if needed. */
if( hb_parl( 1 ) )
hb_socketSetBroadcast( socket->sd, TRUE );
hb_itemReturnRelease( pSocket );
}
HB_FUNC( HB_INETDGRAMSEND )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
const char * szAddress = hb_parc( 2 );
int iPort = hb_parni( 3 );
PHB_ITEM pBuffer = hb_param( 4, HB_IT_STRING );
int iLen;
const char * szBuffer;
if( socket == NULL || szAddress == NULL || iPort == 0 || pBuffer == NULL )
hb_inetErrRT();
else if( ! hb_inetIsOpen( socket ) )
{
socket->iCount = 0;
hb_retni( -1 );
}
else
{
socket->iCount = 0;
if( socket->remote )
hb_xfree( socket->remote );
if( !hb_socketInetAddr( &socket->remote, &socket->remotelen, szAddress, iPort ) )
{
socket->iError = hb_socketGetError();
iLen = -1;
}
else
{
szBuffer = hb_itemGetCPtr( pBuffer );
iLen = ( int ) hb_itemGetCLen( pBuffer );
if( HB_ISNUM( 5 ) )
{
int iMaxLen = hb_parni( 5 );
if( iMaxLen < iLen )
iLen = HB_MAX( iMaxLen, 0 );
}
iLen = hb_socketSendTo( socket->sd, szBuffer, iLen, 0,
socket->remote, socket->remotelen,
socket->iTimeout );
if( iLen == -1 )
{
if( hb_socketGetError() == HB_SOCKET_ERR_TIMEOUT )
socket->iError = HB_INET_ERR_TIMEOUT;
else
socket->iError = hb_socketGetError();
}
else
{
socket->iError = HB_INET_ERR_OK;
socket->iCount = iLen;
}
}
hb_retni( iLen );
}
}
HB_FUNC( HB_INETDGRAMRECV )
{
PHB_SOCKET_STRUCT socket = HB_PARSOCKET( 1 );
PHB_ITEM pBuffer = hb_param( 2, HB_IT_STRING );
int iTimeElapsed = 0;
int iLen = 0, iMax;
char * buffer = NULL;
ULONG ulLen;
BOOL fRepeat;
if( socket == NULL || pBuffer == NULL || ! HB_ISBYREF( 2 ) )
hb_inetErrRT();
else if( ! hb_inetIsOpen( socket ) )
{
socket->iCount = 0;
hb_retni( -1 );
}
else
{
socket->iCount = 0;
if( hb_itemGetWriteCL( pBuffer, &buffer, &ulLen ) )
iLen = ( int ) ulLen;
if( HB_ISNUM( 3 ) )
{
iMax = hb_parni( 3 );
if( iMax < iLen )
iLen = HB_MAX( iMax, 0 );
}
do
{
fRepeat = FALSE;
if( socket->remote )
hb_xfree( socket->remote );
iMax = hb_socketRecvFrom( socket->sd, buffer, iLen, 0,
&socket->remote, &socket->remotelen,
socket->iTimeout );
iTimeElapsed += socket->iTimeout;
if( socket->pPeriodicBlock )
{
hb_execFromArray( socket->pPeriodicBlock );
/* do we continue? */
fRepeat = hb_parl( -1 ) && hb_vmRequestQuery() == 0 &&
( socket->iTimeLimit == -1 || iTimeElapsed < socket->iTimeLimit );
}
}
while( fRepeat );
if( iMax == 0 )
socket->iError = HB_INET_ERR_CLOSEDCONN;
else if( iMax < 0 )
{
if( hb_socketGetError() == HB_SOCKET_ERR_TIMEOUT )
socket->iError = HB_INET_ERR_TIMEOUT;
else
socket->iError = hb_socketGetError();
}
else
socket->iError = HB_INET_ERR_OK;
hb_retni( iMax );
}
}
/***********************************************************
* Generic utility(?) functions
************************************************************/
HB_FUNC( HB_INETCRLF )
{
hb_retc_const( s_inetCRLF );
}
HB_FUNC( HB_INETISSOCKET )
{
hb_retl( HB_PARSOCKET( 1 ) != NULL );
}