Files
harbour-core/harbour/source/rtl/hbinet.c
Przemyslaw Czerpak c3e1436da0 2009-06-26 02:22 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* 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.
2009-06-26 00:33:38 +00:00

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