diff --git a/ftk/src/ftk.h b/ftk/src/ftk.h index 0576806..2736ef9 100644 --- a/ftk/src/ftk.h +++ b/ftk/src/ftk.h @@ -684,6 +684,7 @@ flminterface IF_ThreadInfo; flminterface IF_OStream; flminterface IF_IOStream; + flminterface IF_TCPListener; flminterface IF_SSLIOStream; flminterface IF_LogMessageClient; flminterface IF_Thread; @@ -696,6 +697,7 @@ class F_ListItem; class F_ListManager; class F_Arg; + class F_TCPIOStream; /**************************************************************************** Desc: Cross-platform definitions @@ -1529,8 +1531,14 @@ const char * pszHost, FLMUINT uiPort, FLMUINT uiFlags, + FLMUINT uiConnectTimeout, IF_IOStream ** ppIOStream); + RCODE FLMAPI FlmOpenTCPListener( + FLMBYTE * pucBindAddr, + FLMUINT uiBindPort, + IF_TCPListener ** ppListener); + RCODE FLMAPI FlmRemoveMultiFileStream( const char * pszDirectory, const char * pszBaseName); @@ -1624,6 +1632,52 @@ #endif }; + /**************************************************************************** + Desc: + ****************************************************************************/ + flminterface IF_TCPListener : public F_Object + { + virtual RCODE FLMAPI connectClient( + F_TCPIOStream ** ppClientStream, + FLMUINT uiTimeout = 0); + }; + + /**************************************************************************** + Desc: + ****************************************************************************/ + flminterface IF_TCPIOStream : public IF_IOStream + { + virtual RCODE FLMAPI read( + void * pvBuffer, + FLMUINT uiBytesToRead, + FLMUINT * puiBytesRead) = 0; + + virtual RCODE FLMAPI write( + const void * pvBuffer, + FLMUINT uiBytesToWrite, + FLMUINT * puiBytesWritten) = 0; + + virtual const char * FLMAPI getLocalHostName( void) = 0; + + virtual const char * FLMAPI getLocalHostAddress( void) = 0; + + virtual const char * FLMAPI getPeerHostName( void) = 0; + + virtual const char * FLMAPI getPeerHostAddress( void) = 0; + + virtual RCODE FLMAPI readNoWait( + void * pvBuffer, + FLMUINT uiCount, + FLMUINT * puiReadRead) = 0; + + virtual RCODE FLMAPI readAll( + void * pvBuffer, + FLMUINT uiCount, + FLMUINT * puiBytesRead) = 0; + + virtual RCODE FLMAPI closeStream( void) = 0; + }; + /**************************************************************************** Desc: ****************************************************************************/ @@ -3979,6 +4033,10 @@ const char * pszFormat, ...); + FLMINT FLMAPI f_errprintf( + const char * pszFormat, + ...); + FLMINT FLMAPI f_printf( IF_PrintfClient * pClient, const char * pszFormat, @@ -4141,6 +4199,12 @@ FLMUINT uiFlags) = 0; }; + RCODE FLMAPI FlmAllocStdoutPrintfClient( + IF_PrintfClient ** ppClient); + + RCODE FLMAPI FlmAllocStderrPrintfClient( + IF_PrintfClient ** ppClient); + /**************************************************************************** Desc: XML ****************************************************************************/ @@ -7321,12 +7385,8 @@ typedef FLMBOOL (* F_ARG_VALIDATOR) ( const char * pszGivenArg, const char * pszIdentifier, - F_StringAcc * pOutputAccumulator, - void * pvUserData); - - typedef void (* F_ARG_OUTPUT_CALLBACK) ( - const char * pszOutputString, - void * pvUserData); + IF_PrintfClient * pPrintfClient, + void * pvAppData); typedef enum { @@ -7352,18 +7412,13 @@ { public: - F_ArgSet( - char * pszDescription, - F_ARG_OUTPUT_CALLBACK outputCallback, - void * pvOutputCallbackData); + F_ArgSet(); virtual ~F_ArgSet(); - FINLINE const char * FLMAPI getDescription( void) - { - return( m_pszDescription); - } - + RCODE FLMAPI setup( + IF_PrintfClient * pPrintfClient); + RCODE FLMAPI addArg( const char * pszIdentifier, const char * pszShortHelp, @@ -7374,8 +7429,7 @@ RCODE FLMAPI parseCommandLine( FLMUINT uiArgc, - const char ** ppszArgv, - FLMBOOL * pbPrintedUsage); + const char ** ppszArgv); FLMBOOL FLMAPI argIsPresent( const char * pszIdentifier); @@ -7421,15 +7475,12 @@ F_Arg * getArg( const char * pszIdentifier); - RCODE printUsage( void); + void printUsage( void); - RCODE dump( + void dump( F_Vector * pVec, FLMUINT uiVecLen); - void outputLines( - const char * pszStr); - FLMBOOL needsPreprocessing( void); RCODE preProcessParams( void); @@ -7439,7 +7490,6 @@ char * pszBuffer); RCODE displayShortHelpLines( - F_StringAcc * pStringAcc, const char * pszShortHelp, FLMUINT uiCharsPerLine); @@ -7448,10 +7498,8 @@ FLMUINT uiVecLen); RCODE parseOption( - const char * pszArg, - FLMBOOL * pbPrintedUsage); + const char * pszArg); - char * m_pszDescription; char m_szExecBaseName[ F_PATH_MAX_SIZE]; F_Vector m_argVec; FLMUINT m_uiArgVecIndex; @@ -7464,8 +7512,7 @@ F_Arg * m_pRepeatingArg; FLMUINT m_uiArgc; F_Vector * m_pArgv; - F_ARG_OUTPUT_CALLBACK m_outputCallback; - void * m_pvOutputCallbackData; + IF_PrintfClient * m_pPrintfClient; }; /**************************************************************************** diff --git a/ftk/src/ftkarg.cpp b/ftk/src/ftkarg.cpp index 607fcad..e3bea53 100644 --- a/ftk/src/ftkarg.cpp +++ b/ftk/src/ftkarg.cpp @@ -392,15 +392,8 @@ void F_Arg::getString( /**************************************************************************** Desc: ****************************************************************************/ -F_ArgSet::F_ArgSet( - char * pszDescription, - F_ARG_OUTPUT_CALLBACK outputCallback, - void * pvOutputCallbackData) +F_ArgSet::F_ArgSet() { - m_pszDescription = pszDescription; - m_outputCallback = outputCallback; - m_pvOutputCallbackData = pvOutputCallbackData; - m_uiArgVecIndex = 0; m_uiArgc = 0; m_pArgv = NULL; @@ -408,8 +401,8 @@ F_ArgSet::F_ArgSet( m_uiOptionsVecLen = 0; m_uiRequiredArgsVecLen = 0; m_uiOptionalArgsVecLen = 0; - m_szExecBaseName[ 0] = 0; + m_pPrintfClient = NULL; } /**************************************************************************** @@ -449,6 +442,27 @@ F_ArgSet::~F_ArgSet() pArg->Release(); } } + + if( m_pPrintfClient) + { + m_pPrintfClient->Release(); + } +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE FLMAPI F_ArgSet::setup( + IF_PrintfClient * pPrintfClient) +{ + RCODE rc = NE_FLM_OK; + + if( (m_pPrintfClient = pPrintfClient) != NULL) + { + m_pPrintfClient->AddRef(); + } + + return( rc); } /**************************************************************************** @@ -756,89 +770,51 @@ FLMBOOL F_ArgSet::needMoreArgs( /**************************************************************************** Desc: ****************************************************************************/ -RCODE F_ArgSet::dump( +void F_ArgSet::dump( F_Vector * pVec, FLMUINT uiVecLen) { - RCODE rc = NE_FLM_OK; FLMUINT uiLoop; - F_StringAcc acc; // Loop through the args and print out a table for easy reference to see // what was set and what wasn't for( uiLoop = 0; uiLoop < uiVecLen; uiLoop++) { - F_Arg * pArg = (F_Arg *)(pVec->getElementAt( uiLoop)); + F_Arg * pArg = (F_Arg *)(pVec->getElementAt( uiLoop)); - if( RC_BAD( rc = acc.appendTEXT( " "))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( pArg->getIdentifier()))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( ": "))) - { - goto Exit; - } + f_printf( m_pPrintfClient, " "); + f_printf( m_pPrintfClient, pArg->getIdentifier()); + f_printf( m_pPrintfClient, ": "); if( pArg->isPresent()) { - if( RC_BAD( rc = acc.appendTEXT( "values={"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "values={"); for( FLMUINT uiVals = 0; uiVals < pArg->getValueCount(); uiVals++) { - if( RC_BAD( rc = acc.appendTEXT( pArg->getValue( uiVals)))) - { - goto Exit; - } + f_printf( m_pPrintfClient, pArg->getValue( uiVals)); if( uiVals != (pArg->getValueCount() - 1)) { - if( RC_BAD( rc = acc.appendTEXT( ","))) - { - goto Exit; - } + f_printf( m_pPrintfClient, ","); } } - if( RC_BAD( rc = acc.appendTEXT( "}\n"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "}\n"); } else { - if( RC_BAD( rc = acc.appendTEXT( "not supplied\n"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "not supplied\n"); } } - - if( acc.getTEXT()) - { - outputLines( (const char *)acc.getTEXT()); - } - -Exit: - - return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE F_ArgSet::parseOption( - const char * pszArg, - FLMBOOL * pbPrintedUsage) + const char * pszArg) { RCODE rc = NE_FLM_OK; const char * pszArgArg; @@ -860,33 +836,14 @@ RCODE F_ArgSet::parseOption( { if( pArg->getContentType() != F_ARG_CONTENT_NONE) { - F_StringAcc acc; + f_printf( m_pPrintfClient, "ERROR: Option "); + f_printf( m_pPrintfClient, pArg->getIdentifier()); + f_printf( m_pPrintfClient, " requires argument of the form option=value"); - if( RC_BAD( rc = acc.appendTEXT( "ERROR: option "))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( pArg->getIdentifier()))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( - " requires argument of the form option=value"))) - { - goto Exit; - } - - outputLines( (const char *)acc.getTEXT()); - rc = printUsage(); - *pbPrintedUsage = TRUE; + printUsage(); - if( RC_OK( rc)) - { - rc = RC_SET( NE_FLM_FAILURE); - goto Exit; - } + rc = RC_SET( NE_FLM_FAILURE); + goto Exit; } else { @@ -913,28 +870,14 @@ RCODE F_ArgSet::parseOption( if( pArg->getContentType() == F_ARG_CONTENT_NONE) { - F_StringAcc acc; - - if( RC_BAD( rc = acc.appendTEXT( - "ERROR: cannot give argument to option "))) - { - goto Exit; - } + f_printf( m_pPrintfClient, + "ERROR: Cannot give argument to option "); + f_printf( m_pPrintfClient, pArg->getIdentifier()); - if( RC_BAD( rc = acc.appendTEXT( pArg->getIdentifier()))) - { - goto Exit; - } - - outputLines( (const char *)acc.getTEXT()); - rc = printUsage(); - *pbPrintedUsage = TRUE; + printUsage(); - if( RC_OK( rc)) - { - rc = RC_SET( NE_FLM_FAILURE); - goto Exit; - } + rc = RC_SET( NE_FLM_FAILURE); + goto Exit; } else { @@ -953,27 +896,13 @@ RCODE F_ArgSet::parseOption( if ( !bFoundMatch) { - F_StringAcc acc; + f_printf( m_pPrintfClient, "Unknown option "); + f_printf( m_pPrintfClient, pszArg); + f_printf( m_pPrintfClient, "\n"); - if( RC_BAD( rc = acc.appendTEXT( "ERROR: unknown option "))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( pszArg))) - { - goto Exit; - } - - outputLines( (const char *)acc.getTEXT()); - rc = printUsage(); - *pbPrintedUsage = TRUE; - - if( RC_OK( rc)) - { - rc = RC_SET( NE_FLM_FAILURE); - } + printUsage(); + rc = RC_SET( NE_FLM_FAILURE); goto Exit; } @@ -987,11 +916,9 @@ Desc: ****************************************************************************/ RCODE F_ArgSet::parseCommandLine( FLMUINT uiArgc, - const char ** ppszArgv, - FLMBOOL * pbPrintedUsage) + const char ** ppszArgv) { RCODE rc = NE_FLM_OK; - F_StringAcc errorAcc; FLMUINT uiLoop; FLMUINT uiArgs; FLMBOOL bNegative; @@ -999,8 +926,6 @@ RCODE F_ArgSet::parseCommandLine( char szDir[ F_PATH_MAX_SIZE]; IF_FileSystem * pFileSystem = NULL; - *pbPrintedUsage = FALSE; - // Set up members we'll need if( !m_pArgv) @@ -1067,18 +992,9 @@ RCODE F_ArgSet::parseCommandLine( f_strcmp( pszArg, "-?") == 0 || f_strcmp( pszArg, "?") == 0) { - if( RC_BAD( rc = printUsage())) - { - goto Exit; - } - - *pbPrintedUsage = TRUE; - - if( RC_OK( rc)) - { - rc = RC_SET( NE_FLM_FAILURE); - } + printUsage(); + rc = RC_SET( NE_FLM_FAILURE); goto Exit; } else if( pszArg[ 0] == '-') @@ -1086,7 +1002,7 @@ RCODE F_ArgSet::parseCommandLine( // Option-handling is sufficiently complex that we'll handle it // elsewhere in its own function - if ( RC_BAD( rc = parseOption( pszArg, pbPrintedUsage))) + if ( RC_BAD( rc = parseOption( pszArg))) { goto Exit; } @@ -1156,27 +1072,12 @@ RCODE F_ArgSet::parseCommandLine( } else { - errorAcc.clear(); + f_printf( m_pPrintfClient, "invalid extra argument "); + f_printf( m_pPrintfClient, pszArg); - if( RC_BAD( rc = errorAcc.appendTEXT( "invalid extra argument "))) - { - goto Exit; - } - - if( RC_BAD( rc = errorAcc.appendTEXT( pszArg))) - { - goto Exit; - } - - outputLines( (const char *)errorAcc.getTEXT()); - rc = printUsage(); - *pbPrintedUsage = TRUE; - - if( RC_OK( rc)) - { - rc = RC_SET( NE_FLM_FAILURE); - } + printUsage(); + rc = RC_SET( NE_FLM_FAILURE); goto Exit; } } @@ -1193,25 +1094,18 @@ RCODE F_ArgSet::parseCommandLine( if ( !pArg->isPresent()) { - errorAcc.clear(); - if( RC_BAD( rc = errorAcc.appendf( - "ERROR: did not pass required arg #%u <%s>\n", - uiLoop + 1, pArg->getIdentifier()))) + f_printf( m_pPrintfClient, + "ERROR: Did not pass required arg #%u <%s>\n", + uiLoop + 1, pArg->getIdentifier()); { goto Exit; } } } - outputLines( (const char *)errorAcc.getTEXT()); - rc = printUsage(); - *pbPrintedUsage = TRUE; - - if( RC_OK( rc)) - { - rc = RC_SET( NE_FLM_FAILURE); - } - + printUsage(); + + rc = RC_SET( NE_FLM_FAILURE); goto Exit; } @@ -1225,12 +1119,6 @@ RCODE F_ArgSet::parseCommandLine( f_assert( pArg); - // Set up the accumulator so the generic error message appears - // prior to the previous one. Set it up as if will fail ... we may - // not even use the partial error message. - - errorAcc.clear(); - // If it's present, then it has a value we will want to validate if( pArg->isPresent()) @@ -1258,21 +1146,10 @@ RCODE F_ArgSet::parseCommandLine( if( !bValidated) { - if( RC_BAD( errorAcc.appendTEXT( "ERROR: argument '"))) - { - goto Exit; - } - - if( RC_BAD( errorAcc.appendTEXT( pszStr))) - { - goto Exit; - } - - if( RC_BAD( errorAcc.appendTEXT( - "' is not a valid representation of a boolean"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "ERROR: Argument '"); + f_printf( m_pPrintfClient, pszStr); + f_printf( m_pPrintfClient, + "' is not a valid representation of a boolean"); break; } @@ -1288,7 +1165,7 @@ RCODE F_ArgSet::parseCommandLine( pszStr = pArg->getValue( uiArgs); if( (bValidated = pArg->getValidator()( pszStr, - pArg->getIdentifier(), &errorAcc, + pArg->getIdentifier(), m_pPrintfClient, pArg->getValidatorData())) == FALSE) { break; @@ -1328,13 +1205,10 @@ RCODE F_ArgSet::parseCommandLine( if( (iArg > iMax) || (iArg < iMin)) { - if( RC_BAD( errorAcc.appendf( - "ERROR: argument '%s' violates range " + f_printf( m_pPrintfClient, + "ERROR: Argument '%s' violates range " "requirement of min=%d, max=%d", - pszStr, iMin, iMax))) - { - goto Exit; - } + pszStr, iMin, iMax); bValidated = FALSE; break; @@ -1351,13 +1225,10 @@ RCODE F_ArgSet::parseCommandLine( if( (uiArg > uiMax) || (uiArg < uiMin)) { - if( RC_BAD( errorAcc.appendf( - "ERROR: argument '%s' violates range " + f_printf( m_pPrintfClient, + "ERROR: Argument '%s' violates range " "requirement of min=%u, max=%u", - pszStr, uiMin, uiMax))) - { - goto Exit; - } + pszStr, uiMin, uiMax); bValidated = FALSE; break; @@ -1395,55 +1266,26 @@ RCODE F_ArgSet::parseCommandLine( if( !bValidated) { - if( RC_BAD( rc = errorAcc.appendTEXT( "ERROR: '"))) - { - goto Exit; - } - - if( RC_BAD( rc = errorAcc.appendTEXT( pszStr))) - { - goto Exit; - } - - if( RC_BAD( rc = errorAcc.appendTEXT( - "' is invalid. Must be a member of {"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "ERROR: '"); + f_printf( m_pPrintfClient, pszStr); + f_printf( m_pPrintfClient, + "' is invalid. Must be a member of {"); for( uiStrSet = 0; uiStrSet < uiStrSetLen; uiStrSet++) { const char * pszNextMember = (const char *)pStringSet->getElementAt( uiStrSet); - if( RC_BAD( rc = errorAcc.appendTEXT( "'"))) - { - goto Exit; - } - - if( RC_BAD( rc = errorAcc.appendTEXT( pszNextMember))) - { - goto Exit; - } - - if( RC_BAD( rc = errorAcc.appendTEXT( "'"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "'"); + f_printf( m_pPrintfClient, pszNextMember); + f_printf( m_pPrintfClient, "'"); if( uiStrSet != (uiStrSetLen - 1)) { - if( RC_BAD( rc = errorAcc.appendTEXT( ","))) - { - goto Exit; - } + f_printf( m_pPrintfClient, ","); } } - if( RC_BAD( rc = errorAcc.appendTEXT( "}\n"))) - { - goto Exit; - } - + f_printf( m_pPrintfClient, "}\n"); break; } } @@ -1462,21 +1304,9 @@ RCODE F_ArgSet::parseCommandLine( if ( !bValidated) { - if( RC_BAD( rc = errorAcc.appendTEXT( "ERROR: file "))) - { - goto Exit; - } - - if( RC_BAD( rc = errorAcc.appendTEXT( pszStr))) - { - goto Exit; - } - - if( RC_BAD( rc = errorAcc.appendTEXT( " does not exist\n"))) - { - goto Exit; - } - + f_printf( m_pPrintfClient, "ERROR: File "); + f_printf( m_pPrintfClient, pszStr); + f_printf( m_pPrintfClient, " does not exist\n"); break; } } @@ -1496,41 +1326,16 @@ RCODE F_ArgSet::parseCommandLine( if( !bValidated) { - if( RC_BAD( rc = errorAcc.appendTEXT( "\nargument '"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "\nargument '"); + f_printf( m_pPrintfClient, pArg->getIdentifier()); + f_printf( m_pPrintfClient, "}\n"); + f_printf( m_pPrintfClient, "' did not validate with value '"); + f_printf( m_pPrintfClient, pszStr); + f_printf( m_pPrintfClient, "'\n"); - if( RC_BAD( rc = errorAcc.appendTEXT( pArg->getIdentifier()))) - { - goto Exit; - } - - if( RC_BAD( rc = errorAcc.appendTEXT( - "' did not validate with value '"))) - { - goto Exit; - } - - if( RC_BAD( rc = errorAcc.appendTEXT( pszStr))) - { - goto Exit; - } - - if( RC_BAD( rc = errorAcc.appendTEXT( "'\n"))) - { - goto Exit; - } - - outputLines( (const char *)errorAcc.getTEXT()); - rc = printUsage(); - *pbPrintedUsage = TRUE; - - if( RC_OK( rc)) - { - rc = RC_SET( NE_FLM_FAILURE); - } + printUsage(); + rc = RC_SET( NE_FLM_FAILURE); goto Exit; } } @@ -1543,14 +1348,6 @@ Exit: pFileSystem->Release(); } - if( RC_BAD( rc) && !(*pbPrintedUsage)) - { - F_StringAcc acc; - - acc.appendf( "ERROR: parseCommandLine(): %u\n", rc); - outputLines( (const char *)acc.getTEXT()); - } - return( rc); } @@ -1560,7 +1357,6 @@ Desc: Print out the short help lines, breaking up at word boundaries. This when changing it. ****************************************************************************/ RCODE F_ArgSet::displayShortHelpLines( - F_StringAcc * pStringAcc, const char * pszShortHelp, FLMUINT uiCharsPerLine) { @@ -1594,16 +1390,9 @@ RCODE F_ArgSet::displayShortHelpLines( pszClone[ uiLastGoodBreakingPos] = 0; - if( RC_BAD( rc = pStringAcc->appendTEXT( pszClone))) - { - goto Exit; - } - - if( RC_BAD( rc = pStringAcc->appendTEXT( - "\n "))) - { - goto Exit; - } + f_printf( m_pPrintfClient, pszClone); + f_printf( m_pPrintfClient, + "\n "); pszClone += f_strlen( pszClone) + 1; uiLoop = 0; @@ -1614,11 +1403,7 @@ RCODE F_ArgSet::displayShortHelpLines( } else if( uiLoop == (uiLen - 1)) { - if( RC_BAD( rc = pStringAcc->appendTEXT( pszClone))) - { - goto Exit; - } - + f_printf( m_pPrintfClient, pszClone); break; } else if( f_isWhitespace( pszClone[ uiLoop])) @@ -1642,149 +1427,75 @@ Exit: /**************************************************************************** Desc: ****************************************************************************/ -RCODE F_ArgSet::printUsage( void) +void F_ArgSet::printUsage( void) { RCODE rc = NE_FLM_OK; - F_StringAcc acc; FLMUINT uiLoop = 0; - // Print usage line - - if( RC_BAD( rc = acc.appendTEXT( "Usage: "))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( m_szExecBaseName))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "Usage: "); + f_printf( m_pPrintfClient, m_szExecBaseName); if( m_uiOptionsVecLen > 0) { - if( RC_BAD( rc = acc.appendTEXT( " [OPTIONS]"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, " [OPTIONS]"); } if( m_uiRequiredArgsVecLen > 0) { - if( RC_BAD( rc = acc.appendTEXT( " "))) - { - goto Exit; - } + f_printf( m_pPrintfClient, " "); } for( uiLoop = 0; uiLoop < m_uiRequiredArgsVecLen; uiLoop++) { F_Arg * pArg = (F_Arg*)m_requiredArgsVec.getElementAt( uiLoop); - if( RC_BAD( rc = acc.appendTEXT( "<"))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( pArg->getIdentifier()))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( ">"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "<"); + f_printf( m_pPrintfClient, pArg->getIdentifier()); + f_printf( m_pPrintfClient, ">"); if( uiLoop != (m_uiRequiredArgsVecLen - 1)) { - if( RC_BAD( rc = acc.appendTEXT( " "))) - { - goto Exit; - } + f_printf( m_pPrintfClient, " "); } } if( m_uiOptionalArgsVecLen > 0) { - if( RC_BAD( rc = acc.appendTEXT( " "))) - { - goto Exit; - } + f_printf( m_pPrintfClient, " "); } for ( uiLoop = 0; uiLoop < m_uiOptionalArgsVecLen; uiLoop++) { F_Arg * pArg = (F_Arg*)m_optionalArgsVec.getElementAt( uiLoop); - if( RC_BAD( rc = acc.appendTEXT( "["))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( pArg->getIdentifier()))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( "]"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "["); + f_printf( m_pPrintfClient, pArg->getIdentifier()); + f_printf( m_pPrintfClient, "]"); if( uiLoop != (m_uiOptionalArgsVecLen - 1)) { - if( RC_BAD( rc = acc.appendTEXT( " "))) - { - goto Exit; - } + f_printf( m_pPrintfClient, " "); } } if ( m_pRepeatingArg) { - if( RC_BAD( rc = acc.appendTEXT( " ["))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( m_pRepeatingArg->getIdentifier()))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( "...]"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, " ["); + f_printf( m_pPrintfClient, m_pRepeatingArg->getIdentifier()); + f_printf( m_pPrintfClient, "...]"); } - if( RC_BAD( rc = acc.appendTEXT( "\n"))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( m_pszDescription))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( "\n\n"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "\n\n"); if( m_uiOptionsVecLen > 0) { // The following is fairly hard-coded to get the spacing right - if( RC_BAD( rc = acc.appendTEXT( + f_printf( m_pPrintfClient, "OPTIONS:\n" "\n" - "identifier case sensitive description\n" - "----------------- -------------- ---------------------------------------\n"))) - { - goto Exit; - } + "identifier case sensitive description\n" + "----------------- -------------- ---------------------------------------\n"); // Show all the options @@ -1795,49 +1506,24 @@ RCODE F_ArgSet::printUsage( void) const char * pszIdentifier = pArg->getIdentifier(); FLMUINT uiIdentifierLength = f_strlen( pszIdentifier); - if( RC_BAD( rc = acc.appendTEXT( "-"))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( pszIdentifier))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "-"); + f_printf( m_pPrintfClient, pszIdentifier); if( pArg->getContentType() != F_ARG_CONTENT_NONE) { const char * pszArgArgIndicator = "=ARG"; - if( RC_BAD( rc = acc.appendTEXT( pszArgArgIndicator))) - { - goto Exit; - } - + f_printf( m_pPrintfClient, pszArgArgIndicator); uiIdentifierLength += f_strlen( pszArgArgIndicator); } - if( RC_BAD( rc = acc.appendCHAR( ' ', (16 - uiIdentifierLength)))) - { - goto Exit; - } + m_pPrintfClient->outputChar( ' ', 16 - uiIdentifierLength); - if( RC_BAD( rc = acc.appendTEXT( " "))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( (pArg->getCaseSensitive()) + f_printf( m_pPrintfClient, " "); + f_printf( m_pPrintfClient, (pArg->getCaseSensitive()) ? "y" - : "n"))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendCHAR( ' ', 16))) - { - goto Exit; - } + : "n"); + m_pPrintfClient->outputChar( ' ', 16); if( RC_BAD( rc = f_strdup( pArg->getShortHelp(), (char **)&pszHelpClone))) @@ -1845,7 +1531,7 @@ RCODE F_ArgSet::printUsage( void) goto Exit; } - rc = displayShortHelpLines( &acc, pszHelpClone, 39); + rc = displayShortHelpLines( pszHelpClone, 39); if( pszHelpClone) { @@ -1858,32 +1544,23 @@ RCODE F_ArgSet::printUsage( void) goto Exit; } - if( RC_BAD( rc = acc.appendTEXT( "\n"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "\n"); } - if( RC_BAD( rc = acc.appendTEXT( "\n"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "\n"); } if( m_uiRequiredArgsVecLen > 0) { - if( RC_BAD( rc = acc.appendTEXT( + f_printf( m_pPrintfClient, "REQUIRED args:\n" - "\n"))) - { - goto Exit; - } + "\n"); for( uiLoop = 0; uiLoop < m_uiRequiredArgsVecLen; uiLoop++) { - F_Arg * pArg = (F_Arg*)m_requiredArgsVec.getElementAt( uiLoop); - F_StringAcc tempAcc; - FLMUINT uiPads; + F_Arg * pArg = (F_Arg*)m_requiredArgsVec.getElementAt( uiLoop); + F_StringAcc tempAcc; + FLMUINT uiPads; if( RC_BAD( rc = tempAcc.appendTEXT( "<"))) { @@ -1907,37 +1584,24 @@ RCODE F_ArgSet::printUsage( void) goto Exit; } - if( RC_BAD( rc = acc.appendTEXT( tempAcc.getTEXT()))) + f_printf( m_pPrintfClient, tempAcc.getTEXT()); + + if( RC_BAD( rc = displayShortHelpLines( pArg->getShortHelp(), 39))) { goto Exit; } - if( RC_BAD( rc = displayShortHelpLines( - &acc, pArg->getShortHelp(), 39))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( "\n"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "\n"); } - if( RC_BAD( rc = acc.appendTEXT( "\n\n"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "\n\n"); } if( m_uiOptionalArgsVecLen > 0) { - if( RC_BAD( rc = acc.appendTEXT( + f_printf( m_pPrintfClient, "OPTIONAL args:\n" - "\n"))) - { - goto Exit; - } + "\n"); for( uiLoop = 0; uiLoop < m_uiOptionalArgsVecLen; uiLoop++) { @@ -1967,27 +1631,17 @@ RCODE F_ArgSet::printUsage( void) goto Exit; } - if( RC_BAD( rc = acc.appendTEXT( tempAcc.getTEXT()))) + f_printf( m_pPrintfClient, tempAcc.getTEXT()); + + if( RC_BAD( rc = displayShortHelpLines( pArg->getShortHelp(), 39))) { goto Exit; } - if( RC_BAD( rc = displayShortHelpLines( - &acc, pArg->getShortHelp(), 39))) - { - goto Exit; - } - - if( RC_BAD( rc = acc.appendTEXT( "\n"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "\n"); } - if( RC_BAD( rc = acc.appendTEXT( "\n\n"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "\n\n"); } if( m_pRepeatingArg) @@ -1995,12 +1649,9 @@ RCODE F_ArgSet::printUsage( void) F_StringAcc tempAcc; FLMUINT uiPads; - if( RC_BAD( rc = acc.appendTEXT( + f_printf( m_pPrintfClient, "REPEATING arg:\n" - "\n"))) - { - goto Exit; - } + "\n"); if( RC_BAD( rc = tempAcc.appendTEXT( "["))) { @@ -2024,74 +1675,20 @@ RCODE F_ArgSet::printUsage( void) goto Exit; } - if( RC_BAD( rc = acc.appendTEXT( tempAcc.getTEXT()))) - { - goto Exit; - } + f_printf( m_pPrintfClient, tempAcc.getTEXT()); if( RC_BAD( rc = displayShortHelpLines( - &acc, m_pRepeatingArg->getShortHelp(), 39))) + m_pRepeatingArg->getShortHelp(), 39))) { goto Exit; } - if( RC_BAD( rc = acc.appendTEXT( "\n\n"))) - { - goto Exit; - } + f_printf( m_pPrintfClient, "\n\n"); } - outputLines( (const char *)acc.getTEXT()); - Exit: - return( rc); -} - -/**************************************************************************** -Desc: Output lines of text in the argument by making calls to the - output callback, one per line. -****************************************************************************/ -void F_ArgSet::outputLines( - const char * pszStr) -{ - if( m_outputCallback) - { - char pszOneLine[ 80]; - FLMUINT uiStrLen = f_strlen( pszStr); - const char * pEndLine; - - for( ;;) - { - pEndLine = f_strchr( (const char *)pszStr, '\n'); - - if( uiStrLen == 0) - { - break; - } - else if( pEndLine && ((pEndLine - pszStr) > 79)) - { - f_strncpy( pszOneLine, pszStr, 79); - pszOneLine[ 79] = 0; - m_outputCallback( pszOneLine, m_pvOutputCallbackData); - pszStr += 79; - } - else if( !pEndLine) - { - m_outputCallback( pszStr, m_pvOutputCallbackData); - break; - } - else - { - f_strncpy( pszOneLine, pszStr, 79); - pszOneLine[ 79] = 0; - m_outputCallback( pszOneLine, m_pvOutputCallbackData); - - pszStr = pEndLine + 1; - uiStrLen = f_strlen( pszStr); - } - } - } + return; } /**************************************************************************** @@ -2343,7 +1940,7 @@ RCODE F_ArgSet::preProcessParams( void) { // There's probably a cycle in the @-files if we're going this deep - outputLines( "ERROR: cycle in @-files detected"); + f_printf( m_pPrintfClient, "ERROR: Cycle in @-files detected"); rc = RC_SET( NE_FLM_FAILURE); goto Exit; } @@ -2353,24 +1950,9 @@ RCODE F_ArgSet::preProcessParams( void) if( RC_BAD( rc = f_filetobuf( (const char *)(pszNextArg + 1), &pszBuffer))) { - F_StringAcc acc; - - if( RC_BAD( acc.appendTEXT( "ERROR: reading @-file "))) - { - goto Exit; - } - - if( RC_BAD( acc.appendTEXT( pszNextArg))) - { - goto Exit; - } - - if( RC_BAD( acc.appendTEXT( "!"))) - { - goto Exit; - } - - outputLines( (const char *)acc.getTEXT()); + f_printf( m_pPrintfClient, "ERROR: Reading @-file "); + f_printf( m_pPrintfClient, pszNextArg); + f_printf( m_pPrintfClient, "!"); goto Exit; } diff --git a/ftk/src/ftknet.cpp b/ftk/src/ftknet.cpp new file mode 100644 index 0000000..316a9d4 --- /dev/null +++ b/ftk/src/ftknet.cpp @@ -0,0 +1,1499 @@ +//------------------------------------------------------------------------------ +// Desc: +// Tabs: 3 +// +// Copyright (c) 1998, 2007 Novell, Inc. All Rights Reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version 2.1 +// of the License. +// +// This library 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 +// Library Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com. +// +// $Id$ +//------------------------------------------------------------------------------ + +#include "ftksys.h" + +FSTATIC RCODE f_socketPeek( + int iSocket, + FLMUINT uiTimeoutVal, + FLMBOOL bPeekRead); + +FSTATIC void f_closeSocket( + int * piSocket); + +/**************************************************************************** +Desc: +****************************************************************************/ +class F_TCPListener : public IF_TCPListener +{ +public: + + F_TCPListener() + { + m_bBound = FALSE; + m_iSocket = INVALID_SOCKET; + } + + virtual ~F_TCPListener() + { + if( m_iSocket != INVALID_SOCKET) + { + f_closeSocket( &m_iSocket); + } + } + + RCODE FLMAPI bind( + FLMUINT uiBindPort, + FLMBYTE * pucBindAddr = NULL); + + RCODE FLMAPI connectClient( + F_TCPIOStream ** ppClientStream, + FLMUINT uiTimeout = 3); + +private: + + FLMBOOL m_bBound; + SOCKET m_iSocket; +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +class F_TCPIOStream : public IF_IOStream +{ +public: + + #if defined( FLM_WIN) && _MSC_VER < 1300 + using IF_IStream::operator delete; + #endif + + F_TCPIOStream( void); + + virtual ~F_TCPIOStream( void); + + RCODE openStream( + const char * pucHostAddress, + FLMUINT uiPort, + FLMUINT uiFlags, + FLMUINT uiConnectTimeout); + + RCODE openStream( + int iSocket, + FLMUINT uiFlags); + + RCODE FLMAPI read( + void * pvBuffer, + FLMUINT uiBytesToRead, + FLMUINT * puiBytesRead); + + RCODE FLMAPI write( + const void * pvBuffer, + FLMUINT uiBytesToWrite, + FLMUINT * puiBytesWritten); + + FINLINE RCODE socketPeekWrite( + FLMUINT uiTimeOut) + { + return( f_socketPeek( m_iSocket, uiTimeOut, FALSE)); + } + + FINLINE RCODE f_socketPeekRead( + FLMUINT uiTimeOut) + { + return( f_socketPeek( m_iSocket, uiTimeOut, TRUE)); + }; + + FINLINE const char * getName( void) + { + getLocalInfo(); + return( (const char *)m_pszName); + }; + + FINLINE const char * getAddr( void) + { + getLocalInfo(); + return( (const char *)m_pszIp); + }; + + FINLINE const char * getPeerName( void) + { + getRemoteInfo(); + return( (const char *)m_pszPeerName); + }; + + FINLINE const char * getPeerAddr( void) + { + getRemoteInfo(); + return( (const char *)m_pszPeerIp); + }; + + RCODE readNoWait( + void * pvBuffer, + FLMUINT uiCount, + FLMUINT * puiReadRead); + + RCODE readAll( + void * pvBuffer, + FLMUINT uiCount, + FLMUINT * puiBytesRead); + + RCODE setTcpDelay( + FLMBOOL bOn); + + RCODE FLMAPI closeStream( void); + +private: + + RCODE getLocalInfo( void); + + RCODE getRemoteInfo( void); + +#ifndef FLM_UNIX + WSADATA m_wsaData; +#endif + FLMBOOL m_bInitialized; + SOCKET m_iSocket; + FLMUINT m_uiIOTimeout; + FLMBOOL m_bConnected; + char m_pszIp[ 256]; + char m_pszName[ 256]; + char m_pszPeerIp[ 256]; + char m_pszPeerName[ 256]; + unsigned long m_ulRemoteAddr; +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +#ifdef FLM_OPENSSL +class F_SSLIOStream : public IF_SSLIOStream +{ +public: + + F_SSLIOStream() + { + m_pBio = NULL; + m_pContext = NULL; + m_pSSL = NULL; + m_pPeerCertificate = NULL; + m_pszPeerCertText = NULL; + m_szPeerName[ 0] = 0; + } + + virtual ~F_SSLIOStream() + { + closeStream(); + } + + RCODE FLMAPI openStream( + const char * pszHost, + FLMUINT uiPort = 443, + FLMUINT uiFlags = 0); + + RCODE FLMAPI read( + void * pvBuffer, + FLMUINT uiBytesToRead, + FLMUINT * puiBytesRead = NULL); + + RCODE FLMAPI write( + const void * pvBuffer, + FLMUINT uiBytesToWrite, + FLMUINT * puiBytesWritten = NULL); + + const char * FLMAPI getPeerCertificateText( void); + + RCODE FLMAPI closeStream( void); + +private: + + BIO * m_pBio; + SSL_CTX * m_pContext; + SSL * m_pSSL; + X509 * m_pPeerCertificate; + char * m_pszPeerCertText; + char m_szPeerName[ 256]; +}; +#endif + +/***************************************************************************** +Desc: +*****************************************************************************/ +RCODE F_TCPListener::bind( + FLMUINT uiBindPort, + FLMBYTE * pucBindAddr) +{ + RCODE rc = NE_FLM_OK; + struct sockaddr_in address; + int iTmp; + + if( m_bBound) + { + rc = RC_SET( NE_FLM_SOCKET_FAIL); + goto Exit; + } + + if( (m_iSocket = socket( AF_INET, + SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) + { + rc = RC_SET( NE_FLM_SOCKET_FAIL); + goto Exit; + } + + f_memset( &address, 0, sizeof( address)); + address.sin_family = AF_INET; + + if( !pucBindAddr) + { + address.sin_addr.s_addr = htonl( INADDR_ANY); + } + else + { + address.sin_addr.s_addr = inet_addr( (char *)pucBindAddr); + } + address.sin_port = htons( (u_short)uiBindPort); + + // Bind to the address and port + + if( ::bind( m_iSocket, (struct sockaddr *)&address, sizeof( address)) != 0) + { + rc = RC_SET( NE_FLM_BIND_FAIL); + goto Exit; + } + + // listen() prepares a socket to accept a connection and specifies a + // queue limit for incoming connections. The accept() accepts the + // connection. Listen returns immediatly. + +#ifdef FLM_NLM + if( listen( m_iSocket, 32) < 0) +#endif + { + if( listen( m_iSocket, 5) < 0) + { + rc = RC_SET( NE_FLM_LISTEN_FAIL); + goto Exit; + } + } + + // Disable Nagel's algorithm + + iTmp = 1; + if( (setsockopt( m_iSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&iTmp, + (unsigned)sizeof( iTmp) )) < 0) + { + rc = RC_SET( NE_FLM_SOCKET_SET_OPT_FAIL); + goto Exit; + } + + m_bBound = TRUE; + +Exit: + + if( RC_BAD( rc) && m_iSocket != INVALID_SOCKET) + { + f_closeSocket( &m_iSocket); + } + + return( rc); +} + +/***************************************************************************** +Desc: +*****************************************************************************/ +RCODE F_TCPListener::connectClient( + F_TCPIOStream ** ppClientStream, + FLMUINT uiConnectTimeout) +{ + RCODE rc = NE_FLM_OK; + SOCKET iSocket = INVALID_SOCKET; + struct sockaddr_in address; + F_TCPIOStream * pClientStream = NULL; +#if defined( FLM_UNIX) && !defined( FLM_OSX) + socklen_t iAddrLen; +#else + int iAddrLen; +#endif + + if( !m_bBound) + { + rc = RC_SET( NE_FLM_BIND_FAIL); + goto Exit; + } + + if( RC_BAD( rc = f_socketPeek( m_iSocket, uiConnectTimeout, TRUE))) + { + goto Exit; + } + + iAddrLen = sizeof( struct sockaddr); + + if( (iSocket = accept( m_iSocket, + (struct sockaddr *)&address, &iAddrLen)) == INVALID_SOCKET) + { + rc = RC_SET( NE_FLM_ACCEPT_FAIL); + goto Exit; + } + + if( (pClientStream = f_new F_TCPIOStream) == NULL) + { + rc = RC_SET( NE_FLM_MEM); + goto Exit; + } + + if( RC_BAD( rc = pClientStream->openStream( iSocket, 0))) + { + goto Exit; + } + + iSocket = INVALID_SOCKET; + *ppClientStream = pClientStream; + pClientStream = NULL; + +Exit: + + if( pClientStream) + { + pClientStream->Release(); + } + + if( iSocket != INVALID_SOCKET) + { + f_closeSocket( &iSocket); + } + + return( rc); +} + +/***************************************************************************** +Desc: +******************************************************************************/ +RCODE FLMAPI FlmOpenTCPIOStream( + const char * pszHost, + FLMUINT uiPort, + FLMUINT uiFlags, + FLMUINT uiConnectTimeout, + IF_IOStream ** ppIOStream) +{ + RCODE rc = NE_FLM_OK; + F_TCPIOStream * pIOStream = NULL; + + if( (pIOStream = f_new F_TCPIOStream) == NULL) + { + rc = RC_SET( NE_FLM_MEM); + goto Exit; + } + + if( RC_BAD( rc = pIOStream->openStream( pszHost, uiPort, + uiFlags, uiConnectTimeout))) + { + goto Exit; + } + + *ppIOStream = pIOStream; + pIOStream = NULL; + +Exit: + + if( pIOStream) + { + pIOStream->Release(); + } + + return( rc); +} + +/***************************************************************************** +Desc: +******************************************************************************/ +RCODE FLMAPI FlmAllocSSLIOStream( + IF_IOStream ** ppIOStream) +{ +#ifdef FLM_OPENSSL + + if( (*ppIOStream = f_new F_SSLIOStream) == NULL) + { + return( RC_SET( NE_FLM_MEM)); + } + + return( NE_FLM_OK); + +#else + + F_UNREFERENCED_PARM( ppIOStream); + return( RC_SET( NE_FLM_NOT_IMPLEMENTED)); + +#endif +} + +/***************************************************************************** +Desc: +******************************************************************************/ +RCODE FLMAPI FlmOpenSSLIOStream( + const char * pszHost, + FLMUINT uiPort, + FLMUINT uiFlags, + IF_IOStream ** ppIOStream) +{ +#ifdef FLM_OPENSSL + + RCODE rc = NE_FLM_OK; + F_SSLIOStream * pIOStream = NULL; + + if( (pIOStream = f_new F_SSLIOStream) == NULL) + { + rc = RC_SET( NE_FLM_MEM); + goto Exit; + } + + if( RC_BAD( rc = pIOStream->openStream( pszHost, uiPort, uiFlags))) + { + goto Exit; + } + + *ppIOStream = pIOStream; + pIOStream = NULL; + +Exit: + + if( pIOStream) + { + pIOStream->Release(); + } + + return( rc); + +#else + + F_UNREFERENCED_PARM( pszHost); + F_UNREFERENCED_PARM( uiPort); + F_UNREFERENCED_PARM( uiFlags); + F_UNREFERENCED_PARM( ppIOStream); + + return( RC_SET( NE_FLM_NOT_IMPLEMENTED)); + +#endif +} + +/******************************************************************** +Desc: +*********************************************************************/ +F_TCPIOStream::F_TCPIOStream( void) +{ + m_pszIp[ 0] = 0; + m_pszName[ 0] = 0; + m_pszPeerIp[ 0] = 0; + m_pszPeerName[ 0] = 0; + m_uiIOTimeout = 30; + m_iSocket = INVALID_SOCKET; + m_ulRemoteAddr = 0; + m_bInitialized = FALSE; + m_bConnected = FALSE; + +#ifndef FLM_UNIX + if( !WSAStartup( MAKEWORD( 2, 0), &m_wsaData)) + { + m_bInitialized = TRUE; + } +#endif +} + +/******************************************************************** +Desc: +*********************************************************************/ +F_TCPIOStream::~F_TCPIOStream( void) +{ + if( m_bConnected) + { + closeStream(); + } + +#ifndef FLM_UNIX + if( m_bInitialized) + { + WSACleanup(); + } +#endif +} + +/******************************************************************** +Desc: Opens a new connection +*********************************************************************/ +RCODE F_TCPIOStream::openStream( + const char * pucHostName, + FLMUINT uiPort, + FLMUINT, // uiFlags, + FLMUINT uiConnectTimeout) +{ + RCODE rc = NE_FLM_OK; + FLMINT iSockErr; + FLMINT iTries; + FLMINT iMaxTries = 5; + struct sockaddr_in address; + struct hostent * pHostEntry; + unsigned long ulIPAddr; + int iTmp; + + f_assert( !m_bConnected); + m_iSocket = INVALID_SOCKET; + + if( pucHostName && pucHostName[ 0] != '\0') + { + ulIPAddr = inet_addr( (char *)pucHostName); + if( ulIPAddr == (unsigned long)(-1)) + { + pHostEntry = gethostbyname( (char *)pucHostName); + + if( !pHostEntry) + { + rc = RC_SET( NE_FLM_NOIP_ADDR); + goto Exit; + } + else + { + ulIPAddr = *((unsigned long *)pHostEntry->h_addr); + } + + } + } + else + { + ulIPAddr = inet_addr( (char *)"127.0.0.1"); + } + + // Fill in the Socket structure with family type + + f_memset( (char *)&address, 0, sizeof( struct sockaddr_in)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = (unsigned)ulIPAddr; + address.sin_port = htons( (unsigned short)uiPort); + + // Allocate a socket, then attempt to connect to it! + + if( (m_iSocket = socket( AF_INET, + SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) + { + rc = RC_SET( NE_FLM_SOCKET_FAIL); + goto Exit; + } + + // Now attempt to connect with the specified partner host, + // time-out if connection doesn't complete within alloted time + +#ifdef FLM_WIN + + if( uiConnectTimeout) + { + if ( uiConnectTimeout < 5 ) + { + iMaxTries = (iMaxTries * uiConnectTimeout) / 5; + uiConnectTimeout = 5; + } + } + else + { + iMaxTries = 1; + } +#endif + + for( iTries = 0; iTries < iMaxTries; iTries++ ) + { + iSockErr = 0; + if( connect( m_iSocket, (struct sockaddr *)((void *)&address), + (unsigned)sizeof(struct sockaddr)) >= 0) + { + break; + } + + #ifndef FLM_UNIX + iSockErr = WSAGetLastError(); + #else + iSockErr = errno; + #endif + + #ifdef FLM_WIN + + // In WIN, we sometimes get WSAEINVAL when, if we keep + // trying, we will eventually connect. Therefore, + // here we'll treat WSAEINVAL as EINPROGRESS. + + if( iSockErr == WSAEINVAL) + { + f_closeSocket( &m_iSocket); + + if( (m_iSocket = socket( AF_INET, + SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) + { + rc = RC_SET( NE_FLM_SOCKET_FAIL); + goto Exit; + } + #if defined( FLM_WIN) || defined( FLM_NLM) + iSockErr = WSAEINPROGRESS; + #else + iSockErr = EINPROGRESS; + #endif + continue; + } + #endif + + #if defined( FLM_WIN) || defined( FLM_NLM) + if( iSockErr == WSAEISCONN ) + #else + if( iSockErr == EISCONN ) + #endif + { + break; + } + #if defined( FLM_WIN) || defined( FLM_NLM) + else if( iSockErr == WSAEWOULDBLOCK) + #else + else if( iSockErr == EWOULDBLOCK) + #endif + { + // Let's wait a split second to give the connection + // request a chance. + + f_sleep( 100 ); + continue; + } + #if defined( FLM_WIN) || defined( FLM_NLM) + else if( iSockErr == WSAEINPROGRESS) + #else + else if( iSockErr == EINPROGRESS) + #endif + { + if( RC_OK( rc = f_socketPeek( m_iSocket, uiConnectTimeout, FALSE))) + { + // Let's wait a split second to give the connection + // request a chance. + + f_sleep( 100 ); + continue; + } + } + + rc = RC_SET( NE_FLM_CONNECT_FAIL); + goto Exit; + } + + // Disable Nagel's algorithm + + iTmp = 1; + if( (setsockopt( m_iSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&iTmp, + (unsigned)sizeof( iTmp) )) < 0) + { + rc = RC_SET( NE_FLM_SOCKET_SET_OPT_FAIL); + goto Exit; + } + + m_bConnected = TRUE; + +Exit: + + if( RC_BAD( rc)) + { + f_closeSocket( &m_iSocket); + } + + return( rc); +} + +/******************************************************************** +Desc: Opens a new connection +*********************************************************************/ +RCODE F_TCPIOStream::openStream( + int iSocket, + FLMUINT) // uiFlags +{ + RCODE rc = NE_FLM_OK; + int iTmp; + + f_assert( !m_bConnected); + f_assert( m_iSocket == INVALID_SOCKET); + + // Disable Nagel's algorithm + + iTmp = 1; + if( (setsockopt( iSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&iTmp, + (unsigned)sizeof( iTmp) )) < 0) + { + rc = RC_SET( NE_FLM_SOCKET_SET_OPT_FAIL); + goto Exit; + } + + m_iSocket = iSocket; + m_bConnected = TRUE; + +Exit: + + return( rc); +} + +/******************************************************************** +Desc: Gets information about the local host machine. +*********************************************************************/ +RCODE F_TCPIOStream::getLocalInfo( void) +{ + RCODE rc = NE_FLM_OK; + struct hostent * pHostEnt; + FLMUINT32 ui32IPAddr; + + m_pszIp[ 0] = 0; + m_pszName[ 0] = 0; + + if( !m_pszName[ 0]) + { + if( gethostname( m_pszName, (unsigned)sizeof( m_pszName))) + { + rc = RC_SET( NE_FLM_SOCKET_FAIL); + goto Exit; + } + } + + if( !m_pszIp[ 0] && (pHostEnt = gethostbyname( m_pszName)) != NULL) + { + ui32IPAddr = (FLMUINT32)(*((unsigned long *)pHostEnt->h_addr)); + if( ui32IPAddr != (FLMUINT32)-1) + { + struct in_addr InAddr; + + InAddr.s_addr = ui32IPAddr; + f_strcpy( m_pszIp, inet_ntoa( InAddr)); + } + } + +Exit: + + return( rc); +} + +/******************************************************************** +Desc: Gets information about the remote machine. +*********************************************************************/ +RCODE F_TCPIOStream::getRemoteInfo( void) +{ + RCODE rc = NE_FLM_OK; + struct sockaddr_in SockAddrIn; + char * InetAddr = NULL; + struct hostent * HostsName; + + m_pszPeerIp[ 0] = 0; + m_pszPeerName[ 0] = 0; + + SockAddrIn.sin_addr.s_addr = (unsigned)m_ulRemoteAddr; + + InetAddr = inet_ntoa( SockAddrIn.sin_addr); + f_strcpy( m_pszPeerIp, InetAddr); + + // Try to get the peer's host name by looking up his IP + // address. + + HostsName = gethostbyaddr( (char *)&SockAddrIn.sin_addr.s_addr, + (unsigned)sizeof( unsigned long), AF_INET ); + + if( HostsName != NULL) + { + f_strcpy( m_pszPeerName, (char*) HostsName->h_name ); + } + else + { + if( !InetAddr) + { + InetAddr = inet_ntoa( SockAddrIn.sin_addr); + } + + f_strcpy( m_pszPeerName, InetAddr); + } + + return( rc); +} + +/******************************************************************** +Desc: +*********************************************************************/ +RCODE FLMAPI F_TCPIOStream::write( + const void * pucBuffer, + FLMUINT uiBytesToWrite, + FLMUINT * puiBytesWritten) +{ + RCODE rc = NE_FLM_OK; + FLMINT iRetryCount = 0; + FLMINT iBytesWritten = 0; + + if( m_iSocket == INVALID_SOCKET) + { + rc = RC_SET( NE_FLM_CONNECT_FAIL); + goto Exit; + } + + f_assert( pucBuffer && uiBytesToWrite); + +Retry: + + if( puiBytesWritten) + { + *puiBytesWritten = 0; + } + + if( RC_OK( rc = f_socketPeek( m_iSocket, m_uiIOTimeout, FALSE))) + { + iBytesWritten = send( m_iSocket, + (char *)pucBuffer, (int)uiBytesToWrite, 0); + + switch( iBytesWritten) + { + case -1: + { + if( puiBytesWritten) + { + *puiBytesWritten = 0; + } + + rc = RC_SET( NE_FLM_SOCKET_WRITE_FAIL); + break; + } + + case 0: + { + rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); + break; + } + + default: + { + if( puiBytesWritten) + { + *puiBytesWritten = (FLMUINT)iBytesWritten; + } + + break; + } + } + } + + if( RC_BAD( rc) && rc != NE_FLM_SOCKET_WRITE_TIMEOUT) + { +#ifndef FLM_UNIX + FLMINT iSockErr = WSAGetLastError(); +#else + FLMINT iSockErr = errno; +#endif + +#if defined( FLM_WIN) || defined( FLM_NLM) + if( iSockErr == WSAECONNABORTED) +#else + if( iSockErr == ECONNABORTED) +#endif + { + rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); + } +#if defined( FLM_WIN) || defined( FLM_NLM) + else if( iSockErr == WSAEWOULDBLOCK && iRetryCount < 5) +#else + else if( iSockErr == EWOULDBLOCK && iRetryCount < 5) +#endif + { + iRetryCount++; + f_sleep( (FLMUINT)(100 * iRetryCount)); + goto Retry; + } + } + +Exit: + + return( rc); +} + +/******************************************************************** +Desc: +*********************************************************************/ +RCODE FLMAPI F_TCPIOStream::read( + void * pucBuffer, + FLMUINT uiBytesToWrite, + FLMUINT * puiBytesRead) +{ + RCODE rc = NE_FLM_OK; + FLMINT iReadCnt = 0; + + f_assert( m_bConnected && pucBuffer && uiBytesToWrite); + + if( RC_OK( rc = f_socketPeek( m_iSocket, m_uiIOTimeout, TRUE))) + { + iReadCnt = (FLMINT)recv( m_iSocket, + (char *)pucBuffer, (int)uiBytesToWrite, 0); + + switch ( iReadCnt) + { + case -1: + { + iReadCnt = 0; +#if defined( FLM_WIN) || defined( FLM_NLM) + if ( WSAGetLastError() == WSAECONNRESET) +#else + if( errno == ECONNRESET) +#endif + { + rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); + } + else + { + rc = RC_SET( NE_FLM_SOCKET_READ_FAIL); + } + break; + } + + case 0: + { + rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); + break; + } + + default: + { + break; + } + } + } + + if( puiBytesRead) + { + *puiBytesRead = (FLMUINT)iReadCnt; + } + + return( rc); +} + +/******************************************************************** +Desc: Reads data from the connection - Timeout valkue is zero, no error + is generated if timeout occurs. +*********************************************************************/ +RCODE F_TCPIOStream::readNoWait( + void * pvBuffer, + FLMUINT uiBytesToRead, + FLMUINT * puiBytesRead) +{ + RCODE rc = NE_FLM_OK; + FLMINT iReadCnt = 0; + + f_assert( m_bConnected && pvBuffer && uiBytesToRead); + + if( puiBytesRead) + { + *puiBytesRead = 0; + } + + if( RC_OK( rc = f_socketPeek( m_iSocket, (FLMUINT)0, TRUE))) + { + iReadCnt = recv( m_iSocket, (char *)pvBuffer, (int)uiBytesToRead, 0); + switch ( iReadCnt) + { + case -1: + { + *puiBytesRead = 0; +#if defined( FLM_WIN) || defined( FLM_NLM) + if ( WSAGetLastError() == WSAECONNRESET) +#else + if( errno == ECONNRESET) +#endif + { + rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); + } + else + { + rc = RC_SET( NE_FLM_SOCKET_READ_FAIL); + } + goto Exit; + } + + case 0: + { + rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); + goto Exit; + } + + default: + { + break; + } + } + } + else if (rc == NE_FLM_SOCKET_READ_TIMEOUT) + { + rc = NE_FLM_OK; + } + + if( puiBytesRead) + { + *puiBytesRead = (FLMUINT)iReadCnt; + } + +Exit: + + return( rc); +} + +/******************************************************************** +Desc: Reads data and does not return until all requested data has + been read or a timeout error has been encountered. +*********************************************************************/ +RCODE F_TCPIOStream::readAll( + void * pvBuffer, + FLMUINT uiBytesToRead, + FLMUINT * puiBytesRead) +{ + RCODE rc = NE_FLM_OK; + FLMUINT uiToRead = 0; + FLMUINT uiHaveRead = 0; + FLMUINT uiPartialCnt; + FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer; + + f_assert( m_bConnected && pvBuffer && uiBytesToRead); + + uiToRead = uiBytesToRead; + while( uiToRead) + { + if( RC_BAD( rc = read( pucBuffer, uiToRead, &uiPartialCnt))) + { + goto Exit; + } + + pucBuffer += uiPartialCnt; + uiHaveRead += uiPartialCnt; + uiToRead = (FLMUINT)(uiBytesToRead - uiHaveRead); + + if( puiBytesRead) + { + *puiBytesRead = uiHaveRead; + } + } + +Exit: + + return( rc); +} + +/******************************************************************** +Desc: Closes any open connections +*********************************************************************/ +RCODE FLMAPI F_TCPIOStream::closeStream( void) +{ + if( m_iSocket == INVALID_SOCKET) + { + goto Exit; + } + + f_closeSocket( &m_iSocket); + +Exit: + + m_bConnected = FALSE; + return( NE_FLM_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +#ifdef FLM_OPENSSL +RCODE FLMAPI F_SSLIOStream::openStream( + const char * pszHost, + FLMUINT uiPort, + FLMUINT uiFlags) +{ + RCODE rc = NE_FLM_OK; + char szPort[ 32]; + X509_NAME * pPeerName; + EVP_PKEY * pPublicKey = NULL; + BIO * pMemBIO = NULL; + FLMUINT uiCertTextLen; + const char * pszCertText; + + if( !uiPort) + { + uiPort = 443; + } + + // Setup the connection to use SSLv2, SSLv3, or TLSv1 depending on + // the capabilities of the peer + + if( (m_pContext = SSL_CTX_new( SSLv23_client_method())) == NULL) + { + rc = RC_SET( NE_FLM_CONNECT_FAIL); + goto Exit; + } + + // Set the default path for verifying certificates + + if( !SSL_CTX_set_default_verify_paths( m_pContext)) + { + rc = RC_SET( NE_FLM_CONNECT_FAIL); + goto Exit; + } + + // Configure the BIO + + if( (m_pBio = BIO_new_ssl_connect( m_pContext)) == NULL) + { + rc = RC_SET( NE_FLM_CONNECT_FAIL); + goto Exit; + } + + BIO_get_ssl( m_pBio, &m_pSSL); + if( m_pSSL == NULL) + { + rc = RC_SET( NE_FLM_CONNECT_FAIL); + goto Exit; + } + + SSL_set_mode( m_pSSL, SSL_MODE_AUTO_RETRY); + BIO_set_conn_hostname( m_pBio, pszHost); + + f_sprintf( szPort, "%u", (unsigned)uiPort); + BIO_set_conn_port( m_pBio, szPort); + + // Open the connection + + if( BIO_do_connect( m_pBio) <= 0) + { + rc = RC_SET( NE_FLM_CONNECT_FAIL); + goto Exit; + } + + if( SSL_get_verify_result( m_pSSL) != X509_V_OK) + { + rc = RC_SET( NE_FLM_CONNECT_FAIL); + goto Exit; + } + + if( (m_pPeerCertificate = SSL_get_peer_certificate( m_pSSL)) == NULL) + { + rc = RC_SET( NE_FLM_CONNECT_FAIL); + goto Exit; + } + + if( (pPeerName = X509_get_subject_name( m_pPeerCertificate)) == NULL) + { + rc = RC_SET( NE_FLM_CONNECT_FAIL); + goto Exit; + } + + if( (X509_NAME_get_text_by_NID( pPeerName, NID_commonName, + m_szPeerName, sizeof( m_szPeerName))) == -1) + { + rc = RC_SET( NE_FLM_CONNECT_FAIL); + goto Exit; + } + + if( f_stricmp( pszHost, m_szPeerName) != 0) + { + rc = RC_SET( NE_FLM_CONNECT_FAIL); + goto Exit; + } + + // Get the peer's certificate text + + if( (pMemBIO = BIO_new( BIO_s_mem())) == NULL) + { + rc = RC_SET( NE_FLM_MEM); + goto Exit; + } + + if( (pPublicKey = X509_get_pubkey( m_pPeerCertificate)) == NULL) + { + rc = RC_SET( NE_FLM_CONNECT_FAIL); + goto Exit; + } + + if( pPublicKey->type != EVP_PKEY_RSA) + { + rc = RC_SET( NE_FLM_CONNECT_FAIL); + goto Exit; + } + + if( (PEM_write_bio_X509( pMemBIO, m_pPeerCertificate)) == 0) + { + rc = RC_SET( NE_FLM_MEM); + goto Exit; + } + + if( (uiCertTextLen = BIO_get_mem_data( pMemBIO, &pszCertText)) == 0) + { + rc = RC_SET( NE_FLM_MEM); + goto Exit; + } + + if( RC_BAD( rc = f_alloc( uiCertTextLen + 1, &m_pszPeerCertText))) + { + goto Exit; + } + + f_memcpy( m_pszPeerCertText, pszCertText, uiCertTextLen + 1); + +Exit: + + if( pMemBIO) + { + BIO_free( pMemBIO); + } + + if( pPublicKey) + { + EVP_PKEY_free( pPublicKey); + } + + if( RC_BAD( rc)) + { + closeStream(); + } + + return( rc); +} +#endif + +/**************************************************************************** +Desc: +****************************************************************************/ +#ifdef FLM_OPENSSL +RCODE FLMAPI F_SSLIOStream::read( + void * pvBuffer, + FLMUINT uiBytesToRead, + FLMUINT * puiBytesRead) +{ + RCODE rc = NE_FLM_OK; + int iBytesRead; + FLMUINT uiTotalBytesRead = 0; + char * pucBuffer = (char *)pvBuffer; + + while( uiBytesToRead) + { + if( (iBytesRead = BIO_read( m_pBio, &pucBuffer[ uiTotalBytesRead], + uiBytesToRead)) <= 0) + { + if( !BIO_should_retry( m_pBio)) + { + rc = RC_SET( NE_FLM_EOF_HIT); + goto Exit; + } + + continue; + } + + uiTotalBytesRead += iBytesRead; + uiBytesToRead -= iBytesRead; + } + +Exit: + + if( puiBytesRead) + { + *puiBytesRead = uiTotalBytesRead; + } + + return( rc); +} +#endif + +/**************************************************************************** +Desc: +****************************************************************************/ +#ifdef FLM_OPENSSL +RCODE FLMAPI F_SSLIOStream::write( + const void * pvBuffer, + FLMUINT uiBytesToWrite, + FLMUINT * puiBytesWritten) +{ + RCODE rc = NE_FLM_OK; + int iBytesWritten = 0; + + if( !uiBytesToWrite) + { + goto Exit; + } + + if( (iBytesWritten = BIO_write( m_pBio, pvBuffer, uiBytesToWrite)) <= 0) + { + iBytesWritten = 0; + rc = RC_SET( NE_FLM_SOCKET_WRITE_FAIL); + goto Exit; + } + +Exit: + + if( puiBytesWritten) + { + *puiBytesWritten = (FLMUINT)iBytesWritten; + } + + return( rc); +} +#endif + +/**************************************************************************** +Desc: +****************************************************************************/ +#ifdef FLM_OPENSSL +RCODE FLMAPI F_SSLIOStream::closeStream( void) +{ + if( m_pBio) + { + BIO_free_all( m_pBio); + m_pBio = NULL; + m_pSSL = NULL; + } + + if( m_pPeerCertificate) + { + X509_free( m_pPeerCertificate); + m_pPeerCertificate = NULL; + } + + if( m_pszPeerCertText) + { + f_free( &m_pszPeerCertText); + } + + if( m_pContext) + { + SSL_CTX_free( m_pContext); + m_pContext = NULL; + } + + m_szPeerName[ 0] = 0; + + return( NE_FLM_OK); +} +#endif + +/****************************************************************************** +Desc: +******************************************************************************/ +#ifdef FLM_OPENSSL +const char * FLMAPI F_SSLIOStream::getPeerCertificateText( void) +{ + return( m_pszPeerCertText); +} +#endif + +/******************************************************************** +Desc: +*********************************************************************/ +RCODE f_socketPeek( + int iSocket, + FLMUINT uiTimeoutVal, + FLMBOOL bPeekRead) +{ + RCODE rc = NE_FLM_OK; + struct timeval TimeOut; + int iMaxDescs; + fd_set GenDescriptors; + fd_set * DescrRead; + fd_set * DescrWrt; + + if( iSocket != INVALID_SOCKET) + { + FD_ZERO( &GenDescriptors); +#ifdef FLM_WIN + #pragma warning( push) + #pragma warning( disable : 4127) +#endif + + FD_SET( iSocket, &GenDescriptors); + +#ifdef FLM_WIN + #pragma warning( pop) +#endif + + iMaxDescs = (int)(iSocket + 1); + DescrRead = bPeekRead ? &GenDescriptors : NULL; + DescrWrt = bPeekRead ? NULL : &GenDescriptors; + + TimeOut.tv_sec = (long)uiTimeoutVal; + TimeOut.tv_usec = (long)0; + + if( select( iMaxDescs, DescrRead, DescrWrt, NULL, &TimeOut) < 0 ) + { + rc = RC_SET( NE_FLM_SELECT_ERR); + goto Exit; + } + else + { + if( !FD_ISSET( iSocket, &GenDescriptors)) + { + rc = bPeekRead + ? RC_SET( NE_FLM_SOCKET_READ_TIMEOUT) + : RC_SET( NE_FLM_SOCKET_WRITE_TIMEOUT); + } + } + } + else + { + rc = RC_SET( NE_FLM_CONNECT_FAIL); + } + +Exit: + + return( rc); +} + +/******************************************************************** +Desc: +*********************************************************************/ +void f_closeSocket( + int * piSocket) +{ + if( *piSocket != INVALID_SOCKET) + { +#ifndef FLM_UNIX + closesocket( *piSocket); +#else + ::close( *piSocket); +#endif + *piSocket = INVALID_SOCKET; + } +} + +/***************************************************************************** +Desc: +******************************************************************************/ +RCODE FLMAPI FlmOpenTCPListener( + FLMBYTE * pucBindAddr, + FLMUINT uiBindPort, + IF_TCPListener ** ppListener) +{ + RCODE rc = NE_FLM_OK; + F_TCPListener * pListener = NULL; + + if( (pListener = f_new F_TCPListener) == NULL) + { + rc = RC_SET( NE_FLM_MEM); + goto Exit; + } + + if( RC_BAD( pListener->bind( uiBindPort, pucBindAddr))) + { + goto Exit; + } + + *ppListener = pListener; + pListener = NULL; + +Exit: + + if( pListener) + { + pListener->Release(); + } + + return( rc); +} + diff --git a/ftk/src/ftkprntf.cpp b/ftk/src/ftkprntf.cpp index 7f73ca6..73b159f 100644 --- a/ftk/src/ftkprntf.cpp +++ b/ftk/src/ftkprntf.cpp @@ -145,6 +145,114 @@ private: F_DynaBuf m_dynaBuf; }; +/**************************************************************************** +Desc: +****************************************************************************/ +class FLMEXP F_StdoutPrintfClient : public IF_PrintfClient +{ +public: + + F_StdoutPrintfClient() + { + } + + virtual ~F_StdoutPrintfClient() + { + } + + FINLINE FLMINT FLMAPI outputChar( + char cChar) + { + f_printf( "%c", cChar); + return( 1); + } + + FINLINE FLMINT FLMAPI outputChar( + char cChar, + FLMUINT uiCount) + { + FLMINT iBytesOutput = (FLMINT)uiCount; + + while( uiCount) + { + f_printf( "%c", cChar); + uiCount--; + } + + return( iBytesOutput); + } + + FINLINE FLMINT FLMAPI outputStr( + const char * pszStr, + FLMUINT uiLen) + { + f_printf( "%*s", (unsigned)uiLen, pszStr); + return( (FLMINT)uiLen); + } + + FINLINE FLMINT FLMAPI colorFormatter( + char, // cFormatChar, + eColorType, // eColor, + FLMUINT) // uiFlags) + { + return( 0); + } +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +class FLMEXP F_StderrPrintfClient : public IF_PrintfClient +{ +public: + + F_StderrPrintfClient() + { + } + + virtual ~F_StderrPrintfClient() + { + } + + FINLINE FLMINT FLMAPI outputChar( + char cChar) + { + f_printf( "%c", cChar); + return( 1); + } + + FINLINE FLMINT FLMAPI outputChar( + char cChar, + FLMUINT uiCount) + { + FLMINT iBytesOutput = (FLMINT)uiCount; + + while( uiCount) + { + f_printf( "%c", cChar); + uiCount--; + } + + return( iBytesOutput); + } + + FINLINE FLMINT FLMAPI outputStr( + const char * pszStr, + FLMUINT uiLen) + { + f_printf( "%*s", (unsigned)uiLen, pszStr); + return( (FLMINT)uiLen); + } + + FINLINE FLMINT FLMAPI colorFormatter( + char, // cFormatChar, + eColorType, // eColor, + FLMUINT) // uiFlags) + { + return( 0); + } +}; + /**************************************************************************** Desc: Parameter 'format' points to text following a '%' sign. Process legal field information. Leave 'format' pointing at the format @@ -885,3 +993,55 @@ FLMINT FLMAPI f_printf( return( iLen); } +/**************************************************************************** +Desc: +****************************************************************************/ +FLMINT FLMAPI f_errprintf( + const char * pszFormat, + ...) +{ + FLMINT iLen; + f_va_list args; + F_DynaPrintfClient printfClient; + + f_va_start( args, pszFormat); + iLen = f_vprintf( &printfClient, pszFormat, &args); + f_va_end( args); + printfClient.outputChar( 0); + +#ifndef FLM_RING_ZERO_NLM + fprintf( stderr, printfClient.getBufferPtr()); + fflush( stderr); +#endif + + return( iLen); +} + +/***************************************************************************** +Desc: +******************************************************************************/ +RCODE FLMAPI FlmAllocStdoutPrintfClient( + IF_PrintfClient ** ppClient) +{ + if( (*ppClient = f_new F_StdoutPrintfClient) == NULL) + { + return( RC_SET( NE_FLM_MEM)); + } + + return( NE_FLM_OK); +} + +/***************************************************************************** +Desc: +******************************************************************************/ +RCODE FLMAPI FlmAllocStderrPrintfClient( + IF_PrintfClient ** ppClient) +{ + if( (*ppClient = f_new F_StderrPrintfClient) == NULL) + { + return( RC_SET( NE_FLM_MEM)); + } + + return( NE_FLM_OK); +} + diff --git a/ftk/src/ftkstrm.cpp b/ftk/src/ftkstrm.cpp index af53997..90d3817 100644 --- a/ftk/src/ftkstrm.cpp +++ b/ftk/src/ftkstrm.cpp @@ -222,166 +222,6 @@ private: IF_OStream * m_pOStream; }; -/**************************************************************************** -Desc: -****************************************************************************/ -class F_TCPIOStream : public IF_IOStream -{ -public: - - #if defined( FLM_WIN) && _MSC_VER < 1300 - using IF_IStream::operator delete; - #endif - - F_TCPIOStream( void); - - virtual ~F_TCPIOStream( void); - - RCODE openStream( - const char * pucHostAddress, - FLMUINT uiPort, - FLMUINT uiFlags, - FLMUINT uiConnectTimeout = 3, - FLMUINT uiDataTimeout = 15); - - RCODE FLMAPI read( - void * pvBuffer, - FLMUINT uiBytesToRead, - FLMUINT * puiBytesRead); - - RCODE FLMAPI write( - const void * pvBuffer, - FLMUINT uiBytesToWrite, - FLMUINT * puiBytesWritten); - - FINLINE RCODE socketPeekWrite( - FLMINT iTimeOut) - { - return( socketPeek( iTimeOut, FALSE)); - } - - FINLINE RCODE socketPeekRead( - FLMINT iTimeOut) - { - return( socketPeek( iTimeOut, TRUE)); - }; - - FINLINE const char * getName( void) - { - getLocalInfo(); - return( (const char *)m_pszName); - }; - - FINLINE const char * getAddr( void) - { - getLocalInfo(); - return( (const char *)m_pszIp); - }; - - FINLINE const char * getPeerName( void) - { - getRemoteInfo(); - return( (const char *)m_pszPeerName); - }; - - FINLINE const char * getPeerAddr( void) - { - getRemoteInfo(); - return( (const char *)m_pszPeerIp); - }; - - RCODE readNoWait( - void * pvBuffer, - FLMUINT uiCount, - FLMUINT * puiReadRead); - - RCODE readAll( - void * pvBuffer, - FLMUINT uiCount, - FLMUINT * puiBytesRead); - - RCODE setTcpDelay( - FLMBOOL bOn); - - RCODE FLMAPI closeStream( void); - -private: - - RCODE getLocalInfo( void); - - RCODE getRemoteInfo( void); - - RCODE socketPeek( - FLMINT iTimoutVal, - FLMBOOL bPeekRead); - -#ifndef FLM_UNIX - WSADATA m_wsaData; -#endif - FLMBOOL m_bInitialized; - SOCKET m_iSocket; - FLMUINT m_uiIOTimeout; - FLMBOOL m_bConnected; - char m_pszIp[ 256]; - char m_pszName[ 256]; - char m_pszPeerIp[ 256]; - char m_pszPeerName[ 256]; - unsigned long m_ulRemoteAddr; -}; - -/**************************************************************************** -Desc: -****************************************************************************/ -#ifdef FLM_OPENSSL -class F_SSLIOStream : public IF_SSLIOStream -{ -public: - - F_SSLIOStream() - { - m_pBio = NULL; - m_pContext = NULL; - m_pSSL = NULL; - m_pPeerCertificate = NULL; - m_pszPeerCertText = NULL; - m_szPeerName[ 0] = 0; - } - - virtual ~F_SSLIOStream() - { - closeStream(); - } - - RCODE FLMAPI openStream( - const char * pszHost, - FLMUINT uiPort = 443, - FLMUINT uiFlags = 0); - - RCODE FLMAPI read( - void * pvBuffer, - FLMUINT uiBytesToRead, - FLMUINT * puiBytesRead = NULL); - - RCODE FLMAPI write( - const void * pvBuffer, - FLMUINT uiBytesToWrite, - FLMUINT * puiBytesWritten = NULL); - - const char * FLMAPI getPeerCertificateText( void); - - RCODE FLMAPI closeStream( void); - -private: - - BIO * m_pBio; - SSL_CTX * m_pContext; - SSL * m_pSSL; - X509 * m_pPeerCertificate; - char * m_pszPeerCertText; - char m_szPeerName[ 256]; -}; -#endif - /***************************************************************************** Desc: ******************************************************************************/ @@ -812,114 +652,6 @@ Exit: return( rc); } -/***************************************************************************** -Desc: -******************************************************************************/ -RCODE FLMAPI FlmOpenTCPIOStream( - const char * pszHost, - FLMUINT uiPort, - FLMUINT uiFlags, - IF_IOStream ** ppIOStream) -{ - RCODE rc = NE_FLM_OK; - F_TCPIOStream * pIOStream = NULL; - - if( (pIOStream = f_new F_TCPIOStream) == NULL) - { - rc = RC_SET( NE_FLM_MEM); - goto Exit; - } - - if( RC_BAD( rc = pIOStream->openStream( pszHost, uiPort, uiFlags))) - { - goto Exit; - } - - *ppIOStream = pIOStream; - pIOStream = NULL; - -Exit: - - if( pIOStream) - { - pIOStream->Release(); - } - - return( rc); -} - -/***************************************************************************** -Desc: -******************************************************************************/ -RCODE FLMAPI FlmAllocSSLIOStream( - IF_IOStream ** ppIOStream) -{ -#ifdef FLM_OPENSSL - - if( (*ppIOStream = f_new F_SSLIOStream) == NULL) - { - return( RC_SET( NE_FLM_MEM)); - } - - return( NE_FLM_OK); - -#else - - F_UNREFERENCED_PARM( ppIOStream); - return( RC_SET( NE_FLM_NOT_IMPLEMENTED)); - -#endif -} - -/***************************************************************************** -Desc: -******************************************************************************/ -RCODE FLMAPI FlmOpenSSLIOStream( - const char * pszHost, - FLMUINT uiPort, - FLMUINT uiFlags, - IF_IOStream ** ppIOStream) -{ -#ifdef FLM_OPENSSL - - RCODE rc = NE_FLM_OK; - F_SSLIOStream * pIOStream = NULL; - - if( (pIOStream = f_new F_SSLIOStream) == NULL) - { - rc = RC_SET( NE_FLM_MEM); - goto Exit; - } - - if( RC_BAD( rc = pIOStream->openStream( pszHost, uiPort, uiFlags))) - { - goto Exit; - } - - *ppIOStream = pIOStream; - pIOStream = NULL; - -Exit: - - if( pIOStream) - { - pIOStream->Release(); - } - - return( rc); - -#else - - F_UNREFERENCED_PARM( pszHost); - F_UNREFERENCED_PARM( uiPort); - F_UNREFERENCED_PARM( uiFlags); - F_UNREFERENCED_PARM( ppIOStream); - - return( RC_SET( NE_FLM_NOT_IMPLEMENTED)); - -#endif -} - /**************************************************************************** Desc: *****************************************************************************/ @@ -2953,952 +2685,6 @@ RCODE FLMAPI F_UncompressingIStream::closeStream( void) return( NE_FLM_OK); } -/******************************************************************** -Desc: -*********************************************************************/ -F_TCPIOStream::F_TCPIOStream( void) -{ - m_pszIp[ 0] = 0; - m_pszName[ 0] = 0; - m_pszPeerIp[ 0] = 0; - m_pszPeerName[ 0] = 0; - m_uiIOTimeout = 10; - m_iSocket = INVALID_SOCKET; - m_ulRemoteAddr = 0; - m_bInitialized = FALSE; - m_bConnected = FALSE; - -#ifndef FLM_UNIX - if( !WSAStartup( MAKEWORD( 2, 0), &m_wsaData)) - { - m_bInitialized = TRUE; - } -#endif -} - -/******************************************************************** -Desc: -*********************************************************************/ -F_TCPIOStream::~F_TCPIOStream( void) -{ - if( m_bConnected) - { - closeStream(); - } - -#ifndef FLM_UNIX - if( m_bInitialized) - { - WSACleanup(); - } -#endif -} - -/******************************************************************** -Desc: Opens a new connection -*********************************************************************/ -RCODE F_TCPIOStream::openStream( - const char * pucHostName, - FLMUINT uiPort, - FLMUINT, // uiFlags, - FLMUINT uiConnectTimeout, - FLMUINT uiDataTimeout) -{ - RCODE rc = NE_FLM_OK; - FLMINT iSockErr; - FLMINT iTries; - FLMINT iMaxTries = 5; - struct sockaddr_in address; - struct hostent * pHostEntry; - unsigned long ulIPAddr; - int iTmp; - - f_assert( !m_bConnected); - m_iSocket = INVALID_SOCKET; - - if( pucHostName && pucHostName[ 0] != '\0') - { - ulIPAddr = inet_addr( (char *)pucHostName); - if( ulIPAddr == (unsigned long)(-1)) - { - pHostEntry = gethostbyname( (char *)pucHostName); - - if( !pHostEntry) - { - rc = RC_SET( NE_FLM_NOIP_ADDR); - goto Exit; - } - else - { - ulIPAddr = *((unsigned long *)pHostEntry->h_addr); - } - - } - } - else - { - ulIPAddr = inet_addr( (char *)"127.0.0.1"); - } - - // Fill in the Socket structure with family type - - f_memset( (char *)&address, 0, sizeof( struct sockaddr_in)); - address.sin_family = AF_INET; - address.sin_addr.s_addr = (unsigned)ulIPAddr; - address.sin_port = htons( (unsigned short)uiPort); - - // Allocate a socket, then attempt to connect to it! - - if( (m_iSocket = socket( AF_INET, - SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) - { - rc = RC_SET( NE_FLM_SOCKET_FAIL); - goto Exit; - } - - // Now attempt to connect with the specified partner host, - // time-out if connection doesn't complete within alloted time - -#ifdef FLM_WIN - - if( uiConnectTimeout) - { - if ( uiConnectTimeout < 5 ) - { - iMaxTries = (iMaxTries * uiConnectTimeout) / 5; - uiConnectTimeout = 5; - } - } - else - { - iMaxTries = 1; - } -#endif - - for( iTries = 0; iTries < iMaxTries; iTries++ ) - { - iSockErr = 0; - if( connect( m_iSocket, (struct sockaddr *)((void *)&address), - (unsigned)sizeof(struct sockaddr)) >= 0) - { - break; - } - - #ifndef FLM_UNIX - iSockErr = WSAGetLastError(); - #else - iSockErr = errno; - #endif - - #ifdef FLM_WIN - - // In WIN, we sometimes get WSAEINVAL when, if we keep - // trying, we will eventually connect. Therefore, - // here we'll treat WSAEINVAL as EINPROGRESS. - - if( iSockErr == WSAEINVAL) - { - #ifndef FLM_UNIX - closesocket( m_iSocket); - #else - ::close( m_iSocket); - #endif - if( (m_iSocket = socket( AF_INET, - SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) - { - rc = RC_SET( NE_FLM_SOCKET_FAIL); - goto Exit; - } - #if defined( FLM_WIN) || defined( FLM_NLM) - iSockErr = WSAEINPROGRESS; - #else - iSockErr = EINPROGRESS; - #endif - continue; - } - #endif - - #if defined( FLM_WIN) || defined( FLM_NLM) - if( iSockErr == WSAEISCONN ) - #else - if( iSockErr == EISCONN ) - #endif - { - break; - } - #if defined( FLM_WIN) || defined( FLM_NLM) - else if( iSockErr == WSAEWOULDBLOCK) - #else - else if( iSockErr == EWOULDBLOCK) - #endif - { - // Let's wait a split second to give the connection - // request a chance. - - f_sleep( 100 ); - continue; - } - #if defined( FLM_WIN) || defined( FLM_NLM) - else if( iSockErr == WSAEINPROGRESS) - #else - else if( iSockErr == EINPROGRESS) - #endif - { - if( RC_OK( rc = socketPeek( uiConnectTimeout, FALSE))) - { - // Let's wait a split second to give the connection - // request a chance. - - f_sleep( 100 ); - continue; - } - } - - rc = RC_SET( NE_FLM_CONNECT_FAIL); - goto Exit; - } - - // Disable Nagel's algorithm - - iTmp = 1; - if( (setsockopt( m_iSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&iTmp, - (unsigned)sizeof( iTmp) )) < 0) - { - rc = RC_SET( NE_FLM_SOCKET_SET_OPT_FAIL); - goto Exit; - } - - m_uiIOTimeout = uiDataTimeout; - m_bConnected = TRUE; - -Exit: - - if( RC_BAD( rc)) - { - if( m_iSocket != INVALID_SOCKET) - { - #ifndef FLM_UNIX - closesocket( m_iSocket); - #else - ::close( m_iSocket); - #endif - m_iSocket = INVALID_SOCKET; - } - } - - return( rc); -} - -/******************************************************************** -Desc: Gets information about the local host machine. -*********************************************************************/ -RCODE F_TCPIOStream::getLocalInfo( void) -{ - RCODE rc = NE_FLM_OK; - struct hostent * pHostEnt; - FLMUINT32 ui32IPAddr; - - m_pszIp[ 0] = 0; - m_pszName[ 0] = 0; - - if( !m_pszName[ 0]) - { - if( gethostname( m_pszName, (unsigned)sizeof( m_pszName))) - { - rc = RC_SET( NE_FLM_SOCKET_FAIL); - goto Exit; - } - } - - if( !m_pszIp[ 0] && (pHostEnt = gethostbyname( m_pszName)) != NULL) - { - ui32IPAddr = (FLMUINT32)(*((unsigned long *)pHostEnt->h_addr)); - if( ui32IPAddr != (FLMUINT32)-1) - { - struct in_addr InAddr; - - InAddr.s_addr = ui32IPAddr; - f_strcpy( m_pszIp, inet_ntoa( InAddr)); - } - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Gets information about the remote machine. -*********************************************************************/ -RCODE F_TCPIOStream::getRemoteInfo( void) -{ - RCODE rc = NE_FLM_OK; - struct sockaddr_in SockAddrIn; - char * InetAddr = NULL; - struct hostent * HostsName; - - m_pszPeerIp[ 0] = 0; - m_pszPeerName[ 0] = 0; - - SockAddrIn.sin_addr.s_addr = (unsigned)m_ulRemoteAddr; - - InetAddr = inet_ntoa( SockAddrIn.sin_addr); - f_strcpy( m_pszPeerIp, InetAddr); - - // Try to get the peer's host name by looking up his IP - // address. - - HostsName = gethostbyaddr( (char *)&SockAddrIn.sin_addr.s_addr, - (unsigned)sizeof( unsigned long), AF_INET ); - - if( HostsName != NULL) - { - f_strcpy( m_pszPeerName, (char*) HostsName->h_name ); - } - else - { - if (!InetAddr) - { - InetAddr = inet_ntoa( SockAddrIn.sin_addr); - } - - f_strcpy( m_pszPeerName, InetAddr); - } - - return( rc); -} - -/******************************************************************** -Desc: Tests for socket data readiness -*********************************************************************/ -RCODE F_TCPIOStream::socketPeek( - FLMINT iTimeoutVal, - FLMBOOL bPeekRead) -{ - RCODE rc = NE_FLM_OK; - struct timeval TimeOut; - int iMaxDescs; - fd_set GenDescriptors; - fd_set * DescrRead; - fd_set * DescrWrt; - - if( m_iSocket != INVALID_SOCKET) - { - FD_ZERO( &GenDescriptors); -#ifdef FLM_WIN - #pragma warning( push) - #pragma warning( disable : 4127) -#endif - - FD_SET( m_iSocket, &GenDescriptors); - -#ifdef FLM_WIN - #pragma warning( pop) -#endif - - iMaxDescs = (int)(m_iSocket + 1); - DescrRead = bPeekRead ? &GenDescriptors : NULL; - DescrWrt = bPeekRead ? NULL : &GenDescriptors; - - TimeOut.tv_sec = (long)iTimeoutVal; - TimeOut.tv_usec = (long)0; - - if( select( iMaxDescs, DescrRead, DescrWrt, NULL, &TimeOut) < 0 ) - { - rc = RC_SET( NE_FLM_SELECT_ERR); - goto Exit; - } - else - { - if( !FD_ISSET( m_iSocket, &GenDescriptors)) - { - rc = bPeekRead - ? RC_SET( NE_FLM_SOCKET_READ_TIMEOUT) - : RC_SET( NE_FLM_SOCKET_WRITE_TIMEOUT); - } - } - } - else - { - rc = RC_SET( NE_FLM_CONNECT_FAIL); - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: -*********************************************************************/ -RCODE FLMAPI F_TCPIOStream::write( - const void * pucBuffer, - FLMUINT uiBytesToWrite, - FLMUINT * puiBytesWritten) -{ - RCODE rc = NE_FLM_OK; - FLMINT iRetryCount = 0; - FLMINT iBytesWritten = 0; - - if( m_iSocket == INVALID_SOCKET) - { - rc = RC_SET( NE_FLM_CONNECT_FAIL); - goto Exit; - } - - f_assert( pucBuffer && uiBytesToWrite); - -Retry: - - if( puiBytesWritten) - { - *puiBytesWritten = 0; - } - - if( RC_OK( rc = socketPeek( m_uiIOTimeout, FALSE))) - { - iBytesWritten = send( m_iSocket, - (char *)pucBuffer, (int)uiBytesToWrite, 0); - - switch( iBytesWritten) - { - case -1: - { - if( puiBytesWritten) - { - *puiBytesWritten = 0; - } - - rc = RC_SET( NE_FLM_SOCKET_WRITE_FAIL); - break; - } - - case 0: - { - rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); - break; - } - - default: - { - if( puiBytesWritten) - { - *puiBytesWritten = (FLMUINT)iBytesWritten; - } - - break; - } - } - } - - if( RC_BAD( rc) && rc != NE_FLM_SOCKET_WRITE_TIMEOUT) - { -#ifndef FLM_UNIX - FLMINT iSockErr = WSAGetLastError(); -#else - FLMINT iSockErr = errno; -#endif - -#if defined( FLM_WIN) || defined( FLM_NLM) - if( iSockErr == WSAECONNABORTED) -#else - if( iSockErr == ECONNABORTED) -#endif - { - rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); - } -#if defined( FLM_WIN) || defined( FLM_NLM) - else if( iSockErr == WSAEWOULDBLOCK && iRetryCount < 5) -#else - else if( iSockErr == EWOULDBLOCK && iRetryCount < 5) -#endif - { - iRetryCount++; - f_sleep( (FLMUINT)(100 * iRetryCount)); - goto Retry; - } - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: -*********************************************************************/ -RCODE FLMAPI F_TCPIOStream::read( - void * pucBuffer, - FLMUINT uiBytesToWrite, - FLMUINT * puiBytesRead) -{ - RCODE rc = NE_FLM_OK; - FLMINT iReadCnt = 0; - - f_assert( m_bConnected && pucBuffer && uiBytesToWrite); - - if( RC_OK( rc = socketPeek( m_uiIOTimeout, TRUE))) - { - iReadCnt = (FLMINT)recv( m_iSocket, - (char *)pucBuffer, (int)uiBytesToWrite, 0); - - switch ( iReadCnt) - { - case -1: - { - iReadCnt = 0; -#if defined( FLM_WIN) || defined( FLM_NLM) - if ( WSAGetLastError() == WSAECONNRESET) -#else - if( errno == ECONNRESET) -#endif - { - rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); - } - else - { - rc = RC_SET( NE_FLM_SOCKET_READ_FAIL); - } - break; - } - - case 0: - { - rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); - break; - } - - default: - { - break; - } - } - } - - if( puiBytesRead) - { - *puiBytesRead = (FLMUINT)iReadCnt; - } - - return( rc); -} - -/******************************************************************** -Desc: Reads data from the connection - Timeout valkue is zero, no error - is generated if timeout occurs. -*********************************************************************/ -RCODE F_TCPIOStream::readNoWait( - void * pvBuffer, - FLMUINT uiBytesToRead, - FLMUINT * puiBytesRead) -{ - RCODE rc = NE_FLM_OK; - FLMINT iReadCnt = 0; - - f_assert( m_bConnected && pvBuffer && uiBytesToRead); - - if( puiBytesRead) - { - *puiBytesRead = 0; - } - - if( RC_OK( rc = socketPeek( (FLMUINT)0, TRUE))) - { - iReadCnt = recv( m_iSocket, (char *)pvBuffer, (int)uiBytesToRead, 0); - switch ( iReadCnt) - { - case -1: - { - *puiBytesRead = 0; -#if defined( FLM_WIN) || defined( FLM_NLM) - if ( WSAGetLastError() == WSAECONNRESET) -#else - if( errno == ECONNRESET) -#endif - { - rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); - } - else - { - rc = RC_SET( NE_FLM_SOCKET_READ_FAIL); - } - goto Exit; - } - - case 0: - { - rc = RC_SET( NE_FLM_SOCKET_DISCONNECT); - goto Exit; - } - - default: - { - break; - } - } - } - else if (rc == NE_FLM_SOCKET_READ_TIMEOUT) - { - rc = NE_FLM_OK; - } - - if( puiBytesRead) - { - *puiBytesRead = (FLMUINT)iReadCnt; - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Reads data and does not return until all requested data has - been read or a timeout error has been encountered. -*********************************************************************/ -RCODE F_TCPIOStream::readAll( - void * pvBuffer, - FLMUINT uiBytesToRead, - FLMUINT * puiBytesRead) -{ - RCODE rc = NE_FLM_OK; - FLMUINT uiToRead = 0; - FLMUINT uiHaveRead = 0; - FLMUINT uiPartialCnt; - FLMBYTE * pucBuffer = (FLMBYTE *)pvBuffer; - - f_assert( m_bConnected && pvBuffer && uiBytesToRead); - - uiToRead = uiBytesToRead; - while( uiToRead) - { - if( RC_BAD( rc = read( pucBuffer, uiToRead, &uiPartialCnt))) - { - goto Exit; - } - - pucBuffer += uiPartialCnt; - uiHaveRead += uiPartialCnt; - uiToRead = (FLMUINT)(uiBytesToRead - uiHaveRead); - - if( puiBytesRead) - { - *puiBytesRead = uiHaveRead; - } - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Closes any open connections -*********************************************************************/ -RCODE FLMAPI F_TCPIOStream::closeStream( void) -{ - if( m_iSocket == INVALID_SOCKET) - { - goto Exit; - } - -#ifndef FLM_UNIX - closesocket( m_iSocket); -#else - ::close( m_iSocket); -#endif - -Exit: - - m_iSocket = INVALID_SOCKET; - m_bConnected = FALSE; - - return( NE_FLM_OK); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -#ifdef FLM_OPENSSL -RCODE FLMAPI F_SSLIOStream::openStream( - const char * pszHost, - FLMUINT uiPort, - FLMUINT uiFlags) -{ - RCODE rc = NE_FLM_OK; - char szPort[ 32]; - X509_NAME * pPeerName; - EVP_PKEY * pPublicKey = NULL; - BIO * pMemBIO = NULL; - FLMUINT uiCertTextLen; - const char * pszCertText; - - if( !uiPort) - { - uiPort = 443; - } - - // Setup the connection to use SSLv2, SSLv3, or TLSv1 depending on - // the capabilities of the peer - - if( (m_pContext = SSL_CTX_new( SSLv23_client_method())) == NULL) - { - rc = RC_SET( NE_FLM_CONNECT_FAIL); - goto Exit; - } - - // Set the default path for verifying certificates - - if( !SSL_CTX_set_default_verify_paths( m_pContext)) - { - rc = RC_SET( NE_FLM_CONNECT_FAIL); - goto Exit; - } - - // Configure the BIO - - if( (m_pBio = BIO_new_ssl_connect( m_pContext)) == NULL) - { - rc = RC_SET( NE_FLM_CONNECT_FAIL); - goto Exit; - } - - BIO_get_ssl( m_pBio, &m_pSSL); - if( m_pSSL == NULL) - { - rc = RC_SET( NE_FLM_CONNECT_FAIL); - goto Exit; - } - - SSL_set_mode( m_pSSL, SSL_MODE_AUTO_RETRY); - BIO_set_conn_hostname( m_pBio, pszHost); - - f_sprintf( szPort, "%u", (unsigned)uiPort); - BIO_set_conn_port( m_pBio, szPort); - - // Open the connection - - if( BIO_do_connect( m_pBio) <= 0) - { - rc = RC_SET( NE_FLM_CONNECT_FAIL); - goto Exit; - } - - if( SSL_get_verify_result( m_pSSL) != X509_V_OK) - { - rc = RC_SET( NE_FLM_CONNECT_FAIL); - goto Exit; - } - - if( (m_pPeerCertificate = SSL_get_peer_certificate( m_pSSL)) == NULL) - { - rc = RC_SET( NE_FLM_CONNECT_FAIL); - goto Exit; - } - - if( (pPeerName = X509_get_subject_name( m_pPeerCertificate)) == NULL) - { - rc = RC_SET( NE_FLM_CONNECT_FAIL); - goto Exit; - } - - if( (X509_NAME_get_text_by_NID( pPeerName, NID_commonName, - m_szPeerName, sizeof( m_szPeerName))) == -1) - { - rc = RC_SET( NE_FLM_CONNECT_FAIL); - goto Exit; - } - - if( f_stricmp( pszHost, m_szPeerName) != 0) - { - rc = RC_SET( NE_FLM_CONNECT_FAIL); - goto Exit; - } - - // Get the peer's certificate text - - if( (pMemBIO = BIO_new( BIO_s_mem())) == NULL) - { - rc = RC_SET( NE_FLM_MEM); - goto Exit; - } - - if( (pPublicKey = X509_get_pubkey( m_pPeerCertificate)) == NULL) - { - rc = RC_SET( NE_FLM_CONNECT_FAIL); - goto Exit; - } - - if( pPublicKey->type != EVP_PKEY_RSA) - { - rc = RC_SET( NE_FLM_CONNECT_FAIL); - goto Exit; - } - - if( (PEM_write_bio_X509( pMemBIO, m_pPeerCertificate)) == 0) - { - rc = RC_SET( NE_FLM_MEM); - goto Exit; - } - - if( (uiCertTextLen = BIO_get_mem_data( pMemBIO, &pszCertText)) == 0) - { - rc = RC_SET( NE_FLM_MEM); - goto Exit; - } - - if( RC_BAD( rc = f_alloc( uiCertTextLen + 1, &m_pszPeerCertText))) - { - goto Exit; - } - - f_memcpy( m_pszPeerCertText, pszCertText, uiCertTextLen + 1); - -Exit: - - if( pMemBIO) - { - BIO_free( pMemBIO); - } - - if( pPublicKey) - { - EVP_PKEY_free( pPublicKey); - } - - if( RC_BAD( rc)) - { - closeStream(); - } - - return( rc); -} -#endif - -/**************************************************************************** -Desc: -****************************************************************************/ -#ifdef FLM_OPENSSL -RCODE FLMAPI F_SSLIOStream::read( - void * pvBuffer, - FLMUINT uiBytesToRead, - FLMUINT * puiBytesRead) -{ - RCODE rc = NE_FLM_OK; - int iBytesRead; - FLMUINT uiTotalBytesRead = 0; - char * pucBuffer = (char *)pvBuffer; - - while( uiBytesToRead) - { - if( (iBytesRead = BIO_read( m_pBio, &pucBuffer[ uiTotalBytesRead], - uiBytesToRead)) <= 0) - { - if( !BIO_should_retry( m_pBio)) - { - rc = RC_SET( NE_FLM_EOF_HIT); - goto Exit; - } - - continue; - } - - uiTotalBytesRead += iBytesRead; - uiBytesToRead -= iBytesRead; - } - -Exit: - - if( puiBytesRead) - { - *puiBytesRead = uiTotalBytesRead; - } - - return( rc); -} -#endif - -/**************************************************************************** -Desc: -****************************************************************************/ -#ifdef FLM_OPENSSL -RCODE FLMAPI F_SSLIOStream::write( - const void * pvBuffer, - FLMUINT uiBytesToWrite, - FLMUINT * puiBytesWritten) -{ - RCODE rc = NE_FLM_OK; - int iBytesWritten = 0; - - if( !uiBytesToWrite) - { - goto Exit; - } - - if( (iBytesWritten = BIO_write( m_pBio, pvBuffer, uiBytesToWrite)) <= 0) - { - iBytesWritten = 0; - rc = RC_SET( NE_FLM_SOCKET_WRITE_FAIL); - goto Exit; - } - -Exit: - - if( puiBytesWritten) - { - *puiBytesWritten = (FLMUINT)iBytesWritten; - } - - return( rc); -} -#endif - -/**************************************************************************** -Desc: -****************************************************************************/ -#ifdef FLM_OPENSSL -RCODE FLMAPI F_SSLIOStream::closeStream( void) -{ - if( m_pBio) - { - BIO_free_all( m_pBio); - m_pBio = NULL; - m_pSSL = NULL; - } - - if( m_pPeerCertificate) - { - X509_free( m_pPeerCertificate); - m_pPeerCertificate = NULL; - } - - if( m_pszPeerCertText) - { - f_free( &m_pszPeerCertText); - } - - if( m_pContext) - { - SSL_CTX_free( m_pContext); - m_pContext = NULL; - } - - m_szPeerName[ 0] = 0; - - return( NE_FLM_OK); -} -#endif - -/****************************************************************************** -Desc: -******************************************************************************/ -#ifdef FLM_OPENSSL -const char * FLMAPI F_SSLIOStream::getPeerCertificateText( void) -{ - return( m_pszPeerCertText); -} -#endif - /****************************************************************************** Desc: Read all data from input stream and write to the output stream. ******************************************************************************/