2010-06-09 23:38 UTC+0200 Viktor Szakats (harbour.01 syenar.hu)

* include/hbsocket.ch
    + Added address info array positions.

  * src/rtl/hbsockhb.c
    - Deleted spaces @ EOL.

  * contrib/hbtpathy/telepath.prg
  * contrib/hbcomm/tests/test.prg
  * contrib/hbcomm/hbcomm.prg
  * contrib/hbsms/hbsms.prg
    ! Fixed HB_COMRECV() which requires a preallocated string
      to be passed.
      (no testing done, please review me, I'm almost sure I've
      made mistakes here)

  * examples/httpsrv/uhttpd.hbp
  * examples/httpsrv/uhttpd.prg
  - examples/httpsrv/socket.c
    + Changed to use new natic SOCKET API.
This commit is contained in:
Viktor Szakats
2010-06-09 21:38:32 +00:00
parent b4fb0856f5
commit ea7e1d15b9
10 changed files with 84 additions and 455 deletions

View File

@@ -1,281 +0,0 @@
/*
* $Id$
*/
/*
* Harbour Project source code:
* socket API
*
* Copyright 2009 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
* www - http://harbour-project.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
*
* As a special exception, the Harbour Project gives permission for
* additional uses of the text contained in its release of Harbour.
*
* The exception is that, if you link the Harbour libraries with other
* files to produce an executable, this does not by itself cause the
* resulting executable to be covered by the GNU General Public License.
* Your use of that executable is in no way restricted on account of
* linking the Harbour library code into it.
*
* This exception does not however invalidate any other reasons why
* the executable file might be covered by the GNU General Public License.
*
* This exception applies only to the code released by the Harbour
* Project under the name Harbour. If you copy code from other
* Harbour Project or Free Software Foundation releases into a copy of
* Harbour, as the General Public License permits, the exception does
* not apply to the code that you add in this way. To avoid misleading
* anyone as to the status of such modified files, you must delete
* this exception notice from them.
*
* If you write modifications of your own for Harbour, it is your choice
* whether to permit this exception to apply to your modifications.
* If you do not wish that, delete this exception notice.
*
*/
/*
Function naming:
The intention of this library is to be as close as possible to the original
socket implementation. This supposed to be valid for function names also,
but some of the names are very platform dependent, ex., WSA*() functions.
select() function name is reserved for standard Harbour's function, so,
socket_*() prefix was used:
socket_init() - WSAStartup()
socket_exit() - WSACleanup()
socket_error() - WSALastError()
socket_select() - select()
Finally I renamed all functions to have socket_*() prefix to be more "prefix
compatible" and not to occupy a general function names like send(), bind(),
accept(), listen(), etc.:
socket_create() - socket()
socket_close() - closesocket()
socket_shutdown() - shutdown()
socket_bind() - bind()
socket_listen() - listen()
socket_accept() - accept()
socket_send() - send()
socket_recv() - recv()
socket_recv() - recv()
socket_getsockname() - getsockname()
socket_getpeername() - getpeername()
Types mapping:
SOCKET
UINT_PTR in Windows, let's map it to pointer type, and INVALID_SOCKET value to NIL
struct sockaddr
It is not only IP addresses, also can be IPX, etc. All network-host byte order
conversion should be hidden from Harbour API. So, let's map to:
{ adress_familly, ... }
AF_INET: { AF_INET, cAddr, nPort }
other: { AF_?, cAddressDump }
*/
#include "hbsocket.h"
#include "hbapiitm.h"
static HB_SOCKET hb_parsocket( int iParam )
{
return HB_ISPOINTER( iParam ) ? ( HB_SOCKET ) ( HB_PTRDIFF )
hb_parptr( iParam ) : HB_NO_SOCKET;
}
static void hb_retsocket( HB_SOCKET hSocket )
{
if( hSocket != HB_NO_SOCKET )
hb_retptr( ( void * ) ( HB_PTRDIFF ) hSocket );
}
static HB_SOCKET hb_itemGetSocket( PHB_ITEM pSocket )
{
if( pSocket && HB_IS_POINTER( pSocket ) )
return ( HB_SOCKET ) ( HB_PTRDIFF ) hb_itemGetPtr( pSocket );
else
return HB_NO_SOCKET;
}
HB_FUNC( SOCKET_INIT )
{
hb_retni( hb_socketInit() );
}
HB_FUNC( SOCKET_EXIT )
{
hb_socketCleanup();
}
HB_FUNC( SOCKET_ERROR )
{
hb_retni( hb_socketGetError() );
}
HB_FUNC( SOCKET_CREATE )
{
hb_retsocket( hb_socketOpen( hb_parnidef( 1, HB_SOCKET_PF_INET ),
hb_parnidef( 2, HB_SOCKET_PT_STREAM ),
hb_parnidef( 3, HB_SOCKET_IPPROTO_TCP ) ) );
}
HB_FUNC( SOCKET_CLOSE )
{
hb_retni( hb_socketClose( hb_parsocket( 1 ) ) );
}
HB_FUNC( SOCKET_BIND )
{
void * sa;
unsigned len;
if( hb_socketAddrFromItem( &sa, &len, hb_param( 2, HB_IT_ANY ) ) )
{
hb_retni( hb_socketBind( hb_parsocket( 1 ), sa, len ) );
hb_xfree( sa );
}
}
HB_FUNC( SOCKET_LISTEN )
{
hb_retni( hb_socketListen( hb_parsocket( 1 ), hb_parnidef( 2, 10 ) ) );
}
HB_FUNC( SOCKET_ACCEPT )
{
if( HB_ISBYREF( 2 ) )
{
void * sa;
unsigned len;
PHB_ITEM pItem;
hb_retsocket( hb_socketAccept( hb_parsocket( 1 ), &sa, &len,
HB_ISNUM( 3 ) ? hb_parnint( 3 ) : -1 ) );
pItem = hb_socketAddrToItem( sa, len );
if( pItem )
{
hb_itemParamStoreForward( 2, pItem );
hb_itemRelease( pItem );
}
else
hb_stor( 2 );
if( sa )
hb_xfree( sa );
}
else
hb_retsocket( hb_socketAccept( hb_parsocket( 1 ), NULL, 0,
HB_ISNUM( 3 ) ? hb_parnint( 3 ) : -1 ) );
}
HB_FUNC( SOCKET_SHUTDOWN )
{
hb_retni( hb_socketShutdown( hb_parsocket( 1 ),
hb_parnidef( 2, HB_SOCKET_SHUT_RDWR ) ) );
}
HB_FUNC( SOCKET_RECV )
{
char * pBuf;
long len;
len = hb_parni( 3 );
if( len <= 0 )
len = 4096;
pBuf = ( char * ) hb_xgrab( len + 1 );
len = hb_socketRecv( hb_parsocket( 1 ), pBuf, len, hb_parni( 4 ),
HB_ISNUM( 5 ) ? hb_parnint( 5 ) : -1 );
hb_retni( len );
hb_storclen( pBuf, len > 0 ? len : 0, 2 );
hb_xfree( pBuf );
}
HB_FUNC( SOCKET_SEND )
{
hb_retni( hb_socketSend( hb_parsocket( 1 ), hb_parc( 2 ), hb_parclen( 2 ),
hb_parni( 4 ), HB_ISNUM( 5 ) ? hb_parnint( 5 ) : -1 ) );
}
HB_FUNC( SOCKET_GETSOCKNAME )
{
void * sa;
unsigned len;
int iRet;
iRet = hb_socketGetSockName( hb_parsocket( 1 ), &sa, &len );
hb_retni( iRet );
if( HB_ISBYREF( 2 ) )
{
PHB_ITEM pItem = hb_socketAddrToItem( sa, len );
if( pItem )
{
hb_itemParamStoreForward( 2, pItem );
hb_itemRelease( pItem );
}
else
hb_stor( 2 );
}
if( sa )
hb_xfree( sa );
}
HB_FUNC( SOCKET_GETPEERNAME )
{
void * sa;
unsigned len;
int iRet;
iRet = hb_socketGetPeerName( hb_parsocket( 1 ), &sa, &len );
hb_retni( iRet );
if( HB_ISBYREF( 2 ) )
{
PHB_ITEM pItem = hb_socketAddrToItem( sa, len );
if( pItem )
{
hb_itemParamStoreForward( 2, pItem );
hb_itemRelease( pItem );
}
else
hb_stor( 2 );
}
if( sa )
hb_xfree( sa );
}
HB_FUNC( SOCKET_CONNECT )
{
void * sa;
unsigned len;
if( hb_socketAddrFromItem( &sa, &len, hb_param( 2, HB_IT_ANY ) ) )
{
hb_retni( hb_socketConnect( hb_parsocket( 1 ), sa, len,
HB_ISNUM( 3 ) ? hb_parnint( 3 ) : -1 ) );
hb_xfree( sa );
}
}
HB_FUNC( SOCKET_SELECT )
{
hb_retni( hb_socketSelect( hb_param( 1, HB_IT_ARRAY ), HB_ISBYREF( 1 ),
hb_param( 2, HB_IT_ARRAY ), HB_ISBYREF( 2 ),
hb_param( 3, HB_IT_ARRAY ), HB_ISBYREF( 3 ),
HB_ISNUM( 4 ) ? hb_parnint( 4 ) : -1,
hb_itemGetSocket ) );
}

View File

@@ -2,6 +2,6 @@
# $Id$
#
-mt -gui uhttpd.prg cgifunc.prg cookie.prg session.prg socket.c
-mt -gui uhttpd.prg cgifunc.prg cookie.prg session.prg
-l{win}hbwin

View File

@@ -93,6 +93,8 @@
#include "hbextern.ch" // need this to use with HRB
#include "hbsocket.ch"
#ifdef GD_SUPPORT
// adding GD support
REQUEST GDIMAGE, GDIMAGECHAR, GDCHART
@@ -103,14 +105,6 @@
#stdout "Lib GD support disabled"
#endif
#ifdef USE_HB_INET
#define APP_INET_SUPPORT "_INET"
#stdout "inet socket API"
#else
#define APP_INET_SUPPORT ""
#stdout "custom socket API"
#endif
#ifdef FIXED_THREADS
#define APP_DT_SUPPORT "_FIXED_THREADS"
#stdout "Fixed # of threads"
@@ -121,7 +115,7 @@
#define APP_NAME "uhttpd"
#define APP_VER_NUM "0.4.4"
#define APP_VERSION APP_VER_NUM + APP_GD_SUPPORT + APP_INET_SUPPORT + APP_DT_SUPPORT
#define APP_VERSION APP_VER_NUM + APP_GD_SUPPORT + APP_DT_SUPPORT
#define AF_INET 2
@@ -180,10 +174,6 @@ STATIC s_aServiceThreads := {}
STATIC s_hHRBModules := {=>}
STATIC s_aDirectoryIndex
#ifdef USE_HB_INET
STATIC s_cLocalAddress, s_nLocalPort
#endif
STATIC s_hActions := { ;
/*"default-handler" => @Handler_Default() ,*/; // default handler
/*"send-as-is" => @Handler_SendAsIs() ,*/;
@@ -542,27 +532,12 @@ FUNCTION MAIN( ... )
// SOCKET CREATION
// --------------------------------------------------------------------------
#ifdef USE_HB_INET
hListen := hb_InetServer( nPort )
IF hb_InetErrorCode( hListen ) != 0
? "Bind Error"
WAIT
hListen := hb_socketOpen()
IF ! hb_socketBind( hListen, { AF_INET, "0.0.0.0", nPort } )
? "bind() error", hb_socketGetError()
ELSEIF ! hb_socketListen( hListen )
? "listen() error", hb_socketGetError()
ELSE
s_nLocalPort := hb_InetPort( hListen )
s_cLocalAddress := hb_InetAddress( hListen )
hb_InetTimeOut( hListen, 3000 )
#else
hListen := socket_create()
IF socket_bind( hListen, { AF_INET, "0.0.0.0", nPort } ) == -1
? "bind() error", socket_error()
ELSEIF socket_listen( hListen ) == -1
? "listen() error", socket_error()
ELSE
#endif
// --------------------------------------------------------------------------------- //
// Starting Accept connection thread
// --------------------------------------------------------------------------------- //
@@ -626,27 +601,16 @@ FUNCTION MAIN( ... )
ENDIF
// Wait a connection
#ifdef USE_HB_INET
IF HB_InetDataReady( hListen, 100 ) > 0
#else
IF socket_select( { hListen },,, 50 ) > 0
#endif
IF hb_socketSelect( { hListen },,,,,, 50 ) > 0
// reset remote values
aRemote := NIL
// Accept a remote connection
#ifdef USE_HB_INET
hSocket := hb_InetAccept( hListen )
#else
hSocket := socket_accept( hListen, @aRemote )
#endif
hSocket := hb_socketAccept( hListen, @aRemote )
IF hSocket == NIL
#ifdef USE_HB_INET
WriteToConsole( hb_StrFormat( "accept() error" ) )
#else
WriteToConsole( hb_StrFormat( "accept() error: %s", socket_error() ) )
#endif
WriteToConsole( hb_StrFormat( "accept() error: %s", hb_socketGetError() ) )
ELSE
@@ -681,11 +645,7 @@ FUNCTION MAIN( ... )
WriteToConsole( "--- Quitting " + APP_NAME + " ---" )
// Close socket
#ifdef USE_HB_INET
hb_InetClose( hListen )
#else
socket_close( hListen )
#endif
hb_socketClose( hListen )
// Close log files
FCLOSE( s_hfileLogAccess )
@@ -802,12 +762,8 @@ STATIC FUNCTION AcceptConnections()
// If I have no more of service threads to use ... (DOS attack ?)
IF nServiceConnections > nMaxServiceThreads
// DROP connection
#ifdef USE_HB_INET
hb_InetClose( hSocket )
#else
socket_shutdown( hSocket )
socket_close( hSocket )
#endif
hb_socketShutdown( hSocket )
hb_socketClose( hSocket )
// If I have no service threads in use ...
ELSEIF nServiceConnections >= nServiceThreads
@@ -949,11 +905,7 @@ STATIC FUNCTION ProcessConnection()
#endif
IF nLen == -1
#ifdef USE_HB_INET
? "recv() error:", hb_InetErrorCode( hSocket ), hb_InetErrorDesc( hSocket )
#else
? "recv() error:", socket_error()
#endif
? "recv() error:", hb_socketGetError()
ELSEIF nLen == 0 /* connection closed */
ELSE
@@ -996,13 +948,8 @@ STATIC FUNCTION ProcessConnection()
nParseTime := hb_milliseconds() - nMsecs
WriteToConsole( "Page served in : " + Str( nParseTime/1000, 7, 4 ) + " seconds" )
#ifdef USE_HB_INET
hb_InetClose( hSocket )
hSocket := NIL
#else
socket_shutdown( hSocket )
socket_close( hSocket )
#endif
hb_socketShutdown( hSocket )
hb_socketClose( hSocket )
IF hb_mutexLock( s_hmtxBusy )
s_nConnections--
@@ -1107,11 +1054,7 @@ STATIC FUNCTION ServiceConnection()
nLen := readRequest( hSocket, @cRequest )
IF nLen == -1
#ifdef USE_HB_INET
? "recv() error:", hb_InetErrorCode( hSocket ), hb_InetErrorDesc( hSocket )
#else
? "recv() error:", socket_error()
#endif
? "recv() error:", hb_socketGetError()
ELSEIF nLen == 0 /* connection closed */
ELSE
@@ -1149,13 +1092,8 @@ STATIC FUNCTION ServiceConnection()
nParseTime := hb_milliseconds() - nMsecs
WriteToConsole( "Page served in : " + Str( nParseTime/1000, 7, 4 ) + " seconds" )
#ifdef USE_HB_INET
hb_InetClose( hSocket )
hSocket := NIL
#else
socket_shutdown( hSocket )
socket_close( hSocket )
#endif
hb_socketShutdown( hSocket )
hb_socketClose( hSocket )
IF hb_mutexLock( s_hmtxBusy )
s_nServiceConnections--
@@ -1690,25 +1628,6 @@ STATIC FUNCTION CGIKill( hProc, hmtxCGIKill )
RETURN nErrorLevel
INIT PROCEDURE SocketInit()
#ifdef USE_HB_INET
hb_InetInit()
#else
IF socket_init() != 0
? "socket_init() error"
ENDIF
#endif
RETURN
EXIT PROCEDURE SocketExit()
#ifdef USE_HB_INET
hb_InetCleanup()
#else
socket_exit()
#endif
RETURN
/********************************************************************
Public helper functions
@@ -1781,15 +1700,10 @@ STATIC FUNCTION readRequest( hSocket, /* @ */ cRequest )
LOCAL cBuf, nLen, nPos
/* receive query */
#ifdef USE_HB_INET
cRequest := hb_InetRecvEndBlock( hSocket, CR_LF + CR_LF, @nLen )
IF nLen > 0
cRequest += CR_LF + CR_LF
ENDIF
#else
cRequest := ""
DO WHILE .T.
nLen := socket_recv( hSocket, @cBuf )
cBuf := Space( 1 )
nLen := hb_socketRecv( hSocket, @cBuf )
IF nLen <= 0
EXIT
ENDIF
@@ -1798,7 +1712,6 @@ STATIC FUNCTION readRequest( hSocket, /* @ */ cRequest )
EXIT
ENDIF
ENDDO
#endif
/* receive CONTENT-LENGTH data */
IF nLen > 0
@@ -1806,28 +1719,19 @@ STATIC FUNCTION readRequest( hSocket, /* @ */ cRequest )
IF nPos > 0
nPos := Val( Substr( cRequest, nPos + 17, 10 ) )
IF nPos > 0
#ifdef USE_HB_INET
cBuf := Space( nPos )
nLen := hb_InetRecvAll( hSocket, @cBuf, nPos )
IF nLen < 0
nLen := -1
ELSE
cRequest += Left( cBuf, nLen )
ENDIF
#else
/* we have to decrease number of bytes to read by already read
* data after CR_LF + CR_LF
*/
nPos -= Len( cRequest ) - At( CR_LF + CR_LF, cRequest ) - 3
WHILE nPos > 0
nLen := socket_recv( hSocket, @cBuf, nPos )
cBuf := Space( 1 )
nLen := hb_socketRecv( hSocket, @cBuf, nPos )
IF nLen <= 0
EXIT
ENDIF
cRequest += cBuf
nPos -= nLen
ENDDO
#endif
ENDIF
ENDIF
ENDIF
@@ -1842,55 +1746,32 @@ STATIC FUNCTION sendReply( hSocket, cSend )
LOCAL nError := 0
LOCAL nLen
#ifdef USE_HB_INET
DO WHILE LEN( cSend ) > 0
IF ( nLen := hb_InetSendAll( hSocket, cSend ) ) == -1
? "send() error:", hb_InetErrorCode( hSocket ), HB_InetErrorDesc( hSocket )
WriteToConsole( hb_StrFormat( "ProcessConnection() - send() error: %s, cSend = %s, hSocket = %s", hb_InetErrorDesc( hSocket ), cSend, hSocket ) )
IF ( nLen := hb_socketSend( hSocket, cSend ) ) == -1
? "send() error:", hb_socketGetError()
WriteToConsole( hb_StrFormat( "ServiceConnection() - send() error: %s, cSend = %s, hSocket = %s", hb_socketGetError(), cSend, hSocket ) )
EXIT
ELSEIF nLen > 0
cSend := SUBSTR( cSend, nLen + 1 )
ENDIF
ENDDO
#else
DO WHILE LEN( cSend ) > 0
IF ( nLen := socket_send( hSocket, cSend ) ) == -1
? "send() error:", socket_error()
WriteToConsole( hb_StrFormat( "ServiceConnection() - send() error: %s, cSend = %s, hSocket = %s", socket_error(), cSend, hSocket ) )
EXIT
ELSEIF nLen > 0
cSend := SUBSTR( cSend, nLen + 1 )
ENDIF
ENDDO
#endif
RETURN nError
STATIC PROCEDURE defineServer( hSocket )
#ifndef USE_HB_INET
LOCAL aI
#endif
// define _SERVER vars (address part)
#ifdef USE_HB_INET
_SERVER[ "REMOTE_ADDR" ] := hb_InetAddress( hSocket )
_SERVER[ "REMOTE_HOST" ] := _SERVER[ "REMOTE_ADDR" ] // no reverse DNS
_SERVER[ "REMOTE_PORT" ] := hb_InetPort( hSocket )
_SERVER[ "SERVER_ADDR" ] := s_cLocalAddress
_SERVER[ "SERVER_PORT" ] := LTrim( Str( s_nLocalPort ) )
#else
IF socket_getpeername( hSocket, @aI ) != -1
_SERVER[ "REMOTE_ADDR" ] := aI[2]
IF ! Empty( aI := hb_socketGetPeerName( hSocket ) )
_SERVER[ "REMOTE_ADDR" ] := aI[ HB_SOCKET_ADINFO_ADDRESS ]
_SERVER[ "REMOTE_HOST" ] := _SERVER[ "REMOTE_ADDR" ] // no reverse DNS
_SERVER[ "REMOTE_PORT" ] := aI[3]
_SERVER[ "REMOTE_PORT" ] := aI[ HB_SOCKET_ADINFO_PORT ]
ENDIF
IF socket_getsockname( hSocket, @aI ) != -1
_SERVER[ "SERVER_ADDR" ] := aI[2]
_SERVER[ "SERVER_PORT" ] := LTrim( Str( aI[3] ) )
IF ! Empty( aI := hb_socketGetSockName( hSocket ) )
_SERVER[ "SERVER_ADDR" ] := aI[ HB_SOCKET_ADINFO_ADDRESS ]
_SERVER[ "SERVER_PORT" ] := LTrim( Str( aI[ HB_SOCKET_ADINFO_PORT ] ) )
ENDIF
#endif
// add other _SERVER vars
_SERVER[ "REQUEST_METHOD" ] := NIL