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( [<cServer>], [<cPort>], [<nTimeOut>] ) -> <lOK>
      function to register alternative NETIO RDD API and set default
      server address and port.
         <cServer>  - server addres       (default 127.0.0.1)
         <cPort>    - server port         (default 2941)
         <nTimeOut> - 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( [<nPort>], [<cAddress>], [<cRootDir>] )
                                                -> <pListenSocket> | NIL
      accept new connection on NETIO listen socket:
         NETIO_ACCEPT( <pListenSocket> [, <nTimeOut>] )
                                                -> <pConnectionSocket> | NIL
      start connection server:
         NETIO_SERVER( <pConnectionSocket> ) -> NIL
      stop connection accepting or connection server:
         NETIO_SERVERSTOP( <pListenSocket> | <pConnectionSocket>, <lStop> )
                                                -> NIL
      activate MT NETIO server (it needs MT HVM):
         NETIO_MTSERVER( [<nPort>], [<cAddress>] ) -> <pListenSocket> | 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.
This commit is contained in:
Przemyslaw Czerpak
2009-08-31 22:56:45 +00:00
parent a596216b49
commit 08e0268da4
13 changed files with 1946 additions and 6 deletions

View File

@@ -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( [<cServer>], [<cPort>], [<nTimeOut>] ) -> <lOK>
function to register alternative NETIO RDD API and set default
server address and port.
<cServer> - server addres (default 127.0.0.1)
<cPort> - server port (default 2941)
<nTimeOut> - 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( [<nPort>], [<cAddress>], [<cRootDir>] )
-> <pListenSocket> | NIL
accept new connection on NETIO listen socket:
NETIO_ACCEPT( <pListenSocket> [, <nTimeOut>] )
-> <pConnectionSocket> | NIL
start connection server:
NETIO_SERVER( <pConnectionSocket> ) -> NIL
stop connection accepting or connection server:
NETIO_SERVERSTOP( <pListenSocket> | <pConnectionSocket>, <lStop> )
-> NIL
activate MT NETIO server (it needs MT HVM):
NETIO_MTSERVER( [<nPort>], [<cAddress>] ) -> <pListenSocket> | 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

View File

@@ -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 "$@"

View File

@@ -17,6 +17,7 @@ DIRS := \
hbgt \
hbmisc \
hbmzip \
hbnetio \
hbnf \
hbodbc \
hbsqlit3 \

View File

@@ -0,0 +1,16 @@
#
# $Id$
#
ROOT := ../../
LIBNAME := hbnetio
C_SOURCES := \
netiosrv.c \
netiocli.c \
PRG_SOURCES := \
netiomt.prg \
include $(TOP)$(ROOT)config/lib.mk

View File

@@ -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 <druzus / at / priv.onet.pl>
* 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

View File

@@ -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( [<cServer>], [<cPort>], [<nTimeOut>] ) -> <lOK>
* 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 <druzus / at / priv.onet.pl>
* 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 */

View File

@@ -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( [<nPort>], [<cAddress>] ) -> <pListenSocket> | NIL
* and can be stopped by:
* NETIO_SERVERSTOP( <pListenSocket>, .T. )
*
* Copyright 2009 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
* 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

View File

@@ -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( [<nPort>], [<cAddress>], [<cRootDir>] )
* -> <pListenSocket> | NIL
* NETIO_ACCEPT( <pListenSocket> [, <nTimeOut>] )
* -> <pConnectionSocket> | NIL
* NETIO_SERVER( <pConnectionSocket> ) -> NIL
* NETIO_SERVERSTOP( <pListenSocket> | <pConnectionSocket>, <lStop> )
* -> NIL
*
* Copyright 2009 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
* 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 );
}
}
}

View File

@@ -0,0 +1,7 @@
#
# $Id: uhttpd2.hbp 11370 2009-06-15 18:22:09Z vszakats $
#
netiotst.prg
-lhbnetio
-mt

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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