* doc/dirstruc.txt
* Updated to reflect current state. [Chen Kedem]
* contrib/examples/pp/hbppcore.c
* contrib/examples/pp/pp.c
* contrib/hbct/disk.c
* contrib/hbct/files.c
* contrib/hbnf/getenvrn.c
* contrib/hbw32/tprinter.c
* contrib/hbziparch/hbxdirec.c
* contrib/hbziparch/hbziparc.c
* contrib/rddads/ads1.c
* contrib/rddads/adsfunc.c
* doc/en/terminal.txt
* include/hb_io.h
* include/hbapifs.h
* include/hbapirdd.h
* include/hbdefs.h
* include/hbsetup.h
* include/hbwince.h
* source/common/hbfsapi.c
* source/compiler/gencobj.c
* source/compiler/hbcomp.c
* source/compiler/hbusage.c
* source/debug/dbgentry.c
* source/main/harbour.c
* source/pp/hbpp.c
* source/pp/ppcore.c
* source/rdd/dbcmd.c
* source/rdd/dbf1.c
* source/rdd/delim1.c
* source/rdd/sdf1.c
* source/rdd/usrrdd/usrrdd.c
* source/rdd/wacore.c
* source/rdd/wafunc.c
* source/rdd/workarea.c
* source/rtl/console.c
* source/rtl/copyfile.c
* source/rtl/defpath.c
* source/rtl/direct.c
* source/rtl/disksphb.c
* source/rtl/file.c
* source/rtl/filesys.c
* source/rtl/fssize.c
* source/rtl/fstemp.c
* source/rtl/gtos2/gtos2.c
* source/rtl/gtpca/gtpca.c
* source/rtl/gtstd/gtstd.c
* source/rtl/gttrm/gttrm.c
* source/rtl/hbffind.c
* source/rtl/hbinet.c
* source/rtl/memofile.c
* source/rtl/philes.c
* source/rtl/seconds.c
* source/rtl/set.c
* source/vm/hvm.c
* source/vm/main.c
* Changed some macros to be in the HB_ namespace, to be
possibly shorter, more unified and clearer.
OS_UNIX_COMPATIBLE -> HB_OS_UNIX_COMPATIBLE
OS_PATH_LIST_SEPARATOR -> HB_OS_PATH_LIST_SEP_CHR
OS_PATH_DELIMITER -> HB_OS_PATH_DELIM_CHR
OS_PATH_DELIMITER_STRING -> HB_OS_PATH_DELIM_STR
OS_PATH_DELIMITER_LIST -> HB_OS_PATH_DELIM_LIST
OS_FILE_MASK -> HB_OS_ALLFILE_MASK
OS_DRIVE_DELIMITER -> HB_OS_DRIVE_DELIM_CHR
OS_HAS_DRIVE_LETTER -> HB_OS_HAS_DRIVE_LETTER
OS_OPT_DELIMITER_LIST -> HB_OS_OPT_DELIM_LIST
OS_EOL_LEN -> HB_OS_EOL_LEN
HARBOUR_GCC_OS2 -> HB_OS_OS2_GCC
HARBOUR_START_PROCEDURE -> HB_START_PROCEDURE
HARBOUR_MAIN_STD -> HB_MAIN_STD
HARBOUR_MAIN_WIN -> HB_MAIN_WIN
HARBOUR_MAX_RDD_DRIVERNAME_LENGTH -> HB_RDD_MAX_DRIVERNAME_LEN
HARBOUR_MAX_RDD_ALIAS_LENGTH -> HB_RDD_MAX_ALIAS_LEN
HARBOUR_MAX_RDD_AREA_NUM -> HB_RDD_MAX_AREA_NUM
; INCOMPATIBLE change, please update your sources, a simple
case-sensitive search and replace on .c/.cpp/.h/.hpp files
will be enough for most sources.
2120 lines
50 KiB
C
2120 lines
50 KiB
C
/*
|
|
* $Id$
|
|
*/
|
|
|
|
/*
|
|
* xHarbour Project source code:
|
|
* The internet protocol / TCP support
|
|
*
|
|
* Copyright 2002 Giancarlo Niccolai [gian@niccolai.ws]
|
|
* Ron Pinkas [Ron@RonPinkas.com]
|
|
* Marcelo Lombardo [marcelo.lombardo@newage-software.com.br]
|
|
* www - http://www.xharbour.org
|
|
*
|
|
* Copyright 2007 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
|
|
* updated and ported to Harbour
|
|
* www - http://www.harbour-project.org
|
|
*
|
|
* Copyright 2008 Miguel Angel marchuet <miguelangel@marchuet.net>
|
|
* added dinamic system buffer
|
|
* 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 "hbapi.h"
|
|
#include "hbapiitm.h"
|
|
#include "hbapierr.h"
|
|
|
|
/* Compile in Unix mode under Cygwin */
|
|
#ifdef HB_OS_UNIX_COMPATIBLE
|
|
#undef HB_OS_WIN_32
|
|
#endif
|
|
|
|
/* HB_INET_H_ */
|
|
#if defined( HB_OS_DOS )
|
|
|
|
#ifndef HB_NO_DEFAULT_INET
|
|
#define HB_NO_DEFAULT_INET
|
|
#endif
|
|
|
|
#else
|
|
|
|
#include <string.h>
|
|
|
|
#if defined( HB_OS_WIN_32 )
|
|
#define _WINSOCKAPI_ /* Prevents inclusion of Winsock.h in Windows.h */
|
|
#define HB_SOCKET_T SOCKET
|
|
#include <winsock2.h>
|
|
#include <windows.h>
|
|
|
|
#define HB_INET_CLOSE( x ) closesocket( x )
|
|
#else
|
|
|
|
#if defined( HB_OS_HPUX )
|
|
#define _XOPEN_SOURCE_EXTENDED
|
|
#endif
|
|
|
|
#define HB_SOCKET_T int
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netdb.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
|
|
#if defined(__WATCOMC__)
|
|
#define h_errno errno
|
|
#else
|
|
extern int h_errno;
|
|
#endif
|
|
#define HB_INET_CLOSE( x ) close( x )
|
|
#include <errno.h>
|
|
#endif
|
|
|
|
typedef struct _HB_SOCKET_STRUCT
|
|
{
|
|
HB_SOCKET_T com;
|
|
char *errorDesc;
|
|
int errorCode;
|
|
struct sockaddr_in remote;
|
|
LONG count;
|
|
int timeout;
|
|
int timelimit;
|
|
PHB_ITEM caPeriodic;
|
|
} HB_SOCKET_STRUCT;
|
|
|
|
#define HB_PARSOCKET( n ) ( ( HB_SOCKET_STRUCT * ) hb_parptrGC( hb_inetSocketFinalize, n ) )
|
|
|
|
#define HB_SOCKET_ZERO_ERROR( s ) \
|
|
do { s->errorCode = 0; s->errorDesc = ""; } while( 0 )
|
|
|
|
#if defined( HB_OS_WIN_32 )
|
|
#define HB_SOCKET_SET_ERROR( s ) \
|
|
do { \
|
|
s->errorCode = WSAGetLastError(); \
|
|
s->errorDesc = strerror( s->errorCode );\
|
|
WSASetLastError( 0 ); \
|
|
} while( 0 )
|
|
|
|
#else
|
|
#define HB_SOCKET_SET_ERROR( s ) \
|
|
do { s->errorCode = errno; s->errorDesc = strerror( errno ); } while( 0 )
|
|
#endif
|
|
|
|
#define HB_SOCKET_SET_ERROR1( s, code ) \
|
|
do { s->errorCode = code; s->errorDesc = strerror( code ); } while( 0 )
|
|
#define HB_SOCKET_SET_ERROR2( s, code, desc ) \
|
|
do { s->errorCode = code; s->errorDesc = desc; } while( 0 )
|
|
|
|
#define HB_SOCKET_INIT( s, p ) \
|
|
do { \
|
|
s = ( HB_SOCKET_STRUCT *) hb_gcAlloc( sizeof( HB_SOCKET_STRUCT ), hb_inetSocketFinalize );\
|
|
memset( s, '\0', sizeof( HB_SOCKET_STRUCT ) );\
|
|
s->com = ( HB_SOCKET_T ) -1;\
|
|
s->timeout = -1;\
|
|
s->timelimit = -1;\
|
|
s->errorDesc = "";\
|
|
p = hb_itemPutPtrGC( p, s );\
|
|
} while( 0 )
|
|
|
|
#ifndef MSG_NOSIGNAL
|
|
#define MSG_NOSIGNAL 0
|
|
#endif
|
|
|
|
#ifndef MSG_DONTWAIT
|
|
/* #define MSG_DONTWAIT 0x80 */
|
|
#define MSG_DONTWAIT 0
|
|
#endif
|
|
|
|
#ifndef MSG_WAITALL
|
|
#define MSG_WAITALL 0
|
|
#endif
|
|
|
|
#endif
|
|
/* HB_INET_H_ */
|
|
|
|
|
|
#if !defined( HB_NO_DEFAULT_INET )
|
|
|
|
#if !defined( HB_WINCE )
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#endif
|
|
|
|
#if defined( HB_OS_UNIX ) || defined( HB_OS_UNIX_COMPATIBLE ) || defined( HB_OS_BSD ) || defined(HB_OS_OS2)
|
|
#include <sys/time.h>
|
|
#endif
|
|
|
|
#if defined(HB_OS_OS2)
|
|
#include <sys/socket.h>
|
|
#include <sys/select.h>
|
|
#include <sys/ioctl.h>
|
|
#endif
|
|
|
|
#if defined( HB_OS_OS2 ) || defined( HB_OS_WIN_32 )
|
|
/* NET_SIZE_T exists because of shortsightedness on the POSIX committee. BSD
|
|
* systems used "int *" as the parameter to accept(), getsockname(),
|
|
* getpeername() et al. Consequently many unixes took an int * for that
|
|
* parameter. The POSIX committee decided that "int" was just too generic and
|
|
* had to be replaced with size_t almost everywhere. There's no problem with
|
|
* that when you're passing by value. But when you're passing by reference
|
|
* this creates a gross source incompatibility with existing programs. On
|
|
* 32-bit architectures it creates only a warning. On 64-bit architectures it
|
|
* creates broken code -- because "int *" is a pointer to a 64-bit quantity and
|
|
* "size_t *" is frequently a pointer to a 32-bit quantity.
|
|
*
|
|
* Some Unixes adopted "size_t *" for the sake of POSIX compliance. Others
|
|
* ignored it because it was such a broken interface. Chaos ensued. POSIX
|
|
* finally woke up and decided that it was wrong and created a new type
|
|
* socklen_t. The only useful value for socklen_t is int, and that's how
|
|
* everyone who has a clue implements it. It is almost always the case that
|
|
* NET_SIZE_T should be defined to be an int, unless the system being compiled
|
|
* for was created in the window of POSIX madness.
|
|
*/
|
|
#define socklen_t int
|
|
#endif
|
|
|
|
#ifdef HB_OS_LINUX
|
|
#include <signal.h>
|
|
#define HB_INET_LINUX_INTERRUPT SIGUSR1+90
|
|
static void hb_inetLinuxSigusrHandle( int sig )
|
|
{
|
|
/* nothing to do */
|
|
HB_SYMBOL_UNUSED( sig );
|
|
}
|
|
#endif
|
|
|
|
/* JC1: we need it volatile to be minimally thread safe. */
|
|
static volatile int s_iSessions = 0;
|
|
|
|
static BOOL hb_inetIsOpen( HB_SOCKET_STRUCT *Socket )
|
|
{
|
|
if( Socket->com == ( HB_SOCKET_T ) -1 )
|
|
{
|
|
HB_SOCKET_SET_ERROR2( Socket, -4, "Closed socket" );
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/* Useful utility function to have a timeout; */
|
|
|
|
static int hb_selectReadSocket( HB_SOCKET_STRUCT *Socket )
|
|
{
|
|
fd_set set;
|
|
struct timeval tv;
|
|
|
|
FD_ZERO( &set );
|
|
FD_SET(Socket->com, &set);
|
|
|
|
if( Socket->timeout == -1 )
|
|
{
|
|
if( select( Socket->com + 1, &set, NULL, NULL, NULL ) < 0 )
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
tv.tv_sec = Socket->timeout/ 1000;
|
|
tv.tv_usec = (Socket->timeout % 1000) * 1000;
|
|
if( select( Socket->com + 1, &set, NULL, NULL, &tv ) < 0 )
|
|
return 0;
|
|
}
|
|
|
|
return FD_ISSET( Socket->com, &set );
|
|
}
|
|
|
|
static int hb_selectWriteSocket( HB_SOCKET_STRUCT *Socket )
|
|
{
|
|
fd_set set;
|
|
struct timeval tv;
|
|
|
|
FD_ZERO( &set );
|
|
FD_SET(Socket->com, &set);
|
|
|
|
if( Socket->timeout == -1 )
|
|
{
|
|
if( select( Socket->com + 1, NULL, &set, NULL, NULL ) < 0 )
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
tv.tv_sec = Socket->timeout/ 1000;
|
|
tv.tv_usec = (Socket->timeout % 1000) * 1000;
|
|
if( select( Socket->com + 1, NULL, &set, NULL, &tv ) < 0 )
|
|
return 0;
|
|
}
|
|
|
|
return FD_ISSET( Socket->com, &set );
|
|
}
|
|
|
|
#if defined(HB_OS_WIN_32)
|
|
static int hb_selectWriteExceptSocket( HB_SOCKET_STRUCT *Socket )
|
|
{
|
|
fd_set set, eset;
|
|
struct timeval tv;
|
|
|
|
FD_ZERO( &set );
|
|
FD_SET(Socket->com, &set);
|
|
FD_ZERO( &eset );
|
|
FD_SET(Socket->com, &eset);
|
|
|
|
if( Socket->timeout == -1 )
|
|
{
|
|
if( select( Socket->com + 1, NULL, &set, &eset, NULL ) < 0 )
|
|
return 2;
|
|
}
|
|
else
|
|
{
|
|
tv.tv_sec = Socket->timeout/ 1000;
|
|
tv.tv_usec = (Socket->timeout % 1000) * 1000;
|
|
if( select(Socket->com + 1, NULL, &set, &eset, &tv) < 0 )
|
|
return 2;
|
|
}
|
|
|
|
if( FD_ISSET( Socket->com, &eset) )
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
if( FD_ISSET( Socket->com, &set ) )
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/*** Utilty to access host DNS */
|
|
static struct hostent * hb_getHosts( char * name, HB_SOCKET_STRUCT *Socket )
|
|
{
|
|
struct hostent *Host = NULL;
|
|
|
|
/* TOFIX: make it MT safe */
|
|
|
|
/* let's see if name is an IP address; not necessary on linux */
|
|
#if defined(HB_OS_WIN_32) || defined(HB_OS_OS2)
|
|
ULONG ulAddr;
|
|
|
|
ulAddr = inet_addr( name );
|
|
if( ulAddr == INADDR_NONE )
|
|
{
|
|
if( strcmp( "255.255.255.255", name ) == 0 )
|
|
{
|
|
Host = gethostbyaddr( (const char*) &ulAddr, sizeof( ulAddr ), AF_INET );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Host = gethostbyaddr( (const char*) &ulAddr, sizeof( ulAddr ), AF_INET );
|
|
}
|
|
#endif
|
|
|
|
if( Host == NULL )
|
|
{
|
|
Host = gethostbyname( name );
|
|
}
|
|
|
|
if( Host == NULL && Socket != NULL )
|
|
{
|
|
#if defined(HB_OS_WIN_32)
|
|
HB_SOCKET_SET_ERROR2( Socket, WSAGetLastError() , "Generic error in gethostbyname()" );
|
|
WSASetLastError( 0 );
|
|
#elif defined(HB_OS_OS2) || defined(HB_OS_HPUX) || defined(__WATCOMC__)
|
|
HB_SOCKET_SET_ERROR2( Socket, h_errno, "Generic error in gethostbyname()" );
|
|
#else
|
|
HB_SOCKET_SET_ERROR2( Socket, h_errno, (char *) hstrerror( h_errno ) );
|
|
#endif
|
|
}
|
|
return Host;
|
|
}
|
|
|
|
|
|
/*** Setup the non-blocking method **/
|
|
|
|
static void hb_socketSetNonBlocking( HB_SOCKET_STRUCT *Socket )
|
|
{
|
|
#ifdef HB_OS_WIN_32
|
|
ULONG mode = 1;
|
|
ioctlsocket( Socket->com, FIONBIO, &mode );
|
|
|
|
#else
|
|
int flags = fcntl( Socket->com, F_GETFL, 0 );
|
|
if( flags != -1 )
|
|
{
|
|
flags |= O_NONBLOCK;
|
|
fcntl( Socket->com, F_SETFL, (LONG) flags );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/*** Setup the blocking method **/
|
|
|
|
static void hb_socketSetBlocking( HB_SOCKET_STRUCT *Socket )
|
|
{
|
|
#ifdef HB_OS_WIN_32
|
|
ULONG mode = 0;
|
|
ioctlsocket( Socket->com, FIONBIO, &mode );
|
|
#else
|
|
int flags = fcntl( Socket->com, F_GETFL, 0 );
|
|
if( flags != -1 )
|
|
{
|
|
flags &= ~O_NONBLOCK;
|
|
fcntl( Socket->com, F_SETFL, ( long ) flags );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*** Utility to connect to a defined remote address ***/
|
|
|
|
static int hb_socketConnect( HB_SOCKET_STRUCT *Socket )
|
|
{
|
|
int iErr1;
|
|
#if ! defined(HB_OS_WIN_32)
|
|
int iErrval;
|
|
socklen_t iErrvalLen;
|
|
#endif
|
|
int iOpt = 1;
|
|
|
|
setsockopt( Socket->com, SOL_SOCKET, SO_KEEPALIVE, (const char *) &iOpt , sizeof( iOpt ));
|
|
|
|
/* we'll be using a nonblocking function */
|
|
hb_socketSetNonBlocking( Socket );
|
|
|
|
iErr1 = connect( Socket->com, (struct sockaddr *) &Socket->remote, sizeof(Socket->remote) );
|
|
if( iErr1 != 0 )
|
|
{
|
|
#if defined(HB_OS_WIN_32)
|
|
if( WSAGetLastError() != WSAEWOULDBLOCK )
|
|
#else
|
|
if( errno != EINPROGRESS )
|
|
#endif
|
|
{
|
|
HB_SOCKET_SET_ERROR( Socket );
|
|
}
|
|
else
|
|
{
|
|
/* Now we wait for socket connection or timeout */
|
|
|
|
#if defined(HB_OS_WIN_32)
|
|
iErr1 = hb_selectWriteExceptSocket( Socket );
|
|
if( iErr1 == 2 )
|
|
{
|
|
HB_SOCKET_SET_ERROR2( Socket, 2, "Connection failed" );
|
|
}
|
|
else if( iErr1 == 1 )
|
|
{
|
|
/* success */
|
|
}
|
|
#else
|
|
if( hb_selectWriteSocket( Socket ) )
|
|
{
|
|
/* Connection has been completed with a failure or a success */
|
|
iErrvalLen = sizeof( iErrval );
|
|
iErr1 = getsockopt( Socket->com,
|
|
SOL_SOCKET,
|
|
SO_ERROR,
|
|
(void *) &iErrval,
|
|
&iErrvalLen
|
|
);
|
|
|
|
if( iErr1 )
|
|
{
|
|
HB_SOCKET_SET_ERROR1( Socket, iErr1 );
|
|
}
|
|
else if( iErrval )
|
|
{
|
|
HB_SOCKET_SET_ERROR1( Socket, iErrval );
|
|
}
|
|
/* Success! */
|
|
}
|
|
#endif
|
|
/* Timed out */
|
|
else
|
|
{
|
|
HB_SOCKET_SET_ERROR2( Socket, -1, "Timeout" );
|
|
}
|
|
}
|
|
}
|
|
|
|
hb_socketSetBlocking( Socket );
|
|
|
|
return Socket->errorCode == 0;
|
|
}
|
|
|
|
|
|
static HB_GARBAGE_FUNC( hb_inetSocketFinalize )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = ( HB_SOCKET_STRUCT *) Cargo;
|
|
|
|
if( Socket->com != ( HB_SOCKET_T ) -1 )
|
|
{
|
|
#if defined( HB_OS_WIN_32 )
|
|
shutdown( Socket->com, SD_BOTH );
|
|
#elif defined(HB_OS_OS2)
|
|
shutdown( Socket->com, SO_RCV_SHUTDOWN + SO_SND_SHUTDOWN );
|
|
#elif !defined(__WATCOMC__)
|
|
shutdown( Socket->com, SHUT_RDWR );
|
|
#endif
|
|
|
|
HB_INET_CLOSE( Socket->com );
|
|
Socket->com = ( HB_SOCKET_T ) -1;
|
|
}
|
|
|
|
if( Socket->caPeriodic != NULL )
|
|
{
|
|
hb_itemRelease( Socket->caPeriodic );
|
|
Socket->caPeriodic = NULL;
|
|
}
|
|
}
|
|
|
|
/*****************************************************
|
|
* Socket Initialization
|
|
***/
|
|
|
|
HB_FUNC( HB_INETINIT )
|
|
{
|
|
if( s_iSessions )
|
|
{
|
|
s_iSessions++;
|
|
}
|
|
else
|
|
{
|
|
#if defined(HB_OS_WIN_32)
|
|
#define HB_MKWORD( l, h ) ((WORD)(((BYTE)(l)) | (((WORD)((BYTE)(h))) << 8)))
|
|
WSADATA wsadata;
|
|
WSAStartup( HB_MKWORD(1,1), &wsadata );
|
|
#elif defined( HB_OS_LINUX )
|
|
signal( HB_INET_LINUX_INTERRUPT, hb_inetLinuxSigusrHandle );
|
|
#endif
|
|
s_iSessions = 1;
|
|
}
|
|
}
|
|
|
|
HB_FUNC( HB_INETCLEANUP )
|
|
{
|
|
if( --s_iSessions == 0 )
|
|
{
|
|
#if defined(HB_OS_WIN_32)
|
|
WSACleanup();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*****************************************************
|
|
* Socket Creation and destruction
|
|
***/
|
|
|
|
HB_FUNC( HB_INETCREATE )
|
|
{
|
|
PHB_ITEM pSocket = NULL;
|
|
HB_SOCKET_STRUCT *Socket;
|
|
HB_SOCKET_INIT( Socket, pSocket );
|
|
|
|
if( ISNUM( 1 ) )
|
|
Socket->timeout = hb_parni(1);
|
|
hb_itemReturnRelease( pSocket );
|
|
}
|
|
|
|
HB_FUNC( HB_INETCLOSE )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket == NULL )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
else if( Socket->com != ( HB_SOCKET_T ) -1 )
|
|
{
|
|
#if defined( HB_OS_WIN_32 )
|
|
shutdown( Socket->com, SD_BOTH );
|
|
#elif defined(HB_OS_OS2)
|
|
shutdown( Socket->com, SO_RCV_SHUTDOWN + SO_SND_SHUTDOWN );
|
|
#elif !defined(__WATCOMC__)
|
|
shutdown( Socket->com, SHUT_RDWR );
|
|
#endif
|
|
|
|
hb_retni( HB_INET_CLOSE( Socket->com ) );
|
|
Socket->com = ( HB_SOCKET_T ) -1;
|
|
|
|
#ifdef HB_OS_LINUX
|
|
kill( 0, HB_INET_LINUX_INTERRUPT );
|
|
#endif
|
|
}
|
|
else
|
|
hb_retni( -1 );
|
|
}
|
|
|
|
HB_FUNC( HB_INETFD )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket == NULL )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
else
|
|
{
|
|
hb_retnint( Socket->com );
|
|
if( ISLOG( 2 ) && hb_parl( 2 ) )
|
|
Socket->com = ( HB_SOCKET_T ) -1;
|
|
}
|
|
}
|
|
|
|
/************************************************
|
|
* Socket data access & management
|
|
***/
|
|
|
|
HB_FUNC( HB_INETSTATUS )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket == NULL )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
else
|
|
/* TODO: hb_retni( Socket->status ); */
|
|
hb_retni( Socket->com == ( HB_SOCKET_T ) -1 ? -1 : 1 );
|
|
}
|
|
|
|
/* Prepared, but still not used; being in wait for comments
|
|
HB_FUNC( HB_INETSTATUSDESC )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket == NULL )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
|
|
switch( Socket->status )
|
|
{
|
|
case 0: hb_retc( "Connection not opened" ); return;
|
|
case 1: hb_retc( "Connection alive" ); return;
|
|
case 2: hb_retc( "Last operation error" ); return;
|
|
case 3: hb_retc( "Last operation timeout" ); return;
|
|
}
|
|
}
|
|
*/
|
|
|
|
HB_FUNC( HB_INETERRORCODE )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket == NULL )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
else
|
|
hb_retni( Socket->errorCode );
|
|
}
|
|
|
|
HB_FUNC( HB_INETERRORDESC )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket == NULL )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
|
|
hb_retc( Socket->errorDesc );
|
|
}
|
|
|
|
HB_FUNC( HB_INETCLEARERROR )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket == NULL )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
else
|
|
HB_SOCKET_ZERO_ERROR( Socket );
|
|
}
|
|
|
|
|
|
HB_FUNC( HB_INETCOUNT )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket == NULL )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
else
|
|
hb_retni( Socket->count );
|
|
}
|
|
|
|
HB_FUNC( HB_INETADDRESS )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
char *addr;
|
|
|
|
if( Socket == NULL )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
else
|
|
{
|
|
addr = inet_ntoa( Socket->remote.sin_addr );
|
|
hb_retc( addr );
|
|
}
|
|
}
|
|
|
|
HB_FUNC( HB_INETPORT )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket == NULL )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
else
|
|
hb_retni( ntohs( Socket->remote.sin_port ) );
|
|
}
|
|
|
|
|
|
HB_FUNC( HB_INETTIMEOUT )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket != NULL )
|
|
{
|
|
hb_retni( Socket->timeout );
|
|
if( ISNUM( 2 ) )
|
|
Socket->timeout = hb_parni( 2 );
|
|
}
|
|
else
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
}
|
|
|
|
HB_FUNC( HB_INETCLEARTIMEOUT )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket == NULL )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
else
|
|
Socket->timeout = -1;
|
|
}
|
|
|
|
HB_FUNC( HB_INETTIMELIMIT )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket == NULL )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
else
|
|
{
|
|
hb_retnl( Socket->timelimit );
|
|
if( ISNUM( 2 ) )
|
|
Socket->timelimit = hb_parnl(2);
|
|
}
|
|
}
|
|
|
|
HB_FUNC( HB_INETCLEARTIMELIMIT )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket == NULL )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
else
|
|
Socket->timelimit = -1;
|
|
}
|
|
|
|
HB_FUNC( HB_INETPERIODCALLBACK )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
PHB_ITEM pExec = hb_param( 2, HB_IT_ARRAY | HB_IT_BLOCK | HB_IT_SYMBOL );
|
|
|
|
if( Socket == NULL )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
else
|
|
{
|
|
if( Socket->caPeriodic )
|
|
hb_itemReturn( Socket->caPeriodic );
|
|
if( pExec )
|
|
{
|
|
if( Socket->caPeriodic )
|
|
hb_itemRelease( Socket->caPeriodic );
|
|
Socket->caPeriodic = hb_itemClone( pExec );
|
|
}
|
|
}
|
|
}
|
|
|
|
HB_FUNC( HB_INETCLEARPERIODCALLBACK )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket == NULL )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
else if( Socket->caPeriodic )
|
|
{
|
|
hb_itemRelease( Socket->caPeriodic );
|
|
Socket->caPeriodic = NULL;
|
|
}
|
|
}
|
|
|
|
HB_FUNC( HB_INETGETSNDBUFSIZE )
|
|
{
|
|
HB_SOCKET_STRUCT * Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket == NULL )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
else if( !hb_inetIsOpen( Socket ) )
|
|
hb_retni( -1 );
|
|
else
|
|
{
|
|
int value;
|
|
socklen_t len = sizeof( value );
|
|
#if defined( HB_OS_WIN_32 )
|
|
getsockopt( Socket->com, SOL_SOCKET, SO_SNDBUF, ( char * ) &value, &len );
|
|
#else
|
|
getsockopt( Socket->com, SOL_SOCKET, SO_SNDBUF, ( void * ) &value, &len );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
HB_FUNC( HB_INETGETRCVBUFSIZE )
|
|
{
|
|
HB_SOCKET_STRUCT * Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket == NULL )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
else if( !hb_inetIsOpen( Socket ) )
|
|
hb_retni( -1 );
|
|
else
|
|
{
|
|
int value;
|
|
socklen_t len = sizeof( value );
|
|
#if defined( HB_OS_WIN_32 )
|
|
getsockopt( Socket->com, SOL_SOCKET, SO_RCVBUF, ( char * ) &value, &len );
|
|
#else
|
|
getsockopt( Socket->com, SOL_SOCKET, SO_RCVBUF, ( void * ) &value, &len );
|
|
#endif
|
|
hb_retni( value );
|
|
}
|
|
}
|
|
|
|
HB_FUNC( HB_INETSETSNDBUFSIZE )
|
|
{
|
|
HB_SOCKET_STRUCT * Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket == NULL )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
else if( !hb_inetIsOpen( Socket ) )
|
|
hb_retni( -1 );
|
|
else
|
|
{
|
|
int value = hb_parni( 2 );
|
|
#if defined( HB_OS_WIN_32 )
|
|
setsockopt( Socket->com, SOL_SOCKET, SO_SNDBUF, ( char * ) &value, sizeof( value ) );
|
|
#else
|
|
setsockopt( Socket->com, SOL_SOCKET, SO_SNDBUF, ( void * ) &value, sizeof( value ) );
|
|
#endif
|
|
hb_retni( value );
|
|
}
|
|
}
|
|
|
|
HB_FUNC( HB_INETSETRCVBUFSIZE )
|
|
{
|
|
HB_SOCKET_STRUCT * Socket = HB_PARSOCKET( 1 );
|
|
|
|
if( Socket == NULL )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
else if( !hb_inetIsOpen( Socket ) )
|
|
hb_retni( -1 );
|
|
else
|
|
{
|
|
int value = hb_parni( 2 );
|
|
#if defined( HB_OS_WIN_32 )
|
|
setsockopt( Socket->com, SOL_SOCKET, SO_RCVBUF, ( char * ) &value, sizeof( value ) );
|
|
#else
|
|
setsockopt( Socket->com, SOL_SOCKET, SO_RCVBUF, ( void * ) &value, sizeof( value ) );
|
|
#endif
|
|
hb_retni( value );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************
|
|
* TCP receive and send functions
|
|
***/
|
|
|
|
static void s_inetRecvInternal( int iMode )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
PHB_ITEM pBuffer = hb_param( 2, HB_IT_STRING );
|
|
char *buffer;
|
|
int iLen, iMaxLen, iReceived;
|
|
int iTimeElapsed;
|
|
|
|
if( Socket == NULL || pBuffer == NULL || !ISBYREF( 2 ) )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
else if( !hb_inetIsOpen( Socket ) )
|
|
{
|
|
hb_retni( 0 );
|
|
return;
|
|
}
|
|
|
|
pBuffer = hb_itemUnShare( pBuffer );
|
|
buffer = hb_itemGetCPtr( pBuffer );
|
|
iLen = hb_itemGetCLen( pBuffer );
|
|
|
|
if( ISNIL( 3 ) )
|
|
{
|
|
iMaxLen = iLen;
|
|
}
|
|
else
|
|
{
|
|
iMaxLen = hb_parni( 3 );
|
|
if( iLen < iMaxLen )
|
|
iMaxLen = iLen;
|
|
}
|
|
|
|
iReceived = 0;
|
|
iTimeElapsed = 0;
|
|
HB_SOCKET_ZERO_ERROR( Socket );
|
|
|
|
do
|
|
{
|
|
if( hb_selectReadSocket( Socket ) )
|
|
{
|
|
iLen = recv( Socket->com, buffer + iReceived, iMaxLen - iReceived, MSG_NOSIGNAL );
|
|
if( iLen > 0 )
|
|
iReceived += iLen;
|
|
|
|
/* Called from InetRecv()? */
|
|
if( iMode == 0 )
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
/* timed out; let's see if we have to run a cb routine */
|
|
iTimeElapsed += Socket->timeout;
|
|
|
|
/* if we have a caPeriodic, timeLimit is our REAL timeout */
|
|
if( Socket->caPeriodic != NULL )
|
|
{
|
|
hb_execFromArray( Socket->caPeriodic );
|
|
|
|
/* do we continue? */
|
|
if( ! hb_parl( -1 ) || ( Socket->timelimit != -1 && iTimeElapsed >= Socket->timelimit ) )
|
|
{
|
|
HB_SOCKET_SET_ERROR2( Socket, -1, "Timeout" );
|
|
hb_retni( iReceived );
|
|
return;
|
|
}
|
|
|
|
/* Declare success to continue loop */
|
|
iLen = 1;
|
|
}
|
|
else /* the timeout has gone, and we have no recovery routine */
|
|
{
|
|
HB_SOCKET_SET_ERROR2( Socket, -1, "Timeout" );
|
|
hb_retni( iReceived );
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
while( iReceived < iMaxLen && iLen > 0 );
|
|
|
|
Socket->count = iReceived;
|
|
|
|
if( iLen == 0 )
|
|
{
|
|
HB_SOCKET_SET_ERROR2( Socket, -2, "Connection closed" );
|
|
hb_retni( iLen );
|
|
}
|
|
else if( iLen < 0 )
|
|
{
|
|
HB_SOCKET_SET_ERROR( Socket );
|
|
hb_retni( iLen );
|
|
}
|
|
else
|
|
hb_retni( iReceived );
|
|
}
|
|
|
|
HB_FUNC( HB_INETRECV )
|
|
{
|
|
s_inetRecvInternal( 0 );
|
|
}
|
|
|
|
|
|
HB_FUNC( HB_INETRECVALL )
|
|
{
|
|
s_inetRecvInternal( 1 );
|
|
}
|
|
|
|
|
|
static void s_inetRecvPattern( char *szPattern )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
PHB_ITEM pResult = hb_param( 2, HB_IT_BYREF );
|
|
PHB_ITEM pMaxSize = hb_param( 3, HB_IT_NUMERIC );
|
|
PHB_ITEM pBufferSize = hb_param( 4, HB_IT_NUMERIC );
|
|
|
|
char cChar;
|
|
char *Buffer;
|
|
int iAllocated, iBufferSize, iMax;
|
|
int iLen = 0, iPatLen;
|
|
int iPos = 0, iTimeElapsed;
|
|
|
|
if( Socket == NULL )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
else if( !hb_inetIsOpen( Socket ) )
|
|
{
|
|
hb_retni( 0 );
|
|
return;
|
|
}
|
|
|
|
if( pBufferSize )
|
|
{
|
|
iBufferSize = hb_itemGetNI( pBufferSize );
|
|
}
|
|
else
|
|
{
|
|
iBufferSize = 80;
|
|
}
|
|
|
|
if( pMaxSize )
|
|
{
|
|
iMax = hb_itemGetNI( pMaxSize );
|
|
}
|
|
else
|
|
{
|
|
iMax = 0;
|
|
}
|
|
|
|
HB_SOCKET_ZERO_ERROR( Socket );
|
|
|
|
Buffer = (char *) hb_xgrab( iBufferSize );
|
|
iAllocated = iBufferSize;
|
|
iTimeElapsed = 0;
|
|
iPatLen = ( int ) strlen( szPattern );
|
|
|
|
do
|
|
{
|
|
if( iPos == iAllocated - 1 )
|
|
{
|
|
iAllocated += iBufferSize;
|
|
Buffer = ( char * ) hb_xrealloc( Buffer, iAllocated );
|
|
}
|
|
|
|
if( hb_selectReadSocket( Socket ) )
|
|
iLen = recv( Socket->com, &cChar, 1, MSG_NOSIGNAL );
|
|
else
|
|
{
|
|
iTimeElapsed += Socket->timeout;
|
|
|
|
if( Socket->caPeriodic != NULL )
|
|
{
|
|
hb_execFromArray( Socket->caPeriodic );
|
|
/* do we continue? */
|
|
if( hb_parl( -1 ) &&
|
|
( Socket->timelimit == -1 || iTimeElapsed < Socket->timelimit ) )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* this signals timeout */
|
|
iLen = -2;
|
|
}
|
|
|
|
if( iLen > 0 )
|
|
{
|
|
Buffer[ iPos++ ] = cChar;
|
|
/* verify endsequence recognition automata status */
|
|
if( iPos >= iPatLen &&
|
|
memcmp( Buffer + iPos - iPatLen, szPattern, iPatLen ) == 0 )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while( iMax == 0 || iPos < iMax );
|
|
|
|
if( iLen <= 0 )
|
|
{
|
|
if( pResult )
|
|
{
|
|
hb_itemPutNI( pResult, iLen );
|
|
}
|
|
|
|
if( iLen == 0 )
|
|
{
|
|
HB_SOCKET_SET_ERROR2( Socket, -2, "Connection closed" );
|
|
}
|
|
else if( iLen == -2 )
|
|
{
|
|
HB_SOCKET_SET_ERROR2( Socket, -1, "Timeout" );
|
|
}
|
|
else
|
|
{
|
|
HB_SOCKET_SET_ERROR( Socket );
|
|
}
|
|
|
|
hb_xfree( (void *) Buffer );
|
|
}
|
|
else
|
|
{
|
|
if( iMax == 0 || iPos < iMax )
|
|
{
|
|
iPos -= iPatLen;
|
|
Socket->count = iPos;
|
|
|
|
if( pResult )
|
|
{
|
|
hb_itemPutNI( pResult, iPos );
|
|
}
|
|
|
|
hb_retclen_buffer( Buffer, iPos );
|
|
}
|
|
else
|
|
{
|
|
HB_SOCKET_SET_ERROR2( Socket, -3, "Buffer overrun" );
|
|
|
|
if( pResult )
|
|
{
|
|
hb_itemPutNI( pResult, -2 );
|
|
}
|
|
|
|
hb_xfree( (void *) Buffer );
|
|
hb_retc( NULL );
|
|
}
|
|
}
|
|
}
|
|
|
|
HB_FUNC( HB_INETRECVLINE )
|
|
{
|
|
s_inetRecvPattern( "\r\n" );
|
|
}
|
|
|
|
HB_FUNC( HB_INETRECVENDBLOCK )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
PHB_ITEM pProto = hb_param( 2, HB_IT_ARRAY | HB_IT_STRING );
|
|
PHB_ITEM pResult = hb_param( 3, HB_IT_BYREF );
|
|
PHB_ITEM pMaxSize = hb_param( 4, HB_IT_NUMERIC );
|
|
PHB_ITEM pBufferSize = hb_param( 5, HB_IT_NUMERIC );
|
|
|
|
char cChar;
|
|
char *Buffer;
|
|
char **Proto;
|
|
int iAllocated, iBufferSize, iMax;
|
|
int iLen;
|
|
int iPos = 0;
|
|
int iPosProto;
|
|
int iTimeElapsed = 0;
|
|
int iprotos;
|
|
int i;
|
|
int *iprotosize;
|
|
int ifindproto = 0;
|
|
BOOL bProtoFound;
|
|
|
|
|
|
if( Socket == NULL )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
else if( !hb_inetIsOpen( Socket ) )
|
|
{
|
|
if( pResult )
|
|
hb_itemPutNI( pResult, -1 );
|
|
hb_retc( NULL );
|
|
return;
|
|
}
|
|
|
|
if( pProto )
|
|
{
|
|
if( HB_IS_ARRAY( pProto ) )
|
|
{
|
|
iprotos = (int) hb_arrayLen( pProto );
|
|
if( iprotos <= 0 )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
|
|
Proto = (char**) hb_xgrab( sizeof(char*) * iprotos );
|
|
iprotosize = (int *) hb_xgrab( sizeof(int) * iprotos );
|
|
|
|
for( i = 0; i < iprotos; i++ )
|
|
{
|
|
Proto[ i ] = hb_arrayGetCPtr( pProto, i + 1 );
|
|
iprotosize[ i ] = hb_arrayGetCLen( pProto, i + 1 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Proto = (char**) hb_xgrab( sizeof(char*) );
|
|
iprotosize = (int *) hb_xgrab( sizeof(int) );
|
|
Proto[0] = hb_itemGetCPtr( pProto );
|
|
iprotosize[0] = hb_itemGetCLen( pProto );
|
|
iprotos = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Proto = (char**) hb_xgrab( sizeof(char*) );
|
|
iprotosize = (int *) hb_xgrab( sizeof(int) );
|
|
Proto[0] = (char *) "\r\n";
|
|
iprotos = 1;
|
|
iprotosize[0] = 2;
|
|
}
|
|
|
|
iBufferSize = pBufferSize ? hb_itemGetNI( pBufferSize ) : 80;
|
|
iMax = pMaxSize ? hb_itemGetNI( pMaxSize ) : 0;
|
|
|
|
HB_SOCKET_ZERO_ERROR( Socket );
|
|
|
|
Buffer = (char *) hb_xgrab( iBufferSize );
|
|
iAllocated = iBufferSize;
|
|
|
|
do
|
|
{
|
|
if( iPos == iAllocated - 1 )
|
|
{
|
|
iAllocated += iBufferSize;
|
|
Buffer = ( char * ) hb_xrealloc( Buffer, iAllocated );
|
|
}
|
|
|
|
iLen = 0;
|
|
|
|
if( hb_selectReadSocket( Socket ) )
|
|
{
|
|
iLen = recv( Socket->com, &cChar, 1, MSG_NOSIGNAL );
|
|
}
|
|
else
|
|
{
|
|
iTimeElapsed += Socket->timeout;
|
|
if( Socket->caPeriodic != NULL )
|
|
{
|
|
hb_execFromArray( Socket->caPeriodic );
|
|
|
|
if( hb_parl( -1 ) &&
|
|
( Socket->timelimit == -1 || iTimeElapsed < Socket->timelimit ) )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
iLen = -2;
|
|
}
|
|
|
|
if( iLen > 0 )
|
|
{
|
|
int protos;
|
|
bProtoFound = 0;
|
|
|
|
for( protos=0; protos < iprotos; protos++ )
|
|
{
|
|
if( cChar == Proto[protos][iprotosize[protos]-1] && iprotosize[protos] <= iPos )
|
|
{
|
|
bProtoFound = 1;
|
|
for(iPosProto=0; iPosProto < (iprotosize[protos]-1); iPosProto++)
|
|
{
|
|
if(Proto[protos][iPosProto] != Buffer[ (iPos-iprotosize[protos])+iPosProto+1 ])
|
|
{
|
|
bProtoFound = 0;
|
|
break;
|
|
}
|
|
}
|
|
if(bProtoFound)
|
|
{
|
|
ifindproto = protos;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(bProtoFound)
|
|
{
|
|
break;
|
|
}
|
|
|
|
Buffer[ iPos++ ] = cChar;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while( iMax == 0 || iPos < iMax );
|
|
|
|
if( iLen <= 0 )
|
|
{
|
|
if( pResult )
|
|
{
|
|
hb_itemPutNI( pResult, iLen );
|
|
}
|
|
|
|
if( iLen == 0 )
|
|
{
|
|
HB_SOCKET_SET_ERROR2( Socket, -2, "Connection closed" );
|
|
}
|
|
else if( iLen == -2 )
|
|
{
|
|
HB_SOCKET_SET_ERROR2( Socket, -1, "Timeout" );
|
|
}
|
|
else
|
|
{
|
|
HB_SOCKET_SET_ERROR( Socket );
|
|
}
|
|
|
|
hb_xfree( ( void * ) Buffer );
|
|
hb_retc( NULL );
|
|
}
|
|
else
|
|
{
|
|
if( iMax == 0 || iPos < iMax )
|
|
{
|
|
Socket->count = iPos;
|
|
|
|
if( pResult )
|
|
{
|
|
hb_itemPutNI( pResult, iPos - (iprotosize[ifindproto]-1) );
|
|
}
|
|
|
|
hb_retclen_buffer( Buffer, iPos - (iprotosize[ifindproto]-1) );
|
|
}
|
|
else
|
|
{
|
|
HB_SOCKET_SET_ERROR2( Socket, -1, "Buffer overrun" );
|
|
|
|
if( pResult )
|
|
{
|
|
hb_itemPutNI( pResult, -2 );
|
|
}
|
|
|
|
hb_xfree( (void *) Buffer );
|
|
hb_retc( NULL );
|
|
}
|
|
}
|
|
|
|
hb_xfree( Proto );
|
|
hb_xfree( iprotosize );
|
|
}
|
|
|
|
HB_FUNC( HB_INETDATAREADY )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
int iVal;
|
|
fd_set rfds;
|
|
struct timeval tv = {0,0};
|
|
|
|
if( Socket == NULL || ( hb_pcount() > 1 && ! ISNUM( 2 ) ) )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
else if( !hb_inetIsOpen( Socket ) )
|
|
{
|
|
hb_retl( FALSE );
|
|
return;
|
|
}
|
|
|
|
HB_SOCKET_ZERO_ERROR( Socket );
|
|
|
|
/* Watch our socket. */
|
|
if( hb_pcount() > 1 )
|
|
{
|
|
iVal = hb_parni( 2 );
|
|
tv.tv_sec = iVal / 1000;
|
|
tv.tv_usec = (iVal % 1000) * 1000;
|
|
}
|
|
|
|
FD_ZERO(&rfds);
|
|
FD_SET(Socket->com, &rfds);
|
|
|
|
iVal = select( Socket->com + 1, &rfds, NULL, NULL, &tv );
|
|
/* Don't rely on the value of tv now! */
|
|
|
|
if( iVal < 0 )
|
|
{
|
|
HB_SOCKET_SET_ERROR( Socket );
|
|
}
|
|
|
|
hb_retni( iVal );
|
|
}
|
|
|
|
|
|
static void s_inetSendInternal( int iMode )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
PHB_ITEM pBuffer = hb_param( 2, HB_IT_STRING );
|
|
char *Buffer;
|
|
int iLen, iSent, iSend;
|
|
|
|
if( Socket == NULL || pBuffer == NULL )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
else if( !hb_inetIsOpen( Socket ) )
|
|
{
|
|
hb_retni( 0 );
|
|
return;
|
|
}
|
|
|
|
Buffer = hb_itemGetCPtr( pBuffer );
|
|
iSend = ( int ) hb_itemGetCLen( pBuffer );
|
|
if( ISNUM( 3 ) )
|
|
{
|
|
iLen = hb_parni( 3 );
|
|
if( iLen < iSend )
|
|
iSend = iLen;
|
|
}
|
|
|
|
HB_SOCKET_ZERO_ERROR( Socket );
|
|
|
|
iSent = 0;
|
|
iLen = 0;
|
|
while( iSent < iSend )
|
|
{
|
|
iLen = 0;
|
|
if( hb_selectWriteSocket( Socket ) )
|
|
iLen = send( Socket->com, Buffer + iSent, iSend - iSent, MSG_NOSIGNAL );
|
|
|
|
if( iLen > 0 )
|
|
{
|
|
iSent += iLen;
|
|
}
|
|
else if( iLen == 0 )
|
|
{
|
|
HB_SOCKET_SET_ERROR2( Socket, -1 , "Timeout" );
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
HB_SOCKET_SET_ERROR( Socket );
|
|
break;
|
|
}
|
|
if( iMode == 0 )
|
|
break;
|
|
}
|
|
|
|
Socket->count = iSent;
|
|
|
|
hb_retni( iLen > 0 ? iSent : -1 );
|
|
}
|
|
|
|
HB_FUNC( HB_INETSEND )
|
|
{
|
|
s_inetSendInternal( 0 );
|
|
}
|
|
|
|
HB_FUNC( HB_INETSENDALL )
|
|
{
|
|
s_inetSendInternal( 1 );
|
|
}
|
|
|
|
|
|
/*******************************************
|
|
* Name resolution interface functions
|
|
***/
|
|
|
|
HB_FUNC( HB_INETGETHOSTS )
|
|
{
|
|
char * szHost = hb_parc( 1 );
|
|
struct hostent *Host;
|
|
char ** cHosts;
|
|
int iCount = 0;
|
|
|
|
if( szHost == NULL )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
|
|
Host = hb_getHosts( szHost, NULL );
|
|
if( Host )
|
|
{
|
|
cHosts = Host->h_addr_list;
|
|
while( *cHosts )
|
|
{
|
|
iCount++;
|
|
cHosts++;
|
|
}
|
|
}
|
|
|
|
if( iCount == 0 )
|
|
hb_reta( 0 );
|
|
else
|
|
{
|
|
PHB_ITEM pHosts = hb_itemArrayNew( iCount );
|
|
iCount = 0;
|
|
cHosts = Host->h_addr_list;
|
|
while( *cHosts )
|
|
{
|
|
hb_arraySetC( pHosts, ++iCount,
|
|
inet_ntoa( *( ( struct in_addr * ) * cHosts ) ) );
|
|
cHosts++;
|
|
}
|
|
hb_itemReturnRelease( pHosts );
|
|
}
|
|
}
|
|
|
|
|
|
HB_FUNC( HB_INETGETALIAS )
|
|
{
|
|
char * szHost = hb_parc( 1 );
|
|
struct hostent *Host;
|
|
char ** cHosts;
|
|
int iCount = 0;
|
|
|
|
if( szHost == NULL )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
|
|
Host = hb_getHosts( szHost, NULL );
|
|
if( Host )
|
|
{
|
|
cHosts = Host->h_aliases;
|
|
while( *cHosts )
|
|
{
|
|
iCount++;
|
|
cHosts++;
|
|
}
|
|
}
|
|
|
|
if( iCount == 0 )
|
|
hb_reta( 0 );
|
|
else
|
|
{
|
|
PHB_ITEM pHosts = hb_itemArrayNew( iCount );
|
|
iCount = 0;
|
|
cHosts = Host->h_aliases;
|
|
while( *cHosts )
|
|
{
|
|
hb_arraySetC( pHosts, ++iCount,
|
|
inet_ntoa( *( ( struct in_addr * ) * cHosts ) ) );
|
|
cHosts++;
|
|
}
|
|
hb_itemReturnRelease( pHosts );
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************
|
|
* Server Specific functions
|
|
****/
|
|
|
|
HB_FUNC( HB_INETSERVER )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 2 );
|
|
PHB_ITEM pSocket = NULL;
|
|
char * szAddress;
|
|
int iPort;
|
|
int iOpt = 1;
|
|
int iListen;
|
|
|
|
/* Parameter error checking */
|
|
if( ! ISNUM( 1 ) || ( Socket == NULL && !ISNIL( 2 ) ) )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
|
|
if( Socket != NULL )
|
|
{
|
|
HB_SOCKET_ZERO_ERROR( Socket );
|
|
}
|
|
else
|
|
{
|
|
HB_SOCKET_INIT( Socket, pSocket );
|
|
}
|
|
|
|
/* Creates comm socket */
|
|
#if defined(HB_OS_WIN_32)
|
|
Socket->com = socket( AF_INET, SOCK_STREAM, 0 );
|
|
#else
|
|
Socket->com = socket( PF_INET, SOCK_STREAM, 0 );
|
|
#endif
|
|
|
|
if( Socket->com == ( HB_SOCKET_T ) -1 )
|
|
{
|
|
HB_SOCKET_SET_ERROR( Socket );
|
|
if( pSocket )
|
|
hb_itemReturnRelease( pSocket );
|
|
else
|
|
hb_itemReturn( hb_param( 2, HB_IT_ANY ) );
|
|
return;
|
|
}
|
|
|
|
/* we'll be using only nonblocking sockets */
|
|
/* hb_socketSetNonBlocking( Socket ); */
|
|
|
|
/* Reusable socket; under unix, do not wait it is unused */
|
|
setsockopt( Socket->com, SOL_SOCKET, SO_REUSEADDR, (const char *) &iOpt, sizeof( iOpt ) );
|
|
|
|
iPort = htons( hb_parni( 1 ) );
|
|
|
|
Socket->remote.sin_family = AF_INET;
|
|
Socket->remote.sin_port = iPort;
|
|
|
|
szAddress = hb_parc( 2 );
|
|
Socket->remote.sin_addr.s_addr = szAddress ? inet_addr( szAddress ) : INADDR_ANY;
|
|
|
|
iListen = ISNUM( 3 ) ? hb_parni( 3 ) : 10;
|
|
|
|
if( bind( Socket->com, (struct sockaddr *) &Socket->remote, sizeof(Socket->remote) ) )
|
|
{
|
|
HB_SOCKET_SET_ERROR( Socket );
|
|
HB_INET_CLOSE( Socket->com );
|
|
Socket->com = ( HB_SOCKET_T ) -1;
|
|
}
|
|
else if( listen( Socket->com, iListen ) )
|
|
{
|
|
HB_SOCKET_SET_ERROR( Socket );
|
|
HB_INET_CLOSE( Socket->com );
|
|
Socket->com = ( HB_SOCKET_T ) -1;
|
|
}
|
|
|
|
if( pSocket )
|
|
hb_itemReturnRelease( pSocket );
|
|
else
|
|
hb_itemReturn( hb_param( 2, HB_IT_ANY ) );
|
|
}
|
|
|
|
HB_FUNC( HB_INETACCEPT )
|
|
{
|
|
#if !defined(EAGAIN)
|
|
#define EAGAIN -1
|
|
#endif
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
HB_SOCKET_STRUCT *NewSocket;
|
|
HB_SOCKET_T incoming = 0;
|
|
int iError = EAGAIN;
|
|
struct sockaddr_in si_remote;
|
|
#if defined(_XOPEN_SOURCE_EXTENDED)
|
|
socklen_t Len;
|
|
#elif defined(HB_OS_WIN_32)
|
|
int Len;
|
|
#else
|
|
unsigned int Len;
|
|
#endif
|
|
|
|
if( Socket == NULL )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
else if( !hb_inetIsOpen( Socket ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
Len = sizeof( struct sockaddr_in );
|
|
|
|
/*
|
|
* Accept can (and should) be asynchronously stopped by closing the
|
|
* accepting socket. this will make the wait to terminate, and the
|
|
* calling program will be notivfied through the status of the
|
|
* returned socket.
|
|
*/
|
|
|
|
HB_SOCKET_ZERO_ERROR( Socket );
|
|
|
|
/* Connection incoming */
|
|
while( iError == EAGAIN )
|
|
{
|
|
if( hb_selectReadSocket( Socket ) )
|
|
{
|
|
/* On error (e.g. async connection closed) , com will be -1 and
|
|
errno == 22 (invalid argument ) */
|
|
incoming = accept( Socket->com, (struct sockaddr *) &si_remote, &Len );
|
|
|
|
if( incoming == ( HB_SOCKET_T ) -1 )
|
|
{
|
|
#if defined(HB_OS_WIN_32)
|
|
iError = WSAGetLastError();
|
|
#else
|
|
iError = errno;
|
|
#endif
|
|
}
|
|
else
|
|
iError = 0;
|
|
}
|
|
/* Timeout expired */
|
|
else
|
|
iError = -1;
|
|
}
|
|
|
|
if( iError == -1 )
|
|
{
|
|
HB_SOCKET_SET_ERROR2( Socket, -1, "Timeout" );
|
|
}
|
|
else if( iError > 0 )
|
|
{
|
|
HB_SOCKET_SET_ERROR1( Socket, iError );
|
|
}
|
|
else
|
|
{
|
|
PHB_ITEM pSocket = NULL;
|
|
/* we'll be using only nonblocking sockets */
|
|
HB_SOCKET_INIT( NewSocket, pSocket );
|
|
memcpy( &NewSocket->remote, &si_remote, Len );
|
|
NewSocket->com = incoming;
|
|
/* hb_socketSetNonBlocking( NewSocket ); */
|
|
hb_itemReturnRelease( pSocket );
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************
|
|
* Client specific (connection functions)
|
|
****/
|
|
|
|
HB_FUNC( HB_INETCONNECT )
|
|
{
|
|
char * szHost = hb_parc( 1 );
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 3 );
|
|
PHB_ITEM pSocket = NULL;
|
|
struct hostent *Host;
|
|
int iPort;
|
|
|
|
if( szHost == NULL || !ISNUM( 2 ) || ( Socket == NULL && !ISNIL( 3 ) ) )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
|
|
if( Socket != NULL )
|
|
{
|
|
if( Socket->com != ( HB_SOCKET_T ) -1 )
|
|
{
|
|
HB_INET_CLOSE( Socket->com );
|
|
Socket->com = ( HB_SOCKET_T ) -1;
|
|
}
|
|
HB_SOCKET_ZERO_ERROR( Socket );
|
|
}
|
|
else
|
|
{
|
|
HB_SOCKET_INIT( Socket, pSocket );
|
|
}
|
|
|
|
Host = hb_getHosts( szHost, Socket );
|
|
|
|
/* error had been set by get hosts */
|
|
|
|
if( Host != NULL )
|
|
{
|
|
/* Creates comm socket */
|
|
#if defined(HB_OS_WIN_32)
|
|
Socket->com = socket( AF_INET, SOCK_STREAM, 0);
|
|
#else
|
|
Socket->com = socket( PF_INET, SOCK_STREAM, 0);
|
|
#endif
|
|
|
|
if( Socket->com == ( HB_SOCKET_T ) -1 )
|
|
{
|
|
HB_SOCKET_SET_ERROR( Socket );
|
|
}
|
|
else
|
|
{
|
|
iPort = htons( hb_parni( 2 ) );
|
|
|
|
Socket->remote.sin_family = AF_INET;
|
|
Socket->remote.sin_port= iPort;
|
|
Socket->remote.sin_addr.s_addr = (*(UINT *)Host->h_addr_list[0]);
|
|
|
|
hb_socketConnect( Socket );
|
|
}
|
|
}
|
|
|
|
if( pSocket )
|
|
hb_itemReturnRelease( pSocket );
|
|
else
|
|
hb_itemReturn( hb_param( 3, HB_IT_ANY ) );
|
|
}
|
|
|
|
|
|
HB_FUNC( HB_INETCONNECTIP )
|
|
{
|
|
char * szHost = hb_parc( 1 );
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 3 );
|
|
PHB_ITEM pSocket = NULL;
|
|
int iPort = hb_parni( 2 );
|
|
|
|
if( szHost == NULL || iPort == 0 || ( Socket == NULL && !ISNIL( 3 ) ) )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
|
|
if( Socket != NULL )
|
|
{
|
|
if( Socket->com != ( HB_SOCKET_T ) -1 )
|
|
{
|
|
HB_INET_CLOSE( Socket->com );
|
|
Socket->com = ( HB_SOCKET_T ) -1;
|
|
}
|
|
HB_SOCKET_ZERO_ERROR( Socket );
|
|
}
|
|
else
|
|
{
|
|
HB_SOCKET_INIT( Socket, pSocket );
|
|
}
|
|
|
|
/* Creates comm socket */
|
|
#if defined(HB_OS_WIN_32)
|
|
Socket->com = socket( AF_INET, SOCK_STREAM, 0);
|
|
#else
|
|
Socket->com = socket( PF_INET, SOCK_STREAM, 0);
|
|
#endif
|
|
|
|
if( Socket->com == ( HB_SOCKET_T ) -1 )
|
|
{
|
|
HB_SOCKET_SET_ERROR( Socket );
|
|
}
|
|
else
|
|
{
|
|
iPort = htons( iPort );
|
|
|
|
Socket->remote.sin_family = AF_INET;
|
|
Socket->remote.sin_port= iPort;
|
|
Socket->remote.sin_addr.s_addr = inet_addr( szHost );
|
|
|
|
hb_socketConnect( Socket );
|
|
}
|
|
|
|
if( pSocket )
|
|
hb_itemReturnRelease( pSocket );
|
|
else
|
|
hb_itemReturn( hb_param( 3, HB_IT_ANY ) );
|
|
}
|
|
|
|
/***********************************************************
|
|
* Datagram functions
|
|
************************************************************/
|
|
|
|
HB_FUNC( HB_INETDGRAMBIND )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket;
|
|
PHB_ITEM pSocket = NULL;
|
|
int iPort = hb_parni(1);
|
|
int iOpt = 1;
|
|
char * szAddress;
|
|
|
|
/* Parameter error checking */
|
|
if( iPort == 0 || ( hb_pcount() > 3 && ! ISCHAR( 4 ) ) )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
|
|
HB_SOCKET_INIT( Socket, pSocket );
|
|
|
|
/* Creates comm socket */
|
|
#if defined(HB_OS_WIN_32)
|
|
Socket->com = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
|
|
#else
|
|
Socket->com = socket( PF_INET, SOCK_DGRAM, 0 );
|
|
#endif
|
|
|
|
if( Socket->com == ( HB_SOCKET_T ) -1 )
|
|
{
|
|
HB_SOCKET_SET_ERROR( Socket );
|
|
hb_itemReturnRelease( pSocket );
|
|
return;
|
|
}
|
|
|
|
/* Reusable socket; under unix, do not wait it is unused */
|
|
setsockopt( Socket->com, SOL_SOCKET, SO_REUSEADDR, (const char *) &iOpt, sizeof( iOpt ));
|
|
|
|
/* Setting broadcast if needed. */
|
|
if( hb_parl( 3 ) )
|
|
{
|
|
iOpt = 1;
|
|
setsockopt( Socket->com, SOL_SOCKET, SO_BROADCAST, (const char *) &iOpt, sizeof( iOpt ));
|
|
}
|
|
|
|
/* Binding here */
|
|
iPort = htons( iPort );
|
|
|
|
Socket->remote.sin_family = AF_INET;
|
|
Socket->remote.sin_port = iPort;
|
|
|
|
szAddress = hb_parc( 2 );
|
|
Socket->remote.sin_addr.s_addr = szAddress ? inet_addr( szAddress ) : INADDR_ANY;
|
|
|
|
if( bind( Socket->com, (struct sockaddr *) &Socket->remote, sizeof(Socket->remote) ) )
|
|
{
|
|
HB_SOCKET_SET_ERROR( Socket );
|
|
HB_INET_CLOSE( Socket->com );
|
|
Socket->com = ( HB_SOCKET_T ) -1;
|
|
}
|
|
else if( hb_pcount() > 3 )
|
|
{
|
|
#ifndef IP_ADD_MEMBERSHIP
|
|
#define IP_ADD_MEMBERSHIP 5 /* which header should this be in? */
|
|
#endif
|
|
|
|
/* this structure should be define in a header file. The MS SDK indicates that */
|
|
/* it is in Ws2tcpip.h but I'm not sure I know where it should go in xHb */
|
|
struct ip_mreq
|
|
{
|
|
struct in_addr imr_multiaddr; /* IP multicast address of group */
|
|
struct in_addr imr_interface; /* local IP address of interface */
|
|
};
|
|
|
|
struct ip_mreq mreq ;
|
|
|
|
mreq.imr_multiaddr.s_addr = inet_addr( hb_parc( 4 ) ); /* HELLO_GROUP */
|
|
mreq.imr_interface.s_addr = htonl( INADDR_ANY );
|
|
|
|
#ifndef IPPROTO_IP
|
|
/*
|
|
* some systems may not have this definitions, it should
|
|
* be 0 what works with TCP/UDP sockets or explicitly set
|
|
* to IPPROTO_TCP/IPPROTO_UDP
|
|
*/
|
|
# define IPPROTO_IP 0
|
|
#endif
|
|
|
|
if( setsockopt( Socket->com, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *) &mreq, sizeof( mreq ) ) < 0 )
|
|
{
|
|
HB_SOCKET_SET_ERROR( Socket );
|
|
}
|
|
}
|
|
|
|
hb_itemReturnRelease( pSocket );
|
|
}
|
|
|
|
HB_FUNC( HB_INETDGRAM )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket;
|
|
PHB_ITEM pSocket = NULL;
|
|
int iOpt = 1;
|
|
|
|
HB_SOCKET_INIT( Socket, pSocket );
|
|
|
|
/* Creates comm socket */
|
|
#if defined(HB_OS_WIN_32)
|
|
Socket->com = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
|
|
#else
|
|
Socket->com = socket( PF_INET, SOCK_DGRAM, 0 );
|
|
#endif
|
|
|
|
if( Socket->com == ( HB_SOCKET_T ) -1 )
|
|
{
|
|
HB_SOCKET_SET_ERROR( Socket );
|
|
hb_itemReturnRelease( pSocket );
|
|
return;
|
|
}
|
|
|
|
/* Setting broadcast if needed. */
|
|
if( hb_parl( 1 ) )
|
|
{
|
|
iOpt = 1;
|
|
setsockopt( Socket->com, SOL_SOCKET, SO_BROADCAST, (const char *) &iOpt, sizeof( iOpt ));
|
|
}
|
|
/* we'll be using non blocking sockets in all functions */
|
|
/* hb_socketSetNonBlocking( Socket ); */
|
|
|
|
hb_itemReturnRelease( pSocket );
|
|
}
|
|
|
|
HB_FUNC( HB_INETDGRAMSEND )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
char * szAddress = hb_parc( 2 );
|
|
int iPort = hb_parni( 3 );
|
|
PHB_ITEM pBuffer = hb_param( 4, HB_IT_STRING );
|
|
int iLen;
|
|
char *szBuffer ;
|
|
|
|
if( Socket == NULL ||
|
|
szAddress == NULL || iPort == 0 || pBuffer == NULL )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
else if( !hb_inetIsOpen( Socket ) )
|
|
{
|
|
Socket->count = 0;
|
|
hb_retni( 0 );
|
|
return;
|
|
}
|
|
|
|
Socket->remote.sin_family = AF_INET;
|
|
Socket->remote.sin_port = htons( iPort );
|
|
Socket->remote.sin_addr.s_addr = inet_addr( szAddress );
|
|
szBuffer = hb_itemGetCPtr( pBuffer );
|
|
|
|
iLen = ( int ) hb_itemGetCLen( pBuffer );
|
|
if( ISNUM( 5 ) )
|
|
{
|
|
int iMaxLen = hb_parni( 5 );
|
|
|
|
if( iMaxLen < iLen )
|
|
iLen = iMaxLen;
|
|
}
|
|
|
|
HB_SOCKET_ZERO_ERROR( Socket );
|
|
|
|
Socket->count = 0;
|
|
if( hb_selectWriteSocket( Socket ) )
|
|
{
|
|
Socket->count = sendto( Socket->com, szBuffer, iLen, 0,
|
|
(const struct sockaddr *) &Socket->remote, sizeof( Socket->remote ) );
|
|
}
|
|
|
|
hb_retni( Socket->count );
|
|
|
|
if( Socket->count == 0 )
|
|
{
|
|
HB_SOCKET_SET_ERROR2( Socket, -1, "Timeout" );
|
|
}
|
|
else if( Socket->count < 0 )
|
|
{
|
|
Socket->count = 0;
|
|
HB_SOCKET_SET_ERROR( Socket );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
HB_FUNC( HB_INETDGRAMRECV )
|
|
{
|
|
HB_SOCKET_STRUCT *Socket = HB_PARSOCKET( 1 );
|
|
PHB_ITEM pBuffer = hb_param( 2, HB_IT_STRING );
|
|
int iTimeElapsed = 0;
|
|
int iLen, iMaxLen;
|
|
char *Buffer;
|
|
BOOL fRepeat;
|
|
#if defined(HB_OS_WIN_32)
|
|
int iDtLen = sizeof( struct sockaddr );
|
|
#else
|
|
socklen_t iDtLen = (socklen_t) sizeof( struct sockaddr );
|
|
#endif
|
|
|
|
if( Socket == NULL || pBuffer == NULL || !ISBYREF( 2 ) )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
else if( !hb_inetIsOpen( Socket ) )
|
|
{
|
|
Socket->count = 0;
|
|
hb_retni( -1 );
|
|
return;
|
|
}
|
|
|
|
pBuffer = hb_itemUnShare( pBuffer );
|
|
Buffer = hb_itemGetCPtr( pBuffer );
|
|
|
|
if( ISNUM( 3 ) )
|
|
{
|
|
iMaxLen = hb_parni( 3 );
|
|
}
|
|
else
|
|
{
|
|
iMaxLen = ( int ) hb_itemGetCLen( pBuffer );
|
|
}
|
|
|
|
HB_SOCKET_ZERO_ERROR( Socket );
|
|
|
|
do
|
|
{
|
|
fRepeat = FALSE;
|
|
iLen = -2;
|
|
if( hb_selectReadSocket( Socket ) )
|
|
{
|
|
iLen = recvfrom( Socket->com, Buffer, iMaxLen, 0,
|
|
(struct sockaddr *) &Socket->remote, &iDtLen );
|
|
}
|
|
iTimeElapsed += Socket->timeout;
|
|
if( Socket->caPeriodic != NULL )
|
|
{
|
|
hb_execFromArray( Socket->caPeriodic );
|
|
/* do we continue? */
|
|
fRepeat = hb_parl( -1 ) &&
|
|
( Socket->timelimit == -1 || iTimeElapsed < Socket->timelimit );
|
|
}
|
|
}
|
|
while( fRepeat );
|
|
|
|
if( iLen == -2 )
|
|
{
|
|
HB_SOCKET_SET_ERROR2( Socket, -1, "Timeout" );
|
|
Socket->count = 0;
|
|
iLen = -1;
|
|
}
|
|
else if( iLen == 0 )
|
|
{
|
|
HB_SOCKET_SET_ERROR2( Socket, -2, "Connection closed" );
|
|
Socket->count = 0;
|
|
}
|
|
else if( iLen < 0 )
|
|
{
|
|
HB_SOCKET_SET_ERROR( Socket );
|
|
Socket->count = 0;
|
|
}
|
|
else
|
|
{
|
|
Socket->count = iLen;
|
|
}
|
|
hb_retni( iLen );
|
|
}
|
|
|
|
|
|
/***********************************************************
|
|
* Generic utility(?) functions
|
|
************************************************************/
|
|
|
|
HB_FUNC( HB_INETCRLF )
|
|
{
|
|
hb_retc( "\r\n" );
|
|
}
|
|
|
|
HB_FUNC( HB_INETISSOCKET )
|
|
{
|
|
hb_retl( HB_PARSOCKET( 1 ) != NULL );
|
|
}
|
|
|
|
#endif /* !HB_NO_DEFAULT_INET */
|