From 2abefe1b3e2973d55e4b6789d2eeb9668747c074 Mon Sep 17 00:00:00 2001 From: Przemyslaw Czerpak Date: Mon, 27 Jul 2009 21:43:31 +0000 Subject: [PATCH] 2009-07-27 23:43 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) * harbour/include/hbstack.h + added socket error codes to HB_IOERRORS * harbour/include/Makefile + harbour/include/hbsocket.ch + harbour/include/hbsocket.h * harbour/source/rtl/Makefile + harbour/source/rtl/hbsocket.c + added new BSD socket functions: hb_socket*(). They should be quite close to low level C socket interface with few modifications which help to hide some platform differences. Unfortunately we do not use autoconf so I had to arbitrary set which features are available on some platforms. In practice it means that it reduces portability to older OS-es, i.e. it should work with current Linux versions but it will not without some modifications in macros used to control supported features with older Linuxes using kernel 2.2 or 2.0. The same can happen with other *nix ports like Darwin, SunOS, HP-UX or with different versions of some Windows compilers. I also do not know which functionality is available in OS2 GCC ports and I would like to ask OS2 users to make tests and disable not working features. We also need tests with HP-UX, Darwin and SunOS. IP6 support is enabled only in *nixes. If Windows users are interested in IP6 then please add support for it. Most of Windows compilers do not support standard POSIX functions so I do not want to make it myself using unknown for me API without testing. In *nix builds PF_UNIX/PF_LOCAL sockets are also supported. Support for other socket types can be easy added if someone is interested in them. The constant values used in hbsocket.ch are equal to original BSD socket definitions. If it's necessary then it's possible to enable their translation inside hbsocket.c code though I do not think we will find such OS. The list of hb_socket*() functions was designed to cover all existing functionality in hbinet.c and socket.c. Most of functions supports timeout parameter what effectively allows to hide direct select() usage. Please make test with real applications and report any problems with hb_inet*() functions you will find. * harbour/source/vm/hvm.c * minor cleanup * harbour/source/rtl/hbi18n1.c * cleaned variable name * harbour/source/rtl/hbinet.c * harbour/examples/uhttpd2/socket.c * harbour/contrib/hbssl/hbssl.c * updated to use hb_socket*() functions * harbour/include/hbextern.ch * enabled HB_INET*() functions in DOS builds - they will simply return errors - harbour/include/hbapinet.h - removed old header file * harbour/source/pp/ppcore.c ! modified ENDTEXT marker to work also with comments in the same line It's more closer to Clipper though intentionally we are not fully CA-Cl*pper compatible here. --- harbour/ChangeLog | 63 + harbour/contrib/hbssl/hbssl.c | 10 +- harbour/examples/uhttpd2/socket.c | 467 ++--- harbour/include/Makefile | 3 +- harbour/include/hbapinet.h | 116 -- harbour/include/hbextern.ch | 3 - harbour/include/hbsocket.ch | 191 ++ harbour/include/hbsocket.h | 119 ++ harbour/include/hbstack.h | 2 + harbour/source/pp/ppcore.c | 10 +- harbour/source/rtl/Makefile | 1 + harbour/source/rtl/hbi18n1.c | 4 +- harbour/source/rtl/hbinet.c | 1119 +++--------- harbour/source/rtl/hbsocket.c | 2736 +++++++++++++++++++++++++++++ harbour/source/vm/hvm.c | 2 +- 15 files changed, 3469 insertions(+), 1377 deletions(-) delete mode 100644 harbour/include/hbapinet.h create mode 100644 harbour/include/hbsocket.ch create mode 100644 harbour/include/hbsocket.h create mode 100644 harbour/source/rtl/hbsocket.c diff --git a/harbour/ChangeLog b/harbour/ChangeLog index f9cffce530..ff8fe87f9a 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -17,6 +17,69 @@ past entries belonging to author(s): Viktor Szakats. */ +2009-07-27 23:43 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/include/hbstack.h + + added socket error codes to HB_IOERRORS + + * harbour/include/Makefile + + harbour/include/hbsocket.ch + + harbour/include/hbsocket.h + * harbour/source/rtl/Makefile + + harbour/source/rtl/hbsocket.c + + added new BSD socket functions: hb_socket*(). They should be quite + close to low level C socket interface with few modifications which + help to hide some platform differences. Unfortunately we do not use + autoconf so I had to arbitrary set which features are available + on some platforms. In practice it means that it reduces portability + to older OS-es, i.e. it should work with current Linux versions + but it will not without some modifications in macros used to control + supported features with older Linuxes using kernel 2.2 or 2.0. + The same can happen with other *nix ports like Darwin, SunOS, HP-UX + or with different versions of some Windows compilers. I also do not + know which functionality is available in OS2 GCC ports and I would + like to ask OS2 users to make tests and disable not working features. + We also need tests with HP-UX, Darwin and SunOS. + IP6 support is enabled only in *nixes. If Windows users are interested + in IP6 then please add support for it. Most of Windows compilers do + not support standard POSIX functions so I do not want to make it + myself using unknown for me API without testing. + In *nix builds PF_UNIX/PF_LOCAL sockets are also supported. + Support for other socket types can be easy added if someone is + interested in them. + The constant values used in hbsocket.ch are equal to original BSD + socket definitions. If it's necessary then it's possible to enable + their translation inside hbsocket.c code though I do not think we + will find such OS. + The list of hb_socket*() functions was designed to cover all existing + functionality in hbinet.c and socket.c. Most of functions supports + timeout parameter what effectively allows to hide direct select() + usage. + Please make test with real applications and report any problems + with hb_inet*() functions you will find. + + * harbour/source/vm/hvm.c + * minor cleanup + + * harbour/source/rtl/hbi18n1.c + * cleaned variable name + + * harbour/source/rtl/hbinet.c + * harbour/examples/uhttpd2/socket.c + * harbour/contrib/hbssl/hbssl.c + * updated to use hb_socket*() functions + + * harbour/include/hbextern.ch + * enabled HB_INET*() functions in DOS builds - they will simply return + errors + + - harbour/include/hbapinet.h + - removed old header file + + * harbour/source/pp/ppcore.c + ! modified ENDTEXT marker to work also with comments in the same line + It's more closer to Clipper though intentionally we are not fully + CA-Cl*pper compatible here. + 2009-07-24 09:46 UTC+0200 Viktor Szakats (harbour.01 syenar.hu) * contrib/hbtip/sendmail.prg * contrib/hbtip/client.prg diff --git a/harbour/contrib/hbssl/hbssl.c b/harbour/contrib/hbssl/hbssl.c index ec0f72e041..18f31c3dbb 100644 --- a/harbour/contrib/hbssl/hbssl.c +++ b/harbour/contrib/hbssl/hbssl.c @@ -53,13 +53,11 @@ #include "hbapi.h" #include "hbapierr.h" #include "hbapiitm.h" -#include "hbapinet.h" +#include "hbsocket.h" #include "hbvm.h" #include "hbssl.h" -#if defined( HB_API_NET ) - HB_FUNC( HB_SSL_READ_ALL ) { if( hb_SSL_is( 1 ) ) @@ -82,7 +80,7 @@ HB_FUNC( HB_SSL_READ_ALL ) int iLen; if( SSL_pending( ssl ) || - hb_selectReadFD( ( HB_SOCKET_T ) SSL_get_fd( ssl ), iTimeout ) ) + hb_socketSelectRead( ( HB_SOCKET_T ) SSL_get_fd( ssl ), iTimeout ) ) { iLen = SSL_read( ssl, &buffer, 1 ); @@ -151,7 +149,7 @@ HB_FUNC( HB_SSL_READ_LINE ) int iLen; if( SSL_pending( ssl ) || - hb_selectReadFD( ( HB_SOCKET_T ) SSL_get_fd( ssl ), iTimeout ) ) + hb_socketSelectRead( ( HB_SOCKET_T ) SSL_get_fd( ssl ), iTimeout ) ) { iLen = SSL_read( ssl, &buffer, 1 ); @@ -201,5 +199,3 @@ HB_FUNC( HB_SSL_READ_LINE ) else hb_errRT_BASE( EG_ARG, 2010, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } - -#endif diff --git a/harbour/examples/uhttpd2/socket.c b/harbour/examples/uhttpd2/socket.c index 9f24c08016..48b117dade 100644 --- a/harbour/examples/uhttpd2/socket.c +++ b/harbour/examples/uhttpd2/socket.c @@ -42,450 +42,199 @@ other: { AF_?, cAddressDump } */ -#include "hbapi.h" +#include "hbsocket.h" #include "hbapiitm.h" -#include "hbvm.h" - -#if defined( HB_OS_WIN ) - #define _WINSOCKAPI_ /* Prevents inclusion of winsock.h in windows.h */ - #define HB_SOCKET_T SOCKET - #include - #include - #define socklen_t int - #define SHUT_RDWR SD_BOTH -#else - #include - #include - #include - #include - #include - #define INVALID_SOCKET (-1) - typedef int SOCKET; -#endif - -#ifdef hb_parnidef -#undef hb_parnidef -#endif - static int hb_parnidef( int iParam, int iValue ) { return HB_ISNUM( iParam ) ? hb_parni( iParam ) : iValue; } - -static SOCKET hb_parsocket( int iParam ) +static HB_SOCKET_T hb_parsocket( int iParam ) { - return HB_ISPOINTER( iParam ) ? ( SOCKET ) hb_parptr( 1 ) : INVALID_SOCKET; + return HB_ISPOINTER( iParam ) ? ( HB_SOCKET_T ) ( HB_PTRDIFF ) + hb_parptr( iParam ) : HB_NO_SOCKET; } - -static void hb_retsocket( SOCKET hSocket ) +static void hb_retsocket( HB_SOCKET_T hSocket ) { - if( hSocket == INVALID_SOCKET ) + if( hSocket == HB_NO_SOCKET ) hb_ret(); else - hb_retptr( ( void* ) hSocket ); + hb_retptr( ( void* ) ( HB_PTRDIFF ) hSocket ); } - -static SOCKET hb_itemGetSocket( PHB_ITEM pItem ) +static HB_SOCKET_T hb_itemGetSocket( PHB_ITEM pSocket ) { - return HB_IS_POINTER( pItem ) ? ( SOCKET ) hb_itemGetPtr( pItem ) : INVALID_SOCKET; -} - - -static PHB_ITEM hb_itemPutSocket( PHB_ITEM pItem, SOCKET hSocket ) -{ - if( ! pItem ) - pItem = hb_itemNew( NULL ); - - if( hSocket == INVALID_SOCKET ) - hb_itemClear( pItem ); + if( pSocket && HB_IS_POINTER( pSocket ) ) + return ( HB_SOCKET_T ) ( HB_PTRDIFF ) hb_itemGetPtr( pSocket ); else - hb_itemPutPtr( pItem, ( void* ) hSocket ); - - return pItem; + return HB_NO_SOCKET; } - -static void hb_itemGetSockaddr( PHB_ITEM pItem, struct sockaddr* sa ) -{ - memset( sa, 0, sizeof( struct sockaddr ) ); - - if( HB_IS_ARRAY( pItem ) ) - { - sa->sa_family = hb_arrayGetNI( pItem, 1 ); - - if( sa->sa_family == AF_INET ) - { - ( ( struct sockaddr_in* ) sa)->sin_addr.s_addr = inet_addr( hb_arrayGetCPtr( pItem, 2 ) ); - ( ( struct sockaddr_in* ) sa)->sin_port = htons( hb_arrayGetNI( pItem, 3 ) ); - } - else - { - ULONG ulLen = hb_arrayGetCLen( pItem, 2 ); - - if( ulLen > sizeof( sa->sa_data ) ) - ulLen = sizeof( sa->sa_data ); - memcpy( sa->sa_data, hb_arrayGetCPtr( pItem, 2 ), ulLen ); - } - } -} - - -static PHB_ITEM hb_itemPutSockaddr( PHB_ITEM pItem, const struct sockaddr* saddr ) -{ - pItem = hb_itemNew( pItem ); - - if( saddr->sa_family == AF_INET ) - { - hb_arrayNew( pItem, 3 ); - hb_arraySetNI( pItem, 1, saddr->sa_family ); - hb_arraySetC( pItem, 2, inet_ntoa( ( ( struct sockaddr_in* ) saddr )->sin_addr ) ); - hb_arraySetNI( pItem, 3, ntohs( ( ( struct sockaddr_in* ) saddr )->sin_port ) ); - } - else - { - hb_arrayNew( pItem, 2 ); - hb_arraySetNI( pItem, 1, saddr->sa_family ); - hb_arraySetCL( pItem, 2, saddr->sa_data, sizeof( saddr->sa_data ) ); - } - return pItem; -} - - HB_FUNC( SOCKET_INIT ) { -#if defined( HB_OS_WIN ) - WSADATA wsad; - - hb_retni( WSAStartup( hb_parnidef( 1, 257 ), &wsad ) ); - hb_storclen( (char*) &wsad, sizeof( WSADATA ), 2 ); -#else - hb_retni( 0 ); -#endif + hb_retni( hb_socketInit() ); } - HB_FUNC( SOCKET_EXIT ) { -#if defined( HB_OS_WIN ) - hb_retni( WSACleanup() ); -#else - hb_retni( 0 ); -#endif + hb_socketCleanup(); } - HB_FUNC( SOCKET_ERROR ) { -#if defined( HB_OS_WIN ) - hb_retni( WSAGetLastError() ); -#else - hb_retni( h_errno ); -#endif + hb_retni( hb_socketGetError() ); } - HB_FUNC( SOCKET_CREATE ) { - hb_retsocket( socket( hb_parnidef( 1, PF_INET ), - hb_parnidef( 2, SOCK_STREAM ), - hb_parnidef( 3, IPPROTO_TCP ) ) ); + hb_retsocket( hb_socketOpen( hb_parnidef( 1, HB_SOCK_PF_INET ), + hb_parnidef( 2, HB_SOCK_STREAM ), + hb_parnidef( 3, HB_SOCK_IPPROTO_TCP ) ) ); } - HB_FUNC( SOCKET_CLOSE ) { -#if defined( HB_OS_WIN ) - hb_retni( closesocket( hb_parsocket( 1 ) ) ); -#else - hb_retni( close( hb_parsocket( 1 ) ) ); -#endif + hb_retni( hb_socketClose( hb_parsocket( 1 ) ) ); } - HB_FUNC( SOCKET_BIND ) { - struct sockaddr sa; + void * sa; + unsigned len; - hb_itemGetSockaddr( hb_param( 2, HB_IT_ANY ), &sa ); - hb_retni( bind( hb_parsocket( 1 ), &sa, sizeof( struct sockaddr ) ) ); + if( hb_socketAddrFromItem( &sa, &len, hb_param( 2, HB_IT_ANY ) ) ) + { + hb_retni( hb_socketBind( hb_parsocket( 1 ), sa, len ) ); + hb_xfree( sa ); + } } - HB_FUNC( SOCKET_LISTEN ) { - hb_retni( listen( hb_parsocket( 1 ), hb_parnidef( 2, 10 ) ) ); + hb_retni( hb_socketListen( hb_parsocket( 1 ), hb_parnidef( 2, 10 ) ) ); } - HB_FUNC( SOCKET_ACCEPT ) { - PHB_ITEM pItem; - SOCKET socket = hb_parsocket( 1 ); - struct sockaddr saddr; - socklen_t iSize = sizeof( struct sockaddr ); - - hb_vmUnlock(); - socket = accept( socket, &saddr, &iSize ); - hb_vmLock(); - - hb_retsocket( socket ); if( HB_ISBYREF( 2 ) ) { - pItem = hb_itemPutSockaddr( NULL, &saddr ); - hb_itemParamStoreForward( 2, pItem ); - hb_itemRelease( pItem ); - } -} + void * sa; + unsigned len; + PHB_ITEM pItem; + hb_retsocket( hb_socketAccept( hb_parsocket( 1 ), &sa, &len, + HB_ISNUM( 3 ) ? hb_parnint( 3 ) : -1 ) ); + pItem = hb_socketAddrToItem( sa, len ); + if( pItem ) + { + hb_itemParamStoreForward( 2, pItem ); + hb_itemRelease( pItem ); + } + else + hb_stor( 2 ); + + if( sa ) + hb_xfree( sa ); + } + else + hb_retsocket( hb_socketAccept( hb_parsocket( 1 ), NULL, 0, + HB_ISNUM( 3 ) ? hb_parnint( 3 ) : -1 ) ); +} HB_FUNC( SOCKET_SHUTDOWN ) { - SOCKET socket = hb_parsocket( 1 ); - int i = hb_parnidef( 2, SHUT_RDWR ); - - hb_vmUnlock(); - i = shutdown( socket, i ); - hb_vmLock(); - hb_retni( i ); + hb_retni( hb_socketShutdown( hb_parsocket( 1 ), + hb_parnidef( 2, HB_SOCK_SHUT_RDWR ) ) ); } - HB_FUNC( SOCKET_RECV ) { - SOCKET socket = hb_parsocket( 1 ); - int iLen, iRet, iFlags = hb_parnidef( 4, 0 ); - char* pBuf; + char * pBuf; + long len; - iLen = hb_parni( 3 ); - - if( iLen > 65536 || iLen <= 0 ) - iLen = 4096; - - pBuf = ( char* ) hb_xgrab( ( ULONG ) iLen ); - - hb_vmUnlock(); - iRet = recv( socket, pBuf, iLen, iFlags ); - hb_vmLock(); - - hb_retni( iRet ); - hb_storclen( pBuf, iRet > 0 ? iRet : 0, 2 ); + len = hb_parni( 3 ); + if( len <= 0 ) + len = 4096; + pBuf = ( char* ) hb_xgrab( len + 1 ); + len = hb_socketRecv( hb_parsocket( 1 ), pBuf, len, hb_parni( 4 ), + HB_ISNUM( 5 ) ? hb_parnint( 5 ) : -1 ); + hb_retni( len ); + hb_storclen( pBuf, len > 0 ? len : 0, 2 ); hb_xfree( pBuf ); } - HB_FUNC( SOCKET_SEND ) { - SOCKET socket = hb_parsocket( 1 ); - const char* pBuf = hb_parc( 2 ); - ULONG ulLen = hb_parclen( 2 ); - int iRet, iFlags = hb_parnidef( 3, 0 ); - - hb_vmUnlock(); - iRet = send( socket, pBuf, ulLen, iFlags ); - hb_vmLock(); - hb_retni( iRet ); + hb_retni( hb_socketSend( hb_parsocket( 1 ), hb_parc( 2 ), hb_parclen( 2 ), + hb_parni( 4 ), HB_ISNUM( 5 ) ? hb_parnint( 5 ) : -1 ) ); } - -HB_FUNC( SOCKET_SELECT ) -{ - fd_set setread, setwrite, seterror; - BOOL bRead = 0, bWrite = 0, bError = 0; - struct timeval tv; - SOCKET socket, maxsocket; - PHB_ITEM pArray, pItem; - ULONG ulLen, ulIndex, ulCount; - LONG lTimeout; - int iRet; - - - FD_ZERO( &setread ); - FD_ZERO( &setwrite ); - FD_ZERO( &seterror ); - - maxsocket = (SOCKET) 0; - - pArray = hb_param( 1, HB_IT_ARRAY ); - if( pArray ) - { - ulLen = hb_arrayLen( pArray ); - for( ulIndex = 1; ulIndex <= ulLen; ulIndex++ ) - { - socket = hb_itemGetSocket( hb_arrayGetItemPtr( pArray, ulIndex ) ); - if( socket != INVALID_SOCKET ) - { - bRead = 1; - FD_SET( socket, &setread ); - if( socket > maxsocket ) - maxsocket = socket; - } - } - } - - pArray = hb_param( 2, HB_IT_ARRAY ); - if( pArray ) - { - ulLen = hb_arrayLen( pArray ); - for( ulIndex = 1; ulIndex <= ulLen; ulIndex++ ) - { - socket = hb_itemGetSocket( hb_arrayGetItemPtr( pArray, ulIndex ) ); - if( socket != INVALID_SOCKET ) - { - bWrite = 1; - FD_SET( socket, &setwrite ); - if( socket > maxsocket ) - maxsocket = socket; - } - } - } - - pArray = hb_param( 3, HB_IT_ARRAY ); - if( pArray ) - { - ulLen = hb_arrayLen( pArray ); - for( ulIndex = 1; ulIndex <= ulLen; ulIndex++ ) - { - socket = hb_itemGetSocket( hb_arrayGetItemPtr( pArray, ulIndex ) ); - if( socket != INVALID_SOCKET ) - { - bError = 1; - FD_SET( socket, &seterror ); - if( socket > maxsocket ) - maxsocket = socket; - } - } - } - - /* Default forever */ - lTimeout = HB_ISNUM( 4 ) ? hb_parnl( 4 ) : -1; - - hb_vmUnlock(); - if( lTimeout == -1 ) - { - iRet = select( maxsocket + 1, bRead ? &setread : NULL, bWrite ? &setwrite: NULL, - bError ? &seterror : NULL, NULL ); - } - else - { - tv.tv_sec = lTimeout / 1000; - tv.tv_usec = ( lTimeout % 1000 ) * 1000; - iRet = select( maxsocket + 1, bRead ? &setread : NULL, bWrite ? &setwrite: NULL, - bError ? &seterror : NULL, &tv ); - } - hb_vmLock(); - - pArray = hb_param( 1, HB_IT_ARRAY ); - if( pArray && HB_ISBYREF( 1 ) ) - { - ulLen = hb_arrayLen( pArray ); - pItem = hb_itemNew( NULL ); - hb_arrayNew( pItem, ulLen ); - ulCount = 0; - for( ulIndex = 1; ulIndex <= ulLen; ulIndex++ ) - { - socket = hb_itemGetSocket( hb_arrayGetItemPtr( pArray, ulIndex ) ); - if( socket != INVALID_SOCKET ) - { - if( FD_ISSET( socket, &setread ) ) - { - hb_arraySetForward( pItem, ++ulCount, hb_itemPutSocket( NULL, socket ) ); - } - } - } - hb_itemParamStoreForward( 1, pItem ); - } - - pArray = hb_param( 2, HB_IT_ARRAY ); - if( pArray && HB_ISBYREF( 2 ) ) - { - ulLen = hb_arrayLen( pArray ); - pItem = hb_itemNew( NULL ); - hb_arrayNew( pItem, ulLen ); - ulCount = 0; - for( ulIndex = 1; ulIndex <= ulLen; ulIndex++ ) - { - socket = hb_itemGetSocket( hb_arrayGetItemPtr( pArray, ulIndex ) ); - if( socket != INVALID_SOCKET ) - { - if( FD_ISSET( socket, &setwrite ) ) - { - hb_arraySetForward( pItem, ++ulCount, hb_itemPutSocket( NULL, socket ) ); - } - } - } - hb_itemParamStoreForward( 2, pItem ); - } - - pArray = hb_param( 3, HB_IT_ARRAY ); - if( pArray && HB_ISBYREF( 3 ) ) - { - ulLen = hb_arrayLen( pArray ); - pItem = hb_itemNew( NULL ); - hb_arrayNew( pItem, ulLen ); - ulCount = 0; - for( ulIndex = 1; ulIndex <= ulLen; ulIndex++ ) - { - socket = hb_itemGetSocket( hb_arrayGetItemPtr( pArray, ulIndex ) ); - if( socket != INVALID_SOCKET ) - { - if( FD_ISSET( socket, &seterror ) ) - { - hb_arraySetForward( pItem, ++ulCount, hb_itemPutSocket( NULL, socket ) ); - } - } - } - hb_itemParamStoreForward( 3, pItem ); - } - - hb_retni( iRet ); -} - - HB_FUNC( SOCKET_GETSOCKNAME ) { - PHB_ITEM pItem; - struct sockaddr saddr; - socklen_t iSize = sizeof( struct sockaddr ); + void * sa; + unsigned len; + int iRet; - hb_retni( getsockname( hb_parsocket( 1 ), &saddr, &iSize ) ); + iRet = hb_socketGetSockName( hb_parsocket( 1 ), &sa, &len ); + hb_retni( iRet ); if( HB_ISBYREF( 2 ) ) { - pItem = hb_itemPutSockaddr( NULL, &saddr ); - hb_itemParamStoreForward( 2, pItem ); - hb_itemRelease( pItem ); + PHB_ITEM pItem = hb_socketAddrToItem( sa, len ); + if( pItem ) + { + hb_itemParamStoreForward( 2, pItem ); + hb_itemRelease( pItem ); + } + else + hb_stor( 2 ); } + if( sa ) + hb_xfree( sa ); } - HB_FUNC( SOCKET_GETPEERNAME ) { - PHB_ITEM pItem; - struct sockaddr saddr; - socklen_t iSize = sizeof( struct sockaddr ); + void * sa; + unsigned len; + int iRet; - hb_retni( getpeername( hb_parsocket( 1 ), &saddr, &iSize ) ); + iRet = hb_socketGetPeerName( hb_parsocket( 1 ), &sa, &len ); + hb_retni( iRet ); if( HB_ISBYREF( 2 ) ) { - pItem = hb_itemPutSockaddr( NULL, &saddr ); - hb_itemParamStoreForward( 2, pItem ); - hb_itemRelease( pItem ); + PHB_ITEM pItem = hb_socketAddrToItem( sa, len ); + if( pItem ) + { + hb_itemParamStoreForward( 2, pItem ); + hb_itemRelease( pItem ); + } + else + hb_stor( 2 ); } + if( sa ) + hb_xfree( sa ); } - HB_FUNC( SOCKET_CONNECT ) { - SOCKET socket = hb_parsocket( 1 ); - struct sockaddr sa; - int iRet; + void * sa; + unsigned len; - hb_itemGetSockaddr( hb_param( 2, HB_IT_ANY ), &sa ); - hb_vmUnlock(); - iRet = connect( socket, &sa, sizeof( struct sockaddr ) ); - hb_vmLock(); - hb_retni( iRet ); + if( hb_socketAddrFromItem( &sa, &len, hb_param( 2, HB_IT_ANY ) ) ) + { + hb_retni( hb_socketConnect( hb_parsocket( 1 ), sa, len, + HB_ISNUM( 3 ) ? hb_parnint( 3 ) : -1 ) ); + hb_xfree( sa ); + } +} + +HB_FUNC( SOCKET_SELECT ) +{ + hb_retni( hb_socketSelect( hb_param( 1, HB_IT_ARRAY ), HB_ISBYREF( 1 ), + hb_param( 2, HB_IT_ARRAY ), HB_ISBYREF( 2 ), + hb_param( 3, HB_IT_ARRAY ), HB_ISBYREF( 3 ), + HB_ISNUM( 4 ) ? hb_parnint( 4 ) : -1, + hb_itemGetSocket ) ); } diff --git a/harbour/include/Makefile b/harbour/include/Makefile index 4921ec9205..9405df3b50 100644 --- a/harbour/include/Makefile +++ b/harbour/include/Makefile @@ -16,7 +16,6 @@ C_HEADERS=\ hbapigt.h \ hbapiitm.h \ hbapilng.h \ - hbapinet.h \ hbapirdd.h \ hbassert.h \ hbatomic.h \ @@ -47,6 +46,7 @@ C_HEADERS=\ hbregex.h \ hbset.h \ hbsetup.h \ + hbsocket.h \ hbstack.h \ hbsxfunc.h \ hbthread.h \ @@ -96,6 +96,7 @@ PRG_HEADERS=\ hbpers.ch \ hbsetup.ch \ hbsix.ch \ + hbsocket.ch \ hbstdgen.ch \ hbthread.ch \ hbusrrdd.ch \ diff --git a/harbour/include/hbapinet.h b/harbour/include/hbapinet.h deleted file mode 100644 index 6927e45efc..0000000000 --- a/harbour/include/hbapinet.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * $Id$ - */ - -/* - * Harbour Project source code: - * Networking API - * - * Copyright 2009 Viktor Szakats (harbour.01 syenar.hu) - * 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. - * - */ - -#ifndef HB_APINET_H_ -#define HB_APINET_H_ - -#include "hbapi.h" -#include "hbapiitm.h" - -#if ! defined( HB_OS_DOS ) - -#define HB_API_NET - -HB_EXTERN_BEGIN - -#if defined( HB_OS_WIN ) && ! defined( HB_OS_UNIX_COMPATIBLE ) - #define HB_SOCKET_T SOCKET - - #define _WINSOCKAPI_ /* Prevents inclusion of winsock.h in windows.h */ - #include - #include -#else - #define HB_SOCKET_T int - - #include - #if defined( HB_OS_OS2 ) - #if defined( __WATCOMC__ ) - #include - #include - #endif - #include - #include - #include - #include - #else - #include - #include - #endif - #include - #include - #include - #include -#endif - -typedef struct _HB_SOCKET -{ - HB_SOCKET_T com; - struct sockaddr_in remote; - char szErrorText[ 128 ]; - const char * pszErrorText; - int iErrorCode; - int iCount; - int iTimeout; - int iTimeLimit; - PHB_ITEM pPeriodicBlock; -} HB_SOCKET, * PHB_SOCKET; - -extern int hb_selectReadFD( HB_SOCKET_T fd, int iTimeout ); -extern int hb_selectWriteFD( HB_SOCKET_T fd, int iTimeout ); -extern int hb_selectReadSocket( PHB_SOCKET pSocket ); -extern int hb_selectWriteSocket( PHB_SOCKET pSocket ); - -HB_EXTERN_END - -#endif - -#endif /* HB_APINET_H_ */ diff --git a/harbour/include/hbextern.ch b/harbour/include/hbextern.ch index e710b31256..57cfda8101 100644 --- a/harbour/include/hbextern.ch +++ b/harbour/include/hbextern.ch @@ -1158,7 +1158,6 @@ EXTERNAL HB_REGEXSPLIT EXTERNAL HB_REGEXATX EXTERNAL HB_REGEXALL -#ifndef __PLATFORM__DOS EXTERNAL HB_INETINIT EXTERNAL HB_INETCLEANUP EXTERNAL HB_INETCREATE @@ -1201,8 +1200,6 @@ EXTERNAL HB_INETGETRCVBUFSIZE EXTERNAL HB_INETSETSNDBUFSIZE EXTERNAL HB_INETSETRCVBUFSIZE -#endif /* __PLATFORM__DOS */ - EXTERNAL HB_ZLIBVERSION EXTERNAL HB_ZCOMPRESS EXTERNAL HB_ZCOMPRESSBOUND diff --git a/harbour/include/hbsocket.ch b/harbour/include/hbsocket.ch new file mode 100644 index 0000000000..b5320d9864 --- /dev/null +++ b/harbour/include/hbsocket.ch @@ -0,0 +1,191 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * socket related constant values + * + * Copyright 2009 Przemyslaw Czerpak + * 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. + * + */ + +#ifndef HB_SOCK_CH_ +#define HB_SOCK_CH_ + +/* Harbour socket error codes */ +#define HB_SOCKET_ERR_PIPE 1 +#define HB_SOCKET_ERR_TIMEOUT 2 +#define HB_SOCKET_ERR_WRONGADDR 3 +#define HB_SOCKET_ERR_AFNOSUPPORT 4 +#define HB_SOCKET_ERR_PFNOSUPPORT 5 +#define HB_SOCKET_ERR_PROTONOSUPPORT 6 +#define HB_SOCKET_ERR_PARAMVALUE 7 +#define HB_SOCKET_ERR_NOSUPPORT 8 +#define HB_SOCKET_ERR_NORESOURCE 9 +#define HB_SOCKET_ERR_ACCESS 10 +#define HB_SOCKET_ERR_ADDRINUSE 11 +#define HB_SOCKET_ERR_INTERRUPT 12 +#define HB_SOCKET_ERR_ALREADYCONNECTED 13 +#define HB_SOCKET_ERR_CONNREFUSED 14 +#define HB_SOCKET_ERR_CONNABORTED 15 +#define HB_SOCKET_ERR_CONNRESET 16 +#define HB_SOCKET_ERR_NETUNREACH 17 +#define HB_SOCKET_ERR_NETDOWN 18 +#define HB_SOCKET_ERR_NETRESET 19 +#define HB_SOCKET_ERR_INPROGRESS 20 +#define HB_SOCKET_ERR_ALREADY 21 +#define HB_SOCKET_ERR_ADDRNOTAVAIL 22 +#define HB_SOCKET_ERR_READONLY 23 +#define HB_SOCKET_ERR_AGAIN 24 +#define HB_SOCKET_ERR_INVALIDHANDLE 25 +#define HB_SOCKET_ERR_INVAL 26 +#define HB_SOCKET_ERR_PROTO 27 +#define HB_SOCKET_ERR_PROTOTYPE 28 +#define HB_SOCKET_ERR_NOFILE 29 +#define HB_SOCKET_ERR_NOBUFS 30 +#define HB_SOCKET_ERR_NOMEM 31 +#define HB_SOCKET_ERR_FAULT 32 +#define HB_SOCKET_ERR_NAMETOOLONG 33 +#define HB_SOCKET_ERR_NOENT 34 +#define HB_SOCKET_ERR_NOTDIR 35 +#define HB_SOCKET_ERR_LOOP 36 +#define HB_SOCKET_ERR_MSGSIZE 37 +#define HB_SOCKET_ERR_DESTADDRREQ 38 +#define HB_SOCKET_ERR_NOPROTOOPT 39 +#define HB_SOCKET_ERR_NOTCONN 40 +#define HB_SOCKET_ERR_SHUTDOWN 41 +#define HB_SOCKET_ERR_TOOMANYREFS 42 +#define HB_SOCKET_ERR_RESTARTSYS 43 +#define HB_SOCKET_ERR_NOSR 44 +#define HB_SOCKET_ERR_HOSTDOWN 45 +#define HB_SOCKET_ERR_HOSTUNREACH 46 +#define HB_SOCKET_ERR_NOTEMPTY 47 +#define HB_SOCKET_ERR_USERS 48 +#define HB_SOCKET_ERR_DQUOT 49 +#define HB_SOCKET_ERR_STALE 50 +#define HB_SOCKET_ERR_REMOTE 51 +#define HB_SOCKET_ERR_PROCLIM 52 +#define HB_SOCKET_ERR_DISCON 53 +#define HB_SOCKET_ERR_NOMORE 54 +#define HB_SOCKET_ERR_CANCELLED 55 +#define HB_SOCKET_ERR_INVALIDPROCTABLE 56 +#define HB_SOCKET_ERR_INVALIDPROVIDER 57 +#define HB_SOCKET_ERR_PROVIDERFAILEDINIT 58 +#define HB_SOCKET_ERR_REFUSED 59 +#define HB_SOCKET_ERR_SYSNOTREADY 60 +#define HB_SOCKET_ERR_VERNOTSUPPORTED 61 +#define HB_SOCKET_ERR_NOTINITIALISED 62 +#define HB_SOCKET_ERR_TRYAGAIN 63 +#define HB_SOCKET_ERR_HOSTNOTFOUND 64 +#define HB_SOCKET_ERR_NORECOVERY 65 +#define HB_SOCKET_ERR_NODATA 66 +#define HB_SOCKET_ERR_SYSCALLFAILURE 67 +#define HB_SOCKET_ERR_SERVICENOTFOUND 68 +#define HB_SOCKET_ERR_TYPENOTFOUND 69 +#define HB_SOCKET_ERR_OTHER 70 + + +/* protocol family */ +#define HB_SOCK_PF_LOCAL 1 +#define HB_SOCK_PF_INET 2 +#define HB_SOCK_PF_IPX 4 +#define HB_SOCK_PF_INET6 10 +#define HB_SOCK_PF_PACKET 17 + +/* address familly */ +#define HB_SOCK_AF_LOCAL HB_SOCK_PF_LOCAL +#define HB_SOCK_AF_INET HB_SOCK_PF_INET +#define HB_SOCK_AF_IPX HB_SOCK_PF_IPX +#define HB_SOCK_AF_INET6 HB_SOCK_PF_INET6 +#define HB_SOCK_AF_PACKET HB_SOCK_PF_PACKET + +/* protocol type */ +#define HB_SOCK_STREAM 1 +#define HB_SOCK_DGRAM 2 +#define HB_SOCK_RAW 3 +#define HB_SOCK_RDM 4 +#define HB_SOCK_SEQPACKET 5 + +/* IP protocols */ +#define HB_SOCK_IPPROTO_IP 0 /* Dummy protocol for TCP */ +#define HB_SOCK_IPPROTO_ICMP 1 /* Internet Control Message Protocol */ +#define HB_SOCK_IPPROTO_IGMP 2 /* Internet Group Management Protocol */ +#define HB_SOCK_IPPROTO_IPIP 4 /* IPIP tunnels (older KA9Q tunnels use 94) */ +#define HB_SOCK_IPPROTO_TCP 6 /* Transmission Control Protocol */ +#define HB_SOCK_IPPROTO_EGP 8 /* Exterior Gateway Protocol */ +#define HB_SOCK_IPPROTO_PUP 12 /* PUP protocol */ +#define HB_SOCK_IPPROTO_UDP 17 /* User Datagram Protocol */ +#define HB_SOCK_IPPROTO_IDP 22 /* XNS IDP protocol */ +#define HB_SOCK_IPPROTO_DCCP 23 /* DCCP protocol */ +#define HB_SOCK_IPPROTO_RDP 29 /* RDP */ +#define HB_SOCK_IPPROTO_TP 29 /* SO Transport Protocol Class 4 */ +#define HB_SOCK_IPPROTO_IPV6 41 /* IPv6 header */ +#define HB_SOCK_IPPROTO_ROUTING 43 /* IPv6 routing header */ +#define HB_SOCK_IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */ +#define HB_SOCK_IPPROTO_RSVP 46 /* Reservation Protocol */ +#define HB_SOCK_IPPROTO_GRE 47 /* General Routing Encapsulation */ +#define HB_SOCK_IPPROTO_ESP 50 /* Encapsulating security payload */ +#define HB_SOCK_IPPROTO_AH 51 /* Authentication header */ +#define HB_SOCK_IPPROTO_ICMPV6 58 /* ICMP v6 */ +#define HB_SOCK_IPPROTO_NONE 59 /* IPv6 no next header */ +#define HB_SOCK_IPPROTO_DSTOPTS 60 /* IPv6 destination options */ +#define HB_SOCK_IPPROTO_ND 77 /* ND */ +#define HB_SOCK_IPPROTO_ICLFXBM 78 /* ICLFXBM */ +#define HB_SOCK_IPPROTO_EON 80 /* EON */ +#define HB_SOCK_IPPROTO_MTP 92 /* Multicast Transport Protocol */ +#define HB_SOCK_IPPROTO_ENCAP 98 /* Encapsulation Header */ +#define HB_SOCK_IPPROTO_PIM 103 /* Protocol Independent Multicast */ +#define HB_SOCK_IPPROTO_COMP 108 /* Compression Header Protocol */ +#define HB_SOCK_IPPROTO_PGM 113 /* PGM */ +#define HB_SOCK_IPPROTO_L2TP 115 /* L2TP */ +#define HB_SOCK_IPPROTO_SCTP 132 /* Stream Control Transmission Protocol */ +#define HB_SOCK_IPPROTO_RAW 255 /* Raw IP packets */ + +/* shutdown actions */ +#define HB_SOCK_SHUT_RD 0 +#define HB_SOCK_SHUT_WR 1 +#define HB_SOCK_SHUT_RDWR 2 + + +#endif /* HB_SOCK_CH_ */ diff --git a/harbour/include/hbsocket.h b/harbour/include/hbsocket.h new file mode 100644 index 0000000000..487589d56b --- /dev/null +++ b/harbour/include/hbsocket.h @@ -0,0 +1,119 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * socket C API + * + * Copyright 2009 Przemyslaw Czerpak + * 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. + * + */ + +#ifndef HB_SOCK_H_ +#define HB_SOCK_H_ + +#include "hbapi.h" +#include "hbsocket.ch" + +HB_EXTERN_BEGIN + +#if defined( HB_OS_WIN ) && ! defined( HB_OS_UNIX_COMPATIBLE ) + typedef HB_PTRUINT HB_SOCKET_T; +#else + typedef int HB_SOCKET_T; +#endif + +typedef HB_SOCKET_T ( * HB_SOCK_FUNC )( PHB_ITEM ); + +#define HB_NO_SOCKET ( ( HB_SOCKET_T ) -1 ) + +HB_EXPORT extern int hb_socketInit( void ); +HB_EXPORT extern void hb_socketCleanup( void ); +HB_EXPORT extern int hb_socketGetError( void ); +HB_EXPORT extern int hb_socketGetOsError( void ); +HB_EXPORT extern const char * hb_socketErrorStr( int iError ); +HB_EXPORT extern int hb_socketGetAddrFamilly( const void * pSockAddr, unsigned len ); +HB_EXPORT extern BOOL hb_socketLocalAddr( void ** pSockAddr, unsigned * puiLen, const char * szAddr ); +HB_EXPORT extern BOOL hb_socketInetAddr( void ** pSockAddr, unsigned * puiLen, const char * szAddr, int iPort ); +HB_EXPORT extern BOOL hb_socketInet6Addr( void ** pSockAddr, unsigned * puiLen, const char * szAddr, int iPort ); +HB_EXPORT extern char * hb_socketAddrGetName( const void * pSockAddr, unsigned len ); +HB_EXPORT extern char * hb_socketResolveAddr( const char * szAddr, int af ); +HB_EXPORT extern PHB_ITEM hb_socketGetHosts( const char * szAddr, int af ); +HB_EXPORT extern PHB_ITEM hb_socketGetAliases( const char * szAddr, int af ); +HB_EXPORT extern int hb_socketAddrGetPort( const void * pSockAddr, unsigned len ); +HB_EXPORT extern BOOL hb_socketAddrFromItem( void ** pSockAddr, unsigned * puiLen, PHB_ITEM pAddrItm ); +HB_EXPORT extern PHB_ITEM hb_socketAddrToItem( const void * pSockAddr, unsigned len ); +HB_EXPORT extern int hb_socketGetSockName( HB_SOCKET_T sd, void ** pSockAddr, unsigned * puiLen ); +HB_EXPORT extern int hb_socketGetPeerName( HB_SOCKET_T sd, void ** pSockAddr, unsigned * puiLen ); +HB_EXPORT extern HB_SOCKET_T hb_socketOpen( int domain, int type, int protocol ); +HB_EXPORT extern int hb_socketClose( HB_SOCKET_T sd ); +HB_EXPORT extern int hb_socketShutdown( HB_SOCKET_T sd, int iMode ); +HB_EXPORT extern int hb_socketBind( HB_SOCKET_T sd, const void * pSockAddr, unsigned uiLen ); +HB_EXPORT extern int hb_socketListen( HB_SOCKET_T sd, int iBacklog ); +HB_EXPORT extern HB_SOCKET_T hb_socketAccept( HB_SOCKET_T sd, void ** pSockAddr, unsigned * puiLen, HB_LONG timeout ); +HB_EXPORT extern int hb_socketConnect( HB_SOCKET_T sd, const void * pSockAddr, unsigned uiLen, HB_LONG timeout ); +HB_EXPORT extern long hb_socketSend( HB_SOCKET_T sd, const void * data, long len, int flags, HB_LONG timeout ); +HB_EXPORT extern long hb_socketSendTo( HB_SOCKET_T sd, const void * data, long len, int flags, const void * pSockAddr, unsigned uiSockLen, HB_LONG timeout ); +HB_EXPORT extern long hb_socketRecv( HB_SOCKET_T sd, void * data, long len, int flags, HB_LONG timeout ); +HB_EXPORT extern long hb_socketRecvFrom( HB_SOCKET_T sd, void * data, long len, int flags, void ** pSockAddr, unsigned * puiSockLen, HB_LONG timeout ); +HB_EXPORT extern int hb_socketSetBlockingIO( HB_SOCKET_T sd, BOOL fBlocking ); +HB_EXPORT extern int hb_socketSetReuseAddr( HB_SOCKET_T sd, BOOL fReuse ); +HB_EXPORT extern int hb_socketSetKeepAlive( HB_SOCKET_T sd, BOOL fKeepAlive ); +HB_EXPORT extern int hb_socketSetBroadcast( HB_SOCKET_T sd, BOOL fBroadcast ); +HB_EXPORT extern int hb_socketSetSndBufSize( HB_SOCKET_T sd, int iSize ); +HB_EXPORT extern int hb_socketSetRcvBufSize( HB_SOCKET_T sd, int iSize ); +HB_EXPORT extern int hb_socketGetRcvBufSize( HB_SOCKET_T sd, int * piSize ); +HB_EXPORT extern int hb_socketGetSndBufSize( HB_SOCKET_T sd, int * piSize ); +HB_EXPORT extern int hb_socketSetMulticast( HB_SOCKET_T sd, int af, const char * szAddr ); +HB_EXPORT extern int hb_socketSelectRead( HB_SOCKET_T sd, HB_LONG timeout ); +HB_EXPORT extern int hb_socketSelectWrite( HB_SOCKET_T sd, HB_LONG timeout ); +HB_EXPORT extern int hb_socketSelectWriteEx( HB_SOCKET_T sd, HB_LONG timeout ); +HB_EXPORT extern int hb_socketSelect( PHB_ITEM pArrayRD, BOOL fSetRD, + PHB_ITEM pArrayWR, BOOL fSetWR, + PHB_ITEM pArrayEX, BOOL fSetEX, + HB_LONG timeout, HB_SOCK_FUNC pFunc ); + +HB_EXTERN_END + +#endif /* HB_SOCK_H_ */ diff --git a/harbour/include/hbstack.h b/harbour/include/hbstack.h index 93527d30fe..3be5d4c2be 100644 --- a/harbour/include/hbstack.h +++ b/harbour/include/hbstack.h @@ -93,6 +93,8 @@ typedef struct USHORT uiFError; USHORT uiErrorLast; USHORT uiOsErrorLast; + USHORT uiSocketError; + int iSocketOsError; } HB_IOERRORS, * PHB_IOERRORS; diff --git a/harbour/source/pp/ppcore.c b/harbour/source/pp/ppcore.c index 422dab3f4b..45d8b429c2 100644 --- a/harbour/source/pp/ppcore.c +++ b/harbour/source/pp/ppcore.c @@ -789,7 +789,15 @@ static BOOL hb_pp_hasCommand( char * pBuffer, ULONG ulLen, ULONG * pulAt, int iC { while( ul < ulLen && HB_PP_ISBLANK( pBuffer[ ul ] ) ) ++ul; - if( ul == ulLen || pBuffer[ ul ] == ';' ) + + if( ul + 1 < ulLen && + ( pBuffer[ ul ] == '/' || pBuffer[ ul ] == '&' ) && + pBuffer[ ul ] == pBuffer[ ul + 1 ] ) + /* strip the rest of line with // or && comment */ + ul = ulLen; + + if( ul == ulLen || pBuffer[ ul ] == ';' || + ( ul + 1 < ulLen && pBuffer[ ul ] == '/' && pBuffer[ ul + 1 ] == '*' ) ) { * pulAt = ul; return TRUE; diff --git a/harbour/source/rtl/Makefile b/harbour/source/rtl/Makefile index 98ee668b1f..edf5cc082a 100644 --- a/harbour/source/rtl/Makefile +++ b/harbour/source/rtl/Makefile @@ -85,6 +85,7 @@ C_SOURCES=\ hbsha1hm.c \ hbsha2.c \ hbsha2hm.c \ + hbsocket.c \ hbstrfmt.c \ hbstrsh.c \ hbtoken.c \ diff --git a/harbour/source/rtl/hbi18n1.c b/harbour/source/rtl/hbi18n1.c index 7a05a8ae87..2c376adb3e 100644 --- a/harbour/source/rtl/hbi18n1.c +++ b/harbour/source/rtl/hbi18n1.c @@ -584,8 +584,8 @@ static const char * hb_i18n_setcodepage( PHB_I18N_TRANS pI18N, { if( fTranslate && cdpage ) { - ULONG ulLen = hb_hashLen( pI18N->context_table ), ul; - for( ul = 1; ul <= ulLen; ++ul ) + ULONG ulHashLen = hb_hashLen( pI18N->context_table ), ul; + for( ul = 1; ul <= ulHashLen; ++ul ) { PHB_ITEM pContext = hb_hashGetValueAt( pI18N->context_table, ul ); ULONG ulCount = hb_hashLen( pContext ), ulLen, u; diff --git a/harbour/source/rtl/hbinet.c b/harbour/source/rtl/hbinet.c index e4d825df57..3fbdf862b0 100644 --- a/harbour/source/rtl/hbinet.c +++ b/harbour/source/rtl/hbinet.c @@ -62,173 +62,66 @@ #include "hbapi.h" #include "hbapiitm.h" -#include "hbapinet.h" +#include "hbsocket.h" #include "hbapierr.h" #include "hbvm.h" -/* Compile in Unix mode under Cygwin */ -#if defined( HB_OS_UNIX_COMPATIBLE ) - #undef HB_OS_WIN -#endif +typedef struct _HB_SOCKET +{ + HB_SOCKET_T com; + void * remote; + unsigned remotelen; + char szErrorText[ 128 ]; + const char * pszErrorText; + int iErrorCode; + int iCount; + int iTimeout; + int iTimeLimit; + PHB_ITEM pPeriodicBlock; +} HB_SOCKET, * PHB_SOCKET; -/* HB_INET_H_ */ -#if defined( HB_OS_DOS ) +#define HB_PARSOCKET( n ) ( ( PHB_SOCKET ) hb_parptrGC( hb_inetSocketFinalize, n ) ) - #ifndef HB_NO_DEFAULT_INET - #define HB_NO_DEFAULT_INET - #endif - -#else - - #include - - #if defined( HB_OS_WIN ) - #define HB_INET_CLOSE( x ) closesocket( x ) - #else - - #if defined( HB_OS_HPUX ) - #define _XOPEN_SOURCE_EXTENDED - #endif - - #if ! defined( h_errno ) - #if defined( __WATCOMC__ ) - #define h_errno errno - #else - extern int h_errno; - #endif - #endif - #define HB_INET_CLOSE( x ) close( x ) - #endif - - #define HB_PARSOCKET( n ) ( ( PHB_SOCKET ) hb_parptrGC( hb_inetSocketFinalize, n ) ) - - #define HB_SOCKET_ZERO_ERROR( s ) \ - do { \ - s->iErrorCode = 0; \ - s->pszErrorText = ""; \ - } while( 0 ) - - #if defined( HB_OS_WIN ) - #if defined( _MSC_VER ) && _MSC_VER >= 1400 - #define HB_SOCKET_SET_ERROR( s ) \ - do { \ - s->iErrorCode = WSAGetLastError(); \ - strerror_s( s->szErrorText, sizeof( s->szErrorText ), s->iErrorCode ); \ - s->pszErrorText = s->szErrorText; \ - WSASetLastError( 0 ); \ - } while( 0 ) - #else - #define HB_SOCKET_SET_ERROR( s ) \ - do { \ - s->iErrorCode = WSAGetLastError(); \ - s->pszErrorText = strerror( s->iErrorCode ); \ - WSASetLastError( 0 ); \ - } while( 0 ) - #endif - #else - #define HB_SOCKET_SET_ERROR( s ) \ +#define HB_SOCKET_ZERO_ERROR( s ) \ do { \ - s->iErrorCode = errno; \ - s->pszErrorText = strerror( errno ); \ + s->iErrorCode = 0; \ + s->pszErrorText = ""; \ } while( 0 ) - #endif - #if defined( _MSC_VER ) && _MSC_VER >= 1400 - #define HB_SOCKET_SET_ERROR1( s, code ) \ +#define HB_SOCKET_SET_ERROR( s ) \ + do { \ + s->iErrorCode = hb_socketGetError(); \ + s->pszErrorText = hb_socketErrorStr( s->iErrorCode ); \ + } while( 0 ) + +#define HB_SOCKET_SET_ERROR1( s, code ) \ do { \ s->iErrorCode = code; \ - strerror_s( s->szErrorText, sizeof( s->szErrorText ), code ); \ - s->pszErrorText = s->szErrorText; \ + s->pszErrorText = hb_socketErrorStr( code ); \ } while( 0 ) - #else - #define HB_SOCKET_SET_ERROR1( s, code ) \ + +#define HB_SOCKET_SET_ERROR2( s, code, desc ) \ do { \ s->iErrorCode = code; \ - s->pszErrorText = strerror( code ); \ + s->pszErrorText = desc; \ } while( 0 ) - #endif - #define HB_SOCKET_SET_ERROR2( s, code, desc ) \ - do { \ - s->iErrorCode = code; \ - s->pszErrorText = desc; \ - } while( 0 ) - #define HB_SOCKET_INIT( s, p ) \ +#define HB_SOCKET_INIT( s, p ) \ do { \ s = ( PHB_SOCKET ) hb_gcAlloc( sizeof( HB_SOCKET ), hb_inetSocketFinalize ); \ memset( s, '\0', sizeof( HB_SOCKET ) ); \ - s->com = ( HB_SOCKET_T ) -1; \ + s->com = HB_NO_SOCKET; \ s->iTimeout = -1; \ s->iTimeLimit = -1; \ s->pszErrorText = ""; \ p = hb_itemPutPtrGC( p, s ); \ } while( 0 ) - #ifndef MSG_NOSIGNAL - #define MSG_NOSIGNAL 0 - #endif - - #ifndef MSG_DONTWAIT - /* #define MSG_DONTWAIT 0x80 */ - #define MSG_DONTWAIT 0 - #endif - - #ifndef MSG_WAITALL - #define MSG_WAITALL 0 - #endif - -#endif -/* HB_INET_H_ */ - - -#if !defined( HB_NO_DEFAULT_INET ) - -#if !defined( HB_OS_WIN_CE ) - #include - #include -#endif - -#if defined( HB_OS_UNIX ) || defined( HB_OS_UNIX_COMPATIBLE ) || defined( HB_OS_OS2 ) - #include -#endif - - -#if defined( HB_OS_OS2 ) || defined( HB_OS_WIN ) - /* NET_SIZE_T exists because of shortsightedness on the POSIX committee. BSD - * systems used "int *" as the parameter to accept(), getsockname(), - * getpeername() et al. Consequently many unixes took an int * for that - * parameter. The POSIX committee decided that "int" was just too generic and - * had to be replaced with size_t almost everywhere. There's no problem with - * that when you're passing by value. But when you're passing by reference - * this creates a gross source incompatibility with existing programs. On - * 32-bit architectures it creates only a warning. On 64-bit architectures it - * creates broken code -- because "int *" is a pointer to a 32-bit quantity and - * "size_t *" is frequently a pointer to a 64-bit quantity. - * - * Some Unixes adopted "size_t *" for the sake of POSIX compliance. Others - * ignored it because it was such a broken interface. Chaos ensued. POSIX - * finally woke up and decided that it was wrong and created a new type - * socklen_t. The only useful value for socklen_t is int, and that's how - * everyone who has a clue implements it. It is almost always the case that - * NET_SIZE_T should be defined to be an int, unless the system being compiled - * for was created in the window of POSIX madness. - */ - #define socklen_t int -#endif - -#if defined( __POCC__ ) && ( __POCC__ >= 500 ) && defined( HB_OS_WIN_64 ) - /* TOFIX: Bad workaround for the '__WSAFDIsSet unresolved' problem - in Pelles C 5.00.13 AMD64 mode, to make final executables - link at all. Some hbinet.c features (or the whole module) - won't properly work though. [vszakats] */ - #undef FD_ISSET - #define FD_ISSET( s, f ) ( 0 ) -#endif - #if defined( HB_OS_LINUX ) -#include /* #define HB_INET_LINUX_INTERRUPT SIGUSR1 + 90 */ # ifdef HB_INET_LINUX_INTERRUPT +# include + static void hb_inetLinuxSigusrHandle( int sig ) { /* nothing to do */ @@ -239,12 +132,9 @@ static void hb_inetLinuxSigusrHandle( int sig ) static const char * s_inetCRLF = "\r\n"; -/* JC1: we need it volatile to be minimally thread safe. */ -static volatile int s_iSessions = 0; - static BOOL hb_inetIsOpen( PHB_SOCKET Socket ) { - if( Socket->com == ( HB_SOCKET_T ) -1 ) + if( Socket->com == HB_NO_SOCKET ) { HB_SOCKET_SET_ERROR2( Socket, -4, "Closed socket" ); return FALSE; @@ -252,318 +142,29 @@ static BOOL hb_inetIsOpen( PHB_SOCKET Socket ) return TRUE; } -int hb_selectReadFD( HB_SOCKET_T fd, int iTimeout ) +static int hb_inetConnect( PHB_SOCKET Socket ) { - fd_set set; - struct timeval tv; - int iResult; + int iErr; - hb_vmUnlock(); + hb_socketSetKeepAlive( Socket->com, TRUE ); - FD_ZERO( &set ); - FD_SET( fd, &set ); + iErr = hb_socketConnect( Socket->com, Socket->remote, Socket->remotelen, + Socket->iTimeout ); + if( iErr != 0 ) + HB_SOCKET_SET_ERROR( Socket ); - if( iTimeout == -1 ) - iResult = select( fd + 1, &set, NULL, NULL, NULL ); - else - { - tv.tv_sec = iTimeout / 1000; - tv.tv_usec = ( iTimeout % 1000 ) * 1000; - iResult = select( fd + 1, &set, NULL, NULL, &tv ); - } - - hb_vmLock(); - - return iResult > 0 ? FD_ISSET( fd, &set ) : 0; + return iErr == 0; } -int hb_selectWriteFD( HB_SOCKET_T fd, int iTimeout ) -{ - fd_set set; - struct timeval tv; - int iResult; - - hb_vmUnlock(); - - FD_ZERO( &set ); - FD_SET( fd, &set ); - - if( iTimeout == -1 ) - iResult = select( fd + 1, NULL, &set, NULL, NULL ); - else - { - tv.tv_sec = iTimeout / 1000; - tv.tv_usec = ( iTimeout % 1000 ) * 1000; - iResult = select( fd + 1, NULL, &set, NULL, &tv ); - } - - hb_vmLock(); - - return iResult > 0 ? FD_ISSET( fd, &set ) : 0; -} - -/* Useful utility function to have a timeout; */ - -int hb_selectReadSocket( PHB_SOCKET Socket ) -{ - fd_set set; - struct timeval tv; - int iResult; - - hb_vmUnlock(); - - FD_ZERO( &set ); - FD_SET( Socket->com, &set ); - - if( Socket->iTimeout == -1 ) - iResult = select( Socket->com + 1, &set, NULL, NULL, NULL ); - else - { - tv.tv_sec = Socket->iTimeout / 1000; - tv.tv_usec = ( Socket->iTimeout % 1000 ) * 1000; - iResult = select( Socket->com + 1, &set, NULL, NULL, &tv ); - } - - hb_vmLock(); - - return iResult > 0 ? FD_ISSET( Socket->com, &set ) : 0; -} - -int hb_selectWriteSocket( PHB_SOCKET Socket ) -{ - fd_set set; - struct timeval tv; - int iResult; - - hb_vmUnlock(); - - FD_ZERO( &set ); - FD_SET( Socket->com, &set ); - - if( Socket->iTimeout == -1 ) - iResult = select( Socket->com + 1, NULL, &set, NULL, NULL ); - else - { - tv.tv_sec = Socket->iTimeout / 1000; - tv.tv_usec = ( Socket->iTimeout % 1000 ) * 1000; - iResult = select( Socket->com + 1, NULL, &set, NULL, &tv ); - } - - hb_vmLock(); - - return iResult > 0 ? FD_ISSET( Socket->com, &set ) : 0; -} - -#if defined( HB_OS_WIN ) -static int hb_selectWriteExceptSocket( PHB_SOCKET Socket ) -{ - fd_set set, eset; - struct timeval tv; - int iResult; - - hb_vmUnlock(); - - FD_ZERO( &set ); - FD_SET( Socket->com, &set ); - FD_ZERO( &eset ); - FD_SET( Socket->com, &eset ); - - if( Socket->iTimeout == -1 ) - iResult = select( Socket->com + 1, NULL, &set, &eset, NULL ); - else - { - tv.tv_sec = Socket->iTimeout / 1000; - tv.tv_usec = ( Socket->iTimeout % 1000 ) * 1000; - iResult = select( Socket->com + 1, NULL, &set, &eset, &tv ); - } - - hb_vmLock(); - - if( iResult < 0 || FD_ISSET( Socket->com, &eset) ) - return 2; - else if( FD_ISSET( Socket->com, &set ) ) - return 1; - else - return 0; -} -#endif - -/*** Utilty to access host DNS */ -static struct hostent * hb_getHosts( const char * name, PHB_SOCKET Socket ) -{ - struct hostent * Host = NULL; - - hb_vmUnlock(); - - /* TOFIX: make it MT safe */ - - /* let's see if name is an IP address; not necessary on Linux */ -#if defined( HB_OS_WIN ) || defined( HB_OS_OS2 ) - { - ULONG ulAddr; - - ulAddr = inet_addr( name ); - if( ulAddr == INADDR_NONE ) - { - if( strcmp( "255.255.255.255", name ) == 0 ) - Host = gethostbyaddr( ( const char * ) &ulAddr, sizeof( ulAddr ), AF_INET ); - } - else - Host = gethostbyaddr( ( const char * ) &ulAddr, sizeof( ulAddr ), AF_INET ); - } -#endif - - if( Host == NULL ) - Host = gethostbyname( name ); - - if( Host == NULL && Socket ) - { -#if defined( HB_OS_WIN ) - HB_SOCKET_SET_ERROR2( Socket, WSAGetLastError() , "Generic error in gethostbyname()" ); - WSASetLastError( 0 ); -#elif defined( HB_OS_OS2 ) || defined( HB_OS_HPUX ) || defined( __WATCOMC__ ) - HB_SOCKET_SET_ERROR2( Socket, h_errno, "Generic error in gethostbyname()" ); -#else - HB_SOCKET_SET_ERROR2( Socket, h_errno, ( char * ) hstrerror( h_errno ) ); -#endif - } - - hb_vmLock(); - - return Host; -} - - -/*** Setup the non-blocking method **/ - -static void hb_socketSetNonBlocking( PHB_SOCKET Socket ) -{ -#if defined( HB_OS_WIN ) - u_long mode = 1; - ioctlsocket( Socket->com, FIONBIO, &mode ); -#elif defined( O_NONBLOCK ) - int flags = fcntl( Socket->com, F_GETFL, 0 ); - if( flags != -1 ) - { - flags |= O_NONBLOCK; - fcntl( Socket->com, F_SETFL, ( long ) flags ); - } -#else - HB_SYMBOL_UNUSED( Socket ); -#endif -} - - -/*** Setup the blocking method **/ - -static void hb_socketSetBlocking( PHB_SOCKET Socket ) -{ -#if defined( HB_OS_WIN ) - u_long mode = 0; - ioctlsocket( Socket->com, FIONBIO, &mode ); -#elif defined( O_NONBLOCK ) - int flags = fcntl( Socket->com, F_GETFL, 0 ); - if( flags != -1 ) - { - flags &= ~O_NONBLOCK; - fcntl( Socket->com, F_SETFL, ( long ) flags ); - } -#else - HB_SYMBOL_UNUSED( Socket ); -#endif -} - -/*** Utility to connect to a defined remote address ***/ - -static int hb_socketConnect( PHB_SOCKET Socket ) -{ - int iErr1; - #if ! defined( HB_OS_WIN ) - int iErrval; - socklen_t iErrvalLen; - #endif - int iOpt = 1; - - hb_vmUnlock(); - - setsockopt( Socket->com, SOL_SOCKET, SO_KEEPALIVE, ( const char * ) &iOpt, sizeof( iOpt ) ); - - /* we'll be using a nonblocking function */ - hb_socketSetNonBlocking( Socket ); - - iErr1 = connect( Socket->com, ( struct sockaddr * ) ( void * ) &Socket->remote, sizeof( Socket->remote ) ); - if( iErr1 != 0 ) - { -#if defined( HB_OS_WIN ) - if( WSAGetLastError() != WSAEWOULDBLOCK ) -#else - if( errno != EINPROGRESS ) -#endif - { - HB_SOCKET_SET_ERROR( Socket ); - } - else - { - /* Now we wait for socket connection or timeout */ - -#if defined( HB_OS_WIN ) - iErr1 = hb_selectWriteExceptSocket( Socket ); - if( iErr1 == 2 ) - { - HB_SOCKET_SET_ERROR2( Socket, 2, "Connection failed" ); - } - else if( iErr1 == 1 ) - { - /* success */ - } -#else - if( hb_selectWriteSocket( Socket ) ) - { - /* Connection has been completed with a failure or a success */ - iErrvalLen = sizeof( iErrval ); - iErr1 = getsockopt( Socket->com, - SOL_SOCKET, - SO_ERROR, - ( void * ) &iErrval, - &iErrvalLen - ); - - if( iErr1 ) - HB_SOCKET_SET_ERROR1( Socket, iErr1 ); - else if( iErrval ) - HB_SOCKET_SET_ERROR1( Socket, iErrval ); - /* Success! */ - } -#endif - else - HB_SOCKET_SET_ERROR2( Socket, -1, "Timeout" ); - } - } - - hb_socketSetBlocking( Socket ); - - hb_vmLock(); - - return Socket->iErrorCode == 0; -} - - static HB_GARBAGE_FUNC( hb_inetSocketFinalize ) { PHB_SOCKET Socket = ( PHB_SOCKET ) Cargo; - if( Socket->com != ( HB_SOCKET_T ) -1 ) + if( Socket->com != HB_NO_SOCKET ) { - #if defined( HB_OS_WIN ) - shutdown( Socket->com, SD_BOTH ); - #elif defined( HB_OS_OS2 ) - shutdown( Socket->com, SO_RCV_SHUTDOWN + SO_SND_SHUTDOWN ); - #elif !defined( __WATCOMC__ ) - shutdown( Socket->com, SHUT_RDWR ); - #endif - - HB_INET_CLOSE( Socket->com ); - Socket->com = ( HB_SOCKET_T ) -1; + hb_socketShutdown( Socket->com, HB_SOCK_SHUT_RDWR ); + hb_socketClose( Socket->com ); + Socket->com = HB_NO_SOCKET; } if( Socket->pPeriodicBlock ) @@ -571,6 +172,11 @@ static HB_GARBAGE_FUNC( hb_inetSocketFinalize ) hb_itemRelease( Socket->pPeriodicBlock ); Socket->pPeriodicBlock = NULL; } + if( Socket->remote ) + { + hb_xfree( Socket->remote ); + Socket->remote = NULL; + } } /***************************************************** @@ -579,29 +185,15 @@ static HB_GARBAGE_FUNC( hb_inetSocketFinalize ) HB_FUNC( HB_INETINIT ) { - if( s_iSessions ) - s_iSessions++; - else - { - #if defined( HB_OS_WIN ) - #define HB_MKWORD( l, h ) ((WORD)(((BYTE)(l)) | (((WORD)((BYTE)(h))) << 8))) - WSADATA wsadata; - WSAStartup( HB_MKWORD( 1, 1 ), &wsadata ); - #elif defined( HB_INET_LINUX_INTERRUPT ) - signal( HB_INET_LINUX_INTERRUPT, hb_inetLinuxSigusrHandle ); - #endif - s_iSessions = 1; - } + hb_socketInit(); +#if defined( HB_INET_LINUX_INTERRUPT ) + signal( HB_INET_LINUX_INTERRUPT, hb_inetLinuxSigusrHandle ); +#endif } HB_FUNC( HB_INETCLEANUP ) { - if( --s_iSessions == 0 ) - { - #if defined( HB_OS_WIN ) - WSACleanup(); - #endif - } + hb_socketCleanup(); } /***************************************************** @@ -626,26 +218,15 @@ HB_FUNC( HB_INETCLOSE ) if( Socket ) { - if( Socket->com != ( HB_SOCKET_T ) -1 ) + if( Socket->com != HB_NO_SOCKET ) { - hb_vmUnlock(); + hb_socketShutdown( Socket->com, HB_SOCK_SHUT_RDWR ); + hb_retni( hb_socketClose( Socket->com ) ); + Socket->com = HB_NO_SOCKET; - #if defined( HB_OS_WIN ) - shutdown( Socket->com, SD_BOTH ); - #elif defined( HB_OS_OS2 ) - shutdown( Socket->com, SO_RCV_SHUTDOWN + SO_SND_SHUTDOWN ); - #elif !defined( __WATCOMC__ ) - shutdown( Socket->com, SHUT_RDWR ); - #endif - - hb_retni( HB_INET_CLOSE( Socket->com ) ); - Socket->com = ( HB_SOCKET_T ) -1; - - #ifdef HB_INET_LINUX_INTERRUPT - kill( 0, HB_INET_LINUX_INTERRUPT ); - #endif - - hb_vmLock(); +#ifdef HB_INET_LINUX_INTERRUPT + kill( 0, HB_INET_LINUX_INTERRUPT ); +#endif } else hb_retni( -1 ); @@ -663,7 +244,7 @@ HB_FUNC( HB_INETFD ) hb_retnint( Socket->com ); if( hb_parl( 2 ) ) - Socket->com = ( HB_SOCKET_T ) -1; + Socket->com = HB_NO_SOCKET; } else hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); @@ -678,7 +259,7 @@ HB_FUNC( HB_INETSTATUS ) PHB_SOCKET Socket = HB_PARSOCKET( 1 ); if( Socket ) - hb_retni( Socket->com == ( HB_SOCKET_T ) -1 ? -1 : 1 ); /* TODO: hb_retni( Socket->status ); */ + hb_retni( Socket->com == HB_NO_SOCKET ? -1 : 1 ); /* TODO: hb_retni( Socket->status ); */ else hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } @@ -749,7 +330,14 @@ HB_FUNC( HB_INETADDRESS ) PHB_SOCKET Socket = HB_PARSOCKET( 1 ); if( Socket ) - hb_retc( inet_ntoa( Socket->remote.sin_addr ) ); + { + char * szAddr = Socket->remote ? + hb_socketAddrGetName( Socket->remote, Socket->remotelen ) : NULL; + if( szAddr ) + hb_retc_buffer( szAddr ); + else + hb_retc_null(); + } else hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } @@ -759,12 +347,12 @@ HB_FUNC( HB_INETPORT ) PHB_SOCKET Socket = HB_PARSOCKET( 1 ); if( Socket ) - hb_retni( ntohs( Socket->remote.sin_port ) ); + hb_retni( Socket->remote ? + hb_socketAddrGetPort( Socket->remote, Socket->remotelen ) : 0 ); else hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } - HB_FUNC( HB_INETTIMEOUT ) { PHB_SOCKET Socket = HB_PARSOCKET( 1 ); @@ -859,19 +447,13 @@ HB_FUNC( HB_INETGETSNDBUFSIZE ) if( Socket ) { + int iSize = -1; if( hb_inetIsOpen( Socket ) ) { - int value; - socklen_t len = sizeof( value ); -#if defined( HB_OS_WIN ) - getsockopt( Socket->com, SOL_SOCKET, SO_SNDBUF, ( char * ) &value, &len ); -#else - getsockopt( Socket->com, SOL_SOCKET, SO_SNDBUF, ( void * ) &value, &len ); -#endif - hb_retni( value ); + if( hb_socketGetSndBufSize( Socket->com, &iSize ) != 0 ) + iSize = -1; } - else - hb_retni( -1 ); + hb_retni( iSize ); } else hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); @@ -883,19 +465,13 @@ HB_FUNC( HB_INETGETRCVBUFSIZE ) if( Socket ) { + int iSize = -1; if( hb_inetIsOpen( Socket ) ) { - int value; - socklen_t len = sizeof( value ); -#if defined( HB_OS_WIN ) - getsockopt( Socket->com, SOL_SOCKET, SO_RCVBUF, ( char * ) &value, &len ); -#else - getsockopt( Socket->com, SOL_SOCKET, SO_RCVBUF, ( void * ) &value, &len ); -#endif - hb_retni( value ); + if( hb_socketGetRcvBufSize( Socket->com, &iSize ) != 0 ) + iSize = -1; } - else - hb_retni( -1 ); + hb_retni( iSize ); } else hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); @@ -907,18 +483,13 @@ HB_FUNC( HB_INETSETSNDBUFSIZE ) if( Socket ) { + int iSize = -1; if( hb_inetIsOpen( Socket ) ) { - int value = hb_parni( 2 ); -#if defined( HB_OS_WIN ) - setsockopt( Socket->com, SOL_SOCKET, SO_SNDBUF, ( char * ) &value, sizeof( value ) ); -#else - setsockopt( Socket->com, SOL_SOCKET, SO_SNDBUF, ( void * ) &value, sizeof( value ) ); -#endif - hb_retni( value ); + iSize = hb_parni( 2 ); + hb_socketSetSndBufSize( Socket->com, iSize ); } - else - hb_retni( -1 ); + hb_retni( iSize ); } else hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); @@ -930,18 +501,13 @@ HB_FUNC( HB_INETSETRCVBUFSIZE ) if( Socket ) { + int iSize = -1; if( hb_inetIsOpen( Socket ) ) { - int value = hb_parni( 2 ); -#if defined( HB_OS_WIN ) - setsockopt( Socket->com, SOL_SOCKET, SO_RCVBUF, ( char * ) &value, sizeof( value ) ); -#else - setsockopt( Socket->com, SOL_SOCKET, SO_RCVBUF, ( void * ) &value, sizeof( value ) ); -#endif - hb_retni( value ); + iSize = hb_parni( 2 ); + hb_socketSetRcvBufSize( Socket->com, iSize ); } - else - hb_retni( -1 ); + hb_retni( iSize ); } else hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); @@ -990,31 +556,27 @@ static void s_inetRecvInternal( int iMode ) else iMaxLen = iLen; - hb_vmUnlock(); - iReceived = 0; iTimeElapsed = 0; HB_SOCKET_ZERO_ERROR( Socket ); do { - if( hb_selectReadSocket( Socket ) ) + iLen = hb_socketRecv( Socket->com, buffer + iReceived, iMaxLen - iReceived, + 0, Socket->iTimeout ); + if( iLen >= 0 ) { - iLen = recv( Socket->com, buffer + iReceived, iMaxLen - iReceived, MSG_NOSIGNAL ); - if( iLen > 0 ) - iReceived += iLen; + iReceived += iLen; /* Called from InetRecv()? */ if( iMode == 0 ) break; } - else + 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; - hb_vmLock(); - /* if we have a pPeriodicBlock, timeLimit is our REAL timeout */ if( Socket->pPeriodicBlock ) { @@ -1038,16 +600,12 @@ static void s_inetRecvInternal( int iMode ) hb_retni( iReceived ); return; } - - hb_vmUnlock(); } } while( iReceived < iMaxLen && iLen > 0 ); Socket->iCount = iReceived; - hb_vmLock(); - if( iLen == 0 ) { HB_SOCKET_SET_ERROR2( Socket, -2, "Connection closed" ); @@ -1084,7 +642,7 @@ static void s_inetRecvPattern( const char * szPattern ) char cChar = '\0'; char * Buffer; int iAllocated, iBufferSize, iMax; - int iLen = 0, iPatLen; + int iLen, iPatLen; int iPos = 0, iTimeElapsed; if( Socket == NULL ) @@ -1101,8 +659,6 @@ static void s_inetRecvPattern( const char * szPattern ) iBufferSize = pBufferSize ? hb_itemGetNI( pBufferSize ) : 80; iMax = pMaxSize ? hb_itemGetNI( pMaxSize ) : 0; - hb_vmUnlock(); - HB_SOCKET_ZERO_ERROR( Socket ); Buffer = ( char * ) hb_xgrab( iBufferSize ); @@ -1118,9 +674,8 @@ static void s_inetRecvPattern( const char * szPattern ) Buffer = ( char * ) hb_xrealloc( Buffer, iAllocated ); } - if( hb_selectReadSocket( Socket ) ) - iLen = recv( Socket->com, &cChar, 1, MSG_NOSIGNAL ); - else + iLen = hb_socketRecv( Socket->com, &cChar, 1, 0, Socket->iTimeout ); + if( iLen == -1 && hb_socketGetError() == HB_SOCKET_ERR_TIMEOUT ) { iTimeElapsed += Socket->iTimeout; @@ -1128,10 +683,8 @@ static void s_inetRecvPattern( const char * szPattern ) { BOOL fResult; - hb_vmLock(); hb_execFromArray( Socket->pPeriodicBlock ); fResult = hb_parl( -1 ) && hb_vmRequestQuery() == 0; - hb_vmUnlock(); /* do we continue? */ if( fResult && @@ -1160,8 +713,6 @@ static void s_inetRecvPattern( const char * szPattern ) } while( iMax == 0 || iPos < iMax ); - hb_vmLock(); - if( iLen <= 0 ) { if( pResult ) @@ -1282,8 +833,6 @@ HB_FUNC( HB_INETRECVENDBLOCK ) iBufferSize = pBufferSize ? hb_itemGetNI( pBufferSize ) : 80; iMax = pMaxSize ? hb_itemGetNI( pMaxSize ) : 0; - hb_vmUnlock(); - HB_SOCKET_ZERO_ERROR( Socket ); Buffer = ( char * ) hb_xgrab( iBufferSize ); @@ -1297,23 +846,16 @@ HB_FUNC( HB_INETRECVENDBLOCK ) Buffer = ( char * ) hb_xrealloc( Buffer, iAllocated ); } - iLen = 0; - - if( hb_selectReadSocket( Socket ) ) - { - iLen = recv( Socket->com, &cChar, 1, MSG_NOSIGNAL ); - } - else + iLen = hb_socketRecv( Socket->com, &cChar, 1, 0, Socket->iTimeout ); + if( iLen == -1 && hb_socketGetError() == HB_SOCKET_ERR_TIMEOUT ) { iTimeElapsed += Socket->iTimeout; if( Socket->pPeriodicBlock ) { BOOL fResult; - hb_vmLock(); hb_execFromArray( Socket->pPeriodicBlock ); fResult = hb_parl( -1 ) && hb_vmRequestQuery() == 0; - hb_vmUnlock(); if( fResult && ( Socket->iTimeLimit == -1 || iTimeElapsed < Socket->iTimeLimit ) ) @@ -1362,8 +904,6 @@ HB_FUNC( HB_INETRECVENDBLOCK ) } while( iMax == 0 || iPos < iMax ); - hb_vmLock(); - if( iLen <= 0 ) { if( pResult ) @@ -1410,8 +950,6 @@ HB_FUNC( HB_INETDATAREADY ) { PHB_SOCKET Socket = HB_PARSOCKET( 1 ); int iVal; - fd_set rfds; - struct timeval tv = { 0, 0 }; if( Socket == NULL || ( hb_pcount() >= 2 && ! HB_ISNUM( 2 ) ) ) { @@ -1424,28 +962,10 @@ HB_FUNC( HB_INETDATAREADY ) return; } - if( HB_ISNUM( 2 ) ) - { - iVal = hb_parni( 2 ); - tv.tv_sec = iVal / 1000; - tv.tv_usec = ( iVal % 1000 ) * 1000; - } - - hb_vmUnlock(); - HB_SOCKET_ZERO_ERROR( Socket ); - - FD_ZERO( &rfds ); - FD_SET( Socket->com, &rfds ); - - iVal = select( Socket->com + 1, &rfds, NULL, NULL, &tv ); - /* Don't rely on the value of tv now! */ - + iVal = hb_socketSelectRead( Socket->com, HB_ISNUM( 2 ) ? hb_parnint( 2 ) : 0 ); if( iVal < 0 ) HB_SOCKET_SET_ERROR( Socket ); - - hb_vmLock(); - hb_retni( iVal ); } @@ -1478,24 +998,19 @@ static void s_inetSendInternal( int iMode ) iSend = iLen; } - hb_vmUnlock(); - HB_SOCKET_ZERO_ERROR( Socket ); iSent = 0; iLen = 0; while( iSent < iSend ) { - if( hb_selectWriteSocket( Socket ) ) - iLen = send( Socket->com, Buffer + iSent, iSend - iSent, MSG_NOSIGNAL ); - else - iLen = 0; - + iLen = hb_socketSend( Socket->com, Buffer + iSent, iSend - iSent, 0, + Socket->iTimeout ); if( iLen > 0 ) { iSent += iLen; } - else if( iLen == 0 ) + else if( iLen == -1 && hb_socketGetError() == HB_SOCKET_ERR_TIMEOUT ) { HB_SOCKET_SET_ERROR2( Socket, -1, "Timeout" ); break; @@ -1512,8 +1027,6 @@ static void s_inetSendInternal( int iMode ) Socket->iCount = iSent; - hb_vmLock(); - hb_retni( iLen > 0 ? iSent : -1 ); } @@ -1538,34 +1051,10 @@ HB_FUNC( HB_INETGETHOSTS ) if( szHost ) { - struct hostent * Host = hb_getHosts( szHost, NULL ); + PHB_ITEM pHosts = hb_socketGetHosts( szHost, HB_SOCK_PF_INET ); - char ** cHosts; - int iCount = 0; - - if( Host ) - { - cHosts = Host->h_addr_list; - while( *cHosts ) - { - iCount++; - cHosts++; - } - } - - if( iCount ) - { - PHB_ITEM pHosts = hb_itemArrayNew( iCount ); - iCount = 0; - cHosts = Host->h_addr_list; - while( *cHosts ) - { - hb_arraySetC( pHosts, ++iCount, - inet_ntoa( *( ( struct in_addr * ) * cHosts ) ) ); - cHosts++; - } + if( pHosts ) hb_itemReturnRelease( pHosts ); - } else hb_reta( 0 ); } @@ -1573,41 +1062,16 @@ HB_FUNC( HB_INETGETHOSTS ) hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } - HB_FUNC( HB_INETGETALIAS ) { const char * szHost = hb_parc( 1 ); if( szHost ) { - struct hostent * Host = hb_getHosts( szHost, NULL ); + PHB_ITEM pHosts = hb_socketGetAliases( szHost, HB_SOCK_PF_INET ); - char ** cHosts; - int iCount = 0; - - if( Host ) - { - cHosts = Host->h_aliases; - while( *cHosts ) - { - iCount++; - cHosts++; - } - } - - if( iCount ) - { - PHB_ITEM pHosts = hb_itemArrayNew( iCount ); - iCount = 0; - cHosts = Host->h_aliases; - while( *cHosts ) - { - hb_arraySetC( pHosts, ++iCount, - inet_ntoa( *( ( struct in_addr * ) * cHosts ) ) ); - cHosts++; - } + if( pHosts ) hb_itemReturnRelease( pHosts ); - } else hb_reta( 0 ); } @@ -1625,9 +1089,7 @@ HB_FUNC( HB_INETSERVER ) PHB_SOCKET Socket = HB_PARSOCKET( 2 ); PHB_ITEM pSocket = NULL; const char * szAddress; - int iPort; - int iOpt = 1; - int iListen; + int iPort, iListen; /* Parameter error checking */ if( ! HB_ISNUM( 1 ) || ( Socket == NULL && ! HB_ISNIL( 2 ) ) ) @@ -1642,13 +1104,8 @@ HB_FUNC( HB_INETSERVER ) HB_SOCKET_INIT( Socket, pSocket ); /* Creates comm socket */ -#if defined( HB_OS_WIN ) - Socket->com = socket( AF_INET, SOCK_STREAM, 0 ); -#else - Socket->com = socket( PF_INET, SOCK_STREAM, 0 ); -#endif - - if( Socket->com == ( HB_SOCKET_T ) -1 ) + Socket->com = hb_socketOpen( HB_SOCK_PF_INET, HB_SOCK_STREAM, 0 ); + if( Socket->com == HB_NO_SOCKET ) { HB_SOCKET_SET_ERROR( Socket ); if( pSocket ) @@ -1659,37 +1116,37 @@ HB_FUNC( HB_INETSERVER ) } /* we'll be using only nonblocking sockets */ - /* hb_socketSetNonBlocking( Socket ); */ + /* hb_socketSetBlockingIO( Socket->com, FALSE ); */ - /* Reusable socket; under unix, do not wait it is unused */ - setsockopt( Socket->com, SOL_SOCKET, SO_REUSEADDR, ( const char * ) &iOpt, sizeof( iOpt ) ); - - iPort = htons( ( hbU16 ) hb_parni( 1 ) ); - - Socket->remote.sin_family = AF_INET; - Socket->remote.sin_port = ( hbU16 ) iPort; + hb_socketSetReuseAddr( Socket->com, TRUE ); + iPort = hb_parni( 1 ); szAddress = hb_parc( 2 ); - Socket->remote.sin_addr.s_addr = szAddress ? inet_addr( szAddress ) : INADDR_ANY; - iListen = HB_ISNUM( 3 ) ? hb_parni( 3 ) : 10; - - hb_vmUnlock(); - - if( bind( Socket->com, ( struct sockaddr * ) ( void * ) &Socket->remote, sizeof( Socket->remote ) ) ) + if( Socket->remote ) + hb_xfree( Socket->remote ); + if( hb_socketInetAddr( &Socket->remote, &Socket->remotelen, + szAddress ? szAddress : "255.255.255.255", iPort ) ) + { + if( hb_socketBind( Socket->com, Socket->remote, Socket->remotelen ) == -1 ) + { + HB_SOCKET_SET_ERROR( Socket ); + hb_socketClose( Socket->com ); + Socket->com = HB_NO_SOCKET; + } + else if( hb_socketListen( Socket->com, iListen ) == -1 ) + { + HB_SOCKET_SET_ERROR( Socket ); + hb_socketClose( Socket->com ); + Socket->com = HB_NO_SOCKET; + } + } + else { HB_SOCKET_SET_ERROR( Socket ); - HB_INET_CLOSE( Socket->com ); - Socket->com = ( HB_SOCKET_T ) -1; + hb_socketClose( Socket->com ); + Socket->com = HB_NO_SOCKET; } - else if( listen( Socket->com, iListen ) ) - { - HB_SOCKET_SET_ERROR( Socket ); - HB_INET_CLOSE( Socket->com ); - Socket->com = ( HB_SOCKET_T ) -1; - } - - hb_vmLock(); if( pSocket ) hb_itemReturnRelease( pSocket ); @@ -1697,18 +1154,13 @@ HB_FUNC( HB_INETSERVER ) hb_itemReturn( hb_param( 2, HB_IT_ANY ) ); } -#ifndef EAGAIN - #define EAGAIN -1 -#endif - HB_FUNC( HB_INETACCEPT ) { PHB_SOCKET Socket = HB_PARSOCKET( 1 ); PHB_SOCKET NewSocket; - HB_SOCKET_T incoming = 0; - int iError = EAGAIN; - struct sockaddr_in si_remote; - socklen_t Len; + HB_SOCKET_T incoming; + void * sa; + unsigned len; if( Socket == NULL ) { @@ -1718,61 +1170,33 @@ HB_FUNC( HB_INETACCEPT ) else if( ! hb_inetIsOpen( Socket ) ) return; - hb_vmUnlock(); - - Len = sizeof( struct sockaddr_in ); - /* - * Accept can (and should) be asynchronously stopped by closing the - * accepting socket. this will make the wait to terminate, and the - * calling program will be notivfied through the status of the - * returned socket. - */ + * Accept can (and should) be asynchronously stopped by closing the + * accepting socket. this will make the wait to terminate, and the + * calling program will be notivfied through the status of the + * returned socket. + */ HB_SOCKET_ZERO_ERROR( Socket ); - /* Connection incoming */ - while( iError == EAGAIN ) - { - if( hb_selectReadSocket( Socket ) ) - { - /* On error (e.g. async connection closed) , com will be -1 and - errno == 22 (invalid argument ) */ - incoming = accept( Socket->com, ( struct sockaddr * ) ( void * ) &si_remote, &Len ); + incoming = hb_socketAccept( Socket->com, &sa, &len, Socket->iTimeout ); - if( incoming == ( HB_SOCKET_T ) -1 ) - { -#if defined( HB_OS_WIN ) - iError = WSAGetLastError(); -#else - iError = errno; -#endif - } - else - iError = 0; - } + if( incoming == HB_NO_SOCKET ) + { + if( hb_socketGetError() == HB_SOCKET_ERR_TIMEOUT ) + HB_SOCKET_SET_ERROR2( Socket, -1, "Timeout" ); else - iError = -1; /* Timeout expired */ - } - - hb_vmLock(); - - if( iError == -1 ) - { - HB_SOCKET_SET_ERROR2( Socket, -1, "Timeout" ); - } - else if( iError > 0 ) - { - HB_SOCKET_SET_ERROR1( Socket, iError ); + HB_SOCKET_SET_ERROR( Socket ); } else { PHB_ITEM pSocket = NULL; - /* we'll be using only nonblocking sockets */ HB_SOCKET_INIT( NewSocket, pSocket ); - memcpy( &NewSocket->remote, &si_remote, Len ); + NewSocket->remote = sa; + NewSocket->remotelen = len; NewSocket->com = incoming; - /* hb_socketSetNonBlocking( NewSocket ); */ + /* we'll be using only nonblocking sockets */ + /* hb_socketSetBlockingIO( Socket->com, FALSE ); */ hb_itemReturnRelease( pSocket ); } } @@ -1784,12 +1208,12 @@ HB_FUNC( HB_INETACCEPT ) HB_FUNC( HB_INETCONNECT ) { const char * szHost = hb_parc( 1 ); + char * szAddr; PHB_SOCKET Socket = HB_PARSOCKET( 3 ); PHB_ITEM pSocket = NULL; - struct hostent * Host; - int iPort; + int iPort = hb_parni( 2 ); - if( szHost == NULL || ! HB_ISNUM( 2 ) || ( Socket == NULL && ! HB_ISNIL( 3 ) ) ) + if( szHost == NULL || iPort == 0 || ( Socket == NULL && ! HB_ISNIL( 3 ) ) ) { hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); return; @@ -1797,43 +1221,36 @@ HB_FUNC( HB_INETCONNECT ) if( Socket ) { - if( Socket->com != ( HB_SOCKET_T ) -1 ) + if( Socket->com != HB_NO_SOCKET ) { - HB_INET_CLOSE( Socket->com ); - Socket->com = ( HB_SOCKET_T ) -1; + hb_socketClose( Socket->com ); + Socket->com = HB_NO_SOCKET; } HB_SOCKET_ZERO_ERROR( Socket ); } else HB_SOCKET_INIT( Socket, pSocket ); - Host = hb_getHosts( szHost, Socket ); - - /* error had been set by get hosts */ - - if( Host ) + szAddr = hb_socketResolveAddr( szHost, HB_SOCK_AF_INET ); + if( !szAddr ) + HB_SOCKET_SET_ERROR( Socket ); + else { /* Creates comm socket */ -#if defined( HB_OS_WIN ) - Socket->com = socket( AF_INET, SOCK_STREAM, 0); -#else - Socket->com = socket( PF_INET, SOCK_STREAM, 0); -#endif - - if( Socket->com == ( HB_SOCKET_T ) -1 ) - { + Socket->com = hb_socketOpen( HB_SOCK_PF_INET, HB_SOCK_STREAM, 0 ); + if( Socket->com == HB_NO_SOCKET ) HB_SOCKET_SET_ERROR( Socket ); - } else { - iPort = htons( ( hbU16 ) hb_parni( 2 ) ); - - Socket->remote.sin_family = AF_INET; - Socket->remote.sin_port = ( hbU16 ) iPort; - Socket->remote.sin_addr.s_addr = ( * ( UINT * ) Host->h_addr_list[ 0 ] ); - - hb_socketConnect( Socket ); + if( Socket->remote ) + hb_xfree( Socket->remote ); + if( hb_socketInetAddr( &Socket->remote, &Socket->remotelen, + szAddr, iPort ) ) + hb_inetConnect( Socket ); + else + HB_SOCKET_SET_ERROR( Socket ); } + hb_xfree( szAddr ); } if( pSocket ) @@ -1857,38 +1274,29 @@ HB_FUNC( HB_INETCONNECTIP ) if( Socket ) { - if( Socket->com != ( HB_SOCKET_T ) -1 ) + if( Socket->com != HB_NO_SOCKET ) { - HB_INET_CLOSE( Socket->com ); - Socket->com = ( HB_SOCKET_T ) -1; + hb_socketClose( Socket->com ); + Socket->com = HB_NO_SOCKET; } HB_SOCKET_ZERO_ERROR( Socket ); } else - { HB_SOCKET_INIT( Socket, pSocket ); - } /* Creates comm socket */ -#if defined( HB_OS_WIN ) - Socket->com = socket( AF_INET, SOCK_STREAM, 0 ); -#else - Socket->com = socket( PF_INET, SOCK_STREAM, 0 ); -#endif - - if( Socket->com == ( HB_SOCKET_T ) -1 ) - { + Socket->com = hb_socketOpen( HB_SOCK_PF_INET, HB_SOCK_STREAM, 0 ); + if( Socket->com == HB_NO_SOCKET ) HB_SOCKET_SET_ERROR( Socket ); - } else { - iPort = htons( ( hbU16 ) iPort ); - - Socket->remote.sin_family = AF_INET; - Socket->remote.sin_port = ( hbU16 ) iPort; - Socket->remote.sin_addr.s_addr = inet_addr( szHost ); - - hb_socketConnect( Socket ); + if( Socket->remote ) + hb_xfree( Socket->remote ); + if( hb_socketInetAddr( &Socket->remote, &Socket->remotelen, + szHost, iPort ) ) + hb_inetConnect( Socket ); + else + HB_SOCKET_SET_ERROR( Socket ); } if( pSocket ) @@ -1906,7 +1314,6 @@ HB_FUNC( HB_INETDGRAMBIND ) PHB_SOCKET Socket; PHB_ITEM pSocket = NULL; int iPort = hb_parni( 1 ); - int iOpt = 1; const char * szAddress; /* Parameter error checking */ @@ -1919,82 +1326,42 @@ HB_FUNC( HB_INETDGRAMBIND ) HB_SOCKET_INIT( Socket, pSocket ); /* Creates comm socket */ -#if defined( HB_OS_WIN ) - Socket->com = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); -#else - Socket->com = socket( PF_INET, SOCK_DGRAM, 0 ); -#endif - - if( Socket->com == ( HB_SOCKET_T ) -1 ) + Socket->com = hb_socketOpen( HB_SOCK_PF_INET, HB_SOCK_DGRAM, HB_SOCK_IPPROTO_UDP ); + if( Socket->com == HB_NO_SOCKET ) { HB_SOCKET_SET_ERROR( Socket ); hb_itemReturnRelease( pSocket ); return; } - /* Reusable socket; under unix, do not wait it is unused */ - setsockopt( Socket->com, SOL_SOCKET, SO_REUSEADDR, ( const char * ) &iOpt, sizeof( iOpt ) ); + hb_socketSetReuseAddr( Socket->com, TRUE ); /* Setting broadcast if needed. */ if( hb_parl( 3 ) ) - { - iOpt = 1; - setsockopt( Socket->com, SOL_SOCKET, SO_BROADCAST, ( const char * ) &iOpt, sizeof( iOpt ) ); - } - - /* Binding here */ - iPort = htons( ( hbU16 ) iPort ); - - Socket->remote.sin_family = AF_INET; - Socket->remote.sin_port = ( hbU16 ) iPort; + hb_socketSetBroadcast( Socket->com, TRUE ); szAddress = hb_parc( 2 ); - Socket->remote.sin_addr.s_addr = szAddress ? inet_addr( szAddress ) : INADDR_ANY; - - hb_vmUnlock(); - - if( bind( Socket->com, ( struct sockaddr * ) ( void * ) &Socket->remote, sizeof( Socket->remote ) ) ) + if( Socket->remote ) + hb_xfree( Socket->remote ); + if( !hb_socketInetAddr( &Socket->remote, &Socket->remotelen, + szAddress ? szAddress : "255.255.255.255", iPort ) ) { HB_SOCKET_SET_ERROR( Socket ); - HB_INET_CLOSE( Socket->com ); - Socket->com = ( HB_SOCKET_T ) -1; + hb_socketClose( Socket->com ); + Socket->com = HB_NO_SOCKET; + } + else if( hb_socketBind( Socket->com, Socket->remote, Socket->remotelen ) == -1 ) + { + HB_SOCKET_SET_ERROR( Socket ); + hb_socketClose( Socket->com ); + Socket->com = HB_NO_SOCKET; } else if( hb_pcount() >= 4 ) { - #ifndef IP_ADD_MEMBERSHIP - #define IP_ADD_MEMBERSHIP 5 /* which header should this be in? */ - #endif - - /* this structure should be define in a header file. The MS SDK indicates that */ - /* it is in Ws2tcpip.h but I'm not sure I know where it should go in xHb */ - struct ip_mreq - { - struct in_addr imr_multiaddr; /* IP multicast address of group */ - struct in_addr imr_interface; /* local IP address of interface */ - }; - - struct ip_mreq mreq; - - mreq.imr_multiaddr.s_addr = inet_addr( hb_parc( 4 ) ); /* HELLO_GROUP */ - mreq.imr_interface.s_addr = htonl( INADDR_ANY ); - -#ifndef IPPROTO_IP - /* - * some systems may not have this definitions, it should - * be 0 what works with TCP/UDP sockets or explicitly set - * to IPPROTO_TCP/IPPROTO_UDP - */ -# define IPPROTO_IP 0 -#endif - - if( setsockopt( Socket->com, IPPROTO_IP, IP_ADD_MEMBERSHIP, ( const char * ) &mreq, sizeof( mreq ) ) < 0 ) - { + if( hb_socketSetMulticast( Socket->com, HB_SOCK_PF_INET, hb_parc( 4 ) ) != 0 ) HB_SOCKET_SET_ERROR( Socket ); - } } - hb_vmLock(); - hb_itemReturnRelease( pSocket ); } @@ -2002,18 +1369,12 @@ HB_FUNC( HB_INETDGRAM ) { PHB_SOCKET Socket; PHB_ITEM pSocket = NULL; - int iOpt = 1; HB_SOCKET_INIT( Socket, pSocket ); /* Creates comm socket */ -#if defined( HB_OS_WIN ) - Socket->com = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); -#else - Socket->com = socket( PF_INET, SOCK_DGRAM, 0 ); -#endif - - if( Socket->com == ( HB_SOCKET_T ) -1 ) + Socket->com = hb_socketOpen( HB_SOCK_PF_INET, HB_SOCK_DGRAM, HB_SOCK_IPPROTO_UDP ); + if( Socket->com == HB_NO_SOCKET ) { HB_SOCKET_SET_ERROR( Socket ); hb_itemReturnRelease( pSocket ); @@ -2022,12 +1383,10 @@ HB_FUNC( HB_INETDGRAM ) /* Setting broadcast if needed. */ if( hb_parl( 1 ) ) - { - iOpt = 1; - setsockopt( Socket->com, SOL_SOCKET, SO_BROADCAST, ( const char * ) &iOpt, sizeof( iOpt ) ); - } + hb_socketSetBroadcast( Socket->com, TRUE ); + /* we'll be using non blocking sockets in all functions */ - /* hb_socketSetNonBlocking( Socket ); */ + /* hb_socketSetBlockingIO( Socket->com, FALSE ); */ hb_itemReturnRelease( pSocket ); } @@ -2053,43 +1412,39 @@ HB_FUNC( HB_INETDGRAMSEND ) return; } - Socket->remote.sin_family = AF_INET; - Socket->remote.sin_port = htons( ( hbU16 ) iPort ); - Socket->remote.sin_addr.s_addr = inet_addr( szAddress ); - szBuffer = hb_itemGetCPtr( pBuffer ); + if( Socket->remote ) + hb_xfree( Socket->remote ); + if( !hb_socketInetAddr( &Socket->remote, &Socket->remotelen, szAddress, iPort ) ) + { + HB_SOCKET_SET_ERROR( Socket ); + Socket->iCount = 0; + hb_retni( 0 ); + return; + } + szBuffer = hb_itemGetCPtr( pBuffer ); iLen = ( int ) hb_itemGetCLen( pBuffer ); if( HB_ISNUM( 5 ) ) { int iMaxLen = hb_parni( 5 ); - if( iMaxLen < iLen ) iLen = iMaxLen; } - hb_vmUnlock(); - HB_SOCKET_ZERO_ERROR( Socket ); - Socket->iCount = 0; - if( hb_selectWriteSocket( Socket ) ) - { - Socket->iCount = ( int ) sendto( Socket->com, szBuffer, iLen, 0, - ( const struct sockaddr * ) ( void * ) &Socket->remote, sizeof( Socket->remote ) ); - } - - hb_vmLock(); - + Socket->iCount = hb_socketSendTo( Socket->com, szBuffer, iLen, 0, + Socket->remote, Socket->remotelen, + Socket->iTimeout ); hb_retni( Socket->iCount ); - if( Socket->iCount == 0 ) - { - HB_SOCKET_SET_ERROR2( Socket, -1, "Timeout" ); - } - else if( Socket->iCount < 0 ) + if( Socket->iCount == -1 ) { Socket->iCount = 0; - HB_SOCKET_SET_ERROR( Socket ); + if( hb_socketGetError() == HB_SOCKET_ERR_TIMEOUT ) + HB_SOCKET_SET_ERROR2( Socket, -1, "Timeout" ); + else + HB_SOCKET_SET_ERROR( Socket ); } } @@ -2102,7 +1457,6 @@ HB_FUNC( HB_INETDGRAMRECV ) char * Buffer; ULONG ulLen; BOOL fRepeat; - socklen_t iDtLen = ( socklen_t ) sizeof( struct sockaddr ); if( Socket == NULL || pBuffer == NULL || ! HB_ISBYREF( 2 ) ) { @@ -2133,33 +1487,28 @@ HB_FUNC( HB_INETDGRAMRECV ) else iMaxLen = iLen; - hb_vmUnlock(); - HB_SOCKET_ZERO_ERROR( Socket ); do { fRepeat = FALSE; - iLen = -2; - if( hb_selectReadSocket( Socket ) ) - { - iLen = recvfrom( Socket->com, Buffer, iMaxLen, 0, - ( struct sockaddr * ) ( void * ) &Socket->remote, &iDtLen ); - } + if( Socket->remote ) + hb_xfree( Socket->remote ); + iLen = hb_socketRecvFrom( Socket->com, Buffer, iMaxLen, 0, + &Socket->remote, &Socket->remotelen, + Socket->iTimeout ); iTimeElapsed += Socket->iTimeout; if( Socket->pPeriodicBlock ) { - hb_vmLock(); hb_execFromArray( Socket->pPeriodicBlock ); /* do we continue? */ fRepeat = hb_parl( -1 ) && hb_vmRequestQuery() == 0 && ( Socket->iTimeLimit == -1 || iTimeElapsed < Socket->iTimeLimit ); - hb_vmUnlock(); } } while( fRepeat ); - if( iLen == -2 ) + if( iLen == -1 && hb_socketGetError() == HB_SOCKET_ERR_TIMEOUT ) { HB_SOCKET_SET_ERROR2( Socket, -1, "Timeout" ); Socket->iCount = 0; @@ -2178,8 +1527,6 @@ HB_FUNC( HB_INETDGRAMRECV ) else Socket->iCount = iLen; - hb_vmLock(); - hb_retni( iLen ); } @@ -2197,5 +1544,3 @@ HB_FUNC( HB_INETISSOCKET ) { hb_retl( HB_PARSOCKET( 1 ) != NULL ); } - -#endif /* !HB_NO_DEFAULT_INET */ diff --git a/harbour/source/rtl/hbsocket.c b/harbour/source/rtl/hbsocket.c new file mode 100644 index 0000000000..519dc1b112 --- /dev/null +++ b/harbour/source/rtl/hbsocket.c @@ -0,0 +1,2736 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * socket C API + * + * Copyright 2009 Przemyslaw Czerpak + * 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 "hbsocket.h" + +#if defined( HB_OS_DOS ) +# if !defined( HB_SOCKET_OFF ) +# define HB_SOCKET_OFF +# endif +#endif + +#if !defined( HB_SOCKET_OFF ) + +/* we do not use autoconf so we can only guess what is supported + * by platform and/or CRTL :-( + */ +/* we are using following macros: + + platform supports inet_aton() function: + #define HB_HAS_INET_ATON + + platform supports inet_pton() function: + #define HB_HAS_INET_PTON + + platform supports inet_ntop() function: + #define HB_HAS_INET_NTOP + + platform supports thread safe (using TLS) inet_ntoa() function: + #define HB_IS_INET_NTOA_MT_SAFE + + platform supports getaddrinfo()/freeaddrinfo() functions: + #define HB_HAS_ADDRINFO + + platform supports IP6 protocol: + #define HB_HAS_INET6 + + platform supports unix/local protocol: + #define HB_HAS_UNIX + + platform supports 'struct sockaddr_storage' which can be used as holder + for all socket address structures in all supported protocols, + simple 'struct sockaddr' is not large enough for such usage: + #define HB_HAS_SOCKADDR_STORAGE + + timeval parameter used in select() function is updated by kernel/CRTL + and decreased by the amount of time the function was waiting: + #define HB_HAS_SELECT_TIMER + + all implementations should use BSD compatible constant values but + if it's not guarantied then these two mactos can be used. + protocol families have to be translated: + #define HB_SOCKET_TRANSLATE_DOMAIN + + protocol types have to be translated: + #define HB_SOCKET_TRANSLATE_TYPE +*/ + +#if defined( HB_OS_HPUX ) +# define _XOPEN_SOURCE_EXTENDED +#endif + +#if defined( HB_OS_UNIX ) +# define HB_HAS_UNIX +# if !defined( __WATCOMC__ ) +# define HB_HAS_INET_ATON +# define HB_HAS_INET_PTON +# define HB_HAS_INET_NTOP +# define HB_HAS_INET6 +# define HB_HAS_SOCKADDR_STORAGE +# define HB_HAS_ADDRINFO +# endif +# if defined( HB_OS_LINUX ) +# define HB_HAS_SELECT_TIMER +# endif +#elif defined( HB_OS_WIN ) +# if defined( __WATCOMC__ ) +# if ( NTDDI_VERSION >= 0x06000000 ) +# define HB_HAS_INET_PTON +# define HB_HAS_INET_NTOP +# endif +# define HB_HAS_SOCKADDR_STORAGE +/* # define HB_HAS_INET6 */ +# elif defined( __MINGW32__ ) +# define HB_HAS_SOCKADDR_STORAGE +# elif defined( __POCC__ ) +# define HB_HAS_SOCKADDR_STORAGE +# endif +# define HB_IS_INET_NTOA_MT_SAFE +#elif defined( HB_OS_OS2 ) +# if defined( __WATCOMC__ ) +# define HB_HAS_INET_PTON +# define HB_HAS_INET_NTOP +# else + /* please verify it and disable unsupported options in GCC OS2 */ +# define HB_HAS_INET_PTON +# define HB_HAS_INET_NTOP +# endif +#endif + + +#if defined( HB_OS_WIN ) && ! defined( HB_OS_UNIX_COMPATIBLE ) +# include +# include +#else +# include +# if defined( HB_OS_OS2 ) +# if defined( __WATCOMC__ ) +# include +# include +# endif +# include +# include +# endif +# include +# include +# include +# include +# include +# include +# if defined( HB_HAS_UNIX ) +# include +# endif +# include +# include +#endif + +#if defined( HB_OS_OS2 ) || defined( HB_OS_WIN ) +# define socklen_t int +#endif + +#if !defined( INET_ADDRSTRLEN ) +# define INET_ADDRSTRLEN 16 +#endif + +#if defined( __WATCOMC__ ) && defined( HB_OS_LINUX ) && !defined( IP_ADD_MEMBERSHIP ) + /* it's missed in OpenWatcom 1.8 Linux header files :-( */ +# define IP_ADD_MEMBERSHIP 35 + struct ip_mreq + { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* Local IP address of interface */ + }; +#endif + +#endif /* HB_SOCKET_OFF */ + +#include "hbapi.h" +#include "hbapiitm.h" +#include "hbvm.h" +#include "hbstack.h" +#include "hbthread.h" +#include "hbdate.h" + +/* TODO change error description to sth more user friendly */ +const char * s_socketErrors[] = { + "OK", + "EPIPE", + "ETIMEOUT", + "EWRONGADDR", + "EAFNOSUPPORT", + "EPFNOSUPPORT", + "EPROTONOSUPPORT", + "EPARAMVALUE", + "ENOSUPPORT", + "ENORESOURCE", + "EACCESS", + "EADDRINUSE", + "EINTERRUPT", + "EALREADYCONNECTED", + "ECONNREFUSED", + "ECONNABORTED", + "ECONNRESET", + "ENETUNREACH", + "ENETDOWN", + "ENETRESET", + "EINPROGRESS", + "EALREADY", + "EADDRNOTAVAIL", + "EREADONLY", + "EAGAIN", + "EINVALIDHANDLE", + "EINVAL", + "EPROTO", + "EPROTOTYPE", + "ENOFILE", + "ENOBUFS", + "ENOMEM", + "EFAULT", + "ENAMETOOLONG", + "ENOENT", + "ENOTDIR", + "ELOOP", + "EMSGSIZE", + "EDESTADDRREQ", + "ENOPROTOOPT", + "ENOTCONN", + "ESHUTDOWN", + "ETOOMANYREFS", + "ERESTARTSYS", + "ENOSR", + "EHOSTDOWN", + "EHOSTUNREACH", + "ENOTEMPTY", + "EUSERS", + "EDQUOT", + "ESTALE", + "EREMOTE", + "EPROCLIM", + "EDISCON", + "ENOMORE", + "ECANCELLED", + "EINVALIDPROCTABLE", + "EINVALIDPROVIDER", + "EPROVIDERFAILEDINIT", + "EREFUSED", + "ESYSNOTREADY", + "EVERNOTSUPPORTED", + "ENOTINITIALISED", + "TRYAGAIN", + "HOSTNOTFOUND", + "NORECOVERY", + "NODATA", + "ESYSCALLFAILURE", + "ESERVICENOTFOUND", + "ETYPENOTFOUND", + "EOTHER" +}; + +int hb_socketGetError( void ) +{ + return hb_stackIOErrors()->uiSocketError; +} + +int hb_socketGetOsError( void ) +{ + return hb_stackIOErrors()->iSocketOsError; +} + +const char * hb_socketErrorStr( int iError ) +{ + if( iError >= 0 && iError <= HB_SOCKET_ERR_OTHER ) + return s_socketErrors[ iError ]; + else + return ""; +} + +static void hb_socketSetRawError( int err ) +{ + PHB_IOERRORS pError = hb_stackIOErrors(); + pError->uiSocketError = ( USHORT ) err; + pError->iSocketOsError = 0; +} + +#if defined( HB_SOCKET_OFF ) + +int hb_socketInit( void ) { return -1; } + +void hb_socketCleanup( void ) { ; } + +int hb_socketGetAddrFamilly( const void * pSockAddr, unsigned len ) +{ + HB_SYMBOL_UNUSED( pSockAddr ); + HB_SYMBOL_UNUSED( len ); + return -1; +} + +BOOL hb_socketLocalAddr( void ** pSockAddr, unsigned * puiLen, + const char * szAddr ) +{ + HB_SYMBOL_UNUSED( szAddr ); + hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); + *pSockAddr = NULL; + *puiLen = 0; + return FALSE; +} + +BOOL hb_socketInetAddr( void ** pSockAddr, unsigned * puiLen, + const char * szAddr, int iPort ) +{ + HB_SYMBOL_UNUSED( szAddr ); + HB_SYMBOL_UNUSED( iPort ); + hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); + *pSockAddr = NULL; + *puiLen = 0; + return FALSE; +} + +BOOL hb_socketInet6Addr( void ** pSockAddr, unsigned * puiLen, + const char * szAddr, int iPort ) +{ + HB_SYMBOL_UNUSED( szAddr ); + HB_SYMBOL_UNUSED( iPort ); + hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); + *pSockAddr = NULL; + *puiLen = 0; + return FALSE; +} + +char * hb_socketAddrGetName( const void * pSockAddr, unsigned len ) +{ + HB_SYMBOL_UNUSED( pSockAddr ); + HB_SYMBOL_UNUSED( len ); + hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); + return NULL; +} + +int hb_socketAddrGetPort( const void * pSockAddr, unsigned len ) +{ + HB_SYMBOL_UNUSED( pSockAddr ); + HB_SYMBOL_UNUSED( len ); + hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); + return -1; +} + +BOOL hb_socketAddrFromItem( void ** pSockAddr, unsigned * puiLen, PHB_ITEM pAddrItm ) +{ + HB_SYMBOL_UNUSED( pAddrItm ); + hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); + *pSockAddr = NULL; + *puiLen = 0; + return FALSE; +} + +PHB_ITEM hb_socketAddrToItem( const void * pSockAddr, unsigned len ) +{ + HB_SYMBOL_UNUSED( pSockAddr ); + HB_SYMBOL_UNUSED( len ); + hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); + return NULL; +} + +int hb_socketGetSockName( HB_SOCKET_T sd, void ** pSockAddr, unsigned * puiLen ) +{ + HB_SYMBOL_UNUSED( sd ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + *pSockAddr = NULL; + *puiLen = 0; + return -1; +} + +int hb_socketGetPeerName( HB_SOCKET_T sd, void ** pSockAddr, unsigned * puiLen ) +{ + HB_SYMBOL_UNUSED( sd ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + *pSockAddr = NULL; + *puiLen = 0; + return -1; +} + +HB_SOCKET_T hb_socketOpen( int domain, int type, int protocol ) +{ + HB_SYMBOL_UNUSED( domain ); + HB_SYMBOL_UNUSED( type ); + HB_SYMBOL_UNUSED( protocol ); + hb_socketSetRawError( HB_SOCKET_ERR_PFNOSUPPORT ); + return HB_NO_SOCKET; +} + +int hb_socketClose( HB_SOCKET_T sd ) +{ + HB_SYMBOL_UNUSED( sd ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +int hb_socketShutdown( HB_SOCKET_T sd, int iMode ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( iMode ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +int hb_socketBind( HB_SOCKET_T sd, const void * pSockAddr, unsigned uiLen ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( pSockAddr ); + HB_SYMBOL_UNUSED( uiLen ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +int hb_socketListen( HB_SOCKET_T sd, int iBacklog ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( iBacklog ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +HB_SOCKET_T hb_socketAccept( HB_SOCKET_T sd, void ** pSockAddr, unsigned * puiLen, HB_LONG timeout ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( pSockAddr ); + HB_SYMBOL_UNUSED( puiLen ); + HB_SYMBOL_UNUSED( timeout ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return HB_NO_SOCKET; +} + +int hb_socketConnect( HB_SOCKET_T sd, const void * pSockAddr, unsigned uiLen, HB_LONG timeout ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( pSockAddr ); + HB_SYMBOL_UNUSED( uiLen ); + HB_SYMBOL_UNUSED( timeout ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +long hb_socketSend( HB_SOCKET_T sd, const void * data, long len, int flags, HB_LONG timeout ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( data ); + HB_SYMBOL_UNUSED( len ); + HB_SYMBOL_UNUSED( flags ); + HB_SYMBOL_UNUSED( timeout ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +long hb_socketSendTo( HB_SOCKET_T sd, const void * data, long len, int flags, const void * pSockAddr, unsigned uiSockLen, HB_LONG timeout ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( data ); + HB_SYMBOL_UNUSED( len ); + HB_SYMBOL_UNUSED( flags ); + HB_SYMBOL_UNUSED( pSockAddr ); + HB_SYMBOL_UNUSED( uiSockLen ); + HB_SYMBOL_UNUSED( timeout ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +long hb_socketRecv( HB_SOCKET_T sd, void * data, long len, int flags, HB_LONG timeout ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( data ); + HB_SYMBOL_UNUSED( len ); + HB_SYMBOL_UNUSED( flags ); + HB_SYMBOL_UNUSED( timeout ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +long hb_socketRecvFrom( HB_SOCKET_T sd, void * data, long len, int flags, void ** pSockAddr, unsigned * puiSockLen, HB_LONG timeout ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( data ); + HB_SYMBOL_UNUSED( len ); + HB_SYMBOL_UNUSED( flags ); + HB_SYMBOL_UNUSED( pSockAddr ); + HB_SYMBOL_UNUSED( puiSockLen ); + HB_SYMBOL_UNUSED( timeout ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +int hb_socketSetBlockingIO( HB_SOCKET_T sd, BOOL fBlocking ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( fBlocking ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +int hb_socketSetReuseAddr( HB_SOCKET_T sd, BOOL fReuse ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( fReuse ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +int hb_socketSetKeepAlive( HB_SOCKET_T sd, BOOL fKeepAlive ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( fKeepAlive ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +int hb_socketSetBroadcast( HB_SOCKET_T sd, BOOL fBroadcast ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( fBroadcast ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +int hb_socketSetSndBufSize( HB_SOCKET_T sd, int iSize ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( iSize ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +int hb_socketSetRcvBufSize( HB_SOCKET_T sd, int iSize ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( iSize ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +int hb_socketGetSndBufSize( HB_SOCKET_T sd, int * piSize ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( piSize ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +int hb_socketGetRcvBufSize( HB_SOCKET_T sd, int * piSize ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( piSize ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +int hb_socketSetMulticast( HB_SOCKET_T sd, int af, const char * szAddr ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( af ); + HB_SYMBOL_UNUSED( szAddr ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +int hb_socketSelectRead( HB_SOCKET_T sd, HB_LONG timeout ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( timeout ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +int hb_socketSelectWrite( HB_SOCKET_T sd, HB_LONG timeout ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( timeout ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + + +int hb_socketSelectWriteEx( HB_SOCKET_T sd, HB_LONG timeout ) +{ + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( timeout ); + hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); + return -1; +} + +int hb_socketSelect( PHB_ITEM pArrayRD, BOOL fSetRD, + PHB_ITEM pArrayWR, BOOL fSetWR, + PHB_ITEM pArrayEX, BOOL fSetEX, + HB_LONG timeout, HB_SOCK_FUNC pFunc ) +{ + HB_SYMBOL_UNUSED( pArrayRD ); + HB_SYMBOL_UNUSED( fSetRD ); + HB_SYMBOL_UNUSED( pArrayWR ); + HB_SYMBOL_UNUSED( fSetWR ); + HB_SYMBOL_UNUSED( pArrayEX ); + HB_SYMBOL_UNUSED( fSetEX ); + HB_SYMBOL_UNUSED( timeout ); + HB_SYMBOL_UNUSED( pFunc ); + hb_socketSetRawError( HB_SOCKET_ERR_NOSUPPORT ); + return -1; +} + +char * hb_socketResolveAddr( const char * szAddr, int af ) +{ + HB_SYMBOL_UNUSED( szAddr ); + HB_SYMBOL_UNUSED( af ); + hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); + return NULL; +} + +PHB_ITEM hb_socketGetHosts( const char * szAddr, int af ) +{ + HB_SYMBOL_UNUSED( szAddr ); + HB_SYMBOL_UNUSED( af ); + hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); + return NULL; +} + +PHB_ITEM hb_socketGetAliases( const char * szAddr, int af ) +{ + HB_SYMBOL_UNUSED( szAddr ); + HB_SYMBOL_UNUSED( af ); + hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); + return NULL; +} + +#else + +#define HB_SOCKADDR_MAX_LEN 256 + +#if defined( HB_OS_WIN ) +# define HB_SOCK_GETERROR() WSAGetLastError() +# define HB_SOCK_IS_EINTR() ( WSAGetLastError() == WSAEINTR ) +# define HB_SOCK_IS_EINPROGRES() ( WSAGetLastError() == WSAEWOULDBLOCK ) +#else +# define HB_SOCK_GETERROR() errno +# define HB_SOCK_IS_EINTR() ( errno == EINTR ) +# define HB_SOCK_IS_EINPROGRES() ( errno == EINPROGRESS ) +#endif + +/* MT macros */ +#define HB_SOCKET_LOCK hb_threadEnterCriticalSection( &s_sockMtx ); +#define HB_SOCKET_UNLOCK hb_threadLeaveCriticalSection( &s_sockMtx ); +static HB_CRITICAL_NEW( s_sockMtx ); + +static int s_iSessions; + +#if !defined( HB_HAS_INET_NTOP ) && !defined( HB_IS_INET_NTOA_MT_SAFE ) && defined( AF_INET ) +static const char * hb_inet_ntoa( struct in_addr * addr, char * pBuffer ) +{ + /* dirty hack to make inet_ntoa() MT safe, + * in many systems inet_ntoa() returns pointer to + * static buffer and is not MT safe. + */ + ULONG u = ntohl( addr->s_addr ); + hb_snprintf( pBuffer, INET_ADDRSTRLEN, "%hd.%hd.%hd.%hd", + HB_UHBYTE( u ), HB_ULBYTE( u ), HB_HIBYTE( u ), HB_LOBYTE( u ) ); + return pBuffer; +} +#endif + +int hb_socketInit( void ) +{ + int ret = 0; + + HB_SOCKET_LOCK + if( ++s_iSessions == 1 ) + { +#if defined( HB_OS_WIN ) + WSADATA wsadata; + ret = WSAStartup( HB_MKUSHORT( 1, 1 ), &wsadata ); +#endif + } + HB_SOCKET_UNLOCK + + return ret; +} + +void hb_socketCleanup( void ) +{ + HB_SOCKET_LOCK + if( --s_iSessions == 0 ) + { +#if defined( HB_OS_WIN ) + WSACleanup(); +#endif + } + HB_SOCKET_UNLOCK +} + +static void hb_socketSetOsError( int err ) +{ + PHB_IOERRORS pError = hb_stackIOErrors(); + USHORT uiErr; + +#if defined( HB_OS_WIN ) + switch( err ) + { + case WSAEINTR: + uiErr = HB_SOCKET_ERR_INTERRUPT; + break; + case WSAEBADF: + case WSAENOTSOCK: + uiErr = HB_SOCKET_ERR_INVALIDHANDLE; + break; + case WSAEACCES: + uiErr = HB_SOCKET_ERR_ACCESS; + break; + case WSAEFAULT: + uiErr = HB_SOCKET_ERR_FAULT; + break; + case WSAEINVAL: + uiErr = HB_SOCKET_ERR_INVAL; + break; + case WSAEMFILE: + uiErr = HB_SOCKET_ERR_NOFILE; + break; + case WSAEWOULDBLOCK: + uiErr = HB_SOCKET_ERR_AGAIN; + break; + case WSAEINPROGRESS: + uiErr = HB_SOCKET_ERR_INPROGRESS; + break; + case WSAEALREADY: + uiErr = HB_SOCKET_ERR_ALREADY; + break; + case WSAEDESTADDRREQ: + uiErr = HB_SOCKET_ERR_DESTADDRREQ; + break; + case WSAEMSGSIZE: + uiErr = HB_SOCKET_ERR_MSGSIZE; + break; + case WSAEPROTOTYPE: + uiErr = HB_SOCKET_ERR_PROTOTYPE; + break; + case WSAENOPROTOOPT: + uiErr = HB_SOCKET_ERR_NOPROTOOPT; + break; + case WSAEPROTONOSUPPORT: + uiErr = HB_SOCKET_ERR_PROTONOSUPPORT; + break; + case WSAEOPNOTSUPP: + case WSAESOCKTNOSUPPORT: + uiErr = HB_SOCKET_ERR_NOSUPPORT; + break; + case WSAEPFNOSUPPORT: + uiErr = HB_SOCKET_ERR_PFNOSUPPORT; + break; + case WSAEAFNOSUPPORT: + uiErr = HB_SOCKET_ERR_AFNOSUPPORT; + break; + case WSAEADDRINUSE: + uiErr = HB_SOCKET_ERR_ADDRINUSE; + break; + case WSAEADDRNOTAVAIL: + uiErr = HB_SOCKET_ERR_ADDRNOTAVAIL; + break; + case WSAENETDOWN: + uiErr = HB_SOCKET_ERR_NETDOWN; + break; + case WSAENETUNREACH: + uiErr = HB_SOCKET_ERR_NETUNREACH; + break; + case WSAENETRESET: + uiErr = HB_SOCKET_ERR_NETRESET; + break; + case WSAECONNREFUSED: + uiErr = HB_SOCKET_ERR_CONNREFUSED; + break; + case WSAECONNABORTED: + uiErr = HB_SOCKET_ERR_CONNABORTED; + break; + case WSAECONNRESET: + uiErr = HB_SOCKET_ERR_CONNRESET; + break; + case WSAENOBUFS: + uiErr = HB_SOCKET_ERR_NOBUFS; + break; + case WSAEISCONN: + uiErr = HB_SOCKET_ERR_ALREADYCONNECTED; + break; + case WSAENOTCONN: + uiErr = HB_SOCKET_ERR_NOTCONN; + break; + case WSAESHUTDOWN: + uiErr = HB_SOCKET_ERR_SHUTDOWN; + break; + case WSAETOOMANYREFS: + uiErr = HB_SOCKET_ERR_TOOMANYREFS; + break; + case WSAETIMEDOUT: + uiErr = HB_SOCKET_ERR_TIMEOUT; + break; + case WSAELOOP: + uiErr = HB_SOCKET_ERR_LOOP; + break; + case WSAENAMETOOLONG: + uiErr = HB_SOCKET_ERR_NAMETOOLONG; + break; + case WSAEHOSTDOWN: + uiErr = HB_SOCKET_ERR_HOSTDOWN; + break; + case WSAEHOSTUNREACH: + uiErr = HB_SOCKET_ERR_HOSTUNREACH; + break; + case WSAENOTEMPTY: + uiErr = HB_SOCKET_ERR_NOTEMPTY; + break; + case WSAEUSERS: + uiErr = HB_SOCKET_ERR_USERS; + break; + case WSAEDQUOT: + uiErr = HB_SOCKET_ERR_DQUOT; + break; + case WSAESTALE: + uiErr = HB_SOCKET_ERR_STALE; + break; + case WSAEREMOTE: + uiErr = HB_SOCKET_ERR_REMOTE; + break; + case WSAEPROCLIM: + uiErr = HB_SOCKET_ERR_PROCLIM; + break; + case WSAEDISCON: + uiErr = HB_SOCKET_ERR_DISCON; + break; + case WSAENOMORE: + uiErr = HB_SOCKET_ERR_NOMORE; + break; + case WSAECANCELLED: + uiErr = HB_SOCKET_ERR_CANCELLED; + break; + case WSAEINVALIDPROCTABLE: + uiErr = HB_SOCKET_ERR_INVALIDPROCTABLE; + break; + case WSAEINVALIDPROVIDER: + uiErr = HB_SOCKET_ERR_INVALIDPROVIDER; + break; + case WSAEPROVIDERFAILEDINIT: + uiErr = HB_SOCKET_ERR_PROVIDERFAILEDINIT; + break; + case WSAEREFUSED: + uiErr = HB_SOCKET_ERR_REFUSED; + break; + case WSATRY_AGAIN: + uiErr = HB_SOCKET_ERR_TRYAGAIN; + break; + case WSASYSNOTREADY: + uiErr = HB_SOCKET_ERR_SYSNOTREADY; + break; + case WSAVERNOTSUPPORTED: + uiErr = HB_SOCKET_ERR_VERNOTSUPPORTED; + break; + case WSANOTINITIALISED: + uiErr = HB_SOCKET_ERR_NOTINITIALISED; + break; + case WSAHOST_NOT_FOUND: + uiErr = HB_SOCKET_ERR_HOSTNOTFOUND; + break; + case WSANO_RECOVERY: + uiErr = HB_SOCKET_ERR_NORECOVERY; + break; + case WSANO_DATA: + uiErr = HB_SOCKET_ERR_NODATA; + break; + case WSASYSCALLFAILURE: + uiErr = HB_SOCKET_ERR_SYSCALLFAILURE; + break; + case WSASERVICE_NOT_FOUND: + uiErr = HB_SOCKET_ERR_SERVICENOTFOUND; + break; + case WSATYPE_NOT_FOUND: + uiErr = HB_SOCKET_ERR_TYPENOTFOUND; + break; + case WSA_E_NO_MORE: + uiErr = HB_SOCKET_ERR_NOMORE; + break; + case WSA_E_CANCELLED: + uiErr = HB_SOCKET_ERR_CANCELLED; + break; + default: + uiErr = HB_SOCKET_ERR_OTHER; + break; + } +#else + switch( err ) + { +#if defined( EPFNOSUPPORT ) + case EPFNOSUPPORT: + uiErr = HB_SOCKET_ERR_PFNOSUPPORT; + break; +#endif +#if defined( EAFNOSUPPORT ) + case EAFNOSUPPORT: + uiErr = HB_SOCKET_ERR_AFNOSUPPORT; + break; +#endif +#if defined( EPROTONOSUPPORT ) + case EPROTONOSUPPORT: + uiErr = HB_SOCKET_ERR_PROTONOSUPPORT; + break; +#endif + case EADDRINUSE: + uiErr = HB_SOCKET_ERR_ADDRINUSE; + break; + case EINTR: + uiErr = HB_SOCKET_ERR_INTERRUPT; + break; + case ETIMEDOUT: + uiErr = HB_SOCKET_ERR_TIMEOUT; + break; + case EISCONN: + uiErr = HB_SOCKET_ERR_ALREADYCONNECTED; + break; + case ENOTCONN: + uiErr = HB_SOCKET_ERR_NOTCONN; + break; + case ECONNABORTED: + uiErr = HB_SOCKET_ERR_CONNABORTED; + break; + case ECONNRESET: + uiErr = HB_SOCKET_ERR_CONNRESET; + break; + case ECONNREFUSED: + uiErr = HB_SOCKET_ERR_CONNREFUSED; + break; + case ENETUNREACH: + uiErr = HB_SOCKET_ERR_NETUNREACH; + break; + case ENETDOWN: + uiErr = HB_SOCKET_ERR_NETDOWN; + break; + case ENETRESET: + uiErr = HB_SOCKET_ERR_NETRESET; + break; + case EINPROGRESS: + uiErr = HB_SOCKET_ERR_INPROGRESS; + break; + case EALREADY: + uiErr = HB_SOCKET_ERR_ALREADY; + break; + case EADDRNOTAVAIL: + uiErr = HB_SOCKET_ERR_ADDRNOTAVAIL; + break; + case EROFS: + uiErr = HB_SOCKET_ERR_READONLY; + break; + case EAGAIN: +#if defined( EWOULDBLOCK ) +# if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +# endif +#endif + uiErr = HB_SOCKET_ERR_AGAIN; + break; + case EPIPE: + uiErr = HB_SOCKET_ERR_PIPE; + break; + case EPERM: + case EACCES: + uiErr = HB_SOCKET_ERR_ACCESS; + break; + case EBADF: + case ENOTSOCK: + uiErr = HB_SOCKET_ERR_INVALIDHANDLE; + break; + case EINVAL: + uiErr = HB_SOCKET_ERR_INVAL; + break; +#if defined( EPROTO ) + case EPROTO: + uiErr = HB_SOCKET_ERR_PROTO; + break; +#endif + case EPROTOTYPE: + uiErr = HB_SOCKET_ERR_PROTOTYPE; + break; + case EOPNOTSUPP: + case ESOCKTNOSUPPORT: + uiErr = HB_SOCKET_ERR_NOSUPPORT; + break; + case EMFILE: + case ENFILE: + uiErr = HB_SOCKET_ERR_NOFILE; + break; + case ENOBUFS: + uiErr = HB_SOCKET_ERR_NOBUFS; + break; + case ENOMEM: + uiErr = HB_SOCKET_ERR_NOMEM; + break; + case EFAULT: + uiErr = HB_SOCKET_ERR_FAULT; + break; + case ENAMETOOLONG: + uiErr = HB_SOCKET_ERR_NAMETOOLONG; + break; + case ENOENT: + uiErr = HB_SOCKET_ERR_NOENT; + break; + case ENOTDIR: + uiErr = HB_SOCKET_ERR_NOTDIR; + break; + case ELOOP: + uiErr = HB_SOCKET_ERR_LOOP; + break; +#if defined( ENOSR ) + case ENOSR: + uiErr = HB_SOCKET_ERR_NOSR; + break; +#endif +#if defined( ERESTARTSYS ) + case ERESTARTSYS: + uiErr = HB_SOCKET_ERR_RESTARTSYS; + break; +#endif + case EDESTADDRREQ: + uiErr = HB_SOCKET_ERR_DESTADDRREQ; + break; + case EMSGSIZE: + uiErr = HB_SOCKET_ERR_MSGSIZE; + break; + case ENOPROTOOPT: + uiErr = HB_SOCKET_ERR_NOPROTOOPT; + break; + case ESHUTDOWN: + uiErr = HB_SOCKET_ERR_SHUTDOWN; + break; + case ETOOMANYREFS: + uiErr = HB_SOCKET_ERR_TOOMANYREFS; + break; + case EHOSTDOWN: + uiErr = HB_SOCKET_ERR_HOSTDOWN; + break; + case EHOSTUNREACH: + uiErr = HB_SOCKET_ERR_HOSTUNREACH; + break; + case ENOTEMPTY: + uiErr = HB_SOCKET_ERR_NOTEMPTY; + break; +#if defined( EUSERS ) + case EUSERS: + uiErr = HB_SOCKET_ERR_USERS; + break; +#endif + case EDQUOT: + uiErr = HB_SOCKET_ERR_DQUOT; + break; +#if defined( ESTALE ) + case ESTALE: + uiErr = HB_SOCKET_ERR_STALE; + break; +#endif +#if defined( EREMOTE ) + case EREMOTE: + uiErr = HB_SOCKET_ERR_REMOTE; + break; +#endif +#if defined( EPROCLIM ) + case EPROCLIM: + uiErr = HB_SOCKET_ERR_PROCLIM; + break; +#endif +#if defined( EDISCON ) + case EDISCON: + uiErr = HB_SOCKET_ERR_DISCON; + break; +#endif +#if defined( ENOMORE ) + case ENOMORE: + uiErr = HB_SOCKET_ERR_NOMORE; + break; +#endif +#if defined( ECANCELLED ) + case ECANCELLED: + uiErr = HB_SOCKET_ERR_CANCELLED; + break; +#endif +#if defined( EINVALIDPROCTABLE ) + case EINVALIDPROCTABLE: + uiErr = HB_SOCKET_ERR_INVALIDPROCTABLE; + break; +#endif +#if defined( EINVALIDPROVIDER ) + case EINVALIDPROVIDER: + uiErr = HB_SOCKET_ERR_INVALIDPROVIDER; + break; +#endif +#if defined( EPROVIDERFAILEDINIT ) + case EPROVIDERFAILEDINIT: + uiErr = HB_SOCKET_ERR_PROVIDERFAILEDINIT; + break; +#endif +#if defined( EREFUSED ) + case EREFUSED: + uiErr = HB_SOCKET_ERR_REFUSED; + break; +#endif +/* +#if defined( TRY_AGAIN ) + case TRY_AGAIN: + uiErr = HB_SOCKET_ERR_TRYAGAIN; + break; +#endif +#if defined( HOST_NOT_FOUND ) + case HOST_NOT_FOUND: + uiErr = HB_SOCKET_ERR_HOSTNOTFOUND; + break; +#endif +#if defined( NO_RECOVERY ) + case NO_RECOVERY: + uiErr = HB_SOCKET_ERR_NORECOVERY; + break; +#endif +#if defined( NO_DATA ) || defined( NO_ADDRESS ) +#if defined( NO_DATA ) + case NO_DATA: +#endif +#if defined( NO_ADDRESS ) && \ + ( !defined( NO_DATA ) || NO_ADDRESS != NO_DATA ) + case NO_ADDRESS: +#endif + uiErr = HB_SOCKET_ERR_NODATA; + break; +#endif +*/ + default: + uiErr = HB_SOCKET_ERR_OTHER; + break; + } +#endif + + pError->uiSocketError = uiErr; + pError->iSocketOsError = err; +} + +static int hb_socketSelectRD( HB_SOCKET_T sd, HB_LONG timeout ) +{ + struct timeval tv, * ptv; + fd_set rfds; + int iResult; +#if !defined( HB_HAS_SELECT_TIMER ) + HB_ULONG timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); +#endif + + for( ;; ) + { + FD_ZERO( &rfds ); + FD_SET( sd, &rfds ); + + if( timeout >= 0 ) + { + tv.tv_sec = timeout / 1000; + tv.tv_usec = ( timeout % 1000 ) * 1000; + ptv = &tv; + } + else + ptv = NULL; + + iResult = select( sd + 1, &rfds, NULL, NULL, ptv ); + hb_socketSetOsError( iResult >= 0 ? 0 : HB_SOCK_GETERROR() ); + if( iResult == -1 && timeout > 0 && HB_SOCK_IS_EINTR() && + hb_vmRequestQuery() == 0 ) +#if defined( HB_HAS_SELECT_TIMER ) + continue; +#else + { + HB_ULONG timecurr = hb_dateMilliSeconds(); + if( timecurr > timer ) + { + timeout -= timecurr - timer; + if( timeout > 0 ) + continue; + } + } +#endif + break; + } + + return iResult < 0 ? -1 : + ( iResult > 0 && FD_ISSET( sd, &rfds ) ? 1 : 0 ); +} + +static int hb_socketSelectWR( HB_SOCKET_T sd, HB_LONG timeout ) +{ + struct timeval tv, * ptv; + fd_set wfds; + int iResult; +#if !defined( HB_HAS_SELECT_TIMER ) + HB_ULONG timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); +#endif + + for( ;; ) + { + FD_ZERO( &wfds ); + FD_SET( sd, &wfds ); + + if( timeout >= 0 ) + { + tv.tv_sec = timeout / 1000; + tv.tv_usec = ( timeout % 1000 ) * 1000; + ptv = &tv; + } + else + ptv = NULL; + + iResult = select( sd + 1, &wfds, NULL, NULL, ptv ); + hb_socketSetOsError( iResult >= 0 ? 0 : HB_SOCK_GETERROR() ); + if( iResult == -1 && timeout > 0 && HB_SOCK_IS_EINTR() && + hb_vmRequestQuery() == 0 ) +#if defined( HB_HAS_SELECT_TIMER ) + continue; +#else + { + HB_ULONG timecurr = hb_dateMilliSeconds(); + if( timecurr > timer ) + { + timeout -= timecurr - timer; + if( timeout > 0 ) + continue; + } + } +#endif + break; + } + + return iResult < 0 ? -1 : + ( iResult > 0 && FD_ISSET( sd, &wfds ) ? 1 : 0 ); +} + +static int hb_socketSelectWRE( HB_SOCKET_T sd, HB_LONG timeout ) +{ + struct timeval tv, * ptv; + fd_set wfds, * pefds; +#if defined( HB_OS_WIN ) + fd_set efds; +#endif + int iResult; +#if !defined( HB_HAS_SELECT_TIMER ) + HB_ULONG timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); +#endif + + for( ;; ) + { + FD_ZERO( &wfds ); + FD_SET( sd, &wfds ); +#if defined( HB_OS_WIN ) + FD_ZERO( &efds ); + FD_SET( sd, &efds ); + pefds = &efds; +#else + pefds = NULL; +#endif + if( timeout >= 0 ) + { + tv.tv_sec = timeout / 1000; + tv.tv_usec = ( timeout % 1000 ) * 1000; + ptv = &tv; + } + else + ptv = NULL; + + iResult = select( sd + 1, NULL, &wfds, pefds, ptv ); + hb_socketSetOsError( iResult >= 0 ? 0 : HB_SOCK_GETERROR() ); +#if defined( HB_OS_WIN ) + if( iResult > 0 && FD_ISSET( sd, pefds ) ) + iResult = -1; + else +#endif + if( iResult == -1 && timeout > 0 && HB_SOCK_IS_EINTR() && + hb_vmRequestQuery() == 0 ) +#if defined( HB_HAS_SELECT_TIMER ) + continue; +#else + { + HB_ULONG timecurr = hb_dateMilliSeconds(); + if( timecurr > timer ) + { + timeout -= timecurr - timer; + if( timeout > 0 ) + continue; + } + } +#endif + break; + } +#if !defined( HB_OS_WIN ) + if( iResult > 0 && FD_ISSET( sd, &wfds ) ) + { + int iError; + socklen_t len = sizeof( iError ); + + if( getsockopt( sd, SOL_SOCKET, SO_ERROR, ( void * ) &iError, &len ) != 0 ) + { + iResult = -1; + hb_socketSetOsError( HB_SOCK_GETERROR() ); + } + else if( iError != 0 ) + { + iResult = -1; + hb_socketSetOsError( iError ); + } + } +#endif + + return iResult < 0 ? -1 : + ( iResult > 0 && FD_ISSET( sd, &wfds ) ? 1 : 0 ); +} + +int hb_socketGetAddrFamilly( const void * pSockAddr, unsigned len ) +{ + return pSockAddr && len ? ( ( struct sockaddr * ) pSockAddr )->sa_family : -1; +} + +BOOL hb_socketLocalAddr( void ** pSockAddr, unsigned * puiLen, + const char * szAddr ) +{ +#if defined( HB_HAS_UNIX ) + struct sockaddr_un sa; + memset( &sa, 0, sizeof( sa ) ); +#if defined( AF_UNIX ) + sa.sun_family = AF_UNIX; +#else + sa.sun_family = AF_LOCAL; +#endif + hb_strncpy( sa.sun_path, szAddr, sizeof( sa.sun_path ) - 1 ); + *pSockAddr = memcpy( hb_xgrab( sizeof( sa ) + 1 ), &sa, sizeof( sa ) ); + *puiLen = ( unsigned ) sizeof( sa ); + return TRUE; +#else + HB_SYMBOL_UNUSED( szAddr ); + *pSockAddr = NULL; + *puiLen = 0; + hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); + return FALSE; +#endif +} + +BOOL hb_socketInetAddr( void ** pSockAddr, unsigned * puiLen, + const char * szAddr, int iPort ) +{ +#if defined( AF_INET ) + struct sockaddr_in sa; + + memset( &sa, 0, sizeof( sa ) ); + sa.sin_family = AF_INET; + sa.sin_port = htons( ( hbU16 ) iPort ); +#if defined( HB_HAS_INET_PTON ) + if( inet_pton( AF_INET, szAddr, &sa.sin_addr ) > 0 ) +#elif defined( HB_HAS_INET_ATON ) + if( inet_aton( szAddr, &sa.sin_addr ) != 0 ) +#else + sa.sin_addr.s_addr = inet_addr( szAddr ); + if( sa.sin_addr.s_addr != INADDR_NONE || + strcmp( "255.255.255.255", szAddr ) == 0 ) /* dirty hack */ +#endif + { + *pSockAddr = memcpy( hb_xgrab( sizeof( sa ) + 1 ), &sa, sizeof( sa ) ); + *puiLen = ( unsigned ) sizeof( sa ); + return TRUE; + } + else + hb_socketSetRawError( HB_SOCKET_ERR_WRONGADDR ); +#else + HB_SYMBOL_UNUSED( szAddr ); + HB_SYMBOL_UNUSED( iPort ); + hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); +#endif + *pSockAddr = NULL; + *puiLen = 0; + return FALSE; +} + +BOOL hb_socketInet6Addr( void ** pSockAddr, unsigned * puiLen, + const char * szAddr, int iPort ) +{ +#if defined( HB_HAS_INET6 ) + struct sockaddr_in6 sa; + int err; + + memset( &sa, 0, sizeof( sa ) ); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons( ( hbU16 ) iPort ); +#if defined( HB_HAS_INET_PTON ) + err = inet_pton( AF_INET6, szAddr, &sa.sin6_addr ); + if( err > 0 ) + { + *pSockAddr = memcpy( hb_xgrab( sizeof( sa ) + 1 ), &sa, sizeof( sa ) ); + *puiLen = ( unsigned ) sizeof( sa ); + return TRUE; + } + else if( err == 0 ) + hb_socketSetRawError( HB_SOCKET_ERR_WRONGADDR ); + else + hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); +#else + int TODO; +#endif +#else + HB_SYMBOL_UNUSED( szAddr ); + HB_SYMBOL_UNUSED( iPort ); + hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); +#endif + *pSockAddr = NULL; + *puiLen = 0; + return FALSE; +} + +/* caller must free the buffer if not NULL */ +char * hb_socketAddrGetName( const void * pSockAddr, unsigned len ) +{ + char * szName = NULL; + + switch( hb_socketGetAddrFamilly( pSockAddr, len ) ) + { +#if defined( AF_INET ) + case AF_INET: + if( len >= sizeof( struct sockaddr_in ) ) + { + struct sockaddr_in * sa = ( struct sockaddr_in * ) pSockAddr; + const char * szAddr; +# if defined( HB_HAS_INET_NTOP ) + char buf[ INET_ADDRSTRLEN ]; + szAddr = inet_ntop( AF_INET, &sa->sin_addr, buf, sizeof( buf ) ); +# elif defined( HB_IS_INET_NTOA_MT_SAFE ) + szAddr = inet_ntoa( sa->sin_addr ); +# else + char buf[ INET_ADDRSTRLEN ]; + szAddr = hb_inet_ntoa( &sa->sin_addr, buf ); +# endif + if( szAddr ) + szName = hb_strdup( szAddr ); + } + break; +#endif +#if defined( HB_HAS_INET6 ) + case AF_INET6: + if( len >= sizeof( struct sockaddr_in6 ) ) + { + struct sockaddr_in6 * sa = ( struct sockaddr_in6 * ) pSockAddr; + const char * szAddr; +# if defined( HB_HAS_INET_NTOP ) + char buf[ INET6_ADDRSTRLEN ]; + szAddr = inet_ntop( AF_INET, &sa->sin6_addr, buf, sizeof( buf ) ); +# else + { + int TODO; + szAddr = NULL; + } +# endif + if( szAddr ) + szName = hb_strdup( szAddr ); + } + break; +#endif +#if defined( HB_HAS_UNIX ) +# if defined( AF_UNIX ) + case AF_UNIX: +# else + case AF_LOCAL: +# endif + if( len >= sizeof( struct sockaddr_un ) ) + { + struct sockaddr_un * sa = ( struct sockaddr_un * ) pSockAddr; + szName = hb_strdup( sa->sun_path ); + } + break; +#endif +#if defined( AF_IPX ) + case AF_IPX: + break; +#endif +#if defined( AF_PACKET ) + case AF_PACKET: + break; +#endif + } + hb_socketSetRawError( szName ? 0 : HB_SOCKET_ERR_AFNOSUPPORT ); + return szName; +} + +int hb_socketAddrGetPort( const void * pSockAddr, unsigned len ) +{ + int iPort = -1; + + switch( hb_socketGetAddrFamilly( pSockAddr, len ) ) + { +#if defined( AF_INET ) + case AF_INET: + if( len >= sizeof( struct sockaddr_in ) ) + iPort = ntohs( ( ( struct sockaddr_in * ) pSockAddr )->sin_port ); + break; +#endif +#if defined( HB_HAS_INET6 ) + case AF_INET6: + if( len >= sizeof( struct sockaddr_in6 ) ) + iPort = ntohs( ( ( struct sockaddr_in6 * ) pSockAddr )->sin6_port ); + break; +#endif +#if defined( HB_HAS_UNIX ) +# if defined( AF_UNIX ) + case AF_UNIX: +# else + case AF_LOCAL: +# endif + break; +#endif +#if defined( AF_IPX ) + case AF_IPX: + break; +#endif +#if defined( AF_PACKET ) + case AF_PACKET: + break; +#endif + } + hb_socketSetRawError( iPort != -1 ? 0 : HB_SOCKET_ERR_AFNOSUPPORT ); + return iPort; +} + +BOOL hb_socketAddrFromItem( void ** pSockAddr, unsigned * puiLen, PHB_ITEM pAddrItm ) +{ + BOOL fOK = FALSE; + + *pSockAddr = NULL; + *puiLen = 0; + + if( pAddrItm && HB_IS_ARRAY( pAddrItm ) ) + { + if( hb_arrayLen( pAddrItm ) >= 2 && + ( hb_arrayGetType( pAddrItm, 1 ) & HB_IT_NUMERIC ) != 0 ) + { + switch( hb_arrayGetNI( pAddrItm, 1 ) ) + { + case HB_SOCK_PF_INET: + fOK = hb_socketInetAddr( pSockAddr, puiLen, + hb_arrayGetCPtr( pAddrItm, 2 ), + hb_arrayGetNI( pAddrItm, 3 ) ); + break; + case HB_SOCK_PF_INET6: + fOK = hb_socketInet6Addr( pSockAddr, puiLen, + hb_arrayGetCPtr( pAddrItm, 2 ), + hb_arrayGetNI( pAddrItm, 3 ) ); + break; + case HB_SOCK_PF_LOCAL: + fOK = hb_socketLocalAddr( pSockAddr, puiLen, + hb_arrayGetCPtr( pAddrItm, 2 ) ); + break; + case HB_SOCK_PF_PACKET: + case HB_SOCK_PF_IPX: + break; + } + } + } + hb_socketSetRawError( fOK ? 0 : HB_SOCKET_ERR_AFNOSUPPORT ); + return fOK; +} + +PHB_ITEM hb_socketAddrToItem( const void * pSockAddr, unsigned len ) +{ + PHB_ITEM pAddrItm = NULL; + + switch( hb_socketGetAddrFamilly( pSockAddr, len ) ) + { +#if defined( AF_INET ) + case AF_INET: + if( len >= sizeof( struct sockaddr_in ) ) + { + struct sockaddr_in * sa = ( struct sockaddr_in * ) pSockAddr; + const char * szAddr; +# if defined( HB_HAS_INET_NTOP ) + char buf[ INET_ADDRSTRLEN ]; + szAddr = inet_ntop( AF_INET, &sa->sin_addr, buf, sizeof( buf ) ); +# elif defined( HB_IS_INET_NTOA_MT_SAFE ) + szAddr = inet_ntoa( sa->sin_addr ); +# else + char buf[ INET_ADDRSTRLEN ]; + szAddr = hb_inet_ntoa( &sa->sin_addr, buf ); +# endif + if( szAddr ) + { + pAddrItm = hb_itemArrayNew( 3 ); + hb_arraySetNI( pAddrItm, 1, HB_SOCK_PF_INET ); + hb_arraySetC( pAddrItm, 2, szAddr ); + hb_arraySetNI( pAddrItm, 3, ntohs( sa->sin_port ) ); + } + } + break; +#endif +#if defined( HB_HAS_INET6 ) + case AF_INET6: + if( len >= sizeof( struct sockaddr_in6 ) ) + { + struct sockaddr_in6 * sa = ( struct sockaddr_in6 * ) pSockAddr; + const char * szAddr; +# if defined( HB_HAS_INET_NTOP ) + char buf[ INET6_ADDRSTRLEN ]; + szAddr = inet_ntop( AF_INET, &sa->sin6_addr, buf, sizeof( buf ) ); +# else + { + int TODO; + szAddr = NULL; + } +# endif + if( szAddr ) + { + pAddrItm = hb_itemArrayNew( 3 ); + hb_arraySetNI( pAddrItm, 1, HB_SOCK_PF_INET6 ); + hb_arraySetC( pAddrItm, 2, szAddr ); + hb_arraySetNI( pAddrItm, 3, ntohs( sa->sin6_port ) ); + } + } + break; +#endif +#if defined( HB_HAS_UNIX ) +# if defined( AF_UNIX ) + case AF_UNIX: +# else + case AF_LOCAL: +# endif + if( len >= sizeof( struct sockaddr_un ) ) + { + struct sockaddr_un * sa = ( struct sockaddr_un * ) pSockAddr; + pAddrItm = hb_itemArrayNew( 2 ); + hb_arraySetNI( pAddrItm, 1, HB_SOCK_PF_LOCAL ); + hb_arraySetC( pAddrItm, 2, sa->sun_path ); + } + break; +#endif +#if defined( AF_IPX ) + case AF_IPX: + break; +#endif +#if defined( AF_PACKET ) + case AF_PACKET: + break; +#endif + } + hb_socketSetRawError( pAddrItm ? 0 : HB_SOCKET_ERR_AFNOSUPPORT ); + return pAddrItm; +} + +int hb_socketGetSockName( HB_SOCKET_T sd, void ** pSockAddr, unsigned * puiLen ) +{ + int ret; +#if defined( HB_HAS_SOCKADDR_STORAGE ) + struct sockaddr_storage st; + struct sockaddr * sa = ( struct sockaddr * ) ( void * ) &st; +#else + char st[ HB_SOCKADDR_MAX_LEN ]; + struct sockaddr * sa = ( struct sockaddr * ) ( void * ) st; +#endif + socklen_t len = sizeof( st ); + + ret = getsockname( sd, sa, &len ); + hb_socketSetOsError( ret == 0 ? 0 : HB_SOCK_GETERROR() ); + if( ret == 0 ) + { + *pSockAddr = memcpy( hb_xgrab( len + 1 ), sa, len ); + *puiLen = ( unsigned ) len; + } + else + { + *pSockAddr = NULL; + *puiLen = 0; + } + + return ret; +} + +int hb_socketGetPeerName( HB_SOCKET_T sd, void ** pSockAddr, unsigned * puiLen ) +{ + int ret; +#if defined( __WATCOMC__ ) && defined( HB_OS_LINUX ) + /* it's still not supported by Linux OpenWatcom port :-( */ + ret = -1; + hb_socketSetRawError( HB_SOCKET_ERR_NOSUPPORT ); +#else +#if defined( HB_HAS_SOCKADDR_STORAGE ) + struct sockaddr_storage st; + struct sockaddr * sa = ( struct sockaddr * ) ( void * ) &st; +#else + char st[ HB_SOCKADDR_MAX_LEN ]; + struct sockaddr * sa = ( struct sockaddr * ) ( void * ) st; +#endif + socklen_t len = sizeof( st ); + + ret = getpeername( sd, sa, &len ); + hb_socketSetOsError( ret == 0 ? 0 : HB_SOCK_GETERROR() ); + if( ret == 0 ) + { + *pSockAddr = memcpy( hb_xgrab( len + 1 ), sa, len ); + *puiLen = ( unsigned ) len; + } + else +#endif + { + *pSockAddr = NULL; + *puiLen = 0; + } + + return ret; +} + +HB_SOCKET_T hb_socketOpen( int domain, int type, int protocol ) +{ + HB_SOCKET_T sd = HB_NO_SOCKET; + int err = 0; + +#if defined( HB_SOCKET_TRANSLATE_DOMAIN ) + switch( domain ) + { + case HB_SOCK_PF_INET: +#if defined( PF_INET ) + domain = PF_INET; +#elif defined( AF_INET ) + domain = AF_INET; +#else + err = HB_SOCKET_ERR_PFNOSUPPORT; +#endif + break; + + case HB_SOCK_PF_INET6: +#if defined( PF_INET6 ) + domain = PF_INET6; +#elif defined( AF_INET6 ) + domain = AF_INET6; +#else + err = HB_SOCKET_ERR_PFNOSUPPORT; +#endif + break; + + case HB_SOCK_PF_LOCAL: +#if defined( PF_LOCAL ) + domain = PF_LOCAL; +#elif defined( AF_LOCAL ) + domain = AF_LOCAL; +#elif defined( PF_UNIX ) + domain = PF_UNIX; +#elif defined( AF_UNIX ) + domain = AF_UNIX; +#else + err = HB_SOCKET_ERR_PFNOSUPPORT; +#endif + break; + + case HB_SOCK_PF_PACKET: +#if defined( PF_PACKET ) + domain = PF_PACKET; +#elif defined( AF_PACKET ) + domain = AF_PACKET; +#else + err = HB_SOCKET_ERR_PFNOSUPPORT; +#endif + break; + + case HB_SOCK_PF_IPX: +#if defined( PF_IPX ) + domain = PF_IPX; +#elif defined( AF_ ) + domain = AF_IPX; +#else + err = HB_SOCKET_ERR_PFNOSUPPORT; +#endif + break; + + default: + err = HB_SOCKET_ERR_PFNOSUPPORT; + } +#endif + +#if defined( HB_SOCKET_TRANSLATE_TYPE ) + if( err == 0 ) switch( type ) + { + case HB_SOCK_STREAM: +#if defined( SOCK_STREAM ) + type = SOCK_STREAM; +#else + err = HB_SOCKET_ERR_PROTONOSUPPORT; +#endif + break; + + case HB_SOCK_DGRAM: +#if defined( SOCK_DGRAM ) + type = SOCK_DGRAM; +#else + err = HB_SOCKET_ERR_PROTONOSUPPORT; +#endif + break; + + case HB_SOCK_SEQPACKET: +#if defined( SOCK_SEQPACKET ) + type = SOCK_SEQPACKET; +#else + err = HB_SOCKET_ERR_PROTONOSUPPORT; +#endif + break; + + case HB_SOCK_RAW: +#if defined( SOCK_RAW ) + type = SOCK_RAW; +#else + err = HB_SOCKET_ERR_PROTONOSUPPORT; +#endif + break; + + case HB_SOCK_RDM: +#if defined( SOCK_RDM ) + type = SOCK_RDM; +#else + err = HB_SOCKET_ERR_PROTONOSUPPORT; +#endif + break; + + default: + err = HB_SOCKET_ERR_PROTONOSUPPORT; + } +#endif + + if( err == 0 ) + { + sd = socket( domain, type, protocol ); + hb_socketSetOsError( sd != HB_NO_SOCKET ? 0 : HB_SOCK_GETERROR() ); + } + else + hb_socketSetRawError( err ); + + return sd; +} + +int hb_socketClose( HB_SOCKET_T sd ) +{ + int ret; + + hb_vmUnlock(); +#if defined( HB_OS_WIN ) + ret = closesocket( sd ); +#else +# if defined EINTR + /* ignoring EINTR in close() it's quite common bug when sockets or + * pipes are used. Without such protection it's not safe to use + * signals in user code. + */ + do + ret = close( sd ); + while( ret == -1 && errno == EINTR ); +# else + ret = close( sd ); +# endif +#endif + hb_socketSetOsError( ret == 0 ? 0 : HB_SOCK_GETERROR() ); + hb_vmLock(); + + return ret; +} + +int hb_socketShutdown( HB_SOCKET_T sd, int iMode ) +{ + int ret; + +#if defined( HB_OS_WIN ) + if( iMode == HB_SOCK_SHUT_RD ) + iMode = SD_RECEIVE; + else if( iMode == HB_SOCK_SHUT_WR ) + iMode = SD_SEND; + else if( iMode == HB_SOCK_SHUT_RDWR ) + iMode = SD_BOTH; +#elif defined( HB_OS_OS2 ) + if( iMode == HB_SOCK_SHUT_RD ) + iMode = SO_RCV_SHUTDOWN; + else if( iMode == HB_SOCK_SHUT_WR ) + iMode = SO_SND_SHUTDOWN; + else if( iMode == HB_SOCK_SHUT_RDWR ) + iMode = SO_RCV_SHUTDOWN | SO_SND_SHUTDOWN; +#elif defined( __WATCOMC__ ) + if( iMode == HB_SOCK_SHUT_RD || + iMode == HB_SOCK_SHUT_WR || + iMode == HB_SOCK_SHUT_RDWR ) + { ; } +#else + if( iMode == HB_SOCK_SHUT_RD ) + iMode = SHUT_RD; + else if( iMode == HB_SOCK_SHUT_WR ) + iMode = SHUT_WR; + else if( iMode == HB_SOCK_SHUT_RDWR ) + iMode = SHUT_RDWR; +#endif + else + { + hb_socketSetRawError( HB_SOCKET_ERR_PARAMVALUE ); + return -1; + } + +#if defined( __WATCOMC__ ) && defined( HB_OS_LINUX ) + /* it's still not supported by Linux OpenWatcom port :-( */ + ret = -1; + hb_socketSetRawError( HB_SOCKET_ERR_NOSUPPORT ); +#else + hb_vmUnlock(); + ret = shutdown( sd, iMode ); + hb_socketSetOsError( ret == 0 ? 0 : HB_SOCK_GETERROR() ); + hb_vmLock(); +#endif + return ret; +} + +int hb_socketBind( HB_SOCKET_T sd, const void * pSockAddr, unsigned uiLen ) +{ + int ret; + + /* it allows to reuse port immediately without timeout used to + * clean all pending connections addressed to previous port owner + */ + hb_socketSetReuseAddr( sd, TRUE ); + + ret = bind( sd, ( struct sockaddr * ) pSockAddr, ( socklen_t ) uiLen ); + hb_socketSetOsError( ret == 0 ? 0 : HB_SOCK_GETERROR() ); + + return ret; +} + +int hb_socketListen( HB_SOCKET_T sd, int iBacklog ) +{ + int ret; + + ret = listen( sd, iBacklog ); + hb_socketSetOsError( ret == 0 ? 0 : HB_SOCK_GETERROR() ); + + return ret; +} + +HB_SOCKET_T hb_socketAccept( HB_SOCKET_T sd, void ** pSockAddr, unsigned * puiLen, HB_LONG timeout ) +{ + HB_SOCKET_T newsd = HB_NO_SOCKET; + int ret; +#if defined( HB_HAS_SOCKADDR_STORAGE ) + struct sockaddr_storage st; + struct sockaddr * sa = ( struct sockaddr * ) ( void * ) &st; +#else + char st[ HB_SOCKADDR_MAX_LEN ]; + struct sockaddr * sa = ( struct sockaddr * ) ( void * ) st; +#endif + socklen_t len = sizeof( st ); + + hb_vmUnlock(); + ret = hb_socketSelectRD( sd, timeout ); + if( ret > 0 ) + { + /* it's necessary to set non blocking IO to be sure that application + * will not be frozen inside accept(). It may happen if some asynchronous + * network error appear after above select() or when other thread + * accepts incoming connection (concurrent calls). + */ + ret = timeout < 0 ? 0 : hb_socketSetBlockingIO( sd, FALSE ); + newsd = accept( sd, sa, &len ); + hb_socketSetOsError( newsd != HB_NO_SOCKET ? 0 : HB_SOCK_GETERROR() ); + if( ret > 0 ) + hb_socketSetBlockingIO( sd, TRUE ); + if( pSockAddr && puiLen ) + { + if( newsd == HB_NO_SOCKET ) + { + *pSockAddr = NULL; + *puiLen = 0; + } + else + { + *pSockAddr = memcpy( hb_xgrab( len + 1 ), sa, len ); + *puiLen = ( unsigned ) len; + } + } + } + else if( ret == 0 ) + hb_socketSetRawError( HB_SOCKET_ERR_TIMEOUT ); + hb_vmLock(); + return newsd; +} + +int hb_socketConnect( HB_SOCKET_T sd, const void * pSockAddr, unsigned uiLen, HB_LONG timeout ) +{ + int ret, blk; + + hb_vmUnlock(); + + /* set not blocking IO to implement timeout in connect() operation in + * portable way without using signals + */ + blk = timeout < 0 ? 0 : hb_socketSetBlockingIO( sd, FALSE ); + ret = connect( sd, ( struct sockaddr * ) pSockAddr, ( socklen_t ) uiLen ); + hb_socketSetOsError( ret == 0 ? 0 : HB_SOCK_GETERROR() ); + if( ret != 0 && HB_SOCK_IS_EINPROGRES() && timeout >= 0 ) + { + /* inside hb_socketSelectWRE() we have code which hides differences + * between Windows and POSIX platforms in error detection. + */ + ret = hb_socketSelectWRE( sd, timeout ); + if( ret > 0 ) + ret = 0; + else if( ret == 0 ) + { + hb_socketSetRawError( HB_SOCKET_ERR_TIMEOUT ); + ret = -1; + } + } + if( blk > 0 ) + hb_socketSetBlockingIO( sd, TRUE ); + hb_vmLock(); + return ret; +} + +long hb_socketSend( HB_SOCKET_T sd, const void * data, long len, int flags, HB_LONG timeout ) +{ + long lSent = 0; + int ret = 0; + + hb_vmUnlock(); + + if( timeout >= 0 ) + { + ret = hb_socketSelectRD( sd, timeout ); + if( ret == 0 ) + { + hb_socketSetRawError( HB_SOCKET_ERR_TIMEOUT ); + ret = -1; + } + } + if( ret >= 0 ) + { + /* in POSIX systems writing data to broken connection stream causes + * that system generates SIGPIPE which has to be caught by application + * otherwise the default action for SIGPIPE is application termination. + * we do not want to generate it so we are setting MSG_NOSIGNAL flag. + */ +#if defined( MSG_NOSIGNAL ) + flags |= MSG_NOSIGNAL; +#endif + do + { + lSent = send( sd, ( const char * ) data, len, flags ); + hb_socketSetOsError( HB_SOCK_GETERROR() ); + } + while( lSent == -1 && HB_SOCK_IS_EINTR() && hb_vmRequestQuery() == 0 ); + } + hb_vmLock(); + + return lSent; +} + +long hb_socketSendTo( HB_SOCKET_T sd, const void * data, long len, int flags, + const void * pSockAddr, unsigned uiSockLen, HB_LONG timeout ) +{ + long lSent = 0; + int ret = 0; + + hb_vmUnlock(); + + if( timeout >= 0 ) + { + ret = hb_socketSelectRD( sd, timeout ); + if( ret == 0 ) + { + hb_socketSetRawError( HB_SOCKET_ERR_TIMEOUT ); + ret = -1; + } + } + if( ret >= 0 ) + { + /* see note above about SIGPIPE */ +#if defined( MSG_NOSIGNAL ) + flags |= MSG_NOSIGNAL; +#endif + do + { + lSent = sendto( sd, ( const char * ) data, len, flags, + ( struct sockaddr * ) pSockAddr, ( socklen_t ) uiSockLen ); + hb_socketSetOsError( HB_SOCK_GETERROR() ); + } + while( lSent == -1 && HB_SOCK_IS_EINTR() && hb_vmRequestQuery() == 0 ); + } + hb_vmLock(); + + return lSent; +} + +long hb_socketRecv( HB_SOCKET_T sd, void * data, long len, int flags, HB_LONG timeout ) +{ + long lReceived = 0; + int ret = 0; + + hb_vmUnlock(); + + if( timeout >= 0 ) + { + ret = hb_socketSelectWR( sd, timeout ); + if( ret == 0 ) + { + hb_socketSetRawError( HB_SOCKET_ERR_TIMEOUT ); + ret = -1; + } + } + if( ret >= 0 ) + { + do + { + lReceived = recv( sd, ( char * ) data, len, flags ); + hb_socketSetOsError( HB_SOCK_GETERROR() ); + } + while( lReceived == -1 && HB_SOCK_IS_EINTR() && hb_vmRequestQuery() == 0 ); + } + hb_vmLock(); + + return lReceived; +} + +long hb_socketRecvFrom( HB_SOCKET_T sd, void * data, long len, int flags, void ** pSockAddr, unsigned * puiSockLen, HB_LONG timeout ) +{ + long lReceived = 0; + int ret = 0; + + hb_vmUnlock(); + + if( timeout >= 0 ) + { + ret = hb_socketSelectWR( sd, timeout ); + if( ret == 0 ) + { + hb_socketSetRawError( HB_SOCKET_ERR_TIMEOUT ); + ret = -1; + } + } + if( ret >= 0 ) + { +#if defined( HB_HAS_SOCKADDR_STORAGE ) + struct sockaddr_storage st; + struct sockaddr * sa = ( struct sockaddr * ) ( void * ) &st; +#else + char st[ HB_SOCKADDR_MAX_LEN ]; + struct sockaddr * sa = ( struct sockaddr * ) ( void * ) st; +#endif + socklen_t salen = sizeof( st ); + + do + { + lReceived = recvfrom( sd, ( char * ) data, len, flags, sa, &salen ); + hb_socketSetOsError( HB_SOCK_GETERROR() ); + } + while( lReceived == -1 && HB_SOCK_IS_EINTR() && hb_vmRequestQuery() == 0 ); + + if( pSockAddr && puiSockLen ) + { + if( lReceived == -1 ) + { + *pSockAddr = NULL; + *puiSockLen = 0; + } + else + { + *pSockAddr = memcpy( hb_xgrab( salen + 1 ), sa, salen ); + *puiSockLen = ( unsigned ) salen; + } + } + } + hb_vmLock(); + + return lReceived; +} + +int hb_socketSetBlockingIO( HB_SOCKET_T sd, BOOL fBlocking ) +{ + int ret; +#if defined( HB_OS_WIN ) + u_long mode = fBlocking ? 0 : 1; + ret = ioctlsocket( sd, FIONBIO, &mode ); + hb_socketSetOsError( ret != -1 ? 0 : HB_SOCK_GETERROR() ); + if( ret == 0 ) + ret = 1; +#elif defined( O_NONBLOCK ) + ret = fcntl( sd, F_GETFL, 0 ); + if( ret != -1 ) + { + BOOL fBlocked; + long flags; + fBlocked = ( ret & O_NONBLOCK ) == 0; + if( fBlocking ? !fBlocked : fBlocked ) + { + if( fBlocking ) + flags = ret & ~O_NONBLOCK; + else + flags = ret | O_NONBLOCK; + ret = fcntl( sd, F_SETFL, flags ); + if( ret == 0 ) + ret = 1; + } + else + ret = 0; + } + hb_socketSetOsError( ret != -1 ? 0 : HB_SOCK_GETERROR() ); +#else + int TODO; + HB_SYMBOL_UNUSED( sd ); + HB_SYMBOL_UNUSED( fBlocking ); + hb_socketSetRawError( HB_SOCKET_ERR_NOSUPPORT ); + ret = -1; +#endif + return ret; +} + +int hb_socketSetReuseAddr( HB_SOCKET_T sd, BOOL fReuse ) +{ + /* it allows to reuse port immediately without timeout used to + * clean all pending connections addressed to previous port owner + */ + int val = fReuse ? 1 : 0; + return setsockopt( sd, SOL_SOCKET, SO_REUSEADDR, ( const char * ) &val, sizeof( val ) ); +} + +int hb_socketSetKeepAlive( HB_SOCKET_T sd, BOOL fKeepAlive ) +{ + int val = fKeepAlive ? 1 : 0; + return setsockopt( sd, SOL_SOCKET, SO_KEEPALIVE, ( const char * ) &val, sizeof( val ) ); +} + +int hb_socketSetBroadcast( HB_SOCKET_T sd, BOOL fBroadcast ) +{ + int val = fBroadcast ? 1 : 0; + return setsockopt( sd, SOL_SOCKET, SO_BROADCAST, ( const char * ) &val, sizeof( val ) ); +} + +int hb_socketSetSndBufSize( HB_SOCKET_T sd, int iSize ) +{ + return setsockopt( sd, SOL_SOCKET, SO_SNDBUF, ( const char * ) &iSize, sizeof( iSize ) ); +} + +int hb_socketSetRcvBufSize( HB_SOCKET_T sd, int iSize ) +{ + return setsockopt( sd, SOL_SOCKET, SO_RCVBUF, ( const char * ) &iSize, sizeof( iSize ) ); +} + +int hb_socketGetSndBufSize( HB_SOCKET_T sd, int * piSize ) +{ + socklen_t len = sizeof( * piSize ); + return getsockopt( sd, SOL_SOCKET, SO_SNDBUF, ( char * ) piSize, &len ); +} + +int hb_socketGetRcvBufSize( HB_SOCKET_T sd, int * piSize ) +{ + socklen_t len = sizeof( * piSize ); + return getsockopt( sd, SOL_SOCKET, SO_RCVBUF, ( char * ) piSize, &len ); +} + +int hb_socketSetMulticast( HB_SOCKET_T sd, int af, const char * szAddr ) +{ + if( af == HB_SOCK_AF_INET ) + { +#if defined( IP_ADD_MEMBERSHIP ) && defined( IPPROTO_IP ) + struct ip_mreq mreq; + + mreq.imr_multiaddr.s_addr = inet_addr( szAddr ); + mreq.imr_interface.s_addr = htonl( INADDR_ANY ); + + return setsockopt( sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, ( const char * ) &mreq, sizeof( mreq ) ); +#else + int TODO; +#endif + } +#if defined( HB_HAS_INET6 ) + else if( af == HB_SOCK_AF_INET6 ) + { +#if defined( HB_HAS_INET_PTON ) && defined( IN6ADDR_ANY_INIT ) + struct ipv6_mreq mreq; + int err = inet_pton( AF_INET6, szAddr, &mreq.ipv6mr_multiaddr ); + if( err > 0 ) + { + const struct in6_addr ia = IN6ADDR_ANY_INIT; + memcpy( &mreq.ipv6mr_interface, &ia, sizeof( struct in6_addr ) ); + return setsockopt( sd, IPPROTO_IPV6, IPV6_JOIN_GROUP, ( const char * ) &mreq, sizeof( mreq ) ); + } + else if( err == 0 ) + hb_socketSetRawError( HB_SOCKET_ERR_WRONGADDR ); + else + hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); + return -1; +#else + int TODO; +#endif + } +#endif + + hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); + return -1; +} + +int hb_socketSelectRead( HB_SOCKET_T sd, HB_LONG timeout ) +{ + int ret; + + hb_vmUnlock(); + ret = hb_socketSelectRD( sd, timeout ); + hb_vmLock(); + + return ret; +} + +int hb_socketSelectWrite( HB_SOCKET_T sd, HB_LONG timeout ) +{ + int ret; + + hb_vmUnlock(); + ret = hb_socketSelectWR( sd, timeout ); + hb_vmLock(); + + return ret; +} + +int hb_socketSelectWriteEx( HB_SOCKET_T sd, HB_LONG timeout ) +{ + int ret; + + hb_vmUnlock(); + ret = hb_socketSelectWRE( sd, timeout ); + hb_vmLock(); + + return ret; +} + +int hb_socketSelect( PHB_ITEM pArrayRD, BOOL fSetRD, + PHB_ITEM pArrayWR, BOOL fSetWR, + PHB_ITEM pArrayEX, BOOL fSetEX, + HB_LONG timeout, HB_SOCK_FUNC pFunc ) +{ + HB_SOCKET_T maxsd, sd; + int i, ret; + ULONG ulLen, ulPos, ul; + PHB_ITEM pItemSets[ 3 ]; + BOOL pSet[ 3 ]; + fd_set fds[3], *pfds[ 3 ]; + struct timeval tv, *ptv; + + pItemSets[ 0 ] = pArrayRD; + pItemSets[ 1 ] = pArrayWR; + pItemSets[ 2 ] = pArrayEX; + pSet[ 0 ] = fSetRD; + pSet[ 1 ] = fSetWR; + pSet[ 2 ] = fSetEX; + + maxsd = 0; + for( i = 0; i < 3; i++ ) + { + ret = 0; + ulLen = pItemSets[ i ] ? hb_arrayLen( pItemSets[ i ] ) : 0; + if( ulLen > 0 ) + { + FD_ZERO( &fds[ i ] ); + for( ul = 1; ul <= ulLen; ul++ ) + { + if( pFunc ) + sd = pFunc( hb_arrayGetItemPtr( pItemSets[ i ], ul ) ); + else + { + HB_TYPE type = hb_arrayGetType( pItemSets[ i ], ul ); + if( type & HB_IT_NUMERIC ) + sd = ( HB_SOCKET_T ) hb_arrayGetNInt( pItemSets[ i ], ul ); + else if( type & HB_IT_POINTER ) + sd = ( HB_SOCKET_T ) ( HB_PTRDIFF ) hb_arrayGetPtr( pItemSets[ i ], ul ); + else + sd = HB_NO_SOCKET; + } + if( sd != HB_NO_SOCKET ) + { + if( maxsd < sd ) + maxsd = sd; + FD_SET( sd, &fds[ i ] ); + ret = 1; + } + } + } + pfds[ i ] = ret ? &fds[ i ] : NULL; + } + + if( timeout >= 0 ) + { + tv.tv_sec = ( timeout / 1000 ); + tv.tv_usec = ( timeout % 1000 ) * 1000; + ptv = &tv; + } + else + ptv = NULL; + + ret = select( maxsd + 1, pfds[ 0 ], pfds[ 1 ], pfds[ 2 ], ptv ); + + for( i = 0; i < 3; i++ ) + { + if( pfds[ i ] && pSet[ i ] ) + { + ulPos = 0; + if( ret > 0 ) + { + ulLen = hb_arrayLen( pItemSets[ i ] ); + for( ul = 1; ul <= ulLen; ul++ ) + { + if( pFunc ) + sd = pFunc( hb_arrayGetItemPtr( pItemSets[ i ], ul ) ); + else + { + HB_TYPE type = hb_arrayGetType( pItemSets[ i ], ul ); + if( type & HB_IT_NUMERIC ) + sd = ( HB_SOCKET_T ) hb_arrayGetNInt( pItemSets[ i ], ul ); + else if( type & HB_IT_POINTER ) + sd = ( HB_SOCKET_T ) ( HB_PTRDIFF ) hb_arrayGetPtr( pItemSets[ i ], ul ); + else + sd = HB_NO_SOCKET; + } + if( sd != HB_NO_SOCKET && FD_ISSET( sd, pfds[ i ] ) ) + { + if( ++ulPos != ul ) + { + hb_itemCopy( hb_arrayGetItemPtr( pItemSets[ i ], ulPos ), + hb_arrayGetItemPtr( pItemSets[ i ], ul ) ); + } + } + } + } + hb_arraySize( pItemSets[ i ], ulPos ); + } + } + + return ret; +} + +/* DNS functions */ +char * hb_socketResolveAddr( const char * szAddr, int af ) +{ + char * szResult = NULL; + +#ifdef HB_HAS_ADDRINFO + +#if defined( HB_SOCKET_TRANSLATE_DOMAIN ) + switch( af ) + { + case HB_SOCK_PF_INET: +#if defined( PF_INET ) + af = PF_INET; +#elif defined( AF_INET ) + af = AF_INET; +#endif + break; + + case HB_SOCK_PF_INET6: +#if defined( PF_INET6 ) + af = PF_INET6; +#elif defined( AF_INET6 ) + af = AF_INET6; +#endif + break; + + case HB_SOCK_PF_LOCAL: +#if defined( PF_LOCAL ) + af = PF_LOCAL; +#elif defined( AF_LOCAL ) + af = AF_LOCAL; +#elif defined( PF_UNIX ) + af = PF_UNIX; +#elif defined( AF_UNIX ) + af = AF_UNIX; +#endif + break; + + case HB_SOCK_PF_PACKET: +#if defined( PF_PACKET ) + af = PF_PACKET; +#elif defined( AF_PACKET ) + af = AF_PACKET; +#endif + break; + + case HB_SOCK_PF_IPX: +#if defined( PF_IPX ) + af = PF_IPX; +#elif defined( AF_ ) + af = AF_IPX; +#endif + break; + } +#endif + + { + struct addrinfo hints, *res = NULL; + + hb_vmUnlock(); + + memset( &hints, 0, sizeof( hints ) ); + hints.ai_family = af; + if( getaddrinfo( szAddr, NULL, &hints, &res ) == 0 ) + { + szResult = hb_socketAddrGetName( res->ai_addr, res->ai_addrlen ); + freeaddrinfo( res ); + } + + hb_vmLock(); + } +#else + + if( af == HB_SOCK_PF_INET ) + { + struct hostent * he = NULL; + + hb_vmUnlock(); + + /* gethostbyname() in Windows and OS2 does not accept direct IP + * addresses + */ +#if defined( HB_OS_WIN ) || defined( HB_OS_OS2 ) + { + ULONG addr = inet_addr( szAddr ); + if( addr != INADDR_NONE || strcmp( "255.255.255.255", szAddr ) == 0 ) + he = gethostbyaddr( ( const char * ) &addr, sizeof( addr ), AF_INET ); + } +#endif + if( he == NULL ) + he = gethostbyname( szAddr ); + + if( he && he->h_addr_list[ 0 ] ) + szResult = hb_strdup( he->h_addr_list[ 0 ] ); + + hb_vmLock(); + } +#if defined( HB_HAS_INET6 ) + else if( af == HB_SOCK_PF_INET6 ) + { + int TODO; + } +#endif + +#endif + + return szResult; +} + +PHB_ITEM hb_socketGetHosts( const char * szAddr, int af ) +{ + PHB_ITEM pItem = NULL; + +#ifdef HB_HAS_ADDRINFO + +#if defined( HB_SOCKET_TRANSLATE_DOMAIN ) + switch( af ) + { + case HB_SOCK_PF_INET: +#if defined( PF_INET ) + af = PF_INET; +#elif defined( AF_INET ) + af = AF_INET; +#endif + break; + + case HB_SOCK_PF_INET6: +#if defined( PF_INET6 ) + af = PF_INET6; +#elif defined( AF_INET6 ) + af = AF_INET6; +#endif + break; + + case HB_SOCK_PF_LOCAL: +#if defined( PF_LOCAL ) + af = PF_LOCAL; +#elif defined( AF_LOCAL ) + af = AF_LOCAL; +#elif defined( PF_UNIX ) + af = PF_UNIX; +#elif defined( AF_UNIX ) + af = AF_UNIX; +#endif + break; + + case HB_SOCK_PF_PACKET: +#if defined( PF_PACKET ) + af = PF_PACKET; +#elif defined( AF_PACKET ) + af = AF_PACKET; +#endif + break; + + case HB_SOCK_PF_IPX: +#if defined( PF_IPX ) + af = PF_IPX; +#elif defined( AF_ ) + af = AF_IPX; +#endif + break; + } +#endif + + { + struct addrinfo hints, *res = NULL, *ai; + int iResult; + + hb_vmUnlock(); + memset( &hints, 0, sizeof( hints ) ); + hints.ai_family = af; + iResult = getaddrinfo( szAddr, NULL, &hints, &res ); + hb_vmLock(); + + if( iResult == 0 ) + { + int iCount = 0, i; + ai = res; + while( ai ) + { + ++iCount; + ai = ai->ai_next; + } + if( iCount ) + { + pItem = hb_itemArrayNew( iCount ); + ai = res; + iCount = 0; + while( ai ) + { + char * szResult = hb_socketAddrGetName( res->ai_addr, res->ai_addrlen ); + if( szResult ) + { + for( i = 1; i <= iCount; ++i ) + { + if( strcmp( hb_arrayGetCPtr( pItem, i ), szResult ) == 0 ) + { + hb_xfree( szResult ); + szResult = NULL; + break; + } + } + if( szResult ) + { + ++iCount; + if( !hb_arraySetCLPtr( pItem, iCount, szResult, strlen( szResult ) ) ) + hb_xfree( szResult ); + } + } + ai = ai->ai_next; + } + hb_arraySize( pItem, iCount ); + } + freeaddrinfo( res ); + } + } +#else + + if( af == HB_SOCK_PF_INET ) + { + struct hostent * he = NULL; + int iCount = 0; + + hb_vmUnlock(); + + /* gethostbyname() in Windows and OS2 does not accept direct IP + * addresses + */ +#if defined( HB_OS_WIN ) || defined( HB_OS_OS2 ) + { + ULONG addr = inet_addr( szAddr ); + if( addr != INADDR_NONE || strcmp( "255.255.255.255", szAddr ) == 0 ) + he = gethostbyaddr( ( const char * ) &addr, sizeof( addr ), AF_INET ); + } +#endif + if( he == NULL ) + he = gethostbyname( szAddr ); + + hb_vmLock(); + + if( he ) + { + while( he->h_addr_list[ iCount ] ) + ++iCount; + } + if( iCount > 0 ) + { + pItem = hb_itemArrayNew( iCount ); + do + { + struct in_addr * sin = ( struct in_addr * ) he->h_addr_list[ iCount - 1 ]; +# if defined( HB_HAS_INET_NTOP ) + char buf[ INET_ADDRSTRLEN ]; + szAddr = inet_ntop( AF_INET, sin, buf, sizeof( buf ) ); +# elif defined( HB_IS_INET_NTOA_MT_SAFE ) + szAddr = inet_ntoa( *sin ); +# else + char buf[ INET_ADDRSTRLEN ]; + szAddr = hb_inet_ntoa( sin, buf ); +# endif + hb_arraySetC( pItem, iCount, szAddr ); + } + while( --iCount ); + } + } +#if defined( HB_HAS_INET6 ) + else if( af == HB_SOCK_PF_INET6 ) + { + int TODO; + } +#endif + +#endif + + return pItem; +} + +PHB_ITEM hb_socketGetAliases( const char * szAddr, int af ) +{ + /* TODO: implement it */ + HB_SYMBOL_UNUSED( szAddr ); + HB_SYMBOL_UNUSED( af ); + hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); + return NULL; +} + +#endif /* !HB_SOCKET_OFF */ diff --git a/harbour/source/vm/hvm.c b/harbour/source/vm/hvm.c index 43870cf201..1d0f4d585e 100644 --- a/harbour/source/vm/hvm.c +++ b/harbour/source/vm/hvm.c @@ -7499,8 +7499,8 @@ void hb_vmFreeSymbols( PHB_SYMBOLS pSymbols ) if( pSymbol->pDynSym && pSymbol->pDynSym->pSymbol != pSymbol && ( pSymbol->scope.value & HB_FS_LOCAL ) == 0 ) pSymbol->scope.value |= HB_FS_DEFERRED; + pSymbol->scope.value &= ~( HB_FS_PCODEFUNC | HB_FS_DYNCODE ); } - pSymbol->scope.value &= ~( HB_FS_PCODEFUNC | HB_FS_DYNCODE ); } pSymbols->hDynLib = NULL; pSymbols->fActive = FALSE;