* harbour/include/hbapifs.h
* harbour/src/rtl/filesys.c
% removed unnecessary PID setting in POSIX file lock function.
+ added new C function:
int hb_fsLockTest( HB_FHANDLE hFileHandle, HB_FOFFSET nStart,
HB_FOFFSET nLength, HB_USHORT uiMode );
It allows to test file range lock status.
It returns -1 on error, 0 when lock can be set and value greater
then 0 if part of given range is locked by other process. In POSIX
systems this value is PID of current lock owner. In other systems
it's always 1.
In uiMode only FLX_SHARED bit is significant.
* harbour/include/hbapifs.h
* harbour/src/rtl/filebuf.c
+ added new C function:
int hb_fileLockTest( PHB_FILE pFile, HB_FOFFSET nStart,
HB_FOFFSET nLen, int iType );
It's redirected to hb_fsLockTest()
* harbour/contrib/hbnetio/netio.h
* harbour/contrib/hbnetio/netiocli.c
* harbour/contrib/hbnetio/netiosrv.c
* harbour/contrib/hbmemio/memio.c
+ implemented hb_fileLockTest() low level code
* harbour/include/dbinfo.ch
+ added DBI_LOCKTEST
* harbour/src/rdd/dbf1.c
% small code simplification
+ implemented DBI_LOCKTEST
dbInfo( DBI_LOCKTEST [, <nRecNo> ] ) -> <nStatus>
returns corresponding results to C level hb_fsLockTest() function.
If current workarea is already locked then 0 is returned.
If low level FS is located on POSIX system (accessed directly or by
HBNETIO) then value greater then 0 is PID of current lock owner.
If the lock is hold by aliased area or other thread of calling
process then <nStatus> is current PID. In Other systems 1 is returned
when lock cannot be set in current workarea.
If <nRecNo> is given then the test is for RLOCK() otherwise FLOCK()
operation.
1451 lines
47 KiB
C
1451 lines
47 KiB
C
/*
|
|
* $Id$
|
|
*/
|
|
|
|
/*
|
|
* Harbour Project source code:
|
|
* demonstration code for alternative RDD IO API which uses own
|
|
* very simple TCP/IP file server with RPC support
|
|
* All files which names starts 'net:' are redirected to this API.
|
|
* This is server code giving the following .prg functions:
|
|
* NETIO_LISTEN( [<nPort>], [<cAddress>], [<cRootDir>], [<lRPC>] )
|
|
* -> <pListenSocket> | NIL
|
|
* NETIO_ACCEPT( <pListenSocket>, [<nTimeOut>],
|
|
* [<cPass>], [<nCompressionLevel>], [<nStrategy>] )
|
|
* -> <pConnectionSocket> | NIL
|
|
* NETIO_COMPRESS( <pConnectionSocket>,
|
|
* [<cPass>], [<nCompressionLevel>], [<nStrategy>] )
|
|
* -> NIL
|
|
* NETIO_SERVER( <pConnectionSocket> ) -> NIL
|
|
* NETIO_SERVERSTOP( <pListenSocket> | <pConnectionSocket> [, <lStop>] )
|
|
* -> NIL
|
|
* NETIO_RPC( <pListenSocket> | <pConnectionSocket> [, <lEnable>] )
|
|
* -> <lPrev>
|
|
* NETIO_RPCFILTER( <pConnectionSocket>,
|
|
* <sFuncSym> | <hValue> | NIL ) -> NIL
|
|
*
|
|
* NETIO_SRVSTATUS( <pConnectionSocket> [, <nStreamID>] ) -> <nStatus>
|
|
* NETIO_SRVSENDITEM( <pConnectionSocket>, <nStreamID>, <xData> )
|
|
* -> <lSent>
|
|
* NETIO_SRVSENDDATA( <pConnectionSocket>, <nStreamID>, <cData> )
|
|
* -> <lSent>
|
|
*
|
|
* Copyright 2009 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
|
|
* www - http://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 "hbapifs.h"
|
|
#include "hbapierr.h"
|
|
#include "hbsocket.h"
|
|
#include "hbznet.h"
|
|
#include "hbzlib.ch"
|
|
#include "hbinit.h"
|
|
#include "hbvm.h"
|
|
#include "hbstack.h"
|
|
#include "hbthread.h"
|
|
#include "netio.h"
|
|
|
|
|
|
/*
|
|
* server code
|
|
*/
|
|
|
|
typedef struct _HB_CONSTREAM
|
|
{
|
|
int id;
|
|
int type;
|
|
struct _HB_CONSTREAM * next;
|
|
}
|
|
HB_CONSTREAM, * PHB_CONSTREAM;
|
|
|
|
typedef struct _HB_CONSRV
|
|
{
|
|
HB_SOCKET sd;
|
|
PHB_ZNETSTREAM zstream;
|
|
PHB_FILE fileTable[ NETIO_FILES_MAX ];
|
|
int filesCount;
|
|
int firstFree;
|
|
HB_BOOL stop;
|
|
HB_BOOL rpc;
|
|
HB_BOOL login;
|
|
PHB_SYMB rpcFunc;
|
|
PHB_ITEM rpcFilter;
|
|
PHB_ITEM mutex;
|
|
PHB_CONSTREAM streams;
|
|
HB_MAXUINT wr_count;
|
|
HB_MAXUINT rd_count;
|
|
int rootPathLen;
|
|
char rootPath[ HB_PATH_MAX ];
|
|
}
|
|
HB_CONSRV, * PHB_CONSRV;
|
|
|
|
typedef struct _HB_LISTENSD
|
|
{
|
|
HB_SOCKET sd;
|
|
HB_BOOL stop;
|
|
HB_BOOL rpc;
|
|
char rootPath[ HB_PATH_MAX ];
|
|
}
|
|
HB_LISTENSD, * PHB_LISTENSD;
|
|
|
|
static HB_BOOL s_isDirSep( char c )
|
|
{
|
|
/* intentionally used explicit values instead of harbour macros
|
|
* because client can use different OS
|
|
*/
|
|
return c == '/' || c == '\\';
|
|
}
|
|
|
|
static const char * s_consrvFilePath( char * pszFileName, PHB_CONSRV conn )
|
|
{
|
|
int iPos = 0, iLevel = 0;
|
|
char ch = HB_OS_PATH_DELIM_CHR;
|
|
|
|
if( conn->rootPathLen )
|
|
{
|
|
while( s_isDirSep( pszFileName[ 0 ] ) )
|
|
++pszFileName;
|
|
}
|
|
|
|
while( pszFileName[ iPos ] && iLevel >= 0 )
|
|
{
|
|
if( conn->rootPathLen && s_isDirSep( ch ) )
|
|
{
|
|
if( pszFileName[ iPos ] == '.' &&
|
|
pszFileName[ iPos + 1 ] == '.' &&
|
|
( pszFileName[ iPos + 2 ] == '\0' ||
|
|
s_isDirSep( pszFileName[ iPos + 2 ] ) ) )
|
|
--iLevel;
|
|
else if( pszFileName[ iPos ] &&
|
|
!s_isDirSep( pszFileName[ iPos ] ) &&
|
|
!( pszFileName[ iPos ] == '.' &&
|
|
s_isDirSep( pszFileName[ iPos + 1 ] ) ) )
|
|
++iLevel;
|
|
}
|
|
ch = pszFileName[ iPos ];
|
|
if( s_isDirSep( ch ) )
|
|
pszFileName[ iPos ] = HB_OS_PATH_DELIM_CHR;
|
|
++iPos;
|
|
}
|
|
|
|
if( iLevel < 0 )
|
|
pszFileName = NULL;
|
|
else if( conn->rootPathLen )
|
|
{
|
|
memmove( pszFileName + conn->rootPathLen, pszFileName, iPos + 1 );
|
|
memcpy( pszFileName, conn->rootPath, conn->rootPathLen );
|
|
}
|
|
|
|
return pszFileName;
|
|
}
|
|
|
|
static HB_ERRCODE s_srvFsError( void )
|
|
{
|
|
HB_ERRCODE errCode = hb_fsError();
|
|
if( errCode == 0 )
|
|
errCode = NETIO_ERR_FILE_IO;
|
|
return errCode;
|
|
}
|
|
|
|
static int s_srvFileNew( PHB_CONSRV conn, PHB_FILE pFile )
|
|
{
|
|
if( conn->filesCount < NETIO_FILES_MAX )
|
|
{
|
|
while( conn->firstFree < NETIO_FILES_MAX )
|
|
{
|
|
if( conn->fileTable[ conn->firstFree ] == NULL )
|
|
{
|
|
conn->filesCount++;
|
|
conn->fileTable[ conn->firstFree ] = pFile;
|
|
return conn->firstFree;
|
|
}
|
|
conn->firstFree++;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static PHB_FILE s_srvFileFree( PHB_CONSRV conn, int iFile )
|
|
{
|
|
if( iFile < NETIO_FILES_MAX && conn->filesCount > 0 )
|
|
{
|
|
PHB_FILE pFile = conn->fileTable[ iFile ];
|
|
if( pFile )
|
|
{
|
|
conn->fileTable[ iFile ] = NULL;
|
|
conn->filesCount--;
|
|
if( conn->firstFree > iFile )
|
|
conn->firstFree = iFile;
|
|
return pFile;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static PHB_FILE s_srvFileGet( PHB_CONSRV conn, int iFile )
|
|
{
|
|
if( iFile < NETIO_FILES_MAX && conn->filesCount > 0 )
|
|
return conn->fileTable[ iFile ];
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
static void s_consrv_disconnect( PHB_CONSRV conn )
|
|
{
|
|
if( conn->sd != HB_NO_SOCKET )
|
|
{
|
|
hb_socketClose( conn->sd );
|
|
conn->sd = HB_NO_SOCKET;
|
|
}
|
|
|
|
if( conn->zstream )
|
|
{
|
|
hb_znetClose( conn->zstream );
|
|
conn->zstream = NULL;
|
|
}
|
|
}
|
|
|
|
static void s_consrv_close( PHB_CONSRV conn )
|
|
{
|
|
int i = 0;
|
|
|
|
if( conn->rpcFilter )
|
|
hb_itemRelease( conn->rpcFilter );
|
|
|
|
while( conn->streams )
|
|
{
|
|
PHB_CONSTREAM stream = conn->streams;
|
|
conn->streams = stream->next;
|
|
hb_xfree( stream );
|
|
}
|
|
|
|
if( conn->mutex )
|
|
hb_itemRelease( conn->mutex );
|
|
|
|
if( conn->sd != HB_NO_SOCKET )
|
|
hb_socketClose( conn->sd );
|
|
|
|
if( conn->zstream )
|
|
hb_znetClose( conn->zstream );
|
|
|
|
while( conn->filesCount > 0 )
|
|
{
|
|
if( i >= NETIO_FILES_MAX )
|
|
break; /* internal error, it should not happen */
|
|
|
|
if( conn->fileTable[ i ] )
|
|
{
|
|
hb_fileClose( conn->fileTable[ i ] );
|
|
conn->filesCount--;
|
|
}
|
|
++i;
|
|
}
|
|
|
|
hb_xfree( conn );
|
|
}
|
|
|
|
static HB_GARBAGE_FUNC( s_consrv_destructor )
|
|
{
|
|
PHB_CONSRV * conn_ptr = ( PHB_CONSRV * ) Cargo;
|
|
|
|
if( *conn_ptr )
|
|
{
|
|
PHB_CONSRV conn = *conn_ptr;
|
|
*conn_ptr = NULL;
|
|
s_consrv_close( conn );
|
|
}
|
|
}
|
|
|
|
static HB_GARBAGE_FUNC( s_consrv_mark )
|
|
{
|
|
PHB_CONSRV * conn_ptr = ( PHB_CONSRV * ) Cargo;
|
|
|
|
if( *conn_ptr && ( *conn_ptr )->rpcFilter )
|
|
hb_gcMark( ( *conn_ptr )->rpcFilter );
|
|
}
|
|
|
|
static const HB_GC_FUNCS s_gcConSrvFuncs =
|
|
{
|
|
s_consrv_destructor,
|
|
s_consrv_mark
|
|
};
|
|
|
|
static PHB_CONSRV s_consrvParam( int iParam )
|
|
{
|
|
PHB_CONSRV * conn_ptr = ( PHB_CONSRV * ) hb_parptrGC( &s_gcConSrvFuncs,
|
|
iParam );
|
|
|
|
if( conn_ptr && *conn_ptr )
|
|
return *conn_ptr;
|
|
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return NULL;
|
|
}
|
|
|
|
static void s_consrvRet( PHB_CONSRV conn )
|
|
{
|
|
if( conn )
|
|
{
|
|
PHB_CONSRV * conn_ptr = ( PHB_CONSRV * ) hb_gcAllocate( sizeof( PHB_CONSRV ),
|
|
&s_gcConSrvFuncs );
|
|
*conn_ptr = conn;
|
|
hb_retptrGC( conn_ptr );
|
|
}
|
|
else
|
|
hb_ret();
|
|
}
|
|
|
|
static PHB_CONSRV s_consrvNew( HB_SOCKET connsd, const char * szRootPath, HB_BOOL rpc )
|
|
{
|
|
PHB_CONSRV conn = ( PHB_CONSRV ) memset( hb_xgrab( sizeof( HB_CONSRV ) ),
|
|
0, sizeof( HB_CONSRV ) );
|
|
conn->sd = connsd;
|
|
conn->rpc = rpc;
|
|
if( szRootPath )
|
|
{
|
|
hb_strncpy( conn->rootPath, szRootPath, sizeof( conn->rootPath ) - 1 );
|
|
conn->rootPathLen = ( int ) strlen( conn->rootPath );
|
|
}
|
|
|
|
return conn;
|
|
}
|
|
|
|
static long s_srvRecvAll( PHB_CONSRV conn, void * buffer, long len )
|
|
{
|
|
HB_BYTE * ptr = ( HB_BYTE * ) buffer;
|
|
long lRead = 0, l;
|
|
|
|
while( lRead < len && !conn->stop )
|
|
{
|
|
if( conn->zstream )
|
|
l = hb_znetRead( conn->zstream, conn->sd, ptr + lRead, len - lRead, 1000 );
|
|
else
|
|
l = hb_socketRecv( conn->sd, ptr + lRead, len - lRead, 0, 1000 );
|
|
if( l <= 0 )
|
|
{
|
|
if( hb_socketGetError() != HB_SOCKET_ERR_TIMEOUT ||
|
|
hb_vmRequestQuery() != 0 )
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
lRead += l;
|
|
conn->rd_count += l;
|
|
}
|
|
}
|
|
|
|
return lRead;
|
|
}
|
|
|
|
static long s_srvSendAll( PHB_CONSRV conn, void * buffer, long len )
|
|
{
|
|
HB_BYTE * ptr = ( HB_BYTE * ) buffer;
|
|
long lSent = 0, lLast = 1, l;
|
|
|
|
if( !conn->mutex || hb_threadMutexLock( conn->mutex ) )
|
|
{
|
|
while( lSent < len && !conn->stop )
|
|
{
|
|
if( conn->zstream )
|
|
l = hb_znetWrite( conn->zstream, conn->sd, ptr + lSent, len - lSent, -1, &lLast );
|
|
else
|
|
l = lLast = hb_socketSend( conn->sd, ptr + lSent, len - lSent, 0, -1 );
|
|
if( l > 0 )
|
|
{
|
|
lSent += l;
|
|
conn->wr_count += l;
|
|
}
|
|
if( lLast <= 0 )
|
|
{
|
|
if( hb_socketGetError() != HB_SOCKET_ERR_TIMEOUT ||
|
|
hb_vmRequestQuery() != 0 )
|
|
break;
|
|
}
|
|
}
|
|
if( conn->zstream && lLast > 0 && !conn->stop )
|
|
{
|
|
if( hb_znetFlush( conn->zstream, conn->sd, -1 ) != 0 )
|
|
lSent = -1;
|
|
}
|
|
|
|
if( conn->mutex )
|
|
hb_threadMutexUnlock( conn->mutex );
|
|
}
|
|
return lSent;
|
|
}
|
|
|
|
static HB_GARBAGE_FUNC( s_listensd_destructor )
|
|
{
|
|
PHB_LISTENSD * lsd_ptr = ( PHB_LISTENSD * ) Cargo;
|
|
|
|
if( *lsd_ptr )
|
|
{
|
|
PHB_LISTENSD lsd = *lsd_ptr;
|
|
*lsd_ptr = NULL;
|
|
if( lsd->sd != HB_NO_SOCKET )
|
|
{
|
|
hb_socketClose( lsd->sd );
|
|
lsd->sd = HB_NO_SOCKET;
|
|
}
|
|
hb_xfree( lsd );
|
|
}
|
|
}
|
|
|
|
static const HB_GC_FUNCS s_gcListensdFuncs =
|
|
{
|
|
s_listensd_destructor,
|
|
hb_gcDummyMark
|
|
};
|
|
|
|
static PHB_LISTENSD s_listenParam( int iParam, HB_BOOL fError )
|
|
{
|
|
PHB_LISTENSD * lsd_ptr = ( PHB_LISTENSD * )
|
|
hb_parptrGC( &s_gcListensdFuncs, iParam );
|
|
|
|
if( lsd_ptr && *lsd_ptr )
|
|
return *lsd_ptr;
|
|
|
|
if( fError )
|
|
hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
|
|
return NULL;
|
|
}
|
|
|
|
static void s_listenRet( HB_SOCKET sd, const char * szRootPath, HB_BOOL rpc )
|
|
{
|
|
if( sd != HB_NO_SOCKET )
|
|
{
|
|
PHB_LISTENSD lsd, * lsd_ptr;
|
|
int iLen;
|
|
|
|
lsd = ( PHB_LISTENSD ) memset( hb_xgrab( sizeof( HB_LISTENSD ) ),
|
|
0, sizeof( HB_LISTENSD ) );
|
|
lsd->sd = sd;
|
|
lsd->rpc = rpc;
|
|
if( szRootPath )
|
|
hb_strncpy( lsd->rootPath, szRootPath, sizeof( lsd->rootPath ) - 1 );
|
|
else
|
|
hb_fsBaseDirBuff( lsd->rootPath );
|
|
iLen = ( int ) strlen( lsd->rootPath );
|
|
if( iLen > 0 )
|
|
{
|
|
if( !s_isDirSep( lsd->rootPath[ iLen - 1 ] ) )
|
|
{
|
|
if( iLen == sizeof( lsd->rootPath ) - 1 )
|
|
--iLen;
|
|
lsd->rootPath[ iLen ] = HB_OS_PATH_DELIM_CHR;
|
|
}
|
|
}
|
|
lsd_ptr = ( PHB_LISTENSD * ) hb_gcAllocate( sizeof( PHB_LISTENSD ),
|
|
&s_gcListensdFuncs );
|
|
*lsd_ptr = lsd;
|
|
hb_retptrGC( lsd_ptr );
|
|
}
|
|
else
|
|
hb_ret();
|
|
}
|
|
|
|
|
|
/* NETIO_RPC( <pListenSocket> | <pConnectionSocket> [, <lEnable>] ) -> <lPrev>
|
|
*/
|
|
HB_FUNC( NETIO_RPC )
|
|
{
|
|
PHB_LISTENSD lsd = s_listenParam( 1, HB_FALSE );
|
|
HB_BOOL fRPC = HB_FALSE;
|
|
|
|
if( lsd )
|
|
{
|
|
fRPC = lsd->rpc;
|
|
if( HB_ISLOG( 2 ) )
|
|
lsd->rpc = hb_parl( 2 );
|
|
}
|
|
else
|
|
{
|
|
PHB_CONSRV conn = s_consrvParam( 1 );
|
|
if( conn )
|
|
{
|
|
fRPC = conn->rpc;
|
|
if( HB_ISLOG( 2 ) )
|
|
conn->rpc = hb_parl( 2 );
|
|
}
|
|
}
|
|
hb_retl( fRPC );
|
|
}
|
|
|
|
/* NETIO_RPCFILTER( <pConnectionSocket>,
|
|
* <sFuncSym> | <hValue> | NIL ) -> NIL
|
|
*/
|
|
HB_FUNC( NETIO_RPCFILTER )
|
|
{
|
|
PHB_CONSRV conn = s_consrvParam( 1 );
|
|
if( conn )
|
|
{
|
|
if( conn->rpcFilter )
|
|
{
|
|
hb_itemRelease( conn->rpcFilter );
|
|
conn->rpcFilter = NULL;
|
|
}
|
|
conn->rpcFunc = hb_itemGetSymbol( hb_param( 2, HB_IT_SYMBOL ) );
|
|
if( !conn->rpcFunc )
|
|
{
|
|
PHB_ITEM pHash = hb_param( 2, HB_IT_HASH );
|
|
if( pHash )
|
|
{
|
|
conn->rpcFilter = hb_itemNew( pHash );
|
|
hb_gcUnlock( conn->rpcFilter );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* NETIO_SERVERSTOP( <pListenSocket> | <pConnectionSocket> [, <lStop>] ) -> NIL
|
|
*/
|
|
HB_FUNC( NETIO_SERVERSTOP )
|
|
{
|
|
PHB_LISTENSD lsd = s_listenParam( 1, HB_FALSE );
|
|
HB_BOOL fStop = hb_parldef( 2, 1 );
|
|
|
|
if( lsd )
|
|
lsd->stop = fStop;
|
|
else
|
|
{
|
|
PHB_CONSRV conn = s_consrvParam( 1 );
|
|
if( conn )
|
|
conn->stop = fStop;
|
|
}
|
|
}
|
|
|
|
/* NETIO_LISTEN( [<nPort>], [<cIfAddr>], [<cRootDir>], [<lRPC>] )
|
|
* -> <pListenSocket> | NIL
|
|
*/
|
|
HB_FUNC( NETIO_LISTEN )
|
|
{
|
|
static HB_BOOL s_fInit = HB_TRUE;
|
|
|
|
int iPort = hb_parnidef( 1, NETIO_DEFAULT_PORT );
|
|
const char * szAddress = hb_parc( 2 );
|
|
const char * szRootPath = hb_parc( 3 );
|
|
HB_BOOL fRPC = hb_parl( 4 );
|
|
void * pSockAddr;
|
|
unsigned uiLen;
|
|
HB_SOCKET sd = HB_NO_SOCKET;
|
|
|
|
if( s_fInit )
|
|
{
|
|
hb_socketInit();
|
|
s_fInit = HB_FALSE;
|
|
}
|
|
|
|
if( hb_socketInetAddr( &pSockAddr, &uiLen, szAddress, iPort ) )
|
|
{
|
|
sd = hb_socketOpen( HB_SOCKET_PF_INET, HB_SOCKET_PT_STREAM, 0 );
|
|
if( sd != HB_NO_SOCKET )
|
|
{
|
|
if( hb_socketBind( sd, pSockAddr, uiLen ) != 0 ||
|
|
hb_socketListen( sd, 10 ) != 0 )
|
|
{
|
|
hb_socketClose( sd );
|
|
sd = HB_NO_SOCKET;
|
|
}
|
|
}
|
|
hb_xfree( pSockAddr );
|
|
}
|
|
|
|
s_listenRet( sd, szRootPath, fRPC );
|
|
}
|
|
|
|
/* NETIO_ACCEPT( <pListenSocket>, [<nTimeOut>],
|
|
* [<cPass>], [<nCompressionLevel>], [<nStrategy>] )
|
|
* -> <pConnectionSocket> | NIL
|
|
*/
|
|
HB_FUNC( NETIO_ACCEPT )
|
|
{
|
|
PHB_LISTENSD lsd = s_listenParam( 1, HB_TRUE );
|
|
PHB_CONSRV conn = NULL;
|
|
|
|
if( lsd && lsd->sd != HB_NO_SOCKET && !lsd->stop )
|
|
{
|
|
HB_MAXINT timeout = hb_parnintdef( 2, -1 );
|
|
HB_SOCKET connsd;
|
|
int iLevel, iStrategy, keylen = ( int ) hb_parclen( 3 );
|
|
|
|
if( keylen > NETIO_PASSWD_MAX )
|
|
keylen = NETIO_PASSWD_MAX;
|
|
iLevel = hb_parnidef( 4, keylen ? HB_ZLIB_COMPRESSION_DEFAULT :
|
|
HB_ZLIB_COMPRESSION_DISABLE );
|
|
iStrategy = hb_parnidef( 5, HB_ZLIB_STRATEGY_DEFAULT );
|
|
|
|
do
|
|
connsd = hb_socketAccept( lsd->sd, NULL, NULL, timeout < 0 ? 1000 : timeout );
|
|
while( connsd == HB_NO_SOCKET && !lsd->stop && timeout < 0 &&
|
|
hb_socketGetError() == HB_SOCKET_ERR_TIMEOUT &&
|
|
hb_vmRequestQuery() == 0 );
|
|
|
|
if( connsd != HB_NO_SOCKET )
|
|
{
|
|
hb_socketSetKeepAlive( connsd, HB_TRUE );
|
|
hb_socketSetNoDelay( connsd, HB_TRUE );
|
|
conn = s_consrvNew( connsd, lsd->rootPath, lsd->rpc );
|
|
|
|
|
|
if( iLevel != HB_ZLIB_COMPRESSION_DISABLE )
|
|
{
|
|
conn->zstream = hb_znetOpen( iLevel, iStrategy );
|
|
if( conn->zstream != NULL )
|
|
{
|
|
if( keylen )
|
|
hb_znetEncryptKey( conn->zstream, hb_parc( 3 ), keylen );
|
|
}
|
|
else
|
|
{
|
|
s_consrv_close( conn );
|
|
conn = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
s_consrvRet( conn );
|
|
}
|
|
|
|
/* NETIO_COMPRESS( <pConnectionSocket>,
|
|
* [<cPass>], [<nCompressionLevel>], [<nStrategy>] ) -> NIL
|
|
*/
|
|
HB_FUNC( NETIO_COMPRESS )
|
|
{
|
|
PHB_CONSRV conn = s_consrvParam( 1 );
|
|
|
|
if( conn && conn->sd != HB_NO_SOCKET && !conn->stop )
|
|
{
|
|
int iLevel, iStrategy, keylen = ( int ) hb_parclen( 3 );
|
|
|
|
if( keylen > NETIO_PASSWD_MAX )
|
|
keylen = NETIO_PASSWD_MAX;
|
|
iLevel = hb_parnidef( 4, keylen ? HB_ZLIB_COMPRESSION_DEFAULT :
|
|
HB_ZLIB_COMPRESSION_DISABLE );
|
|
iStrategy = hb_parnidef( 5, HB_ZLIB_STRATEGY_DEFAULT );
|
|
|
|
if( iLevel == HB_ZLIB_COMPRESSION_DISABLE )
|
|
{
|
|
if( conn->zstream )
|
|
{
|
|
hb_znetClose( conn->zstream );
|
|
conn->zstream = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PHB_ZNETSTREAM zstream = hb_znetOpen( iLevel, iStrategy );
|
|
if( zstream != NULL )
|
|
{
|
|
if( conn->zstream )
|
|
hb_znetClose( conn->zstream );
|
|
conn->zstream = zstream;
|
|
if( keylen > NETIO_PASSWD_MAX )
|
|
keylen = NETIO_PASSWD_MAX;
|
|
if( keylen )
|
|
hb_znetEncryptKey( zstream, hb_parc( 2 ), keylen );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static HB_BOOL s_netio_login_accept( PHB_CONSRV conn )
|
|
{
|
|
if( conn && conn->sd != HB_NO_SOCKET && !conn->stop && !conn->login )
|
|
{
|
|
HB_BYTE msgbuf[ NETIO_MSGLEN ];
|
|
|
|
if( s_srvRecvAll( conn, msgbuf, NETIO_MSGLEN ) == NETIO_MSGLEN &&
|
|
HB_GET_LE_INT32( msgbuf ) == NETIO_LOGIN )
|
|
{
|
|
long len = HB_GET_LE_INT16( &msgbuf[ 4 ] );
|
|
|
|
if( len < ( long ) sizeof( msgbuf ) &&
|
|
len == ( long ) strlen( NETIO_LOGINSTRID ) &&
|
|
s_srvRecvAll( conn, msgbuf, len ) == len )
|
|
{
|
|
if( memcmp( NETIO_LOGINSTRID, msgbuf, len ) == 0 )
|
|
{
|
|
HB_PUT_LE_UINT32( &msgbuf[ 0 ], NETIO_LOGIN );
|
|
HB_PUT_LE_UINT32( &msgbuf[ 4 ], NETIO_CONNECTED );
|
|
memset( msgbuf + 8, '\0', NETIO_MSGLEN - 8 );
|
|
if( s_srvSendAll( conn, msgbuf, NETIO_MSGLEN ) == NETIO_MSGLEN )
|
|
conn->login = HB_TRUE;
|
|
}
|
|
}
|
|
}
|
|
if( !conn->login )
|
|
s_consrv_disconnect( conn );
|
|
}
|
|
|
|
return conn->login;
|
|
}
|
|
|
|
/* NETIO_VERIFYCLIENT( <pConnectionSocket> ) -> <lAccepted>
|
|
*/
|
|
HB_FUNC( NETIO_VERIFYCLIENT )
|
|
{
|
|
PHB_CONSRV conn = s_consrvParam( 1 );
|
|
if( conn )
|
|
hb_retl( s_netio_login_accept( conn ) );
|
|
}
|
|
|
|
/* NETIO_SERVER( <pConnectionSocket> ) -> NIL
|
|
*/
|
|
HB_FUNC( NETIO_SERVER )
|
|
{
|
|
PHB_CONSRV conn = s_consrvParam( 1 );
|
|
|
|
if( s_netio_login_accept( conn ) )
|
|
{
|
|
/* clear return value if any */
|
|
hb_ret();
|
|
|
|
for( ;; )
|
|
{
|
|
HB_BYTE buffer[ 2048 ], * ptr = NULL, * msg;
|
|
HB_BYTE msgbuf[ NETIO_MSGLEN ];
|
|
HB_BOOL fNoAnswer = HB_FALSE;
|
|
HB_ERRCODE errCode = 0, errFsCode;
|
|
long len = 0, size, size2;
|
|
int iFileNo, iStreamID, iResult;
|
|
HB_U32 uiMsg;
|
|
HB_USHORT uiFalgs;
|
|
char * szExt;
|
|
PHB_FILE pFile;
|
|
HB_FOFFSET llOffset, llSize;
|
|
|
|
msg = buffer;
|
|
|
|
if( s_srvRecvAll( conn, msgbuf, NETIO_MSGLEN ) != NETIO_MSGLEN )
|
|
break;
|
|
|
|
uiMsg = HB_GET_LE_UINT32( msgbuf );
|
|
switch( uiMsg )
|
|
{
|
|
case NETIO_EXISTS:
|
|
size = HB_GET_LE_UINT16( &msgbuf[ 4 ] );
|
|
if( size <= 0 )
|
|
errCode = NETIO_ERR_WRONG_PARAM;
|
|
else
|
|
{
|
|
if( size + conn->rootPathLen >= ( long ) sizeof( buffer ) )
|
|
ptr = msg = ( HB_BYTE * ) hb_xgrab( size + conn->rootPathLen + 1 );
|
|
msg[ size ] = '\0';
|
|
if( s_srvRecvAll( conn, msg, size ) != size )
|
|
errCode = NETIO_ERR_READ;
|
|
else
|
|
{
|
|
const char * szFile = s_consrvFilePath( ( char * ) msg, conn );
|
|
|
|
if( !szFile )
|
|
errCode = NETIO_ERR_WRONG_FILE_PATH;
|
|
else if( !hb_fileExists( szFile, NULL ) )
|
|
errCode = s_srvFsError();
|
|
else
|
|
{
|
|
HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_EXISTS );
|
|
memset( msg + 4, '\0', NETIO_MSGLEN - 4 );
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case NETIO_DELETE:
|
|
size = HB_GET_LE_UINT16( &msgbuf[ 4 ] );
|
|
if( size <= 0 )
|
|
errCode = NETIO_ERR_WRONG_PARAM;
|
|
else
|
|
{
|
|
if( size + conn->rootPathLen >= ( long ) sizeof( buffer ) )
|
|
ptr = msg = ( HB_BYTE * ) hb_xgrab( size + conn->rootPathLen + 1 );
|
|
msg[ size ] = '\0';
|
|
if( s_srvRecvAll( conn, msg, size ) != size )
|
|
errCode = NETIO_ERR_READ;
|
|
else
|
|
{
|
|
const char * szFile = s_consrvFilePath( ( char * ) msg, conn );
|
|
|
|
if( !szFile )
|
|
errCode = NETIO_ERR_WRONG_FILE_PATH;
|
|
else if( !hb_fileDelete( szFile ) )
|
|
errCode = s_srvFsError();
|
|
else
|
|
{
|
|
HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_DELETE );
|
|
memset( msg + 4, '\0', NETIO_MSGLEN - 4 );
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case NETIO_RENAME:
|
|
size = HB_GET_LE_UINT16( &msgbuf[ 4 ] );
|
|
size2 = HB_GET_LE_UINT16( &msgbuf[ 6 ] );
|
|
if( size <= 0 || size2 <= 0 )
|
|
errCode = NETIO_ERR_WRONG_PARAM;
|
|
else
|
|
{
|
|
if( HB_MAX( size, size2 ) + conn->rootPathLen >= ( long ) sizeof( buffer ) )
|
|
ptr = msg = ( HB_BYTE * ) hb_xgrab( HB_MAX( size, size2 ) + conn->rootPathLen + 1 );
|
|
msg[ size ] = '\0';
|
|
if( s_srvRecvAll( conn, msg, size ) != size )
|
|
errCode = NETIO_ERR_READ;
|
|
else
|
|
{
|
|
char * szOldName = NULL;
|
|
const char * szFile = s_consrvFilePath( ( char * ) msg, conn );
|
|
|
|
if( szFile )
|
|
szOldName = hb_strdup( szFile );
|
|
|
|
msg[ size2 ] = '\0';
|
|
if( s_srvRecvAll( conn, msg, size2 ) != size2 )
|
|
errCode = NETIO_ERR_READ;
|
|
else if( !szOldName )
|
|
errCode = NETIO_ERR_WRONG_FILE_PATH;
|
|
else
|
|
{
|
|
szFile = s_consrvFilePath( ( char * ) msg, conn );
|
|
if( !szFile )
|
|
errCode = NETIO_ERR_WRONG_FILE_PATH;
|
|
else if( !hb_fileRename( szOldName, szFile ) )
|
|
errCode = s_srvFsError();
|
|
else
|
|
{
|
|
HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_RENAME );
|
|
memset( msg + 4, '\0', NETIO_MSGLEN - 4 );
|
|
}
|
|
}
|
|
if( szOldName )
|
|
hb_xfree( szOldName );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case NETIO_OPEN:
|
|
uiFalgs = HB_GET_LE_UINT16( &msgbuf[ 6 ] );
|
|
szExt = msgbuf[ 8 ] ? hb_strndup( ( const char * ) &msgbuf[ 8 ],
|
|
NETIO_MSGLEN - 8 ) : NULL;
|
|
size = HB_GET_LE_UINT16( &msgbuf[ 4 ] );
|
|
if( size <= 0 )
|
|
errCode = NETIO_ERR_WRONG_PARAM;
|
|
else
|
|
{
|
|
if( size + conn->rootPathLen >= ( long ) sizeof( buffer ) )
|
|
ptr = msg = ( HB_BYTE * ) hb_xgrab( size + conn->rootPathLen + 1 );
|
|
msg[ size ] = '\0';
|
|
if( s_srvRecvAll( conn, msg, size ) != size )
|
|
errCode = NETIO_ERR_READ;
|
|
else if( conn->filesCount >= NETIO_FILES_MAX )
|
|
errCode = NETIO_ERR_FILES_MAX;
|
|
else
|
|
{
|
|
const char * szFile = s_consrvFilePath( ( char * ) msg, conn );
|
|
|
|
if( !szFile )
|
|
errCode = NETIO_ERR_WRONG_FILE_PATH;
|
|
else
|
|
{
|
|
pFile = hb_fileExtOpen( szFile, szExt, uiFalgs, NULL, NULL );
|
|
if( !pFile )
|
|
errCode = s_srvFsError();
|
|
else
|
|
{
|
|
iFileNo = s_srvFileNew( conn, pFile );
|
|
if( iFileNo < 0 )
|
|
{
|
|
errCode = NETIO_ERR_FILES_MAX;
|
|
hb_fileClose( pFile );
|
|
}
|
|
else
|
|
{
|
|
HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_OPEN );
|
|
HB_PUT_LE_UINT16( &msg[ 4 ], iFileNo );
|
|
memset( msg + 6, '\0', NETIO_MSGLEN - 6 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if( szExt )
|
|
hb_xfree( szExt );
|
|
break;
|
|
|
|
case NETIO_READ:
|
|
iFileNo = HB_GET_LE_UINT16( &msgbuf[ 4 ] );
|
|
size = HB_GET_LE_UINT32( &msgbuf[ 6 ] );
|
|
llOffset = HB_GET_LE_INT64( &msgbuf[ 10 ] );
|
|
if( size < 0 )
|
|
errCode = NETIO_ERR_WRONG_PARAM;
|
|
else
|
|
{
|
|
if( size >= ( long ) ( sizeof( buffer ) - NETIO_MSGLEN ) )
|
|
ptr = msg = ( HB_BYTE * ) hb_xgrab( size + NETIO_MSGLEN );
|
|
pFile = s_srvFileGet( conn, iFileNo );
|
|
if( pFile == NULL )
|
|
errCode = NETIO_ERR_WRONG_FILE_HANDLE;
|
|
else
|
|
{
|
|
len = ( long ) hb_fileReadAt( pFile, msg + NETIO_MSGLEN, size, llOffset );
|
|
errFsCode = hb_fsError();
|
|
HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_READ );
|
|
HB_PUT_LE_UINT32( &msg[ 4 ], len );
|
|
HB_PUT_LE_UINT32( &msg[ 8 ], errFsCode );
|
|
memset( msg + 12, '\0', NETIO_MSGLEN - 12 );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case NETIO_WRITE:
|
|
iFileNo = HB_GET_LE_UINT16( &msgbuf[ 4 ] );
|
|
size = HB_GET_LE_UINT32( &msgbuf[ 6 ] );
|
|
llOffset = HB_GET_LE_INT64( &msgbuf[ 10 ] );
|
|
if( size < 0 )
|
|
errCode = NETIO_ERR_WRONG_PARAM;
|
|
else
|
|
{
|
|
if( size >= ( long ) sizeof( buffer ) )
|
|
ptr = msg = ( HB_BYTE * ) hb_xgrab( size );
|
|
if( s_srvRecvAll( conn, msg, size ) != size )
|
|
errCode = NETIO_ERR_READ;
|
|
else
|
|
{
|
|
pFile = s_srvFileGet( conn, iFileNo );
|
|
if( pFile == NULL )
|
|
errCode = NETIO_ERR_WRONG_FILE_HANDLE;
|
|
else
|
|
{
|
|
size = ( long ) hb_fileWriteAt( pFile, msg, size, llOffset );
|
|
errFsCode = hb_fsError();
|
|
HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_WRITE );
|
|
HB_PUT_LE_UINT32( &msg[ 4 ], size );
|
|
HB_PUT_LE_UINT32( &msg[ 8 ], errFsCode );
|
|
memset( msg + 12, '\0', NETIO_MSGLEN - 12 );
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case NETIO_UNLOCK:
|
|
fNoAnswer = HB_TRUE;
|
|
case NETIO_LOCK:
|
|
case NETIO_TESTLOCK:
|
|
iFileNo = HB_GET_LE_UINT16( &msgbuf[ 4 ] );
|
|
llOffset = HB_GET_LE_INT64( &msgbuf[ 6 ] );
|
|
llSize = HB_GET_LE_INT64( &msgbuf[ 14 ] );
|
|
uiFalgs = HB_GET_LE_UINT16( &msgbuf[ 22 ] );
|
|
pFile = s_srvFileGet( conn, iFileNo );
|
|
if( pFile == NULL )
|
|
errCode = NETIO_ERR_WRONG_FILE_HANDLE;
|
|
else if( uiMsg == NETIO_TESTLOCK )
|
|
{
|
|
iResult = hb_fileLockTest( pFile, llOffset, llSize, uiFalgs );
|
|
errFsCode = hb_fsError();
|
|
HB_PUT_LE_UINT32( &msg[ 0 ], uiMsg );
|
|
HB_PUT_LE_UINT32( &msg[ 4 ], iResult );
|
|
HB_PUT_LE_UINT32( &msg[ 8 ], errFsCode );
|
|
memset( msg + 12, '\0', NETIO_MSGLEN - 4 );
|
|
}
|
|
else if( !hb_fileLock( pFile, llOffset, llSize, uiFalgs ) )
|
|
errCode = s_srvFsError();
|
|
else if( !fNoAnswer )
|
|
{
|
|
HB_PUT_LE_UINT32( &msg[ 0 ], uiMsg );
|
|
memset( msg + 4, '\0', NETIO_MSGLEN - 4 );
|
|
}
|
|
break;
|
|
|
|
case NETIO_TRUNC:
|
|
iFileNo = HB_GET_LE_UINT16( &msgbuf[ 4 ] );
|
|
llOffset = HB_GET_LE_INT64( &msgbuf[ 6 ] );
|
|
pFile = s_srvFileGet( conn, iFileNo );
|
|
if( pFile == NULL )
|
|
errCode = NETIO_ERR_WRONG_FILE_HANDLE;
|
|
else if( !hb_fileTruncAt( pFile, llOffset ) )
|
|
errCode = s_srvFsError();
|
|
else
|
|
{
|
|
HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_TRUNC );
|
|
memset( msg + 4, '\0', NETIO_MSGLEN - 4 );
|
|
}
|
|
break;
|
|
|
|
case NETIO_SIZE:
|
|
iFileNo = HB_GET_LE_UINT16( &msgbuf[ 4 ] );
|
|
pFile = s_srvFileGet( conn, iFileNo );
|
|
if( pFile == NULL )
|
|
errCode = NETIO_ERR_WRONG_FILE_HANDLE;
|
|
else
|
|
{
|
|
llOffset = hb_fileSize( pFile );
|
|
errFsCode = hb_fsError();
|
|
HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_SIZE );
|
|
HB_PUT_LE_UINT64( &msg[ 4 ], llOffset );
|
|
HB_PUT_LE_UINT32( &msg[ 12 ], errFsCode );
|
|
memset( msg + 16, '\0', NETIO_MSGLEN - 16 );
|
|
}
|
|
break;
|
|
|
|
case NETIO_CLOSE:
|
|
iFileNo = HB_GET_LE_UINT16( &msgbuf[ 4 ] );
|
|
pFile = s_srvFileFree( conn, iFileNo );
|
|
if( pFile == NULL )
|
|
errCode = NETIO_ERR_WRONG_FILE_HANDLE;
|
|
else
|
|
{
|
|
hb_fileClose( pFile );
|
|
HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_CLOSE );
|
|
memset( msg + 4, '\0', NETIO_MSGLEN - 4 );
|
|
}
|
|
break;
|
|
|
|
case NETIO_COMMIT:
|
|
iFileNo = HB_GET_LE_UINT16( &msgbuf[ 4 ] );
|
|
pFile = s_srvFileGet( conn, iFileNo );
|
|
if( pFile )
|
|
hb_fileCommit( pFile );
|
|
fNoAnswer = HB_TRUE;
|
|
break;
|
|
|
|
case NETIO_SRVCLOSE:
|
|
iStreamID = HB_GET_LE_INT32( &msgbuf[ 4 ] );
|
|
if( iStreamID && conn->mutex && hb_threadMutexLock( conn->mutex ) )
|
|
{
|
|
PHB_CONSTREAM * pStreamPtr = &conn->streams;
|
|
while( *pStreamPtr )
|
|
{
|
|
if( ( *pStreamPtr )->id == iStreamID )
|
|
{
|
|
PHB_CONSTREAM stream = *pStreamPtr;
|
|
*pStreamPtr = stream->next;
|
|
hb_xfree( stream );
|
|
break;
|
|
}
|
|
pStreamPtr = &( *pStreamPtr )->next;
|
|
}
|
|
if( *pStreamPtr == NULL )
|
|
iStreamID = 0;
|
|
hb_threadMutexUnlock( conn->mutex );
|
|
}
|
|
else
|
|
iStreamID = 0;
|
|
|
|
if( iStreamID == 0 )
|
|
errCode = NETIO_ERR_WRONG_STREAMID;
|
|
else
|
|
{
|
|
HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_SRVCLOSE );
|
|
memset( msg + 4, '\0', NETIO_MSGLEN - 4 );
|
|
}
|
|
break;
|
|
|
|
case NETIO_PROC:
|
|
fNoAnswer = HB_TRUE;
|
|
case NETIO_PROCIS:
|
|
case NETIO_PROCW:
|
|
case NETIO_FUNC:
|
|
case NETIO_FUNCCTRL:
|
|
if( !conn->rpc )
|
|
{
|
|
errCode = NETIO_ERR_UNSUPPORTED;
|
|
break;
|
|
}
|
|
size = HB_GET_LE_UINT32( &msgbuf[ 4 ] );
|
|
if( size < 2 )
|
|
errCode = NETIO_ERR_WRONG_PARAM;
|
|
else
|
|
{
|
|
if( size >= ( long ) sizeof( buffer ) )
|
|
ptr = msg = ( HB_BYTE * ) hb_xgrab( size );
|
|
if( s_srvRecvAll( conn, msg, size ) != size )
|
|
errCode = NETIO_ERR_READ;
|
|
else
|
|
{
|
|
const char * data = ( const char * ) msg;
|
|
size2 = ( long ) hb_strnlen( data, size ) + 1;
|
|
if( size2 > size )
|
|
errCode = NETIO_ERR_WRONG_PARAM;
|
|
else
|
|
{
|
|
PHB_DYNS pDynSym = NULL;
|
|
PHB_ITEM pItem = NULL;
|
|
|
|
if( conn->rpcFilter )
|
|
{
|
|
pItem = hb_hashGetCItemPtr( conn->rpcFilter, data );
|
|
if( !pItem )
|
|
errCode = NETIO_ERR_NOT_EXISTS;
|
|
}
|
|
else
|
|
{
|
|
pDynSym = hb_dynsymFindName( data );
|
|
if( !pDynSym || !hb_dynsymIsFunction( pDynSym ) )
|
|
errCode = NETIO_ERR_NOT_EXISTS;
|
|
}
|
|
|
|
if( uiMsg != NETIO_PROCIS && errCode == 0 )
|
|
{
|
|
if( hb_vmRequestReenter() )
|
|
{
|
|
HB_SIZE nSize = size - size2;
|
|
HB_USHORT uiPCount = 0;
|
|
HB_BOOL fSend = HB_FALSE;
|
|
int iStreamType;
|
|
|
|
iStreamID = 0;
|
|
data += size2;
|
|
if( pItem )
|
|
{
|
|
fSend = HB_TRUE;
|
|
hb_vmPushEvalSym();
|
|
hb_vmPush( pItem );
|
|
}
|
|
else if( conn->rpcFunc )
|
|
{
|
|
hb_vmPushSymbol( conn->rpcFunc );
|
|
hb_vmPushNil();
|
|
hb_vmPushDynSym( pDynSym );
|
|
++uiPCount;
|
|
}
|
|
else
|
|
{
|
|
hb_vmPushDynSym( pDynSym );
|
|
hb_vmPushNil();
|
|
}
|
|
if( uiMsg == NETIO_FUNCCTRL )
|
|
{
|
|
iStreamID = HB_GET_LE_INT32( &msgbuf[ 8 ] );
|
|
iStreamType = HB_GET_LE_INT32( &msgbuf[ 12 ] );
|
|
hb_vmPush( hb_param( 1, HB_IT_ANY ) );
|
|
hb_vmPushInteger( iStreamID );
|
|
uiPCount += 2;
|
|
if( iStreamType != NETIO_SRVDATA &&
|
|
iStreamType != NETIO_SRVITEM )
|
|
iStreamID = 0;
|
|
if( iStreamID )
|
|
{
|
|
PHB_CONSTREAM stream = ( PHB_CONSTREAM )
|
|
hb_xgrab( sizeof( HB_CONSTREAM ) );
|
|
stream->id = iStreamID;
|
|
stream->type = iStreamType;
|
|
stream->next = conn->streams;
|
|
conn->streams = stream;
|
|
|
|
if( conn->mutex == NULL )
|
|
conn->mutex = hb_threadMutexCreate();
|
|
if( !hb_threadMutexLock( conn->mutex ) )
|
|
errCode = NETIO_ERR_REFUSED;
|
|
}
|
|
else
|
|
errCode = NETIO_ERR_WRONG_PARAM;
|
|
}
|
|
while( nSize > 0 && errCode == 0 )
|
|
{
|
|
pItem = hb_itemDeserialize( &data, &nSize );
|
|
if( !pItem )
|
|
{
|
|
errCode = NETIO_ERR_WRONG_PARAM;
|
|
break;
|
|
}
|
|
++uiPCount;
|
|
hb_vmPush( pItem );
|
|
hb_itemRelease( pItem );
|
|
}
|
|
if( errCode != 0 )
|
|
{
|
|
uiPCount += 2;
|
|
do
|
|
hb_stackPop();
|
|
while( --uiPCount );
|
|
}
|
|
else
|
|
{
|
|
if( fSend )
|
|
hb_vmSend( uiPCount );
|
|
else
|
|
hb_vmProc( uiPCount );
|
|
if( uiMsg == NETIO_FUNC || uiMsg == NETIO_FUNCCTRL )
|
|
{
|
|
HB_SIZE itmSize;
|
|
PHB_ITEM pResult = hb_stackReturnItem();
|
|
char * itmData = hb_itemSerialize( pResult, HB_TRUE, &itmSize );
|
|
if( itmSize <= sizeof( buffer ) - NETIO_MSGLEN )
|
|
msg = buffer;
|
|
else if( !ptr || itmSize > ( HB_SIZE ) size - NETIO_MSGLEN )
|
|
{
|
|
if( ptr )
|
|
hb_xfree( ptr );
|
|
ptr = msg = ( HB_BYTE * ) hb_xgrab( itmSize + NETIO_MSGLEN );
|
|
}
|
|
memcpy( msg + NETIO_MSGLEN, itmData, itmSize );
|
|
hb_xfree( itmData );
|
|
len = ( long ) itmSize;
|
|
if( iStreamID && hb_itemGetNI( pResult ) == iStreamID )
|
|
{
|
|
hb_threadMutexUnlock( conn->mutex );
|
|
iStreamID = 0;
|
|
}
|
|
}
|
|
}
|
|
hb_vmRequestRestore();
|
|
if( iStreamID )
|
|
{
|
|
PHB_CONSTREAM stream = conn->streams;
|
|
|
|
if( stream->id == iStreamID )
|
|
{
|
|
conn->streams = stream->next;
|
|
hb_xfree( stream );
|
|
}
|
|
hb_threadMutexUnlock( conn->mutex );
|
|
}
|
|
}
|
|
else
|
|
errCode = NETIO_ERR_REFUSED;
|
|
}
|
|
}
|
|
if( errCode == 0 && !fNoAnswer )
|
|
{
|
|
HB_PUT_LE_UINT32( &msg[ 0 ], uiMsg );
|
|
HB_PUT_LE_UINT32( &msg[ 4 ], len );
|
|
memset( msg + 8, '\0', NETIO_MSGLEN - 8 );
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case NETIO_SYNC:
|
|
continue;
|
|
|
|
default: /* unkown message */
|
|
errCode = NETIO_ERR_UNKNOWN_COMMAND;
|
|
break;
|
|
}
|
|
|
|
if( fNoAnswer )
|
|
{
|
|
/* continue; */ /* do not send dummy record */
|
|
HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_SYNC );
|
|
memset( msg + 4, '\0', NETIO_MSGLEN - 4 );
|
|
len = NETIO_MSGLEN;
|
|
}
|
|
else if( errCode != 0 )
|
|
{
|
|
HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_ERROR );
|
|
HB_PUT_LE_UINT32( &msg[ 4 ], errCode );
|
|
memset( msg + 8, '\0', NETIO_MSGLEN - 8 );
|
|
len = NETIO_MSGLEN;
|
|
}
|
|
else
|
|
len += NETIO_MSGLEN;
|
|
|
|
errCode = s_srvSendAll( conn, msg, len ) != len;
|
|
|
|
if( ptr )
|
|
hb_xfree( ptr );
|
|
|
|
if( errCode )
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* NETIO_SRVSENDITEM( <pConnectionSocket>, <nStreamID>, <xData> ) -> <lSent>
|
|
*/
|
|
HB_FUNC( NETIO_SRVSENDITEM )
|
|
{
|
|
PHB_CONSRV conn = s_consrvParam( 1 );
|
|
int iStreamID = hb_parni( 2 );
|
|
PHB_ITEM pItem = hb_param( 3, HB_IT_ANY );
|
|
HB_BOOL fResult = HB_FALSE;
|
|
|
|
if( conn && conn->sd != HB_NO_SOCKET && !conn->stop && conn->mutex &&
|
|
iStreamID && pItem )
|
|
{
|
|
char * itmData, * msg;
|
|
HB_SIZE nLen;
|
|
long lLen;
|
|
|
|
itmData = hb_itemSerialize( pItem, HB_TRUE, &nLen );
|
|
lLen = ( long ) nLen;
|
|
msg = ( char * ) hb_xgrab( lLen + NETIO_MSGLEN );
|
|
HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_SRVITEM );
|
|
HB_PUT_LE_UINT32( &msg[ 4 ], iStreamID );
|
|
HB_PUT_LE_UINT32( &msg[ 8 ], lLen );
|
|
memset( msg + 12, '\0', NETIO_MSGLEN - 12 );
|
|
memcpy( msg + NETIO_MSGLEN, itmData, lLen );
|
|
hb_xfree( itmData );
|
|
|
|
lLen += NETIO_MSGLEN;
|
|
if( hb_threadMutexLock( conn->mutex ) )
|
|
{
|
|
PHB_CONSTREAM stream = conn->streams;
|
|
while( stream )
|
|
{
|
|
if( stream->id == iStreamID )
|
|
break;
|
|
stream = stream->next;
|
|
}
|
|
if( stream && stream->type == NETIO_SRVITEM )
|
|
fResult = s_srvSendAll( conn, msg, lLen ) == lLen;
|
|
hb_threadMutexUnlock( conn->mutex );
|
|
}
|
|
hb_xfree( msg );
|
|
}
|
|
hb_retl( fResult );
|
|
}
|
|
|
|
/* NETIO_SRVSENDDATA( <pConnectionSocket>, <nStreamID>, <cData> ) -> <lSent>
|
|
*/
|
|
HB_FUNC( NETIO_SRVSENDDATA )
|
|
{
|
|
PHB_CONSRV conn = s_consrvParam( 1 );
|
|
int iStreamID = hb_parni( 2 );
|
|
long lLen = ( long ) hb_parclen( 3 );
|
|
HB_BOOL fResult = HB_FALSE;
|
|
|
|
if( conn && conn->sd != HB_NO_SOCKET && !conn->stop && conn->mutex &&
|
|
iStreamID && lLen > 0 )
|
|
{
|
|
char * msg;
|
|
|
|
msg = ( char * ) hb_xgrab( lLen + NETIO_MSGLEN );
|
|
HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_SRVDATA );
|
|
HB_PUT_LE_UINT32( &msg[ 4 ], iStreamID );
|
|
HB_PUT_LE_UINT32( &msg[ 8 ], lLen );
|
|
memset( msg + 12, '\0', NETIO_MSGLEN - 12 );
|
|
memcpy( msg + NETIO_MSGLEN, hb_parc( 3 ), lLen );
|
|
|
|
lLen += NETIO_MSGLEN;
|
|
if( hb_threadMutexLock( conn->mutex ) )
|
|
{
|
|
PHB_CONSTREAM stream = conn->streams;
|
|
while( stream )
|
|
{
|
|
if( stream->id == iStreamID )
|
|
break;
|
|
stream = stream->next;
|
|
}
|
|
if( stream && stream->type == NETIO_SRVDATA )
|
|
fResult = s_srvSendAll( conn, msg, lLen ) == lLen;
|
|
hb_threadMutexUnlock( conn->mutex );
|
|
}
|
|
hb_xfree( msg );
|
|
}
|
|
hb_retl( fResult );
|
|
}
|
|
|
|
/* NETIO_SRVSTATUS( <pConnectionSocket>
|
|
* [, <nStreamID> | <nSrvInfo>, @<xData>] ) -> <nStatus>
|
|
*/
|
|
HB_FUNC( NETIO_SRVSTATUS )
|
|
{
|
|
PHB_CONSRV conn = s_consrvParam( 1 );
|
|
int iStreamID = hb_parni( 2 ), iSrvInfo = 0;
|
|
int iStatus = NETIO_SRVSTAT_RUNNING;
|
|
|
|
if( iStreamID < 0 )
|
|
{
|
|
iSrvInfo = iStreamID;
|
|
iStreamID = 0;
|
|
}
|
|
|
|
if( !conn )
|
|
iStatus = NETIO_SRVSTAT_WRONGHANDLE;
|
|
else if( conn->sd == HB_NO_SOCKET )
|
|
iStatus = NETIO_SRVSTAT_CLOSED;
|
|
else if( conn->stop )
|
|
iStatus = NETIO_SRVSTAT_STOPPED;
|
|
else if( iStreamID != 0 && conn->mutex )
|
|
{
|
|
if( hb_threadMutexLock( conn->mutex ) )
|
|
{
|
|
PHB_CONSTREAM stream = conn->streams;
|
|
while( stream )
|
|
{
|
|
if( stream->id == iStreamID )
|
|
{
|
|
iStatus = stream->type == NETIO_SRVDATA ?
|
|
NETIO_SRVSTAT_DATASTREAM : NETIO_SRVSTAT_ITEMSTREAM;
|
|
break;
|
|
}
|
|
stream = stream->next;
|
|
}
|
|
hb_threadMutexUnlock( conn->mutex );
|
|
}
|
|
}
|
|
else switch( iSrvInfo )
|
|
{
|
|
case NETIO_SRVINFO_FILESCOUNT:
|
|
hb_storni( conn->filesCount, 3 );
|
|
break;
|
|
case NETIO_SRVINFO_BYTESSENT:
|
|
hb_stornint( conn->wr_count, 3 );
|
|
break;
|
|
case NETIO_SRVINFO_BYTESRECEIVED:
|
|
hb_stornint( conn->rd_count, 3 );
|
|
break;
|
|
case NETIO_SRVINFO_PEERADDRESS:
|
|
{
|
|
void * addr;
|
|
unsigned int len;
|
|
PHB_ITEM pItem = NULL;
|
|
|
|
if( hb_socketGetPeerName( conn->sd, &addr, &len ) == 0 )
|
|
{
|
|
pItem = hb_socketAddrToItem( addr, len );
|
|
if( addr )
|
|
hb_xfree( addr );
|
|
}
|
|
if( !hb_itemParamStoreRelease( 3, pItem ) && pItem )
|
|
hb_itemRelease( pItem );
|
|
break;
|
|
}
|
|
}
|
|
hb_retni( iStatus );
|
|
}
|