Files
harbour-core/harbour/source/rtl/hbsocket.c
Przemyslaw Czerpak 2abefe1b3e 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-27 21:43:31 +00:00

2737 lines
68 KiB
C

/*
* $Id$
*/
/*
* Harbour Project source code:
* socket C API
*
* Copyright 2009 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
* 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 <winsock2.h>
# include <ws2tcpip.h>
#else
# include <errno.h>
# if defined( HB_OS_OS2 )
# if defined( __WATCOMC__ )
# include <types.h>
# include <nerrno.h>
# endif
# include <sys/select.h>
# include <sys/ioctl.h>
# endif
# include <sys/time.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <netdb.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# if defined( HB_HAS_UNIX )
# include <sys/un.h>
# endif
# include <unistd.h>
# include <fcntl.h>
#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 */