From b9836e09efad03487c9046e54f70da36f42f371a Mon Sep 17 00:00:00 2001 From: Mindaugas Kavaliauskas Date: Tue, 8 Jun 2010 18:54:58 +0000 Subject: [PATCH] 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. --- harbour/ChangeLog | 66 ++- harbour/examples/udpds/udpds.prg | 125 ++++++ harbour/src/rtl/Makefile | 1 + harbour/src/rtl/hbsockhb.c | 672 +++++++++++++++++++++++++++++++ 4 files changed, 862 insertions(+), 2 deletions(-) create mode 100644 harbour/examples/udpds/udpds.prg create mode 100644 harbour/src/rtl/hbsockhb.c diff --git a/harbour/ChangeLog b/harbour/ChangeLog index a980792257..49ad645927 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -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) diff --git a/harbour/examples/udpds/udpds.prg b/harbour/examples/udpds/udpds.prg new file mode 100644 index 0000000000..ea7322a956 --- /dev/null +++ b/harbour/examples/udpds/udpds.prg @@ -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 + diff --git a/harbour/src/rtl/Makefile b/harbour/src/rtl/Makefile index 69a2f089b3..3a03071948 100644 --- a/harbour/src/rtl/Makefile +++ b/harbour/src/rtl/Makefile @@ -96,6 +96,7 @@ C_SOURCES := \ hbsha2.c \ hbsha2hm.c \ hbsocket.c \ + hbsockhb.c \ hbstrfmt.c \ hbstrsh.c \ hbtoken.c \ diff --git a/harbour/src/rtl/hbsockhb.c b/harbour/src/rtl/hbsockhb.c new file mode 100644 index 0000000000..016ce66182 --- /dev/null +++ b/harbour/src/rtl/hbsockhb.c @@ -0,0 +1,672 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * Socket API wrapper functions + * + * Copyright 2010 Mindaugas Kavaliauskas + * 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 ); +}