* source/rtl/hbsocket.c
! Applied fix for Cygwin as per Przemek's instructions.
(I've guarded #undef HB_OS_WIN with defined( __CYGWIN_ ))
* INSTALL
- Deleted some by now irrelevant restrictions and rules.
+ Added pointers to NT GNU Make, DJ GNU Make and OS/2 GNU Make.
+ Added HB_COMPILER/HB_ARCHITECTURE to option list. These
should now be mostly optional. They are only needed in a
few situations when autodetection cannot work (secondary pocc
targets for example), or in cross build situations when
we want to force some non-native configuration.
% Deleted HB_INSTALL_PREFIX from examples. It's optional.
% Deleted all settings which are now autodetected.
I didn't retest them of course, please try them, and if
something was removed by mistake pls report it.
The reduction is quite dramatic. Starting the build is
really only just starting GNU Make in most cases.
% Converted *all* examples to not use starter script/batch
files. As a next step I'll probably delete them to make
even *less* choices for builders and because current
starter files don't offer anything interesting anymore.
Maybe also included GNU Make executable will also be
deleted.
% Simplified Cygwin example.
* make_gnu.bat
- Deleted Cygwin logic.
; I just realized that after all these GNU Make development,
there is no need at all for make_gnu.sh for Cygwin and it's
a no brainer to launch make either using NT shell or Cygwin/MSYS
shell. It just works by starting GNU Make in whichever shell
or environment you are. [ Well, with NT shell it doesn't seem
to work because gcc.exe is named gcc-3.exe on my system,
anyway, this doesn't change the point. ]
The only remaining "complexity" is finding the name of GNU
Make in a given environment and not use the wrong one
(f.e. Cygwin make.exe in NT shell).
* config/global.cf
+ Added svnversion output in verbose mode.
2797 lines
70 KiB
C
2797 lines
70 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 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 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 ) && ! 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_INET6
|
|
# define HB_HAS_SOCKADDR_STORAGE
|
|
# define HB_HAS_ADDRINFO
|
|
# define HB_HAS_INET6_ADDR_CONST
|
|
# 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
|
|
/* test shows that GCC 3.3.6 does not support inet_pton() and 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( __CYGWIN__ )
|
|
#undef HB_OS_WIN
|
|
#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 */
|
|
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 );
|
|
#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 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:
|
|
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 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;
|
|
int err;
|
|
|
|
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 )
|
|
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 )
|
|
switch( domain )
|
|
{
|
|
case HB_SOCKET_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_SOCKET_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_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
|
|
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
|
|
err = HB_SOCKET_ERR_PFNOSUPPORT;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_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_SOCKET_PT_STREAM:
|
|
#if defined( SOCK_STREAM )
|
|
type = SOCK_STREAM;
|
|
#else
|
|
err = HB_SOCKET_ERR_PROTONOSUPPORT;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_PT_DGRAM:
|
|
#if defined( SOCK_DGRAM )
|
|
type = SOCK_DGRAM;
|
|
#else
|
|
err = HB_SOCKET_ERR_PROTONOSUPPORT;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_PT_SEQPACKET:
|
|
#if defined( SOCK_SEQPACKET )
|
|
type = SOCK_SEQPACKET;
|
|
#else
|
|
err = HB_SOCKET_ERR_PROTONOSUPPORT;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_PT_RAW:
|
|
#if defined( SOCK_RAW )
|
|
type = SOCK_RAW;
|
|
#else
|
|
err = HB_SOCKET_ERR_PROTONOSUPPORT;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_PT_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 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 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( 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 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;
|
|
|
|
#ifdef HB_HAS_ADDRINFO
|
|
|
|
#if defined( HB_SOCKET_TRANSLATE_DOMAIN )
|
|
switch( af )
|
|
{
|
|
case HB_SOCKET_PF_INET:
|
|
#if defined( PF_INET )
|
|
af = PF_INET;
|
|
#elif defined( AF_INET )
|
|
af = AF_INET;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_PF_INET6:
|
|
#if defined( PF_INET6 )
|
|
af = PF_INET6;
|
|
#elif defined( AF_INET6 )
|
|
af = AF_INET6;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_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_SOCKET_PF_PACKET:
|
|
#if defined( PF_PACKET )
|
|
af = PF_PACKET;
|
|
#elif defined( AF_PACKET )
|
|
af = AF_PACKET;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_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_SOCKET_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 ] )
|
|
{
|
|
struct in_addr * sin = ( struct in_addr * ) he->h_addr_list[ 0 ];
|
|
# 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 );
|
|
}
|
|
hb_vmLock();
|
|
}
|
|
#if defined( HB_HAS_INET6 )
|
|
else if( af == HB_SOCKET_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_SOCKET_PF_INET:
|
|
#if defined( PF_INET )
|
|
af = PF_INET;
|
|
#elif defined( AF_INET )
|
|
af = AF_INET;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_PF_INET6:
|
|
#if defined( PF_INET6 )
|
|
af = PF_INET6;
|
|
#elif defined( AF_INET6 )
|
|
af = AF_INET6;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_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_SOCKET_PF_PACKET:
|
|
#if defined( PF_PACKET )
|
|
af = PF_PACKET;
|
|
#elif defined( AF_PACKET )
|
|
af = AF_PACKET;
|
|
#endif
|
|
break;
|
|
|
|
case HB_SOCKET_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_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 */
|