Files
harbour-core/harbour/source/rtl/hbsocket.c
Viktor Szakats fdc37cc149 2009-08-14 20:08 UTC+0200 Viktor Szakats (harbour.01 syenar.hu)
* 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.
2009-08-14 18:10:21 +00:00

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 */