//------------------------------------------------------------------------- // Desc: FLAIM C/S client interface // Tabs: 3 // // Copyright (c) 1998-2006 Novell, Inc. All Rights Reserved. // // This program is free software; you can redistribute it and/or // modify it under the terms of version 2 of the GNU General Public // License as published by the Free Software Foundation. // // 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 program; 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: fcs_bios.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ //------------------------------------------------------------------------- // These must be defined BEFORE any includes. Unfortunately, this // also means that we can't use our FLM_HPUX define because it hasn't // been set yet... #if defined( __hpux) || defined( hpux) #define _XOPEN_SOURCE_EXTENDED 1 #define _INCLUDE_HPUX_SOURCE #endif #include "flaimsys.h" #if defined( FLM_NLM) && !defined ( __MWERKS__) // Disable errors for "expression for 'while' is always false" // Needed for FD_SET macro #pragma warning 555 9 #endif #ifdef FLM_WIN // conditional expression is constant (from FD_SET()) #pragma warning( disable : 4127) #endif FSTATIC FLMBOOL flmGetNextHexPacketSlot( FLMBYTE * pucUsedMap, FLMUINT uiMapSize, f_randomGenerator * pRandGen, FLMUINT * puiSlot); FSTATIC RCODE flmGetNextHexPacketBytes( FLMBYTE * pucUsedMap, FLMUINT uiMapSize, FLMBYTE * pucPacket, f_randomGenerator * pRandGen, FLMBYTE * pucBuf, FLMUINT uiCount); /**************************************************************************** Desc: *****************************************************************************/ FCS_BIOS::FCS_BIOS( void) { GedPoolInit( &m_pool, (FCS_BIOS_BLOCK_SIZE + sizeof( FCSBIOSBLOCK)) * 2); m_bMessageActive = FALSE; m_pRootBlock = NULL; m_pCurrWriteBlock = NULL; m_pCurrReadBlock = NULL; m_bAcceptingData = FALSE; m_pEventHook = NULL; m_pvUserData = 0; } /**************************************************************************** Desc: *****************************************************************************/ FCS_BIOS::~FCS_BIOS() { GedPoolFree( &m_pool); } /**************************************************************************** Desc: Clears all pending data *****************************************************************************/ RCODE FCS_BIOS::reset( void) { return( close()); } /**************************************************************************** Desc: Flushes any pending data and closes the stream. *****************************************************************************/ RCODE FCS_BIOS::close( void) { RCODE rc = FERR_OK; GedPoolReset( &m_pool, NULL); m_bMessageActive = FALSE; m_pRootBlock = NULL; m_pCurrWriteBlock = NULL; m_pCurrReadBlock = NULL; m_bAcceptingData = FALSE; return( rc); } /**************************************************************************** Desc: Writes the requested amount of data to the stream. *****************************************************************************/ RCODE FCS_BIOS::write( FLMBYTE * pucData, FLMUINT uiLength) { FLMUINT uiCopySize; FLMUINT uiDataPos = 0; FCSBIOSBLOCK * pPrevBlock = NULL; RCODE rc = FERR_OK; if( !m_bAcceptingData) { GedPoolReset( &m_pool, NULL); m_pCurrWriteBlock = NULL; m_pCurrReadBlock = NULL; m_pRootBlock = NULL; m_bAcceptingData = TRUE; } while( uiLength) { if( !m_pCurrWriteBlock || m_pCurrWriteBlock->uiCurrWriteOffset == FCS_BIOS_BLOCK_SIZE) { pPrevBlock = m_pCurrWriteBlock; m_pCurrWriteBlock = (FCSBIOSBLOCK *)GedPoolCalloc( &m_pool, sizeof( FCSBIOSBLOCK)); if( !m_pCurrWriteBlock) { rc = RC_SET( FERR_MEM); goto Exit; } m_pCurrWriteBlock->pucBlock = (FLMBYTE *)GedPoolAlloc( &m_pool, FCS_BIOS_BLOCK_SIZE); if( !m_pCurrWriteBlock->pucBlock) { rc = RC_SET( FERR_MEM); goto Exit; } if( pPrevBlock) { pPrevBlock->pNextBlock = m_pCurrWriteBlock; } else { m_pRootBlock = m_pCurrWriteBlock; m_pCurrReadBlock = m_pCurrWriteBlock; } } uiCopySize = f_min( uiLength, (FLMUINT)(FCS_BIOS_BLOCK_SIZE - m_pCurrWriteBlock->uiCurrWriteOffset)); flmAssert( uiCopySize != 0); f_memcpy( &(m_pCurrWriteBlock->pucBlock[ m_pCurrWriteBlock->uiCurrWriteOffset]), &(pucData[ uiDataPos]), uiCopySize); m_pCurrWriteBlock->uiCurrWriteOffset += uiCopySize; uiDataPos += uiCopySize; uiLength -= uiCopySize; } Exit: return( rc); } /**************************************************************************** Desc: Terminates the current message *****************************************************************************/ RCODE FCS_BIOS::endMessage( void) { RCODE rc = FERR_OK; if( !m_bAcceptingData) { goto Exit; } if( m_pEventHook) { if( RC_BAD( rc = m_pEventHook( this, FCS_BIOS_EOM_EVENT, m_pvUserData))) { goto Exit; } } Exit: m_bAcceptingData = FALSE; return( rc); } /**************************************************************************** Desc: Reads the requested amount of data from the stream. *****************************************************************************/ RCODE FCS_BIOS::read( FLMBYTE * pucData, FLMUINT uiLength, FLMUINT * puiBytesRead) { FLMUINT uiCopySize; FLMUINT uiDataPos = 0; RCODE rc = FERR_OK; if( puiBytesRead) { *puiBytesRead = 0; } if( m_bAcceptingData) { m_bAcceptingData = FALSE; } while( uiLength) { if( m_pCurrReadBlock && m_pCurrReadBlock->uiCurrReadOffset == m_pCurrReadBlock->uiCurrWriteOffset) { m_pCurrReadBlock = m_pCurrReadBlock->pNextBlock; } if( !m_pCurrReadBlock) { GedPoolReset( &m_pool, NULL); rc = RC_SET( FERR_EOF_HIT); goto Exit; } uiCopySize = f_min( uiLength, m_pCurrReadBlock->uiCurrWriteOffset - m_pCurrReadBlock->uiCurrReadOffset); f_memcpy( &(pucData[ uiDataPos]), &(m_pCurrReadBlock->pucBlock[ m_pCurrReadBlock->uiCurrReadOffset]), uiCopySize); m_pCurrReadBlock->uiCurrReadOffset += uiCopySize; uiDataPos += uiCopySize; if( puiBytesRead) { (*puiBytesRead) += uiCopySize; } uiLength -= uiCopySize; } Exit: return( rc); } /**************************************************************************** Desc: *****************************************************************************/ FLMBOOL FCS_BIOS::isDataAvailable( void) { if( m_bAcceptingData) { if( m_pRootBlock && m_pRootBlock->uiCurrWriteOffset) { return( TRUE); } } else if( m_pCurrReadBlock && ((m_pCurrReadBlock->uiCurrReadOffset < m_pCurrReadBlock->uiCurrWriteOffset) || (m_pCurrReadBlock->pNextBlock))) { return( TRUE); } return( FALSE); } /**************************************************************************** Desc: Returns the amount of data available for reading *****************************************************************************/ FLMUINT FCS_BIOS::getAvailable( void) { FLMUINT uiAvail = 0; FCSBIOSBLOCK * pBlk; if( m_bAcceptingData) { if( m_pRootBlock && m_pRootBlock->uiCurrWriteOffset) { pBlk = m_pRootBlock; while( pBlk) { uiAvail += pBlk->uiCurrWriteOffset; pBlk = pBlk->pNextBlock; } } } else if( m_pCurrReadBlock && ((m_pCurrReadBlock->uiCurrReadOffset < m_pCurrReadBlock->uiCurrWriteOffset) || (m_pCurrReadBlock->pNextBlock))) { pBlk = m_pCurrReadBlock; while( pBlk) { uiAvail += (pBlk->uiCurrWriteOffset - pBlk->uiCurrReadOffset); pBlk = pBlk->pNextBlock; } } return( uiAvail); } /**************************************************************************** Desc: ****************************************************************************/ FCS_DIS::FCS_DIS( void) { m_pIStream = NULL; m_uiBOffset = m_uiBDataSize = 0; m_bSetupCalled = FALSE; } /**************************************************************************** Desc: ****************************************************************************/ FCS_DIS::~FCS_DIS( void) { if( m_bSetupCalled) { (void)close(); } } /**************************************************************************** Desc: ****************************************************************************/ RCODE FCS_DIS::setup( FCS_ISTM * pIStream) { m_pIStream = pIStream; m_bSetupCalled = TRUE; return( FERR_OK); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FCS_DIS::readByte( FLMBYTE * pValue) { return( read( pValue, 1, NULL)); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FCS_DIS::readShort( FLMINT16 * pValue) { RCODE rc; if( RC_OK( rc = read( (FLMBYTE *)pValue, 2, NULL))) { *pValue = flmBigEndianToINT16( (FLMBYTE *)pValue); } return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FCS_DIS::readUShort( FLMUINT16 * pValue) { RCODE rc; if( RC_OK( rc = read( (FLMBYTE *)pValue, 2, NULL))) { *pValue = flmBigEndianToUINT16( (FLMBYTE *)pValue); } return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FCS_DIS::readInt( FLMINT32 * pValue) { RCODE rc; if( RC_OK( rc = read( (FLMBYTE *)pValue, 4, NULL))) { *pValue = flmBigEndianToINT32( (FLMBYTE *)pValue); } return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FCS_DIS::readUInt( FLMUINT32 * pValue) { RCODE rc; if( RC_OK( rc = read( (FLMBYTE *)pValue, 4, NULL))) { *pValue = flmBigEndianToUINT32( (FLMBYTE *)pValue); } return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FCS_DIS::readInt64( FLMINT64 * pValue) { RCODE rc; if( RC_OK( rc = read( (FLMBYTE *)pValue, 8, NULL))) { *pValue = flmBigEndianToINT64( (FLMBYTE *)pValue); } return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FCS_DIS::readUInt64( FLMUINT64 * pValue) { RCODE rc; if( RC_OK( rc = read( (FLMBYTE *)pValue, 8, NULL))) { *pValue = flmBigEndianToUINT64( (FLMBYTE *)pValue); } return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE FCS_DIS::skip( FLMUINT uiBytesToSkip) { return( read( NULL, uiBytesToSkip, NULL)); } /**************************************************************************** Desc: Flushes any pending data and closes the DIS ****************************************************************************/ RCODE FCS_DIS::close( void) { RCODE rc = FERR_OK; // Verify that Setup has been called. flmAssert( m_bSetupCalled == TRUE); // Terminate and flush. if( RC_BAD( rc = endMessage())) { goto Exit; } // Reset the member variables. m_pIStream = NULL; Exit: return( rc); } /**************************************************************************** Desc: Returns the state of the stream (open == TRUE, closed == FALSE) ****************************************************************************/ FLMBOOL FCS_DIS::isOpen( void) { // Verify that Setup has been called. flmAssert( m_bSetupCalled == TRUE); if( m_pIStream && m_pIStream->isOpen()) { return( TRUE); } return( FALSE); } /**************************************************************************** Desc: Flushes and terminates the current parent stream message ****************************************************************************/ RCODE FCS_DIS::endMessage( void) { RCODE rc = FERR_OK; // Verify that Setup has been called. flmAssert( m_bSetupCalled == TRUE); if( !m_pIStream) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Flush any pending data. if( RC_BAD( rc = flush())) { goto Exit; } // Terminate the message. if( RC_BAD( rc = m_pIStream->endMessage())) { goto Exit; } Exit: return( rc); } /**************************************************************************** Desc: Flushes any pending data ****************************************************************************/ RCODE FCS_DIS::flush( void) { RCODE rc = FERR_OK; // Verify that Setup has been called. flmAssert( m_bSetupCalled == TRUE); if( !m_pIStream) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Flush the passed-in input stream. if( RC_BAD( rc = m_pIStream->flush())) { goto Exit; } Exit: return( rc); } /**************************************************************************** Desc: Reads the specified number of bytes. ****************************************************************************/ RCODE FCS_DIS::read( FLMBYTE * pucData, FLMUINT uiLength, FLMUINT * puiBytesRead) { FLMUINT uiCopySize; FLMUINT uiReadLen; FLMBYTE * pucPos = NULL; RCODE rc = FERR_OK; // Verify that Setup has been called. flmAssert( m_bSetupCalled == TRUE); if( !m_pIStream) { rc = RC_SET( FERR_FAILURE); goto Exit; } if( puiBytesRead) { *puiBytesRead = uiLength; } pucPos = pucData; while( uiLength) { if( m_uiBOffset == m_uiBDataSize) { m_uiBOffset = m_uiBDataSize = 0; if( RC_BAD( rc = m_pIStream->read( m_pucBuffer, FCS_DIS_BUFFER_SIZE, &uiReadLen))) { if( uiReadLen) { rc = FERR_OK; } else { goto Exit; } } m_uiBDataSize = uiReadLen; } uiCopySize = m_uiBDataSize - m_uiBOffset; if( uiLength < uiCopySize) { uiCopySize = uiLength; } if( pucPos) { #if defined( FLM_NLM) || defined( FLM_WIN) if( uiCopySize == 1) { *pucPos = m_pucBuffer[ m_uiBOffset]; } else if( uiLength == 2) { *(FLMUINT16 *)pucPos = *((FLMUINT16 *)&m_pucBuffer[ m_uiBOffset]); } else if( uiLength == 4) { *(FLMUINT32 *)pucPos = *((FLMUINT32 *)&m_pucBuffer[ m_uiBOffset]); } else { f_memcpy( pucPos, &(m_pucBuffer[ m_uiBOffset]), uiCopySize); } #else f_memcpy( pucPos, &(m_pucBuffer[ m_uiBOffset]), uiCopySize); #endif pucPos += uiCopySize; } m_uiBOffset += uiCopySize; uiLength -= uiCopySize; } Exit: if( RC_OK( rc) && uiLength) { // Unable to satisfy the read request. rc = RC_SET( FERR_EOF_HIT); } if( puiBytesRead) { (*puiBytesRead) -= uiLength; } return( rc); } /**************************************************************************** Desc: Reads a binary token from the stream. The token is tagged with a length. ****************************************************************************/ RCODE FCS_DIS::readBinary( POOL * pPool, FLMBYTE ** ppValue, FLMUINT * puiDataSize) { FLMUINT16 ui16DataSize; RCODE rc = FERR_OK; if( RC_BAD( rc = readUShort( &ui16DataSize))) { goto Exit; } if( pPool) { // If the data size is non-zero, allocate a buffer and // read the entire binary value. if( ui16DataSize) { if( (*ppValue = (FLMBYTE *)GedPoolAlloc( pPool, ui16DataSize)) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } if( RC_BAD( rc = read( *ppValue, ui16DataSize, NULL))) { goto Exit; } } else { *ppValue = NULL; } } else { // The application is not interested in the value. Just skip the // to the end of the value. if( RC_BAD( rc = skip( ui16DataSize))) { goto Exit; } } Exit: if( puiDataSize) { *puiDataSize = ui16DataSize; } return( rc); } /**************************************************************************** Desc: Reads a large binary token from the stream. The token is tagged with a length. ****************************************************************************/ RCODE FCS_DIS::readLargeBinary( POOL * pPool, FLMBYTE ** ppValue, FLMUINT * puiDataSize) { FLMUINT32 ui32DataSize; RCODE rc = FERR_OK; if( RC_BAD( rc = readUInt( &ui32DataSize))) { goto Exit; } if( pPool) { // If the data size is non-zero, allocate a buffer and // read the entire binary value. if( ui32DataSize) { if( (*ppValue = (FLMBYTE *)GedPoolAlloc( pPool, ui32DataSize)) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } if( RC_BAD( rc = read( *ppValue, ui32DataSize, NULL))) { goto Exit; } } else { *ppValue = NULL; } } else { // The application is not interested in the value. Just skip the // to the end of the value. if( RC_BAD( rc = skip( ui32DataSize))) { goto Exit; } } Exit: if( puiDataSize) { *puiDataSize = (FLMUINT)ui32DataSize; } return( rc); } /**************************************************************************** Desc: Reads a UTF-8 string from the stream. ****************************************************************************/ RCODE FCS_DIS::readUTF( POOL * pPool, FLMUNICODE ** ppValue) { FLMBYTE ucByte1; FLMBYTE ucByte2; FLMBYTE ucByte3; FLMBYTE ucLoByte; FLMBYTE ucHiByte; FLMUINT16 ui16UTFLen; FLMUINT uiOffset = 0; RCODE rc = FERR_OK; // Read the data. if( RC_BAD( rc = readUShort( &ui16UTFLen))) { goto Exit; } // Check the size of the UTF string. FLAIM does not support // strings that are larger than 32K characters. if( ui16UTFLen >= 32767) { rc = RC_SET( FERR_MEM); goto Exit; } // Allocate space for the string. if( pPool) { *ppValue = (FLMUNICODE *)GedPoolAlloc( pPool, (FLMUINT)((FLMUINT)sizeof( FLMUNICODE) * (FLMUINT)(ui16UTFLen + 1))); } else if( ppValue) { *ppValue = NULL; } while( ui16UTFLen) { // Read and decode the bytes. if( RC_BAD( rc = read( &ucByte1, 1, NULL))) { goto Exit; } if( (ucByte1 & 0xC0) != 0xC0) { ucHiByte = 0; ucLoByte = ucByte1; } else { if( RC_BAD( rc = read( &ucByte2, 1, NULL))) { goto Exit; } if( (ucByte1 & 0xE0) == 0xE0) { if( RC_BAD( rc = read( &ucByte3, 1, NULL))) { goto Exit; } ucHiByte = (FLMBYTE)(((ucByte1 & 0x0F) << 4) | ((ucByte2 & 0x3C) >> 2)); ucLoByte = (FLMBYTE)(((ucByte2 & 0x03) << 6) | (ucByte3 & 0x3F)); } else { ucHiByte = (FLMBYTE)(((ucByte1 & 0x1C) >> 2)); ucLoByte = (FLMBYTE)(((ucByte1 & 0x03) << 6) | (ucByte2 & 0x3F)); } } if( pPool) { (*ppValue)[ uiOffset] = (FLMUNICODE)(((((FLMUNICODE)(ucHiByte)) << 8) | ((FLMUNICODE)(ucLoByte)))); } uiOffset++; ui16UTFLen--; } if( pPool) { (*ppValue)[ uiOffset] = 0; } Exit: return( rc); } /**************************************************************************** Desc: Reads an Hierarchical Tagged Data record from the stream. ****************************************************************************/ RCODE FCS_DIS::readHTD( POOL * pPool, FLMUINT uiContainer, FLMUINT uiDrn, NODE ** ppNode, FlmRecord ** ppRecord) { FLMBYTE ucType; FLMBYTE ucLevel = 0; FLMBYTE ucPrevLevel = 0; FLMBYTE ucDescriptor; FLMBYTE ucFlags; FLMUINT16 ui16Tag; FLMBOOL bHasValue; FLMBOOL bChild; FLMBOOL bSibling; FLMBOOL bLeftTruncated; FLMBOOL bRightTruncated; NODE * pRoot = NULL; NODE * pNode = NULL; NODE * pPrevNode = NULL; void * pField = NULL; void * pvMark = NULL; RCODE rc = FERR_OK; if( pPool) { pvMark = GedPoolMark( pPool); } for( ;;) { // Reset variables. bChild = FALSE; bSibling = FALSE; // Read the attribute's tag number. if( RC_BAD( rc = readUShort( &ui16Tag))) { goto Exit; } // A tag number of 0 indicates that the end of the HTD data // stream has been reached. if( !ui16Tag) { break; } // Read the attribute's descriptor. if( RC_BAD(rc = read( &ucDescriptor, 1, NULL))) { goto Exit; } // Set the flag indicating whether or not the // attribute has a value. bHasValue = (FLMBOOL)((ucDescriptor & HTD_HAS_VALUE_FLAG) ? (FLMBOOL)TRUE : (FLMBOOL)FALSE); // Set the value type. ucType = (FLMBYTE)((ucDescriptor & HTD_VALUE_TYPE_MASK)); // Get the attribute's level. switch( (ucDescriptor & HTD_LEVEL_MASK) >> HTD_LEVEL_POS) { case HTD_LEVEL_SIBLING: { bSibling = TRUE; ucLevel = ucPrevLevel; break; } case HTD_LEVEL_CHILD: { if( ucLevel < 0xFF) { bChild = TRUE; ucLevel = (FLMBYTE)(ucPrevLevel + 1); } else { rc = RC_SET( FERR_BAD_FIELD_LEVEL); goto Exit; } break; } case HTD_LEVEL_BACK: { if( ucLevel > 0) { ucLevel = (FLMBYTE)(ucPrevLevel - 1); } else { rc = RC_SET( FERR_BAD_FIELD_LEVEL); goto Exit; } break; } case HTD_LEVEL_BACK_X: { FLMBYTE ucLevelsBack; if( RC_BAD(rc = read( &ucLevelsBack, 1, NULL))) { goto Exit; } if( ucPrevLevel >= ucLevelsBack) { ucLevel = (FLMBYTE)(ucPrevLevel - ucLevelsBack); } else { rc = RC_SET( FERR_BAD_FIELD_LEVEL); goto Exit; } break; } } // Allocate the record object if( ppRecord && ucLevel == 0) { if( *ppRecord) { if( (*ppRecord)->isReadOnly() || (*ppRecord)->getRefCount() > 1) { (*ppRecord)->Release(); if( (*ppRecord = f_new FlmRecord) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } } else { // Reuse the existing FlmRecord object. (*ppRecord)->clear(); } } else { if( (*ppRecord = f_new FlmRecord) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } } (*ppRecord)->setContainerID( uiContainer); (*ppRecord)->setID( uiDrn); } // Allocate the attribute. if( pPool && ppNode) { pNode = GedNodeMake( pPool, ui16Tag, &rc); if( RC_BAD( rc)) { goto Exit; } } bLeftTruncated = FALSE; bRightTruncated = FALSE; // Read the attribute's value. switch( ucType) { case HTD_TYPE_UNICODE: { FLMUNICODE * pUTF; if( pNode) { GedValTypeSet( pNode, FLM_TEXT_TYPE); } if( ppRecord) { if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel, ui16Tag, FLM_TEXT_TYPE, &pField))) { goto Exit; } } if( !bHasValue) { break; } // Read UNICODE text in UTF-8 format. if( pPool) { if( RC_BAD( rc = readUTF( pPool, &pUTF))) { goto Exit; } if( pNode) { if( RC_BAD( rc = GedPutUNICODE( pPool, pNode, pUTF))) { goto Exit; } } if( ppRecord) { if( RC_BAD( rc = (*ppRecord)->setUnicode( pField, pUTF))) { goto Exit; } } } else { if( RC_BAD( rc = readUTF( NULL, NULL))) { goto Exit; } } break; } case HTD_TYPE_UINT: { FLMUINT32 ui32Value; if( pNode) { GedValTypeSet( pNode, FLM_NUMBER_TYPE); } if( ppRecord) { if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel, ui16Tag, FLM_NUMBER_TYPE, &pField))) { goto Exit; } } if( !bHasValue) { break; } // Read an unsigned 32-bit integer. if( RC_BAD( rc = readUInt( &ui32Value))) { goto Exit; } if( pNode) { if( RC_BAD( rc = GedPutUINT( pPool, pNode, ui32Value))) { goto Exit; } } if( ppRecord) { if( RC_BAD( rc = (*ppRecord)->setUINT( pField, ui32Value))) { goto Exit; } } break; } case HTD_TYPE_INT: { FLMINT32 i32Value; if( pNode) { GedValTypeSet( pNode, FLM_NUMBER_TYPE); } if( ppRecord) { if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel, ui16Tag, FLM_NUMBER_TYPE, &pField))) { goto Exit; } } if( !bHasValue) { break; } // Read a signed 32-bit integer. if( RC_BAD( rc = readInt( &i32Value))) { goto Exit; } if( pNode) { if( RC_BAD( rc = GedPutINT( pPool, pNode, i32Value))) { goto Exit; } } if( ppRecord) { if( RC_BAD( rc = (*ppRecord)->setINT( pField, i32Value))) { goto Exit; } } break; } case HTD_TYPE_CONTEXT: { FLMUINT32 ui32Value; if( pNode) { GedValTypeSet( pNode, FLM_CONTEXT_TYPE); } if( ppRecord) { if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel, ui16Tag, FLM_CONTEXT_TYPE, &pField))) { goto Exit; } } if( !bHasValue) { break; } // Read an unsigned 32-bit integer. if( RC_BAD( rc = readUInt( &ui32Value))) { goto Exit; } if( pNode) { if( RC_BAD( rc = GedPutRecPtr( pPool, pNode, ui32Value))) { goto Exit; } } if( ppRecord) { if( RC_BAD( rc = (*ppRecord)->setRecPointer( pField, ui32Value))) { goto Exit; } } break; } case HTD_TYPE_BINARY: { FLMUINT16 ui16DataSize; FLMBYTE * pucData = NULL; if( pNode) { GedValTypeSet( pNode, FLM_BINARY_TYPE); } if( ppRecord) { if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel, ui16Tag, FLM_BINARY_TYPE, &pField))) { goto Exit; } } if( !bHasValue) { break; } // Read a binary data stream. if( RC_BAD( rc = readUShort( &ui16DataSize))) { goto Exit; } if( pPool) { if( pNode) { if( (pucData = (FLMBYTE *)GedAllocSpace( pPool, pNode, FLM_BINARY_TYPE, ui16DataSize)) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } } else if( ppRecord) { if( RC_BAD(rc = (*ppRecord)->allocStorageSpace( pField, FLM_BINARY_TYPE, ui16DataSize, 0, 0, 0, &pucData, NULL))) { goto Exit; } } if( RC_BAD( rc = read( pucData, ui16DataSize, NULL))) { goto Exit; } if( pNode) { if( ppRecord) { if( RC_BAD( rc = (*ppRecord)->setBinary( pField, pucData, ui16DataSize))) { goto Exit; } } } } else { if( RC_BAD( rc = skip( ui16DataSize))) { goto Exit; } } break; } case HTD_TYPE_DATE: { rc = RC_SET( FERR_NOT_IMPLEMENTED); goto Exit; } case HTD_TYPE_GEDCOM: { FLMBYTE ucGedType; FLMUINT16 ui16DataSize; FLMBYTE * pucData = NULL; // Read the GEDCOM data type and flags if( RC_BAD( rc = read( &ucGedType, 1, NULL))) { goto Exit; } ucFlags = ucGedType & 0xF0; ucGedType &= 0x0F; if( ucFlags & 0x10) { bLeftTruncated = TRUE; } if( ucFlags & 0x20) { bRightTruncated = TRUE; } if( ucGedType != FLM_TEXT_TYPE && ucGedType != FLM_NUMBER_TYPE && ucGedType != FLM_BINARY_TYPE && ucGedType != FLM_BLOB_TYPE && ucGedType != FLM_CONTEXT_TYPE) { rc = RC_SET( FERR_NOT_IMPLEMENTED); goto Exit; } if( pNode) { GedValTypeSet( pNode, ucGedType); if( bLeftTruncated) { GedSetLeftTruncated( pNode); } if( bRightTruncated) { GedSetRightTruncated( pNode); } } if( ppRecord) { if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel, ui16Tag, ucGedType, &pField))) { goto Exit; } if( bLeftTruncated) { (*ppRecord)->setLeftTruncated( pField, TRUE); } if( bRightTruncated) { (*ppRecord)->setRightTruncated( pField, TRUE); } } if( !bHasValue) { break; } // Read the data size. if( RC_BAD( rc = readUShort( &ui16DataSize))) { goto Exit; } // Read the data value. if( pPool) { if( pNode) { if( (pucData = (FLMBYTE *)GedAllocSpace( pPool, pNode, ucGedType, ui16DataSize)) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } } else if( ppRecord) { if (RC_BAD( rc = (*ppRecord)->allocStorageSpace( pField, ucGedType, ui16DataSize, 0, 0, 0, &pucData, NULL))) { goto Exit; } } if( RC_BAD( rc = read( pucData, ui16DataSize, NULL))) { goto Exit; } if( pNode) { if( ppRecord) { if( RC_BAD( rc = (*ppRecord)->setBinary( pField, pucData, ui16DataSize))) { goto Exit; } } } } else { if( RC_BAD( rc = skip( ui16DataSize))) { goto Exit; } } break; } default: { rc = RC_SET( FERR_NOT_IMPLEMENTED); goto Exit; } } // Set the truncation flags if( ucType != HTD_TYPE_GEDCOM) { if( pNode) { if( bLeftTruncated) { GedSetLeftTruncated( pNode); } if( bRightTruncated) { GedSetRightTruncated( pNode); } } else if( pField) { if( bLeftTruncated) { (*ppRecord)->setLeftTruncated( pField, TRUE); } if( bRightTruncated) { (*ppRecord)->setRightTruncated( pField, TRUE); } } } // Graft the attribute into the tree. if( pNode) { if( pRoot == NULL) { pRoot = pNode; } else { if( bSibling) { pPrevNode->next = pNode; pNode->prior = pPrevNode; GedNodeLevelSet( pNode, GedNodeLevel( pPrevNode)); } else if( bChild) { pPrevNode->next = pNode; pNode->prior = pPrevNode; GedNodeLevelSet( pNode, GedNodeLevel( pPrevNode) + 1); } else { pPrevNode->next = pNode; pNode->prior = pPrevNode; GedNodeLevelSet( pNode, ucLevel); } } } ucPrevLevel = ucLevel; pPrevNode = pNode; // Reset the pool if a GEDCOM record is not going to be returned. if( pPool && !ppNode) { GedPoolReset( pPool, pvMark); } } Exit: if( RC_OK( rc)) { if( ppNode) { *ppNode = pRoot; } } else { if( ppRecord && *ppRecord) { (*ppRecord)->Release(); } } if( pPool && !ppNode) { GedPoolReset( pPool, pvMark); } return( rc); } /**************************************************************************** Desc: ****************************************************************************/ FCS_DOS::FCS_DOS( void) { m_pOStream = NULL; m_uiBOffset = 0; GedPoolInit( &m_tmpPool, 512); m_bSetupCalled = FALSE; } /**************************************************************************** Desc: ****************************************************************************/ FCS_DOS::~FCS_DOS( void) { if( m_bSetupCalled) { (void)close(); } GedPoolFree( &m_tmpPool); } /**************************************************************************** Desc: Writes a specified number of bytes from a buffer to the output stream. ****************************************************************************/ RCODE FCS_DOS::write( FLMBYTE * pucData, FLMUINT uiLength) { RCODE rc = FERR_OK; // Verify that setup has been called. flmAssert( m_bSetupCalled == TRUE); // Write the data. Retry_Write: if( FCS_DOS_BUFFER_SIZE - m_uiBOffset >= uiLength) { #if defined( FLM_NLM) || defined( FLM_WIN) if( uiLength == 1) { m_pucBuffer[ m_uiBOffset] = *pucData; m_uiBOffset++; } else if( uiLength == 2) { *(FLMUINT16 *)&(m_pucBuffer[ m_uiBOffset]) = *((FLMUINT16 *)pucData); m_uiBOffset += 2; } else if( uiLength == 4) { *(FLMUINT32 *)&(m_pucBuffer[ m_uiBOffset]) = *((FLMUINT32 *)pucData); m_uiBOffset += 4; } else { f_memcpy( &(m_pucBuffer[ m_uiBOffset]), pucData, uiLength); m_uiBOffset += uiLength; } #else f_memcpy( &(m_pucBuffer[ m_uiBOffset]), pucData, uiLength); m_uiBOffset += uiLength; #endif } else { if( m_uiBOffset > 0) { if( RC_BAD( rc = flush())) { goto Exit; } } if( uiLength <= FCS_DOS_BUFFER_SIZE) { goto Retry_Write; } if( RC_BAD( rc = m_pOStream->write( pucData, uiLength))) { goto Exit; } } Exit: return( rc); } /**************************************************************************** Desc: Writes a UNICODE string to the stream in the UTF-8 format. ****************************************************************************/ RCODE FCS_DOS::writeUTF( FLMUNICODE * puzValue) { FLMUINT uiUTFLen; FLMUNICODE * puzTmp; RCODE rc = FERR_OK; // Verify that setup has been called. flmAssert( m_bSetupCalled == TRUE); // Verify pValue is valid. flmAssert( puzValue != NULL); // Determine the size of the string. uiUTFLen = 0; puzTmp = puzValue; while( *puzTmp) { uiUTFLen++; puzTmp++; } if( RC_BAD( rc = writeUShort( (FLMUINT16)uiUTFLen))) { goto Exit; } puzTmp = puzValue; while( *puzTmp) { if( *puzTmp <= 0x007F) { if( RC_BAD( rc = writeByte( (FLMBYTE)(*puzTmp)))) { goto Exit; } } else if( *puzTmp >= 0x0080 && *puzTmp <= 0x07FF) { if( RC_BAD( rc = writeUShort((FLMUINT16) ((((FLMUINT16)(0xC0 | (FLMBYTE)((*puzTmp & 0x07C0) >> 6))) << 8) | (FLMUINT16)(0x80 | (FLMBYTE)(*puzTmp & 0x003F)))))) { goto Exit; } } else { if( RC_BAD( rc = writeUShort((FLMUINT16) ((((FLMUINT16)(0xE0 | (FLMBYTE)((*puzTmp & 0xF000) >> 12))) << 8) | (FLMUINT16)(0x80 | (FLMBYTE)((*puzTmp & 0x0FC0) >> 6)))))) { goto Exit; } if( RC_BAD( rc = writeByte( (0x80 | (FLMBYTE)(*puzTmp & 0x003F))))) { goto Exit; } } puzTmp++; } Exit: return( rc); } /**************************************************************************** Desc: Writes a binary token (including length) to the stream. ****************************************************************************/ RCODE FCS_DOS::writeBinary( FLMBYTE * pucValue, FLMUINT uiSize) { RCODE rc = FERR_OK; flmAssert( uiSize <= 0x0000FFFF); if( RC_BAD( rc = writeUShort( (FLMUINT16)uiSize))) { goto Exit; } if( uiSize) { if( RC_BAD( rc = write( pucValue, uiSize))) { goto Exit; } } Exit: return( rc); } /**************************************************************************** Desc: Writes a large binary token (including length) to the stream. ****************************************************************************/ RCODE FCS_DOS::writeLargeBinary( FLMBYTE * pucValue, FLMUINT uiSize) { RCODE rc = FERR_OK; if( RC_BAD( rc = writeUInt32( (FLMUINT32)uiSize))) { goto Exit; } if( uiSize) { if( RC_BAD( rc = write( pucValue, uiSize))) { goto Exit; } } Exit: return( rc); } /**************************************************************************** Desc: Writes a Hierarchical Tagged Data record to the stream. ****************************************************************************/ RCODE FCS_DOS::writeHTD( NODE * pHTD, FlmRecord * pRecord, FLMBOOL bSendForest, FLMBOOL bSendAsGedcom) { FLMUINT uiPrevLevel = 0; FLMUINT uiLevelsBack = 0; FLMUINT uiDescriptor = 0; FLMUINT uiCurLevel = 0; FLMUINT uiCurValType = 0; FLMUINT uiCurDataLen = 0; FLMBOOL bLeftTruncated; FLMBOOL bRightTruncated; FLMBYTE * pucCurData = NULL; FLMBYTE pucTmpBuf[ 32]; void * pvMark = GedPoolMark( &m_tmpPool); NODE * pCurNode = NULL; void * pCurField = NULL; RCODE rc = FERR_OK; // Verify that setup has been called. flmAssert( m_bSetupCalled == TRUE); // Set the current node or field if( pHTD) { pCurNode = pHTD; } else { pCurField = pRecord->root(); } while( pCurNode || pCurField) { // See if we are done sending the tree/forest. if( pCurNode) { if( !bSendForest && (pCurNode != pHTD) && (GedNodeLevel( pCurNode) == GedNodeLevel( pHTD))) { break; } } // Output the attribute's tag number. if( pCurNode) { flmUINT16ToBigEndian( (FLMUINT16)GedTagNum( pCurNode), pucTmpBuf); } else if( pCurField) { flmUINT16ToBigEndian( (FLMUINT16)pRecord->getFieldID( pCurField), pucTmpBuf); } if( RC_BAD( rc = write( pucTmpBuf, 2))) { goto Exit; } // Setup the attribute's descriptor. uiDescriptor = 0; uiLevelsBack = 0; if( pCurNode) { uiCurLevel = GedNodeLevel( pCurNode); } else { uiCurLevel = pRecord->getLevel( pCurField); } if( uiCurLevel == uiPrevLevel) { (void)(uiDescriptor |= (HTD_LEVEL_SIBLING << HTD_LEVEL_POS)); } else if( uiCurLevel == uiPrevLevel + 1) { uiDescriptor |= (HTD_LEVEL_CHILD << HTD_LEVEL_POS); } else if( uiCurLevel == uiPrevLevel - 1) { uiDescriptor |= (HTD_LEVEL_BACK << HTD_LEVEL_POS); } else if( uiCurLevel < uiPrevLevel) { uiDescriptor |= (HTD_LEVEL_BACK_X << HTD_LEVEL_POS); uiLevelsBack = uiPrevLevel - uiCurLevel; } else { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } if( pCurNode) { uiCurDataLen = GedValLen( pCurNode); uiCurValType = GedValType( pCurNode) & 0x0F; bLeftTruncated = GedIsLeftTruncated( pCurNode); bRightTruncated = GedIsRightTruncated( pCurNode); pucCurData = (FLMBYTE *)GedValPtr( pCurNode); } else { uiCurDataLen = pRecord->getDataLength( pCurField); uiCurValType = (FLMUINT)pRecord->getDataType( pCurField); bLeftTruncated = pRecord->isLeftTruncated( pCurField); bRightTruncated = pRecord->isRightTruncated( pCurField); pucCurData = (FLMBYTE *)(pRecord->getDataPtr( pCurField)); } if( uiCurDataLen) { uiDescriptor |= HTD_HAS_VALUE_FLAG; } if( bSendAsGedcom) { uiDescriptor |= HTD_TYPE_GEDCOM; } else { switch( uiCurValType) { case FLM_TEXT_TYPE: { uiDescriptor |= HTD_TYPE_UNICODE; break; } case FLM_NUMBER_TYPE: { // To save conversion time, cheat to determine if // the number is negative. if( ((*pucCurData & 0xF0) == 0xB0)) { uiDescriptor |= HTD_TYPE_INT; } else { uiDescriptor |= HTD_TYPE_UINT; } break; } case FLM_CONTEXT_TYPE: { uiDescriptor |= HTD_TYPE_CONTEXT; break; } case FLM_BINARY_TYPE: { uiDescriptor |= HTD_TYPE_BINARY; break; } default: { rc = RC_SET( FERR_NOT_IMPLEMENTED); goto Exit; } } } // Output the attribute's descriptor. pucTmpBuf[ 0] = (FLMBYTE)uiDescriptor; if( RC_BAD( rc = write( pucTmpBuf, 1))) { goto Exit; } // Output the "levels back" value (if available). if( uiLevelsBack) { flmAssert( uiLevelsBack <= 0xFF); pucTmpBuf[ 0] = (FLMBYTE)uiLevelsBack; if( RC_BAD( rc = write( pucTmpBuf, 1))) { goto Exit; } } // Output the attribute's value. if( bSendAsGedcom) { // Output the GEDCOM data type and flags pucTmpBuf[ 0] = (FLMBYTE)uiCurValType; if( bLeftTruncated) { pucTmpBuf[ 0] |= 0x10; } if( bRightTruncated) { pucTmpBuf[ 0] |= 0x20; } if( RC_BAD( rc = write( pucTmpBuf, 1))) { goto Exit; } if( uiCurDataLen) { // Output the data size. flmAssert( uiCurDataLen <= 0x0000FFFF); flmUINT16ToBigEndian( (FLMUINT16)uiCurDataLen, pucTmpBuf); if( RC_BAD( rc = write( pucTmpBuf, 2))) { goto Exit; } // Send the data. if( RC_BAD( rc = write( pucCurData, uiCurDataLen))) { goto Exit; } } } else { // Send the value. switch( uiCurValType) { case FLM_TEXT_TYPE: { // Extract the value. if( uiCurDataLen) { FLMUINT uiBufSize; FLMUNICODE * puzValue; // Reset the temporary pool. GedPoolReset( &m_tmpPool, pvMark); if( uiCurDataLen <= 32751) { // Allocate a buffer that is twice the size of the // attribute's value length. This is necessary because the // UNICODE conversion will may double the size of the // attribute's value. A "safety" zone of 32 bytes is added // to the buffer size to allow for strings that may require // more than 2x the attribute's size and to account for // null-termination bytes. uiBufSize = (2 * uiCurDataLen) + 32; } else { // Allocate a full 64K. uiBufSize = 65535; } if( (puzValue = (FLMUNICODE *)GedPoolAlloc( &m_tmpPool, uiBufSize)) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } // Extract UNICODE from the attribute. if( (pCurNode && RC_BAD( rc = GedGetUNICODE( pCurNode, puzValue, &uiBufSize))) || (pCurField && RC_BAD( rc = pRecord->getUnicode( pCurField, puzValue, &uiBufSize)))) { if( rc == FERR_CONV_DEST_OVERFLOW) { // Since we did not correctly guess the buffer size, // try again. This time, take the slow (but safe) // approach of calculating the size of the UNICODE string. if( (pCurNode && RC_BAD( rc = GedGetUNICODE( pCurNode, NULL, &uiBufSize))) || (pCurField && RC_BAD( rc = pRecord->getUnicodeLength( pCurField, &uiBufSize)))) { goto Exit; } // Add two bytes to account for null-termination. uiBufSize += 2; // Reset the pool to clear the prior allocation. GedPoolReset( &m_tmpPool, pvMark); // Allocate the new buffer. if( (puzValue = (FLMUNICODE *)GedPoolAlloc( &m_tmpPool, uiBufSize)) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } // Extract the UNICODE string. if( (pCurNode && RC_BAD( rc = GedGetUNICODE( pCurNode, puzValue, &uiBufSize))) || (pCurField && RC_BAD( rc = pRecord->getUnicode( pCurField, puzValue, &uiBufSize)))) { goto Exit; } } else { goto Exit; } } // Write the attribute's value. if( RC_BAD( rc = writeUTF( puzValue))) { goto Exit; } } break; } case FLM_NUMBER_TYPE: { if( uiCurDataLen) { if( uiDescriptor & HTD_TYPE_INT) { // Since the number is negative, extract and send it // as a signed 32-bit value. FLMINT iValue; if( (pCurNode && RC_BAD( rc = GedGetINT( pCurNode, &iValue))) || (pCurField && RC_BAD( rc = pRecord->getINT( pCurField, &iValue)))) { goto Exit; } // Write the value. if( RC_BAD( rc = writeInt32( (FLMINT32)iValue))) { goto Exit; } } else { // The number is non-negative FLMUINT uiValue; if( (pCurNode && RC_BAD( rc = GedGetUINT( pCurNode, &uiValue))) || (pCurField && RC_BAD( rc = pRecord->getUINT( pCurField, &uiValue)))) { goto Exit; } // Write the value. if( RC_BAD( rc = writeUInt32( (FLMUINT32)uiValue))) { goto Exit; } } } break; } case FLM_CONTEXT_TYPE: { // Extract the value. if( uiCurDataLen) { // The context node has a DRN value associated with // it. Send the value as an unsigned 32-bit number. FLMUINT uiDrn; if( (pCurNode && RC_BAD( rc = GedGetRecPtr( pCurNode, &uiDrn))) || (pCurField && RC_BAD( rc = pRecord->getUINT( pCurField, &uiDrn)))) { goto Exit; } if( RC_BAD( rc = writeUInt32( (FLMUINT32)uiDrn))) { goto Exit; } } break; } case FLM_BINARY_TYPE: { // Extract the value. if( uiCurDataLen) { if( RC_BAD( rc = writeUShort( (FLMUINT16)uiCurDataLen))) { goto Exit; } if( RC_BAD( rc = write( pucCurData, uiCurDataLen))) { goto Exit; } } break; } default: { rc = RC_SET( FERR_NOT_IMPLEMENTED); goto Exit; } } } uiPrevLevel = uiCurLevel; if( pCurNode) { pCurNode = GedNodeNext( pCurNode); } else { pCurField = pRecord->next( pCurField); } } // Write a zero tag to indicate the end of the transmission. if( RC_BAD( rc = writeUShort( 0))) { goto Exit; } Exit: GedPoolReset( &m_tmpPool, pvMark); return( rc); } /**************************************************************************** Desc: Flushes any pending data and closes the stream. ****************************************************************************/ RCODE FCS_DOS::close( void) { RCODE rc = FERR_OK; // Verify that setup has been called. flmAssert( m_bSetupCalled == TRUE); // Flush and terminate any pending message. if( RC_BAD( rc = endMessage())) { goto Exit; } Exit: return( rc); } /**************************************************************************** Desc: Flushes pending data. ****************************************************************************/ RCODE FCS_DOS::flush( void) { // Verify that setup has been called. flmAssert( m_bSetupCalled == TRUE); // Flush the output buffer. if( m_uiBOffset > 0) { m_pOStream->write( m_pucBuffer, m_uiBOffset); m_uiBOffset = 0; } // Flush the parent stream. return( m_pOStream->flush()); } /**************************************************************************** Desc: Flushes and terminates the current parent stream message ****************************************************************************/ RCODE FCS_DOS::endMessage( void) { RCODE rc = FERR_OK; // Verify that Setup has been called. flmAssert( m_bSetupCalled == TRUE); if( !m_pOStream) { rc = RC_SET( FERR_FAILURE); goto Exit; } // Flush any pending data. if( RC_BAD( rc = flush())) { goto Exit; } // Terminate the message. if( RC_BAD( rc = m_pOStream->endMessage())) { goto Exit; } Exit: return( rc); } /**************************************************************************** Desc: *****************************************************************************/ FCS_FIS::FCS_FIS( void) { m_pFileHdl = NULL; m_pucBufPos = NULL; m_pucBuffer = NULL; m_uiFileOffset = 0; m_uiBlockSize = 0; m_uiBlockEnd = 0; } /**************************************************************************** Desc: *****************************************************************************/ FCS_FIS::~FCS_FIS( void) { if( m_pFileHdl) { m_pFileHdl->Release(); } if( m_pucBuffer) { f_free( &m_pucBuffer); } } /**************************************************************************** Desc: Configures the input stream for use *****************************************************************************/ RCODE FCS_FIS::setup( const char * pszFilePath, FLMUINT uiBlockSize) { RCODE rc = FERR_OK; flmAssert( uiBlockSize); if( RC_BAD( rc = close())) { goto Exit; } if( RC_BAD( rc = gv_FlmSysData.pFileSystem->Open( pszFilePath, F_IO_RDONLY | F_IO_SH_DENYNONE, &m_pFileHdl))) { goto Exit; } m_uiBlockSize = uiBlockSize; if( RC_BAD( rc = f_alloc( m_uiBlockSize, &m_pucBuffer))) { goto Exit; } m_pucBufPos = m_pucBuffer; Exit: return( rc); } /**************************************************************************** Desc: Closes the input stream and frees any resources *****************************************************************************/ RCODE FCS_FIS::close( void) { if( m_pFileHdl) { m_pFileHdl->Close(); m_pFileHdl->Release(); m_pFileHdl = NULL; } if( m_pucBuffer) { f_free( &m_pucBuffer); } return( FERR_OK); } /**************************************************************************** Desc: Reads the requested amount of data from the stream. *****************************************************************************/ RCODE FCS_FIS::read( FLMBYTE * pucData, FLMUINT uiLength, FLMUINT * puiBytesRead) { RCODE rc = FERR_OK; FLMUINT uiBytesRead = 0; FLMUINT uiMaxSize; if( puiBytesRead) { *puiBytesRead = 0; } if( !m_pFileHdl) { rc = RC_SET( FERR_READING_FILE); goto Exit; } while( uiLength) { uiMaxSize = m_uiBlockEnd - (FLMUINT)(m_pucBufPos - m_pucBuffer); if( !uiMaxSize) { if( RC_BAD( rc = getNextPacket())) { goto Exit; } } else if( uiLength <= uiMaxSize) { f_memcpy( pucData, m_pucBufPos, uiLength); m_pucBufPos += uiLength; uiBytesRead += uiLength; uiLength = 0; } else { f_memcpy( pucData, m_pucBufPos, uiMaxSize); m_pucBufPos += uiMaxSize; pucData += uiMaxSize; uiLength -= uiMaxSize; uiBytesRead += uiMaxSize; } } Exit: if( puiBytesRead) { *puiBytesRead = uiBytesRead; } return( rc); } /**************************************************************************** Desc: Flushes any pending data. *****************************************************************************/ RCODE FCS_FIS::flush( void) { return( FERR_OK); } /**************************************************************************** Desc: Flushes any pending data. *****************************************************************************/ RCODE FCS_FIS::endMessage( void) { return( FERR_OK); } /**************************************************************************** Desc: Returns TRUE if the stream is open *****************************************************************************/ FLMBOOL FCS_FIS::isOpen( void) { return( TRUE); } /**************************************************************************** Desc: Reads the next block from the file *****************************************************************************/ RCODE FCS_FIS::getNextPacket( void) { RCODE rc = FERR_OK; if( RC_BAD( rc = m_pFileHdl->Read( m_uiFileOffset, m_uiBlockSize, m_pucBuffer, &m_uiBlockEnd))) { if( rc == FERR_IO_END_OF_FILE) { if( !m_uiBlockEnd) { goto Exit; } else { rc = FERR_OK; } } } m_uiFileOffset += m_uiBlockEnd; m_pucBufPos = m_pucBuffer; Exit: return( rc); } /**************************************************************************** Desc: Constructor *****************************************************************************/ FCS_IPIS::FCS_IPIS( FCS_TCP * pTcpObj) { m_pTcpObj = pTcpObj; m_pucBufPos = m_pucBuffer; m_bStreamInvalid = FALSE; m_bMessageActive = FALSE; m_bGotLastPacket = FALSE; m_uiPacketSize = 0; } /**************************************************************************** Desc: *****************************************************************************/ FCS_IPIS::~FCS_IPIS( void) { (void)close(); } /**************************************************************************** Desc: *****************************************************************************/ FLMBOOL FCS_IPIS::isOpen( void) { return( TRUE); } /**************************************************************************** Desc: *****************************************************************************/ RCODE FCS_IPIS::close( void) { (void)endMessage(); m_bStreamInvalid = FALSE; return( FERR_OK); } /**************************************************************************** Desc: Reads the requested amount of data from the stream. *****************************************************************************/ RCODE FCS_IPIS::read( FLMBYTE * pucData, FLMUINT uiLength, FLMUINT * puiBytesRead) { FLMUINT uiBytesRead = 0; FLMUINT uiMaxSize; RCODE rc = FERR_OK; if( puiBytesRead) { *puiBytesRead = 0; } if( !m_bStreamInvalid) { while( uiLength) { uiMaxSize = m_uiPacketSize - (FLMUINT)(m_pucBufPos - m_pucBuffer); if( !uiMaxSize) { if( RC_BAD( rc = getNextPacket())) { goto Exit; } } else if( uiLength <= uiMaxSize) { f_memcpy( pucData, m_pucBufPos, uiLength); m_pucBufPos += uiLength; uiBytesRead += uiLength; uiLength = 0; } else { f_memcpy( pucData, m_pucBufPos, uiMaxSize); m_pucBufPos += uiMaxSize; pucData += uiMaxSize; uiLength -= uiMaxSize; uiBytesRead += uiMaxSize; } } } else { rc = RC_SET( FERR_READING_FILE); } Exit: if( puiBytesRead) { *puiBytesRead = uiBytesRead; } return( rc); } /**************************************************************************** Desc: Flushes any pending data. *****************************************************************************/ RCODE FCS_IPIS::flush( void) { RCODE rc = FERR_OK; if( !m_bMessageActive) { goto Exit; } for( ;;) { if( RC_BAD( rc = getNextPacket())) { if( rc == FERR_EOF_HIT) { rc = FERR_OK; } goto Exit; } } Exit: m_pucBufPos = m_pucBuffer; return( rc); } /**************************************************************************** Desc: Flushes any pending data. *****************************************************************************/ RCODE FCS_IPIS::endMessage( void) { RCODE rc = FERR_OK; if( !m_bMessageActive) { goto Exit; } if( RC_BAD( rc = flush())) { goto Exit; } Exit: m_bMessageActive = FALSE; m_bGotLastPacket = FALSE; return( rc); } /**************************************************************************** Desc: Reads the next packet off the wire. *****************************************************************************/ RCODE FCS_IPIS::getNextPacket( void) { FLMBYTE pucDescriptor[ 2]; FLMUINT uiDescriptor; FLMUINT uiActualCnt = 0; RCODE rc = FERR_OK; if( !m_bStreamInvalid) { if( !m_bMessageActive) { m_bMessageActive = TRUE; } if( m_bGotLastPacket) { rc = RC_SET( FERR_EOF_HIT); goto Exit; } if( RC_BAD( rc = m_pTcpObj->readAll( pucDescriptor, 2, &uiActualCnt))) { goto Exit; } uiDescriptor = flmBigEndianToUINT16( pucDescriptor); m_uiPacketSize = uiDescriptor & 0x7FFF; if( uiDescriptor & 0x8000) { m_bGotLastPacket = TRUE; } if( m_uiPacketSize > FCS_IPIS_BUFFER_SIZE) { m_uiPacketSize = 0; rc = RC_SET( FERR_READING_FILE); goto Exit; } if( m_uiPacketSize > 0) { if( RC_BAD( rc = m_pTcpObj->readAll( m_pucBuffer, m_uiPacketSize, &uiActualCnt))) { goto Exit; } } else { if( m_bGotLastPacket) { rc = RC_SET( FERR_EOF_HIT); } else { rc = RC_SET( FERR_READING_FILE); } goto Exit; } m_pucBufPos = m_pucBuffer; } else { rc = RC_SET( FERR_READING_FILE); } Exit: if( RC_BAD( rc) && rc != FERR_EOF_HIT) { m_bStreamInvalid = TRUE; } return( rc); } /**************************************************************************** Desc: *****************************************************************************/ FCS_IPOS::FCS_IPOS( FCS_TCP * pTcpObj) { m_pTcpObj = pTcpObj; m_pucBufPos = &(m_pucBuffer[ 2]); m_bOpen = TRUE; m_bMessageActive = FALSE; } /**************************************************************************** Desc: Flushes any pending data and closes the stream. *****************************************************************************/ RCODE FCS_IPOS::close( void) { RCODE rc = FERR_OK; if( m_bOpen) { rc = endMessage(); m_bOpen = FALSE; } return( rc); } /**************************************************************************** Desc: Writes the requested amount of data to the stream. *****************************************************************************/ RCODE FCS_IPOS::write( FLMBYTE * pucData, FLMUINT uiLength) { FLMUINT uiMaxSize; RCODE rc = FERR_OK; if( !uiLength) { goto Exit; } if( m_bOpen) { while( uiLength) { uiMaxSize = (FLMUINT)(FCS_IPOS_BUFFER_SIZE - (m_pucBufPos - m_pucBuffer)); if( !uiMaxSize) { if( RC_BAD( rc = flush())) { goto Exit; } } else if( uiLength <= uiMaxSize) { f_memcpy( m_pucBufPos, pucData, uiLength); m_pucBufPos += uiLength; uiLength = 0; } else { f_memcpy( m_pucBufPos, pucData, uiMaxSize); m_pucBufPos += uiMaxSize; pucData += uiMaxSize; uiLength -= uiMaxSize; if( RC_BAD( rc = flush())) { goto Exit; } } } m_bMessageActive = TRUE; } else { rc = RC_SET( FERR_WRITING_FILE); } Exit: return( rc); } /**************************************************************************** Desc: Flushes any pending data and optionally ends the current message. *****************************************************************************/ RCODE FCS_IPOS::_flush( FLMBOOL bEndMessage) { FLMUINT uiActualCnt; FLMUINT uiLength; FLMUINT uiDescriptor; RCODE rc = FERR_OK; if( (uiLength = (FLMUINT)(m_pucBufPos - m_pucBuffer)) != 0) { uiDescriptor = uiLength - 2; if( bEndMessage) { uiDescriptor |= 0x8000; } if( uiDescriptor) { flmUINT16ToBigEndian( (FLMUINT16)uiDescriptor, m_pucBuffer); if( RC_BAD( rc = m_pTcpObj->write( m_pucBuffer, uiLength, &uiActualCnt))) { goto Exit; } } } Exit: m_pucBufPos = &(m_pucBuffer[ 2]); return( rc); } /**************************************************************************** Desc: Terminates the current message *****************************************************************************/ RCODE FCS_IPOS::endMessage( void) { RCODE rc = FERR_OK; if( !m_bMessageActive) { goto Exit; } if( RC_BAD( rc = _flush( TRUE))) { goto Exit; } Exit: m_bMessageActive = FALSE; return( rc); } /******************************************************************** Desc: Constructor *********************************************************************/ FCS_TCP::FCS_TCP( 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: Destructor *********************************************************************/ FCS_TCP::~FCS_TCP( void ) { if( m_bConnected) { close(); } #ifndef FLM_UNIX if( m_bInitialized) { WSACleanup(); } #endif } /******************************************************************** Desc: Gets information about the local host machine. *********************************************************************/ RCODE FCS_TCP::_GetLocalInfo( void) { struct hostent * pHostEnt; FLMUINT32 ui32IPAddr; RCODE rc = FERR_OK; m_pszIp[ 0] = '\0'; m_pszName[ 0] = '\0'; if( m_pszName[ 0] == '\0') { if( gethostname( m_pszName, (unsigned)sizeof( m_pszName))) { rc = RC_SET( FERR_SVR_SOCK_FAIL); goto Exit; } } if( m_pszIp[ 0] == '\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 FCS_TCP::_GetRemoteInfo( void) { struct sockaddr_in SockAddrIn; char * InetAddr = NULL; struct hostent * HostsName; RCODE rc = FERR_OK; m_pszPeerIp[ 0] = '\0'; m_pszPeerName[ 0] = '\0'; SockAddrIn.sin_addr.s_addr = (unsigned)m_ulRemoteAddr; // inet_ntoa() - converts a 32-bit value in in_addr format into an ASCII // string representing the address in dotted notation. // VISIT: // NetWare: Macro in arpa/inet.h. "Apps with multiple threads should use // NWinet_ntoa instead of inet_ntoa. Then we can get rid of the semaphore! 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. If found, copy IP Host name "BEVIS@NOVELL.COM" to TCPInfo // otherwise, use his IP address as IP name. // VISIT: // Netware: "If your app has multiple threads, use either NWgethostbyaddr // or NetDBgethostbyaddr(). This does the blocking? This may be done // already in netdb.h - it is hard to tell. 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 FCS_TCP::_SocketPeek( FLMINT iTimeoutVal, FLMBOOL bPeekRead) { struct timeval TimeOut; int iMaxDescs; fd_set GenDescriptors; fd_set * DescrRead; fd_set * DescrWrt; RCODE rc = FERR_OK; if( m_iSocket != INVALID_SOCKET) { FD_ZERO( &GenDescriptors ); FD_SET( m_iSocket, &GenDescriptors ); 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( FERR_SVR_SELECT_ERR); goto Exit; } else { if( !FD_ISSET( m_iSocket, &GenDescriptors)) { rc = bPeekRead ? RC_SET( FERR_SVR_READ_TIMEOUT) : RC_SET( FERR_SVR_WRT_TIMEOUT); } } } else { rc = RC_SET( FERR_SVR_CONNECT_FAIL); } Exit: return( rc); } /******************************************************************** Desc: Writes data to the connection. *********************************************************************/ RCODE FCS_TCP::write( FLMBYTE * pucDataBuffer, FLMUINT uiDataCnt, FLMUINT * puiWrtCnt) { FLMUINT uiPartialCnt; FLMUINT uiToWrite; FLMUINT uiHaveWritten = 0; RCODE rc = FERR_OK; if( m_iSocket == INVALID_SOCKET) { rc = RC_SET( FERR_SVR_CONNECT_FAIL); } uiToWrite = uiDataCnt; *puiWrtCnt = 0; while( uiToWrite > 0) { // The internal write call checks the arguments if( RC_BAD( rc = _write( pucDataBuffer, uiToWrite, &uiPartialCnt))) { goto Exit; } pucDataBuffer += uiPartialCnt; uiHaveWritten += uiPartialCnt; uiToWrite = (FLMUINT)(uiDataCnt - uiHaveWritten); *puiWrtCnt = uiHaveWritten; } Exit: return( rc); } /******************************************************************** Desc: *********************************************************************/ RCODE FCS_TCP::_write( FLMBYTE * pucBuffer, FLMUINT uiDataCnt, FLMUINT *puiWrtCnt) { FLMINT iRetryCount = 0; FLMINT iWrtCnt = 0; RCODE rc = FERR_OK; flmAssert( m_iSocket != INVALID_SOCKET && pucBuffer && uiDataCnt); Retry: *puiWrtCnt = 0; if( RC_OK( rc = _SocketPeek( m_uiIOTimeout, FALSE))) { iWrtCnt = send( m_iSocket, (char *)pucBuffer, (int)uiDataCnt, 0 ); switch ( iWrtCnt ) { case -1: { *puiWrtCnt = 0; rc = RC_SET( FERR_SVR_WRT_FAIL); break; } case 0: { rc = RC_SET( FERR_SVR_DISCONNECT); break; } default: { *puiWrtCnt = (FLMUINT)iWrtCnt; break; } } } if( RC_BAD( rc) && rc != FERR_SVR_WRT_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( FERR_SVR_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; } } return( rc); } /******************************************************************** Desc: Reads data from the connection *********************************************************************/ RCODE FCS_TCP::read( FLMBYTE * pucBuffer, FLMUINT uiDataCnt, FLMUINT * puiReadCnt) { FLMINT iReadCnt = 0; RCODE rc = FERR_OK; flmAssert( m_bConnected && pucBuffer && uiDataCnt); if( RC_OK( rc = _SocketPeek( m_uiIOTimeout, TRUE))) { iReadCnt = (FLMINT)recv( m_iSocket, (char *)pucBuffer, (int)uiDataCnt, 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( FERR_SVR_DISCONNECT); } else { rc = RC_SET( FERR_SVR_READ_FAIL); } break; } case 0: { rc = RC_SET( FERR_SVR_DISCONNECT); break; } default: { break; } } } if( puiReadCnt) { *puiReadCnt = (FLMUINT)iReadCnt; } return( rc); } /******************************************************************** Desc: Reads data from the connection - Timeout valkue is zero, no error is generated if timeout occurs. *********************************************************************/ RCODE FCS_TCP::readNoWait( FLMBYTE * pucBuffer, FLMUINT uiDataCnt, FLMUINT * puiReadCnt) { FLMINT iReadCnt = 0; RCODE rc = FERR_OK; flmAssert( m_bConnected && pucBuffer && uiDataCnt); if( puiReadCnt) { *puiReadCnt = 0; } if( RC_OK( rc = _SocketPeek( (FLMUINT)0, TRUE))) { iReadCnt = recv( m_iSocket, (char *)pucBuffer, (int)uiDataCnt, 0); switch ( iReadCnt) { case -1: { *puiReadCnt = 0; #if defined( FLM_WIN) || defined( FLM_NLM) if ( WSAGetLastError() == WSAECONNRESET) #else if( errno == ECONNRESET) #endif { rc = RC_SET( FERR_SVR_DISCONNECT); } else { rc = RC_SET( FERR_SVR_READ_FAIL); } goto Exit; } case 0: { rc = RC_SET( FERR_SVR_DISCONNECT); goto Exit; } default: { break; } } } else if (rc == FERR_SVR_READ_TIMEOUT) { rc = FERR_OK; } if( puiReadCnt) { *puiReadCnt = (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 FCS_TCP::readAll( FLMBYTE * pucBuffer, FLMUINT uiDataCnt, FLMUINT * puiReadCnt) { FLMUINT uiToRead = 0; FLMUINT uiHaveRead = 0; FLMUINT uiPartialCnt; RCODE rc = FERR_OK; flmAssert( m_bConnected && pucBuffer && uiDataCnt); uiToRead = uiDataCnt; while( uiToRead) { if( RC_BAD( rc = read( pucBuffer, uiToRead, &uiPartialCnt))) { goto Exit; } pucBuffer += uiPartialCnt; uiHaveRead += uiPartialCnt; uiToRead = (FLMUINT)(uiDataCnt - uiHaveRead); if( puiReadCnt) { *puiReadCnt = uiHaveRead; } } Exit: return( rc); } /******************************************************************** Desc: Enables or disables Nagle's algorithm *********************************************************************/ RCODE FCS_TCP::setTcpDelay( FLMBOOL bOn) { RCODE rc = FERR_OK; int iOn; if( m_iSocket != INVALID_SOCKET) { iOn = bOn ? 1 : 0; if( (setsockopt( m_iSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&iOn, (unsigned)sizeof( iOn) )) < 0) { rc = RC_SET( FERR_SVR_SOCKOPT_FAIL); goto Exit; } } else { rc = RC_SET( FERR_SVR_ALREADY_CLOSED); } Exit: return( rc); } /******************************************************************** Desc: Closes any open connections *********************************************************************/ void FCS_TCP::close( FLMBOOL bForce) { if( m_iSocket == INVALID_SOCKET) { goto Exit; } #ifdef FLM_NLM F_UNREFERENCED_PARM( bForce); #else if( !bForce) { char ucTmpBuf[ 128]; struct timeval tv; fd_set fds; fd_set fds_read; fd_set fds_err; // Close our half of the connection shutdown( m_iSocket, 1); // Set up to wait for readable data on the socket FD_ZERO( &fds); FD_SET( m_iSocket, &fds); tv.tv_sec = 10; tv.tv_usec = 0; fds_read = fds; fds_err = fds; // Wait for data or an error while( select( m_iSocket + 1, &fds_read, NULL, &fds_err, &tv) > 0) { if( recv( m_iSocket, ucTmpBuf, sizeof( ucTmpBuf), 0) <= 0) { break; } fds_read = fds; fds_err = fds; } shutdown( m_iSocket, 2); } #endif #ifndef FLM_UNIX closesocket( m_iSocket); #else ::close( m_iSocket); #endif Exit: m_iSocket = INVALID_SOCKET; m_bConnected = FALSE; } /******************************************************************** Desc: Creates a client object *********************************************************************/ FCS_TCP_CLIENT::FCS_TCP_CLIENT( void) : FCS_TCP() { m_bConnected = FALSE; } /******************************************************************** Desc: Closes any connections and frees client resources *********************************************************************/ FCS_TCP_CLIENT::~FCS_TCP_CLIENT( void ) { (void)close(); } /******************************************************************** Desc: Opens a new connection *********************************************************************/ RCODE FCS_TCP_CLIENT::openConnection( const char * pucHostName, FLMUINT uiPort, FLMUINT uiConnectTimeout, FLMUINT uiDataTimeout) { FLMINT iSockErr; FLMINT iTries; FLMINT iMaxTries = 5; struct sockaddr_in address; struct hostent * pHostEntry; unsigned long ulIPAddr; RCODE rc = FERR_OK; flmAssert( !m_bConnected); m_iSocket = INVALID_SOCKET; if( pucHostName && pucHostName[ 0] != '\0') { ulIPAddr = inet_addr( (char *)pucHostName); if( ulIPAddr == (unsigned long)INADDR_NONE) { pHostEntry = gethostbyname( (char *)pucHostName); if( !pHostEntry) { rc = RC_SET( FERR_SVR_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( FERR_SVR_SOCK_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 *)&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( FERR_SVR_SOCK_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( FERR_SVR_CONNECT_FAIL); } if( RC_BAD( rc)) { if( m_iSocket != INVALID_SOCKET) { #ifndef FLM_UNIX closesocket( m_iSocket); #else ::close( m_iSocket); #endif m_iSocket = INVALID_SOCKET; } goto Exit; } m_uiIOTimeout = uiDataTimeout; setTcpDelay( TRUE); m_bConnected = TRUE; Exit: return( rc); } /******************************************************************** Desc: Constructor *********************************************************************/ FCS_TCP_SERVER::FCS_TCP_SERVER( void) : FCS_TCP() { m_bBound = FALSE; } /******************************************************************** Desc: Destructor *********************************************************************/ FCS_TCP_SERVER::~FCS_TCP_SERVER( void) { if( m_bBound) { close( TRUE); } } /******************************************************************** Desc: Bind to a port prior to listening for connections *********************************************************************/ RCODE FCS_TCP_SERVER::bind( FLMUINT uiBindPort, FLMBYTE * pucBindAddr) { struct sockaddr_in address; RCODE rc = FERR_OK; if( m_bBound) { rc = RC_SET( FERR_SVR_SOCK_FAIL); goto Exit; } if( (m_iSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) { rc = RC_SET( FERR_SVR_SOCK_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( (unsigned short)uiBindPort); // Bind to the address+port if( ::bind( m_iSocket, (struct sockaddr *)&address, (unsigned)sizeof( address)) != 0) { rc = RC_SET( FERR_SVR_BIND_FAIL); goto Exit; } // Bind succeeded! // 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( FERR_SVR_LISTEN_FAIL); goto Exit; } } // Disable the packet send delay. setTcpDelay( TRUE); m_bBound = TRUE; Exit: if( RC_BAD( rc) && m_iSocket != INVALID_SOCKET) { #ifndef FLM_UNIX closesocket( m_iSocket); #else ::close( m_iSocket); #endif m_iSocket = INVALID_SOCKET; } return( rc); } /******************************************************************** Desc: Wait for and accept a client connection *********************************************************************/ RCODE FCS_TCP_SERVER::connectClient( FCS_TCP * pClient, FLMINT uiConnectTimeout, FLMINT uiDataTimeout) { SOCKET iSocket; #if defined( FLM_UNIX) socklen_t iAddrLen; #else int iAddrLen; #endif struct sockaddr_in address; RCODE rc = FERR_OK; if( !m_bBound) { rc = RC_SET( FERR_SVR_BIND_FAIL); goto Exit; } if( RC_BAD( rc = _SocketPeek( uiConnectTimeout, TRUE))) { goto Exit; } iAddrLen = (int)sizeof( struct sockaddr); if( (iSocket = accept( m_iSocket, (struct sockaddr *)&address, &iAddrLen)) == INVALID_SOCKET) { rc = RC_SET( FERR_SVR_ACCEPT_FAIL); goto Exit; } pClient->m_ulRemoteAddr = address.sin_addr.s_addr; pClient->m_iSocket = iSocket; pClient->m_bConnected = TRUE; pClient->m_uiIOTimeout = uiDataTimeout; pClient->setTcpDelay( TRUE); Exit: return( rc); } /**************************************************************************** Desc: Converts a UNICODE string consisting of 7-bit ASCII characters to a native string. *****************************************************************************/ RCODE fcsConvertUnicodeToNative( POOL * pPool, const FLMUNICODE * puzUnicode, char ** ppucNative) { RCODE rc = FERR_OK; char * pucDest = NULL; FLMUINT uiCount; uiCount = 0; while( puzUnicode[ uiCount]) { if( puzUnicode[ uiCount] > 0x007F) { rc = RC_SET( FERR_CONV_ILLEGAL); goto Exit; } uiCount++; } if( (pucDest = (char *)GedPoolAlloc( pPool, (FLMUINT)(uiCount + 1))) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } uiCount = 0; while( puzUnicode[ uiCount]) { pucDest[ uiCount] = f_tonative( (FLMBYTE)puzUnicode[ uiCount]); uiCount++; } pucDest[ uiCount] = '\0'; Exit: *ppucNative = pucDest; return( rc); } /**************************************************************************** Desc: Converts a native string to a double-byte UNICODE string. *****************************************************************************/ RCODE fcsConvertNativeToUnicode( POOL * pPool, const char * pszNative, FLMUNICODE ** ppuzUnicode) { RCODE rc = FERR_OK; FLMUNICODE * puzDest; FLMUINT uiCount; uiCount = f_strlen( pszNative); if( (puzDest = (FLMUNICODE *)GedPoolAlloc( pPool, (FLMUINT)((FLMUINT)sizeof( FLMUNICODE) * (FLMUINT)(uiCount + 1)))) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } uiCount = 0; while( pszNative[ uiCount]) { puzDest[ uiCount] = (FLMUNICODE)f_toascii( pszNative[ uiCount]); uiCount++; } puzDest[ uiCount] = 0; Exit: *ppuzUnicode = puzDest; return( rc); } /**************************************************************************** Desc: Initializes members of a CREATE_OPTS structure to their default values *****************************************************************************/ void fcsInitCreateOpts( CREATE_OPTS * pCreateOptsRV) { f_memset( pCreateOptsRV, 0, sizeof( CREATE_OPTS)); pCreateOptsRV->uiBlockSize = DEFAULT_BLKSIZ; pCreateOptsRV->uiMinRflFileSize = DEFAULT_MIN_RFL_FILE_SIZE; pCreateOptsRV->uiMaxRflFileSize = DEFAULT_MAX_RFL_FILE_SIZE; pCreateOptsRV->bKeepRflFiles = DEFAULT_KEEP_RFL_FILES_FLAG; pCreateOptsRV->bLogAbortedTransToRfl = DEFAULT_LOG_ABORTED_TRANS_FLAG; pCreateOptsRV->uiDefaultLanguage = DEFAULT_LANG; pCreateOptsRV->uiVersionNum = FLM_CUR_FILE_FORMAT_VER_NUM; } /**************************************************************************** Desc: Converts a CHECKPOINT_INFO structure to an HTD tree *****************************************************************************/ RCODE fcsBuildCheckpointInfo( CHECKPOINT_INFO * pChkptInfo, POOL * pPool, NODE ** ppTree) { NODE * pRootNd = NULL; void * pMark = GedPoolMark( pPool); FLMUINT uiTmp; RCODE rc = FERR_OK; *ppTree = NULL; // Build the root node of the tree. if( (pRootNd = GedNodeMake( pPool, FCS_CPI_CONTEXT, &rc)) == NULL) { goto Exit; } // Add fields to the tree. if( pChkptInfo->bRunning) { uiTmp = 1; if( RC_BAD( rc = gedAddField( pPool, pRootNd, FCS_CPI_RUNNING, (void *)&uiTmp, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pChkptInfo->uiRunningTime) { if( RC_BAD( rc = gedAddField( pPool, pRootNd, FCS_CPI_START_TIME, (void *)&pChkptInfo->uiRunningTime, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pChkptInfo->bForcingCheckpoint) { uiTmp = 1; if( RC_BAD( rc = gedAddField( pPool, pRootNd, FCS_CPI_FORCING_CP, (void *)&uiTmp, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pChkptInfo->uiForceCheckpointRunningTime) { if( RC_BAD( rc = gedAddField( pPool, pRootNd, FCS_CPI_FORCE_CP_START_TIME, (void *)&pChkptInfo->uiForceCheckpointRunningTime, 4, FLM_NUMBER_TYPE))) { goto Exit; } } if( pChkptInfo->iForceCheckpointReason) { uiTmp = pChkptInfo->iForceCheckpointReason; if( RC_BAD( rc = gedAddField( pPool, pRootNd, FCS_CPI_FORCE_CP_REASON, (void *)&uiTmp, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pChkptInfo->bWritingDataBlocks) { uiTmp = 1; if( RC_BAD( rc = gedAddField( pPool, pRootNd, FCS_CPI_WRITING_DATA_BLOCKS, (void *)&uiTmp, 4, FLM_NUMBER_TYPE))) { goto Exit; } } if( pChkptInfo->uiLogBlocksWritten) { if( RC_BAD( rc = gedAddField( pPool, pRootNd, FCS_CPI_LOG_BLOCKS_WRITTEN, (void *)&pChkptInfo->uiLogBlocksWritten, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pChkptInfo->uiDataBlocksWritten) { if( RC_BAD( rc = gedAddField( pPool, pRootNd, FCS_CPI_DATA_BLOCKS_WRITTEN, (void *)&pChkptInfo->uiDataBlocksWritten, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pChkptInfo->uiDirtyCacheBytes) { if( RC_BAD( rc = gedAddField( pPool, pRootNd, FCS_CPI_DIRTY_CACHE_BYTES, (void *)&pChkptInfo->uiDirtyCacheBytes, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pChkptInfo->uiBlockSize) { if( RC_BAD( rc = gedAddField( pPool, pRootNd, FCS_CPI_BLOCK_SIZE, (void *)&pChkptInfo->uiBlockSize, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pChkptInfo->uiWaitTruncateTime) { if( RC_BAD( rc = gedAddField( pPool, pRootNd, FCS_CPI_WAIT_TRUNC_TIME, (void *)&pChkptInfo->uiWaitTruncateTime, 0, FLM_NUMBER_TYPE))) { goto Exit; } } *ppTree = pRootNd; Exit: if( RC_BAD( rc)) { GedPoolReset( pPool, pMark); } return( rc); } /**************************************************************************** Desc: Converts a LOCK_USER structure (or list of structures) to an HTD tree *****************************************************************************/ RCODE fcsBuildLockUser( LOCK_USER * pLockUser, FLMBOOL bList, POOL * pPool, NODE ** ppTree) { NODE * pRootNd = NULL; NODE * pContextNd = NULL; void * pMark = GedPoolMark( pPool); RCODE rc = FERR_OK; *ppTree = NULL; if( !pLockUser) { goto Exit; } // Add fields to the tree. for( ;;) { if( (pContextNd = GedNodeMake( pPool, FCS_LUSR_CONTEXT, &rc)) == NULL) { goto Exit; } if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_LUSR_THREAD_ID, (void *)&pLockUser->uiThreadId, 0, FLM_NUMBER_TYPE))) { goto Exit; } if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_LUSR_TIME, (void *)&pLockUser->uiTime, 0, FLM_NUMBER_TYPE))) { goto Exit; } if( pRootNd == NULL) { pRootNd = pContextNd; } else { GedSibGraft( pRootNd, pContextNd, GED_LAST); } if( !bList) { break; } pLockUser++; if( !pLockUser->uiTime) { break; } } *ppTree = pRootNd; Exit: if( RC_BAD( rc)) { GedPoolReset( pPool, pMark); } return( rc); } /**************************************************************************** Desc: Converts an HTD tree to a LOCK_USER structure (or list of structures) *****************************************************************************/ RCODE fcsExtractLockUser( NODE * pTree, FLMBOOL bExtractAsList, void * pvLockUser) { NODE * pTmpNd; FLMUINT uiItemCount = 0; FLMUINT fieldPath[ 8]; LOCK_USER * pLockUser = NULL; FLMUINT uiLoop; RCODE rc = FERR_OK; if( !pTree) { if( bExtractAsList) { *((LOCK_USER **)pvLockUser) = NULL; } else { f_memset( (LOCK_USER *)pvLockUser, 0, sizeof( LOCK_USER)); } goto Exit; } if( bExtractAsList) { pTmpNd = pTree; while( pTmpNd != NULL) { if( GedTagNum( pTmpNd) == FCS_LUSR_CONTEXT) { uiItemCount++; } pTmpNd = pTmpNd->next; } if( RC_BAD( rc = f_alloc( sizeof( LOCK_USER) * (uiItemCount + 1), &pLockUser))) { goto Exit; } *((LOCK_USER **)pvLockUser) = pLockUser; } else { pLockUser = (LOCK_USER *)pvLockUser; f_memset( pLockUser, 0, sizeof( LOCK_USER)); uiItemCount = 1; } // Parse the tree and extract the values. for( uiLoop = 0; uiLoop < uiItemCount; uiLoop++) { fieldPath[ 0] = FCS_LUSR_CONTEXT; fieldPath[ 1] = FCS_LUSR_THREAD_ID; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pLockUser[ uiLoop].uiThreadId); } fieldPath[ 0] = FCS_LUSR_CONTEXT; fieldPath[ 1] = FCS_LUSR_TIME; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pLockUser[ uiLoop].uiTime); } pTree = GedSibNext( pTree); } if( bExtractAsList) { f_memset( &(pLockUser[ uiItemCount]), 0, sizeof( LOCK_USER)); } Exit: return( rc); } /**************************************************************************** Desc: Extracts a CHECKPOINT_INFO structure from an HTD tree. *****************************************************************************/ RCODE fcsExtractCheckpointInfo( NODE * pTree, CHECKPOINT_INFO * pChkptInfo) { NODE * pTmpNd; FLMUINT fieldPath[ 8]; FLMUINT uiTmp; RCODE rc = FERR_OK; // Initialize the structure f_memset( pChkptInfo, 0, sizeof( CHECKPOINT_INFO)); // Parse the tree and extract the values. fieldPath[ 0] = FCS_CPI_CONTEXT; fieldPath[ 1] = FCS_CPI_RUNNING; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &uiTmp); pChkptInfo->bRunning = uiTmp ? TRUE : FALSE; } fieldPath[ 0] = FCS_CPI_CONTEXT; fieldPath[ 1] = FCS_CPI_START_TIME; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pChkptInfo->uiRunningTime); } fieldPath[ 0] = FCS_CPI_CONTEXT; fieldPath[ 1] = FCS_CPI_FORCING_CP; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &uiTmp); pChkptInfo->bForcingCheckpoint = uiTmp ? TRUE : FALSE; } fieldPath[ 0] = FCS_CPI_CONTEXT; fieldPath[ 1] = FCS_CPI_FORCE_CP_START_TIME; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pChkptInfo->uiForceCheckpointRunningTime); } fieldPath[ 0] = FCS_CPI_CONTEXT; fieldPath[ 1] = FCS_CPI_FORCE_CP_REASON; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetINT( pTmpNd, &pChkptInfo->iForceCheckpointReason); } fieldPath[ 0] = FCS_CPI_CONTEXT; fieldPath[ 1] = FCS_CPI_WRITING_DATA_BLOCKS; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &uiTmp); pChkptInfo->bWritingDataBlocks = uiTmp ? TRUE : FALSE; } fieldPath[ 0] = FCS_CPI_CONTEXT; fieldPath[ 1] = FCS_CPI_LOG_BLOCKS_WRITTEN; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pChkptInfo->uiLogBlocksWritten); } fieldPath[ 0] = FCS_CPI_CONTEXT; fieldPath[ 1] = FCS_CPI_DATA_BLOCKS_WRITTEN; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pChkptInfo->uiDataBlocksWritten); } fieldPath[ 0] = FCS_CPI_CONTEXT; fieldPath[ 1] = FCS_CPI_DIRTY_CACHE_BYTES; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pChkptInfo->uiDirtyCacheBytes); } fieldPath[ 0] = FCS_CPI_CONTEXT; fieldPath[ 1] = FCS_CPI_BLOCK_SIZE; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pChkptInfo->uiBlockSize); } fieldPath[ 0] = FCS_CPI_CONTEXT; fieldPath[ 1] = FCS_CPI_WAIT_TRUNC_TIME; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pChkptInfo->uiWaitTruncateTime); } return( rc); } /**************************************************************************** Desc: Translates a FLAIM query operator to a c/s query operator *****************************************************************************/ RCODE fcsTranslateQFlmToQCSOp( QTYPES eFlmOp, FLMUINT * puiCSOp) { RCODE rc = FERR_OK; switch( eFlmOp) { case FLM_AND_OP: *puiCSOp = FCS_ITERATOR_AND_OP; break; case FLM_OR_OP: *puiCSOp = FCS_ITERATOR_OR_OP; break; case FLM_NOT_OP: *puiCSOp = FCS_ITERATOR_NOT_OP; break; case FLM_EQ_OP: *puiCSOp = FCS_ITERATOR_EQ_OP; break; case FLM_MATCH_OP: *puiCSOp = FCS_ITERATOR_MATCH_OP; break; case FLM_MATCH_BEGIN_OP: *puiCSOp = FCS_ITERATOR_MATCH_BEGIN_OP; break; case FLM_CONTAINS_OP: *puiCSOp = FCS_ITERATOR_CONTAINS_OP; break; case FLM_NE_OP: *puiCSOp = FCS_ITERATOR_NE_OP; break; case FLM_LT_OP: *puiCSOp = FCS_ITERATOR_LT_OP; break; case FLM_LE_OP: *puiCSOp = FCS_ITERATOR_LE_OP; break; case FLM_GT_OP: *puiCSOp = FCS_ITERATOR_GT_OP; break; case FLM_GE_OP: *puiCSOp = FCS_ITERATOR_GE_OP; break; case FLM_BITAND_OP: *puiCSOp = FCS_ITERATOR_BITAND_OP; break; case FLM_BITOR_OP: *puiCSOp = FCS_ITERATOR_BITOR_OP; break; case FLM_BITXOR_OP: *puiCSOp = FCS_ITERATOR_BITXOR_OP; break; case FLM_MULT_OP: *puiCSOp = FCS_ITERATOR_MULT_OP; break; case FLM_DIV_OP: *puiCSOp = FCS_ITERATOR_DIV_OP; break; case FLM_MOD_OP: *puiCSOp = FCS_ITERATOR_MOD_OP; break; case FLM_PLUS_OP: *puiCSOp = FCS_ITERATOR_PLUS_OP; break; case FLM_MINUS_OP: *puiCSOp = FCS_ITERATOR_MINUS_OP; break; case FLM_NEG_OP: *puiCSOp = FCS_ITERATOR_NEG_OP; break; case FLM_LPAREN_OP: *puiCSOp = FCS_ITERATOR_LPAREN_OP; break; case FLM_RPAREN_OP: *puiCSOp = FCS_ITERATOR_RPAREN_OP; break; default: rc = RC_SET( FERR_NOT_IMPLEMENTED); break; } return( rc); } /**************************************************************************** Desc: Translates a FLAIM query operator to a c/s query operator *****************************************************************************/ RCODE fcsTranslateQCSToQFlmOp( FLMUINT uiCSOp, QTYPES * peFlmOp) { RCODE rc = FERR_OK; switch( uiCSOp) { case FCS_ITERATOR_AND_OP: *peFlmOp = FLM_AND_OP; break; case FCS_ITERATOR_OR_OP: *peFlmOp = FLM_OR_OP; break; case FCS_ITERATOR_NOT_OP: *peFlmOp = FLM_NOT_OP; break; case FCS_ITERATOR_EQ_OP: *peFlmOp = FLM_EQ_OP; break; case FCS_ITERATOR_MATCH_OP: *peFlmOp = FLM_MATCH_OP; break; case FCS_ITERATOR_MATCH_BEGIN_OP: *peFlmOp = FLM_MATCH_BEGIN_OP; break; case FCS_ITERATOR_CONTAINS_OP: *peFlmOp = FLM_CONTAINS_OP; break; case FCS_ITERATOR_NE_OP: *peFlmOp = FLM_NE_OP; break; case FCS_ITERATOR_LT_OP: *peFlmOp = FLM_LT_OP; break; case FCS_ITERATOR_LE_OP: *peFlmOp = FLM_LE_OP; break; case FCS_ITERATOR_GT_OP: *peFlmOp = FLM_GT_OP; break; case FCS_ITERATOR_GE_OP: *peFlmOp = FLM_GE_OP; break; case FCS_ITERATOR_BITAND_OP: *peFlmOp = FLM_BITAND_OP; break; case FCS_ITERATOR_BITOR_OP: *peFlmOp = FLM_BITOR_OP; break; case FCS_ITERATOR_BITXOR_OP: *peFlmOp = FLM_BITXOR_OP; break; case FCS_ITERATOR_MULT_OP: *peFlmOp = FLM_MULT_OP; break; case FCS_ITERATOR_DIV_OP: *peFlmOp = FLM_DIV_OP; break; case FCS_ITERATOR_MOD_OP: *peFlmOp = FLM_MOD_OP; break; case FCS_ITERATOR_PLUS_OP: *peFlmOp = FLM_PLUS_OP; break; case FCS_ITERATOR_MINUS_OP: *peFlmOp = FLM_MINUS_OP; break; case FCS_ITERATOR_NEG_OP: *peFlmOp = FLM_NEG_OP; break; case FCS_ITERATOR_LPAREN_OP: *peFlmOp = FLM_LPAREN_OP; break; case FCS_ITERATOR_RPAREN_OP: *peFlmOp = FLM_RPAREN_OP; break; default: rc = RC_SET( FERR_NOT_IMPLEMENTED); break; } return( rc); } /**************************************************************************** Desc: Converts an FINDEX_STATUS structure to an HTD tree *****************************************************************************/ RCODE fcsBuildIndexStatus( FINDEX_STATUS * pIndexStatus, POOL * pPool, NODE ** ppTree) { NODE * pContextNd = NULL; void * pMark = GedPoolMark( pPool); FLMUINT uiTmp; RCODE rc = FERR_OK; *ppTree = NULL; if( !pIndexStatus) { goto Exit; } // Add fields to the tree. if( (pContextNd = GedNodeMake( pPool, FCS_IXSTAT_CONTEXT, &rc)) == NULL) { goto Exit; } if( pIndexStatus->uiIndexNum) { if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_IXSTAT_INDEX_NUM, (void *)&pIndexStatus->uiIndexNum, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pIndexStatus->uiStartTime) { if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_IXSTAT_START_TIME, (void *)&pIndexStatus->uiStartTime, 0, FLM_NUMBER_TYPE))) { goto Exit; } // Send the "auto-online" flag for backwards compatibility uiTmp = 1; if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_IXSTAT_AUTO_ONLINE, (void *)&uiTmp, 0, FLM_NUMBER_TYPE))) { goto Exit; } // Send the priority (high) for backwards compatibility uiTmp = 1; if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_IXSTAT_PRIORITY, (void *)&uiTmp, 0, FLM_NUMBER_TYPE))) { goto Exit; } } // Set the suspended time field (for backwards compatibility) // if the index is suspended if( pIndexStatus->bSuspended) { f_timeGetSeconds( &uiTmp); if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_IXSTAT_SUSPEND_TIME, (void *)&uiTmp, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pIndexStatus->uiLastRecordIdIndexed) { if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_IXSTAT_LAST_REC_INDEXED, (void *)&pIndexStatus->uiLastRecordIdIndexed, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pIndexStatus->uiKeysProcessed) { if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_IXSTAT_KEYS_PROCESSED, (void *)&pIndexStatus->uiKeysProcessed, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pIndexStatus->uiRecordsProcessed) { if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_IXSTAT_RECS_PROCESSED, (void *)&pIndexStatus->uiRecordsProcessed, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pIndexStatus->bSuspended) { uiTmp = (FLMUINT)pIndexStatus->bSuspended; if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_IXSTAT_STATE, (void *)&uiTmp, 0, FLM_NUMBER_TYPE))) { goto Exit; } } *ppTree = pContextNd; Exit: if( RC_BAD( rc)) { GedPoolReset( pPool, pMark); } return( rc); } /**************************************************************************** Desc: Extracts an FINDEX_STATUS structure from an HTD tree. *****************************************************************************/ RCODE fcsExtractIndexStatus( NODE * pTree, FINDEX_STATUS * pIndexStatus) { NODE * pTmpNd; FLMUINT fieldPath[ 8]; RCODE rc = FERR_OK; // Initialize the structure f_memset( pIndexStatus, 0, sizeof( FINDEX_STATUS)); // Make sure pTree is non-null if( !pTree) { goto Exit; } // Parse the tree and extract the values. fieldPath[ 0] = FCS_IXSTAT_CONTEXT; fieldPath[ 1] = FCS_IXSTAT_INDEX_NUM; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pIndexStatus->uiIndexNum); } fieldPath[ 1] = FCS_IXSTAT_START_TIME; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pIndexStatus->uiStartTime); } fieldPath[ 1] = FCS_IXSTAT_LAST_REC_INDEXED; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pIndexStatus->uiLastRecordIdIndexed); } fieldPath[ 1] = FCS_IXSTAT_KEYS_PROCESSED; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pIndexStatus->uiKeysProcessed); } fieldPath[ 1] = FCS_IXSTAT_RECS_PROCESSED; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pIndexStatus->uiRecordsProcessed); } fieldPath[ 1] = FCS_IXSTAT_STATE; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { FLMUINT uiTmp; (void)GedGetUINT( pTmpNd, &uiTmp); pIndexStatus->bSuspended = uiTmp ? TRUE : FALSE; } Exit: return( rc); } /**************************************************************************** Desc: Converts an FLM_MEM_INFO structure to an HTD tree *****************************************************************************/ RCODE fcsBuildMemInfo( FLM_MEM_INFO * pMemInfo, POOL * pPool, NODE ** ppTree) { FLMUINT uiTmp; NODE * pContextNd = NULL; NODE * pSubContext = NULL; void * pMark = GedPoolMark( pPool); FLM_CACHE_USAGE * pUsage; RCODE rc = FERR_OK; *ppTree = NULL; if( !pMemInfo) { goto Exit; } // Add fields to the tree. if( (pContextNd = GedNodeMake( pPool, FCS_MEMINFO_CONTEXT, &rc)) == NULL) { goto Exit; } if( pMemInfo->bDynamicCacheAdjust) { uiTmp = 1; if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_MEMINFO_DYNA_CACHE_ADJ, (void *)&uiTmp, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pMemInfo->uiCacheAdjustPercent) { if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_MEMINFO_CACHE_ADJ_PERCENT, (void *)&pMemInfo->uiCacheAdjustPercent, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pMemInfo->uiCacheAdjustMin) { if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_MEMINFO_CACHE_ADJ_MIN, (void *)&pMemInfo->uiCacheAdjustMin, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pMemInfo->uiCacheAdjustMax) { if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_MEMINFO_CACHE_ADJ_MAX, (void *)&pMemInfo->uiCacheAdjustMax, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pMemInfo->uiCacheAdjustMinToLeave) { if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_MEMINFO_CACHE_ADJ_MIN_LEAVE, (void *)&pMemInfo->uiCacheAdjustMinToLeave, 0, FLM_NUMBER_TYPE))) { goto Exit; } } pUsage = &pMemInfo->RecordCache; if( (pSubContext = GedNodeMake( pPool, FCS_MEMINFO_RECORD_CACHE, &rc)) == NULL) { goto Exit; } add_usage: if( pUsage->uiMaxBytes) { if( RC_BAD( rc = gedAddField( pPool, pSubContext, FCS_MEMINFO_MAX_BYTES, (void *)&pUsage->uiMaxBytes, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pUsage->uiCount) { if( RC_BAD( rc = gedAddField( pPool, pSubContext, FCS_MEMINFO_COUNT, (void *)&pUsage->uiCount, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pUsage->uiOldVerCount) { if( RC_BAD( rc = gedAddField( pPool, pSubContext, FCS_MEMINFO_OLD_VER_COUNT, (void *)&pUsage->uiOldVerCount, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pUsage->uiTotalBytesAllocated) { if( RC_BAD( rc = gedAddField( pPool, pSubContext, FCS_MEMINFO_TOTAL_BYTES_ALLOC, (void *)&pUsage->uiTotalBytesAllocated, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pUsage->uiOldVerBytes) { if( RC_BAD( rc = gedAddField( pPool, pSubContext, FCS_MEMINFO_OLD_VER_BYTES, (void *)&pUsage->uiOldVerBytes, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pUsage->uiCacheHits) { if( RC_BAD( rc = gedAddField( pPool, pSubContext, FCS_MEMINFO_CACHE_HITS, (void *)&pUsage->uiCacheHits, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pUsage->uiCacheHitLooks) { if( RC_BAD( rc = gedAddField( pPool, pSubContext, FCS_MEMINFO_CACHE_HIT_LOOKS, (void *)&pUsage->uiCacheHitLooks, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pUsage->uiCacheFaults) { if( RC_BAD( rc = gedAddField( pPool, pSubContext, FCS_MEMINFO_CACHE_FAULTS, (void *)&pUsage->uiCacheFaults, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pUsage->uiCacheFaultLooks) { if( RC_BAD( rc = gedAddField( pPool, pSubContext, FCS_MEMINFO_CACHE_FAULT_LOOKS, (void *)&pUsage->uiCacheFaultLooks, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( GedChild( pSubContext)) { GedChildGraft( pContextNd, pSubContext, GED_LAST); } if( pUsage != &pMemInfo->BlockCache) { pUsage = &pMemInfo->BlockCache; if( (pSubContext = GedNodeMake( pPool, FCS_MEMINFO_BLOCK_CACHE, &rc)) == NULL) { goto Exit; } goto add_usage; } *ppTree = pContextNd; Exit: if( RC_BAD( rc)) { GedPoolReset( pPool, pMark); } return( rc); } /**************************************************************************** Desc: Extracts a FLM_MEM_INFO structure from an HTD tree. *****************************************************************************/ RCODE fcsExtractMemInfo( NODE * pTree, FLM_MEM_INFO * pMemInfo) { NODE * pTmpNd; FLMUINT fieldPath[ 8]; FLMUINT uiTmp; FLM_CACHE_USAGE * pUsage; FLMUINT uiUsageTag; RCODE rc = FERR_OK; // Initialize the structure f_memset( pMemInfo, 0, sizeof( FLM_MEM_INFO)); // Make sure pTree is non-null if( !pTree) { goto Exit; } // Parse the tree and extract the values. fieldPath[ 0] = FCS_MEMINFO_CONTEXT; fieldPath[ 1] = FCS_MEMINFO_DYNA_CACHE_ADJ; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &uiTmp); pMemInfo->bDynamicCacheAdjust = (FLMBOOL)(uiTmp ? TRUE : FALSE); } fieldPath[ 1] = FCS_MEMINFO_CACHE_ADJ_PERCENT; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pMemInfo->uiCacheAdjustPercent); } fieldPath[ 1] = FCS_MEMINFO_CACHE_ADJ_MIN; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pMemInfo->uiCacheAdjustMin); } fieldPath[ 1] = FCS_MEMINFO_CACHE_ADJ_MAX; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pMemInfo->uiCacheAdjustMax); } fieldPath[ 1] = FCS_MEMINFO_CACHE_ADJ_MIN_LEAVE; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pMemInfo->uiCacheAdjustMinToLeave); } pUsage = &pMemInfo->RecordCache; uiUsageTag = FCS_MEMINFO_RECORD_CACHE; get_usage: fieldPath[ 0] = FCS_MEMINFO_CONTEXT; fieldPath[ 1] = uiUsageTag; fieldPath[ 2] = FCS_MEMINFO_MAX_BYTES; fieldPath[ 3] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pUsage->uiMaxBytes); } fieldPath[ 2] = FCS_MEMINFO_COUNT; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pUsage->uiCount); } fieldPath[ 2] = FCS_MEMINFO_OLD_VER_COUNT; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pUsage->uiOldVerCount); } fieldPath[ 2] = FCS_MEMINFO_TOTAL_BYTES_ALLOC; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pUsage->uiTotalBytesAllocated); } fieldPath[ 2] = FCS_MEMINFO_OLD_VER_BYTES; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pUsage->uiOldVerBytes); } fieldPath[ 2] = FCS_MEMINFO_CACHE_HITS; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pUsage->uiCacheHits); } fieldPath[ 2] = FCS_MEMINFO_CACHE_HIT_LOOKS; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pUsage->uiCacheHitLooks); } fieldPath[ 2] = FCS_MEMINFO_CACHE_FAULTS; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pUsage->uiCacheFaults); } fieldPath[ 2] = FCS_MEMINFO_CACHE_FAULT_LOOKS; if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pUsage->uiCacheFaultLooks); } if( pUsage != &pMemInfo->BlockCache) { pUsage = &pMemInfo->BlockCache; uiUsageTag = FCS_MEMINFO_BLOCK_CACHE; goto get_usage; } Exit: return( rc); } /**************************************************************************** Desc: Builds a GEDCOM tree containing information on all FLAIM threads *****************************************************************************/ RCODE fcsBuildThreadInfo( POOL * pPool, NODE ** ppTree) { NODE * pContextNd = NULL; NODE * pRootNd = NULL; void * pMark = GedPoolMark( pPool); F_THREAD_INFO * pThreadInfo = NULL; FLMUINT uiNumThreads; FLMUINT uiLoop; RCODE rc = FERR_OK; *ppTree = NULL; // Query FLAIM for available threads if( RC_BAD( rc = FlmGetThreadInfo( pPool, &pThreadInfo, &uiNumThreads))) { goto Exit; } if( (pRootNd = GedNodeMake( pPool, FCS_THREAD_INFO_ROOT, &rc)) == NULL) { goto Exit; } if( RC_BAD( rc = GedPutRecPtr( pPool, pRootNd, uiNumThreads))) { goto Exit; } for( uiLoop = 0; uiLoop < uiNumThreads; uiLoop++) { // Add fields to the tree. if( (pContextNd = GedNodeMake( pPool, FCS_THREAD_INFO_CONTEXT, &rc)) == NULL) { goto Exit; } GedChildGraft( pRootNd, pContextNd, GED_LAST); if( pThreadInfo->uiThreadId) { if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_THREADINFO_THREAD_ID, (void *)&pThreadInfo->uiThreadId, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pThreadInfo->uiThreadGroup) { if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_THREADINFO_THREAD_GROUP, (void *)&pThreadInfo->uiThreadGroup, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pThreadInfo->uiAppId) { if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_THREADINFO_APP_ID, (void *)&pThreadInfo->uiAppId, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pThreadInfo->uiStartTime) { if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_THREADINFO_START_TIME, (void *)&pThreadInfo->uiStartTime, 0, FLM_NUMBER_TYPE))) { goto Exit; } } if( pThreadInfo->pszThreadName) { if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_THREADINFO_THREAD_NAME, (void *)pThreadInfo->pszThreadName, 0, FLM_TEXT_TYPE))) { goto Exit; } } if( pThreadInfo->pszThreadStatus) { if( RC_BAD( rc = gedAddField( pPool, pContextNd, FCS_THREADINFO_THREAD_STATUS, (void *)pThreadInfo->pszThreadStatus, 0, FLM_TEXT_TYPE))) { goto Exit; } } pThreadInfo++; } *ppTree = pRootNd; Exit: if( RC_BAD( rc)) { GedPoolReset( pPool, pMark); } return( rc); } /**************************************************************************** Desc: Extracts a list of F_THREAD_INFO structure from an HTD tree. *****************************************************************************/ RCODE fcsExtractThreadInfo( NODE * pTree, POOL * pPool, F_THREAD_INFO ** ppThreadInfo, FLMUINT * puiNumThreads) { NODE * pTmpNd; NODE * pContextNd; void * pMark = GedPoolMark( pPool); FLMUINT uiTmp; F_THREAD_INFO * pThreadInfo; F_THREAD_INFO * pCurThread; FLMUINT uiNumThreads; FLMUINT uiLoop; RCODE rc = FERR_OK; *ppThreadInfo = NULL; *puiNumThreads = 0; if( GedTagNum( pTree) != FCS_THREAD_INFO_ROOT) { rc = RC_SET( FERR_SYNTAX); goto Exit; } if( RC_BAD( rc = GedGetUINT( pTree, &uiNumThreads))) { goto Exit; } if( !uiNumThreads) { goto Exit; } if( (pThreadInfo = (F_THREAD_INFO *)GedPoolCalloc( pPool, uiNumThreads * sizeof( F_THREAD_INFO))) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } if( (pContextNd = GedFind( 1, pTree, FCS_THREAD_INFO_CONTEXT, 1)) == NULL) { rc = RC_SET( FERR_SYNTAX); goto Exit; } for( uiLoop = 0, pCurThread = pThreadInfo; uiLoop < uiNumThreads; uiLoop++, pCurThread++) { if( (pTmpNd = GedFind( 1, pContextNd, FCS_THREADINFO_THREAD_ID, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pCurThread->uiThreadId); } if( (pTmpNd = GedFind( 1, pContextNd, FCS_THREADINFO_THREAD_GROUP, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pCurThread->uiThreadGroup); } if( (pTmpNd = GedFind( 1, pContextNd, FCS_THREADINFO_APP_ID, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pCurThread->uiAppId); } if( (pTmpNd = GedFind( 1, pContextNd, FCS_THREADINFO_START_TIME, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &pCurThread->uiStartTime); } if( (pTmpNd = GedFind( 1, pContextNd, FCS_THREADINFO_THREAD_NAME, 1)) != NULL) { if( RC_BAD( rc = GedGetNATIVE( pTmpNd, NULL, &uiTmp))) { goto Exit; } if( uiTmp) { uiTmp++; if( (pCurThread->pszThreadName = (char *)GedPoolAlloc( pPool, uiTmp)) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } } if( RC_BAD( rc = GedGetNATIVE( pTmpNd, pCurThread->pszThreadName, &uiTmp))) { goto Exit; } } if( (pTmpNd = GedFind( 1, pContextNd, FCS_THREADINFO_THREAD_STATUS, 1)) != NULL) { if( RC_BAD( rc = GedGetNATIVE( pTmpNd, NULL, &uiTmp))) { goto Exit; } if( uiTmp) { uiTmp++; if( (pCurThread->pszThreadStatus = (char *)GedPoolAlloc( pPool, uiTmp)) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } } if( RC_BAD( rc = GedGetNATIVE( pTmpNd, pCurThread->pszThreadStatus, &uiTmp))) { goto Exit; } } if( (pContextNd = GedSibNext( pContextNd)) != NULL) { if( GedTagNum( pContextNd) != FCS_THREAD_INFO_CONTEXT) { rc = RC_SET( FERR_SYNTAX); goto Exit; } } } *ppThreadInfo = pThreadInfo; *puiNumThreads = uiNumThreads; Exit: if( RC_BAD( rc)) { GedPoolReset( pPool, pMark); } return( rc); } /**************************************************************************** Desc: Reads a block from a remote database *****************************************************************************/ RCODE fcsGetBlock( HFDB hDb, FLMUINT uiAddress, FLMUINT uiMinTransId, FLMUINT * puiCount, FLMUINT * puiBlocksExamined, FLMUINT * puiNextBlkAddr, FLMUINT uiFlags, FLMBYTE * pucBlock) { FDB * pDb = (FDB *)hDb; RCODE rc = FERR_OK; flmAssert( IsInCSMode( hDb)); fdbInitCS( pDb); CS_CONTEXT * pCSContext = pDb->pCSContext; FCL_WIRE Wire( pCSContext, pDb); if( !pCSContext->bConnectionGood) { rc = RC_SET( FERR_BAD_SERVER_CONNECTION); goto Transmission_Error; } if( RC_BAD( rc = Wire.sendOp( FCS_OPCLASS_DATABASE, FCS_OP_DATABASE_GET_BLOCK))) { goto Exit; } if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_ADDRESS, uiAddress))) { goto Transmission_Error; } if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_TRANSACTION_ID, uiMinTransId))) { goto Transmission_Error; } if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_COUNT, *puiCount))) { goto Transmission_Error; } if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_FLAGS, uiFlags))) { goto Transmission_Error; } if( RC_BAD( rc = Wire.sendTerminate())) { goto Transmission_Error; } // Read the response if (RC_BAD( rc = Wire.read())) { goto Transmission_Error; } if( RC_BAD( rc = Wire.getRCode())) { if( rc != FERR_IO_END_OF_FILE) { goto Exit; } } *puiBlocksExamined = (FLMUINT)Wire.getNumber2(); *puiCount = (FLMUINT)Wire.getCount(); *puiNextBlkAddr = Wire.getAddress(); if( *puiCount) { f_memcpy( pucBlock, Wire.getBlock(), Wire.getBlockSize()); } goto Exit; Transmission_Error: pCSContext->bConnectionGood = FALSE; goto Exit; Exit: fdbExit( pDb); return( rc); } /**************************************************************************** Desc: Instructs the server to generate a serial number *****************************************************************************/ RCODE fcsCreateSerialNumber( void * pvCSContext, FLMBYTE * pucSerialNum) { RCODE rc = FERR_OK; CS_CONTEXT * pCSContext = (CS_CONTEXT *)pvCSContext; FCL_WIRE Wire( pCSContext); if( !pCSContext->bConnectionGood) { rc = RC_SET( FERR_BAD_SERVER_CONNECTION); goto Transmission_Error; } if( RC_BAD( rc = Wire.sendOp( FCS_OPCLASS_MISC, FCS_OP_CREATE_SERIAL_NUM))) { goto Exit; } if( RC_BAD( rc = Wire.sendTerminate())) { goto Transmission_Error; } // Read the response if (RC_BAD( rc = Wire.read())) { goto Transmission_Error; } if( RC_BAD( rc = Wire.getRCode())) { goto Exit; } if( !Wire.getSerialNum()) { rc = RC_SET( FERR_FAILURE); goto Exit; } f_memcpy( pucSerialNum, Wire.getSerialNum(), F_SERIAL_NUM_SIZE); goto Exit; Transmission_Error: pCSContext->bConnectionGood = FALSE; goto Exit; Exit: return( rc); } /**************************************************************************** Desc: Sets or clears the backup active flag for the database Note: This should only be called internally from the backup routines. *****************************************************************************/ RCODE fcsSetBackupActiveFlag( HFDB hDb, FLMBOOL bBackupActive) { FDB * pDb = (FDB *)hDb; RCODE rc = FERR_OK; flmAssert( IsInCSMode( hDb)); fdbInitCS( pDb); CS_CONTEXT * pCSContext = pDb->pCSContext; FCL_WIRE Wire( pCSContext, pDb); if( !pCSContext->bConnectionGood) { rc = RC_SET( FERR_BAD_SERVER_CONNECTION); goto Transmission_Error; } if( RC_BAD( rc = Wire.sendOp( FCS_OPCLASS_DATABASE, FCS_OP_DB_SET_BACKUP_FLAG))) { goto Exit; } if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_BOOLEAN, bBackupActive))) { goto Transmission_Error; } if( RC_BAD( rc = Wire.sendTerminate())) { goto Transmission_Error; } /* Read the response. */ if (RC_BAD( rc = Wire.read())) { goto Transmission_Error; } if( RC_BAD( rc = Wire.getRCode())) { goto Exit; } goto Exit; Transmission_Error: pCSContext->bConnectionGood = FALSE; goto Exit; Exit: fdbExit( pDb); return( rc); } /**************************************************************************** Desc: Commits an update transaction and updates the log header. Note: This should only be called internally from the backup routines. *****************************************************************************/ RCODE fcsDbTransCommitEx( HFDB hDb, FLMBOOL bForceCheckpoint, FLMBYTE * pucLogHdr) { RCODE rc = FERR_OK; FDB * pDb = (FDB *)hDb; FLMBOOL bInitializedFdb = FALSE; if( IsInCSMode( hDb)) { fdbInitCS( pDb); bInitializedFdb = TRUE; FCL_WIRE Wire( pDb->pCSContext, pDb); if (!pDb->pCSContext->bConnectionGood) { rc = RC_SET( FERR_BAD_SERVER_CONNECTION); } else { rc = Wire.doTransOp( FCS_OP_TRANSACTION_COMMIT_EX, 0, 0, 0, pucLogHdr, bForceCheckpoint); } } else { rc = RC_SET( FERR_ILLEGAL_OP); goto Exit; } Exit: if( bInitializedFdb) { fdbExit( pDb); } return( rc); } /**************************************************************************** Desc: Generates a hex-encoded, obfuscated string consisting of characters 0-9, A-F from the passed-in data buffer. *****************************************************************************/ RCODE flmGenerateHexPacket( FLMBYTE * pucData, FLMUINT uiDataSize, FLMBYTE ** ppucPacket) { FLMUINT32 * pui32CRCTbl = NULL; FLMBYTE * pucBinPacket = NULL; FLMBYTE * pucHexPacket = NULL; FLMBYTE * pucUsedMap = NULL; FLMUINT32 ui32Tmp; FLMUINT uiLoop; FLMUINT uiSlot = 0; FLMBYTE ucTmp[ 32]; FLMUINT uiBinPacketSize; FLMBOOL bTmp; f_randomGenerator randGen; RCODE rc = FERR_OK; // Determine the packet size. Make the minimum packet size 128 bytes // to account for the 64-byte "header" and for the overhead of the // CRC bytes, etc. Round the packet size up to the nearest 64-byte // boundary after adding on the data size. uiBinPacketSize = 128 + uiDataSize; if( (uiBinPacketSize % 64) != 0) { uiBinPacketSize += (64 - (uiBinPacketSize % 64)); } // Allocate buffers for building the packet if( RC_BAD( rc = f_alloc( uiBinPacketSize, &pucBinPacket))) { goto Exit; } if( RC_BAD( rc = f_calloc( uiBinPacketSize, &pucUsedMap))) { goto Exit; } // First 64-bytes of the packet are reserved as a header f_memset( pucUsedMap, 0xFF, 64); // Initialize the CRC table. if( RC_BAD( rc = f_initCRCTable( &pui32CRCTbl))) { goto Exit; } // Initialize the random number generator and seed with the current // time. f_randomize( &randGen); // Fill the packet with random "noise" for( uiLoop = 0; uiLoop < uiBinPacketSize; uiLoop += 4) { ui32Tmp = f_randomLong( &randGen); UD2FBA( ui32Tmp, &pucBinPacket[ uiLoop]); } for( uiLoop = 0; uiLoop < 512; uiLoop++) { ui32Tmp = f_randomLong( &randGen); UD2FBA( ui32Tmp, &pucBinPacket[ f_randomChoice( &randGen, 1, (int)(uiBinPacketSize / 4)) - 1]); } // Determine a new random seed based on bytes in the // packet header if( (ui32Tmp = (FLMUINT32)FB2UD( &pucBinPacket[ f_randomChoice( &randGen, 1, 61) - 1])) == 0) { ui32Tmp = 1; } f_randomSetSeed( &randGen, ui32Tmp); // Use the CRC of the header and the also first four bytes // of the header as an 8-byte validation signature. This will // be needed to decode the packet. // Initialize the CRC to 0xFFFFFFFF and then compute the 1's // complement of the returned CRC. This implements the // "standard" CRC used by PKZIP, etc. ui32Tmp = 0xFFFFFFFF; f_updateCRC( pui32CRCTbl, pucBinPacket, 64, &ui32Tmp); ui32Tmp = ~ui32Tmp; UD2FBA( ui32Tmp, &ucTmp[ 0]); f_memcpy( &ucTmp[ 4], pucBinPacket, 4); for( uiLoop = 0; uiLoop < 8; uiLoop++) { bTmp = flmGetNextHexPacketSlot( pucUsedMap, uiBinPacketSize, &randGen, &uiSlot); flmAssert( bTmp); pucBinPacket[ uiSlot] = ucTmp[ uiLoop]; } // Encode the data size UD2FBA( uiDataSize, &ucTmp[ 0]); for( uiLoop = 0; uiLoop < 4; uiLoop++) { bTmp = flmGetNextHexPacketSlot( pucUsedMap, uiBinPacketSize, &randGen, &uiSlot); flmAssert( bTmp); pucBinPacket[ uiSlot] = ucTmp[ uiLoop]; } // Randomly dispurse the data throughout the buffer. Obfuscate the // data using the first 64-bytes of the buffer. for( uiLoop = 0; uiLoop < uiDataSize; uiLoop++) { bTmp = flmGetNextHexPacketSlot( pucUsedMap, uiBinPacketSize, &randGen, &uiSlot); flmAssert( bTmp); pucBinPacket[ uiSlot] = pucData[ uiLoop] ^ pucBinPacket[ uiLoop % 64]; } // Calculate and encode the data CRC ui32Tmp = 0xFFFFFFFF; f_updateCRC( pui32CRCTbl, pucData, uiDataSize, &ui32Tmp); ui32Tmp = ~ui32Tmp; UD2FBA( ui32Tmp, &ucTmp[ 0]); for( uiLoop = 0; uiLoop < 4; uiLoop++) { bTmp = flmGetNextHexPacketSlot( pucUsedMap, uiBinPacketSize, &randGen, &uiSlot); flmAssert( bTmp); pucBinPacket[ uiSlot] = ucTmp[ uiLoop]; } // Hex encode the binary packet if( RC_BAD( rc = f_alloc( (uiBinPacketSize * 2) + 1, &pucHexPacket))) { goto Exit; } for( uiLoop = 0; uiLoop < uiBinPacketSize; uiLoop++) { FLMBYTE ucLowNibble = pucBinPacket[ uiLoop] & 0x0F; FLMBYTE ucHighNibble = (pucBinPacket[ uiLoop] & 0xF0) >> 4; pucHexPacket[ uiLoop << 1] = (ucHighNibble <= 9 ? (ucHighNibble + '0') : ((ucHighNibble - 0xA) + 'A')); pucHexPacket[ (uiLoop << 1) + 1] = (ucLowNibble <= 9 ? (ucLowNibble + '0') : ((ucLowNibble - 0xA) + 'A')); } pucHexPacket[ uiBinPacketSize * 2] = 0; *ppucPacket = pucHexPacket; pucHexPacket = NULL; Exit: if( pui32CRCTbl) { f_freeCRCTable( &pui32CRCTbl); } if( pucUsedMap) { f_free( &pucUsedMap); } if( pucBinPacket) { f_free( &pucBinPacket); } if( pucHexPacket) { f_free( &pucHexPacket); } return( rc); } /**************************************************************************** Desc: Extracts a data buffer from the passed-in hex-encoded, obfuscated string. *****************************************************************************/ RCODE flmExtractHexPacketData( FLMBYTE * pucPacket, FLMBYTE ** ppucData, FLMUINT * puiDataSize) { FLMUINT32 * pui32CRCTbl = NULL; FLMBYTE * pucUsedMap = NULL; FLMBYTE * pucData = NULL; FLMBYTE * pucBinPacket = NULL; FLMBYTE * pucTmp; FLMUINT32 ui32Tmp; FLMUINT32 ui32FirstCRC; FLMUINT32 ui32Seed; FLMUINT uiPacketSize; FLMUINT uiLoop; FLMUINT uiDataSize; FLMBYTE ucTmp[ 32]; FLMBYTE ucVal = 0; FLMBOOL bValid; f_randomGenerator randGen; RCODE rc = FERR_OK; // Determine the packet size, ignoring all characters except 0-9, A-F uiPacketSize = 0; pucTmp = pucPacket; while( *pucTmp) { if( (*pucTmp >= '0' && *pucTmp <= '9') || (*pucTmp >= 'A' && *pucTmp <= 'F')) { uiPacketSize++; } pucTmp++; } if( uiPacketSize & 0x00000001 || (uiPacketSize % 4) != 0 || uiPacketSize < 128) { rc = RC_SET( FERR_INVALID_CRC); goto Exit; } // Get the actual size of the decoded binary data by dividing // the packet size by 2 uiPacketSize >>= 1; // Allocate a buffer and convert the data from hex ASCII to binary if( RC_BAD( rc = f_calloc( uiPacketSize, &pucBinPacket))) { goto Exit; } uiLoop = 0; pucTmp = pucPacket; while( *pucTmp) { bValid = FALSE; if( *pucTmp >= '0' && *pucTmp <= '9') { ucVal = *pucTmp - '0'; bValid = TRUE; } else if( *pucTmp >= 'A' && *pucTmp <= 'F') { ucVal = (*pucTmp - 'A') + 0x0A; bValid = TRUE; } if( bValid) { if( (uiLoop & 0x00000001) == 0) { ucVal <<= 4; } pucBinPacket[ uiLoop >> 1] |= ucVal; uiLoop++; } pucTmp++; } // Allocate the data map if( RC_BAD( rc = f_calloc( uiPacketSize, &pucUsedMap))) { goto Exit; } // First 64-bytes of the packet are reserved f_memset( pucUsedMap, 0xFF, 64); // Initialize the CRC table if( RC_BAD( rc = f_initCRCTable( &pui32CRCTbl))) { goto Exit; } // Determine the CRC of the 1st 64-bytes ui32FirstCRC = 0xFFFFFFFF; f_updateCRC( pui32CRCTbl, pucBinPacket, 64, &ui32FirstCRC); ui32FirstCRC = ~ui32FirstCRC; // Search for the random seed within the first 64 bytes ui32Seed = 0; for( uiLoop = 0; uiLoop < 61; uiLoop++) { ui32Tmp = FB2UD( &pucBinPacket[ uiLoop]); f_randomSetSeed( &randGen, ui32Tmp); if( RC_BAD( rc = flmGetNextHexPacketBytes( pucUsedMap, uiPacketSize, pucBinPacket, &randGen, ucTmp, 8))) { goto Exit; } if( FB2UD( &ucTmp[ 0]) == ui32FirstCRC && f_memcmp( &ucTmp[ 4], &pucBinPacket[ 0], 4) == 0) { ui32Seed = ui32Tmp; break; } // Reset the "used" map f_memset( pucUsedMap, 0, uiPacketSize); f_memset( pucUsedMap, 0xFF, 64); } if( !ui32Seed) { rc = RC_SET( FERR_INVALID_CRC); goto Exit; } // Get the data size if( RC_BAD( rc = flmGetNextHexPacketBytes( pucUsedMap, uiPacketSize, pucBinPacket, &randGen, ucTmp, 4))) { goto Exit; } uiDataSize = (FLMUINT)FB2UD( &ucTmp[ 0]); if( uiDataSize > uiPacketSize) { rc = RC_SET( FERR_INVALID_CRC); goto Exit; } // Allocate space for the data if( RC_BAD( rc = f_alloc( uiDataSize, &pucData))) { goto Exit; } // Get the data if( RC_BAD( rc = flmGetNextHexPacketBytes( pucUsedMap, uiPacketSize, pucBinPacket, &randGen, pucData, uiDataSize))) { goto Exit; } // Un-obfuscate the data for( uiLoop = 0; uiLoop < uiDataSize; uiLoop++) { pucData[ uiLoop] = pucData[ uiLoop] ^ pucBinPacket[ uiLoop % 64]; } // Get the data CRC if( RC_BAD( rc = flmGetNextHexPacketBytes( pucUsedMap, uiPacketSize, pucBinPacket, &randGen, ucTmp, 4))) { goto Exit; } // Verify the data CRC ui32Tmp = 0xFFFFFFFF; f_updateCRC( pui32CRCTbl, pucData, uiDataSize, &ui32Tmp); ui32Tmp = ~ui32Tmp; if( ui32Tmp != FB2UD( &ucTmp[ 0])) { rc = RC_SET( FERR_INVALID_CRC); goto Exit; } *ppucData = pucData; pucData = NULL; *puiDataSize = uiDataSize; Exit: if( pui32CRCTbl) { f_freeCRCTable( &pui32CRCTbl); } if( pucUsedMap) { f_free( &pucUsedMap); } if( pucData) { f_free( &pucData); } if( pucBinPacket) { f_free( &pucBinPacket); } return( rc); } /**************************************************************************** Desc: Used by flmGenerateHexPacket to find an unused byte in the packet *****************************************************************************/ FLMBOOL flmGetNextHexPacketSlot( FLMBYTE * pucUsedMap, FLMUINT uiMapSize, f_randomGenerator * pRandGen, FLMUINT * puiSlot) { FLMUINT uiLoop; FLMUINT uiSlot = 0; FLMBOOL bFound = FALSE; for( uiLoop = 0; uiLoop < 100; uiLoop++) { uiSlot = ((FLMUINT)f_randomLong( pRandGen)) % uiMapSize; if( !pucUsedMap[ uiSlot]) { bFound = TRUE; goto Exit; } } // Scan the table from the top to find an empty slot for( uiSlot = 0; uiSlot < uiMapSize; uiSlot++) { if( !pucUsedMap[ uiSlot]) { bFound = TRUE; goto Exit; } } Exit: if( bFound) { flmAssert( uiSlot < uiMapSize); *puiSlot = uiSlot; pucUsedMap[ uiSlot] = 0xFF; } return( bFound); } /**************************************************************************** Desc: Used by flmExtractHexPacket to get the next N bytes of data from the packet. *****************************************************************************/ RCODE flmGetNextHexPacketBytes( FLMBYTE * pucUsedMap, FLMUINT uiMapSize, FLMBYTE * pucPacket, f_randomGenerator * pRandGen, FLMBYTE * pucBuf, FLMUINT uiCount) { FLMUINT uiSlot; FLMUINT uiLoop; RCODE rc = FERR_OK; for( uiLoop = 0; uiLoop < uiCount; uiLoop++) { if( !flmGetNextHexPacketSlot( pucUsedMap, uiMapSize, pRandGen, &uiSlot)) { rc = RC_SET( FERR_INVALID_CRC); goto Exit; } pucBuf[ uiLoop] = pucPacket[ uiSlot]; } Exit: return( rc); } /**************************************************************************** Desc: Decodes a string containing %XX sequences and does it in place. Typically, this data comes from an HTML form. ****************************************************************************/ void fcsDecodeHttpString( char * pszSrc) { char * pszDest; pszDest = pszSrc; while( *pszSrc) { if( *pszSrc == '%') { pszSrc++; if( f_isHexChar( pszSrc[ 0]) && f_isHexChar( pszSrc[ 1])) { *pszDest = (f_getHexVal( pszSrc[ 0]) << 4) | f_getHexVal( pszSrc[ 1]); pszSrc += 2; pszDest++; continue; } } else if( *pszSrc == '+') { *pszDest = ' '; pszSrc++; pszDest++; continue; } if( pszSrc != pszDest) { *pszDest = *pszSrc; } pszSrc++; pszDest++; } *pszDest = 0; } /**************************************************************************** Desc: *****************************************************************************/ FCS_WIRE::FCS_WIRE( FCS_DIS * pDIStream, FCS_DOS * pDOStream) { GedPoolInit( &m_pool, 2048); m_pPool = &m_pool; m_pDIStream = pDIStream; m_pDOStream = pDOStream; m_pRecord = NULL; m_pFromKey = NULL; m_pUntilKey = NULL; m_bSendGedcom = FALSE; (void)resetCommon(); } /**************************************************************************** Desc: *****************************************************************************/ FCS_WIRE::~FCS_WIRE( void) { if( m_pRecord) { m_pRecord->Release(); m_pRecord = NULL; } if( m_pFromKey) { m_pFromKey->Release(); m_pFromKey = NULL; } if( m_pUntilKey) { m_pUntilKey->Release(); m_pUntilKey = NULL; } GedPoolFree( &m_pool); } /**************************************************************************** Desc: Resets all member variables to their default / initial values. *****************************************************************************/ void FCS_WIRE::resetCommon( void) { if( m_pRecord) { m_pRecord->Release(); m_pRecord = NULL; } if( m_pFromKey) { m_pFromKey->Release(); m_pFromKey = NULL; } if( m_pUntilKey) { m_pUntilKey->Release(); m_pUntilKey = NULL; } m_uiClass = 0; m_uiOp = 0; m_uiRCode = 0; m_uiDrn = 0; m_uiTransType = FLM_READ_TRANS; m_ui64Count = 0; m_uiItemId = 0; m_uiIndexId = 0; m_puzItemName = NULL; m_pHTD = NULL; m_uiSessionId = FCS_INVALID_ID; m_uiSessionCookie = 0; m_uiContainer = FLM_DATA_CONTAINER; m_uiTransId = FCS_INVALID_ID; m_uiIteratorId = FCS_INVALID_ID; m_puzFilePath = NULL; m_puzFilePath2 = NULL; m_puzFilePath3 = NULL; m_pucBlock = NULL; m_pucSerialNum = NULL; m_uiBlockSize = 0; m_bIncludesAsync = FALSE; fcsInitCreateOpts( &m_CreateOpts); GedPoolReset( m_pPool, NULL); m_bFlag = FALSE; m_ui64Number1 = 0; m_ui64Number2 = 0; m_ui64Number3 = 0; m_uiAddress = 0; m_uiFlags = 0; m_uiFlaimVersion = 0; m_i64SignedValue = 0; m_pCSContext = NULL; m_pDb = NULL; } /**************************************************************************** Desc: Reads the class and opcode for a client request or server response. *****************************************************************************/ RCODE FCS_WIRE::readOpcode( void) { FLMBYTE ucClass; FLMBYTE ucOp; RCODE rc = FERR_OK; /* Read the opcode. */ if( RC_BAD( rc = m_pDIStream->read( &ucClass, 1, NULL))) { goto Exit; } m_uiClass = ucClass; if( RC_BAD( rc = m_pDIStream->read( &ucOp, 1, NULL))) { goto Exit; } m_uiOp = ucOp; Exit: return( rc); } /**************************************************************************** Desc: Reads a client request or server response and sets the appropriate member variable values. *****************************************************************************/ RCODE FCS_WIRE::readCommon( FLMUINT * puiTagRV, FLMBOOL * pbEndRV) { FLMUINT16 ui16Tmp; FLMUINT uiTag = 0; RCODE rc = FERR_OK; *pbEndRV = FALSE; // Read the tag. if( RC_BAD( rc = m_pDIStream->readUShort( &ui16Tmp))) { goto Exit; } uiTag = ui16Tmp; // Read the request / response values. switch( (uiTag & WIRE_VALUE_TAG_MASK)) { case WIRE_VALUE_RCODE: { rc = readNumber( uiTag, &m_uiRCode); uiTag = 0; break; } case WIRE_VALUE_SESSION_ID: { rc = readNumber( uiTag, &m_uiSessionId); uiTag = 0; break; } case WIRE_VALUE_SESSION_COOKIE: { rc = readNumber( uiTag, &m_uiSessionCookie); uiTag = 0; break; } case WIRE_VALUE_CONTAINER_ID: { rc = readNumber( uiTag, &m_uiContainer); uiTag = 0; break; } case WIRE_VALUE_COUNT: { rc = readNumber( uiTag, NULL, NULL, &m_ui64Count); uiTag = 0; break; } case WIRE_VALUE_DRN: { rc = readNumber( uiTag, &m_uiDrn); uiTag = 0; break; } case WIRE_VALUE_INDEX_ID: { rc = readNumber( uiTag, &m_uiIndexId); uiTag = 0; break; } case WIRE_VALUE_HTD: { rc = m_pDIStream->readHTD( m_pPool, 0, 0, &m_pHTD, NULL); uiTag = 0; break; } case WIRE_VALUE_RECORD: { FlmRecord * pRecord = m_pRecord; if( RC_OK( rc = receiveRecord( &pRecord))) { if( m_pRecord != pRecord) { if( m_pRecord) { m_pRecord->Release(); } m_pRecord = pRecord; } } uiTag = 0; break; } case WIRE_VALUE_FROM_KEY: { FlmRecord * pFromKey = m_pFromKey; if( RC_OK( rc = receiveRecord( &pFromKey))) { if( m_pFromKey != pFromKey) { if( m_pFromKey) { m_pFromKey->Release(); } m_pFromKey = pFromKey; } } uiTag = 0; break; } case WIRE_VALUE_UNTIL_KEY: { FlmRecord * pUntilKey = m_pUntilKey; if( RC_OK( rc = receiveRecord( &pUntilKey))) { if( m_pUntilKey != pUntilKey) { if( m_pUntilKey) { m_pUntilKey->Release(); } m_pUntilKey = pUntilKey; } } uiTag = 0; break; } case WIRE_VALUE_CREATE_OPTS: { rc = receiveCreateOpts(); uiTag = 0; break; } case WIRE_VALUE_ITERATOR_ID: { rc = readNumber( uiTag, &m_uiIteratorId); uiTag = 0; break; } case WIRE_VALUE_TRANSACTION_TYPE: { rc = readNumber( uiTag, &m_uiTransType); uiTag = 0; break; } case WIRE_VALUE_TRANSACTION_ID: { rc = readNumber( uiTag, &m_uiTransId); uiTag = 0; break; } case WIRE_VALUE_ITEM_NAME: { rc = m_pDIStream->readUTF( m_pPool, &m_puzItemName); uiTag = 0; break; } case WIRE_VALUE_ITEM_ID: { rc = readNumber( uiTag, &m_uiItemId); uiTag = 0; break; } case WIRE_VALUE_BOOLEAN: { FLMUINT uiTmp; if( RC_OK( rc = readNumber( uiTag, &uiTmp))) { m_bFlag = (FLMBOOL)((uiTmp) ? (FLMBOOL)TRUE : (FLMBOOL)FALSE); } uiTag = 0; break; } case WIRE_VALUE_NUMBER1: { rc = readNumber( uiTag, NULL, NULL, &m_ui64Number1); uiTag = 0; break; } case WIRE_VALUE_NUMBER2: { rc = readNumber( uiTag, NULL, NULL, &m_ui64Number2); uiTag = 0; break; } case WIRE_VALUE_NUMBER3: { rc = readNumber( uiTag, NULL, NULL, &m_ui64Number3); uiTag = 0; break; } case WIRE_VALUE_ADDRESS: { rc = readNumber( uiTag, &m_uiAddress); uiTag = 0; break; } case WIRE_VALUE_SIGNED_NUMBER: { rc = readNumber( uiTag, NULL, NULL, NULL, &m_i64SignedValue); uiTag = 0; break; } case WIRE_VALUE_FILE_PATH: { rc = m_pDIStream->readUTF( m_pPool, &m_puzFilePath); uiTag = 0; break; } case WIRE_VALUE_FILE_PATH_2: { rc = m_pDIStream->readUTF( m_pPool, &m_puzFilePath2); uiTag = 0; break; } case WIRE_VALUE_FILE_PATH_3: { rc = m_pDIStream->readUTF( m_pPool, &m_puzFilePath3); uiTag = 0; break; } case WIRE_VALUE_BLOCK: { rc = m_pDIStream->readLargeBinary( m_pPool, &m_pucBlock, &m_uiBlockSize); uiTag = 0; break; } case WIRE_VALUE_SERIAL_NUM: { FLMUINT uiSerialLen; if( RC_BAD( rc = m_pDIStream->readBinary( m_pPool, &m_pucSerialNum, &uiSerialLen))) { goto Exit; } if( uiSerialLen != F_SERIAL_NUM_SIZE) { rc = RC_SET( FERR_CONV_DEST_OVERFLOW); goto Exit; } uiTag = 0; break; } case WIRE_VALUE_START_ASYNC: { m_bIncludesAsync = TRUE; *pbEndRV = TRUE; uiTag = 0; break; } case WIRE_VALUE_FLAGS: { rc = readNumber( uiTag, &m_uiFlags); uiTag = 0; break; } case WIRE_VALUE_FLAIM_VERSION: { rc = readNumber( uiTag, &m_uiFlaimVersion); uiTag = 0; break; } case WIRE_VALUE_TERMINATE: { rc = m_pDIStream->endMessage(); *pbEndRV = TRUE; uiTag = 0; break; } default: { break; } } Exit: *puiTagRV = uiTag; return( rc); } /**************************************************************************** Desc: Copies the internal CREATE_OPTS structure into a user-supplied location *****************************************************************************/ void FCS_WIRE::copyCreateOpts( CREATE_OPTS * pCreateOptsRV) { f_memcpy( pCreateOptsRV, &m_CreateOpts, sizeof( CREATE_OPTS)); } /**************************************************************************** Desc: Reads a numeric value from the specified data input stream. *****************************************************************************/ RCODE FCS_WIRE::readNumber( FLMUINT uiTag, FLMUINT * puiNumber, FLMINT * piNumber, FLMUINT64 * pui64Number, FLMINT64 * pi64Number) { RCODE rc = FERR_OK; flmAssert( !(puiNumber && piNumber)); // Read the number of bytes specified by the // value's tag. switch( ((uiTag & WIRE_VALUE_TYPE_MASK) >> WIRE_VALUE_TYPE_START_BIT)) { case WIRE_VALUE_TYPE_GEN_0: { if( puiNumber) { *puiNumber = 0; } else if( piNumber) { *piNumber = 0; } else if( pui64Number) { *pui64Number = 0; } else if( pi64Number) { *pi64Number = 0; } break; } case WIRE_VALUE_TYPE_GEN_1: { FLMBYTE ucValue; if( RC_BAD( rc = m_pDIStream->read( &ucValue, 1, NULL))) { goto Exit; } if( puiNumber) { *puiNumber = (FLMUINT)ucValue; } else if( piNumber) { *piNumber = (FLMINT)*((FLMINT8 *)&ucValue); } else if( pui64Number) { *pui64Number = (FLMUINT64)ucValue; } else if( pi64Number) { *pi64Number = (FLMINT64)*((FLMINT8 *)&ucValue); } break; } case WIRE_VALUE_TYPE_GEN_2: { if( puiNumber || pui64Number) { FLMUINT16 ui16Value; if( RC_BAD( rc = m_pDIStream->readUShort( &ui16Value))) { goto Exit; } if( puiNumber) { *puiNumber = (FLMUINT)ui16Value; } else if( pui64Number) { *pui64Number = (FLMUINT64)ui16Value; } } else if( piNumber || pi64Number) { FLMINT16 i16Value; if( RC_BAD( rc = m_pDIStream->readShort( &i16Value))) { goto Exit; } if( piNumber) { *piNumber = (FLMINT)i16Value; } else if( pi64Number) { *pi64Number = (FLMINT)i16Value; } } break; } case WIRE_VALUE_TYPE_GEN_4: { if( puiNumber || pui64Number) { FLMUINT32 ui32Value; if( RC_BAD( rc = m_pDIStream->readUInt( &ui32Value))) { goto Exit; } if( puiNumber) { *puiNumber = (FLMUINT)ui32Value; } else if( pui64Number) { *pui64Number = (FLMUINT64)ui32Value; } } else if( piNumber || pi64Number) { FLMINT32 i32Value; if( RC_BAD( rc = m_pDIStream->readInt( &i32Value))) { goto Exit; } if( piNumber) { *piNumber = (FLMINT)i32Value; } else if( pi64Number) { *pi64Number = (FLMINT64)i32Value; } } break; } case WIRE_VALUE_TYPE_GEN_8: { if( puiNumber || piNumber) { rc = RC_SET( FERR_CONV_NUM_OVERFLOW); } else { if( pui64Number) { if( RC_BAD( rc = m_pDIStream->readUInt64( pui64Number))) { goto Exit; } } else if( pi64Number) { if( RC_BAD( rc = m_pDIStream->readInt64( pi64Number))) { goto Exit; } } else { flmAssert( 0); rc = RC_SET( FERR_INVALID_PARM); goto Exit; } } break; } } Exit: return( rc); } /**************************************************************************** Desc: Writes an unsigned number to the specified data output stream. *****************************************************************************/ RCODE FCS_WIRE::writeUnsignedNumber( FLMUINT uiTag, FLMUINT64 ui64Number) { RCODE rc = FERR_OK; if( ui64Number <= (FLMUINT64)0x000000FF) { uiTag |= WIRE_VALUE_TYPE_GEN_1 << WIRE_VALUE_TYPE_START_BIT; if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) { goto Exit; } if( RC_BAD( rc = m_pDOStream->writeByte( (FLMBYTE)ui64Number))) { goto Exit; } } else if( ui64Number <= (FLMUINT64)0x0000FFFF) { uiTag |= WIRE_VALUE_TYPE_GEN_2 << WIRE_VALUE_TYPE_START_BIT; if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) { goto Exit; } if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)ui64Number))) { goto Exit; } } else if( ui64Number <= (FLMUINT64)0xFFFFFFFF) { uiTag |= WIRE_VALUE_TYPE_GEN_4 << WIRE_VALUE_TYPE_START_BIT; if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) { goto Exit; } if( RC_BAD( rc = m_pDOStream->writeUInt32( (FLMUINT32)ui64Number))) { goto Exit; } } else { uiTag |= WIRE_VALUE_TYPE_GEN_8 << WIRE_VALUE_TYPE_START_BIT; if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) { goto Exit; } if( RC_BAD( rc = m_pDOStream->writeUInt64( ui64Number))) { goto Exit; } } Exit: return( rc); } /**************************************************************************** Desc: Writes a signed number to the specified data output stream. *****************************************************************************/ RCODE FCS_WIRE::writeSignedNumber( FLMUINT uiTag, FLMINT64 i64Number) { RCODE rc = FERR_OK; if( RC_BAD( rc = writeUnsignedNumber( uiTag, (FLMUINT64)i64Number))) { goto Exit; } Exit: return( rc); } /**************************************************************************** Desc: Skips a parameter or return value in the data stream *****************************************************************************/ RCODE FCS_WIRE::skipValue( FLMUINT uiTag) { RCODE rc = FERR_OK; switch( ((uiTag & WIRE_VALUE_TYPE_MASK) >> WIRE_VALUE_TYPE_START_BIT)) { case WIRE_VALUE_TYPE_GEN_0: { break; } case WIRE_VALUE_TYPE_GEN_1: { if( RC_BAD( rc = m_pDIStream->skip( 1))) { goto Exit; } break; } case WIRE_VALUE_TYPE_GEN_2: { if( RC_BAD( rc = m_pDIStream->skip( 2))) { goto Exit; } break; } case WIRE_VALUE_TYPE_GEN_4: { if( RC_BAD( rc = m_pDIStream->skip( 4))) { goto Exit; } break; } case WIRE_VALUE_TYPE_GEN_8: { if( RC_BAD( rc = m_pDIStream->skip( 8))) { goto Exit; } break; } case WIRE_VALUE_TYPE_BINARY: { if( RC_BAD( rc = m_pDIStream->readBinary( NULL, NULL, NULL))) { goto Exit; } break; } case WIRE_VALUE_TYPE_LARGE_BINARY: { if( RC_BAD( rc = m_pDIStream->readLargeBinary( NULL, NULL, NULL))) { goto Exit; } break; } case WIRE_VALUE_TYPE_HTD: { if( RC_BAD( rc = m_pDIStream->readHTD( NULL, 0, 0, NULL, NULL))) { goto Exit; } break; } case WIRE_VALUE_TYPE_RECORD: { if( RC_BAD( rc = receiveRecord( NULL))) { goto Exit; } } case WIRE_VALUE_TYPE_UTF: { if( RC_BAD( rc = m_pDIStream->readUTF( NULL, NULL))) { goto Exit; } break; } default: { rc = RC_SET( FERR_FAILURE); goto Exit; } } Exit: return( rc); } /**************************************************************************** Desc: Sends an opcode to the client *****************************************************************************/ RCODE FCS_WIRE::sendOpcode( FLMUINT uiClass, FLMUINT uiOp) { FLMBYTE ucClass = (FLMBYTE)uiClass; FLMBYTE ucOp = (FLMBYTE)uiOp; RCODE rc = FERR_OK; if( RC_BAD( rc = m_pDOStream->write( &ucClass, 1))) { goto Exit; } if( RC_BAD( rc = m_pDOStream->write( &ucOp, 1))) { goto Exit; } Exit: return( rc); } /**************************************************************************** Desc: Sends a value to the client *****************************************************************************/ RCODE FCS_WIRE::sendTerminate( void) { RCODE rc = FERR_OK; if( RC_BAD( rc = m_pDOStream->writeUShort( 0))) { goto Exit; } if( RC_BAD( rc = m_pDOStream->endMessage())) { goto Exit; } Exit: return( rc); } /**************************************************************************** Desc: Sends a value to the client *****************************************************************************/ RCODE FCS_WIRE::sendNumber( FLMUINT uiTag, FLMUINT64 ui64Value, FLMINT64 i64Value) { RCODE rc = FERR_OK; // Send the parameter tag and value. switch( uiTag) { case WIRE_VALUE_AREA_ID: case WIRE_VALUE_OP_SEQ_NUM: case WIRE_VALUE_FLAGS: case WIRE_VALUE_CLIENT_VERSION: case WIRE_VALUE_SESSION_ID: case WIRE_VALUE_SESSION_COOKIE: case WIRE_VALUE_CONTAINER_ID: case WIRE_VALUE_INDEX_ID: case WIRE_VALUE_ITEM_ID: case WIRE_VALUE_TRANSACTION_ID: case WIRE_VALUE_TRANSACTION_TYPE: case WIRE_VALUE_DRN: case WIRE_VALUE_COUNT: case WIRE_VALUE_AUTOTRANS: case WIRE_VALUE_MAX_LOCK_WAIT: case WIRE_VALUE_RECORD_COUNT: case WIRE_VALUE_BOOLEAN: case WIRE_VALUE_ITERATOR_ID: case WIRE_VALUE_SHARED_DICT_ID: case WIRE_VALUE_PARENT_DICT_ID: case WIRE_VALUE_TYPE: case WIRE_VALUE_NUMBER1: case WIRE_VALUE_NUMBER2: case WIRE_VALUE_NUMBER3: case WIRE_VALUE_ADDRESS: case WIRE_VALUE_FLAIM_VERSION: { if( RC_BAD( rc = writeUnsignedNumber( uiTag, ui64Value))) { goto Exit; } break; } case WIRE_VALUE_SIGNED_NUMBER: { if( RC_BAD( rc = writeSignedNumber( uiTag, i64Value))) { goto Exit; } break; } default: { #ifdef FLM_DEBUG flmAssert( 0); #else rc = RC_SET( FERR_NOT_IMPLEMENTED); goto Exit; #endif } } Exit: return( rc); } /**************************************************************************** Desc: Sends a value to the client *****************************************************************************/ RCODE FCS_WIRE::sendBinary( FLMUINT uiTag, FLMBYTE * pData, FLMUINT uiLength) { RCODE rc = FERR_OK; // Send the parameter tag and value. switch( uiTag) { case WIRE_VALUE_PASSWORD: case WIRE_VALUE_SERIAL_NUM: { uiTag |= WIRE_VALUE_TYPE_BINARY << WIRE_VALUE_TYPE_START_BIT; if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) { goto Exit; } if( RC_BAD( rc = m_pDOStream->writeBinary( pData, uiLength))) { goto Exit; } break; } case WIRE_VALUE_BLOCK: { uiTag |= WIRE_VALUE_TYPE_LARGE_BINARY << WIRE_VALUE_TYPE_START_BIT; if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) { goto Exit; } if( RC_BAD( rc = m_pDOStream->writeLargeBinary( pData, uiLength))) { goto Exit; } break; } default: { #ifdef FLM_DEBUG flmAssert( 0); #else rc = RC_SET( FERR_NOT_IMPLEMENTED); goto Exit; #endif } } Exit: return( rc); } /**************************************************************************** Desc: Sends a record *****************************************************************************/ RCODE FCS_WIRE::sendRecord( FLMUINT uiTag, FlmRecord * pRecord) { #define RECORD_OUTPUT_BUFFER_SIZE 64 FLMBYTE pucBuffer[ RECORD_OUTPUT_BUFFER_SIZE]; FLMBYTE * pucBufPos; FLMBYTE ucDescriptor; RCODE rc = FERR_OK; // Send the parameter tag and value. switch( uiTag) { case WIRE_VALUE_RECORD: case WIRE_VALUE_FROM_KEY: case WIRE_VALUE_UNTIL_KEY: { uiTag |= WIRE_VALUE_TYPE_RECORD << WIRE_VALUE_TYPE_START_BIT; if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) { goto Exit; } // The format of a record is (X = 1 bit): // // X X XXXXXX 0-64 bytes HTD // RESERVED HTD_FOLLOWS ID_LENGTH ID_VALUE TREE (optional) // // This sequence can repeat, terminating with a 0 byte. ucDescriptor = 0; pucBufPos = pucBuffer; ucDescriptor |= (FLMBYTE)RECORD_HAS_HTD_FLAG; // Output the descriptor. ucDescriptor |= (FLMBYTE)RECORD_ID_SIZE; *pucBufPos = ucDescriptor; pucBufPos++; // Output the ID. Current format of a record ID is: // // 4-byte container ID, 4-byte DRN flmUINT32ToBigEndian( pRecord->getContainerID(), pucBufPos); pucBufPos += 4; flmUINT32ToBigEndian( pRecord->getID(), pucBufPos); pucBufPos += 4; // Send the descriptor and record source. if( RC_BAD( rc = m_pDOStream->write( pucBuffer, pucBufPos - pucBuffer))) { goto Exit; } // Send the record. if( RC_BAD( rc = m_pDOStream->writeHTD( NULL, pRecord, FALSE, m_bSendGedcom))) { goto Exit; } break; } default: { #ifdef FLM_DEBUG flmAssert( 0); #else rc = RC_SET( FERR_NOT_IMPLEMENTED); goto Exit; #endif } } Exit: return( rc); } /**************************************************************************** Desc: Sends a value to the client *****************************************************************************/ RCODE FCS_WIRE::sendDrnList( FLMUINT uiTag, FLMUINT * puiList) { FLMUINT uiItemCount; FLMUINT uiLoop; FLMUINT uiBufSize = 0; FLMBYTE * pucItemBuf = NULL; FLMBYTE * pucItemPos; RCODE rc = FERR_OK; if( !puiList) { rc = RC_SET( FERR_MEM); goto Exit; } // Send the parameter tag and value. switch( uiTag) { case WIRE_VALUE_DRN_LIST: { uiTag |= WIRE_VALUE_TYPE_BINARY << WIRE_VALUE_TYPE_START_BIT; if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) { goto Exit; } // Count the entries in the list. For now, support only a list of // 2048 elements. for( uiItemCount = 0; uiItemCount < 2048; uiItemCount++) { if( !puiList[ uiItemCount]) { break; } } // Allocate a buffer for the list. uiBufSize = (FLMUINT)(((FLMUINT)sizeof( FLMUINT) * uiItemCount) + (FLMUINT)4); if( RC_BAD( rc = f_calloc( uiBufSize, &pucItemBuf))) { goto Exit; } pucItemPos = pucItemBuf; // Set the item count. UD2FBA( uiItemCount, pucItemPos); pucItemPos += 4; // Put the items into the buffer. for( uiLoop = 0; uiLoop < uiItemCount; uiLoop++) { UD2FBA( puiList[ uiLoop], pucItemPos); pucItemPos += 4; } // Send the list. if( RC_BAD( rc = m_pDOStream->writeBinary( pucItemBuf, uiBufSize))) { goto Exit; } break; } default: { #ifdef FLM_DEBUG flmAssert( 0); #else rc = RC_SET( FERR_NOT_IMPLEMENTED); goto Exit; #endif } } Exit: if( pucItemBuf) { f_free( (void **)&pucItemBuf); } return( rc); } /**************************************************************************** Desc: Sends a value to the client *****************************************************************************/ RCODE FCS_WIRE::sendString( FLMUINT uiTag, FLMUNICODE * puzString) { RCODE rc = FERR_OK; // Send the parameter tag and value. switch( uiTag) { case WIRE_VALUE_FILE_NAME: case WIRE_VALUE_FILE_PATH: case WIRE_VALUE_FILE_PATH_2: case WIRE_VALUE_FILE_PATH_3: case WIRE_VALUE_DICT_FILE_PATH: case WIRE_VALUE_ITEM_NAME: case WIRE_VALUE_DICT_BUFFER: { uiTag |= WIRE_VALUE_TYPE_UTF << WIRE_VALUE_TYPE_START_BIT; if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) { goto Exit; } if( RC_BAD( rc = m_pDOStream->writeUTF( puzString))) { goto Exit; } break; } default: { #ifdef FLM_DEBUG flmAssert( 0); #else rc = RC_SET( FERR_NOT_IMPLEMENTED); goto Exit; #endif } } Exit: return( rc); } /**************************************************************************** Desc: Sends a value to the client *****************************************************************************/ RCODE FCS_WIRE::sendHTD( FLMUINT uiTag, NODE * pHTD) { RCODE rc = FERR_OK; // Send the parameter tag and value. switch( uiTag) { case WIRE_VALUE_HTD: case WIRE_VALUE_ITERATOR_SELECT: case WIRE_VALUE_ITERATOR_FROM: case WIRE_VALUE_ITERATOR_WHERE: case WIRE_VALUE_ITERATOR_CONFIG: { uiTag |= WIRE_VALUE_TYPE_HTD << WIRE_VALUE_TYPE_START_BIT; if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) { goto Exit; } if( RC_BAD( rc = m_pDOStream->writeHTD( pHTD, NULL, TRUE, m_bSendGedcom))) { goto Exit; } break; } default: { #ifdef FLM_DEBUG flmAssert( 0); #else rc = RC_SET( FERR_NOT_IMPLEMENTED); goto Exit; #endif } } Exit: return( rc); } /**************************************************************************** Desc: Sends a value to the client *****************************************************************************/ RCODE FCS_WIRE::sendHTD( FLMUINT uiTag, FlmRecord * pRecord) { RCODE rc = FERR_OK; // Send the parameter tag and value. switch( uiTag) { case WIRE_VALUE_HTD: { uiTag |= WIRE_VALUE_TYPE_HTD << WIRE_VALUE_TYPE_START_BIT; if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) { goto Exit; } if( RC_BAD( rc = m_pDOStream->writeHTD( NULL, pRecord, FALSE, m_bSendGedcom))) { goto Exit; } break; } default: { #ifdef FLM_DEBUG flmAssert( 0); #else rc = RC_SET( FERR_NOT_IMPLEMENTED); goto Exit; #endif } } Exit: return( rc); } /**************************************************************************** Desc: Copies the current HTD tree to the application's pool *****************************************************************************/ RCODE FCS_WIRE::getHTD( POOL * pPool, NODE ** ppTreeRV) { RCODE rc = FERR_OK; if( !m_pHTD) { *ppTreeRV = NULL; goto Exit; } if( (*ppTreeRV = GedCopy( pPool, GED_FOREST, m_pHTD)) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } Exit: return( rc); } /**************************************************************************** Desc: Sends a value to the client *****************************************************************************/ RCODE FCS_WIRE::sendCreateOpts( FLMUINT uiTag, CREATE_OPTS * pCreateOpts) { NODE * pRootNd = NULL; void * pvMark = GedPoolMark( m_pPool); RCODE rc = FERR_OK; FLMUINT uiTmp; // If no create options, goto exit. if( !pCreateOpts) { rc = RC_SET( FERR_MEM); goto Exit; } // Send the parameter tag and value. switch( uiTag) { case WIRE_VALUE_CREATE_OPTS: { uiTag |= WIRE_VALUE_TYPE_HTD << WIRE_VALUE_TYPE_START_BIT; if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) { goto Exit; } // Build the root node of the CreateOpts tree. if( (pRootNd = GedNodeMake( m_pPool, FCS_COPT_CONTEXT, &rc)) == NULL) { goto Exit; } // Add fields to the tree. if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, FCS_COPT_BLOCK_SIZE, (void *)&pCreateOpts->uiBlockSize, 0, FLM_NUMBER_TYPE))) { goto Exit; } if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, FCS_COPT_MIN_RFL_FILE_SIZE, (void *)&pCreateOpts->uiMinRflFileSize, 0, FLM_NUMBER_TYPE))) { goto Exit; } if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, FCS_COPT_MAX_RFL_FILE_SIZE, (void *)&pCreateOpts->uiMaxRflFileSize, 0, FLM_NUMBER_TYPE))) { goto Exit; } uiTmp = pCreateOpts->bKeepRflFiles ? 1 : 0; if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, FCS_COPT_KEEP_RFL_FILES, (void *)&uiTmp, 0, FLM_NUMBER_TYPE))) { goto Exit; } uiTmp = pCreateOpts->bLogAbortedTransToRfl ? 1 : 0; if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, FCS_COPT_LOG_ABORTED_TRANS, (void *)&uiTmp, 0, FLM_NUMBER_TYPE))) { goto Exit; } if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, FCS_COPT_DEFAULT_LANG, (void *)&pCreateOpts->uiDefaultLanguage, 0, FLM_NUMBER_TYPE))) { goto Exit; } if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, FCS_COPT_VERSION, (void *)&pCreateOpts->uiVersionNum, 0, FLM_NUMBER_TYPE))) { goto Exit; } if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, FCS_COPT_APP_MAJOR_VER, (void *)&pCreateOpts->uiAppMajorVer, 0, FLM_NUMBER_TYPE))) { goto Exit; } if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, FCS_COPT_APP_MINOR_VER, (void *)&pCreateOpts->uiAppMinorVer, 0, FLM_NUMBER_TYPE))) { goto Exit; } // Send the tree. if( RC_BAD( rc = m_pDOStream->writeHTD( pRootNd, NULL, TRUE, m_bSendGedcom))) { goto Exit; } break; } default: { #ifdef FLM_DEBUG flmAssert( 0); #else rc = RC_SET( FERR_NOT_IMPLEMENTED); goto Exit; #endif } } Exit: GedPoolReset( m_pPool, pvMark); return( rc); } /**************************************************************************** Desc: Sends a value to the client *****************************************************************************/ RCODE FCS_WIRE::sendNameTable( FLMUINT uiTag, F_NameTable * pNameTable) { void * pvMark = GedPoolMark( m_pPool); NODE * pRootNd; NODE * pNd; NODE * pItemIdNd; FLMUINT uiMaxNameChars = 1024; FLMUNICODE * puzItemName = NULL; FLMUINT uiId; FLMUINT uiType; FLMUINT uiSubType; FLMUINT uiNextPos; RCODE rc = FERR_OK; // If the name table pointer is invalid, goto exit. if( !pNameTable) { rc = RC_SET( FERR_MEM); goto Exit; } // Allocate a temporary name buffer if( (puzItemName = (FLMUNICODE *)GedPoolAlloc( m_pPool, uiMaxNameChars * sizeof( FLMUNICODE))) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } // Send the parameter tag and value. switch( uiTag) { case WIRE_VALUE_NAME_TABLE: { uiTag |= WIRE_VALUE_TYPE_HTD << WIRE_VALUE_TYPE_START_BIT; if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) { goto Exit; } // Build the root node of the name table tree. if( (pRootNd = GedNodeMake( m_pPool, FCS_NAME_TABLE_CONTEXT, &rc)) == NULL) { goto Exit; } uiNextPos = 0; while( pNameTable->getNextTagNumOrder( &uiNextPos, puzItemName, NULL, uiMaxNameChars * sizeof( FLMUNICODE), &uiId, &uiType, &uiSubType)) { if( (pItemIdNd = GedNodeMake( m_pPool, FCS_NAME_TABLE_ITEM_ID, &rc)) == NULL) { goto Exit; } if( RC_BAD( rc = GedPutUINT( m_pPool, pItemIdNd, uiId))) { goto Exit; } if( (pNd = GedNodeMake( m_pPool, FCS_NAME_TABLE_ITEM_NAME, &rc)) == NULL) { goto Exit; } if( RC_BAD( rc = GedPutUNICODE( m_pPool, pNd, puzItemName))) { goto Exit; } GedChildGraft( pItemIdNd, pNd, GED_LAST); if( (pNd = GedNodeMake( m_pPool, FCS_NAME_TABLE_ITEM_TYPE, &rc)) == NULL) { goto Exit; } if( RC_BAD( rc = GedPutUINT( m_pPool, pNd, uiType))) { goto Exit; } GedChildGraft( pItemIdNd, pNd, GED_LAST); if( (pNd = GedNodeMake( m_pPool, FCS_NAME_TABLE_ITEM_SUBTYPE, &rc)) == NULL) { goto Exit; } if( RC_BAD( rc = GedPutUINT( m_pPool, pNd, uiSubType))) { goto Exit; } GedChildGraft( pItemIdNd, pNd, GED_LAST); // Graft the item into the tree GedChildGraft( pRootNd, pItemIdNd, GED_LAST); // Release CPU to prevent CPU hog f_yieldCPU(); } // Send the tree. if( RC_BAD( rc = m_pDOStream->writeHTD( pRootNd, NULL, TRUE, m_bSendGedcom))) { goto Exit; } break; } default: { #ifdef FLM_DEBUG flmAssert( 0); #else rc = RC_SET( FERR_NOT_IMPLEMENTED); goto Exit; #endif } } Exit: GedPoolReset( m_pPool, pvMark); return( rc); } /**************************************************************************** Desc: Receives a record *****************************************************************************/ RCODE FCS_WIRE::receiveRecord( FlmRecord ** ppRecord) { FLMBYTE ucDescriptor = 0; FLMUINT uiIdLen = 0; FLMUINT32 ui32Container; FLMUINT32 ui32Drn; void * pvMark = GedPoolMark( m_pPool); FLMBOOL bHasId = FALSE; RCODE rc = FERR_OK; // Read the record. if( RC_BAD( rc = m_pDIStream->read( &ucDescriptor, 1, NULL))) { goto Exit; } uiIdLen = (FLMUINT)(ucDescriptor & RECORD_ID_SIZE_MASK); if( uiIdLen != RECORD_ID_SIZE) { rc = RC_SET( FERR_FAILURE); goto Exit; } else if( uiIdLen) { bHasId = TRUE; } // Read the record ID. if( bHasId) { if( RC_BAD( rc = m_pDIStream->readUInt( &ui32Container))) { goto Exit; } if( RC_BAD( rc = m_pDIStream->readUInt( &ui32Drn))) { goto Exit; } } // Read the record. if( (ucDescriptor & RECORD_HAS_HTD_FLAG)) { if( RC_BAD( rc = m_pDIStream->readHTD( m_pPool, ui32Container, ui32Drn, NULL, ppRecord))) { goto Exit; } } Exit: if( RC_BAD( rc) && ppRecord && *ppRecord) { (*ppRecord)->Release(); *ppRecord = NULL; } GedPoolReset( m_pPool, pvMark); return( rc); } /**************************************************************************** Desc: Receives a CREATE_OPTS structure as an HTD tree. *****************************************************************************/ RCODE FCS_WIRE::receiveCreateOpts( void) { NODE * pRootNd; NODE * pTmpNd; void * pPoolMark; FLMUINT fieldPath[ 8]; FLMUINT uiTmp; RCODE rc = FERR_OK; pPoolMark = GedPoolMark( m_pPool); // Initialize the CREATE_OPTS structure to its default values. fcsInitCreateOpts( &m_CreateOpts); // Receive the tree. if( RC_BAD( rc = m_pDIStream->readHTD( m_pPool, 0, 0, &pRootNd, NULL))) { goto Exit; } // Parse the tree and extract the values. fieldPath[ 0] = FCS_COPT_CONTEXT; fieldPath[ 1] = FCS_COPT_BLOCK_SIZE; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &m_CreateOpts.uiBlockSize); } fieldPath[ 0] = FCS_COPT_CONTEXT; fieldPath[ 1] = FCS_COPT_MIN_RFL_FILE_SIZE; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &m_CreateOpts.uiMinRflFileSize); } fieldPath[ 0] = FCS_COPT_CONTEXT; fieldPath[ 1] = FCS_COPT_MAX_RFL_FILE_SIZE; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &m_CreateOpts.uiMaxRflFileSize); } fieldPath[ 0] = FCS_COPT_CONTEXT; fieldPath[ 1] = FCS_COPT_KEEP_RFL_FILES; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &uiTmp); m_CreateOpts.bKeepRflFiles = (FLMBOOL)((uiTmp) ? (FLMBOOL)TRUE : (FLMBOOL)FALSE); } fieldPath[ 0] = FCS_COPT_CONTEXT; fieldPath[ 1] = FCS_COPT_LOG_ABORTED_TRANS; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &uiTmp); m_CreateOpts.bLogAbortedTransToRfl = (FLMBOOL)((uiTmp) ? (FLMBOOL)TRUE : (FLMBOOL)FALSE); } fieldPath[ 0] = FCS_COPT_CONTEXT; fieldPath[ 1] = FCS_COPT_DEFAULT_LANG; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &m_CreateOpts.uiDefaultLanguage); } fieldPath[ 0] = FCS_COPT_CONTEXT; fieldPath[ 1] = FCS_COPT_VERSION; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &m_CreateOpts.uiVersionNum); } fieldPath[ 0] = FCS_COPT_CONTEXT; fieldPath[ 1] = FCS_COPT_APP_MAJOR_VER; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &m_CreateOpts.uiAppMajorVer); } fieldPath[ 0] = FCS_COPT_CONTEXT; fieldPath[ 1] = FCS_COPT_APP_MINOR_VER; fieldPath[ 2] = 0; if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) { (void) GedGetUINT( pTmpNd, &m_CreateOpts.uiAppMinorVer); } Exit: GedPoolReset( m_pPool, pPoolMark); return( rc); } /**************************************************************************** Desc: Receives a name table. *****************************************************************************/ RCODE FCS_WIRE::receiveNameTable( F_NameTable ** ppNameTable) { NODE * pRootNd; NODE * pItemIdNd; NODE * pNd = NULL; void * pvMark = GedPoolMark( m_pPool); FLMUINT uiMaxNameChars = 1024; FLMUNICODE * puzItemName; FLMUINT uiItemId; FLMUINT uiItemType; FLMUINT uiItemSubType; F_NameTable * pNameTable = NULL; FLMBOOL bCreatedTable = FALSE; RCODE rc = FERR_OK; // Allocate a temporary name buffer if( (puzItemName = (FLMUNICODE *)GedPoolAlloc( m_pPool, uiMaxNameChars * sizeof( FLMUNICODE))) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } // Initialize the name table. if( (pNameTable = *ppNameTable) == NULL) { if( (pNameTable = f_new F_NameTable) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } bCreatedTable = TRUE; } else { pNameTable->clearTable(); } // Receive the tree. if( RC_BAD( rc = m_pDIStream->readHTD( m_pPool, 0, 0, &pRootNd, NULL))) { goto Exit; } // Parse the tree and extract the values. pItemIdNd = GedChild( pRootNd); while( pItemIdNd) { if( GedTagNum( pItemIdNd) == FCS_NAME_TABLE_ITEM_ID) { if( RC_BAD( rc = GedGetUINT( pItemIdNd, &uiItemId))) { goto Exit; } uiItemType = 0; uiItemSubType = 0; pNd = GedChild( pItemIdNd); while( pNd) { switch( GedTagNum( pNd)) { case FCS_NAME_TABLE_ITEM_NAME: { FLMUINT uiStrLen = uiMaxNameChars * sizeof( FLMUNICODE); if( RC_BAD( rc = GedGetUNICODE( pNd, puzItemName, &uiStrLen))) { goto Exit; } break; } case FCS_NAME_TABLE_ITEM_TYPE: { if( RC_BAD( rc = GedGetUINT( pNd, &uiItemType))) { goto Exit; } break; } case FCS_NAME_TABLE_ITEM_SUBTYPE: { if( RC_BAD( rc = GedGetUINT( pNd, &uiItemSubType))) { goto Exit; } break; } } pNd = GedSibNext( pNd); } if( puzItemName[ 0]) { if( RC_BAD( rc = pNameTable->addTag( puzItemName, NULL, uiItemId, uiItemType, uiItemSubType, FALSE))) { goto Exit; } } } pItemIdNd = GedSibNext( pItemIdNd); // Release CPU to prevent CPU hog f_yieldCPU(); } pNameTable->sortTags(); *ppNameTable = pNameTable; pNameTable = NULL; Exit: if( pNameTable && bCreatedTable) { pNameTable->Release(); } GedPoolReset( m_pPool, pvMark); return( rc); } /**************************************************************************** Desc: *****************************************************************************/ FCL_WIRE::FCL_WIRE( CS_CONTEXT * pCSContext, FDB * pDb) : FCS_WIRE( pCSContext != NULL ? pCSContext->pIDataStream : NULL, pCSContext != NULL ? pCSContext->pODataStream : NULL) { m_pCSContext = pCSContext; m_pDb = pDb; if( m_pCSContext) { m_bSendGedcom = m_pCSContext->bGedcomSupport; } } /**************************************************************************** Desc: Sets the CS CONTEXT in FCL_WIRE and the I/O streams in FCS_WIRE *****************************************************************************/ void FCL_WIRE::setContext( CS_CONTEXT * pCSContext) { m_pCSContext = pCSContext; m_bSendGedcom = pCSContext->bGedcomSupport; FCS_WIRE::setDIStream( pCSContext->pIDataStream); FCS_WIRE::setDOStream( pCSContext->pODataStream); } /**************************************************************************** Desc: Send a client/server opcode with session id, and optionally the database id ****************************************************************************/ RCODE FCL_WIRE::sendOp( FLMUINT uiClass, FLMUINT uiOp) { RCODE rc = FERR_OK; if (!m_pCSContext->bConnectionGood) { rc = RC_SET( FERR_BAD_SERVER_CONNECTION); goto Exit; } // Send the class and opcode if (RC_BAD( rc = sendOpcode( (FLMBYTE)uiClass, (FLMBYTE)uiOp))) { goto Transmission_Error; } // Send session ID if (RC_BAD( rc = sendNumber( WIRE_VALUE_SESSION_ID, m_pCSContext->uiSessionId))) { goto Transmission_Error; } // Send session cookie if (RC_BAD( rc = sendNumber( WIRE_VALUE_SESSION_COOKIE, m_pCSContext->uiSessionCookie))) { goto Transmission_Error; } // Send operation sequence number m_pCSContext->uiOpSeqNum++; if (RC_BAD( rc = sendNumber( WIRE_VALUE_OP_SEQ_NUM, m_pCSContext->uiOpSeqNum))) { goto Transmission_Error; } Exit: return( rc); Transmission_Error: m_pCSContext->bConnectionGood = FALSE; goto Exit; } /**************************************************************************** Desc: This routine instructs the server to start or end a transaction ****************************************************************************/ RCODE FCL_WIRE::doTransOp( FLMUINT uiOp, FLMUINT uiTransType, FLMUINT uiFlags, FLMUINT uiMaxLockWait, FLMBYTE * pszHeader, FLMBOOL bForceCheckpoint) { FLMUINT uiTransFlags = 0; RCODE rc = FERR_OK; // Send request to server if( RC_BAD( rc = sendOp( FCS_OPCLASS_TRANS, uiOp))) { goto Exit; } if( uiOp == FCS_OP_TRANSACTION_BEGIN) { if (RC_BAD( rc = sendNumber( WIRE_VALUE_TRANSACTION_TYPE, uiTransType))) { goto Transmission_Error; } if (RC_BAD( rc = sendNumber( WIRE_VALUE_MAX_LOCK_WAIT, uiMaxLockWait))) { goto Transmission_Error; } if( pszHeader) { uiTransFlags |= FCS_TRANS_FLAG_GET_HEADER; } if( uiFlags & FLM_DONT_KILL_TRANS) { uiTransFlags |= FCS_TRANS_FLAG_DONT_KILL; } if( uiFlags & FLM_DONT_POISON_CACHE) { uiTransFlags |= FCS_TRANS_FLAG_DONT_POISON; } } else if( uiOp == FCS_OP_TRANSACTION_COMMIT_EX) { if( pszHeader) { if( RC_BAD( rc = sendBinary( WIRE_VALUE_BLOCK, pszHeader, F_TRANS_HEADER_SIZE))) { goto Exit; } } if( bForceCheckpoint) { uiTransFlags |= FCS_TRANS_FORCE_CHECKPOINT; } } if( uiTransFlags) { if (RC_BAD( rc = sendNumber( WIRE_VALUE_FLAGS, uiTransFlags))) { goto Transmission_Error; } } if( RC_BAD( rc = sendTerminate())) { goto Transmission_Error; } // Read the response if( RC_BAD( rc = read())) { goto Transmission_Error; } if (RC_BAD( rc = getRCode())) { goto Exit; } if( pszHeader) { if( getBlockSize()) { f_memcpy( pszHeader, getBlock(), getBlockSize()); } else { f_memset( pszHeader, 0, 2048); } } if (!m_pDb) { m_pCSContext->bTransActive = (FLMBOOL)((uiOp == FCS_OP_TRANSACTION_BEGIN) ? (FLMBOOL)TRUE : (FLMBOOL)FALSE); } Exit: return( rc); Transmission_Error: m_pCSContext->bConnectionGood = FALSE; goto Exit; } /**************************************************************************** Desc: Reads a server response for the client. *****************************************************************************/ RCODE FCL_WIRE::read( void) { FLMUINT uiTag; FLMUINT uiCount = 0; FLMBOOL bDone = FALSE; RCODE rc = FERR_OK; // Read the opcode. if( RC_BAD( rc = readOpcode())) { goto Exit; } // Read the request / response values. for( ;;) { if (RC_BAD( rc = readCommon( &uiTag, &bDone))) { if( rc == FERR_EOF_HIT && !uiCount) { rc = FERR_OK; } goto Exit; } if( bDone) { goto Exit; } // uiTag will be non-zero if readCommon did not understand it. uiCount++; if( uiTag) { switch( (uiTag & WIRE_VALUE_TAG_MASK)) { case WIRE_VALUE_NAME_TABLE: { if( RC_BAD( rc = receiveNameTable( &m_pNameTable))) { goto Exit; } break; } default: { if( RC_BAD( rc = skipValue( uiTag))) { goto Exit; } break; } } } } Exit: if( rc == FERR_EOF_HIT) { rc = RC_SET( FERR_FAILURE); goto Exit; } return( rc); }