2010-06-08 21:54 UTC+0300 Mindaugas Kavaliauskas (dbtopas/at/dbtopas.lt)
+ harbour/src/rtl/hbsockhb.c
+ added wrapper functions for Harbour socket API
The list of exported functions is:
HB_SOCKETGETERROR() --> nSocketError
HB_SOCKETGETOSERROR() --> nOSError
HB_SOCKETERRORSTRING( [ nSocketErrror = hb_socketGetError() ] ) --> cError
HB_SOCKETGETSOCKNAME( hSocket ) --> aAddr | NIL
HB_SOCKETGETPEERNAME( hSocket ) --> aAddr | NIL
HB_SOCKETOPEN( [ nDomain = HB_SOCKET_PF_INET ] , [ nType = HB_SOCKET_PT_STREAM ], [ nProtocol = 0 ] ) --> hSocket
HB_SOCKETCLOSE( hSocket ) --> nSuccess
HB_SOCKETSHUTDOWN( hSocket, [ nMode = HB_SOCKET_SHUT_RDWR ] ) --> nSuccess
HB_SOCKETBIND( hSocket, aAddr ) --> nSuccess
HB_SOCKETLISTEN( hSocket, [ iQueueLen = 10 ] ) --> nSuccess
HB_SOCKETACCEPT( hSocket, [ @aAddr ], [ nTimeout = FOREVER ] ) --> nSuccess
HB_SOCKETCONNECT( hSocket, aAddr, [ nTimeout = FOREVER ] ) --> nSuccess
HB_SOCKETSEND( hSocket, cBuffer, [ nLen = LEN( cBuffer ) ], [ nFlags = 0 ], [ nTimeout = FOREVER ] ) --> nBytesSent
HB_SOCKETSENDTO( hSocket, cBuffer, [ nLen = LEN( cBuffer ) ], [ nFlags = 0 ], aAddr, [ nTimeout = FOREVER ] ) --> nBytesSent
HB_SOCKETRECV( hSocket, @cBuffer, [ nLen = LEN( cBuffer ) ], [ nFlags = 0 ], [ nTimeout = FOREVER ] ) --> nBytesRecv
HB_SOCKETRECVFROM( hSocket, @cBuffer, [ nLen = LEN( cBuffer ) ], [ nFlags = 0 ], @aAddr, [ nTimeout = FOREVER ] ) --> nBytesRecv
HB_SOCKETSETBLOCKINGIO( hSocket, lValue ) --> nSuccess
HB_SOCKETSETNODELAY( hSocket, lValue ) --> nSuccess
HB_SOCKETSETREUSEADDR( hSocket, lValue ) --> nSuccess
HB_SOCKETSETKEEPALIVE( hSocket, lValue ) --> nSuccess
HB_SOCKETSETBROADCAST( hSocket, lValue ) --> nSuccess
HB_SOCKETSETSNDBUFSIZE( hSocket, nValue ) --> nSuccess
HB_SOCKETSETRCVBUFSIZE( hSocket, nValue ) --> nSuccess
HB_SOCKETGETSNDBUFSIZE( hSocket, @nValue ) --> nSuccess
HB_SOCKETGETRCVBUFSIZE( hSocket, @nValue ) --> nSuccess
HB_SOCKETSETMULTICAST( hSocket, cAddr ) --> nSuccess
HB_SOCKETSELECTREAD( hSocket, [ nTimeout = FOREVER ] ) --> nRet
HB_SOCKETSELECTWRITE( hSocket, [ nTimeout = FOREVER ] ) --> nRet
HB_SOCKETSELECTWRITEEX( hSocket, [ nTimeout = FOREVER ] ) --> nRet
HB_SOCKETSELECT( aRead, lSetRead, aWrite, lSetWrite, aExcep, lSetExcep, [ nTimeout = FOREVER ] ) --> nRet
HB_SOCKETRESOLVEINETADDR( cAddr, nPort ) --> aAddr | NIL
HB_SOCKETRESOLVEADDR( cAddr, [ nFamily = HB_SOCKET_AF_INET ] ) --> cResolved
HB_SOCKETGETHOSTS( cAddr, [ nFamily = HB_SOCKET_AF_INET ] ) --> aHosts
HB_SOCKETGETIFACES( [ nFamily ], [ lNoAliases ] ) --> aIfaces
+ harbour/examples/udpds
+ harbour/examples/udpds/udpds.prg
+ added UDP Discovery Server sample
This module demonstrates a simple UDP Discovery Server
If you run some service on the network (ex., netio), you need to
know server IP address and configure client to connect to this
address. UDPDS helps client to find server address (or addresses
of multiple servers) on local network. UDPDS should be run in
parallel to real server (ex., netio). Server part of UDPDS uses
threads, so, it should be compiled in MT mode.
Server functions:
UDPDS_Start( nPort, cName [, cVersion ] ) --> hServer
UDPDS_Stop( hServer )
Client function:
UDPDS_Find( nPort, cName ) --> { {"ip_addr_1", "version_1"}, ... }
; Please add .hbc, .hbp files, if it is required. This module requires
only a standard harbour runtime library and MT VM.
This commit is contained in:
@@ -16,6 +16,68 @@
|
||||
The license applies to all entries newer than 2009-04-28.
|
||||
*/
|
||||
|
||||
2010-06-08 21:54 UTC+0300 Mindaugas Kavaliauskas (dbtopas/at/dbtopas.lt)
|
||||
+ harbour/src/rtl/hbsockhb.c
|
||||
+ added wrapper functions for Harbour socket API
|
||||
The list of exported functions is:
|
||||
HB_SOCKETGETERROR() --> nSocketError
|
||||
HB_SOCKETGETOSERROR() --> nOSError
|
||||
HB_SOCKETERRORSTRING( [ nSocketErrror = hb_socketGetError() ] ) --> cError
|
||||
HB_SOCKETGETSOCKNAME( hSocket ) --> aAddr | NIL
|
||||
HB_SOCKETGETPEERNAME( hSocket ) --> aAddr | NIL
|
||||
HB_SOCKETOPEN( [ nDomain = HB_SOCKET_PF_INET ] , [ nType = HB_SOCKET_PT_STREAM ], [ nProtocol = 0 ] ) --> hSocket
|
||||
HB_SOCKETCLOSE( hSocket ) --> nSuccess
|
||||
HB_SOCKETSHUTDOWN( hSocket, [ nMode = HB_SOCKET_SHUT_RDWR ] ) --> nSuccess
|
||||
HB_SOCKETBIND( hSocket, aAddr ) --> nSuccess
|
||||
HB_SOCKETLISTEN( hSocket, [ iQueueLen = 10 ] ) --> nSuccess
|
||||
HB_SOCKETACCEPT( hSocket, [ @aAddr ], [ nTimeout = FOREVER ] ) --> nSuccess
|
||||
HB_SOCKETCONNECT( hSocket, aAddr, [ nTimeout = FOREVER ] ) --> nSuccess
|
||||
HB_SOCKETSEND( hSocket, cBuffer, [ nLen = LEN( cBuffer ) ], [ nFlags = 0 ], [ nTimeout = FOREVER ] ) --> nBytesSent
|
||||
HB_SOCKETSENDTO( hSocket, cBuffer, [ nLen = LEN( cBuffer ) ], [ nFlags = 0 ], aAddr, [ nTimeout = FOREVER ] ) --> nBytesSent
|
||||
HB_SOCKETRECV( hSocket, @cBuffer, [ nLen = LEN( cBuffer ) ], [ nFlags = 0 ], [ nTimeout = FOREVER ] ) --> nBytesRecv
|
||||
HB_SOCKETRECVFROM( hSocket, @cBuffer, [ nLen = LEN( cBuffer ) ], [ nFlags = 0 ], @aAddr, [ nTimeout = FOREVER ] ) --> nBytesRecv
|
||||
HB_SOCKETSETBLOCKINGIO( hSocket, lValue ) --> nSuccess
|
||||
HB_SOCKETSETNODELAY( hSocket, lValue ) --> nSuccess
|
||||
HB_SOCKETSETREUSEADDR( hSocket, lValue ) --> nSuccess
|
||||
HB_SOCKETSETKEEPALIVE( hSocket, lValue ) --> nSuccess
|
||||
HB_SOCKETSETBROADCAST( hSocket, lValue ) --> nSuccess
|
||||
HB_SOCKETSETSNDBUFSIZE( hSocket, nValue ) --> nSuccess
|
||||
HB_SOCKETSETRCVBUFSIZE( hSocket, nValue ) --> nSuccess
|
||||
HB_SOCKETGETSNDBUFSIZE( hSocket, @nValue ) --> nSuccess
|
||||
HB_SOCKETGETRCVBUFSIZE( hSocket, @nValue ) --> nSuccess
|
||||
HB_SOCKETSETMULTICAST( hSocket, cAddr ) --> nSuccess
|
||||
HB_SOCKETSELECTREAD( hSocket, [ nTimeout = FOREVER ] ) --> nRet
|
||||
HB_SOCKETSELECTWRITE( hSocket, [ nTimeout = FOREVER ] ) --> nRet
|
||||
HB_SOCKETSELECTWRITEEX( hSocket, [ nTimeout = FOREVER ] ) --> nRet
|
||||
HB_SOCKETSELECT( aRead, lSetRead, aWrite, lSetWrite, aExcep, lSetExcep, [ nTimeout = FOREVER ] ) --> nRet
|
||||
HB_SOCKETRESOLVEINETADDR( cAddr, nPort ) --> aAddr | NIL
|
||||
HB_SOCKETRESOLVEADDR( cAddr, [ nFamily = HB_SOCKET_AF_INET ] ) --> cResolved
|
||||
HB_SOCKETGETHOSTS( cAddr, [ nFamily = HB_SOCKET_AF_INET ] ) --> aHosts
|
||||
HB_SOCKETGETIFACES( [ nFamily ], [ lNoAliases ] ) --> aIfaces
|
||||
|
||||
+ harbour/examples/udpds
|
||||
+ harbour/examples/udpds/udpds.prg
|
||||
+ added UDP Discovery Server sample
|
||||
|
||||
This module demonstrates a simple UDP Discovery Server
|
||||
|
||||
If you run some service on the network (ex., netio), you need to
|
||||
know server IP address and configure client to connect to this
|
||||
address. UDPDS helps client to find server address (or addresses
|
||||
of multiple servers) on local network. UDPDS should be run in
|
||||
parallel to real server (ex., netio). Server part of UDPDS uses
|
||||
threads, so, it should be compiled in MT mode.
|
||||
|
||||
Server functions:
|
||||
UDPDS_Start( nPort, cName [, cVersion ] ) --> hServer
|
||||
UDPDS_Stop( hServer )
|
||||
|
||||
Client function:
|
||||
UDPDS_Find( nPort, cName ) --> { {"ip_addr_1", "version_1"}, ... }
|
||||
|
||||
; Please add .hbc, .hbp files, if it is required. This module requires
|
||||
only a standard harbour runtime library and MT VM.
|
||||
|
||||
2010-06-08 20:28 UTC+0200 Viktor Szakats (harbour.01 syenar.hu)
|
||||
* src/rtl/hbregexc.c
|
||||
+ Restored RTE which is thrown when unsupported regex string is
|
||||
@@ -64794,7 +64856,7 @@
|
||||
* harbour/contrib/gtwvg/wvgsink.c
|
||||
* harbour/contrib/gtwvg/wvgax.c
|
||||
! Fixes to newer OLE implementation.
|
||||
Thanks to Mindaugus and Przemek for doing all the spadework.
|
||||
Thanks to Mindaugas and Przemek for doing all the spadework.
|
||||
Now I can receive events as was doing before, fantastic.
|
||||
|
||||
2009-05-18 21:36 UTC+0200 Viktor Szakats (harbour.01 syenar.hu)
|
||||
@@ -82902,7 +82964,7 @@
|
||||
* harbour/contrib/gtwvg/wvgsysw.prg
|
||||
* harbour/contrib/gtwvg/wvgwnd.prg
|
||||
! Fixed to respect new compiler warnings.
|
||||
Thanks Mindaugus for this great addition.
|
||||
Thanks Mindaugas for this great addition.
|
||||
Hope code will be faster than before.
|
||||
|
||||
2008-12-20 18:35 UTC+0100 Francesco Saverio Giudice (info/at/fsgiudice.com)
|
||||
|
||||
125
harbour/examples/udpds/udpds.prg
Normal file
125
harbour/examples/udpds/udpds.prg
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* This module demonstrates a simple UDP Discovery Server
|
||||
*
|
||||
* If you run some service on the network (ex., netio) you need to
|
||||
* know server IP address and configure client to connect to this
|
||||
* address. UDPDS helps client to find server address (or addresses
|
||||
* of multiple servers) on local network. UDPDS should be run in
|
||||
* parallel to real server (ex., netio). Server part of UDPDS uses
|
||||
* threads, so, it should be compiled in MT mode.
|
||||
*
|
||||
* Server functions:
|
||||
* UDPDS_Start( nPort, cName [, cVersion ] ) --> hServer
|
||||
* UDPDS_Stop( hServer )
|
||||
*
|
||||
* Client function:
|
||||
* UDPDS_Find( nPort, cName ) --> { {"ip_addr_1", "version_1"}, ... }
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hbsocket.ch"
|
||||
|
||||
/* Test application */
|
||||
|
||||
PROC main( cParam )
|
||||
LOCAL h
|
||||
|
||||
IF ! HB_MTVM()
|
||||
? "This sample should be compiled using MultiThread"
|
||||
RETURN
|
||||
ENDIF
|
||||
|
||||
IF cParam == NIL
|
||||
? "udpds {c|s|cs}"
|
||||
? "Parameter:"
|
||||
? " s - run as a server"
|
||||
? " c - run as a client"
|
||||
RETURN
|
||||
ENDIF
|
||||
|
||||
IF "S" $ UPPER( cParam )
|
||||
IF ! EMPTY( h := UDPDS_Start( 39999, "UDPDSDemo", NETNAME() + " " + HB_TSTOSTR(HB_DATETIME() ) ) )
|
||||
hb_idleSleep( 0.1 )
|
||||
ENDIF
|
||||
ENDIF
|
||||
|
||||
IF "C" $ UPPER( cParam )
|
||||
? HB_VALTOEXP( UDPDS_Find( 39999, "UDPDSDemo" ) )
|
||||
ENDIF
|
||||
|
||||
IF "S" $ UPPER( cParam )
|
||||
? "Press any key to stop server"
|
||||
INKEY(0)
|
||||
UDPDS_Stop( h )
|
||||
ENDIF
|
||||
RETURN
|
||||
|
||||
|
||||
/* Client */
|
||||
|
||||
FUNC UDPDS_Find( nPort, cName )
|
||||
LOCAL hSocket, aRet, nEnd, nTime, cBuffer, nLen, aAddr
|
||||
|
||||
IF ! EMPTY( hSocket := hb_socketOpen( , HB_SOCKET_PT_DGRAM ) )
|
||||
hb_socketSetBroadcast( hSocket, .T. )
|
||||
IF hb_socketSendTo( hSocket, CHR( 5 ) + cName + CHR( 0 ),,, { HB_SOCKET_AF_INET, "255.255.255.255", nPort } ) == LEN( cName ) + 2
|
||||
nTime := hb_milliseconds()
|
||||
nEnd := nTime + 100 /* 100ms delay is enough on LAN */
|
||||
aRet := {}
|
||||
DO WHILE nEnd > nTime
|
||||
cBuffer := SPACE( 2000 )
|
||||
nLen := hb_socketRecvFrom( hSocket, @cBuffer,,, @aAddr, nEnd - nTime )
|
||||
IF LEFT( cBuffer, LEN( cName ) + 2 ) == CHR( 6 ) + cName + CHR( 0 )
|
||||
AADD( aRet, { aAddr[ 2 ], SUBSTR( cBuffer, LEN( cName ) + 3, nLen - LEN( cName ) - 2 ) } )
|
||||
ENDIF
|
||||
nTime := hb_milliseconds()
|
||||
ENDDO
|
||||
ENDIF
|
||||
hb_socketClose( hSocket )
|
||||
ENDIF
|
||||
RETURN aRet
|
||||
|
||||
|
||||
/* Server */
|
||||
|
||||
FUNC UDPDS_Start( nPort, cName, cVersion )
|
||||
LOCAL hSocket
|
||||
IF ! EMPTY( hSocket := hb_socketOpen( , HB_SOCKET_PT_DGRAM ) )
|
||||
IF hb_socketBind( hSocket, { HB_SOCKET_AF_INET, "0.0.0.0", nPort } ) == 0
|
||||
hb_threadDetach( hb_threadStart( @UDPDS(), hSocket, cName, cVersion ) )
|
||||
RETURN hSocket
|
||||
ENDIF
|
||||
hb_socketClose( hSocket )
|
||||
ENDIF
|
||||
RETURN NIL
|
||||
|
||||
|
||||
PROC UDPDS_Stop( hSocket )
|
||||
hb_socketClose( hSocket )
|
||||
RETURN
|
||||
|
||||
|
||||
STATIC PROC UDPDS( hSocket, cName, cVersion )
|
||||
LOCAL cBuffer, nLen, aAddr
|
||||
DO WHILE .T.
|
||||
cBuffer := SPACE( 2000 )
|
||||
nLen := hb_socketRecvFrom( hSocket, @cBuffer,,, @aAddr )
|
||||
IF nLen == -1
|
||||
RETURN
|
||||
ELSE
|
||||
/*
|
||||
* Communication protocol:
|
||||
* Broadcast request: ENQ, ServerName, NUL
|
||||
* Server response: ACK, ServerName, NUL, Version
|
||||
*/
|
||||
IF LEFT( cBuffer, nLen ) == CHR( 5 ) + cName + CHR( 0 )
|
||||
hb_socketSendTo( hSocket, CHR( 6 ) + cName + CHR( 0 ) + IIF( cVersion == NIL, "", cVersion ),,, aAddr )
|
||||
ENDIF
|
||||
ENDIF
|
||||
ENDDO
|
||||
RETURN
|
||||
|
||||
@@ -96,6 +96,7 @@ C_SOURCES := \
|
||||
hbsha2.c \
|
||||
hbsha2hm.c \
|
||||
hbsocket.c \
|
||||
hbsockhb.c \
|
||||
hbstrfmt.c \
|
||||
hbstrsh.c \
|
||||
hbtoken.c \
|
||||
|
||||
672
harbour/src/rtl/hbsockhb.c
Normal file
672
harbour/src/rtl/hbsockhb.c
Normal file
@@ -0,0 +1,672 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Harbour Project source code:
|
||||
* Socket API wrapper functions
|
||||
*
|
||||
* Copyright 2010 Mindaugas Kavaliauskas <dbtopas / at / dbtopas.lt>
|
||||
* 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. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* HB_SOCKETGETERROR() --> nSocketError
|
||||
* HB_SOCKETGETOSERROR() --> nOSError
|
||||
* HB_SOCKETERRORSTRING( [ nSocketErrror = hb_socketGetError() ] ) --> cError
|
||||
* HB_SOCKETGETSOCKNAME( hSocket ) --> aAddr | NIL
|
||||
* HB_SOCKETGETPEERNAME( hSocket ) --> aAddr | NIL
|
||||
* HB_SOCKETOPEN( [ nDomain = HB_SOCKET_PF_INET ] , [ nType = HB_SOCKET_PT_STREAM ], [ nProtocol = 0 ] ) --> hSocket
|
||||
* HB_SOCKETCLOSE( hSocket ) --> nSuccess
|
||||
* HB_SOCKETSHUTDOWN( hSocket, [ nMode = HB_SOCKET_SHUT_RDWR ] ) --> nSuccess
|
||||
* HB_SOCKETBIND( hSocket, aAddr ) --> nSuccess
|
||||
* HB_SOCKETLISTEN( hSocket, [ iQueueLen = 10 ] ) --> nSuccess
|
||||
* HB_SOCKETACCEPT( hSocket, [ @aAddr ], [ nTimeout = FOREVER ] ) --> nSuccess
|
||||
* HB_SOCKETCONNECT( hSocket, aAddr, [ nTimeout = FOREVER ] ) --> nSuccess
|
||||
* HB_SOCKETSEND( hSocket, cBuffer, [ nLen = LEN( cBuffer ) ], [ nFlags = 0 ], [ nTimeout = FOREVER ] ) --> nBytesSent
|
||||
* HB_SOCKETSENDTO( hSocket, cBuffer, [ nLen = LEN( cBuffer ) ], [ nFlags = 0 ], aAddr, [ nTimeout = FOREVER ] ) --> nBytesSent
|
||||
* HB_SOCKETRECV( hSocket, @cBuffer, [ nLen = LEN( cBuffer ) ], [ nFlags = 0 ], [ nTimeout = FOREVER ] ) --> nBytesRecv
|
||||
* HB_SOCKETRECVFROM( hSocket, @cBuffer, [ nLen = LEN( cBuffer ) ], [ nFlags = 0 ], @aAddr, [ nTimeout = FOREVER ] ) --> nBytesRecv
|
||||
* HB_SOCKETSETBLOCKINGIO( hSocket, lValue ) --> nSuccess
|
||||
* HB_SOCKETSETNODELAY( hSocket, lValue ) --> nSuccess
|
||||
* HB_SOCKETSETREUSEADDR( hSocket, lValue ) --> nSuccess
|
||||
* HB_SOCKETSETKEEPALIVE( hSocket, lValue ) --> nSuccess
|
||||
* HB_SOCKETSETBROADCAST( hSocket, lValue ) --> nSuccess
|
||||
* HB_SOCKETSETSNDBUFSIZE( hSocket, nValue ) --> nSuccess
|
||||
* HB_SOCKETSETRCVBUFSIZE( hSocket, nValue ) --> nSuccess
|
||||
* HB_SOCKETGETSNDBUFSIZE( hSocket, @nValue ) --> nSuccess
|
||||
* HB_SOCKETGETRCVBUFSIZE( hSocket, @nValue ) --> nSuccess
|
||||
* HB_SOCKETSETMULTICAST( hSocket, cAddr ) --> nSuccess
|
||||
* HB_SOCKETSELECTREAD( hSocket, [ nTimeout = FOREVER ] ) --> nRet
|
||||
* HB_SOCKETSELECTWRITE( hSocket, [ nTimeout = FOREVER ] ) --> nRet
|
||||
* HB_SOCKETSELECTWRITEEX( hSocket, [ nTimeout = FOREVER ] ) --> nRet
|
||||
* HB_SOCKETSELECT( aRead, lSetRead, aWrite, lSetWrite, aExcep, lSetExcep, [ nTimeout = FOREVER ] ) --> nRet
|
||||
* HB_SOCKETRESOLVEINETADDR( cAddr, nPort ) --> aAddr | NIL
|
||||
* HB_SOCKETRESOLVEADDR( cAddr, [ nFamily = HB_SOCKET_AF_INET ] ) --> cResolved
|
||||
* HB_SOCKETGETHOSTS( cAddr, [ nFamily = HB_SOCKET_AF_INET ] ) --> aHosts
|
||||
* HB_SOCKETGETIFACES( [ nFamily ], [ lNoAliases ] ) --> aIfaces
|
||||
*/
|
||||
|
||||
#include "hbapiitm.h"
|
||||
#include "hbapierr.h"
|
||||
#include "hbvm.h"
|
||||
#include "hbsocket.h"
|
||||
|
||||
HB_MAXINT hb_parnintdef( int iParam, HB_MAXINT iDefault )
|
||||
{
|
||||
return HB_ISNUM( iParam ) ? hb_parnint( iParam ) : iDefault;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HB_SOCKET socket;
|
||||
} HB_PRG_SOCKET, * PHB_PRG_SOCKET;
|
||||
|
||||
|
||||
static HB_BOOL s_fInit = HB_FALSE;
|
||||
|
||||
static HB_GARBAGE_FUNC( hb_socket_destructor )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = ( PHB_PRG_SOCKET ) Cargo;
|
||||
if( pSocket->socket != HB_NO_SOCKET )
|
||||
{
|
||||
hb_socketClose( pSocket->socket );
|
||||
pSocket->socket = HB_NO_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
static const HB_GC_FUNCS s_gcSocketFuncs =
|
||||
{
|
||||
hb_socket_destructor,
|
||||
hb_gcDummyMark
|
||||
};
|
||||
|
||||
static PHB_PRG_SOCKET socketParam( int iParam )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = ( PHB_PRG_SOCKET ) hb_parptrGC( &s_gcSocketFuncs, iParam );
|
||||
|
||||
if( pSocket && pSocket->socket != HB_NO_SOCKET )
|
||||
return pSocket;
|
||||
|
||||
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static HB_BOOL socketaddrParam( int iParam, void ** pAddr, unsigned int * puiLen )
|
||||
{
|
||||
PHB_ITEM pItem = hb_param( iParam, HB_IT_ARRAY );
|
||||
|
||||
if( pItem && hb_socketAddrFromItem( pAddr, puiLen, pItem ) )
|
||||
return HB_TRUE;
|
||||
|
||||
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
||||
return HB_FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void socket_exit( void * cargo )
|
||||
{
|
||||
HB_SYMBOL_UNUSED( cargo );
|
||||
|
||||
if( s_fInit )
|
||||
{
|
||||
hb_socketCleanup();
|
||||
s_fInit = HB_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void socket_init( void )
|
||||
{
|
||||
if( ! s_fInit )
|
||||
{
|
||||
hb_socketInit();
|
||||
hb_vmAtQuit( socket_exit, NULL );
|
||||
s_fInit = HB_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HB_FUNC( HB_SOCKETGETERROR )
|
||||
{
|
||||
hb_retni( hb_socketGetError() );
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETGETOSERROR )
|
||||
{
|
||||
hb_retni( hb_socketGetOsError() );
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETERRORSTRING )
|
||||
{
|
||||
if( HB_ISNUM( 1 ) )
|
||||
hb_retc( hb_socketErrorStr( hb_parni( 1 ) ) );
|
||||
else
|
||||
hb_retc( hb_socketErrorStr( hb_socketGetError() ) );
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETGETSOCKNAME )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
void * addr;
|
||||
unsigned int len;
|
||||
|
||||
if( hb_socketGetSockName( pSocket->socket, &addr, &len ) == 0 )
|
||||
{
|
||||
PHB_ITEM pItem = hb_socketAddrToItem( addr, len );
|
||||
|
||||
if( addr )
|
||||
hb_xfree( addr );
|
||||
|
||||
if( pItem )
|
||||
{
|
||||
hb_itemReturnRelease( pItem );
|
||||
return;
|
||||
}
|
||||
}
|
||||
hb_ret();
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETGETPEERNAME )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
void * addr;
|
||||
unsigned int len;
|
||||
|
||||
if( hb_socketGetPeerName( pSocket->socket, &addr, &len ) == 0 )
|
||||
{
|
||||
PHB_ITEM pItem = hb_socketAddrToItem( addr, len );
|
||||
|
||||
if( addr )
|
||||
hb_xfree( addr );
|
||||
|
||||
if( pItem )
|
||||
{
|
||||
hb_itemReturnRelease( pItem );
|
||||
return;
|
||||
}
|
||||
}
|
||||
hb_ret();
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETOPEN )
|
||||
{
|
||||
HB_SOCKET socket;
|
||||
int iDomain = hb_parnidef( 1, HB_SOCKET_PF_INET );
|
||||
int iType = hb_parnidef( 2, HB_SOCKET_PT_STREAM );
|
||||
int iProtocol = hb_parni( 3 );
|
||||
|
||||
socket_init();
|
||||
if( ( socket = hb_socketOpen( iDomain, iType, iProtocol ) ) != HB_NO_SOCKET )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = ( PHB_PRG_SOCKET ) hb_gcAllocate( sizeof( HB_PRG_SOCKET ),
|
||||
&s_gcSocketFuncs );
|
||||
pSocket->socket = socket;
|
||||
hb_retptrGC( pSocket );
|
||||
}
|
||||
else
|
||||
hb_retptr( NULL );
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETCLOSE )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
int iRet = hb_socketClose( pSocket->socket );
|
||||
pSocket->socket = HB_NO_SOCKET;
|
||||
hb_retni( iRet );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETSHUTDOWN )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
hb_retni( hb_socketShutdown( pSocket->socket, hb_parnidef( 2, HB_SOCKET_SHUT_RDWR ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETBIND )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
void * addr;
|
||||
unsigned int len;
|
||||
|
||||
if( pSocket && socketaddrParam( 2, &addr, &len ) )
|
||||
{
|
||||
hb_retni( hb_socketBind( pSocket->socket, addr, len ) );
|
||||
hb_xfree( addr );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETLISTEN )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
hb_retni( hb_socketListen( pSocket->socket, hb_parnidef( 2, 10 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETACCEPT )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
HB_SOCKET socket;
|
||||
void * addr = NULL;
|
||||
unsigned int len;
|
||||
|
||||
socket = hb_socketAccept( pSocket->socket, &addr, &len, hb_parnintdef( 3, -1 ) );
|
||||
|
||||
if( socket != HB_NO_SOCKET )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = ( PHB_PRG_SOCKET ) hb_gcAllocate( sizeof( HB_PRG_SOCKET ),
|
||||
&s_gcSocketFuncs );
|
||||
pSocket->socket = socket;
|
||||
hb_retptrGC( pSocket );
|
||||
}
|
||||
else
|
||||
hb_retptr( NULL );
|
||||
|
||||
|
||||
if( HB_ISBYREF( 2 ) )
|
||||
{
|
||||
PHB_ITEM pItem = hb_socketAddrToItem( addr, len );
|
||||
if( pItem )
|
||||
{
|
||||
hb_itemParamStoreForward( 2, pItem );
|
||||
hb_itemRelease( pItem );
|
||||
}
|
||||
else
|
||||
hb_stor( 2 );
|
||||
}
|
||||
|
||||
if( addr )
|
||||
hb_xfree( addr );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETCONNECT )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
void * addr;
|
||||
unsigned int len;
|
||||
|
||||
if( pSocket && socketaddrParam( 2, &addr, &len ) )
|
||||
{
|
||||
hb_retni( hb_socketConnect( pSocket->socket, addr, len, hb_parnintdef( 3, -1 ) ) );
|
||||
hb_xfree( addr );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETSEND )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
long lLen = ( long ) hb_parclen( 2 );
|
||||
|
||||
if( HB_ISNUM( 3 ) )
|
||||
{
|
||||
long lParam = hb_parnl( 3 );
|
||||
|
||||
if( lParam >= 0 && lParam < lLen )
|
||||
lLen = lParam;
|
||||
}
|
||||
hb_retnl( hb_socketSend( pSocket->socket, hb_parc( 2 ), lLen, hb_parni( 4 ),
|
||||
hb_parnintdef( 5, -1 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETSENDTO )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
void * addr;
|
||||
unsigned int len;
|
||||
|
||||
if( pSocket && socketaddrParam( 5, &addr, &len ) )
|
||||
{
|
||||
long lLen = ( long ) hb_parclen( 2 );
|
||||
|
||||
if( HB_ISNUM( 3 ) )
|
||||
{
|
||||
long lParam = hb_parnl( 3 );
|
||||
|
||||
if( lParam >= 0 && lParam < lLen )
|
||||
lLen = lParam;
|
||||
}
|
||||
hb_retnl( hb_socketSendTo( pSocket->socket, hb_parc( 2 ), lLen, hb_parni( 4 ),
|
||||
addr, len, hb_parnintdef( 6, -1 ) ) );
|
||||
hb_xfree( addr );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETRECV )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
PHB_ITEM pItem = hb_param( 2, HB_IT_STRING );
|
||||
char * pBuffer;
|
||||
HB_SIZE iLen;
|
||||
|
||||
if( pItem && HB_ISBYREF( 2 ) && hb_itemGetWriteCL( pItem, &pBuffer, &iLen ) )
|
||||
{
|
||||
if( HB_ISNUM( 3 ) )
|
||||
{
|
||||
long lRead = hb_parnl( 3 );
|
||||
if( lRead >= 0 && lRead < ( long ) iLen )
|
||||
iLen = lRead;
|
||||
}
|
||||
hb_retnl( hb_socketRecv( pSocket->socket, pBuffer, ( long ) iLen,
|
||||
hb_parni( 4 ), hb_parnintdef( 5, -1 ) ) );
|
||||
return;
|
||||
}
|
||||
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETRECVFROM )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
PHB_ITEM pItem = hb_param( 2, HB_IT_STRING );
|
||||
char * pBuffer;
|
||||
HB_SIZE iLen;
|
||||
|
||||
if( pItem && HB_ISBYREF( 2 ) && hb_itemGetWriteCL( pItem, &pBuffer, &iLen ) )
|
||||
{
|
||||
void * addr = NULL;
|
||||
unsigned int len;
|
||||
if( HB_ISNUM( 3 ) )
|
||||
{
|
||||
long lRead = hb_parnl( 3 );
|
||||
if( lRead >= 0 && lRead < ( long ) iLen )
|
||||
iLen = lRead;
|
||||
}
|
||||
hb_retnl( hb_socketRecvFrom( pSocket->socket, pBuffer, ( long ) iLen,
|
||||
hb_parni( 4 ), &addr, &len,
|
||||
hb_parnintdef( 6, -1 ) ) );
|
||||
if( HB_ISBYREF( 5 ) )
|
||||
{
|
||||
PHB_ITEM pAddr = hb_socketAddrToItem( addr, len );
|
||||
if( pAddr )
|
||||
{
|
||||
hb_itemParamStoreForward( 5, pAddr );
|
||||
hb_itemRelease( pAddr );
|
||||
}
|
||||
else
|
||||
hb_stor( 5 );
|
||||
}
|
||||
|
||||
if( addr )
|
||||
hb_xfree( addr );
|
||||
return;
|
||||
}
|
||||
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETSETBLOCKINGIO )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
hb_retni( hb_socketSetBlockingIO( pSocket->socket, hb_parl( 2 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETSETNODELAY )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
hb_retni( hb_socketSetNoDelay( pSocket->socket, hb_parl( 2 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETSETREUSEADDR )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
hb_retni( hb_socketSetReuseAddr( pSocket->socket, hb_parl( 2 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETSETKEEPALIVE )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
hb_retni( hb_socketSetKeepAlive( pSocket->socket, hb_parl( 2 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETSETBROADCAST )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
hb_retni( hb_socketSetBroadcast( pSocket->socket, hb_parl( 2 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETSETSNDBUFSIZE )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
hb_retni( hb_socketSetSndBufSize( pSocket->socket, hb_parni( 2 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETSETRCVBUFSIZE )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
hb_retni( hb_socketSetRcvBufSize( pSocket->socket, hb_parni( 2 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETGETSNDBUFSIZE )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
int size;
|
||||
hb_retni( hb_socketGetSndBufSize( pSocket->socket, &size ) );
|
||||
hb_storni( size, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETGETRCVBUFSIZE )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
int size;
|
||||
hb_retni( hb_socketGetRcvBufSize( pSocket->socket, &size ) );
|
||||
hb_storni( size, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETSETMULTICAST )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
hb_retni( hb_socketSetMulticast( pSocket->socket, hb_parnidef( 2, HB_SOCKET_AF_INET ), hb_parc( 3 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETSELECTREAD )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
hb_retni( hb_socketSelectRead( pSocket->socket, hb_parnintdef( 2, -1 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETSELECTWRITE )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
hb_retni( hb_socketSelectWrite( pSocket->socket, hb_parnintdef( 2, -1 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETSELECTWRITEEX )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = socketParam( 1 );
|
||||
if( pSocket )
|
||||
{
|
||||
hb_retni( hb_socketSelectWriteEx( pSocket->socket, hb_parnintdef( 2, -1 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
static HB_SOCKET socketSelectCallback( PHB_ITEM pItem )
|
||||
{
|
||||
PHB_PRG_SOCKET pSocket = ( PHB_PRG_SOCKET ) hb_itemGetPtrGC( pItem, &s_gcSocketFuncs );
|
||||
|
||||
if( pSocket && pSocket->socket != HB_NO_SOCKET )
|
||||
return pSocket->socket;
|
||||
|
||||
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
||||
return HB_NO_SOCKET;
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETSELECT )
|
||||
{
|
||||
socket_init();
|
||||
hb_retni( hb_socketSelect( hb_param( 1, HB_IT_ARRAY ), hb_parl( 2 ),
|
||||
hb_param( 3, HB_IT_ARRAY ), hb_parl( 4 ),
|
||||
hb_param( 5, HB_IT_ARRAY ), hb_parl( 6 ),
|
||||
hb_parnintdef( 7, -1 ), socketSelectCallback ) );
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETRESOLVEINETADDR )
|
||||
{
|
||||
void * addr;
|
||||
unsigned int len;
|
||||
|
||||
socket_init();
|
||||
if( hb_socketResolveInetAddr( &addr, &len, hb_parc( 1 ), hb_parni( 2 ) ) )
|
||||
{
|
||||
PHB_ITEM pItem = hb_socketAddrToItem( addr, len );
|
||||
|
||||
if( addr )
|
||||
hb_xfree( addr );
|
||||
|
||||
if( pItem )
|
||||
{
|
||||
hb_itemReturnRelease( pItem );
|
||||
return;
|
||||
}
|
||||
}
|
||||
hb_ret();
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETRESOLVEADDR )
|
||||
{
|
||||
char * szAddr;
|
||||
|
||||
socket_init();
|
||||
szAddr = hb_socketResolveAddr( hb_parc( 1 ), hb_parnidef( 2, HB_SOCKET_AF_INET ) );
|
||||
if( szAddr )
|
||||
hb_retc_buffer( szAddr );
|
||||
else
|
||||
hb_retc( "" );
|
||||
}
|
||||
|
||||
HB_FUNC( HB_SOCKETGETHOSTS )
|
||||
{
|
||||
PHB_ITEM pItem;
|
||||
|
||||
socket_init();
|
||||
pItem = hb_socketGetHosts( hb_parc( 1 ), hb_parnidef( 2, HB_SOCKET_AF_INET ) );
|
||||
if( pItem )
|
||||
hb_itemReturnRelease( pItem );
|
||||
else
|
||||
hb_reta( 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
This function is not implemented at C level, yet [Mindaugas]
|
||||
|
||||
HB_FUNC( HB_SOCKETGETALIASES )
|
||||
{
|
||||
PHB_ITEM pItem;
|
||||
|
||||
socket_init();
|
||||
pItem = hb_socketGetAliases( hb_parc( 1 ), hb_parnidef( 2, HB_SOCKET_AF_INET ) );
|
||||
if( pItem )
|
||||
hb_itemReturnRelease( pItem );
|
||||
else
|
||||
hb_reta( 0 );
|
||||
}
|
||||
*/
|
||||
|
||||
HB_FUNC( HB_SOCKETGETIFACES )
|
||||
{
|
||||
PHB_ITEM pItem;
|
||||
|
||||
socket_init();
|
||||
pItem = hb_socketGetIFaces( hb_parni( 1 ), hb_parl( 2 ) );
|
||||
if( pItem )
|
||||
hb_itemReturnRelease( pItem );
|
||||
else
|
||||
hb_reta( 0 );
|
||||
}
|
||||
Reference in New Issue
Block a user