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;