/* * $Id$ */ /* * Harbour Project source code: * socket C API * * Copyright 2009 Przemyslaw Czerpak * www - http://www.harbour-project.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). * * As a special exception, the Harbour Project gives permission for * additional uses of the text contained in its release of Harbour. * * The exception is that, if you link the Harbour libraries with other * files to produce an executable, this does not by itself cause the * resulting executable to be covered by the GNU General Public License. * Your use of that executable is in no way restricted on account of * linking the Harbour library code into it. * * This exception does not however invalidate any other reasons why * the executable file might be covered by the GNU General Public License. * * This exception applies only to the code released by the Harbour * Project under the name Harbour. If you copy code from other * Harbour Project or Free Software Foundation releases into a copy of * Harbour, as the General Public License permits, the exception does * not apply to the code that you add in this way. To avoid misleading * anyone as to the status of such modified files, you must delete * this exception notice from them. * * If you write modifications of your own for Harbour, it is your choice * whether to permit this exception to apply to your modifications. * If you do not wish that, delete this exception notice. * */ #include "hbsocket.h" #if defined( HB_OS_DOS ) && !defined( HB_HAS_WATT ) # if !defined( HB_SOCKET_OFF ) # define HB_SOCKET_OFF # endif #endif #if !defined( HB_SOCKET_OFF ) /* we do not use autoconf so we can only guess what is supported * by platform and/or CRTL :-( */ /* we are using following macros: platform supports inet_aton() function: #define HB_HAS_INET_ATON platform supports inet_pton() function: #define HB_HAS_INET_PTON platform supports inet_ntop() function: #define HB_HAS_INET_NTOP platform supports thread safe (using TLS) inet_ntoa() function: #define HB_IS_INET_NTOA_MT_SAFE platform supports getaddrinfo()/freeaddrinfo() functions: #define HB_HAS_ADDRINFO platform supports constant inet6 addresses in6addr_any and in6addr_loopback: #define HB_HAS_INET6_ADDR_CONST platform supports IP6 protocol: #define HB_HAS_INET6 platform supports unix/local protocol: #define HB_HAS_UNIX platform supports 'struct sockaddr_storage' which can be used as holder for all socket address structures in all supported protocols, simple 'struct sockaddr' is not large enough for such usage: #define HB_HAS_SOCKADDR_STORAGE timeval parameter used in select() function is updated by kernel/CRTL and decreased by the amount of time the function was waiting: #define HB_HAS_SELECT_TIMER all implementations should use BSD compatible constant values but if it's not guarantied then these two macros can be used. protocol families have to be translated: #define HB_SOCKET_TRANSLATE_DOMAIN protocol types have to be translated: #define HB_SOCKET_TRANSLATE_TYPE */ #if defined( HB_OS_HPUX ) # define _XOPEN_SOURCE_EXTENDED #endif #if defined( HB_OS_UNIX ) && ! defined( __CYGWIN__ ) # define HB_HAS_UNIX # if !defined( __WATCOMC__ ) # define HB_HAS_INET_ATON # define HB_HAS_INET_PTON # define HB_HAS_INET_NTOP # define HB_HAS_SOCKADDR_STORAGE # define HB_HAS_ADDRINFO # endif # if !defined( __WATCOMC__ ) && !defined( HB_OS_BEOS ) # define HB_HAS_INET6 # define HB_HAS_INET6_ADDR_CONST # endif # if defined( HB_OS_BEOS ) # define HB_SOCKET_TRANSLATE_DOMAIN # define HB_SOCKET_TRANSLATE_TYPE # endif # if defined( HB_OS_LINUX ) # define HB_HAS_SELECT_TIMER # endif #elif defined( HB_OS_WIN ) # if defined( __WATCOMC__ ) # if ( NTDDI_VERSION >= 0x06000000 ) # define HB_HAS_INET_PTON # define HB_HAS_INET_NTOP # endif # define HB_HAS_SOCKADDR_STORAGE /* # define HB_HAS_INET6 */ # elif defined( __MINGW32__ ) # define HB_HAS_SOCKADDR_STORAGE # elif defined( __POCC__ ) && !defined( __XCC__ ) # define HB_HAS_SOCKADDR_STORAGE # endif # define HB_IS_INET_NTOA_MT_SAFE #elif defined( HB_OS_OS2 ) # if defined( __WATCOMC__ ) # define HB_HAS_INET_PTON # define HB_HAS_INET_NTOP # else /* test shows that GCC 3.3.6 does not support inet_pton() and inet_ntop() */ # endif #elif defined( HB_OS_DOS ) # define HB_HAS_INET_ATON # define HB_HAS_INET_PTON # define HB_HAS_INET_NTOP # define HB_HAS_SOCKADDR_STORAGE # define HB_HAS_ADDRINFO # define HB_HAS_INET6_ADDR_CONST /* # define HB_HAS_INET6 */ #endif #if defined( HB_OS_WIN ) && ! defined( HB_OS_UNIX ) # include # include #else # include # if defined( HB_OS_DOS ) # if defined( __WATCOMC__ ) /* workaround for declaration conflicts in tcp.h */ # define _GETOPT_H # endif # include # elif defined( HB_OS_OS2 ) # if defined( __WATCOMC__ ) # include # include # endif # include # include # endif # if !( defined( HB_OS_DOS ) && defined( __WATCOMC__ ) ) # include # endif # include # include # include # include # include # if defined( HB_HAS_UNIX ) # include # endif # include # include # if defined( HB_OS_DOS ) # include # define select select_s # endif #endif #if defined( __CYGWIN__ ) #undef HB_OS_WIN #endif #if defined( HB_OS_OS2 ) || defined( HB_OS_WIN ) || defined( HB_OS_DOS ) # define socklen_t int #endif #if !defined( INET_ADDRSTRLEN ) # define INET_ADDRSTRLEN 16 #endif #if defined( HB_OS_DOS ) && !defined( SHUT_RD ) # define SHUT_RD 0 # define SHUT_WR 1 # define SHUT_RDWR 2 #endif #if defined( __WATCOMC__ ) && defined( HB_OS_LINUX ) && !defined( IP_ADD_MEMBERSHIP ) /* it's missed in OpenWatcom 1.8 Linux header files :-( */ # define IP_ADD_MEMBERSHIP 35 struct ip_mreq { struct in_addr imr_multiaddr; /* IP multicast address of group */ struct in_addr imr_interface; /* Local IP address of interface */ }; #endif #endif /* HB_SOCKET_OFF */ #include "hbapi.h" #include "hbapiitm.h" #include "hbvm.h" #include "hbstack.h" #include "hbthread.h" #include "hbdate.h" /* TODO change error description to sth more user friendly */ static const char * s_socketErrors[] = { "OK", "EPIPE", "ETIMEOUT", "EWRONGADDR", "EAFNOSUPPORT", "EPFNOSUPPORT", "EPROTONOSUPPORT", "EPARAMVALUE", "ENOSUPPORT", "ENORESOURCE", "EACCESS", "EADDRINUSE", "EINTERRUPT", "EALREADYCONNECTED", "ECONNREFUSED", "ECONNABORTED", "ECONNRESET", "ENETUNREACH", "ENETDOWN", "ENETRESET", "EINPROGRESS", "EALREADY", "EADDRNOTAVAIL", "EREADONLY", "EAGAIN", "EINVALIDHANDLE", "EINVAL", "EPROTO", "EPROTOTYPE", "ENOFILE", "ENOBUFS", "ENOMEM", "EFAULT", "ENAMETOOLONG", "ENOENT", "ENOTDIR", "ELOOP", "EMSGSIZE", "EDESTADDRREQ", "ENOPROTOOPT", "ENOTCONN", "ESHUTDOWN", "ETOOMANYREFS", "ERESTARTSYS", "ENOSR", "EHOSTDOWN", "EHOSTUNREACH", "ENOTEMPTY", "EUSERS", "EDQUOT", "ESTALE", "EREMOTE", "EPROCLIM", "EDISCON", "ENOMORE", "ECANCELLED", "EINVALIDPROCTABLE", "EINVALIDPROVIDER", "EPROVIDERFAILEDINIT", "EREFUSED", "ESYSNOTREADY", "EVERNOTSUPPORTED", "ENOTINITIALISED", "TRYAGAIN", "HOSTNOTFOUND", "NORECOVERY", "NODATA", "ESYSCALLFAILURE", "ESERVICENOTFOUND", "ETYPENOTFOUND", "EOTHER" }; int hb_socketGetError( void ) { return hb_stackIOErrors()->uiSocketError; } int hb_socketGetOsError( void ) { return hb_stackIOErrors()->iSocketOsError; } const char * hb_socketErrorStr( int iError ) { if( iError >= 0 && iError <= HB_SOCKET_ERR_OTHER ) return s_socketErrors[ iError ]; else return ""; } static void hb_socketSetRawError( int err ) { PHB_IOERRORS pError = hb_stackIOErrors(); pError->uiSocketError = ( USHORT ) err; pError->iSocketOsError = 0; } #if defined( HB_SOCKET_OFF ) int hb_socketInit( void ) { return -1; } void hb_socketCleanup( void ) { ; } int hb_socketGetAddrFamilly( const void * pSockAddr, unsigned len ) { HB_SYMBOL_UNUSED( pSockAddr ); HB_SYMBOL_UNUSED( len ); return -1; } BOOL hb_socketLocalAddr( void ** pSockAddr, unsigned * puiLen, const char * szAddr ) { HB_SYMBOL_UNUSED( szAddr ); hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); *pSockAddr = NULL; *puiLen = 0; return FALSE; } BOOL hb_socketInetAddr( void ** pSockAddr, unsigned * puiLen, const char * szAddr, int iPort ) { HB_SYMBOL_UNUSED( szAddr ); HB_SYMBOL_UNUSED( iPort ); hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); *pSockAddr = NULL; *puiLen = 0; return FALSE; } BOOL hb_socketInet6Addr( void ** pSockAddr, unsigned * puiLen, const char * szAddr, int iPort ) { HB_SYMBOL_UNUSED( szAddr ); HB_SYMBOL_UNUSED( iPort ); hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); *pSockAddr = NULL; *puiLen = 0; return FALSE; } char * hb_socketAddrGetName( const void * pSockAddr, unsigned len ) { HB_SYMBOL_UNUSED( pSockAddr ); HB_SYMBOL_UNUSED( len ); hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); return NULL; } int hb_socketAddrGetPort( const void * pSockAddr, unsigned len ) { HB_SYMBOL_UNUSED( pSockAddr ); HB_SYMBOL_UNUSED( len ); hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); return -1; } BOOL hb_socketAddrFromItem( void ** pSockAddr, unsigned * puiLen, PHB_ITEM pAddrItm ) { HB_SYMBOL_UNUSED( pAddrItm ); hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); *pSockAddr = NULL; *puiLen = 0; return FALSE; } PHB_ITEM hb_socketAddrToItem( const void * pSockAddr, unsigned len ) { HB_SYMBOL_UNUSED( pSockAddr ); HB_SYMBOL_UNUSED( len ); hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); return NULL; } int hb_socketGetSockName( HB_SOCKET sd, void ** pSockAddr, unsigned * puiLen ) { HB_SYMBOL_UNUSED( sd ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); *pSockAddr = NULL; *puiLen = 0; return -1; } int hb_socketGetPeerName( HB_SOCKET sd, void ** pSockAddr, unsigned * puiLen ) { HB_SYMBOL_UNUSED( sd ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); *pSockAddr = NULL; *puiLen = 0; return -1; } HB_SOCKET hb_socketOpen( int domain, int type, int protocol ) { HB_SYMBOL_UNUSED( domain ); HB_SYMBOL_UNUSED( type ); HB_SYMBOL_UNUSED( protocol ); hb_socketSetRawError( HB_SOCKET_ERR_PFNOSUPPORT ); return HB_NO_SOCKET; } int hb_socketClose( HB_SOCKET sd ) { HB_SYMBOL_UNUSED( sd ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } int hb_socketShutdown( HB_SOCKET sd, int iMode ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( iMode ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } int hb_socketBind( HB_SOCKET sd, const void * pSockAddr, unsigned uiLen ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( pSockAddr ); HB_SYMBOL_UNUSED( uiLen ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } int hb_socketListen( HB_SOCKET sd, int iBacklog ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( iBacklog ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } HB_SOCKET hb_socketAccept( HB_SOCKET sd, void ** pSockAddr, unsigned * puiLen, HB_LONG timeout ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( pSockAddr ); HB_SYMBOL_UNUSED( puiLen ); HB_SYMBOL_UNUSED( timeout ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return HB_NO_SOCKET; } int hb_socketConnect( HB_SOCKET sd, const void * pSockAddr, unsigned uiLen, HB_LONG timeout ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( pSockAddr ); HB_SYMBOL_UNUSED( uiLen ); HB_SYMBOL_UNUSED( timeout ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } long hb_socketSend( HB_SOCKET sd, const void * data, long len, int flags, HB_LONG timeout ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( data ); HB_SYMBOL_UNUSED( len ); HB_SYMBOL_UNUSED( flags ); HB_SYMBOL_UNUSED( timeout ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } long hb_socketSendTo( HB_SOCKET sd, const void * data, long len, int flags, const void * pSockAddr, unsigned uiSockLen, HB_LONG timeout ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( data ); HB_SYMBOL_UNUSED( len ); HB_SYMBOL_UNUSED( flags ); HB_SYMBOL_UNUSED( pSockAddr ); HB_SYMBOL_UNUSED( uiSockLen ); HB_SYMBOL_UNUSED( timeout ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } long hb_socketRecv( HB_SOCKET sd, void * data, long len, int flags, HB_LONG timeout ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( data ); HB_SYMBOL_UNUSED( len ); HB_SYMBOL_UNUSED( flags ); HB_SYMBOL_UNUSED( timeout ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } long hb_socketRecvFrom( HB_SOCKET sd, void * data, long len, int flags, void ** pSockAddr, unsigned * puiSockLen, HB_LONG timeout ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( data ); HB_SYMBOL_UNUSED( len ); HB_SYMBOL_UNUSED( flags ); HB_SYMBOL_UNUSED( pSockAddr ); HB_SYMBOL_UNUSED( puiSockLen ); HB_SYMBOL_UNUSED( timeout ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } int hb_socketSetBlockingIO( HB_SOCKET sd, BOOL fBlocking ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( fBlocking ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } int hb_socketSetReuseAddr( HB_SOCKET sd, BOOL fReuse ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( fReuse ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } int hb_socketSetKeepAlive( HB_SOCKET sd, BOOL fKeepAlive ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( fKeepAlive ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } int hb_socketSetBroadcast( HB_SOCKET sd, BOOL fBroadcast ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( fBroadcast ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } int hb_socketSetSndBufSize( HB_SOCKET sd, int iSize ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( iSize ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } int hb_socketSetRcvBufSize( HB_SOCKET sd, int iSize ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( iSize ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } int hb_socketGetSndBufSize( HB_SOCKET sd, int * piSize ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( piSize ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } int hb_socketGetRcvBufSize( HB_SOCKET sd, int * piSize ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( piSize ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } int hb_socketSetMulticast( HB_SOCKET sd, int af, const char * szAddr ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( af ); HB_SYMBOL_UNUSED( szAddr ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } int hb_socketSelectRead( HB_SOCKET sd, HB_LONG timeout ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( timeout ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } int hb_socketSelectWrite( HB_SOCKET sd, HB_LONG timeout ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( timeout ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } int hb_socketSelectWriteEx( HB_SOCKET sd, HB_LONG timeout ) { HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( timeout ); hb_socketSetRawError( HB_SOCKET_ERR_INVALIDHANDLE ); return -1; } int hb_socketSelect( PHB_ITEM pArrayRD, BOOL fSetRD, PHB_ITEM pArrayWR, BOOL fSetWR, PHB_ITEM pArrayEX, BOOL fSetEX, HB_LONG timeout, HB_SOCKET_FUNC pFunc ) { HB_SYMBOL_UNUSED( pArrayRD ); HB_SYMBOL_UNUSED( fSetRD ); HB_SYMBOL_UNUSED( pArrayWR ); HB_SYMBOL_UNUSED( fSetWR ); HB_SYMBOL_UNUSED( pArrayEX ); HB_SYMBOL_UNUSED( fSetEX ); HB_SYMBOL_UNUSED( timeout ); HB_SYMBOL_UNUSED( pFunc ); hb_socketSetRawError( HB_SOCKET_ERR_NOSUPPORT ); return -1; } char * hb_socketResolveAddr( const char * szAddr, int af ) { HB_SYMBOL_UNUSED( szAddr ); HB_SYMBOL_UNUSED( af ); hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); return NULL; } PHB_ITEM hb_socketGetHosts( const char * szAddr, int af ) { HB_SYMBOL_UNUSED( szAddr ); HB_SYMBOL_UNUSED( af ); hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); return NULL; } PHB_ITEM hb_socketGetAliases( const char * szAddr, int af ) { HB_SYMBOL_UNUSED( szAddr ); HB_SYMBOL_UNUSED( af ); hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); return NULL; } #else #define HB_SOCKADDR_MAX_LEN 256 #if defined( HB_OS_WIN ) # define HB_SOCK_GETERROR() WSAGetLastError() # define HB_SOCK_IS_EINTR() ( WSAGetLastError() == WSAEINTR ) # define HB_SOCK_IS_EINPROGRES() ( WSAGetLastError() == WSAEWOULDBLOCK ) #else # define HB_SOCK_GETERROR() errno # define HB_SOCK_IS_EINTR() ( errno == EINTR ) # define HB_SOCK_IS_EINPROGRES() ( errno == EINPROGRESS ) #endif /* MT macros */ #define HB_SOCKET_LOCK hb_threadEnterCriticalSection( &s_sockMtx ); #define HB_SOCKET_UNLOCK hb_threadLeaveCriticalSection( &s_sockMtx ); static HB_CRITICAL_NEW( s_sockMtx ); static int s_iSessions; #if defined( HB_HAS_INET6 ) && !defined( HB_HAS_INET6_ADDR_CONST ) && \ defined( IN6ADDR_ANY_INIT ) static const struct in6_addr s_in6addr_any = IN6ADDR_ANY_INIT; #endif #if !defined( HB_HAS_INET_NTOP ) && !defined( HB_IS_INET_NTOA_MT_SAFE ) && defined( AF_INET ) static const char * hb_inet_ntoa( struct in_addr * addr, char * pBuffer ) { /* dirty hack to make inet_ntoa() MT safe, * in many systems inet_ntoa() returns pointer to * static buffer and is not MT safe. */ ULONG u = ntohl( addr->s_addr ); hb_snprintf( pBuffer, INET_ADDRSTRLEN, "%hd.%hd.%hd.%hd", HB_UHBYTE( u ), HB_ULBYTE( u ), HB_HIBYTE( u ), HB_LOBYTE( u ) ); return pBuffer; } #endif int hb_socketInit( void ) { int ret = 0; HB_SOCKET_LOCK if( ++s_iSessions == 1 ) { #if defined( HB_OS_WIN ) WSADATA wsadata; ret = WSAStartup( HB_MKUSHORT( 1, 1 ), &wsadata ); #elif defined( HB_OS_DOS ) ret = sock_init(); #endif } HB_SOCKET_UNLOCK return ret; } void hb_socketCleanup( void ) { HB_SOCKET_LOCK if( --s_iSessions == 0 ) { #if defined( HB_OS_WIN ) WSACleanup(); #elif defined( HB_OS_DOS ) sock_exit(); #endif } HB_SOCKET_UNLOCK } static void hb_socketSetOsError( int err ) { PHB_IOERRORS pError = hb_stackIOErrors(); USHORT uiErr; #if defined( HB_OS_WIN ) switch( err ) { case 0: uiErr = 0; break; case WSAEINTR: uiErr = HB_SOCKET_ERR_INTERRUPT; break; case WSAEBADF: case WSAENOTSOCK: uiErr = HB_SOCKET_ERR_INVALIDHANDLE; break; case WSAEACCES: uiErr = HB_SOCKET_ERR_ACCESS; break; case WSAEFAULT: uiErr = HB_SOCKET_ERR_FAULT; break; case WSAEINVAL: uiErr = HB_SOCKET_ERR_INVAL; break; case WSAEMFILE: uiErr = HB_SOCKET_ERR_NOFILE; break; case WSAEWOULDBLOCK: uiErr = HB_SOCKET_ERR_AGAIN; break; case WSAEINPROGRESS: uiErr = HB_SOCKET_ERR_INPROGRESS; break; case WSAEALREADY: uiErr = HB_SOCKET_ERR_ALREADY; break; case WSAEDESTADDRREQ: uiErr = HB_SOCKET_ERR_DESTADDRREQ; break; case WSAEMSGSIZE: uiErr = HB_SOCKET_ERR_MSGSIZE; break; case WSAEPROTOTYPE: uiErr = HB_SOCKET_ERR_PROTOTYPE; break; case WSAENOPROTOOPT: uiErr = HB_SOCKET_ERR_NOPROTOOPT; break; case WSAEPROTONOSUPPORT: uiErr = HB_SOCKET_ERR_PROTONOSUPPORT; break; case WSAEOPNOTSUPP: case WSAESOCKTNOSUPPORT: uiErr = HB_SOCKET_ERR_NOSUPPORT; break; case WSAEPFNOSUPPORT: uiErr = HB_SOCKET_ERR_PFNOSUPPORT; break; case WSAEAFNOSUPPORT: uiErr = HB_SOCKET_ERR_AFNOSUPPORT; break; case WSAEADDRINUSE: uiErr = HB_SOCKET_ERR_ADDRINUSE; break; case WSAEADDRNOTAVAIL: uiErr = HB_SOCKET_ERR_ADDRNOTAVAIL; break; case WSAENETDOWN: uiErr = HB_SOCKET_ERR_NETDOWN; break; case WSAENETUNREACH: uiErr = HB_SOCKET_ERR_NETUNREACH; break; case WSAENETRESET: uiErr = HB_SOCKET_ERR_NETRESET; break; case WSAECONNREFUSED: uiErr = HB_SOCKET_ERR_CONNREFUSED; break; case WSAECONNABORTED: uiErr = HB_SOCKET_ERR_CONNABORTED; break; case WSAECONNRESET: uiErr = HB_SOCKET_ERR_CONNRESET; break; case WSAENOBUFS: uiErr = HB_SOCKET_ERR_NOBUFS; break; case WSAEISCONN: uiErr = HB_SOCKET_ERR_ALREADYCONNECTED; break; case WSAENOTCONN: uiErr = HB_SOCKET_ERR_NOTCONN; break; case WSAESHUTDOWN: uiErr = HB_SOCKET_ERR_SHUTDOWN; break; case WSAETOOMANYREFS: uiErr = HB_SOCKET_ERR_TOOMANYREFS; break; case WSAETIMEDOUT: uiErr = HB_SOCKET_ERR_TIMEOUT; break; case WSAELOOP: uiErr = HB_SOCKET_ERR_LOOP; break; case WSAENAMETOOLONG: uiErr = HB_SOCKET_ERR_NAMETOOLONG; break; case WSAEHOSTDOWN: uiErr = HB_SOCKET_ERR_HOSTDOWN; break; case WSAEHOSTUNREACH: uiErr = HB_SOCKET_ERR_HOSTUNREACH; break; case WSAENOTEMPTY: uiErr = HB_SOCKET_ERR_NOTEMPTY; break; case WSAEUSERS: uiErr = HB_SOCKET_ERR_USERS; break; case WSAEDQUOT: uiErr = HB_SOCKET_ERR_DQUOT; break; case WSAESTALE: uiErr = HB_SOCKET_ERR_STALE; break; case WSAEREMOTE: uiErr = HB_SOCKET_ERR_REMOTE; break; case WSAEPROCLIM: uiErr = HB_SOCKET_ERR_PROCLIM; break; case WSAEDISCON: uiErr = HB_SOCKET_ERR_DISCON; break; case WSAENOMORE: uiErr = HB_SOCKET_ERR_NOMORE; break; case WSAECANCELLED: uiErr = HB_SOCKET_ERR_CANCELLED; break; case WSAEINVALIDPROCTABLE: uiErr = HB_SOCKET_ERR_INVALIDPROCTABLE; break; case WSAEINVALIDPROVIDER: uiErr = HB_SOCKET_ERR_INVALIDPROVIDER; break; case WSAEPROVIDERFAILEDINIT: uiErr = HB_SOCKET_ERR_PROVIDERFAILEDINIT; break; case WSAEREFUSED: uiErr = HB_SOCKET_ERR_REFUSED; break; case WSATRY_AGAIN: uiErr = HB_SOCKET_ERR_TRYAGAIN; break; case WSASYSNOTREADY: uiErr = HB_SOCKET_ERR_SYSNOTREADY; break; case WSAVERNOTSUPPORTED: uiErr = HB_SOCKET_ERR_VERNOTSUPPORTED; break; case WSANOTINITIALISED: uiErr = HB_SOCKET_ERR_NOTINITIALISED; break; case WSAHOST_NOT_FOUND: uiErr = HB_SOCKET_ERR_HOSTNOTFOUND; break; case WSANO_RECOVERY: uiErr = HB_SOCKET_ERR_NORECOVERY; break; case WSANO_DATA: uiErr = HB_SOCKET_ERR_NODATA; break; case WSASYSCALLFAILURE: uiErr = HB_SOCKET_ERR_SYSCALLFAILURE; break; case WSASERVICE_NOT_FOUND: uiErr = HB_SOCKET_ERR_SERVICENOTFOUND; break; case WSATYPE_NOT_FOUND: uiErr = HB_SOCKET_ERR_TYPENOTFOUND; break; case WSA_E_NO_MORE: uiErr = HB_SOCKET_ERR_NOMORE; break; case WSA_E_CANCELLED: uiErr = HB_SOCKET_ERR_CANCELLED; break; default: uiErr = HB_SOCKET_ERR_OTHER; break; } #else switch( err ) { case 0: uiErr = 0; break; #if defined( EPFNOSUPPORT ) case EPFNOSUPPORT: uiErr = HB_SOCKET_ERR_PFNOSUPPORT; break; #endif #if defined( EAFNOSUPPORT ) case EAFNOSUPPORT: uiErr = HB_SOCKET_ERR_AFNOSUPPORT; break; #endif #if defined( EPROTONOSUPPORT ) case EPROTONOSUPPORT: uiErr = HB_SOCKET_ERR_PROTONOSUPPORT; break; #endif case EADDRINUSE: uiErr = HB_SOCKET_ERR_ADDRINUSE; break; case EINTR: uiErr = HB_SOCKET_ERR_INTERRUPT; break; case ETIMEDOUT: uiErr = HB_SOCKET_ERR_TIMEOUT; break; case EISCONN: uiErr = HB_SOCKET_ERR_ALREADYCONNECTED; break; case ENOTCONN: uiErr = HB_SOCKET_ERR_NOTCONN; break; case ECONNABORTED: uiErr = HB_SOCKET_ERR_CONNABORTED; break; case ECONNRESET: uiErr = HB_SOCKET_ERR_CONNRESET; break; case ECONNREFUSED: uiErr = HB_SOCKET_ERR_CONNREFUSED; break; case ENETUNREACH: uiErr = HB_SOCKET_ERR_NETUNREACH; break; case ENETDOWN: uiErr = HB_SOCKET_ERR_NETDOWN; break; case ENETRESET: uiErr = HB_SOCKET_ERR_NETRESET; break; case EINPROGRESS: uiErr = HB_SOCKET_ERR_INPROGRESS; break; case EALREADY: uiErr = HB_SOCKET_ERR_ALREADY; break; case EADDRNOTAVAIL: uiErr = HB_SOCKET_ERR_ADDRNOTAVAIL; break; case EROFS: uiErr = HB_SOCKET_ERR_READONLY; break; case EAGAIN: #if defined( EWOULDBLOCK ) # if EWOULDBLOCK != EAGAIN case EWOULDBLOCK: # endif #endif uiErr = HB_SOCKET_ERR_AGAIN; break; case EPIPE: uiErr = HB_SOCKET_ERR_PIPE; break; case EPERM: case EACCES: uiErr = HB_SOCKET_ERR_ACCESS; break; case EBADF: case ENOTSOCK: uiErr = HB_SOCKET_ERR_INVALIDHANDLE; break; case EINVAL: uiErr = HB_SOCKET_ERR_INVAL; break; #if defined( EPROTO ) case EPROTO: uiErr = HB_SOCKET_ERR_PROTO; break; #endif case EPROTOTYPE: uiErr = HB_SOCKET_ERR_PROTOTYPE; break; case EOPNOTSUPP: #if defined( ESOCKTNOSUPPORT ) case ESOCKTNOSUPPORT: #endif uiErr = HB_SOCKET_ERR_NOSUPPORT; break; case EMFILE: case ENFILE: uiErr = HB_SOCKET_ERR_NOFILE; break; case ENOBUFS: uiErr = HB_SOCKET_ERR_NOBUFS; break; case ENOMEM: uiErr = HB_SOCKET_ERR_NOMEM; break; case EFAULT: uiErr = HB_SOCKET_ERR_FAULT; break; case ENAMETOOLONG: uiErr = HB_SOCKET_ERR_NAMETOOLONG; break; case ENOENT: uiErr = HB_SOCKET_ERR_NOENT; break; case ENOTDIR: uiErr = HB_SOCKET_ERR_NOTDIR; break; case ELOOP: uiErr = HB_SOCKET_ERR_LOOP; break; #if defined( ENOSR ) case ENOSR: uiErr = HB_SOCKET_ERR_NOSR; break; #endif #if defined( ERESTARTSYS ) case ERESTARTSYS: uiErr = HB_SOCKET_ERR_RESTARTSYS; break; #endif case EDESTADDRREQ: uiErr = HB_SOCKET_ERR_DESTADDRREQ; break; case EMSGSIZE: uiErr = HB_SOCKET_ERR_MSGSIZE; break; case ENOPROTOOPT: uiErr = HB_SOCKET_ERR_NOPROTOOPT; break; case ESHUTDOWN: uiErr = HB_SOCKET_ERR_SHUTDOWN; break; #if defined( ETOOMANYREFS ) case ETOOMANYREFS: uiErr = HB_SOCKET_ERR_TOOMANYREFS; break; #endif case EHOSTDOWN: uiErr = HB_SOCKET_ERR_HOSTDOWN; break; case EHOSTUNREACH: uiErr = HB_SOCKET_ERR_HOSTUNREACH; break; case ENOTEMPTY: uiErr = HB_SOCKET_ERR_NOTEMPTY; break; #if defined( EUSERS ) case EUSERS: uiErr = HB_SOCKET_ERR_USERS; break; #endif case EDQUOT: uiErr = HB_SOCKET_ERR_DQUOT; break; #if defined( ESTALE ) case ESTALE: uiErr = HB_SOCKET_ERR_STALE; break; #endif #if defined( EREMOTE ) case EREMOTE: uiErr = HB_SOCKET_ERR_REMOTE; break; #endif #if defined( EPROCLIM ) case EPROCLIM: uiErr = HB_SOCKET_ERR_PROCLIM; break; #endif #if defined( EDISCON ) case EDISCON: uiErr = HB_SOCKET_ERR_DISCON; break; #endif #if defined( ENOMORE ) case ENOMORE: uiErr = HB_SOCKET_ERR_NOMORE; break; #endif #if defined( ECANCELLED ) case ECANCELLED: uiErr = HB_SOCKET_ERR_CANCELLED; break; #endif #if defined( EINVALIDPROCTABLE ) case EINVALIDPROCTABLE: uiErr = HB_SOCKET_ERR_INVALIDPROCTABLE; break; #endif #if defined( EINVALIDPROVIDER ) case EINVALIDPROVIDER: uiErr = HB_SOCKET_ERR_INVALIDPROVIDER; break; #endif #if defined( EPROVIDERFAILEDINIT ) case EPROVIDERFAILEDINIT: uiErr = HB_SOCKET_ERR_PROVIDERFAILEDINIT; break; #endif #if defined( EREFUSED ) case EREFUSED: uiErr = HB_SOCKET_ERR_REFUSED; break; #endif /* #if defined( TRY_AGAIN ) case TRY_AGAIN: uiErr = HB_SOCKET_ERR_TRYAGAIN; break; #endif #if defined( HOST_NOT_FOUND ) case HOST_NOT_FOUND: uiErr = HB_SOCKET_ERR_HOSTNOTFOUND; break; #endif #if defined( NO_RECOVERY ) case NO_RECOVERY: uiErr = HB_SOCKET_ERR_NORECOVERY; break; #endif #if defined( NO_DATA ) || defined( NO_ADDRESS ) #if defined( NO_DATA ) case NO_DATA: #endif #if defined( NO_ADDRESS ) && \ ( !defined( NO_DATA ) || NO_ADDRESS != NO_DATA ) case NO_ADDRESS: #endif uiErr = HB_SOCKET_ERR_NODATA; break; #endif */ default: uiErr = HB_SOCKET_ERR_OTHER; break; } #endif pError->uiSocketError = uiErr; pError->iSocketOsError = err; } #if defined( HB_SOCKET_TRANSLATE_DOMAIN ) static int hb_socketTransDomain( int domain, int *err ) { switch( domain ) { case HB_SOCKET_PF_INET: #if defined( PF_INET ) domain = PF_INET; #elif defined( AF_INET ) domain = AF_INET; #else if( err ) *err = HB_SOCKET_ERR_PFNOSUPPORT; #endif break; case HB_SOCKET_PF_INET6: #if defined( PF_INET6 ) domain = PF_INET6; #elif defined( AF_INET6 ) domain = AF_INET6; #else if( err ) *err = HB_SOCKET_ERR_PFNOSUPPORT; #endif break; case HB_SOCKET_PF_LOCAL: #if defined( PF_LOCAL ) domain = PF_LOCAL; #elif defined( AF_LOCAL ) domain = AF_LOCAL; #elif defined( PF_UNIX ) domain = PF_UNIX; #elif defined( AF_UNIX ) domain = AF_UNIX; #else if( err ) *err = HB_SOCKET_ERR_PFNOSUPPORT; #endif break; case HB_SOCKET_PF_PACKET: #if defined( PF_PACKET ) domain = PF_PACKET; #elif defined( AF_PACKET ) domain = AF_PACKET; #else if( err ) *err = HB_SOCKET_ERR_PFNOSUPPORT; #endif break; case HB_SOCKET_PF_IPX: #if defined( PF_IPX ) domain = PF_IPX; #elif defined( AF_IPX ) domain = AF_IPX; #else if( err ) *err = HB_SOCKET_ERR_PFNOSUPPORT; #endif break; default: if( err ) *err = HB_SOCKET_ERR_PFNOSUPPORT; } return domain; } #endif #if defined( HB_SOCKET_TRANSLATE_TYPE ) static int hb_socketTransType( int type, int *err ) { switch( type ) { case HB_SOCKET_PT_STREAM: #if defined( SOCK_STREAM ) type = SOCK_STREAM; #else if( err ) *err = HB_SOCKET_ERR_PROTONOSUPPORT; #endif break; case HB_SOCKET_PT_DGRAM: #if defined( SOCK_DGRAM ) type = SOCK_DGRAM; #else if( err ) *err = HB_SOCKET_ERR_PROTONOSUPPORT; #endif break; case HB_SOCKET_PT_SEQPACKET: #if defined( SOCK_SEQPACKET ) type = SOCK_SEQPACKET; #else if( err ) *err = HB_SOCKET_ERR_PROTONOSUPPORT; #endif break; case HB_SOCKET_PT_RAW: #if defined( SOCK_RAW ) type = SOCK_RAW; #else if( err ) *err = HB_SOCKET_ERR_PROTONOSUPPORT; #endif break; case HB_SOCKET_PT_RDM: #if defined( SOCK_RDM ) type = SOCK_RDM; #else if( err ) *err = HB_SOCKET_ERR_PROTONOSUPPORT; #endif break; default: if( err ) *err = HB_SOCKET_ERR_PROTONOSUPPORT; } return type; } #endif static int hb_socketSelectRD( HB_SOCKET sd, HB_LONG timeout ) { struct timeval tv, * ptv; fd_set rfds; int iResult; #if !defined( HB_HAS_SELECT_TIMER ) HB_ULONG timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); #endif for( ;; ) { FD_ZERO( &rfds ); FD_SET( sd, &rfds ); if( timeout >= 0 ) { tv.tv_sec = ( long ) ( timeout / 1000 ); tv.tv_usec = ( timeout % 1000 ) * 1000; ptv = &tv; } else ptv = NULL; iResult = select( ( int ) ( sd + 1 ), &rfds, NULL, NULL, ptv ); hb_socketSetOsError( iResult >= 0 ? 0 : HB_SOCK_GETERROR() ); if( iResult == -1 && timeout > 0 && HB_SOCK_IS_EINTR() && hb_vmRequestQuery() == 0 ) #if defined( HB_HAS_SELECT_TIMER ) continue; #else { HB_ULONG timecurr = hb_dateMilliSeconds(); if( timecurr > timer ) { timeout -= timecurr - timer; timer = timecurr; if( timeout > 0 ) continue; } } #endif break; } return iResult < 0 ? -1 : ( iResult > 0 && FD_ISSET( sd, &rfds ) ? 1 : 0 ); } static int hb_socketSelectWR( HB_SOCKET sd, HB_LONG timeout ) { struct timeval tv, * ptv; fd_set wfds; int iResult; #if !defined( HB_HAS_SELECT_TIMER ) HB_ULONG timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); #endif for( ;; ) { FD_ZERO( &wfds ); FD_SET( sd, &wfds ); if( timeout >= 0 ) { tv.tv_sec = ( long ) ( timeout / 1000 ); tv.tv_usec = ( timeout % 1000 ) * 1000; ptv = &tv; } else ptv = NULL; iResult = select( ( int ) ( sd + 1 ), NULL, &wfds, NULL, ptv ); hb_socketSetOsError( iResult >= 0 ? 0 : HB_SOCK_GETERROR() ); if( iResult == -1 && timeout > 0 && HB_SOCK_IS_EINTR() && hb_vmRequestQuery() == 0 ) #if defined( HB_HAS_SELECT_TIMER ) continue; #else { HB_ULONG timecurr = hb_dateMilliSeconds(); if( timecurr > timer ) { timeout -= timecurr - timer; timer = timecurr; if( timeout > 0 ) continue; } } #endif break; } return iResult < 0 ? -1 : ( iResult > 0 && FD_ISSET( sd, &wfds ) ? 1 : 0 ); } static int hb_socketSelectWRE( HB_SOCKET sd, HB_LONG timeout ) { struct timeval tv, * ptv; fd_set wfds, * pefds; #if defined( HB_OS_WIN ) fd_set efds; #endif int iResult; #if !defined( HB_HAS_SELECT_TIMER ) HB_ULONG timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); #endif for( ;; ) { FD_ZERO( &wfds ); FD_SET( sd, &wfds ); #if defined( HB_OS_WIN ) FD_ZERO( &efds ); FD_SET( sd, &efds ); pefds = &efds; #else pefds = NULL; #endif if( timeout >= 0 ) { tv.tv_sec = ( long ) ( timeout / 1000 ); tv.tv_usec = ( timeout % 1000 ) * 1000; ptv = &tv; } else ptv = NULL; iResult = select( ( int ) ( sd + 1 ), NULL, &wfds, pefds, ptv ); hb_socketSetOsError( iResult >= 0 ? 0 : HB_SOCK_GETERROR() ); #if defined( HB_OS_WIN ) if( iResult > 0 && FD_ISSET( sd, pefds ) ) iResult = -1; else #endif if( iResult == -1 && timeout > 0 && HB_SOCK_IS_EINTR() && hb_vmRequestQuery() == 0 ) #if defined( HB_HAS_SELECT_TIMER ) continue; #else { HB_ULONG timecurr = hb_dateMilliSeconds(); if( timecurr > timer ) { timeout -= timecurr - timer; timer = timecurr; if( timeout > 0 ) continue; } } #endif break; } #if !defined( HB_OS_WIN ) if( iResult > 0 && FD_ISSET( sd, &wfds ) ) { int iError; socklen_t len = sizeof( iError ); if( getsockopt( sd, SOL_SOCKET, SO_ERROR, ( void * ) &iError, &len ) != 0 ) { iResult = -1; hb_socketSetOsError( HB_SOCK_GETERROR() ); } else if( iError != 0 ) { iResult = -1; hb_socketSetOsError( iError ); } } #endif return iResult < 0 ? -1 : ( iResult > 0 && FD_ISSET( sd, &wfds ) ? 1 : 0 ); } int hb_socketGetAddrFamilly( const void * pSockAddr, unsigned len ) { return pSockAddr && len ? ( ( struct sockaddr * ) pSockAddr )->sa_family : -1; } BOOL hb_socketLocalAddr( void ** pSockAddr, unsigned * puiLen, const char * szAddr ) { #if defined( HB_HAS_UNIX ) struct sockaddr_un sa; memset( &sa, 0, sizeof( sa ) ); #if defined( AF_UNIX ) sa.sun_family = AF_UNIX; #else sa.sun_family = AF_LOCAL; #endif hb_strncpy( sa.sun_path, szAddr, sizeof( sa.sun_path ) - 1 ); *pSockAddr = memcpy( hb_xgrab( sizeof( sa ) + 1 ), &sa, sizeof( sa ) ); *puiLen = ( unsigned ) sizeof( sa ); return TRUE; #else HB_SYMBOL_UNUSED( szAddr ); *pSockAddr = NULL; *puiLen = 0; hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); return FALSE; #endif } BOOL hb_socketInetAddr( void ** pSockAddr, unsigned * puiLen, const char * szAddr, int iPort ) { #if defined( AF_INET ) struct sockaddr_in sa; memset( &sa, 0, sizeof( sa ) ); sa.sin_family = AF_INET; sa.sin_port = htons( ( hbU16 ) iPort ); if( !szAddr || !*szAddr ) { sa.sin_addr.s_addr = htonl( INADDR_ANY ); *pSockAddr = memcpy( hb_xgrab( sizeof( sa ) + 1 ), &sa, sizeof( sa ) ); *puiLen = ( unsigned ) sizeof( sa ); return TRUE; } else { #if defined( HB_HAS_INET_PTON ) if( inet_pton( AF_INET, szAddr, &sa.sin_addr ) > 0 ) #elif defined( HB_HAS_INET_ATON ) if( inet_aton( szAddr, &sa.sin_addr ) != 0 ) #else sa.sin_addr.s_addr = inet_addr( szAddr ); if( sa.sin_addr.s_addr != INADDR_NONE || strcmp( "255.255.255.255", szAddr ) == 0 ) /* dirty hack */ #endif { *pSockAddr = memcpy( hb_xgrab( sizeof( sa ) + 1 ), &sa, sizeof( sa ) ); *puiLen = ( unsigned ) sizeof( sa ); return TRUE; } else hb_socketSetRawError( HB_SOCKET_ERR_WRONGADDR ); } #else HB_SYMBOL_UNUSED( szAddr ); HB_SYMBOL_UNUSED( iPort ); hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); #endif *pSockAddr = NULL; *puiLen = 0; return FALSE; } BOOL hb_socketInet6Addr( void ** pSockAddr, unsigned * puiLen, const char * szAddr, int iPort ) { #if defined( HB_HAS_INET6 ) struct sockaddr_in6 sa; memset( &sa, 0, sizeof( sa ) ); sa.sin6_family = AF_INET6; sa.sin6_port = htons( ( hbU16 ) iPort ); if( !szAddr || !*szAddr ) { #if defined( HB_HAS_INET6_ADDR_CONST ) memcpy( &sa.sin6_addr, &in6addr_any, sizeof( struct in6_addr ) ); #elif defined( IN6ADDR_ANY_INIT ) memcpy( &sa.sin6_addr, &s_in6addr_any, sizeof( struct in6_addr ) ); #else int TODO; #endif *pSockAddr = memcpy( hb_xgrab( sizeof( sa ) + 1 ), &sa, sizeof( sa ) ); *puiLen = ( unsigned ) sizeof( sa ); return TRUE; } else { #if defined( HB_HAS_INET_PTON ) int err = inet_pton( AF_INET6, szAddr, &sa.sin6_addr ); if( err > 0 ) { *pSockAddr = memcpy( hb_xgrab( sizeof( sa ) + 1 ), &sa, sizeof( sa ) ); *puiLen = ( unsigned ) sizeof( sa ); return TRUE; } else if( err == 0 ) hb_socketSetRawError( HB_SOCKET_ERR_WRONGADDR ); else hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); #else int TODO; #endif } #else HB_SYMBOL_UNUSED( szAddr ); HB_SYMBOL_UNUSED( iPort ); hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); #endif *pSockAddr = NULL; *puiLen = 0; return FALSE; } /* caller must free the buffer if not NULL */ char * hb_socketAddrGetName( const void * pSockAddr, unsigned len ) { char * szName = NULL; switch( hb_socketGetAddrFamilly( pSockAddr, len ) ) { #if defined( AF_INET ) case AF_INET: if( len >= sizeof( struct sockaddr_in ) ) { struct sockaddr_in * sa = ( struct sockaddr_in * ) pSockAddr; const char * szAddr; # if defined( HB_HAS_INET_NTOP ) char buf[ INET_ADDRSTRLEN ]; szAddr = inet_ntop( AF_INET, &sa->sin_addr, buf, sizeof( buf ) ); # elif defined( HB_IS_INET_NTOA_MT_SAFE ) szAddr = inet_ntoa( sa->sin_addr ); # else char buf[ INET_ADDRSTRLEN ]; szAddr = hb_inet_ntoa( &sa->sin_addr, buf ); # endif if( szAddr ) szName = hb_strdup( szAddr ); } break; #endif #if defined( HB_HAS_INET6 ) case AF_INET6: if( len >= sizeof( struct sockaddr_in6 ) ) { struct sockaddr_in6 * sa = ( struct sockaddr_in6 * ) pSockAddr; const char * szAddr; # if defined( HB_HAS_INET_NTOP ) char buf[ INET6_ADDRSTRLEN ]; szAddr = inet_ntop( AF_INET, &sa->sin6_addr, buf, sizeof( buf ) ); # else { int TODO; szAddr = NULL; } # endif if( szAddr ) szName = hb_strdup( szAddr ); } break; #endif #if defined( HB_HAS_UNIX ) # if defined( AF_UNIX ) case AF_UNIX: # else case AF_LOCAL: # endif if( len >= sizeof( struct sockaddr_un ) ) { struct sockaddr_un * sa = ( struct sockaddr_un * ) pSockAddr; szName = hb_strdup( sa->sun_path ); } break; #endif #if defined( AF_IPX ) case AF_IPX: break; #endif #if defined( AF_PACKET ) case AF_PACKET: break; #endif } hb_socketSetRawError( szName ? 0 : HB_SOCKET_ERR_AFNOSUPPORT ); return szName; } int hb_socketAddrGetPort( const void * pSockAddr, unsigned len ) { int iPort = -1; switch( hb_socketGetAddrFamilly( pSockAddr, len ) ) { #if defined( AF_INET ) case AF_INET: if( len >= sizeof( struct sockaddr_in ) ) iPort = ntohs( ( ( struct sockaddr_in * ) pSockAddr )->sin_port ); break; #endif #if defined( HB_HAS_INET6 ) case AF_INET6: if( len >= sizeof( struct sockaddr_in6 ) ) iPort = ntohs( ( ( struct sockaddr_in6 * ) pSockAddr )->sin6_port ); break; #endif #if defined( HB_HAS_UNIX ) # if defined( AF_UNIX ) case AF_UNIX: # else case AF_LOCAL: # endif break; #endif #if defined( AF_IPX ) case AF_IPX: break; #endif #if defined( AF_PACKET ) case AF_PACKET: break; #endif } hb_socketSetRawError( iPort != -1 ? 0 : HB_SOCKET_ERR_AFNOSUPPORT ); return iPort; } BOOL hb_socketAddrFromItem( void ** pSockAddr, unsigned * puiLen, PHB_ITEM pAddrItm ) { BOOL fOK = FALSE; *pSockAddr = NULL; *puiLen = 0; if( pAddrItm && HB_IS_ARRAY( pAddrItm ) ) { if( hb_arrayLen( pAddrItm ) >= 2 && ( hb_arrayGetType( pAddrItm, 1 ) & HB_IT_NUMERIC ) != 0 ) { switch( hb_arrayGetNI( pAddrItm, 1 ) ) { case HB_SOCKET_PF_INET: fOK = hb_socketInetAddr( pSockAddr, puiLen, hb_arrayGetCPtr( pAddrItm, 2 ), hb_arrayGetNI( pAddrItm, 3 ) ); break; case HB_SOCKET_PF_INET6: fOK = hb_socketInet6Addr( pSockAddr, puiLen, hb_arrayGetCPtr( pAddrItm, 2 ), hb_arrayGetNI( pAddrItm, 3 ) ); break; case HB_SOCKET_PF_LOCAL: fOK = hb_socketLocalAddr( pSockAddr, puiLen, hb_arrayGetCPtr( pAddrItm, 2 ) ); break; case HB_SOCKET_PF_PACKET: case HB_SOCKET_PF_IPX: break; } } } hb_socketSetRawError( fOK ? 0 : HB_SOCKET_ERR_AFNOSUPPORT ); return fOK; } PHB_ITEM hb_socketAddrToItem( const void * pSockAddr, unsigned len ) { PHB_ITEM pAddrItm = NULL; switch( hb_socketGetAddrFamilly( pSockAddr, len ) ) { #if defined( AF_INET ) case AF_INET: if( len >= sizeof( struct sockaddr_in ) ) { struct sockaddr_in * sa = ( struct sockaddr_in * ) pSockAddr; const char * szAddr; # if defined( HB_HAS_INET_NTOP ) char buf[ INET_ADDRSTRLEN ]; szAddr = inet_ntop( AF_INET, &sa->sin_addr, buf, sizeof( buf ) ); # elif defined( HB_IS_INET_NTOA_MT_SAFE ) szAddr = inet_ntoa( sa->sin_addr ); # else char buf[ INET_ADDRSTRLEN ]; szAddr = hb_inet_ntoa( &sa->sin_addr, buf ); # endif if( szAddr ) { pAddrItm = hb_itemArrayNew( 3 ); hb_arraySetNI( pAddrItm, 1, HB_SOCKET_PF_INET ); hb_arraySetC( pAddrItm, 2, szAddr ); hb_arraySetNI( pAddrItm, 3, ntohs( sa->sin_port ) ); } } break; #endif #if defined( HB_HAS_INET6 ) case AF_INET6: if( len >= sizeof( struct sockaddr_in6 ) ) { struct sockaddr_in6 * sa = ( struct sockaddr_in6 * ) pSockAddr; const char * szAddr; # if defined( HB_HAS_INET_NTOP ) char buf[ INET6_ADDRSTRLEN ]; szAddr = inet_ntop( AF_INET, &sa->sin6_addr, buf, sizeof( buf ) ); # else { int TODO; szAddr = NULL; } # endif if( szAddr ) { pAddrItm = hb_itemArrayNew( 3 ); hb_arraySetNI( pAddrItm, 1, HB_SOCKET_PF_INET6 ); hb_arraySetC( pAddrItm, 2, szAddr ); hb_arraySetNI( pAddrItm, 3, ntohs( sa->sin6_port ) ); } } break; #endif #if defined( HB_HAS_UNIX ) # if defined( AF_UNIX ) case AF_UNIX: # else case AF_LOCAL: # endif if( len >= sizeof( struct sockaddr_un ) ) { struct sockaddr_un * sa = ( struct sockaddr_un * ) pSockAddr; pAddrItm = hb_itemArrayNew( 2 ); hb_arraySetNI( pAddrItm, 1, HB_SOCKET_PF_LOCAL ); hb_arraySetC( pAddrItm, 2, sa->sun_path ); } break; #endif #if defined( AF_IPX ) case AF_IPX: break; #endif #if defined( AF_PACKET ) case AF_PACKET: break; #endif } hb_socketSetRawError( pAddrItm ? 0 : HB_SOCKET_ERR_AFNOSUPPORT ); return pAddrItm; } int hb_socketGetSockName( HB_SOCKET sd, void ** pSockAddr, unsigned * puiLen ) { int ret; #if defined( HB_HAS_SOCKADDR_STORAGE ) struct sockaddr_storage st; struct sockaddr * sa = ( struct sockaddr * ) ( void * ) &st; #else char st[ HB_SOCKADDR_MAX_LEN ]; struct sockaddr * sa = ( struct sockaddr * ) ( void * ) st; #endif socklen_t len = sizeof( st ); ret = getsockname( sd, sa, &len ); hb_socketSetOsError( ret == 0 ? 0 : HB_SOCK_GETERROR() ); if( ret == 0 ) { *pSockAddr = memcpy( hb_xgrab( len + 1 ), sa, len ); *puiLen = ( unsigned ) len; } else { *pSockAddr = NULL; *puiLen = 0; } return ret; } int hb_socketGetPeerName( HB_SOCKET sd, void ** pSockAddr, unsigned * puiLen ) { int ret; #if defined( __WATCOMC__ ) && defined( HB_OS_LINUX ) /* it's still not supported by Linux OpenWatcom port :-( */ ret = -1; hb_socketSetRawError( HB_SOCKET_ERR_NOSUPPORT ); #else #if defined( HB_HAS_SOCKADDR_STORAGE ) struct sockaddr_storage st; struct sockaddr * sa = ( struct sockaddr * ) ( void * ) &st; #else char st[ HB_SOCKADDR_MAX_LEN ]; struct sockaddr * sa = ( struct sockaddr * ) ( void * ) st; #endif socklen_t len = sizeof( st ); ret = getpeername( sd, sa, &len ); hb_socketSetOsError( ret == 0 ? 0 : HB_SOCK_GETERROR() ); if( ret == 0 ) { *pSockAddr = memcpy( hb_xgrab( len + 1 ), sa, len ); *puiLen = ( unsigned ) len; } else #endif { *pSockAddr = NULL; *puiLen = 0; } return ret; } HB_SOCKET hb_socketOpen( int domain, int type, int protocol ) { HB_SOCKET sd = HB_NO_SOCKET; int err = 0; #if defined( HB_SOCKET_TRANSLATE_DOMAIN ) domain = hb_socketTransDomain( domain, &err ); #endif #if defined( HB_SOCKET_TRANSLATE_TYPE ) if( err == 0 ) type = hb_socketTransType( type, &err ); #endif if( err == 0 ) { sd = socket( domain, type, protocol ); hb_socketSetOsError( sd != HB_NO_SOCKET ? 0 : HB_SOCK_GETERROR() ); } else hb_socketSetRawError( err ); return sd; } int hb_socketClose( HB_SOCKET sd ) { int ret; hb_vmUnlock(); #if defined( HB_OS_WIN ) ret = closesocket( sd ); #elif defined( HB_OS_DOS ) ret = close_s( sd ); #else # if defined( EINTR ) /* ignoring EINTR in close() it's quite common bug when sockets or * pipes are used. Without such protection it's not safe to use * signals in user code. */ do ret = close( sd ); while( ret == -1 && errno == EINTR ); # else ret = close( sd ); # endif #endif hb_socketSetOsError( ret == 0 ? 0 : HB_SOCK_GETERROR() ); hb_vmLock(); return ret; } int hb_socketShutdown( HB_SOCKET sd, int iMode ) { int ret; #if defined( HB_OS_WIN ) if( iMode == HB_SOCKET_SHUT_RD ) iMode = SD_RECEIVE; else if( iMode == HB_SOCKET_SHUT_WR ) iMode = SD_SEND; else if( iMode == HB_SOCKET_SHUT_RDWR ) iMode = SD_BOTH; #elif defined( HB_OS_OS2 ) if( iMode == HB_SOCKET_SHUT_RD ) iMode = SO_RCV_SHUTDOWN; else if( iMode == HB_SOCKET_SHUT_WR ) iMode = SO_SND_SHUTDOWN; else if( iMode == HB_SOCKET_SHUT_RDWR ) iMode = SO_RCV_SHUTDOWN | SO_SND_SHUTDOWN; #elif defined( __WATCOMC__ ) if( iMode == HB_SOCKET_SHUT_RD || iMode == HB_SOCKET_SHUT_WR || iMode == HB_SOCKET_SHUT_RDWR ) { ; } #else if( iMode == HB_SOCKET_SHUT_RD ) iMode = SHUT_RD; else if( iMode == HB_SOCKET_SHUT_WR ) iMode = SHUT_WR; else if( iMode == HB_SOCKET_SHUT_RDWR ) iMode = SHUT_RDWR; #endif else { hb_socketSetRawError( HB_SOCKET_ERR_PARAMVALUE ); return -1; } #if defined( __WATCOMC__ ) && defined( HB_OS_LINUX ) /* it's still not supported by Linux OpenWatcom port :-( */ ret = -1; hb_socketSetRawError( HB_SOCKET_ERR_NOSUPPORT ); #else hb_vmUnlock(); ret = shutdown( sd, iMode ); hb_socketSetOsError( ret == 0 ? 0 : HB_SOCK_GETERROR() ); hb_vmLock(); #endif return ret; } int hb_socketBind( HB_SOCKET sd, const void * pSockAddr, unsigned uiLen ) { int ret; /* it allows to reuse port immediately without timeout used to * clean all pending connections addressed to previous port owner */ hb_socketSetReuseAddr( sd, TRUE ); ret = bind( sd, ( struct sockaddr * ) pSockAddr, ( socklen_t ) uiLen ); hb_socketSetOsError( ret == 0 ? 0 : HB_SOCK_GETERROR() ); return ret; } int hb_socketListen( HB_SOCKET sd, int iBacklog ) { int ret; ret = listen( sd, iBacklog ); hb_socketSetOsError( ret == 0 ? 0 : HB_SOCK_GETERROR() ); return ret; } HB_SOCKET hb_socketAccept( HB_SOCKET sd, void ** pSockAddr, unsigned * puiLen, HB_LONG timeout ) { HB_SOCKET newsd = HB_NO_SOCKET; int ret; #if defined( HB_HAS_SOCKADDR_STORAGE ) struct sockaddr_storage st; struct sockaddr * sa = ( struct sockaddr * ) ( void * ) &st; #else char st[ HB_SOCKADDR_MAX_LEN ]; struct sockaddr * sa = ( struct sockaddr * ) ( void * ) st; #endif socklen_t len = sizeof( st ); hb_vmUnlock(); ret = hb_socketSelectRD( sd, timeout ); if( ret > 0 ) { /* it's necessary to set non blocking IO to be sure that application * will not be frozen inside accept(). It may happen if some asynchronous * network error appear after above select() or when other thread * accepts incoming connection (concurrent calls). */ ret = timeout < 0 ? 0 : hb_socketSetBlockingIO( sd, FALSE ); newsd = accept( sd, sa, &len ); hb_socketSetOsError( newsd != HB_NO_SOCKET ? 0 : HB_SOCK_GETERROR() ); if( ret > 0 ) hb_socketSetBlockingIO( sd, TRUE ); if( pSockAddr && puiLen ) { if( newsd == HB_NO_SOCKET ) { *pSockAddr = NULL; *puiLen = 0; } else { *pSockAddr = memcpy( hb_xgrab( len + 1 ), sa, len ); *puiLen = ( unsigned ) len; } } /* it's not guarantied that socket returned by accept will use * blocking IO operations. On some systems it inherits blocking IO * from parent handler so we have to force blocking IO mode * explicitly.. */ if( newsd != HB_NO_SOCKET ) hb_socketSetBlockingIO( newsd, TRUE ); } else if( ret == 0 ) hb_socketSetRawError( HB_SOCKET_ERR_TIMEOUT ); hb_vmLock(); return newsd; } int hb_socketConnect( HB_SOCKET sd, const void * pSockAddr, unsigned uiLen, HB_LONG timeout ) { int ret, blk; hb_vmUnlock(); /* set not blocking IO to implement timeout in connect() operation in * portable way without using signals */ blk = timeout < 0 ? 0 : hb_socketSetBlockingIO( sd, FALSE ); ret = connect( sd, ( struct sockaddr * ) pSockAddr, ( socklen_t ) uiLen ); hb_socketSetOsError( ret == 0 ? 0 : HB_SOCK_GETERROR() ); if( ret != 0 && HB_SOCK_IS_EINPROGRES() && timeout >= 0 ) { /* inside hb_socketSelectWRE() we have code which hides differences * between Windows and POSIX platforms in error detection. */ ret = hb_socketSelectWRE( sd, timeout ); if( ret > 0 ) ret = 0; else if( ret == 0 ) { hb_socketSetRawError( HB_SOCKET_ERR_TIMEOUT ); ret = -1; } } if( blk > 0 ) hb_socketSetBlockingIO( sd, TRUE ); hb_vmLock(); return ret; } long hb_socketSend( HB_SOCKET sd, const void * data, long len, int flags, HB_LONG timeout ) { long lSent = 0; hb_vmUnlock(); if( timeout >= 0 ) { lSent = hb_socketSelectWR( sd, timeout ); if( lSent == 0 ) { hb_socketSetRawError( HB_SOCKET_ERR_TIMEOUT ); lSent = -1; } } if( lSent >= 0 ) { /* in POSIX systems writing data to broken connection stream causes * that system generates SIGPIPE which has to be caught by application * otherwise the default action for SIGPIPE is application termination. * we do not want to generate it so we are setting MSG_NOSIGNAL flag. */ #if defined( MSG_NOSIGNAL ) flags |= MSG_NOSIGNAL; #endif do { lSent = send( sd, ( const char * ) data, len, flags ); hb_socketSetOsError( HB_SOCK_GETERROR() ); } while( lSent == -1 && HB_SOCK_IS_EINTR() && hb_vmRequestQuery() == 0 ); } hb_vmLock(); return lSent; } long hb_socketSendTo( HB_SOCKET sd, const void * data, long len, int flags, const void * pSockAddr, unsigned uiSockLen, HB_LONG timeout ) { long lSent = 0; hb_vmUnlock(); if( timeout >= 0 ) { lSent = hb_socketSelectWR( sd, timeout ); if( lSent == 0 ) { hb_socketSetRawError( HB_SOCKET_ERR_TIMEOUT ); lSent = -1; } } if( lSent >= 0 ) { /* see note above about SIGPIPE */ #if defined( MSG_NOSIGNAL ) flags |= MSG_NOSIGNAL; #endif do { lSent = sendto( sd, ( const char * ) data, len, flags, ( struct sockaddr * ) pSockAddr, ( socklen_t ) uiSockLen ); hb_socketSetOsError( HB_SOCK_GETERROR() ); } while( lSent == -1 && HB_SOCK_IS_EINTR() && hb_vmRequestQuery() == 0 ); } hb_vmLock(); return lSent; } long hb_socketRecv( HB_SOCKET sd, void * data, long len, int flags, HB_LONG timeout ) { long lReceived = 0; hb_vmUnlock(); if( timeout >= 0 ) { lReceived = hb_socketSelectRD( sd, timeout ); if( lReceived == 0 ) { hb_socketSetRawError( HB_SOCKET_ERR_TIMEOUT ); lReceived = -1; } } if( lReceived >= 0 ) { do { lReceived = recv( sd, ( char * ) data, len, flags ); hb_socketSetOsError( HB_SOCK_GETERROR() ); } while( lReceived == -1 && HB_SOCK_IS_EINTR() && hb_vmRequestQuery() == 0 ); } hb_vmLock(); return lReceived; } long hb_socketRecvFrom( HB_SOCKET sd, void * data, long len, int flags, void ** pSockAddr, unsigned * puiSockLen, HB_LONG timeout ) { long lReceived = 0; hb_vmUnlock(); if( timeout >= 0 ) { lReceived = hb_socketSelectRD( sd, timeout ); if( lReceived == 0 ) { hb_socketSetRawError( HB_SOCKET_ERR_TIMEOUT ); lReceived = -1; } } if( lReceived >= 0 ) { #if defined( HB_HAS_SOCKADDR_STORAGE ) struct sockaddr_storage st; struct sockaddr * sa = ( struct sockaddr * ) ( void * ) &st; #else char st[ HB_SOCKADDR_MAX_LEN ]; struct sockaddr * sa = ( struct sockaddr * ) ( void * ) st; #endif socklen_t salen = sizeof( st ); do { lReceived = recvfrom( sd, ( char * ) data, len, flags, sa, &salen ); hb_socketSetOsError( HB_SOCK_GETERROR() ); } while( lReceived == -1 && HB_SOCK_IS_EINTR() && hb_vmRequestQuery() == 0 ); if( pSockAddr && puiSockLen ) { if( lReceived == -1 ) { *pSockAddr = NULL; *puiSockLen = 0; } else { *pSockAddr = memcpy( hb_xgrab( salen + 1 ), sa, salen ); *puiSockLen = ( unsigned ) salen; } } } hb_vmLock(); return lReceived; } int hb_socketSetBlockingIO( HB_SOCKET sd, BOOL fBlocking ) { int ret; #if defined( HB_OS_WIN ) u_long mode = fBlocking ? 0 : 1; ret = ioctlsocket( sd, FIONBIO, &mode ); hb_socketSetOsError( ret != -1 ? 0 : HB_SOCK_GETERROR() ); if( ret == 0 ) ret = 1; #elif defined( HB_OS_DOS ) int mode = fBlocking ? 0 : 1; ret = ioctlsocket( sd, FIONBIO, ( char * ) &mode ); hb_socketSetOsError( ret != -1 ? 0 : HB_SOCK_GETERROR() ); if( ret == 0 ) ret = 1; #elif defined( O_NONBLOCK ) ret = fcntl( sd, F_GETFL, 0 ); if( ret != -1 ) { BOOL fBlocked; long flags; fBlocked = ( ret & O_NONBLOCK ) == 0; if( fBlocking ? !fBlocked : fBlocked ) { if( fBlocking ) flags = ret & ~O_NONBLOCK; else flags = ret | O_NONBLOCK; ret = fcntl( sd, F_SETFL, flags ); if( ret == 0 ) ret = 1; } else ret = 0; } hb_socketSetOsError( ret != -1 ? 0 : HB_SOCK_GETERROR() ); #elif defined( HB_OS_OS2 ) unsigned long mode = fBlocking ? 0 : 1; ret = ioctl( sd, FIONBIO, ( char * ) &mode ); hb_socketSetOsError( ret != -1 ? 0 : HB_SOCK_GETERROR() ); if( ret == 0 ) ret = 1; #else int TODO; HB_SYMBOL_UNUSED( sd ); HB_SYMBOL_UNUSED( fBlocking ); hb_socketSetRawError( HB_SOCKET_ERR_NOSUPPORT ); ret = -1; #endif return ret; } int hb_socketSetReuseAddr( HB_SOCKET sd, BOOL fReuse ) { /* it allows to reuse port immediately without timeout used to * clean all pending connections addressed to previous port owner */ int val = fReuse ? 1 : 0; return setsockopt( sd, SOL_SOCKET, SO_REUSEADDR, ( const char * ) &val, sizeof( val ) ); } int hb_socketSetKeepAlive( HB_SOCKET sd, BOOL fKeepAlive ) { int val = fKeepAlive ? 1 : 0; return setsockopt( sd, SOL_SOCKET, SO_KEEPALIVE, ( const char * ) &val, sizeof( val ) ); } int hb_socketSetBroadcast( HB_SOCKET sd, BOOL fBroadcast ) { int val = fBroadcast ? 1 : 0; return setsockopt( sd, SOL_SOCKET, SO_BROADCAST, ( const char * ) &val, sizeof( val ) ); } int hb_socketSetSndBufSize( HB_SOCKET sd, int iSize ) { return setsockopt( sd, SOL_SOCKET, SO_SNDBUF, ( const char * ) &iSize, sizeof( iSize ) ); } int hb_socketSetRcvBufSize( HB_SOCKET sd, int iSize ) { return setsockopt( sd, SOL_SOCKET, SO_RCVBUF, ( const char * ) &iSize, sizeof( iSize ) ); } int hb_socketGetSndBufSize( HB_SOCKET sd, int * piSize ) { socklen_t len = sizeof( * piSize ); return getsockopt( sd, SOL_SOCKET, SO_SNDBUF, ( char * ) piSize, &len ); } int hb_socketGetRcvBufSize( HB_SOCKET sd, int * piSize ) { socklen_t len = sizeof( * piSize ); return getsockopt( sd, SOL_SOCKET, SO_RCVBUF, ( char * ) piSize, &len ); } int hb_socketSetMulticast( HB_SOCKET sd, int af, const char * szAddr ) { if( af == HB_SOCKET_AF_INET ) { #if defined( IP_ADD_MEMBERSHIP ) && defined( IPPROTO_IP ) struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = inet_addr( szAddr ); mreq.imr_interface.s_addr = htonl( INADDR_ANY ); return setsockopt( sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, ( const char * ) &mreq, sizeof( mreq ) ); #else int TODO; #endif } #if defined( HB_HAS_INET6 ) else if( af == HB_SOCKET_AF_INET6 ) { #if defined( HB_HAS_INET_PTON ) struct ipv6_mreq mreq; int err = inet_pton( AF_INET6, szAddr, &mreq.ipv6mr_multiaddr ); if( err > 0 ) { mreq.ipv6mr_interface = 0; return setsockopt( sd, IPPROTO_IPV6, IPV6_JOIN_GROUP, ( const char * ) &mreq, sizeof( mreq ) ); } else if( err == 0 ) hb_socketSetRawError( HB_SOCKET_ERR_WRONGADDR ); else hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); return -1; #else int TODO; #endif } #endif hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); return -1; } int hb_socketSelectRead( HB_SOCKET sd, HB_LONG timeout ) { int ret; hb_vmUnlock(); ret = hb_socketSelectRD( sd, timeout ); hb_vmLock(); return ret; } int hb_socketSelectWrite( HB_SOCKET sd, HB_LONG timeout ) { int ret; hb_vmUnlock(); ret = hb_socketSelectWR( sd, timeout ); hb_vmLock(); return ret; } int hb_socketSelectWriteEx( HB_SOCKET sd, HB_LONG timeout ) { int ret; hb_vmUnlock(); ret = hb_socketSelectWRE( sd, timeout ); hb_vmLock(); return ret; } int hb_socketSelect( PHB_ITEM pArrayRD, BOOL fSetRD, PHB_ITEM pArrayWR, BOOL fSetWR, PHB_ITEM pArrayEX, BOOL fSetEX, HB_LONG timeout, HB_SOCKET_FUNC pFunc ) { HB_SOCKET maxsd, sd; int i, ret; ULONG ulLen, ulPos, ul; PHB_ITEM pItemSets[ 3 ]; BOOL pSet[ 3 ]; fd_set fds[ 3 ], *pfds[ 3 ]; struct timeval tv, *ptv; pItemSets[ 0 ] = pArrayRD; pItemSets[ 1 ] = pArrayWR; pItemSets[ 2 ] = pArrayEX; pSet[ 0 ] = fSetRD; pSet[ 1 ] = fSetWR; pSet[ 2 ] = fSetEX; maxsd = 0; for( i = 0; i < 3; i++ ) { ret = 0; ulLen = pItemSets[ i ] ? hb_arrayLen( pItemSets[ i ] ) : 0; if( ulLen > 0 ) { FD_ZERO( &fds[ i ] ); for( ul = 1; ul <= ulLen; ul++ ) { if( pFunc ) sd = pFunc( hb_arrayGetItemPtr( pItemSets[ i ], ul ) ); else { HB_TYPE type = hb_arrayGetType( pItemSets[ i ], ul ); if( type & HB_IT_NUMERIC ) sd = ( HB_SOCKET ) hb_arrayGetNInt( pItemSets[ i ], ul ); else if( type & HB_IT_POINTER ) sd = ( HB_SOCKET ) ( HB_PTRDIFF ) hb_arrayGetPtr( pItemSets[ i ], ul ); else sd = HB_NO_SOCKET; } if( sd != HB_NO_SOCKET ) { if( maxsd < sd ) maxsd = sd; FD_SET( sd, &fds[ i ] ); ret = 1; } } } pfds[ i ] = ret ? &fds[ i ] : NULL; } if( timeout >= 0 ) { tv.tv_sec = ( long ) ( timeout / 1000 ); tv.tv_usec = ( timeout % 1000 ) * 1000; ptv = &tv; } else ptv = NULL; ret = select( ( int ) ( maxsd + 1 ), pfds[ 0 ], pfds[ 1 ], pfds[ 2 ], ptv ); for( i = 0; i < 3; i++ ) { if( pfds[ i ] && pSet[ i ] ) { ulPos = 0; if( ret > 0 ) { ulLen = hb_arrayLen( pItemSets[ i ] ); for( ul = 1; ul <= ulLen; ul++ ) { if( pFunc ) sd = pFunc( hb_arrayGetItemPtr( pItemSets[ i ], ul ) ); else { HB_TYPE type = hb_arrayGetType( pItemSets[ i ], ul ); if( type & HB_IT_NUMERIC ) sd = ( HB_SOCKET ) hb_arrayGetNInt( pItemSets[ i ], ul ); else if( type & HB_IT_POINTER ) sd = ( HB_SOCKET ) ( HB_PTRDIFF ) hb_arrayGetPtr( pItemSets[ i ], ul ); else sd = HB_NO_SOCKET; } if( sd != HB_NO_SOCKET && FD_ISSET( sd, pfds[ i ] ) ) { if( ++ulPos != ul ) { hb_itemCopy( hb_arrayGetItemPtr( pItemSets[ i ], ulPos ), hb_arrayGetItemPtr( pItemSets[ i ], ul ) ); } } } } hb_arraySize( pItemSets[ i ], ulPos ); } } return ret; } /* DNS functions */ char * hb_socketResolveAddr( const char * szAddr, int af ) { char * szResult = NULL; BOOL fTrans = FALSE; if( af == HB_SOCKET_PF_INET ) { struct in_addr sin; #if defined( HB_HAS_INET_PTON ) fTrans = inet_pton( AF_INET, szAddr, &sin ) > 0; #elif defined( HB_HAS_INET_ATON ) fTrans = inet_aton( szAddr, &sin ) != 0; #else sin.s_addr = inet_addr( szAddr ); fTrans = sin.s_addr != INADDR_NONE || strcmp( "255.255.255.255", szAddr ) == 0; /* dirty hack */ #endif #if !defined( HB_HAS_ADDRINFO ) if( !fTrans ) { struct hostent * he; hb_vmUnlock(); he = gethostbyname( szAddr ); if( he && he->h_addr_list[ 0 ] ) { sin.s_addr = ( ( struct in_addr * ) he->h_addr_list[ 0 ] )->s_addr; fTrans = TRUE; } hb_vmLock(); } #endif if( fTrans ) { # if defined( HB_HAS_INET_NTOP ) char buf[ INET_ADDRSTRLEN ]; szAddr = inet_ntop( AF_INET, &sin, buf, sizeof( buf ) ); # elif defined( HB_IS_INET_NTOA_MT_SAFE ) szAddr = inet_ntoa( sin ); # else char buf[ INET_ADDRSTRLEN ]; szAddr = hb_inet_ntoa( &sin, buf ); # endif szResult = hb_strdup( szAddr ); } } #if defined( HB_HAS_INET6 ) else if( af == HB_SOCKET_PF_INET6 ) { #if defined( HB_HAS_INET_PTON ) struct in6_addr sin; fTrans = inet_pton( AF_INET6, szAddr, &sin ) > 0; #else int TODO; fTrans = FALSE; #endif } #endif if( !fTrans ) { #if defined( HB_HAS_ADDRINFO ) struct addrinfo hints, *res = NULL; hb_vmUnlock(); # if defined( HB_SOCKET_TRANSLATE_DOMAIN ) af = hb_socketTransDomain( af, NULL ); # endif memset( &hints, 0, sizeof( hints ) ); hints.ai_family = af; if( getaddrinfo( szAddr, NULL, &hints, &res ) == 0 ) { szResult = hb_socketAddrGetName( res->ai_addr, res->ai_addrlen ); freeaddrinfo( res ); } hb_vmLock(); #endif } return szResult; } PHB_ITEM hb_socketGetHosts( const char * szAddr, int af ) { PHB_ITEM pItem = NULL; #ifdef HB_HAS_ADDRINFO struct addrinfo hints, *res = NULL, *ai; int iResult; hb_vmUnlock(); #if defined( HB_SOCKET_TRANSLATE_DOMAIN ) af = hb_socketTransDomain( af, NULL ); #endif memset( &hints, 0, sizeof( hints ) ); hints.ai_family = af; iResult = getaddrinfo( szAddr, NULL, &hints, &res ); hb_vmLock(); if( iResult == 0 ) { int iCount = 0, i; ai = res; while( ai ) { ++iCount; ai = ai->ai_next; } if( iCount ) { pItem = hb_itemArrayNew( iCount ); ai = res; iCount = 0; while( ai ) { char * szResult = hb_socketAddrGetName( res->ai_addr, res->ai_addrlen ); if( szResult ) { for( i = 1; i <= iCount; ++i ) { if( strcmp( hb_arrayGetCPtr( pItem, i ), szResult ) == 0 ) { hb_xfree( szResult ); szResult = NULL; break; } } if( szResult ) { ++iCount; if( !hb_arraySetCLPtr( pItem, iCount, szResult, strlen( szResult ) ) ) hb_xfree( szResult ); } } ai = ai->ai_next; } hb_arraySize( pItem, iCount ); } freeaddrinfo( res ); } #else if( af == HB_SOCKET_PF_INET ) { struct hostent * he = NULL; int iCount = 0; hb_vmUnlock(); /* gethostbyname() in Windows and OS2 does not accept direct IP * addresses */ #if defined( HB_OS_WIN ) || defined( HB_OS_OS2 ) { ULONG addr = inet_addr( szAddr ); if( addr != INADDR_NONE || strcmp( "255.255.255.255", szAddr ) == 0 ) he = gethostbyaddr( ( const char * ) &addr, sizeof( addr ), AF_INET ); } #endif if( he == NULL ) he = gethostbyname( szAddr ); hb_vmLock(); if( he ) { while( he->h_addr_list[ iCount ] ) ++iCount; } if( iCount > 0 ) { pItem = hb_itemArrayNew( iCount ); do { struct in_addr * sin = ( struct in_addr * ) he->h_addr_list[ iCount - 1 ]; # if defined( HB_HAS_INET_NTOP ) char buf[ INET_ADDRSTRLEN ]; szAddr = inet_ntop( AF_INET, sin, buf, sizeof( buf ) ); # elif defined( HB_IS_INET_NTOA_MT_SAFE ) szAddr = inet_ntoa( *sin ); # else char buf[ INET_ADDRSTRLEN ]; szAddr = hb_inet_ntoa( sin, buf ); # endif hb_arraySetC( pItem, iCount, szAddr ); } while( --iCount ); } } #if defined( HB_HAS_INET6 ) else if( af == HB_SOCKET_PF_INET6 ) { int TODO; } #endif #endif return pItem; } PHB_ITEM hb_socketGetAliases( const char * szAddr, int af ) { /* TODO: implement it */ HB_SYMBOL_UNUSED( szAddr ); HB_SYMBOL_UNUSED( af ); hb_socketSetRawError( HB_SOCKET_ERR_AFNOSUPPORT ); return NULL; } #endif /* !HB_SOCKET_OFF */