* harbour/include/hbvm.h
* harbour/include/hbrdddbf.h
* harbour/include/hbapidbg.h
* harbour/include/hbset.h
* harbour/include/hbcomp.h
* harbour/include/hbapirdd.h
* harbour/include/hbstack.h
* harbour/include/hbsxfunc.h
* harbour/include/hbapilng.h
* harbour/include/hbgtcore.h
* harbour/include/hbapifs.h
* harbour/include/hbdbsort.h
* harbour/include/hbapigt.h
* harbour/include/hbapi.h
* harbour/include/hbapierr.h
* harbour/include/hbapiitm.h
* harbour/include/hbrddfpt.h
* harbour/contrib/hbmysql/mysql.c
* harbour/contrib/hbct/bitnum.c
* harbour/contrib/hbct/token2.c
* harbour/contrib/hbct/charsprd.c
* harbour/contrib/hbct/ctnet.c
* harbour/contrib/hbct/charonly.c
* harbour/contrib/hbct/atadjust.c
* harbour/contrib/hbct/ctwin.c
* harbour/contrib/hbct/charsort.c
* harbour/contrib/hbct/ctwin.h
* harbour/contrib/hbct/charmix.c
* harbour/contrib/hbct/charevod.c
* harbour/contrib/hbct/maxline.c
* harbour/contrib/hbct/wordrepl.c
* harbour/contrib/hbct/charrepl.c
* harbour/contrib/hbct/files.c
* harbour/contrib/hbct/video.c
* harbour/contrib/hbct/charswap.c
* harbour/contrib/hbct/dattime3.c
* harbour/contrib/hbct/charop.c
* harbour/contrib/hbct/misc2.c
* harbour/contrib/hbct/charone.c
* harbour/contrib/hbct/ctstr.c
* harbour/contrib/hbct/screen1.c
* harbour/contrib/hbct/token1.c
* harbour/contrib/hbct/ctstr.h
* harbour/contrib/hbct/charmirr.c
* harbour/contrib/hbct/relation.c
* harbour/contrib/hbct/atnum.c
* harbour/contrib/hbct/like.c
* harbour/contrib/hbct/count.c
* harbour/contrib/hbct/disk.c
* harbour/contrib/hbct/ctstrfil.c
* harbour/contrib/hbct/posdiff.c
* harbour/contrib/hbct/addascii.c
* harbour/contrib/hbct/tab.c
* harbour/contrib/hbct/numline.c
* harbour/contrib/hbct/dattime2.c
* harbour/contrib/hbct/asciisum.c
* harbour/contrib/hbct/expand.c
* harbour/contrib/hbct/pos2.c
* harbour/contrib/hbct/numat.c
* harbour/contrib/hbct/atrepl.c
* harbour/contrib/hbct/wordtoch.c
* harbour/contrib/hbct/print.c
* harbour/contrib/hbct/justify.c
* harbour/contrib/xhb/hbxml.c
* harbour/contrib/xhb/dbf2txt.c
* harbour/contrib/xhb/xhbis.c
* harbour/contrib/xhb/fparse.c
* harbour/contrib/xhb/xstrdel.c
* harbour/contrib/xhb/hbcomprs.c
* harbour/contrib/xhb/datesxhb.c
* harbour/contrib/xhb/xhbmsgs.c
* harbour/contrib/xhb/freadlin.c
* harbour/contrib/xhb/txtline.c
* harbour/contrib/xhb/xhbtrim.c
* harbour/contrib/xhb/xhbcopyf.c
* harbour/contrib/xhb/cstructc.c
* harbour/contrib/xhb/xhbfunc.c
* harbour/contrib/hbtpathy/tplinux.c
* harbour/contrib/hbgt/charmixg.c
* harbour/contrib/hbgt/strexpan.c
* harbour/contrib/hbgt/charodd.c
* harbour/contrib/hbgt/strright.c
* harbour/contrib/hbgt/asciisgt.c
* harbour/contrib/hbgt/strdiffg.c
* harbour/contrib/hbgt/chrtotal.c
* harbour/contrib/hbgt/strcount.c
* harbour/contrib/hbgt/strleft.c
* harbour/contrib/hbgt/ascposgt.c
* harbour/contrib/hbgt/chrfirst.c
* harbour/contrib/hbgt/chrcount.c
* harbour/contrib/hbgt/strpbrk.c
* harbour/contrib/hbgt/chareven.c
* harbour/contrib/hbgt/strcspn.c
* harbour/contrib/hbgt/atdiff.c
* harbour/contrib/hbsqlit3/hbsqlit3.c
* harbour/contrib/hbmzip/hbmzip.c
* harbour/contrib/hbnf/proper.c
* harbour/contrib/hbnf/fttext.c
* harbour/contrib/hbnf/chdir.c
* harbour/contrib/hbnf/getver.c
* harbour/contrib/hbnf/ftattr.c
* harbour/contrib/hbnf/mkdir.c
* harbour/contrib/hbnf/rmdir.c
* harbour/contrib/Makefile
* harbour/contrib/hbcurl/hbcurl.c
* harbour/contrib/rddsql/sddmy/mysqldd.c
* harbour/contrib/rddsql/sddpg/pgsqldd.c
* harbour/contrib/rddsql/sddfb/fbirddd.c
* harbour/contrib/rddsql/sddodbc/odbcdd.c
* harbour/contrib/rddsql/sqlmix.c
* harbour/contrib/hbhpdf/harupdf.c
* harbour/contrib/rddads/adsx.c
* harbour/contrib/rddads/adsfunc.c
* harbour/contrib/rddads/rddads.h
* harbour/contrib/rddads/ads1.c
* harbour/contrib/hbmisc/hb_f.c
* harbour/contrib/hbmisc/strfmt.c
* harbour/contrib/hbmisc/stringsx.c
* harbour/contrib/hbmisc/spd.c
* harbour/contrib/hbtip/utils.c
* harbour/contrib/hbwin/wapi_winbase.c
* harbour/contrib/hbwin/win_misc.c
* harbour/contrib/hbbtree/hb_btree.h
* harbour/contrib/hbbtree/hb_btree.c
* harbour/source/pp/hbpp.c
* harbour/source/vm/runner.c
* harbour/source/vm/estack.c
* harbour/source/vm/itemapi.c
* harbour/source/vm/hvm.c
* harbour/source/vm/cmdarg.c
* harbour/source/vm/memvars.c
* harbour/source/vm/dynlibhb.c
* harbour/source/vm/set.c
* harbour/source/main/harbour.c
* harbour/source/debug/dbgentry.c
* harbour/source/common/hbfsapi.c
* harbour/source/common/hbfopen.c
* harbour/source/rtl/gtdos/gtdos.c
* harbour/source/rtl/diskspac.c
* harbour/source/rtl/console.c
* harbour/source/rtl/chrasc.c
* harbour/source/rtl/fscopy.c
* harbour/source/rtl/run.c
* harbour/source/rtl/spfiles.c
* harbour/source/rtl/defpath.c
* harbour/source/rtl/philes.c
* harbour/source/rtl/oldbox.c
* harbour/source/rtl/math.c
* harbour/source/rtl/hbgtcore.c
* harbour/source/rtl/cdpapi.c
* harbour/source/rtl/gtcrs/gtcrs.c
* harbour/source/rtl/dirdrive.c
* harbour/source/rtl/hbi18n1.c
* harbour/source/rtl/trim.c
* harbour/source/rtl/hbzlibgz.c
* harbour/source/rtl/philesx.c
* harbour/source/rtl/mlcfunc.c
* harbour/source/rtl/filehb.c
* harbour/source/rtl/fstemp.c
* harbour/source/rtl/is.c
* harbour/source/rtl/hbrunfun.c
* harbour/source/rtl/ampm.c
* harbour/source/rtl/setcolor.c
* harbour/source/rtl/oemansi.c
* harbour/source/rtl/disksphb.c
* harbour/source/rtl/hbzlib.c
* harbour/source/rtl/strpeek.c
* harbour/source/rtl/replic.c
* harbour/source/rtl/stuff.c
* harbour/source/rtl/hbstrfmt.c
* harbour/source/rtl/transfrm.c
* harbour/source/rtl/hbhex.c
* harbour/source/rtl/trace.c
* harbour/source/rtl/hbadler.c
* harbour/source/rtl/samples.c
* harbour/source/rtl/filebuf.c
* harbour/source/rtl/hbcrc.c
* harbour/source/rtl/gete.c
* harbour/source/rtl/hbmd5.c
* harbour/source/rtl/langapi.c
* harbour/source/rtl/gtcgi/gtcgi.c
* harbour/source/rtl/errapi.c
* harbour/source/rtl/hbregexc.c
* harbour/source/rtl/natmsg.c
* harbour/source/rtl/fssize.c
* harbour/source/rtl/hbinet.c
* harbour/source/rtl/colorind.c
* harbour/source/rtl/copyfile.c
* harbour/source/rtl/mouseapi.c
* harbour/source/rtl/soundex.c
* harbour/source/rtl/memofile.c
* harbour/source/rtl/hbffind.c
* harbour/source/rtl/gtapi.c
* harbour/source/rtl/direct.c
* harbour/source/rtl/filesys.c
* harbour/source/rtl/file.c
* harbour/source/rtl/val.c
* harbour/source/rtl/hbregex.c
* harbour/source/rtl/rat.c
* harbour/source/rtl/isprint.c
* harbour/source/rdd/dbfntx/dbfntx1.c
* harbour/source/rdd/dbsql.c
* harbour/source/rdd/workarea.c
* harbour/source/rdd/wacore.c
* harbour/source/rdd/sdf1.c
* harbour/source/rdd/dbdetach.c
* harbour/source/rdd/dbcmdx.c
* harbour/source/rdd/dbfnsx/dbfnsx1.c
* harbour/source/rdd/dbcmd.c
* harbour/source/rdd/dbfcdx/dbfcdx1.c
* harbour/source/rdd/delim1.c
* harbour/source/rdd/dbf1.c
* harbour/source/rdd/hsx/hsx.c
* harbour/source/rdd/dbcmd53.c
* harbour/source/rdd/usrrdd/usrrdd.c
* harbour/source/rdd/wafunc.c
* harbour/source/rdd/dbffpt/dbffpt1.c
* harbour/source/rdd/hbsix/sxsem.c
* harbour/source/rdd/hbsix/sxord.c
* harbour/source/rdd/hbsix/sxfname.c
* harbour/source/rdd/hbsix/sxtable.c
* harbour/source/rdd/hbsix/sxdate.c
* harbour/source/rdd/hbsix/sxutil.c
* harbour/source/rdd/hbsix/sxcompr.c
* harbour/source/compiler/hbmain.c
* harbour/source/compiler/cmdcheck.c
* harbour/source/compiler/hbpcode.c
* harbour/source/compiler/genc.c
* harbour/source/compiler/gencc.c
* harbour/source/compiler/hbcmplib.c
* harbour/source/compiler/ppcomp.c
* changed 'char *' and changed 'BYTE *' to 'const char *' in
the following functions:
const char * hb_vmFindModuleSymbolName( PHB_SYMB pSym );
void hb_vmInitSymbolGroup( void * hNewDynLib, int argc,
const char * argv[] );
void hb_dbgEntry( int nMode, int nLine, const char *szName,
int nIndex, PHB_ITEM pFrame );
void hb_dbgAddBreak( void *handle, const char *cModule,
int nLine, const char *szFunction );
void hb_dbgAddWatch( void *handle, const char *szExpr, BOOL bTrace );
PHB_ITEM hb_dbgGetExpressionValue( void *handle,
const char *expression );
BOOL hb_dbgIsValidStopLine( void *handle, const char *szModule,
int nLine );
void hb_dbgSetToCursor( void *handle, const char *szModule,
int nLine );
void hb_dbgSetWatch( void *handle, int nWatch,
const char *szExpr, BOOL bTrace );
const char * hb_setGetCPtr( HB_set_enum set_specifier );
const char * hb_setGetAltFile( void );
const char * hb_setGetDateFormat( void );
const char * hb_setGetTimeFormat( void );
const char * hb_setGetDefault( void );
const char * hb_setGetDelimChars( void );
const char * hb_setGetDevice( void );
const char * hb_setGetExtraFile( void );
const char * hb_setGetPath( void );
const char * hb_setGetMFileExt( void );
const char * hb_setGetPrintFile( void );
const char * hb_setGetEOL( void );
const char * hb_setGetHBOUTLOG( void );
const char * hb_setGetHBOUTLOGINFO( void );
const char * hb_setGetOSCODEPAGE( void );
void hb_compInitPP( HB_COMP_DECL, int argc,
const char * const argv[] );
void hb_compGenPCodeN( const BYTE * pBuffer, ULONG ulSize,
HB_COMP_DECL );
int hb_compMain( int argc, const char * const argv[],
BYTE ** pBufPtr, ULONG * pulSize,
const char * szSource );
void hb_compChkCompilerSwitch( HB_COMP_DECL, int,
const char * const args[] );
void hb_compChkDefines( HB_COMP_DECL, int iArg,
const char * const args[] );
void hb_compGenCString( FILE * yyc, const BYTE * pText, ULONG ulLen );
AREAP hb_rddRequestArea( const char * szAlias, PHB_ITEM pCargo,
BOOL fNewArea, BOOL fWait );
char * hb_stackDirBuffer( void );
LONG hb_sxPtoD( const char * pDate );
const char * hb_langID( void );
const char * hb_langSelectID( const char * pszID );
const char * hb_langDGetItem( int iIndex );
const char * hb_langDGetErrorDesc( ULONG ulIndex );
BOOL hb_fsChDir( const char * pszDirName );
HB_FHANDLE hb_fsCreate( const char * pszFileName, ULONG ulAttr );
HB_FHANDLE hb_fsCreateEx( const char * pszFilename, ULONG ulAttr,
USHORT uiFlags );
HB_FHANDLE hb_fsCreateTemp( const char * pszDir,
const char * pszPrefix,
ULONG ulAttr, char * pszName );
HB_FHANDLE hb_fsCreateTempEx( char * pszName, const char * pszDir,
const char * pszPrefix,
const char * pszExt, ULONG ulAttr );
const char * hb_fsCurDir( USHORT uiDrive );
USHORT hb_fsCurDirBuff( USHORT uiDrive, char * pbyBuffer,
ULONG ulLen );
void hb_fsBaseDirBuff( char * pbyBuffer );
BOOL hb_fsDelete( const char * pszFileName );
BOOL hb_fsFile( const char * pszFileName );
BOOL hb_fsIsDirectory( const char * pszFilename );
HB_FOFFSET hb_fsFSize( const char * pszFileName, BOOL bUseDirEntry );
HB_FHANDLE hb_fsExtOpen( const char * pszFileName,
const char * pDefExt,
char * hb_fsExtName( const char * pFilename,
const char * pDefExt, USHORT uiExFlags,
const char * pPaths );
BOOL hb_fsMkDir( const char * pszDirName );
HB_FHANDLE hb_fsOpen( const char * pszFileName, USHORT uiFlags );
BOOL hb_fsRmDir( const char * pszDirName );
BOOL hb_fsRename( const char * pszOldName,
const char * pszNewName );
BOOL hb_fsGetFileTime( const char * pszFileName,
LONG * plJulian, LONG * plMillisec );
BOOL hb_fsSetFileTime( const char * pszFileName,
LONG lJulian, LONG lMillisec );
BOOL hb_fsGetAttr( const char * pszFileName, ULONG * pulAttr );
BOOL hb_fsSetAttr( const char * pszFileName, ULONG ulAttr );
HB_FHANDLE hb_fsPOpen( const char * pFilename, const char * pMode );
BOOL hb_fsCopy( const char * pSource, const char * pDest );
BOOL hb_spFile( const char * pFilename, char * pRetPath );
BOOL hb_spFileExists( const char * pFilename, char * pRetPath );
HB_FHANDLE hb_spOpen( const char * pFilename, USHORT uiFlags );
HB_FHANDLE hb_spCreate( const char * pFilename, ULONG ulAttr );
HB_FHANDLE hb_spCreateEx( const char * pFilename,
ULONG ulAttr, USHORT uiFlags );
PHB_FILE hb_fileExtOpen( const char * pFilename,
const char * pDefExt, USHORT uiExFlags,
const char * pPaths, PHB_ITEM pError );
PHB_FILE hb_fileCreateTemp( const char * pszDir,
const char * pszPrefix,
ULONG ulAttr, char * pszName );
PHB_FILE hb_fileCreateTempEx( char * pszName, const char * pszDir,
const char * pszPrefix,
const char * pszExt, ULONG ulAttr );
HB_ERRCODE hb_gtBox( SHORT uiTop, SHORT uiLeft, SHORT uiBottom,
SHORT uiRight, const BYTE * pbyFrame );
HB_ERRCODE hb_gtDrawBox( SHORT uiTop, SHORT uiLeft, SHORT uiBottom,
SHORT uiRight, const BYTE * pbyFrame,
int iColor );
HB_ERRCODE hb_gtWrite( const BYTE * pbyStr, ULONG ulLen );
HB_ERRCODE hb_gtWriteAt( USHORT uiRow, USHORT uiCol,
const BYTE * pbyStr, ULONG ulLen );
HB_ERRCODE hb_gtWriteCon( const BYTE * pbyStr, ULONG ulLen );
HB_ERRCODE hb_gtPutText( USHORT uiRow, USHORT uiCol,
const BYTE * pStr, ULONG ulLength,
int iColor );
HB_ERRCODE hb_gtOutStd( const BYTE * pbyStr, ULONG ulLen );
HB_ERRCODE hb_gtOutErr( const BYTE * pbyStr, ULONG ulLen );
HB_ERRCODE hb_gtBoxEx( int iTop, int iLeft, int iBottom, int iRight,
const BYTE * pbyFrame, int iColor );
void hb_mouseRestoreState( const BYTE * pBuffer );
const char * hb_strLTrim( const char * szText, ULONG * ulLen );
const char * hb_conNewLine( void );
const char * hb_conSetColor( const char * szColor );
const char * hb_errGetDescription( PHB_ITEM pError );
const char * hb_errGetFileName( PHB_ITEM pError );
const char * hb_errGetOperation( PHB_ITEM pError );
const char * hb_errGetSubSystem( PHB_ITEM pError );
int hb_ctwAddWindowBox( int iWindow, const BYTE * szBox, int iColor );
const char *ct_at_exact_forward
( const char *pcString, size_t sStrLen,
const char *pcMatch, size_t sMatchLen,
size_t *psMatchStrLen );
const char *ct_at_exact_backward
( const char *pcString, size_t sStrLen,
const char *pcMatch, size_t sMatchLen,
size_t *psMatchStrLen );
const char *ct_at_wildcard_forward
( const char *pcString, size_t sStrLen,
const char *pcMatch, size_t sMatchLen,
char cWildCard, size_t *psMatchStrLen );
const char *ct_at_wildcard_backward
( const char *pcString, size_t sStrLen,
const char *pcMatch, size_t sMatchLen,
char cWildCard, size_t *psMatchStrLen );
const char *ct_at_charset_forward
( const char *pcString, size_t sStrLen,
const char *pcCharSet, size_t sCharSetLen,
size_t *psMatchedCharPos );
const char *ct_at_charset_backward
( const char *pcString, size_t sStrLen,
const char *pcCharSet, size_t sCharSetLen,
size_t *psMatchedCharPos );
char * hb_adsOemToAnsi( const char * pcString, ULONG ulLen );
char * hb_adsAnsiToOem( const char * pcString, ULONG ulLen );
struct hb_BTree * hb_BTreeNew( const char *FileName,
USHORT usPageSize, USHORT usKeySize,
ULONG ulFlags, USHORT usBuffers );
struct hb_BTree * hb_BTreeOpen( const char *FileName, ULONG lFlags,
USHORT usBuffers );
BOOL hb_BTreeInsert( struct hb_BTree * pBTree, const char * szKey,
PHB_ITEM pData );
BOOL hb_BTreeDelete( struct hb_BTree * pBTree, const char * szKey,
LONG lData );
BOOL hb_BTreeSeek( struct hb_BTree * pBTree, const char * szKey,
LONG lData, BOOL bSoftSeek );
const char * hb_BTreeKey( struct hb_BTree * pBTree );
* modified RDD methods:
HB_ERRCODE PUTVALUEFILE( AREAP, USHORT, const char *, USHORT );
HB_ERRCODE GETVALUEFILE( AREAP, USHORT, const char *, USHORT );
* modified GT methods:
void REST( HB_GT_PTR, int, int, int, int, const BYTE * );
void PUTTEXT( HB_GT_PTR, int, int, BYTE, const BYTE *, ULONG );
void WRITEAT( HB_GT_PTR, int, int, const BYTE *, ULONG );
void WRITE( HB_GT_PTR, const BYTE *, ULONG );
void WRITECON( HB_GT_PTR, const BYTE *, ULONG );
void BOX( HB_GT_PTR, int, int, int, int, const BYTE *, BYTE );
void BOXD( HB_GT_PTR, int, int, int, int, const BYTE *, BYTE );
void BOXS( HB_GT_PTR, int, int, int, int, const BYTE *, BYTE );
void OUTSTD( HB_GT_PTR, BYTE *, ULONG );
void OUTERR( HB_GT_PTR, BYTE *, ULONG );
void MOUSERESTORESTATE( HB_GT_PTR, const BYTE * );
* modified RDD structers:
DBFIELDINFO, DBOPENINFO, DBORDERCONDINFO, DBCONSTRAINTINFO,
DBORDERCREATEINFO
+ modified parameters and behevior:
const char * hb_fsNameConv( const char * szFileName, char ** pszFree );
const char * hb_osEncode( const char * szFileName, char ** pszFree );
const char * hb_osDecode( const char * szFileName, char ** pszFree );
Please look at implementation and current usage of these functions.
+ added new function:
BOOL hb_itemGetWriteCL( PHB_ITEM pItem,
char ** pszValue, ULONG * pulLen );
which converts item string buffer to writable state to use with
functions like FREAD() instead of hb_itemUnShare*()
* updatd other code to respect above modifications
! fixed bugs (also GPF traps) located by above modifications
TODO: please make build tests. Especially in OS2 - not tested at all.
2206 lines
52 KiB
C
2206 lines
52 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"
|
|
#include "hbvm.h"
|
|
|
|
/* Compile in Unix mode under Cygwin */
|
|
#if defined( HB_OS_UNIX_COMPATIBLE )
|
|
#undef HB_OS_WIN
|
|
#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 )
|
|
#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 <errno.h>
|
|
#if defined( HB_OS_OS2 )
|
|
#if defined( __WATCOMC__ )
|
|
#include <types.h>
|
|
#include <nerrno.h>
|
|
#endif
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/select.h>
|
|
#include <sys/ioctl.h>
|
|
#else
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#endif
|
|
#include <netdb.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <unistd.h>
|
|
|
|
#if ! defined( h_errno )
|
|
#if defined( __WATCOMC__ )
|
|
#define h_errno errno
|
|
#else
|
|
extern int h_errno;
|
|
#endif
|
|
#endif
|
|
#define HB_INET_CLOSE( x ) close( x )
|
|
#endif
|
|
|
|
typedef struct _HB_SOCKET_STRUCT
|
|
{
|
|
HB_SOCKET_T com;
|
|
char errorDesc_buffer[ 128 ];
|
|
const 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 )
|
|
#if defined( _MSC_VER ) && _MSC_VER >= 1400
|
|
#define HB_SOCKET_SET_ERROR( s ) \
|
|
do { \
|
|
s->errorCode = WSAGetLastError(); \
|
|
strerror_s( s->errorDesc_buffer, sizeof( s->errorDesc_buffer ), s->errorCode ); \
|
|
s->errorDesc = s->errorDesc_buffer; \
|
|
WSASetLastError( 0 ); \
|
|
} while( 0 )
|
|
#else
|
|
#define HB_SOCKET_SET_ERROR( s ) \
|
|
do { \
|
|
s->errorCode = WSAGetLastError(); \
|
|
s->errorDesc = strerror( s->errorCode ); \
|
|
WSASetLastError( 0 ); \
|
|
} while( 0 )
|
|
#endif
|
|
#else
|
|
#define HB_SOCKET_SET_ERROR( s ) \
|
|
do { \
|
|
s->errorCode = errno; \
|
|
s->errorDesc = strerror( errno ); \
|
|
} while( 0 )
|
|
#endif
|
|
|
|
#if defined( _MSC_VER ) && _MSC_VER >= 1400
|
|
#define HB_SOCKET_SET_ERROR1( s, code ) \
|
|
do { \
|
|
s->errorCode = code; \
|
|
strerror_s( s->errorDesc_buffer, sizeof( s->errorDesc_buffer ), code ); \
|
|
s->errorDesc = s->errorDesc_buffer; \
|
|
} while( 0 )
|
|
#else
|
|
#define HB_SOCKET_SET_ERROR1( s, code ) \
|
|
do { \
|
|
s->errorCode = code; \
|
|
s->errorDesc = strerror( code ); \
|
|
} while( 0 )
|
|
#endif
|
|
#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_OS_WIN_CE )
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#endif
|
|
|
|
#if defined( HB_OS_UNIX ) || defined( HB_OS_UNIX_COMPATIBLE ) || defined( HB_OS_OS2 )
|
|
#include <sys/time.h>
|
|
#endif
|
|
|
|
|
|
#if defined( HB_OS_OS2 ) || defined( HB_OS_WIN )
|
|
/* 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 32-bit quantity and
|
|
* "size_t *" is frequently a pointer to a 64-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
|
|
|
|
#if defined( __POCC__ ) && ( __POCC__ >= 500 ) && defined( HB_OS_WIN_64 )
|
|
/* TOFIX: Bad workaround for the '__WSAFDIsSet unresolved' problem
|
|
in Pelles C 5.00.13 AMD64 mode, to make final executables
|
|
link at all. Some hbinet.c features (or the whole module)
|
|
won't properly work though. [vszakats] */
|
|
#undef FD_ISSET
|
|
#define FD_ISSET( s, f ) ( 0 )
|
|
#endif
|
|
|
|
#if defined( HB_OS_LINUX )
|
|
#include <signal.h>
|
|
/* #define HB_INET_LINUX_INTERRUPT SIGUSR1+90 */
|
|
# ifdef HB_INET_LINUX_INTERRUPT
|
|
static void hb_inetLinuxSigusrHandle( int sig )
|
|
{
|
|
/* nothing to do */
|
|
HB_SYMBOL_UNUSED( sig );
|
|
}
|
|
# endif
|
|
#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;
|
|
int iResult;
|
|
|
|
hb_vmUnlock();
|
|
|
|
FD_ZERO( &set );
|
|
FD_SET( Socket->com, &set );
|
|
|
|
if( Socket->timeout == -1 )
|
|
{
|
|
iResult = select( Socket->com + 1, &set, NULL, NULL, NULL );
|
|
}
|
|
else
|
|
{
|
|
tv.tv_sec = Socket->timeout / 1000;
|
|
tv.tv_usec = ( Socket->timeout % 1000 ) * 1000;
|
|
iResult = select( Socket->com + 1, &set, NULL, NULL, &tv );
|
|
}
|
|
|
|
hb_vmLock();
|
|
|
|
return iResult > 0 ? FD_ISSET( Socket->com, &set ) : 0;
|
|
}
|
|
|
|
static int hb_selectWriteSocket( HB_SOCKET_STRUCT * Socket )
|
|
{
|
|
fd_set set;
|
|
struct timeval tv;
|
|
int iResult;
|
|
|
|
hb_vmUnlock();
|
|
|
|
FD_ZERO( &set );
|
|
FD_SET( Socket->com, &set );
|
|
|
|
if( Socket->timeout == -1 )
|
|
{
|
|
iResult = select( Socket->com + 1, NULL, &set, NULL, NULL );
|
|
}
|
|
else
|
|
{
|
|
tv.tv_sec = Socket->timeout / 1000;
|
|
tv.tv_usec = ( Socket->timeout % 1000 ) * 1000;
|
|
iResult = select( Socket->com + 1, NULL, &set, NULL, &tv );
|
|
}
|
|
|
|
hb_vmLock();
|
|
|
|
return iResult > 0 ? FD_ISSET( Socket->com, &set ) : 0;
|
|
}
|
|
|
|
#if defined( HB_OS_WIN )
|
|
static int hb_selectWriteExceptSocket( HB_SOCKET_STRUCT * Socket )
|
|
{
|
|
fd_set set, eset;
|
|
struct timeval tv;
|
|
int iResult;
|
|
|
|
hb_vmUnlock();
|
|
|
|
FD_ZERO( &set );
|
|
FD_SET( Socket->com, &set );
|
|
FD_ZERO( &eset );
|
|
FD_SET( Socket->com, &eset );
|
|
|
|
if( Socket->timeout == -1 )
|
|
{
|
|
iResult = select( Socket->com + 1, NULL, &set, &eset, NULL );
|
|
}
|
|
else
|
|
{
|
|
tv.tv_sec = Socket->timeout / 1000;
|
|
tv.tv_usec = ( Socket->timeout % 1000 ) * 1000;
|
|
iResult = select( Socket->com + 1, NULL, &set, &eset, &tv );
|
|
}
|
|
|
|
hb_vmLock();
|
|
|
|
if( iResult < 0 || FD_ISSET( Socket->com, &eset) )
|
|
return 2;
|
|
else if( FD_ISSET( Socket->com, &set ) )
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/*** Utilty to access host DNS */
|
|
static struct hostent * hb_getHosts( const char * name, HB_SOCKET_STRUCT * Socket )
|
|
{
|
|
struct hostent * Host = NULL;
|
|
|
|
hb_vmUnlock();
|
|
|
|
/* TOFIX: make it MT safe */
|
|
|
|
/* let's see if name is an IP address; not necessary on Linux */
|
|
#if defined( HB_OS_WIN ) || 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 )
|
|
{
|
|
#if defined( HB_OS_WIN )
|
|
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
|
|
}
|
|
|
|
hb_vmLock();
|
|
|
|
return Host;
|
|
}
|
|
|
|
|
|
/*** Setup the non-blocking method **/
|
|
|
|
static void hb_socketSetNonBlocking( HB_SOCKET_STRUCT * Socket )
|
|
{
|
|
#if defined( HB_OS_WIN )
|
|
ULONG mode = 1;
|
|
ioctlsocket( Socket->com, FIONBIO, &mode );
|
|
#elif defined( O_NONBLOCK )
|
|
int flags = fcntl( Socket->com, F_GETFL, 0 );
|
|
if( flags != -1 )
|
|
{
|
|
flags |= O_NONBLOCK;
|
|
fcntl( Socket->com, F_SETFL, (LONG) flags );
|
|
}
|
|
#else
|
|
HB_SYMBOL_UNUSED( Socket );
|
|
#endif
|
|
}
|
|
|
|
|
|
/*** Setup the blocking method **/
|
|
|
|
static void hb_socketSetBlocking( HB_SOCKET_STRUCT * Socket )
|
|
{
|
|
#if defined( HB_OS_WIN )
|
|
ULONG mode = 0;
|
|
ioctlsocket( Socket->com, FIONBIO, &mode );
|
|
#elif defined( O_NONBLOCK )
|
|
int flags = fcntl( Socket->com, F_GETFL, 0 );
|
|
if( flags != -1 )
|
|
{
|
|
flags &= ~O_NONBLOCK;
|
|
fcntl( Socket->com, F_SETFL, ( long ) flags );
|
|
}
|
|
#else
|
|
HB_SYMBOL_UNUSED( Socket );
|
|
#endif
|
|
}
|
|
|
|
/*** Utility to connect to a defined remote address ***/
|
|
|
|
static int hb_socketConnect( HB_SOCKET_STRUCT * Socket )
|
|
{
|
|
int iErr1;
|
|
#if ! defined( HB_OS_WIN )
|
|
int iErrval;
|
|
socklen_t iErrvalLen;
|
|
#endif
|
|
int iOpt = 1;
|
|
|
|
hb_vmUnlock();
|
|
|
|
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 * ) ( void * ) &Socket->remote, sizeof( Socket->remote ) );
|
|
if( iErr1 != 0 )
|
|
{
|
|
#if defined( HB_OS_WIN )
|
|
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 )
|
|
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 );
|
|
|
|
hb_vmLock();
|
|
|
|
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 )
|
|
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 )
|
|
{
|
|
hb_itemRelease( Socket->caPeriodic );
|
|
Socket->caPeriodic = NULL;
|
|
}
|
|
}
|
|
|
|
/*****************************************************
|
|
* Socket Initialization
|
|
***/
|
|
|
|
HB_FUNC( HB_INETINIT )
|
|
{
|
|
if( s_iSessions )
|
|
{
|
|
s_iSessions++;
|
|
}
|
|
else
|
|
{
|
|
#if defined( HB_OS_WIN )
|
|
#define HB_MKWORD( l, h ) ((WORD)(((BYTE)(l)) | (((WORD)((BYTE)(h))) << 8)))
|
|
WSADATA wsadata;
|
|
WSAStartup( HB_MKWORD( 1, 1 ), &wsadata );
|
|
#elif defined( HB_INET_LINUX_INTERRUPT )
|
|
signal( HB_INET_LINUX_INTERRUPT, hb_inetLinuxSigusrHandle );
|
|
#endif
|
|
s_iSessions = 1;
|
|
}
|
|
}
|
|
|
|
HB_FUNC( HB_INETCLEANUP )
|
|
{
|
|
if( --s_iSessions == 0 )
|
|
{
|
|
#if defined( HB_OS_WIN )
|
|
WSACleanup();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*****************************************************
|
|
* Socket Creation and destruction
|
|
***/
|
|
|
|
HB_FUNC( HB_INETCREATE )
|
|
{
|
|
PHB_ITEM pSocket = NULL;
|
|
HB_SOCKET_STRUCT * Socket;
|
|
HB_SOCKET_INIT( Socket, pSocket );
|
|
|
|
if( HB_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 )
|
|
{
|
|
hb_vmUnlock();
|
|
|
|
#if defined( HB_OS_WIN )
|
|
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_INET_LINUX_INTERRUPT
|
|
kill( 0, HB_INET_LINUX_INTERRUPT );
|
|
#endif
|
|
|
|
hb_vmLock();
|
|
}
|
|
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( HB_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 )
|
|
{
|
|
hb_retni( Socket->timeout );
|
|
if( HB_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( HB_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 )
|
|
getsockopt( Socket->com, SOL_SOCKET, SO_SNDBUF, ( char * ) &value, &len );
|
|
#else
|
|
getsockopt( Socket->com, SOL_SOCKET, SO_SNDBUF, ( void * ) &value, &len );
|
|
#endif
|
|
hb_retni( value );
|
|
}
|
|
}
|
|
|
|
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 )
|
|
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 )
|
|
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 )
|
|
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;
|
|
ULONG ulLen;
|
|
int iLen, iMaxLen, iReceived;
|
|
int iTimeElapsed;
|
|
|
|
if( Socket == NULL || pBuffer == NULL || ! HB_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;
|
|
}
|
|
|
|
if( hb_itemGetWriteCL( pBuffer, &buffer, &ulLen ) )
|
|
iLen = ( int ) ulLen;
|
|
else
|
|
{
|
|
iLen = 0;
|
|
buffer = NULL;
|
|
}
|
|
|
|
if( !HB_ISNUM( 3 ) )
|
|
{
|
|
iMaxLen = iLen;
|
|
}
|
|
else
|
|
{
|
|
iMaxLen = hb_parni( 3 );
|
|
if( iLen < iMaxLen )
|
|
iMaxLen = iLen;
|
|
}
|
|
|
|
hb_vmUnlock();
|
|
|
|
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;
|
|
|
|
hb_vmLock();
|
|
|
|
/* if we have a caPeriodic, timeLimit is our REAL timeout */
|
|
if( Socket->caPeriodic )
|
|
{
|
|
hb_execFromArray( Socket->caPeriodic );
|
|
|
|
/* do we continue? */
|
|
if( ! hb_parl( -1 ) || hb_vmRequestQuery() != 0 ||
|
|
( 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;
|
|
}
|
|
|
|
hb_vmUnlock();
|
|
}
|
|
}
|
|
while( iReceived < iMaxLen && iLen > 0 );
|
|
|
|
Socket->count = iReceived;
|
|
|
|
hb_vmLock();
|
|
|
|
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( const 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 = '\0';
|
|
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;
|
|
}
|
|
|
|
iBufferSize = pBufferSize ? hb_itemGetNI( pBufferSize ) : 80;
|
|
iMax = pMaxSize ? hb_itemGetNI( pMaxSize ) : 0;
|
|
|
|
hb_vmUnlock();
|
|
|
|
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 )
|
|
{
|
|
BOOL fResult;
|
|
|
|
hb_vmLock();
|
|
hb_execFromArray( Socket->caPeriodic );
|
|
fResult = hb_parl( -1 ) && hb_vmRequestQuery() == 0;
|
|
hb_vmUnlock();
|
|
|
|
/* do we continue? */
|
|
if( fResult &&
|
|
( 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 );
|
|
|
|
hb_vmLock();
|
|
|
|
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 = '\0';
|
|
char * Buffer;
|
|
const 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 = ( const 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 = ( const 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 = ( const 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_vmUnlock();
|
|
|
|
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 )
|
|
{
|
|
BOOL fResult;
|
|
|
|
hb_vmLock();
|
|
hb_execFromArray( Socket->caPeriodic );
|
|
fResult = hb_parl( -1 ) && hb_vmRequestQuery() == 0;
|
|
hb_vmUnlock();
|
|
|
|
if( fResult &&
|
|
( 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 );
|
|
|
|
hb_vmLock();
|
|
|
|
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 && ! HB_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;
|
|
}
|
|
|
|
if( HB_ISNUM( 2 ) )
|
|
{
|
|
iVal = hb_parni( 2 );
|
|
tv.tv_sec = iVal / 1000;
|
|
tv.tv_usec = ( iVal % 1000 ) * 1000;
|
|
}
|
|
|
|
hb_vmUnlock();
|
|
|
|
HB_SOCKET_ZERO_ERROR( Socket );
|
|
|
|
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_vmLock();
|
|
|
|
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 );
|
|
const 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( HB_ISNUM( 3 ) )
|
|
{
|
|
iLen = hb_parni( 3 );
|
|
if( iLen < iSend )
|
|
iSend = iLen;
|
|
}
|
|
|
|
hb_vmUnlock();
|
|
|
|
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_vmLock();
|
|
|
|
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 )
|
|
{
|
|
const 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 )
|
|
{
|
|
const 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;
|
|
const char * szAddress;
|
|
int iPort;
|
|
int iOpt = 1;
|
|
int iListen;
|
|
|
|
/* Parameter error checking */
|
|
if( ! HB_ISNUM( 1 ) || ( Socket == NULL && ! HB_ISNIL( 2 ) ) )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
|
|
if( Socket )
|
|
HB_SOCKET_ZERO_ERROR( Socket );
|
|
else
|
|
HB_SOCKET_INIT( Socket, pSocket );
|
|
|
|
/* Creates comm socket */
|
|
#if defined( HB_OS_WIN )
|
|
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 = HB_ISNUM( 3 ) ? hb_parni( 3 ) : 10;
|
|
|
|
hb_vmUnlock();
|
|
|
|
if( bind( Socket->com, ( struct sockaddr * ) ( void * ) &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;
|
|
}
|
|
|
|
hb_vmLock();
|
|
|
|
if( pSocket )
|
|
hb_itemReturnRelease( pSocket );
|
|
else
|
|
hb_itemReturn( hb_param( 2, HB_IT_ANY ) );
|
|
}
|
|
|
|
HB_FUNC( HB_INETACCEPT )
|
|
{
|
|
#ifndef 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;
|
|
socklen_t Len;
|
|
|
|
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;
|
|
|
|
hb_vmUnlock();
|
|
|
|
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 * ) ( void * ) &si_remote, &Len );
|
|
|
|
if( incoming == ( HB_SOCKET_T ) -1 )
|
|
{
|
|
#if defined( HB_OS_WIN )
|
|
iError = WSAGetLastError();
|
|
#else
|
|
iError = errno;
|
|
#endif
|
|
}
|
|
else
|
|
iError = 0;
|
|
}
|
|
else
|
|
iError = -1; /* Timeout expired */
|
|
}
|
|
|
|
hb_vmLock();
|
|
|
|
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 )
|
|
{
|
|
const char * szHost = hb_parc( 1 );
|
|
HB_SOCKET_STRUCT * Socket = HB_PARSOCKET( 3 );
|
|
PHB_ITEM pSocket = NULL;
|
|
struct hostent * Host;
|
|
int iPort;
|
|
|
|
if( szHost == NULL || ! HB_ISNUM( 2 ) || ( Socket == NULL && ! HB_ISNIL( 3 ) ) )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
|
|
if( Socket )
|
|
{
|
|
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 )
|
|
{
|
|
/* Creates comm socket */
|
|
#if defined( HB_OS_WIN )
|
|
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 )
|
|
{
|
|
const 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 && ! HB_ISNIL( 3 ) ) )
|
|
{
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return;
|
|
}
|
|
|
|
if( Socket )
|
|
{
|
|
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 )
|
|
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;
|
|
const char * szAddress;
|
|
|
|
/* Parameter error checking */
|
|
if( iPort == 0 || ( hb_pcount() > 3 && ! HB_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 )
|
|
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;
|
|
|
|
hb_vmUnlock();
|
|
|
|
if( bind( Socket->com, ( struct sockaddr * ) ( void * ) &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_vmLock();
|
|
|
|
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 )
|
|
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 );
|
|
const char * szAddress = hb_parc( 2 );
|
|
int iPort = hb_parni( 3 );
|
|
PHB_ITEM pBuffer = hb_param( 4, HB_IT_STRING );
|
|
int iLen;
|
|
const 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( HB_ISNUM( 5 ) )
|
|
{
|
|
int iMaxLen = hb_parni( 5 );
|
|
|
|
if( iMaxLen < iLen )
|
|
iLen = iMaxLen;
|
|
}
|
|
|
|
hb_vmUnlock();
|
|
|
|
HB_SOCKET_ZERO_ERROR( Socket );
|
|
|
|
Socket->count = 0;
|
|
if( hb_selectWriteSocket( Socket ) )
|
|
{
|
|
Socket->count = sendto( Socket->com, szBuffer, iLen, 0,
|
|
( const struct sockaddr * ) ( void * ) &Socket->remote, sizeof( Socket->remote ) );
|
|
}
|
|
|
|
hb_vmLock();
|
|
|
|
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;
|
|
ULONG ulLen;
|
|
BOOL fRepeat;
|
|
socklen_t iDtLen = ( socklen_t ) sizeof( struct sockaddr );
|
|
|
|
if( Socket == NULL || pBuffer == NULL || ! HB_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;
|
|
}
|
|
|
|
if( hb_itemGetWriteCL( pBuffer, &Buffer, &ulLen ) )
|
|
iLen = ( int ) ulLen;
|
|
else
|
|
{
|
|
iLen = 0;
|
|
Buffer = NULL;
|
|
}
|
|
|
|
if( !HB_ISNUM( 3 ) )
|
|
{
|
|
iMaxLen = iLen;
|
|
}
|
|
else
|
|
{
|
|
iMaxLen = hb_parni( 3 );
|
|
if( iLen < iMaxLen )
|
|
iMaxLen = iLen;
|
|
}
|
|
|
|
hb_vmUnlock();
|
|
|
|
HB_SOCKET_ZERO_ERROR( Socket );
|
|
|
|
do
|
|
{
|
|
fRepeat = FALSE;
|
|
iLen = -2;
|
|
if( hb_selectReadSocket( Socket ) )
|
|
{
|
|
iLen = recvfrom( Socket->com, Buffer, iMaxLen, 0,
|
|
( struct sockaddr * ) ( void * ) &Socket->remote, &iDtLen );
|
|
}
|
|
iTimeElapsed += Socket->timeout;
|
|
if( Socket->caPeriodic )
|
|
{
|
|
hb_vmLock();
|
|
hb_execFromArray( Socket->caPeriodic );
|
|
/* do we continue? */
|
|
fRepeat = hb_parl( -1 ) && hb_vmRequestQuery() == 0 &&
|
|
( Socket->timelimit == -1 || iTimeElapsed < Socket->timelimit );
|
|
hb_vmUnlock();
|
|
}
|
|
}
|
|
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_vmLock();
|
|
|
|
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 */
|