1346 lines
33 KiB
C
1346 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 )
|
|
{
|
|
int ret;
|
|
hb_atomic_set( &s_initialize, 0 );
|
|
ret = hb_socketInit();
|
|
if( ret == 0 )
|
|
{
|
|
#if defined( HB_INET_LINUX_INTERRUPT )
|
|
signal( HB_INET_LINUX_INTERRUPT, hb_inetLinuxSigusrHandle );
|
|
#endif
|
|
}
|
|
hb_retl( ret == 0 );
|
|
}
|
|
|
|
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 );
|
|
}
|