* 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.
2737 lines
68 KiB
C
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 */
|