From 08e0268da49123e4e76df999c02b6bbec915cb1f Mon Sep 17 00:00:00 2001 From: Przemyslaw Czerpak Date: Mon, 31 Aug 2009 22:56:45 +0000 Subject: [PATCH] 2009-09-01 00:56 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) * harbour/harbour.spec * harbour/harbour-win-spec * harbour/harbour-wce-spec * harbour/bin/hb-func.sh * harbour/contrib/Makefile + harbour/contrib/hbnetio + harbour/contrib/hbnetio/netio.h + harbour/contrib/hbnetio/netiomt.prg + harbour/contrib/hbnetio/netiocli.c + harbour/contrib/hbnetio/netiosrv.c + harbour/contrib/hbnetio/Makefile + added new library: HBNETIO. It implements alternative RDD IO API which uses own TCP/IP sockets to exchange data between client and server. This library contains client and server code and is fully MT safe. On client side it's enough to execute: NETIO_CONNECT( [], [], [] ) -> function to register alternative NETIO RDD API and set default server address and port. - server addres (default 127.0.0.1) - server port (default 2941) - connection timeout (default -1 - not timeout) Above settings are thread local and parameters of the 1-st successful connection are used as default values for each new thread. After registering NETIO client by above function each file starting "net:" prefix is automatically redirected to given NETIO server, i.e. use "net:mytable" It's also possible to pass NETIO server and port as part of file name, i.e.: use "net:192.168.0.1:10005:mytable" On the server side the following functions are available: create NETIO listen socket: NETIO_LISTEN( [], [], [] ) -> | NIL accept new connection on NETIO listen socket: NETIO_ACCEPT( [, ] ) -> | NIL start connection server: NETIO_SERVER( ) -> NIL stop connection accepting or connection server: NETIO_SERVERSTOP( | , ) -> NIL activate MT NETIO server (it needs MT HVM): NETIO_MTSERVER( [], [] ) -> | NIL To create NETIO server is enough to compile and link with MT HVM this code: proc main() local pListenSocket pListenSocket := netio_mtserver() if empty( pListenSocket ) ? "Cannot start server." else wait "Press any key to stop NETIO server." netio_serverstop( pListenSocket ) pListenSocket := NIL endif return NETIO works with all core RDDs (DBF, DBFFPT, DBFBLOB, DBFNTX, DBFCDX, DBFNSX, SDF, DELIM) and any other RDD which inherits from above or use standard RDD IO API (hb_file*() functions). Without touching even single line in RDD code it gives the same functionality as REDBFCDX in xHarbour but for all RDDs. It's possible that such direct TCP/IP connection is faster then file server protocols especially if they need more then one IP frame to exchange data so it's one of the reason to use it in such cases. Please make real speed tests. The second reason to use NETIO server is resolving problem with concurrent access to the same files using Harbour applications compiled for different platforms, i.e. DOS, LINUX, Windows and OS2. It's very hard to configure all client stations to use correct locking system. NETIO fully resolves this problem so it can be interesting alternative also for MS-Windows users only if they do not want to play with oplocks setting on each station. I'm interesting in user opinions about real life NETIO usage. Have a fun with this new toy ;-) + harbour/contrib/hbnetio/tests + harbour/contrib/hbnetio/tests/netiotst.prg + harbour/contrib/hbnetio/tests/netiotst.hbp + harbour/contrib/hbnetio/tests/data + added simple test code for NETIO. It activates NETIO MT server and then connects to this server to create and browse table with memo file and production index with few tags. --- harbour/ChangeLog | 90 +++ harbour/bin/hb-func.sh | 2 +- harbour/contrib/Makefile | 1 + harbour/contrib/hbnetio/Makefile | 16 + harbour/contrib/hbnetio/netio.h | 112 +++ harbour/contrib/hbnetio/netiocli.c | 791 +++++++++++++++++++++ harbour/contrib/hbnetio/netiomt.prg | 81 +++ harbour/contrib/hbnetio/netiosrv.c | 749 +++++++++++++++++++ harbour/contrib/hbnetio/tests/netiotst.hbp | 7 + harbour/contrib/hbnetio/tests/netiotst.prg | 92 +++ harbour/harbour-wce-spec | 4 +- harbour/harbour-win-spec | 4 +- harbour/harbour.spec | 3 +- 13 files changed, 1946 insertions(+), 6 deletions(-) create mode 100644 harbour/contrib/hbnetio/Makefile create mode 100644 harbour/contrib/hbnetio/netio.h create mode 100644 harbour/contrib/hbnetio/netiocli.c create mode 100644 harbour/contrib/hbnetio/netiomt.prg create mode 100644 harbour/contrib/hbnetio/netiosrv.c create mode 100644 harbour/contrib/hbnetio/tests/netiotst.hbp create mode 100644 harbour/contrib/hbnetio/tests/netiotst.prg diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 9c70038f4e..a576fd93ef 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -17,6 +17,96 @@ past entries belonging to author(s): Viktor Szakats. */ +2009-09-01 00:56 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/harbour.spec + * harbour/harbour-win-spec + * harbour/harbour-wce-spec + * harbour/bin/hb-func.sh + * harbour/contrib/Makefile + + harbour/contrib/hbnetio + + harbour/contrib/hbnetio/netio.h + + harbour/contrib/hbnetio/netiomt.prg + + harbour/contrib/hbnetio/netiocli.c + + harbour/contrib/hbnetio/netiosrv.c + + harbour/contrib/hbnetio/Makefile + + added new library: HBNETIO. + It implements alternative RDD IO API which uses own TCP/IP sockets + to exchange data between client and server. + This library contains client and server code and is fully MT safe. + On client side it's enough to execute: + NETIO_CONNECT( [], [], [] ) -> + function to register alternative NETIO RDD API and set default + server address and port. + - server addres (default 127.0.0.1) + - server port (default 2941) + - connection timeout (default -1 - not timeout) + Above settings are thread local and parameters of the 1-st successful + connection are used as default values for each new thread. + After registering NETIO client by above function each file starting + "net:" prefix is automatically redirected to given NETIO server, i.e. + use "net:mytable" + It's also possible to pass NETIO server and port as part of file name, + i.e.: + use "net:192.168.0.1:10005:mytable" + On the server side the following functions are available: + create NETIO listen socket: + NETIO_LISTEN( [], [], [] ) + -> | NIL + accept new connection on NETIO listen socket: + NETIO_ACCEPT( [, ] ) + -> | NIL + start connection server: + NETIO_SERVER( ) -> NIL + stop connection accepting or connection server: + NETIO_SERVERSTOP( | , ) + -> NIL + activate MT NETIO server (it needs MT HVM): + NETIO_MTSERVER( [], [] ) -> | NIL + + To create NETIO server is enough to compile and link with MT HVM + this code: + + proc main() + local pListenSocket + + pListenSocket := netio_mtserver() + if empty( pListenSocket ) + ? "Cannot start server." + else + wait "Press any key to stop NETIO server." + netio_serverstop( pListenSocket ) + pListenSocket := NIL + endif + return + + NETIO works with all core RDDs (DBF, DBFFPT, DBFBLOB, DBFNTX, DBFCDX, + DBFNSX, SDF, DELIM) and any other RDD which inherits from above or + use standard RDD IO API (hb_file*() functions). + Without touching even single line in RDD code it gives the same + functionality as REDBFCDX in xHarbour but for all RDDs. + It's possible that such direct TCP/IP connection is faster then + file server protocols especially if they need more then one IP frame + to exchange data so it's one of the reason to use it in such cases. + Please make real speed tests. + The second reason to use NETIO server is resolving problem with + concurrent access to the same files using Harbour applications + compiled for different platforms, i.e. DOS, LINUX, Windows and OS2. + It's very hard to configure all client stations to use correct + locking system. NETIO fully resolves this problem so it can be + interesting alternative also for MS-Windows users only if they + do not want to play with oplocks setting on each station. + I'm interesting in user opinions about real life NETIO usage. + + Have a fun with this new toy ;-) + + + harbour/contrib/hbnetio/tests + + harbour/contrib/hbnetio/tests/netiotst.prg + + harbour/contrib/hbnetio/tests/netiotst.hbp + + harbour/contrib/hbnetio/tests/data + + added simple test code for NETIO. It activates NETIO MT server + and then connects to this server to create and browse table with + memo file and production index with few tags. + 2009-08-31 22:09 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) * harbour/source/rdd/sdf1.c * harbour/source/rdd/delim1.c diff --git a/harbour/bin/hb-func.sh b/harbour/bin/hb-func.sh index e104f3c061..0d42f822b8 100755 --- a/harbour/bin/hb-func.sh +++ b/harbour/bin/hb-func.sh @@ -110,7 +110,7 @@ mk_hbgetlibsctb() then libs="$libs gtwin" fi - echo "$libs hbct hbnf hbmzip hbtip xhb hbgd hbfimage rddsql sddfb sddmy sddpg hbodbc hbpgsql hbmysql hbfbird rddads rddado hbhpdf hbvpdf hbcurl hbwin gtwvg gtalleg hbsqlit3 hbbtree $HB_USER_LIBS" + echo "$libs hbct hbnf hbmzip hbnetio hbtip xhb hbgd hbfimage rddsql sddfb sddmy sddpg hbodbc hbpgsql hbmysql hbfbird rddads rddado hbhpdf hbvpdf hbcurl hbwin gtwvg gtalleg hbsqlit3 hbbtree $HB_USER_LIBS" #"hbgf hbgt hbbmcdx hbmisc hbtpathy hbwhat hbziparc hbmsql" else echo "$@" diff --git a/harbour/contrib/Makefile b/harbour/contrib/Makefile index 371f2db1b7..43b8162855 100644 --- a/harbour/contrib/Makefile +++ b/harbour/contrib/Makefile @@ -17,6 +17,7 @@ DIRS := \ hbgt \ hbmisc \ hbmzip \ + hbnetio \ hbnf \ hbodbc \ hbsqlit3 \ diff --git a/harbour/contrib/hbnetio/Makefile b/harbour/contrib/hbnetio/Makefile new file mode 100644 index 0000000000..c504c6ce7d --- /dev/null +++ b/harbour/contrib/hbnetio/Makefile @@ -0,0 +1,16 @@ +# +# $Id$ +# + +ROOT := ../../ + +LIBNAME := hbnetio + +C_SOURCES := \ + netiosrv.c \ + netiocli.c \ + +PRG_SOURCES := \ + netiomt.prg \ + +include $(TOP)$(ROOT)config/lib.mk diff --git a/harbour/contrib/hbnetio/netio.h b/harbour/contrib/hbnetio/netio.h new file mode 100644 index 0000000000..c58dd3a724 --- /dev/null +++ b/harbour/contrib/hbnetio/netio.h @@ -0,0 +1,112 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * demonstration code for alternative RDD IO API which uses own + * very simple TCP/IP file server. + * All files which names starts with 'net:' are redirected to this API. + * This is header file used by client and server code with some constant + * definitions. + * + * Copyright 2009 Przemyslaw Czerpak + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +/* file name prefix used by this file IO implementation */ +#define NETIO_FILE_PREFIX "net:" +#define NETIO_FILE_PREFIX_LEN strlen( NETIO_FILE_PREFIX ) + +/* default server address, port and timeout */ +#define NETIO_DEFAULT_SERVER "127.0.0.1" +#define NETIO_DEFAULT_PORT 2941 +#define NETIO_DEFAULT_TIMEOUT -1 + +/* message size */ +#define NETIO_MSGLEN 24 + +/* maximal number of open files per connection */ +#define NETIO_FILES_MAX 8192 + +/* maximal length of server name */ +#define NETIO_SERVERNAME_MAX 256 + +/* login string */ +#define NETIO_LOGINSTRID "HarbourFileTcpIpServer\003" + +/* messages */ +#define NETIO_LOGIN 1 +#define NETIO_EXISTS 2 +#define NETIO_DELETE 3 +#define NETIO_COMMIT 4 +#define NETIO_SIZE 5 +#define NETIO_TRUNC 6 +#define NETIO_READ 7 +#define NETIO_WRITE 8 +#define NETIO_LOCK 9 +#define NETIO_OPEN 10 +#define NETIO_CLOSE 11 +#define NETIO_ERROR 12 +#define NETIO_CONNECTED 0x4321DEAD + +/* messages format */ +/* { NETIO_LOGIN, len[ 2 ]... } + loginstr[ len ] -> { NETIO_LOGIN, NETIO_CONNECTED[ 4 ], ... } */ +/* { NETIO_EXISTS, len[ 2 ]... } + filename[ len ] -> { NETIO_EXISTS, ... } */ +/* { NETIO_DELETE, len[ 2 ]... } + filename[ len ] -> { NETIO_DELETE, ... } */ +/* { NETIO_OPEN, len[ 2 ], flags[ 2 ], def_ext[], 0, ... } + filename[ len ] -> { NETIO_OPEN, file_no[2], ... } */ +/* { NETIO_READ, file_no[2], size[ 4 ], offset[ 8 ], ... } -> { NETIO_READ, read[ 4 ], err[ 2 ], ... } + data[ read ] */ +/* { NETIO_WRITE, file_no[2], size[ 4 ], offset[ 8 ], ... } + data[ size ] -> { NETIO_WRITE, written[ 4 ], err[ 2 ], ... } */ +/* { NETIO_LOCK, file_no[2], start[ 8 ], len[ 8 ], flags[ 2 ], ... } -> { NETIO_LOCK, ... } */ +/* { NETIO_TRUNC, file_no[2], offset[ 8 ], ... } -> { NETIO_TRUNC, ... } */ +/* { NETIO_SIZE, file_no[2], ... } -> { NETIO_SIZE, size[ 8 ], err[ 2 ], ... } */ +/* { NETIO_COMMIT, file_no[2], ... } -> NULL */ +/* { NETIO_CLOSE, file_no[2], ... } -> { NETIO_CLOSE, ... } */ + +/* netio errors */ +#define NETIO_ERR_UNKNOWN_COMMAND 0xff01 +#define NETIO_ERR_WRONG_PARAM 0xff02 +#define NETIO_ERR_WRONG_FILE_PATH 0xff03 +#define NETIO_ERR_WRONG_FILE_HANDLE 0xff04 +#define NETIO_ERR_FILES_MAX 0xff05 +#define NETIO_ERR_READ 0xff06 diff --git a/harbour/contrib/hbnetio/netiocli.c b/harbour/contrib/hbnetio/netiocli.c new file mode 100644 index 0000000000..661368c0e4 --- /dev/null +++ b/harbour/contrib/hbnetio/netiocli.c @@ -0,0 +1,791 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * demonstration code for alternative RDD IO API which uses own + * very simple TCP/IP file server. + * All files which names starts 'net:' are redirected to this API. + * This is client code with + * NETIO_CONNECT( [], [], [] ) -> + * function which register alternative RDD IO API, sets server + * address and port and connection timeout parameter. + * Then it tries to connect to the server and returns .T. on success. + * + * Copyright 2009 Przemyslaw Czerpak + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +/* this has to be declared before hbapifs.h is included */ +#define _HB_FILE_IMPLEMENTATION_ + +#include "hbapi.h" +#include "hbapifs.h" +#include "hbapiitm.h" +#include "hbapierr.h" +#include "hbsocket.h" +#include "hbinit.h" +#include "hbvm.h" +#include "hbstack.h" +#include "hbthread.h" +#include "netio.h" + +/* + * client code + */ + +typedef struct _HB_CONCLI +{ + HB_COUNTER used; + PHB_ITEM mutex; + int timeout; + int port; + HB_SOCKET sd; + struct _HB_CONCLI * next; + char server[ 1 ]; +} +HB_CONCLI, * PHB_CONCLI; + +typedef struct _HB_FILE +{ + const HB_FILE_FUNCS * pFuncs; + PHB_CONCLI conn; + USHORT fd; +} +HB_FILE; + +typedef struct +{ + int timeout; + int port; + char server[ NETIO_SERVERNAME_MAX ]; +} HB_CONDATA, * PHB_CONDATA; + +/* MT macros */ +#define HB_NETIO_LOCK hb_threadEnterCriticalSection( &s_netioMtx ); +#define HB_NETIO_UNLOCK hb_threadLeaveCriticalSection( &s_netioMtx ); +static HB_CRITICAL_NEW( s_netioMtx ); + +static HB_TSD_NEW( s_conData, sizeof( HB_CONDATA ), NULL, NULL ); + +static PHB_CONCLI s_connections = NULL; + +static BOOL s_defaultInit = TRUE; +static char s_defaultServer[ NETIO_SERVERNAME_MAX ] = NETIO_DEFAULT_SERVER; +static int s_defaultPort = NETIO_DEFAULT_PORT; +static int s_defaultTimeOut = NETIO_DEFAULT_TIMEOUT; + +static const HB_FILE_FUNCS * s_fileMethods( void ); + +static long s_fileRecvAll( PHB_CONCLI conn, void * buffer, long len ) +{ + BYTE * ptr = ( BYTE * ) buffer; + long lRead = 0, l; + + while( lRead < len ) + { + l = hb_socketRecv( conn->sd, ptr + lRead, len - lRead, 0, -1 ); + if( l <= 0 ) + break; + lRead += l; + } + return lRead; +} + +static BOOL s_fileSendMsg( PHB_CONCLI conn, BYTE * msgbuf, + const void * data, long len, BOOL fWait ) +{ + BYTE buffer[ 2048 ]; + BYTE * msg, * ptr = NULL; + LONG lSent = 0, l; + BOOL fResult = FALSE; + + if( len == 0 ) + { + msg = msgbuf; + len = NETIO_MSGLEN; + } + else + { + len += NETIO_MSGLEN; + if( len > ( long ) sizeof( buffer ) ) + msg = ptr = ( BYTE * ) hb_xgrab( len ); + else + msg = buffer; + memcpy( msg, msgbuf, NETIO_MSGLEN ); + memcpy( msg + NETIO_MSGLEN, data, len - NETIO_MSGLEN ); + } + + while( lSent < len ) + { + l = hb_socketSend( conn->sd, msg + lSent, len - lSent, 0, -1 ); + if( l <= 0 ) + break; + lSent += l; + } + + if( ptr ) + hb_xfree( ptr ); + + if( lSent == len ) + { + if( fWait ) + { + int iMsg = HB_GET_LE_INT32( msgbuf ); + + if( s_fileRecvAll( conn, msgbuf, NETIO_MSGLEN ) == NETIO_MSGLEN ) + { + int iResult = HB_GET_LE_INT32( msgbuf ); + + if( iResult == NETIO_ERROR ) + hb_fsSetError( HB_GET_LE_UINT16( &msgbuf[ 4 ] ) ); + else if( iResult == iMsg ) + fResult = TRUE; + } + } + else + fResult = TRUE; + } + + return fResult; +} + +static PHB_CONCLI s_fileConNew( HB_SOCKET sd, const char * pszServer, + int iPort, int iTimeOut ) +{ + PHB_CONCLI conn; + int iLen; + + iLen = ( int ) strlen( pszServer ); + conn = ( PHB_CONCLI ) hb_xgrab( sizeof( HB_CONCLI ) + iLen ); + hb_atomic_set( &conn->used, 1 ); + conn->mutex = hb_threadMutexCreate( FALSE ); + conn->sd = sd; + conn->next = NULL; + conn->timeout = iTimeOut; + conn->port = iPort; + memcpy( conn->server, pszServer, iLen + 1 ); + + return conn; +} + +static void s_fileConFree( PHB_CONCLI conn ) +{ + hb_socketShutdown( conn->sd, HB_SOCKET_SHUT_RDWR ); + hb_socketClose( conn->sd ); + if( conn->mutex ) + hb_itemRelease( conn->mutex ); + hb_xfree( conn ); +} + +static void s_fileConRegister( PHB_CONCLI conn ) +{ + PHB_CONCLI * connPtr; + + HB_NETIO_LOCK + connPtr = &s_connections; + while( *connPtr ) + connPtr = &( *connPtr )->next; + *connPtr = conn; + HB_NETIO_UNLOCK +} + +static void s_fileConClose( PHB_CONCLI conn ) +{ + if( hb_atomic_dec( &conn->used ) ) + { + HB_NETIO_LOCK + if( hb_atomic_get( &conn->used ) == 0 ) + { + PHB_CONCLI * connPtr = &s_connections; + while( *connPtr ) + { + if( *connPtr == conn ) + { + *connPtr = conn->next; + break; + } + connPtr = &( *connPtr )->next; + } + } + else + conn = NULL; /* reused by other thread */ + HB_NETIO_UNLOCK + + if( conn ) + s_fileConFree( conn ); + } +} + +static PHB_CONCLI s_fileConFind( const char * pszServer, int iPort ) +{ + PHB_CONCLI conn; + + HB_NETIO_LOCK + conn = s_connections; + while( conn ) + { + if( conn->port == iPort && hb_stricmp( conn->server, pszServer ) == 0 ) + { + hb_atomic_inc( &conn->used ); + break; + } + conn = conn->next; + } + HB_NETIO_UNLOCK + + return conn; +} + +static BOOL s_fileConLock( PHB_CONCLI conn ) +{ + return !conn->mutex || hb_threadMutexLock( conn->mutex ); +} + +static void s_fileConUnlock( PHB_CONCLI conn ) +{ + if( conn->mutex ) + hb_threadMutexUnlock( conn->mutex ); +} + +static PHB_CONCLI s_fileConnect( const char ** pszFilename, + const char * pszServer, + int iPort, int iTimeOut ) +{ + PHB_CONCLI conn = NULL; + HB_SOCKET sd; + PHB_CONDATA pConData = ( PHB_CONDATA ) hb_stackGetTSD( &s_conData ); + char server[ NETIO_SERVERNAME_MAX ]; + + if( pConData->port ) + { + pszServer = pConData->server; + iPort = pConData->port; + iTimeOut = pConData->timeout; + } + else + { + if( !pszServer ) + pszServer = s_defaultServer; + if( !iPort ) + iPort = s_defaultPort; + if( iTimeOut == 0 || iTimeOut < -1 ) + iTimeOut = s_defaultTimeOut; + } + + if( pszFilename ) + { + /* decode server address and port if given as part of file name + * in format like: + * "192.168.0.1:2941:path/to/file" + */ + const char * psz = strchr( *pszFilename, ':' ); + if( psz ) + { + int iLen = ( int ) ( psz - *pszFilename ); + + if( iLen == 0 || iLen > 1 ) + { + char port_buf[ 10 ]; + if( iLen >= ( int ) sizeof( server ) ) + iLen = ( int ) sizeof( server ) - 1; + if( iLen > 0 ) + { + hb_strncpy( server, *pszFilename, iLen ); + pszServer = server; + } + *pszFilename = psz + 1; + iLen = 0; + while( HB_ISDIGIT( ( *pszFilename )[ iLen ] ) && + iLen < ( int ) sizeof( port_buf ) - 1 ) + { + port_buf[ iLen ] = ( *pszFilename )[ iLen ]; + ++iLen; + } + if( ( *pszFilename )[ iLen ] == ':' ) + { + if( iLen == 0 ) + ++( *pszFilename ); + else if( iLen > 0 ) + { + int iOverflow; + HB_LONG llPort; + + port_buf[ iLen ] = '\0'; + llPort = hb_strValInt( port_buf, &iOverflow ); + + if( !iOverflow && llPort > 0 && llPort < 0x10000 ) + { + *pszFilename += iLen + 1; + iPort = ( int ) llPort; + } + } + } + } + } + } + + conn = s_fileConFind( pszServer, iPort ); + if( conn == NULL ) + { + sd = hb_socketOpen( HB_SOCKET_PF_INET, HB_SOCKET_PT_STREAM, 0 ); + if( sd != HB_NO_SOCKET ) + { + void * pSockAddr; + unsigned uiLen; + + if( hb_socketInetAddr( &pSockAddr, &uiLen, pszServer, iPort ) ) + { + hb_socketSetKeepAlive( sd, TRUE ); + if( hb_socketConnect( sd, pSockAddr, uiLen, iTimeOut ) == 0 ) + { + BYTE msgbuf[ NETIO_MSGLEN ]; + UINT16 len = ( UINT16 ) strlen( NETIO_LOGINSTRID ); + + HB_PUT_LE_UINT32( &msgbuf[ 0 ], NETIO_LOGIN ); + HB_PUT_LE_UINT16( &msgbuf[ 4 ], len ); + memset( msgbuf + 6, '\0', sizeof( msgbuf ) - 6 ); + + conn = s_fileConNew( sd, pszServer, iPort, iTimeOut ); + sd = HB_NO_SOCKET; + + if( !s_fileSendMsg( conn, msgbuf, NETIO_LOGINSTRID, len, TRUE ) || + HB_GET_LE_UINT32( &msgbuf[ 4 ] ) != NETIO_CONNECTED ) + { + s_fileConFree( conn ); + conn = NULL; + } + else + s_fileConRegister( conn ); + } + hb_xfree( pSockAddr ); + } + if( !conn && sd != HB_NO_SOCKET ) + hb_socketClose( sd ); + } + } + + if( conn != NULL && s_defaultInit ) + { + HB_NETIO_LOCK + if( s_defaultInit ) + { + if( pszServer != s_defaultServer ) + hb_strncpy( s_defaultServer, pszServer, sizeof( s_defaultServer ) - 1 ); + s_defaultPort = iPort; + s_defaultTimeOut = iTimeOut; + s_defaultInit = FALSE; + } + HB_NETIO_UNLOCK + } + + return conn; +} + +static void s_netio_exit( void* cargo ) +{ + HB_SYMBOL_UNUSED( cargo ); + + while( s_connections ) + { + PHB_CONCLI conn = s_connections; + s_connections = conn->next; + s_fileConFree( conn ); + } +} + +static void s_netio_init( void ) +{ + static BOOL s_fInit = TRUE; + + if( s_fInit ) + { + hb_fileRegister( s_fileMethods() ); + hb_vmAtQuit( s_netio_exit, NULL ); + s_fInit = FALSE; + } +} + +HB_FUNC( NETIO_CONNECT ) +{ + const char * pszServer = hb_parc( 1 ); + int iPort = hb_parni( 2 ), iTimeOut = hb_parni( 3 ); + PHB_CONCLI conn = NULL; + + s_netio_init(); + + conn = s_fileConnect( NULL, pszServer, iPort, iTimeOut ); + if( conn ) + { + PHB_CONDATA pConData = ( PHB_CONDATA ) hb_stackGetTSD( &s_conData ); + + pConData->timeout = conn->timeout; + pConData->port = conn->port; + hb_strncpy( pConData->server, conn->server, sizeof( pConData->server ) - 1 ); + + s_fileConClose( conn ); + } + + hb_retl( conn != NULL ); +} + +/* Client methods + */ +static BOOL s_fileAccept( const char * pFilename ) +{ + return hb_strnicmp( pFilename, NETIO_FILE_PREFIX, NETIO_FILE_PREFIX_LEN ) == 0; +} + +static BOOL s_fileExists( const char * pFilename, char * pRetPath ) +{ + BOOL fResult = FALSE; + PHB_CONCLI conn; + + if( pRetPath ) + hb_strncpy( pRetPath, pFilename, HB_PATH_MAX - 1 ); + + pFilename += NETIO_FILE_PREFIX_LEN; + + conn = s_fileConnect( &pFilename, NULL, 0, 0 ); + if( conn ) + { + if( s_fileConLock( conn ) ) + { + BYTE msgbuf[ NETIO_MSGLEN ]; + UINT16 len = ( UINT16 ) strlen( pFilename ); + + HB_PUT_LE_UINT32( &msgbuf[ 0 ], NETIO_EXISTS ); + HB_PUT_LE_UINT16( &msgbuf[ 4 ], len ); + memset( msgbuf + 6, '\0', sizeof( msgbuf ) - 6 ); + fResult = s_fileSendMsg( conn, msgbuf, pFilename, len, TRUE ); + s_fileConUnlock( conn ); + } + s_fileConClose( conn ); + } + + return fResult; +} + +static BOOL s_fileDelete( const char * pFilename ) +{ + BOOL fResult = FALSE; + PHB_CONCLI conn; + + pFilename += NETIO_FILE_PREFIX_LEN; + + conn = s_fileConnect( &pFilename, NULL, 0, 0 ); + if( conn ) + { + if( s_fileConLock( conn ) ) + { + BYTE msgbuf[ NETIO_MSGLEN ]; + UINT16 len = ( UINT16 ) strlen( pFilename ); + + HB_PUT_LE_UINT32( &msgbuf[ 0 ], NETIO_DELETE ); + HB_PUT_LE_UINT16( &msgbuf[ 4 ], len ); + memset( msgbuf + 6, '\0', sizeof( msgbuf ) - 6 ); + fResult = s_fileSendMsg( conn, msgbuf, pFilename, len, TRUE ); + s_fileConUnlock( conn ); + } + s_fileConClose( conn ); + } + + return fResult; +} + +static PHB_FILE s_fileOpen( const char * pFilename, const char * pDefExt, + USHORT uiExFlags, const char * pPaths, + PHB_ITEM pError ) +{ + PHB_FILE pFile = NULL; + PHB_CONCLI conn; + const char * pszFile = pFilename + NETIO_FILE_PREFIX_LEN; + + HB_SYMBOL_UNUSED( pPaths ); + + conn = s_fileConnect( &pszFile, NULL, 0, 0 ); + if( conn ) + { + if( s_fileConLock( conn ) ) + { + BYTE msgbuf[ NETIO_MSGLEN ]; + UINT16 len = ( UINT16 ) strlen( pszFile ); + + HB_PUT_LE_UINT32( &msgbuf[ 0 ], NETIO_OPEN ); + HB_PUT_LE_UINT16( &msgbuf[ 4 ], len ); + HB_PUT_LE_UINT16( &msgbuf[ 6 ], uiExFlags ); + memset( msgbuf + 8, '\0', sizeof( msgbuf ) - 8 ); + if( pDefExt ) + hb_strncpy( ( char * ) &msgbuf[ 8 ], + ( const char * ) pDefExt, sizeof( msgbuf ) - 9 ); + + if( s_fileSendMsg( conn, msgbuf, pszFile, len, TRUE ) ) + { + pFile = ( PHB_FILE ) hb_xgrab( sizeof( HB_FILE ) ); + pFile->pFuncs = s_fileMethods(); + pFile->conn = conn; + pFile->fd = HB_GET_LE_UINT16( &msgbuf[ 4 ] ); + } + s_fileConUnlock( conn ); + } + + if( !pFile ) + s_fileConClose( conn ); + } + + if( pError ) + { + hb_errPutFileName( pError, pFilename ); + if( pFile == NULL ) + { + hb_errPutOsCode( pError, hb_fsError() ); + hb_errPutGenCode( pError, ( USHORT ) ( ( uiExFlags & FXO_TRUNCATE ) ? EG_CREATE : EG_OPEN ) ); + } + } + + return pFile; +} + +static void s_fileClose( PHB_FILE pFile ) +{ + if( s_fileConLock( pFile->conn ) ) + { + BYTE msgbuf[ NETIO_MSGLEN ]; + + HB_PUT_LE_UINT32( &msgbuf[ 0 ], NETIO_CLOSE ); + HB_PUT_LE_UINT16( &msgbuf[ 4 ], pFile->fd ); + memset( msgbuf + 6, '\0', sizeof( msgbuf ) - 6 ); + s_fileSendMsg( pFile->conn, msgbuf, NULL, 0, TRUE ); + s_fileConUnlock( pFile->conn ); + } + s_fileConClose( pFile->conn ); + hb_xfree( pFile ); +} + +static BOOL s_fileLock( PHB_FILE pFile, HB_FOFFSET ulStart, HB_FOFFSET ulLen, + int iType ) +{ + BOOL fResult = FALSE; + + if( s_fileConLock( pFile->conn ) ) + { + BYTE msgbuf[ NETIO_MSGLEN ]; + + HB_PUT_LE_UINT32( &msgbuf[ 0 ], NETIO_LOCK ); + HB_PUT_LE_UINT16( &msgbuf[ 4 ], pFile->fd ); + HB_PUT_LE_UINT64( &msgbuf[ 6 ], ulStart ); + HB_PUT_LE_UINT64( &msgbuf[ 14 ], ulLen ); + HB_PUT_LE_UINT16( &msgbuf[ 22 ], ( USHORT ) iType ); + memset( msgbuf + 24, '\0', sizeof( msgbuf ) - 24 ); + + fResult = s_fileSendMsg( pFile->conn, msgbuf, NULL, 0, TRUE ); + s_fileConUnlock( pFile->conn ); + } + + return fResult; +} + +static ULONG s_fileReadAt( PHB_FILE pFile, void * data, ULONG ulSize, + HB_FOFFSET llOffset ) +{ + ULONG ulResult = 0; + + if( s_fileConLock( pFile->conn ) ) + { + BYTE msgbuf[ NETIO_MSGLEN ]; + + HB_PUT_LE_UINT32( &msgbuf[ 0 ], NETIO_READ ); + HB_PUT_LE_UINT16( &msgbuf[ 4 ], pFile->fd ); + HB_PUT_LE_UINT32( &msgbuf[ 6 ], ulSize ); + HB_PUT_LE_UINT64( &msgbuf[ 10 ], llOffset ); + memset( msgbuf + 18, '\0', sizeof( msgbuf ) - 18 ); + + if( s_fileSendMsg( pFile->conn, msgbuf, NULL, 0, TRUE ) ) + { + ulResult = HB_GET_LE_UINT32( &msgbuf[ 4 ] ); + if( ulResult > 0 ) + { + if( ulResult > ulSize ) /* error, it should not happen, enemy attack? */ + ulResult = ulSize; + ulResult = s_fileRecvAll( pFile->conn, data, ulResult ); + } + hb_fsSetError( HB_GET_LE_UINT16( &msgbuf[ 8 ] ) ); + } + s_fileConUnlock( pFile->conn ); + } + + return ulResult; +} + +static ULONG s_fileWriteAt( PHB_FILE pFile, const void * data, ULONG ulSize, + HB_FOFFSET llOffset ) +{ + ULONG ulResult = 0; + + if( s_fileConLock( pFile->conn ) ) + { + BYTE msgbuf[ NETIO_MSGLEN ]; + + HB_PUT_LE_UINT32( &msgbuf[ 0 ], NETIO_WRITE ); + HB_PUT_LE_UINT16( &msgbuf[ 4 ], pFile->fd ); + HB_PUT_LE_UINT32( &msgbuf[ 6 ], ulSize ); + HB_PUT_LE_UINT64( &msgbuf[ 10 ], llOffset ); + memset( msgbuf + 18, '\0', sizeof( msgbuf ) - 18 ); + + if( s_fileSendMsg( pFile->conn, msgbuf, data, ulSize, TRUE ) ) + { + ulResult = HB_GET_LE_UINT32( &msgbuf[ 4 ] ); + hb_fsSetError( HB_GET_LE_UINT16( &msgbuf[ 8 ] ) ); + } + s_fileConUnlock( pFile->conn ); + } + + return ulResult; +} + +static BOOL s_fileTruncAt( PHB_FILE pFile, HB_FOFFSET llOffset ) +{ + BOOL fResult = FALSE; + + if( s_fileConLock( pFile->conn ) ) + { + BYTE msgbuf[ NETIO_MSGLEN ]; + + HB_PUT_LE_UINT32( &msgbuf[ 0 ], NETIO_TRUNC ); + HB_PUT_LE_UINT16( &msgbuf[ 4 ], pFile->fd ); + HB_PUT_LE_UINT64( &msgbuf[ 6 ], llOffset ); + memset( msgbuf + 14, '\0', sizeof( msgbuf ) - 14 ); + + fResult = s_fileSendMsg( pFile->conn, msgbuf, NULL, 0, TRUE ); + s_fileConUnlock( pFile->conn ); + } + + return fResult; +} + +static HB_FOFFSET s_fileSize( PHB_FILE pFile ) +{ + HB_FOFFSET llOffset = 0; + + if( s_fileConLock( pFile->conn ) ) + { + BYTE msgbuf[ NETIO_MSGLEN ]; + + HB_PUT_LE_UINT32( msgbuf, NETIO_SIZE ); + HB_PUT_LE_UINT16( &msgbuf[ 4 ], pFile->fd ); + memset( msgbuf + 6, '\0', sizeof( msgbuf ) - 6 ); + + if( s_fileSendMsg( pFile->conn, msgbuf, NULL, 0, TRUE ) ) + { + llOffset = HB_GET_LE_UINT64( &msgbuf[ 4 ] ); + hb_fsSetError( HB_GET_LE_UINT16( &msgbuf[ 12 ] ) ); + } + s_fileConUnlock( pFile->conn ); + } + + return llOffset; +} + +static void s_fileCommit( PHB_FILE pFile ) +{ + if( s_fileConLock( pFile->conn ) ) + { + BYTE msgbuf[ NETIO_MSGLEN ]; + + HB_PUT_LE_UINT32( msgbuf, NETIO_COMMIT ); + HB_PUT_LE_UINT16( &msgbuf[ 4 ], pFile->fd ); + memset( msgbuf + 6, '\0', sizeof( msgbuf ) - 6 ); + + s_fileSendMsg( pFile->conn, msgbuf, NULL, 0, FALSE ); + s_fileConUnlock( pFile->conn ); + } +} + +static HB_FHANDLE s_fileHandle( PHB_FILE pFile ) +{ + return pFile ? pFile->conn->sd : HB_NO_SOCKET; +} + +static const HB_FILE_FUNCS * s_fileMethods( void ) +{ + static const HB_FILE_FUNCS s_fileFuncs = + { + s_fileAccept, + s_fileExists, + s_fileDelete, + s_fileOpen, + s_fileClose, + s_fileLock, + s_fileReadAt, + s_fileWriteAt, + s_fileTruncAt, + s_fileSize, + s_fileCommit, + s_fileHandle + }; + + return &s_fileFuncs; +} + +/* set HB_NETIO_STARTUP_INIT macro if you want to register NETIO client + * automatically at application startup + */ +#if defined( HB_NETIO_STARTUP_INIT ) + +HB_CALL_ON_STARTUP_BEGIN( _hb_file_io_init_ ) + s_netio_init(); +HB_CALL_ON_STARTUP_END( _hb_file_io_init_ ) + +#if defined( HB_PRAGMA_STARTUP ) + #pragma startup _hb_file_io_init_ +#elif defined( HB_MSC_STARTUP ) + #if defined( HB_OS_WIN_64 ) + #pragma section( HB_MSC_START_SEGMENT, long, read ) + #endif + #pragma data_seg( HB_MSC_START_SEGMENT ) + static HB_$INITSYM hb_vm_auto_hb_file_io_init_ = _hb_file_io_init_; + #pragma data_seg() +#endif + +#endif /* HB_NETIO_STARTUP_INIT */ diff --git a/harbour/contrib/hbnetio/netiomt.prg b/harbour/contrib/hbnetio/netiomt.prg new file mode 100644 index 0000000000..d7ed9a6099 --- /dev/null +++ b/harbour/contrib/hbnetio/netiomt.prg @@ -0,0 +1,81 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * demonstration code for alternative RDD IO API which uses own + * very simple TCP/IP file server. + * All files which names starts 'net:' are redirected to this API. + * This is code for simple MT server which is activated by: + * NETIO_MTSERVER( [], [] ) -> | NIL + * and can be stopped by: + * NETIO_SERVERSTOP( , .T. ) + * + * Copyright 2009 Przemyslaw Czerpak + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +FUNCTION NETIO_MTSERVER( ... ) + LOCAL pListenSocket + + IF hb_mtvm() + pListenSocket := netio_listen( ... ) + IF !Empty( pListenSocket ) + hb_threadDetach( hb_threadStart( @netio_srvloop(), pListenSocket ) ) + ENDIF + ENDIF + RETURN pListenSocket + +STATIC FUNCTION NETIO_SRVLOOP( pListenSocket ) + LOCAL pConnectionSocket + + WHILE .T. + pConnectionSocket := netio_accept( pListenSocket ) + IF Empty( pConnectionSocket ) + EXIT + ENDIF + hb_threadDetach( hb_threadStart( @netio_server(), pConnectionSocket ) ) + pConnectionSocket := NIL + ENDDO + RETURN NIL diff --git a/harbour/contrib/hbnetio/netiosrv.c b/harbour/contrib/hbnetio/netiosrv.c new file mode 100644 index 0000000000..fc11a152d5 --- /dev/null +++ b/harbour/contrib/hbnetio/netiosrv.c @@ -0,0 +1,749 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * demonstration code for alternative RDD IO API which uses own + * very simple TCP/IP file server. + * All files which names starts 'net:' are redirected to this API. + * This is server code giving the following .prg functions: + * NETIO_LISTEN( [], [], [] ) + * -> | NIL + * NETIO_ACCEPT( [, ] ) + * -> | NIL + * NETIO_SERVER( ) -> NIL + * NETIO_SERVERSTOP( | , ) + * -> NIL + * + * Copyright 2009 Przemyslaw Czerpak + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#include "hbapi.h" +#include "hbapifs.h" +#include "hbapierr.h" +#include "hbsocket.h" +#include "hbinit.h" +#include "hbvm.h" +#include "hbthread.h" +#include "netio.h" + + +/* + * server code + */ + +typedef struct _HB_CONSRV +{ + HB_SOCKET sd; + PHB_FILE fileTable[ NETIO_FILES_MAX ]; + int filesCount; + int firstFree; + BOOL stop; + int rootPathLen; + char rootPath[ HB_PATH_MAX ]; +} +HB_CONSRV, * PHB_CONSRV; + +typedef struct _HB_LISTENSD +{ + HB_SOCKET sd; + BOOL stop; + char rootPath[ HB_PATH_MAX ]; +} +HB_LISTENSD, * PHB_LISTENSD; + + +static 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 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_close( PHB_CONSRV conn ) +{ + int i = 0; + + if( conn->sd != HB_NO_SOCKET ) + hb_socketClose( conn->sd ); + + 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; + } + conn->firstFree = 0; + 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 PHB_CONSRV s_consrvParam( int iParam ) +{ + PHB_CONSRV * conn_ptr = ( PHB_CONSRV * ) hb_parptrGC( s_consrv_destructor, + 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_gcAlloc( sizeof( PHB_CONSRV ), + s_consrv_destructor ); + *conn_ptr = conn; + hb_retptrGC( conn_ptr ); + } + else + hb_ret(); +} + +static PHB_CONSRV s_consrvNew( HB_SOCKET connsd, const char * szRootPath ) +{ + PHB_CONSRV conn = ( PHB_CONSRV ) memset( hb_xgrab( sizeof( HB_CONSRV ) ), + 0, sizeof( HB_CONSRV ) ); + conn->sd = connsd; + 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 ) +{ + BYTE * ptr = ( BYTE * ) buffer; + long lRead = 0, l; + + while( lRead < len && !conn->stop ) + { + 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; + } + + return lRead; +} + +static long s_srvSendAll( PHB_CONSRV conn, void * buffer, long len ) +{ + BYTE * ptr = ( BYTE * ) buffer; + long lSent = 0, l; + + while( lSent < len && !conn->stop ) + { + l = hb_socketSend( conn->sd, ptr + lSent, len - lSent, 0, 1000 ); + if( l <= 0 ) + { + if( hb_socketGetError() != HB_SOCKET_ERR_TIMEOUT || + hb_vmRequestQuery() != 0 ) + break; + } + else + lSent += l; + } + + 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 PHB_LISTENSD s_listenParam( int iParam, BOOL fError ) +{ + PHB_LISTENSD * lsd_ptr = ( PHB_LISTENSD * ) + hb_parptrGC( s_listensd_destructor, 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 ) +{ + 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; + 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_gcAlloc( sizeof( PHB_LISTENSD ), + s_listensd_destructor ); + *lsd_ptr = lsd; + hb_retptrGC( lsd_ptr ); + } + else + hb_ret(); +} + + +HB_FUNC( NETIO_SERVERSTOP ) +{ + PHB_LISTENSD lsd = s_listenParam( 1, FALSE ); + BOOL fStop = !HB_ISLOG( 2 ) || hb_parl( 2 ); + + if( lsd ) + lsd->stop = fStop; + else + { + PHB_CONSRV conn = s_consrvParam( 1 ); + if( conn ) + lsd->stop = fStop; + } +} + +HB_FUNC( NETIO_LISTEN ) +{ + int iPort = hb_parnidef( 1, NETIO_DEFAULT_PORT ); + const char * szAddress = hb_parc( 2 ); + const char * szRootPath = hb_parc( 3 ); + void * pSockAddr; + unsigned uiLen; + HB_SOCKET sd = HB_NO_SOCKET; + + 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 ); +} + +HB_FUNC( NETIO_ACCEPT ) +{ + PHB_LISTENSD lsd = s_listenParam( 1, TRUE ); + PHB_CONSRV conn = NULL; + + if( lsd && lsd->sd != HB_NO_SOCKET && !lsd->stop ) + { + HB_LONG timeout = HB_ISNUM( 2 ) ? hb_parnint( 2 ) : -1; + HB_SOCKET connsd; + + 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 ) + { + BOOL fOK = FALSE; + BYTE msgbuf[ 64 ]; + + conn = s_consrvNew( connsd, lsd->rootPath ); + + 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 ) + fOK = TRUE; + } + } + } + + if( !fOK ) + { + s_consrv_close( conn ); + conn = NULL; + } + } + } + + s_consrvRet( conn ); +} + +HB_FUNC( NETIO_SERVER ) +{ + PHB_CONSRV conn = s_consrvParam( 1 ); + + if( conn && conn->sd != HB_NO_SOCKET && !conn->stop ) + { + for( ;; ) + { + BYTE msgbuf[ NETIO_MSGLEN ], buffer[ 2048 ], * ptr = NULL, * msg; + BOOL fNoAnswer = FALSE; + long len = 0, size; + int iError = 0, iFileNo; + USHORT uiFalgs, uiFsError; + char * szExt; + PHB_FILE pFile; + HB_FOFFSET llOffset, llSize; + + msg = buffer; + + if( s_srvRecvAll( conn, msgbuf, NETIO_MSGLEN ) != NETIO_MSGLEN ) + break; + + switch( HB_GET_LE_UINT32( msgbuf ) ) + { + case NETIO_EXISTS: + size = HB_GET_LE_UINT16( &msgbuf[ 4 ] ); + if( size <= 0 ) + iError = NETIO_ERR_WRONG_PARAM; + else + { + if( size + conn->rootPathLen >= ( long ) sizeof( buffer ) ) + ptr = msg = ( BYTE * ) hb_xgrab( size + conn->rootPathLen + 1 ); + msg[ size ] = '\0'; + if( s_srvRecvAll( conn, msg, size ) != size ) + iError = NETIO_ERR_READ; + else + { + const char * szFile = s_consrvFilePath( ( char * ) msg, conn ); + + if( !szFile ) + iError = NETIO_ERR_WRONG_FILE_PATH; + else if( !hb_fileExists( ( const char * ) msg, NULL ) ) + iError = hb_fsError(); + 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 ) + iError = NETIO_ERR_WRONG_PARAM; + else + { + if( size + conn->rootPathLen >= ( long ) sizeof( buffer ) ) + ptr = msg = ( BYTE * ) hb_xgrab( size + conn->rootPathLen + 1 ); + msg[ size ] = '\0'; + if( s_srvRecvAll( conn, msg, size ) != size ) + iError = NETIO_ERR_READ; + else + { + const char * szFile = s_consrvFilePath( ( char * ) msg, conn ); + + if( !szFile ) + iError = NETIO_ERR_WRONG_FILE_PATH; + else if( !hb_fileDelete( ( const char * ) msg ) ) + iError = hb_fsError(); + else + { + HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_DELETE ); + memset( msg + 4, '\0', NETIO_MSGLEN - 4 ); + } + } + } + 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 ) + iError = NETIO_ERR_WRONG_PARAM; + else + { + if( size + conn->rootPathLen >= ( long ) sizeof( buffer ) ) + ptr = msg = ( BYTE * ) hb_xgrab( size + conn->rootPathLen + 1 ); + msg[ size ] = '\0'; + if( s_srvRecvAll( conn, msg, size ) != size ) + iError = NETIO_ERR_READ; + else if( conn->filesCount >= NETIO_FILES_MAX ) + iError = NETIO_ERR_FILES_MAX; + else + { + const char * szFile = s_consrvFilePath( ( char * ) msg, conn ); + + if( !szFile ) + iError = NETIO_ERR_WRONG_FILE_PATH; + else + { + pFile = hb_fileExtOpen( szFile, szExt, uiFalgs, NULL, NULL ); + if( !pFile ) + iError = hb_fsError(); + else + { + iFileNo = s_srvFileNew( conn, pFile ); + if( iFileNo < 0 ) + { + iError = 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 ) + iError = NETIO_ERR_WRONG_PARAM; + else + { + if( size >= ( long ) ( sizeof( buffer ) - NETIO_MSGLEN ) ) + ptr = msg = ( BYTE * ) hb_xgrab( size + NETIO_MSGLEN ); + pFile = s_srvFileGet( conn, iFileNo ); + if( pFile == NULL ) + iError = NETIO_ERR_WRONG_FILE_HANDLE; + else + { + len = hb_fileReadAt( pFile, msg + NETIO_MSGLEN, size, llOffset ); + uiFsError = hb_fsError(); + HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_READ ); + HB_PUT_LE_UINT32( &msg[ 4 ], len ); + HB_PUT_LE_UINT32( &msg[ 8 ], uiFsError ); + memset( msg + 10, '\0', NETIO_MSGLEN - 10 ); + } + } + 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 ) + iError = NETIO_ERR_WRONG_PARAM; + else + { + if( size >= ( long ) sizeof( buffer ) ) + ptr = msg = ( BYTE * ) hb_xgrab( size ); + if( s_srvRecvAll( conn, msg, size ) != size ) + iError = NETIO_ERR_READ; + else + { + pFile = s_srvFileGet( conn, iFileNo ); + if( pFile == NULL ) + iError = NETIO_ERR_WRONG_FILE_HANDLE; + else + { + size = hb_fileWriteAt( pFile, msg, size, llOffset ); + uiFsError = hb_fsError(); + HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_WRITE ); + HB_PUT_LE_UINT32( &msg[ 4 ], size ); + HB_PUT_LE_UINT32( &msg[ 8 ], uiFsError ); + memset( msg + 10, '\0', NETIO_MSGLEN - 10 ); + } + } + } + break; + + case NETIO_LOCK: + 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 ) + iError = NETIO_ERR_WRONG_FILE_HANDLE; + else if( !hb_fileLock( pFile, llOffset, llSize, uiFalgs ) ) + iError = hb_fsError(); + else + { + HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_LOCK ); + 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 ) + iError = NETIO_ERR_WRONG_FILE_HANDLE; + else if( !hb_fileTruncAt( pFile, llOffset ) ) + iError = hb_fsError(); + 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 ) + iError = NETIO_ERR_WRONG_FILE_HANDLE; + else + { + llOffset = hb_fileSize( pFile ); + uiFsError = hb_fsError(); + HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_SIZE ); + HB_PUT_LE_UINT64( &msg[ 4 ], llOffset ); + HB_PUT_LE_UINT32( &msg[ 12 ], uiFsError ); + memset( msg + 14, '\0', NETIO_MSGLEN - 14 ); + } + break; + + case NETIO_CLOSE: + iFileNo = HB_GET_LE_UINT16( &msgbuf[ 4 ] ); + pFile = s_srvFileFree( conn, iFileNo ); + if( pFile == NULL ) + iError = 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 = TRUE; + break; + + default: /* unkown message */ + iError = NETIO_ERR_UNKNOWN_COMMAND; + break; + } + + if( !fNoAnswer ) + { + if( iError != 0 ) + { + HB_PUT_LE_UINT32( &msg[ 0 ], NETIO_ERROR ); + HB_PUT_LE_UINT16( &msg[ 4 ], iError ); + memset( msg + 6, '\0', NETIO_MSGLEN - 6 ); + len = NETIO_MSGLEN; + } + else + len += NETIO_MSGLEN; + + if( s_srvSendAll( conn, msg, len ) != len ) + break; + } + + if( ptr ) + hb_xfree( ptr ); + } + } +} diff --git a/harbour/contrib/hbnetio/tests/netiotst.hbp b/harbour/contrib/hbnetio/tests/netiotst.hbp new file mode 100644 index 0000000000..762bf37aa6 --- /dev/null +++ b/harbour/contrib/hbnetio/tests/netiotst.hbp @@ -0,0 +1,7 @@ +# +# $Id: uhttpd2.hbp 11370 2009-06-15 18:22:09Z vszakats $ +# + +netiotst.prg +-lhbnetio +-mt diff --git a/harbour/contrib/hbnetio/tests/netiotst.prg b/harbour/contrib/hbnetio/tests/netiotst.prg new file mode 100644 index 0000000000..ef8ce32ab6 --- /dev/null +++ b/harbour/contrib/hbnetio/tests/netiotst.prg @@ -0,0 +1,92 @@ +#define DBNAME "net:127.0.0.1:2941:data/_tst_" + +request DBFCDX + +proc main() + local pSockSrv + + set exclusive off + rddSetDefault( "DBFCDX" ) + + pSockSrv := netio_mtserver() + + hb_idleSleep( 0.1 ) + + ? "NETIO_CONNECT():", netio_connect() + + createdb( DBNAME ) + testdb( DBNAME ) + wait + + test( DBNAME ) + wait + + ? + ? "deleteing..." + dbDrop( DBNAME ) + test( DBNAME ) + wait + + netio_serverstop( pSockSrv, .t. ) +return + +proc createdb( cName ) + local n + + dbCreate( cName, {{"F1", "C", 20, 0},; + {"F2", "M", 4, 0},; + {"F3", "N", 10, 2},; + {"F4", "T", 8, 0}} ) + ? "create neterr:", neterr(), hb_osError() + use (cName) + ? "use neterr:", neterr(), hb_osError() + while lastrec() < 100 + dbAppend() + n := recno() - 1 + field->F1 := chr( n % 26 + asc( "A" ) ) + " " + time() + field->F2 := field->F1 + field->F3 := n / 100 + field->F4 := hb_dateTime() + enddo + index on field->F1 tag T1 + index on field->F3 tag T3 + index on field->F4 tag T4 + close + ? +return + +proc testdb( cName ) + local i, j + use (cName) + ? "used:", used() + ? "nterr:", neterr() + ? "alias:", alias() + ? "lastrec:", lastrec() + ? "ordCount:", ordCount() + for i:=1 to ordCount() + ordSetFocus( i ) + ? i, "name:", ordName(), "key:", ordKey(), "keycount:", ordKeyCount() + next + ordSetFocus( 1 ) + dbgotop() + while !eof() + if ! field->F1 == field->F2 + ? "error at record:", recno() + ? " ! '" + field->F1 + "' == '" + field->F2 + "'" + endif + dbSkip() + enddo + wait + i := row() + j := col() + dbgotop() + browse() + setpos( i, j ) + close +return + +proc test( cName ) + ? "test start" + ? "File exists: ", dbExists( cName ) + ? "test end" +return diff --git a/harbour/harbour-wce-spec b/harbour/harbour-wce-spec index f385e8ef75..a7db7c5cbb 100644 --- a/harbour/harbour-wce-spec +++ b/harbour/harbour-wce-spec @@ -108,7 +108,7 @@ export HB_XBUILD=wce export HB_BIN_INSTALL=%{_bindir} export HB_INC_INSTALL=%{_includedir}/%{name} export HB_LIB_INSTALL=%{_libdir}/%{name} -export HB_CONTRIBLIBS="gtwvg hbbmcdx hbbtree hbclipsm hbct hbgt hbmisc hbmzip hbtip hbvpdf hbwin hbziparc rddado xhb %{!?_without_nf:hbnf} %{?_with_odbc:hbodbc} %{?_with_curl:hbcurl} %{?_with_ads:rddads} %{?_with_gd:hbgd} %{?_with_pgsql:hbpgsql} %{?_with_mysql:hbmysql} %{?_with_allegro:gtalleg}" +export HB_CONTRIBLIBS="gtwvg hbbmcdx hbbtree hbclipsm hbct hbgt hbmisc hbmzip hbnetio hbtip hbvpdf hbwin hbziparc rddado xhb %{!?_without_nf:hbnf} %{?_with_odbc:hbodbc} %{?_with_curl:hbcurl} %{?_with_ads:rddads} %{?_with_gd:hbgd} %{?_with_pgsql:hbpgsql} %{?_with_mysql:hbmysql} %{?_with_allegro:gtalleg}" export HB_EXTERNALLIBS=no make %{?_smp_mflags} @@ -137,7 +137,7 @@ export HB_XBUILD=wce export HB_BIN_INSTALL=%{_bindir} export HB_INC_INSTALL=%{_includedir}/%{name} export HB_LIB_INSTALL=%{_libdir}/%{name} -export HB_CONTRIBLIBS="gtwvg hbbmcdx hbbtree hbclipsm hbct hbgt hbmisc hbmzip hbtip hbvpdf hbwin hbziparc rddado xhb %{!?_without_nf:hbnf} %{?_with_odbc:hbodbc} %{?_with_curl:hbcurl} %{?_with_ads:rddads} %{?_with_gd:hbgd} %{?_with_pgsql:hbpgsql} %{?_with_mysql:hbmysql} %{?_with_allegro:gtalleg}" +export HB_CONTRIBLIBS="gtwvg hbbmcdx hbbtree hbclipsm hbct hbgt hbmisc hbmzip hbnetio hbtip hbvpdf hbwin hbziparc rddado xhb %{!?_without_nf:hbnf} %{?_with_odbc:hbodbc} %{?_with_curl:hbcurl} %{?_with_ads:rddads} %{?_with_gd:hbgd} %{?_with_pgsql:hbpgsql} %{?_with_mysql:hbmysql} %{?_with_allegro:gtalleg}" export HB_EXTERNALLIBS=no export _DEFAULT_BIN_DIR=$HB_BIN_INSTALL diff --git a/harbour/harbour-win-spec b/harbour/harbour-win-spec index f81b058c9f..06115942a3 100644 --- a/harbour/harbour-win-spec +++ b/harbour/harbour-win-spec @@ -108,7 +108,7 @@ export HB_XBUILD=win export HB_BIN_INSTALL=%{_bindir} export HB_INC_INSTALL=%{_includedir}/%{name} export HB_LIB_INSTALL=%{_libdir}/%{name} -export HB_CONTRIBLIBS="gtwvg hbbmcdx hbbtree hbclipsm hbct hbgt hbmisc hbmzip hbtip hbvpdf hbwin hbziparc rddado xhb %{!?_without_nf:hbnf} %{?_with_odbc:hbodbc} %{?_with_curl:hbcurl} %{?_with_ads:rddads} %{?_with_gd:hbgd} %{?_with_pgsql:hbpgsql} %{?_with_mysql:hbmysql} %{?_with_allegro:gtalleg}" +export HB_CONTRIBLIBS="gtwvg hbbmcdx hbbtree hbclipsm hbct hbgt hbmisc hbmzip hbnetio hbtip hbvpdf hbwin hbziparc rddado xhb %{!?_without_nf:hbnf} %{?_with_odbc:hbodbc} %{?_with_curl:hbcurl} %{?_with_ads:rddads} %{?_with_gd:hbgd} %{?_with_pgsql:hbpgsql} %{?_with_mysql:hbmysql} %{?_with_allegro:gtalleg}" export HB_EXTERNALLIBS=no make %{?_smp_mflags} @@ -137,7 +137,7 @@ export HB_XBUILD=win export HB_BIN_INSTALL=%{_bindir} export HB_INC_INSTALL=%{_includedir}/%{name} export HB_LIB_INSTALL=%{_libdir}/%{name} -export HB_CONTRIBLIBS="gtwvg hbbmcdx hbbtree hbclipsm hbct hbgt hbmisc hbmzip hbtip hbvpdf hbwin hbziparc rddado xhb %{!?_without_nf:hbnf} %{?_with_odbc:hbodbc} %{?_with_curl:hbcurl} %{?_with_ads:rddads} %{?_with_gd:hbgd} %{?_with_pgsql:hbpgsql} %{?_with_mysql:hbmysql} %{?_with_allegro:gtalleg}" +export HB_CONTRIBLIBS="gtwvg hbbmcdx hbbtree hbclipsm hbct hbgt hbmisc hbmzip hbnetio hbtip hbvpdf hbwin hbziparc rddado xhb %{!?_without_nf:hbnf} %{?_with_odbc:hbodbc} %{?_with_curl:hbcurl} %{?_with_ads:rddads} %{?_with_gd:hbgd} %{?_with_pgsql:hbpgsql} %{?_with_mysql:hbmysql} %{?_with_allegro:gtalleg}" export HB_EXTERNALLIBS=no export _DEFAULT_BIN_DIR=$HB_BIN_INSTALL diff --git a/harbour/harbour.spec b/harbour/harbour.spec index a26646ae87..8268655499 100644 --- a/harbour/harbour.spec +++ b/harbour/harbour.spec @@ -81,7 +81,7 @@ %define hb_idir export HB_INC_INSTALL=%{_includedir}/%{name} %define hb_ldir export HB_LIB_INSTALL=%{_libdir}/%{name} %define hb_cmrc export HB_COMMERCE=%{?_without_gpllib:yes} -%define hb_ctrb export HB_CONTRIBLIBS="hbbmcdx hbbtree hbclipsm hbct hbgt hbmisc hbmzip hbtip hbtpathy hbhpdf hbvpdf hbziparc xhb rddsql %{!?_without_nf:hbnf} %{?_with_odbc:hbodbc} %{?_with_curl:hbcurl} %{?_with_libharu:hbhpdf} %{?_with_ads:rddads} %{?_with_gd:hbgd} %{?_with_pgsql:hbpgsql} %{?_with_mysql:hbmysql} %{?_with_fbsql:hbfbird} %{?_with_allegro:gtalleg}" +%define hb_ctrb export HB_CONTRIBLIBS="hbbmcdx hbbtree hbclipsm hbct hbgt hbmisc hbmzip hbnetio hbtip hbtpathy hbhpdf hbvpdf hbziparc xhb rddsql %{!?_without_nf:hbnf} %{?_with_odbc:hbodbc} %{?_with_curl:hbcurl} %{?_with_libharu:hbhpdf} %{?_with_ads:rddads} %{?_with_gd:hbgd} %{?_with_pgsql:hbpgsql} %{?_with_mysql:hbmysql} %{?_with_fbsql:hbfbird} %{?_with_allegro:gtalleg}" %define hb_extrn export HB_EXTERNALLIBS=no %define hb_env %{hb_plat} ; %{hb_cc} ; %{hb_cflag} ; %{hb_lflag} ; %{hb_gpm} ; %{hb_crs} ; %{hb_sln} ; %{hb_x11} ; %{hb_bdir} ; %{hb_idir} ; %{hb_ldir} ; %{hb_ctrb} ; %{hb_extrn} ; %{hb_cmrc} %define hb_host www.harbour-project.org @@ -659,6 +659,7 @@ rm -rf $RPM_BUILD_ROOT %{_libdir}/%{name}/libhbbtree.a %{_libdir}/%{name}/libhbmisc.a %{_libdir}/%{name}/libhbmzip.a +%{_libdir}/%{name}/libhbnetio.a %{_libdir}/%{name}/libhbct.a %{_libdir}/%{name}/libhbtip*.a %{_libdir}/%{name}/libxhb.a