/* Make a duplicate of a string. */ TA_String *TA_StringDup( TA_StringCache *stringCache, TA_String *string ) { TA_String *str; #if !defined( TA_SINGLE_THREAD ) TA_RetCode retCode; #endif TA_StringCachePriv *stringCachePriv; if( stringCache == NULL ) return NULL; stringCachePriv = (TA_StringCachePriv *)stringCache; if( !string ) return NULL; #if !defined( TA_SINGLE_THREAD ) /* Get the semaphore for this cache. */ retCode = TA_SemaWait( &stringCachePriv->sema ); if( retCode != TA_SUCCESS ) return NULL; #endif str = stringDupInternal( string ); #if !defined( TA_SINGLE_THREAD ) TA_SemaPost( &stringCachePriv->sema ); #endif return str; }
TA_String *TA_StringAlloc_ULong( TA_StringCache *stringCache, unsigned long value ) { TA_StringCachePriv *stringCachePriv; TA_String *retString; #if !defined( TA_SINGLE_THREAD ) TA_RetCode retCode; #endif if( stringCache == NULL ) return NULL; stringCachePriv = (TA_StringCachePriv *)stringCache; #if !defined( TA_SINGLE_THREAD ) /* Get the semaphore for this cache. */ retCode = TA_SemaWait( &stringCachePriv->sema ); if( retCode != TA_SUCCESS ) return NULL; #endif /* The "value" strings are not stored in the cache. * (Because they are known of not being copied often in * the context of TA-LIB). */ retString = valueAllocInternal( value ); #if !defined( TA_SINGLE_THREAD ) TA_SemaPost( &stringCachePriv->sema ); #endif return retString; }
TA_RetCode TA_SetFatalErrorHandler( TA_FatalHandler handler ) { TA_TraceGlobal *global; TA_RetCode retCode; retCode = TA_GetGlobal( &TA_TraceGlobalControl, (void **)&global ); if( retCode != TA_SUCCESS ) return retCode; #if !defined( TA_SINGLE_THREAD ) retCode = TA_SemaWait( &global->callSema ); if( retCode != TA_SUCCESS ) return retCode; #endif global->userHandler = handler; #if !defined( TA_SINGLE_THREAD ) TA_SemaPost( &global->callSema ); #endif return TA_SUCCESS; }
static void internalCheckpoint( TA_TraceGlobal *global, TA_String *key, const char *funcname, const char *filename, unsigned int lineNb ) { #if !defined( TA_SINGLE_THREAD ) TA_RetCode retCode; #endif #ifdef TA_DEBUG TA_TracePosition *tracePosition; #endif /* Make sure there is no tracing while tracing! * In rare occasion, this may prevent to record * some tracing in a multithread environment. * We can live with that compromise. */ if( !TA_IsTraceEnabled() ) return; #if !defined( TA_SINGLE_THREAD ) retCode = TA_SemaWait( &global->callSema ); if( retCode != TA_SUCCESS ) return; #endif #ifdef TA_DEBUG /* If this position is already in the dictionary, just * increment the 'repetition' counter, else create * a new entry in the dictionary. */ TA_TraceDisable(); tracePosition = TA_DictGetValue_S( global->functionCalled, TA_StringToChar(key) ); TA_TraceEnable(); if( tracePosition ) tracePosition->repetition++; else { tracePosition = newTracePosition( funcname, filename, lineNb ); if( !tracePosition ) { #if !defined( TA_SINGLE_THREAD ) TA_SemaPost( &global->callSema ); #endif return; } TA_TraceDisable(); TA_DictAddPair_S( global->functionCalled, key, (void *)tracePosition ); TA_TraceEnable(); } /* Trace position are never deleted, until the library is shutdown. * Make a copy of it in the circular buffer. */ global->codeTrace[global->posForNextTrace] = *tracePosition; #else (void)key; /* Used only when doing debug. */ global->codeTrace[global->posForNextTrace].filename = filename; global->codeTrace[global->posForNextTrace].funcname = funcname; global->codeTrace[global->posForNextTrace].lineNb = lineNb; global->codeTrace[global->posForNextTrace].repetition = 1; #endif /* Move to the next entry in the circular buffer. */ global->posForNextTrace++; if( global->posForNextTrace >= TA_CODE_TRACE_SIZE ) global->posForNextTrace = 0; #if !defined( TA_SINGLE_THREAD ) TA_SemaPost( &global->callSema ); #endif }
void TA_PrivError( unsigned int type, const char *str, const char *filename, const char *date, const char *time, int line, unsigned int j, unsigned int k ) { TA_RetCode retCode; TA_TraceGlobal *global; unsigned int length; retCode = TA_GetGlobal( &TA_TraceGlobalControl, (void **)&global ); if( retCode != TA_SUCCESS ) return; /* If a fatal error already got handled, return * immediatly. */ if( global->fatalErrorRecorded ) return; #if !defined( TA_SINGLE_THREAD ) retCode = TA_SemaWait( &global->callSema ); if( retCode != TA_SUCCESS ) return; #endif /* Double-check inside the critical section. */ if( global->fatalErrorRecorded ) { #if !defined( TA_SINGLE_THREAD ) TA_SemaPost( &global->callSema ); #endif return; } global->fatalErrorRecorded = 1; /* Log the fatal error. */ global->fatalError.position.filename = filename; global->fatalError.position.funcname = NULL; global->fatalError.position.lineNb = line; global->fatalError.position.repetition = 1; global->fatalError.str = NULL; if( str ) { length = strlen( str ) + 1; if( length != 0 ) { global->fatalError.str = (char *)TA_Malloc( length ); memcpy( global->fatalError.str, str, length ); } } global->fatalError.date = date; global->fatalError.time = time; global->fatalError.param1 = j; global->fatalError.param2 = k; global->fatalError.type = type; /* Call the user handler. */ if( global->userHandler ) global->userHandler(); #if !defined( TA_SINGLE_THREAD ) TA_SemaPost( &global->callSema ); #endif }
static TA_RetCode fetchUsingWinInet( TA_NetworkGlobal *global, TA_WebPage *webPage ) { TA_PROLOG TA_RetCode retCode; DWORD retDWORD; LPCTSTR lpszProxyName; TA_WebPageHiddenData *webPageHidden; HINTERNET hSession, hWebPage; TA_TRACE_BEGIN( fetchUsingWinInet ); webPageHidden = (TA_WebPageHiddenData *)webPage->hiddenData; retCode = TA_SUCCESS; /* Will change if an error occured. */ if( !global->connected ) { #if !defined( TA_SINGLE_THREAD ) TA_SemaWait( &global->mutexSema ); #endif /* Check again if connected within the mutex. To avoid * multiple task to initialize at the same time. */ if( !global->connected ) { /* Open and verify connection with a known URL. */ retDWORD = InternetAttemptConnect(0); if( retDWORD != ERROR_SUCCESS ) retCode = TA_NO_INTERNET_CONNECTION; else { /* needed? if( InternetCheckConnection((LPCTSTR)NULL, FLAG_ICC_FORCE_CONNECTION, 0 ) != 0 ) retCode = TA_INTERNET_ACCESS_FAILED; */ /* Ok.. the last step is to get an handle used for * retreiving the Web pages. */ if( webPageHidden->proxyName ) { lpszProxyName = TA_Malloc( 100 + strlen( webPageHidden->proxyName ) ); if( !lpszProxyName ) retCode = TA_ALLOC_ERR; else sprintf( (char *)lpszProxyName, "http=http://%s:%s", webPageHidden->proxyName, webPageHidden->proxyPort? "80":webPageHidden->proxyPort ); } else lpszProxyName = NULL; if( retCode == TA_SUCCESS ) { global->hInternet = InternetOpen( "TA-LIB", INTERNET_OPEN_TYPE_PRECONFIG, lpszProxyName, NULL, 0 ); } if( lpszProxyName ) TA_Free( (void *)lpszProxyName ); } if( !global->hInternet ) webPageHidden->finalErrorCode = GetLastError(); else { /* Success. Set a variable to avoid to connect again. * This variable will also make sure that the hInternet * is freed upon shutdown. */ global->connected = 1; /* Success */ } } #if !defined( TA_SINGLE_THREAD ) TA_SemaPost( &global->mutexSema ); #endif if( retCode != TA_SUCCESS ) { TA_TRACE_RETURN( retCode ); } } if( !global->hInternet ) { /* May be returned in multi-thread situation if * the inital thread did not yet complete or succeed * to establish the internet access. */ TA_TRACE_RETURN( TA_INTERNET_NOT_OPEN_TRY_AGAIN ); } /* Open an internet session. */ hSession = InternetConnect( global->hInternet, webPageHidden->webSiteAddr, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, (unsigned long)INTERNET_SERVICE_HTTP, 0, 0 ); if( !hSession ) { /* Did not work.... mmmm.... always try a second time. */ hSession = InternetConnect( global->hInternet, webPageHidden->webSiteAddr, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, (unsigned long)INTERNET_SERVICE_HTTP, 0, 0 ); } if( !hSession ) { TA_TRACE_RETURN( TA_INTERNET_SERVER_CONNECT_FAILED ); } else { hWebPage = HttpOpenRequest( hSession, "GET", webPageHidden->webSitePage, NULL, NULL, NULL, INTERNET_FLAG_NEED_FILE| INTERNET_FLAG_CACHE_IF_NET_FAIL| INTERNET_FLAG_NO_UI| INTERNET_FLAG_NO_COOKIES| INTERNET_FLAG_RESYNCHRONIZE, 0 ); if( !hWebPage ) retCode = TA_INTERNET_OPEN_REQUEST_FAILED; else { retCode = TA_SetReceiveTimeout( 10000 /* 10 seconds */, hWebPage ); if( retCode == TA_SUCCESS ) { if( !HttpSendRequest( hWebPage, 0, 0, 0, 0 ) ) retCode = TA_INTERNET_SEND_REQUEST_FAILED; else retCode = buildListDataWinInet( webPage, hWebPage ); } InternetCloseHandle( hWebPage ); } InternetCloseHandle( hSession ); } TA_TRACE_RETURN( retCode ); }
static TA_RetCode fetchUsingLibCurl( TA_NetworkGlobal *global, TA_WebPage *webPage ) { TA_PROLOG TA_RetCode retCode; TA_WebPageHiddenData *webPageHidden; const char *string1, *string2, *string3; unsigned int urlLength; char *urlString; CURLcode retValue; long curlInfo; TA_TRACE_BEGIN( fetchUsingLibCurl ); TA_ASSERT( webPage != NULL ); webPageHidden = (TA_WebPageHiddenData *)webPage->hiddenData; /* Open an internet session. */ /* Create the URL. */ string1 = "http://"; urlLength = strlen( string1 ) + 1; if( webPageHidden->webSiteAddr ) { string2 = webPageHidden->webSiteAddr; urlLength += strlen( string2 ); } else string2 = NULL; if( webPageHidden->webSitePage ) { string3 = webPageHidden->webSitePage; urlLength += strlen( string3 ) + 1; } else string3 = NULL; urlString = TA_Malloc( urlLength ); if( !urlString ) { TA_TRACE_RETURN( TA_ALLOC_ERR ); } sprintf( urlString, "%s%s%s%s", string1? string1:"", string2? string2:"", string3 && string3[0] != '/'? "/":"", string3? string3:"" ); /* Serialize the request until a stress testing * application proove that libcurl is multi-thread safe. */ #if !defined( TA_SINGLE_THREAD ) retCode = TA_SemaWait( &global->mutexSema ); if( retCode != TA_SUCCESS ) { TA_Free( urlString ); TA_TRACE_RETURN( retCode ); } #endif /* Specify URL to get */ curl_easy_setopt(global->curlHandle, CURLOPT_URL, urlString ); /* Send all data to the callback function */ curl_easy_setopt(global->curlHandle, CURLOPT_WRITEFUNCTION, libcurlWriteMemoryCallback); /* Specify the opaque data ptr for the callback function */ curl_easy_setopt(global->curlHandle, CURLOPT_FILE, (void *)webPage); /* Fetch it. */ retValue = curl_easy_perform(global->curlHandle); if( retValue == CURLE_OK ) retCode = TA_SUCCESS; else { retValue = curl_easy_getinfo( global->curlHandle, CURLINFO_HTTP_CODE, &curlInfo ); if( retValue == CURLE_OK ) retCode = rfc1945StatusToRetCode( curlInfo ); else retCode = TA_HTTP_SC_UNKNOWN; } #if !defined( TA_SINGLE_THREAD ) TA_SemaPost( &global->mutexSema ); #endif /* Free the url. */ TA_Free( urlString ); TA_TRACE_RETURN( retCode ); }
TA_String *stringAllocNInternal( TA_StringCache *stringCache, const char *string, unsigned int maxNbChar, TA_CharCase caseType ) { TA_String *tmp; unsigned int hashIndex; char *hashEntry; TA_StringCachePriv *stringCachePriv; unsigned int newStringLength; int sameString; unsigned int i; #if !defined( TA_SINGLE_THREAD ) TA_RetCode retCode; #endif if( stringCache == NULL ) return NULL; stringCachePriv = (TA_StringCachePriv *)stringCache; if( !string ) return NULL; hashIndex = calcHash( string, caseType ); TA_ASSERT_RET( hashIndex < NB_CACHE_ENTRY, (TA_String *)NULL ); /* Evaluate the final length of the new string. */ newStringLength = strlen( string ); if( maxNbChar != 0 ) { if( maxNbChar < newStringLength ) newStringLength = maxNbChar; } #if !defined( TA_SINGLE_THREAD ) /* Get the semaphore for this cache. */ retCode = TA_SemaWait( &stringCachePriv->sema ); if( retCode != TA_SUCCESS ) return NULL; #endif /* Check if already in the hash table. If yes, re-use it. */ hashEntry = (char *)stringCachePriv->cache[ hashIndex ]; if( hashEntry && ((unsigned char)hashEntry[0] < 255) ) { /* Check that this is the same string, same size. */ if( (caseType == NO_CASE) && (!strncmp( string, &hashEntry[1], newStringLength)) && (hashEntry[newStringLength+1] == '\0') ) sameString = 1; else if( caseType == PATH ) { sameString = 1; for( i=0; i <= newStringLength && (sameString == 1); i++ ) { if( hashEntry[i+1] == '\0' ) sameString = 0; if( (string[i] != hashEntry[i+1]) && !TA_IsSeparatorChar(string[i]) ) sameString = 0; } if( sameString && (hashEntry[newStringLength+1] != '\0') ) sameString = 0; } else if( caseType == UPPER_CASE ) { sameString = 1; for( i=0; i <= newStringLength && (sameString == 1); i++ ) { if( hashEntry[i+1] == '\0' ) sameString = 0; if( (toupper(string[i]) != hashEntry[i+1]) ) sameString = 0; } if( sameString && (hashEntry[newStringLength+1] != '\0') ) sameString = 0; } else sameString = 0; if( sameString ) { tmp = stringDupInternal( (TA_String *)hashEntry ); #if !defined( TA_SINGLE_THREAD ) TA_SemaPost( &stringCachePriv->sema ); #endif return tmp; } } tmp = stringAllocInternal( string, newStringLength, caseType ); if( tmp != NULL ) { /* Store in cache. */ /* Delete previous entry in the same position in the cache. */ if( hashEntry ) stringFreeInternal( (TA_String *)hashEntry ); /* Keep track of this latest allocation. */ stringCachePriv->cache[hashIndex] = stringDupInternal( tmp ); } #if !defined( TA_SINGLE_THREAD ) TA_SemaPost( &stringCachePriv->sema ); #endif return tmp; }
/* This function return a pointer on the global variable for * a particular module. * If the global variables are NOT initialized, this function will * call the corresponding 'init' function for this module. */ TA_RetCode TA_GetGlobal( const TA_GlobalControl * const control, void **global ) { /* Note: Keep that function simple. * No tracing, no stdio and no assert. */ TA_GlobalModuleId id; TA_RetCode retCode, finalRetCode; const TA_GlobalControl * const locControl = control; /* Validate parameters */ if( !control || !global ) return TA_FATAL_ERR; *global = NULL; id = control->id; if( id >= TA_NB_GLOBAL_ID ) return TA_FATAL_ERR; if( TA_Globals->moduleControl[id].initialize ) { /* This module is already initialized, just return the global. */ *global = TA_Globals->moduleControl[id].global; return TA_SUCCESS; } /* This module did not yet get its global initialized. Let's do it. */ /* Will change if anything happen in the following critical section. */ finalRetCode = TA_SUCCESS; #if !defined( TA_SINGLE_THREAD ) if( !(TA_Globals->moduleControl[id].sema.flags&TA_SEMA_INITIALIZED) ) return TA_FATAL_ERR; retCode = TA_SemaWait( &(TA_Globals->moduleControl[id].sema) ); if( retCode != TA_SUCCESS ) return TA_FATAL_ERR; /* Check again if initialize AFTER we got the semaphore. */ if( !TA_Globals->moduleControl[id].initialize ) { #endif /* The module needs to be initialized. Call the corresponding * 'init' function. */ if( !TA_Globals->moduleControl[id].control ) TA_Globals->moduleControl[id].control = locControl; if( locControl->init ) { retCode = (*locControl->init)( &(TA_Globals->moduleControl[id].global) ); if( retCode != TA_SUCCESS ) finalRetCode = retCode; else TA_Globals->moduleControl[id].initialize = 1; } #if !defined( TA_SINGLE_THREAD ) } retCode = TA_SemaPost( &(TA_Globals->moduleControl[id].sema) ); if( retCode != TA_SUCCESS ) finalRetCode = TA_FATAL_ERR; #endif /* Verify if an error occured inside the critical section. */ if( finalRetCode != TA_SUCCESS ) return finalRetCode; if( TA_Globals->moduleControl[id].initialize ) { /* Ok, everything is now alloc/initialized at this point, simply * return the pointer on the "global variable" for this module. */ *global = TA_Globals->moduleControl[id].global; } else return TA_FATAL_ERR; return TA_SUCCESS; }
TA_RetCode TA_Shutdown( void ) { /* Note: Keep that function simple. * No tracing, no stdio and no assert. */ const TA_GlobalControl *control; unsigned int i; TA_RetCode retCode, finalRetCode; if( TA_Globals->magicNb != TA_LIBC_PRIV_MAGIC_NB ) return TA_LIB_NOT_INITIALIZE; /* Will change if an error occured at any point. */ finalRetCode = TA_SUCCESS; /* Shutdown all the modules who were initialized. * Also destroy the corresponding semaphore. */ for( i=0; i < TA_NB_GLOBAL_ID; i++ ) { /* Disable tracing when starting to shut down * the tracing module. This is to avoid that * the memory module starts do some tracing while we * are shutting down the tracing itself!!! */ if( i == TA_TRACE_GLOBAL_ID ) TA_Globals->traceEnabled = 0; #if !defined( TA_SINGLE_THREAD ) if( TA_Globals->moduleControl[i].sema.flags & TA_SEMA_INITIALIZED ) { retCode = TA_SemaWait( &(TA_Globals->moduleControl[i].sema) ); if( retCode != TA_SUCCESS ) finalRetCode = retCode; #endif /* Just before shutting down the ta_memory module, * free the global string cache. */ if( (i == TA_MEMORY_GLOBAL_ID) && (TA_Globals->dfltCache) ) { retCode = TA_StringCacheFree( TA_Globals->dfltCache ); if( retCode != TA_SUCCESS ) finalRetCode = retCode; } if( TA_Globals->moduleControl[i].initialize ) { control = TA_Globals->moduleControl[i].control; if( control && control->shutdown ) { retCode = (*control->shutdown)( TA_Globals->moduleControl[i].global ); if( retCode != TA_SUCCESS ) finalRetCode = retCode; } TA_Globals->moduleControl[i].initialize = 0; } #if !defined( TA_SINGLE_THREAD ) retCode = TA_SemaDestroy( &(TA_Globals->moduleControl[i].sema) ); if( retCode != TA_SUCCESS ) finalRetCode = retCode; } #endif } /* Initialize to all zero to make sure we invalidate that object. */ memset( TA_Globals, 0, sizeof( TA_LibcPriv ) ); return finalRetCode; }