* source/rtl/hbsocket.c
- Reverted patch committed in 2009-09-18 12:19. It was
overridden by an enhanced version in 2009-09-18 12:37.
2795 lines
71 KiB
C
2795 lines
71 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 ) && !defined( HB_HAS_WATT )
|
|
# 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 constant inet6 addresses in6addr_any and in6addr_loopback:
|
|
#define HB_HAS_INET6_ADDR_CONST
|
|
|
|
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 macros 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 ) && ! defined( __CYGWIN__ )
|
|
# 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_SOCKADDR_STORAGE
|
|
# define HB_HAS_ADDRINFO
|
|
# endif
|
|
# if !defined( __WATCOMC__ ) && !defined( HB_OS_BEOS )
|
|
# define HB_HAS_INET6
|
|
# define HB_HAS_INET6_ADDR_CONST
|
|
# endif
|
|
# if defined( HB_OS_BEOS )
|
|
# define HB_SOCKET_TRANSLATE_DOMAIN
|
|
# define HB_SOCKET_TRANSLATE_TYPE
|
|
# 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__ ) && !defined( __XCC__ )
|
|
# 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
|
|
/* test shows that GCC 3.3.6 does not support inet_pton() and inet_ntop() */
|
|
# endif
|
|
#elif defined( HB_OS_DOS )
|
|
# define HB_HAS_INET_ATON
|
|
# define HB_HAS_INET_PTON
|
|
# define HB_HAS_INET_NTOP
|
|
# define HB_HAS_SOCKADDR_STORAGE
|
|
# define HB_HAS_ADDRINFO
|
|
# define HB_HAS_INET6_ADDR_CONST
|
|
/* # define HB_HAS_INET6 */
|
|
#endif
|
|
|
|
|
|
#if defined( HB_OS_WIN ) && ! defined( HB_OS_UNIX )
|
|
# include <winsock2.h>
|
|
# include <ws2tcpip.h>
|
|
#else
|
|
# include <errno.h>
|
|
# if defined( HB_OS_DOS )
|
|
# if defined( __WATCOMC__ )
|
|
/* workaround for declaration conflicts in tcp.h */
|
|
# define _GETOPT_H
|
|
# endif
|
|
# include <tcp.h>
|
|
# elif defined( HB_OS_OS2 )
|
|
# if defined( __WATCOMC__ )
|
|
# include <types.h>
|
|
# include <nerrno.h>
|
|
# endif
|
|
# include <sys/select.h>
|
|
# include <sys/ioctl.h>
|
|
# endif
|
|
# if !( defined( HB_OS_DOS ) && defined( __WATCOMC__ ) )
|
|
# include <sys/time.h>
|
|
# endif
|
|
# 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>
|
|
# if defined( HB_OS_DOS )
|
|
# include <sys/ioctl.h>
|
|
# define select select_s
|
|
# endif
|
|
#endif
|
|
|
|
#if defined( __CYGWIN__ )
|
|
#undef HB_OS_WIN
|
|
#endif
|
|
|
|
#if defined( HB_OS_OS2 ) || defined( HB_OS_WIN ) || defined( HB_OS_DOS )
|
|
# define socklen_t int
|
|
#endif
|
|
|
|
#if !defined( INET_ADDRSTRLEN )
|
|
# define INET_ADDRSTRLEN 16
|
|
#endif
|
|
|
|
#if defined( HB_OS_DOS ) && !defined( SHUT_RD )
|
|
# define SHUT_RD 0
|
|
# define SHUT_WR 1
|
|
# define SHUT_RDWR 2
|
|
#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 */
|
|
static 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 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 sd, void ** pSockAddr, unsigned * puiLen )
|
|
{
|
|
HB_SYMBOL_UNUSED( sd );
|
|
hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE );
|
|
*pSockAddr = NULL;
|
|
*puiLen = 0;
|
|
return -1;
|
|
}
|
|
|
|
HB_SOCKET 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 sd )
|
|
{
|
|
HB_SYMBOL_UNUSED( sd );
|
|
hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE );
|
|
return -1;
|
|
}
|
|
|
|
int hb_socketShutdown( HB_SOCKET sd, int iMode )
|
|
{
|
|
HB_SYMBOL_UNUSED( sd );
|
|
HB_SYMBOL_UNUSED( iMode );
|
|
hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE );
|
|
return -1;
|
|
}
|
|
|
|
int hb_socketBind( HB_SOCKET 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 sd, int iBacklog )
|
|
{
|
|
HB_SYMBOL_UNUSED( sd );
|
|
HB_SYMBOL_UNUSED( iBacklog );
|
|
hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE );
|
|
return -1;
|
|
}
|
|
|
|
HB_SOCKET hb_socketAccept( HB_SOCKET 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 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 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 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 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 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 sd, BOOL fBlocking )
|
|
{
|
|
HB_SYMBOL_UNUSED( sd );
|
|
HB_SYMBOL_UNUSED( fBlocking );
|
|
hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE );
|
|
return -1;
|
|
}
|
|
|
|
int hb_socketSetReuseAddr( HB_SOCKET sd, BOOL fReuse )
|
|
{
|
|
HB_SYMBOL_UNUSED( sd );
|
|
HB_SYMBOL_UNUSED( fReuse );
|
|
hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE );
|
|
return -1;
|
|
}
|
|
|
|
int hb_socketSetKeepAlive( HB_SOCKET sd, BOOL fKeepAlive )
|
|
{
|
|
HB_SYMBOL_UNUSED( sd );
|
|
HB_SYMBOL_UNUSED( fKeepAlive );
|
|
hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE );
|
|
return -1;
|
|
}
|
|
|
|
int hb_socketSetBroadcast( HB_SOCKET sd, BOOL fBroadcast )
|
|
{
|
|
HB_SYMBOL_UNUSED( sd );
|
|
HB_SYMBOL_UNUSED( fBroadcast );
|
|
hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE );
|
|
return -1;
|
|
}
|
|
|
|
int hb_socketSetSndBufSize( HB_SOCKET sd, int iSize )
|
|
{
|
|
HB_SYMBOL_UNUSED( sd );
|
|
HB_SYMBOL_UNUSED( iSize );
|
|
hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE );
|
|
return -1;
|
|
}
|
|
|
|
int hb_socketSetRcvBufSize( HB_SOCKET sd, int iSize )
|
|
{
|
|
HB_SYMBOL_UNUSED( sd );
|
|
HB_SYMBOL_UNUSED( iSize );
|
|
hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE );
|
|
return -1;
|
|
}
|
|
|
|
int hb_socketGetSndBufSize( HB_SOCKET sd, int * piSize )
|
|
{
|
|
HB_SYMBOL_UNUSED( sd );
|
|
HB_SYMBOL_UNUSED( piSize );
|
|
hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE );
|
|
return -1;
|
|
}
|
|
|
|
int hb_socketGetRcvBufSize( HB_SOCKET sd, int * piSize )
|
|
{
|
|
HB_SYMBOL_UNUSED( sd );
|
|
HB_SYMBOL_UNUSED( piSize );
|
|
hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE );
|
|
return -1;
|
|
}
|
|
|
|
int hb_socketSetMulticast( HB_SOCKET 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 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 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 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_SOCKET_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_INET6 ) && !defined( HB_HAS_INET6_ADDR_CONST ) && \
|
|
defined( IN6ADDR_ANY_INIT )
|
|
static const struct in6_addr s_in6addr_any = IN6ADDR_ANY_INIT;
|
|
#endif
|
|
|
|
#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 );
|
|
#elif defined( HB_OS_DOS )
|
|
ret = sock_init();
|
|
#endif
|
|
}
|
|
HB_SOCKET_UNLOCK
|
|
|
|
return ret;
|
|
}
|
|
|
|
void hb_socketCleanup( void )
|
|
{
|
|
HB_SOCKET_LOCK
|
|
if( --s_iSessions == 0 )
|
|
{
|
|
#if defined( HB_OS_WIN )
|
|
WSACleanup();
|
|
#elif defined( HB_OS_DOS )
|
|
sock_exit();
|
|
#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 0:
|
|
uiErr = 0;
|
|
break;
|
|
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 )
|
|
{
|
|
case 0:
|
|
uiErr = 0;
|
|
break;
|
|
#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:
|
|
#if defined( ESOCKTNOSUPPORT )
|
|
case ESOCKTNOSUPPORT:
|
|
#endif
|
|
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;
|
|
#if defined( ETOOMANYREFS )
|
|
case ETOOMANYREFS:
|
|
uiErr = HB_SOCKET_ERR_TOOMANYREFS;
|
|
break;
|
|
#endif
|
|
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;
|
|
}
|
|
|
|
#if defined( HB_SOCKET_TRANSLATE_DOMAIN )
|
|
static int hb_socketTransDomain( int domain, int *err )
|
|
{
|
|
switch( domain )
|
|
{
|
|
case HB_SOCKET_PF_INET:
|
|
#if defined( PF_INET )
|
|
domain = PF_INET;
|
|
#elif defined( AF_INET )
|
|
domain = AF_INET;
|
|
#else
|
|
if( err )
|
|
*err = HB_SOCKET_ERR_PFNOSUPPORT;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_PF_INET6:
|
|
#if defined( PF_INET6 )
|
|
domain = PF_INET6;
|
|
#elif defined( AF_INET6 )
|
|
domain = AF_INET6;
|
|
#else
|
|
if( err )
|
|
*err = HB_SOCKET_ERR_PFNOSUPPORT;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_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
|
|
if( err )
|
|
*err = HB_SOCKET_ERR_PFNOSUPPORT;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_PF_PACKET:
|
|
#if defined( PF_PACKET )
|
|
domain = PF_PACKET;
|
|
#elif defined( AF_PACKET )
|
|
domain = AF_PACKET;
|
|
#else
|
|
if( err )
|
|
*err = HB_SOCKET_ERR_PFNOSUPPORT;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_PF_IPX:
|
|
#if defined( PF_IPX )
|
|
domain = PF_IPX;
|
|
#elif defined( AF_IPX )
|
|
domain = AF_IPX;
|
|
#else
|
|
if( err )
|
|
*err = HB_SOCKET_ERR_PFNOSUPPORT;
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
if( err )
|
|
*err = HB_SOCKET_ERR_PFNOSUPPORT;
|
|
}
|
|
return domain;
|
|
}
|
|
#endif
|
|
|
|
#if defined( HB_SOCKET_TRANSLATE_TYPE )
|
|
static int hb_socketTransType( int type, int *err )
|
|
{
|
|
switch( type )
|
|
{
|
|
case HB_SOCKET_PT_STREAM:
|
|
#if defined( SOCK_STREAM )
|
|
type = SOCK_STREAM;
|
|
#else
|
|
if( err )
|
|
*err = HB_SOCKET_ERR_PROTONOSUPPORT;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_PT_DGRAM:
|
|
#if defined( SOCK_DGRAM )
|
|
type = SOCK_DGRAM;
|
|
#else
|
|
if( err )
|
|
*err = HB_SOCKET_ERR_PROTONOSUPPORT;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_PT_SEQPACKET:
|
|
#if defined( SOCK_SEQPACKET )
|
|
type = SOCK_SEQPACKET;
|
|
#else
|
|
if( err )
|
|
*err = HB_SOCKET_ERR_PROTONOSUPPORT;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_PT_RAW:
|
|
#if defined( SOCK_RAW )
|
|
type = SOCK_RAW;
|
|
#else
|
|
if( err )
|
|
*err = HB_SOCKET_ERR_PROTONOSUPPORT;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_PT_RDM:
|
|
#if defined( SOCK_RDM )
|
|
type = SOCK_RDM;
|
|
#else
|
|
if( err )
|
|
*err = HB_SOCKET_ERR_PROTONOSUPPORT;
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
if( err )
|
|
*err = HB_SOCKET_ERR_PROTONOSUPPORT;
|
|
}
|
|
return type;
|
|
}
|
|
#endif
|
|
|
|
static int hb_socketSelectRD( HB_SOCKET 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 = ( long ) ( timeout / 1000 );
|
|
tv.tv_usec = ( timeout % 1000 ) * 1000;
|
|
ptv = &tv;
|
|
}
|
|
else
|
|
ptv = NULL;
|
|
|
|
iResult = select( ( int ) ( 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;
|
|
timer = timecurr;
|
|
if( timeout > 0 )
|
|
continue;
|
|
}
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
return iResult < 0 ? -1 :
|
|
( iResult > 0 && FD_ISSET( sd, &rfds ) ? 1 : 0 );
|
|
}
|
|
|
|
static int hb_socketSelectWR( HB_SOCKET 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 = ( long ) ( timeout / 1000 );
|
|
tv.tv_usec = ( timeout % 1000 ) * 1000;
|
|
ptv = &tv;
|
|
}
|
|
else
|
|
ptv = NULL;
|
|
|
|
iResult = select( ( int ) ( sd + 1 ), NULL, &wfds, 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;
|
|
timer = timecurr;
|
|
if( timeout > 0 )
|
|
continue;
|
|
}
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
return iResult < 0 ? -1 :
|
|
( iResult > 0 && FD_ISSET( sd, &wfds ) ? 1 : 0 );
|
|
}
|
|
|
|
static int hb_socketSelectWRE( HB_SOCKET 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 = ( long ) ( timeout / 1000 );
|
|
tv.tv_usec = ( timeout % 1000 ) * 1000;
|
|
ptv = &tv;
|
|
}
|
|
else
|
|
ptv = NULL;
|
|
|
|
iResult = select( ( int ) ( 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;
|
|
timer = timecurr;
|
|
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( !szAddr || !*szAddr )
|
|
{
|
|
sa.sin_addr.s_addr = htonl( INADDR_ANY );
|
|
*pSockAddr = memcpy( hb_xgrab( sizeof( sa ) + 1 ), &sa, sizeof( sa ) );
|
|
*puiLen = ( unsigned ) sizeof( sa );
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
#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;
|
|
|
|
memset( &sa, 0, sizeof( sa ) );
|
|
sa.sin6_family = AF_INET6;
|
|
sa.sin6_port = htons( ( hbU16 ) iPort );
|
|
if( !szAddr || !*szAddr )
|
|
{
|
|
#if defined( HB_HAS_INET6_ADDR_CONST )
|
|
memcpy( &sa.sin6_addr, &in6addr_any, sizeof( struct in6_addr ) );
|
|
#elif defined( IN6ADDR_ANY_INIT )
|
|
memcpy( &sa.sin6_addr, &s_in6addr_any, sizeof( struct in6_addr ) );
|
|
#else
|
|
int TODO;
|
|
#endif
|
|
*pSockAddr = memcpy( hb_xgrab( sizeof( sa ) + 1 ), &sa, sizeof( sa ) );
|
|
*puiLen = ( unsigned ) sizeof( sa );
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
#if defined( HB_HAS_INET_PTON )
|
|
int 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_SOCKET_PF_INET:
|
|
fOK = hb_socketInetAddr( pSockAddr, puiLen,
|
|
hb_arrayGetCPtr( pAddrItm, 2 ),
|
|
hb_arrayGetNI( pAddrItm, 3 ) );
|
|
break;
|
|
case HB_SOCKET_PF_INET6:
|
|
fOK = hb_socketInet6Addr( pSockAddr, puiLen,
|
|
hb_arrayGetCPtr( pAddrItm, 2 ),
|
|
hb_arrayGetNI( pAddrItm, 3 ) );
|
|
break;
|
|
case HB_SOCKET_PF_LOCAL:
|
|
fOK = hb_socketLocalAddr( pSockAddr, puiLen,
|
|
hb_arrayGetCPtr( pAddrItm, 2 ) );
|
|
break;
|
|
case HB_SOCKET_PF_PACKET:
|
|
case HB_SOCKET_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_SOCKET_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_SOCKET_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_SOCKET_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 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 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 hb_socketOpen( int domain, int type, int protocol )
|
|
{
|
|
HB_SOCKET sd = HB_NO_SOCKET;
|
|
int err = 0;
|
|
|
|
#if defined( HB_SOCKET_TRANSLATE_DOMAIN )
|
|
domain = hb_socketTransDomain( domain, &err );
|
|
#endif
|
|
|
|
#if defined( HB_SOCKET_TRANSLATE_TYPE )
|
|
if( err == 0 )
|
|
type = hb_socketTransType( type, &err );
|
|
#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 sd )
|
|
{
|
|
int ret;
|
|
|
|
hb_vmUnlock();
|
|
#if defined( HB_OS_WIN )
|
|
ret = closesocket( sd );
|
|
#elif defined( HB_OS_DOS )
|
|
ret = close_s( 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 sd, int iMode )
|
|
{
|
|
int ret;
|
|
|
|
#if defined( HB_OS_WIN )
|
|
if( iMode == HB_SOCKET_SHUT_RD )
|
|
iMode = SD_RECEIVE;
|
|
else if( iMode == HB_SOCKET_SHUT_WR )
|
|
iMode = SD_SEND;
|
|
else if( iMode == HB_SOCKET_SHUT_RDWR )
|
|
iMode = SD_BOTH;
|
|
#elif defined( HB_OS_OS2 )
|
|
if( iMode == HB_SOCKET_SHUT_RD )
|
|
iMode = SO_RCV_SHUTDOWN;
|
|
else if( iMode == HB_SOCKET_SHUT_WR )
|
|
iMode = SO_SND_SHUTDOWN;
|
|
else if( iMode == HB_SOCKET_SHUT_RDWR )
|
|
iMode = SO_RCV_SHUTDOWN | SO_SND_SHUTDOWN;
|
|
#elif defined( __WATCOMC__ )
|
|
if( iMode == HB_SOCKET_SHUT_RD ||
|
|
iMode == HB_SOCKET_SHUT_WR ||
|
|
iMode == HB_SOCKET_SHUT_RDWR )
|
|
{ ; }
|
|
#else
|
|
if( iMode == HB_SOCKET_SHUT_RD )
|
|
iMode = SHUT_RD;
|
|
else if( iMode == HB_SOCKET_SHUT_WR )
|
|
iMode = SHUT_WR;
|
|
else if( iMode == HB_SOCKET_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 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 sd, int iBacklog )
|
|
{
|
|
int ret;
|
|
|
|
ret = listen( sd, iBacklog );
|
|
hb_socketSetOsError( ret == 0 ? 0 : HB_SOCK_GETERROR() );
|
|
|
|
return ret;
|
|
}
|
|
|
|
HB_SOCKET hb_socketAccept( HB_SOCKET sd, void ** pSockAddr, unsigned * puiLen, HB_LONG timeout )
|
|
{
|
|
HB_SOCKET 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;
|
|
}
|
|
}
|
|
/* it's not guarantied that socket returned by accept will use
|
|
* blocking IO operations. On some systems it inherits blocking IO
|
|
* from parent handler so we have to force blocking IO mode
|
|
* explicitly..
|
|
*/
|
|
if( newsd != HB_NO_SOCKET )
|
|
hb_socketSetBlockingIO( newsd, TRUE );
|
|
}
|
|
else if( ret == 0 )
|
|
hb_socketSetRawError( HB_SOCKET_ERR_TIMEOUT );
|
|
hb_vmLock();
|
|
return newsd;
|
|
}
|
|
|
|
int hb_socketConnect( HB_SOCKET 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 sd, const void * data, long len, int flags, HB_LONG timeout )
|
|
{
|
|
long lSent = 0;
|
|
|
|
hb_vmUnlock();
|
|
|
|
if( timeout >= 0 )
|
|
{
|
|
lSent = hb_socketSelectWR( sd, timeout );
|
|
if( lSent == 0 )
|
|
{
|
|
hb_socketSetRawError( HB_SOCKET_ERR_TIMEOUT );
|
|
lSent = -1;
|
|
}
|
|
}
|
|
if( lSent >= 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 sd, const void * data, long len, int flags,
|
|
const void * pSockAddr, unsigned uiSockLen, HB_LONG timeout )
|
|
{
|
|
long lSent = 0;
|
|
|
|
hb_vmUnlock();
|
|
|
|
if( timeout >= 0 )
|
|
{
|
|
lSent = hb_socketSelectWR( sd, timeout );
|
|
if( lSent == 0 )
|
|
{
|
|
hb_socketSetRawError( HB_SOCKET_ERR_TIMEOUT );
|
|
lSent = -1;
|
|
}
|
|
}
|
|
if( lSent >= 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 sd, void * data, long len, int flags, HB_LONG timeout )
|
|
{
|
|
long lReceived = 0;
|
|
|
|
hb_vmUnlock();
|
|
|
|
if( timeout >= 0 )
|
|
{
|
|
lReceived = hb_socketSelectRD( sd, timeout );
|
|
if( lReceived == 0 )
|
|
{
|
|
hb_socketSetRawError( HB_SOCKET_ERR_TIMEOUT );
|
|
lReceived = -1;
|
|
}
|
|
}
|
|
if( lReceived >= 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 sd, void * data, long len, int flags, void ** pSockAddr, unsigned * puiSockLen, HB_LONG timeout )
|
|
{
|
|
long lReceived = 0;
|
|
|
|
hb_vmUnlock();
|
|
|
|
if( timeout >= 0 )
|
|
{
|
|
lReceived = hb_socketSelectRD( sd, timeout );
|
|
if( lReceived == 0 )
|
|
{
|
|
hb_socketSetRawError( HB_SOCKET_ERR_TIMEOUT );
|
|
lReceived = -1;
|
|
}
|
|
}
|
|
if( lReceived >= 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 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( HB_OS_DOS )
|
|
int mode = fBlocking ? 0 : 1;
|
|
ret = ioctlsocket( sd, FIONBIO, ( char * ) &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() );
|
|
#elif defined( HB_OS_OS2 )
|
|
unsigned long mode = fBlocking ? 0 : 1;
|
|
ret = ioctl( sd, FIONBIO, ( char * ) &mode );
|
|
hb_socketSetOsError( ret != -1 ? 0 : HB_SOCK_GETERROR() );
|
|
if( ret == 0 )
|
|
ret = 1;
|
|
#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 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 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 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 sd, int iSize )
|
|
{
|
|
return setsockopt( sd, SOL_SOCKET, SO_SNDBUF, ( const char * ) &iSize, sizeof( iSize ) );
|
|
}
|
|
|
|
int hb_socketSetRcvBufSize( HB_SOCKET sd, int iSize )
|
|
{
|
|
return setsockopt( sd, SOL_SOCKET, SO_RCVBUF, ( const char * ) &iSize, sizeof( iSize ) );
|
|
}
|
|
|
|
int hb_socketGetSndBufSize( HB_SOCKET sd, int * piSize )
|
|
{
|
|
socklen_t len = sizeof( * piSize );
|
|
return getsockopt( sd, SOL_SOCKET, SO_SNDBUF, ( char * ) piSize, &len );
|
|
}
|
|
|
|
int hb_socketGetRcvBufSize( HB_SOCKET sd, int * piSize )
|
|
{
|
|
socklen_t len = sizeof( * piSize );
|
|
return getsockopt( sd, SOL_SOCKET, SO_RCVBUF, ( char * ) piSize, &len );
|
|
}
|
|
|
|
int hb_socketSetMulticast( HB_SOCKET sd, int af, const char * szAddr )
|
|
{
|
|
if( af == HB_SOCKET_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_SOCKET_AF_INET6 )
|
|
{
|
|
#if defined( HB_HAS_INET_PTON )
|
|
struct ipv6_mreq mreq;
|
|
int err = inet_pton( AF_INET6, szAddr, &mreq.ipv6mr_multiaddr );
|
|
if( err > 0 )
|
|
{
|
|
mreq.ipv6mr_interface = 0;
|
|
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 sd, HB_LONG timeout )
|
|
{
|
|
int ret;
|
|
|
|
hb_vmUnlock();
|
|
ret = hb_socketSelectRD( sd, timeout );
|
|
hb_vmLock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
int hb_socketSelectWrite( HB_SOCKET sd, HB_LONG timeout )
|
|
{
|
|
int ret;
|
|
|
|
hb_vmUnlock();
|
|
ret = hb_socketSelectWR( sd, timeout );
|
|
hb_vmLock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
int hb_socketSelectWriteEx( HB_SOCKET 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_SOCKET_FUNC pFunc )
|
|
{
|
|
HB_SOCKET 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 ) hb_arrayGetNInt( pItemSets[ i ], ul );
|
|
else if( type & HB_IT_POINTER )
|
|
sd = ( HB_SOCKET ) ( 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 = ( long ) ( timeout / 1000 );
|
|
tv.tv_usec = ( timeout % 1000 ) * 1000;
|
|
ptv = &tv;
|
|
}
|
|
else
|
|
ptv = NULL;
|
|
|
|
ret = select( ( int ) ( 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 ) hb_arrayGetNInt( pItemSets[ i ], ul );
|
|
else if( type & HB_IT_POINTER )
|
|
sd = ( HB_SOCKET ) ( 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;
|
|
BOOL fTrans = FALSE;
|
|
|
|
if( af == HB_SOCKET_PF_INET )
|
|
{
|
|
struct in_addr sin;
|
|
#if defined( HB_HAS_INET_PTON )
|
|
fTrans = inet_pton( AF_INET, szAddr, &sin ) > 0;
|
|
#elif defined( HB_HAS_INET_ATON )
|
|
fTrans = inet_aton( szAddr, &sin ) != 0;
|
|
#else
|
|
sin.s_addr = inet_addr( szAddr );
|
|
fTrans = sin.s_addr != INADDR_NONE ||
|
|
strcmp( "255.255.255.255", szAddr ) == 0; /* dirty hack */
|
|
#endif
|
|
|
|
#if !defined( HB_HAS_ADDRINFO )
|
|
if( !fTrans )
|
|
{
|
|
struct hostent * he;
|
|
|
|
hb_vmUnlock();
|
|
he = gethostbyname( szAddr );
|
|
if( he && he->h_addr_list[ 0 ] )
|
|
{
|
|
sin.s_addr = ( ( struct in_addr * ) he->h_addr_list[ 0 ] )->s_addr;
|
|
fTrans = TRUE;
|
|
}
|
|
hb_vmLock();
|
|
}
|
|
#endif
|
|
|
|
if( fTrans )
|
|
{
|
|
# 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
|
|
szResult = hb_strdup( szAddr );
|
|
}
|
|
}
|
|
#if defined( HB_HAS_INET6 )
|
|
else if( af == HB_SOCKET_PF_INET6 )
|
|
{
|
|
#if defined( HB_HAS_INET_PTON )
|
|
struct in6_addr sin;
|
|
fTrans = inet_pton( AF_INET6, szAddr, &sin ) > 0;
|
|
#else
|
|
int TODO;
|
|
fTrans = FALSE;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
if( !fTrans )
|
|
{
|
|
#if defined( HB_HAS_ADDRINFO )
|
|
struct addrinfo hints, *res = NULL;
|
|
|
|
hb_vmUnlock();
|
|
# if defined( HB_SOCKET_TRANSLATE_DOMAIN )
|
|
af = hb_socketTransDomain( af, NULL );
|
|
# endif
|
|
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();
|
|
#endif
|
|
}
|
|
|
|
return szResult;
|
|
}
|
|
|
|
PHB_ITEM hb_socketGetHosts( const char * szAddr, int af )
|
|
{
|
|
PHB_ITEM pItem = NULL;
|
|
|
|
#ifdef HB_HAS_ADDRINFO
|
|
struct addrinfo hints, *res = NULL, *ai;
|
|
int iResult;
|
|
|
|
hb_vmUnlock();
|
|
#if defined( HB_SOCKET_TRANSLATE_DOMAIN )
|
|
af = hb_socketTransDomain( af, NULL );
|
|
#endif
|
|
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_SOCKET_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_SOCKET_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 */
|