| /* |
| * loader.c - load platform dependent DSO containing freebl implementation. |
| * |
| * This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| #define _GNU_SOURCE 1 |
| #include "loader.h" |
| #include "prmem.h" |
| #include "prerror.h" |
| #include "prinit.h" |
| #include "prenv.h" |
| #include "blname.c" |
| |
| #include "prio.h" |
| #include "prprf.h" |
| #include <stdio.h> |
| #include "prsystem.h" |
| #include "nsslowhash.h" |
| #include <dlfcn.h> |
| #include "pratom.h" |
| |
| static PRLibrary *blLib; |
| |
| #define LSB(x) ((x)&0xff) |
| #define MSB(x) ((x) >> 8) |
| |
| static const NSSLOWVector *vector; |
| static const char *libraryName = NULL; |
| |
| /* pretty much only glibc uses this, make sure we don't have any depenencies |
| * on nspr.. */ |
| #undef PORT_Alloc |
| #undef PORT_Free |
| #define PORT_Alloc malloc |
| #define PR_Malloc malloc |
| #define PORT_Free free |
| #define PR_Free free |
| #define PR_GetDirectorySeparator() '/' |
| #define PR_LoadLibraryWithFlags(libspec, flags) \ |
| (PRLibrary *)dlopen(libSpec.value.pathname, RTLD_NOW | RTLD_LOCAL) |
| #define PR_GetLibraryFilePathname(name, addr) \ |
| freebl_lowhash_getLibraryFilePath(addr) |
| |
| static char * |
| freebl_lowhash_getLibraryFilePath(void *addr) |
| { |
| Dl_info dli; |
| if (dladdr(addr, &dli) == 0) { |
| return NULL; |
| } |
| return strdup(dli.dli_fname); |
| } |
| |
| /* |
| * The PR_LoadLibraryWithFlags call above defines this variable away, so we |
| * don't need it.. |
| */ |
| #ifdef nodef |
| static const char *NameOfThisSharedLib = |
| SHLIB_PREFIX "freebl" SHLIB_VERSION "." SHLIB_SUFFIX; |
| #endif |
| |
| #include "genload.c" |
| |
| /* This function must be run only once. */ |
| /* determine if hybrid platform, then actually load the DSO. */ |
| static PRStatus |
| freebl_LoadDSO(void) |
| { |
| PRLibrary *handle; |
| const char *name = getLibName(); |
| |
| if (!name) { |
| /*PR_SetError(PR_LOAD_LIBRARY_ERROR,0); */ |
| return PR_FAILURE; |
| } |
| handle = loader_LoadLibrary(name); |
| if (handle) { |
| void *address = dlsym(handle, "NSSLOW_GetVector"); |
| if (address) { |
| NSSLOWGetVectorFn *getVector = (NSSLOWGetVectorFn *)address; |
| const NSSLOWVector *dsoVector = getVector(); |
| if (dsoVector) { |
| unsigned short dsoVersion = dsoVector->version; |
| unsigned short myVersion = NSSLOW_VERSION; |
| if (MSB(dsoVersion) == MSB(myVersion) && |
| LSB(dsoVersion) >= LSB(myVersion) && |
| dsoVector->length >= sizeof(NSSLOWVector)) { |
| vector = dsoVector; |
| libraryName = name; |
| blLib = handle; |
| return PR_SUCCESS; |
| } |
| } |
| } |
| (void)dlclose(handle); |
| } |
| return PR_FAILURE; |
| } |
| |
| static PRCallOnceType loadFreeBLOnce; |
| |
| static void |
| freebl_RunLoaderOnce(void) |
| { |
| /* Don't have NSPR, so can use the real PR_CallOnce, implement a stripped |
| * down version. */ |
| if (loadFreeBLOnce.initialized) { |
| return; |
| } |
| if (__sync_lock_test_and_set(&loadFreeBLOnce.inProgress, 1) == 0) { |
| loadFreeBLOnce.status = freebl_LoadDSO(); |
| loadFreeBLOnce.initialized = 1; |
| } else { |
| /* shouldn't have a lot of takers on the else clause, which is good |
| * since we don't have condition variables yet. |
| * 'initialized' only ever gets set (not cleared) so we don't |
| * need the traditional locks. */ |
| while (!loadFreeBLOnce.initialized) { |
| sleep(1); /* don't have condition variables, just give up the CPU */ |
| } |
| } |
| } |
| |
| static const NSSLOWVector * |
| freebl_InitVector(void) |
| { |
| if (!vector) { |
| freebl_RunLoaderOnce(); |
| } |
| return vector; |
| } |
| |
| const FREEBLVector * |
| FREEBL_GetVector(void) |
| { |
| if (freebl_InitVector()) { |
| return (vector->p_FREEBL_GetVector)(); |
| } |
| return NULL; |
| } |
| |
| NSSLOWInitContext * |
| NSSLOW_Init(void) |
| { |
| if (freebl_InitVector()) { |
| return (vector->p_NSSLOW_Init)(); |
| } |
| return NULL; |
| } |
| |
| void |
| NSSLOW_Shutdown(NSSLOWInitContext *context) |
| { |
| if (freebl_InitVector()) { |
| (vector->p_NSSLOW_Shutdown)(context); |
| } |
| } |
| |
| void |
| NSSLOW_Reset(NSSLOWInitContext *context) |
| { |
| if (freebl_InitVector()) { |
| (vector->p_NSSLOW_Reset)(context); |
| } |
| } |
| |
| NSSLOWHASHContext * |
| NSSLOWHASH_NewContext( |
| NSSLOWInitContext *initContext, |
| HASH_HashType hashType) |
| { |
| if (freebl_InitVector()) { |
| return (vector->p_NSSLOWHASH_NewContext)(initContext, hashType); |
| } |
| return NULL; |
| } |
| |
| void |
| NSSLOWHASH_Begin(NSSLOWHASHContext *context) |
| { |
| if (freebl_InitVector()) { |
| (vector->p_NSSLOWHASH_Begin)(context); |
| } |
| } |
| |
| void |
| NSSLOWHASH_Update(NSSLOWHASHContext *context, |
| const unsigned char *buf, |
| unsigned int len) |
| { |
| if (freebl_InitVector()) { |
| (vector->p_NSSLOWHASH_Update)(context, buf, len); |
| } |
| } |
| |
| void |
| NSSLOWHASH_End(NSSLOWHASHContext *context, |
| unsigned char *buf, |
| unsigned int *ret, unsigned int len) |
| { |
| if (freebl_InitVector()) { |
| (vector->p_NSSLOWHASH_End)(context, buf, ret, len); |
| } |
| } |
| |
| void |
| NSSLOWHASH_Destroy(NSSLOWHASHContext *context) |
| { |
| if (freebl_InitVector()) { |
| (vector->p_NSSLOWHASH_Destroy)(context); |
| } |
| } |
| |
| unsigned int |
| NSSLOWHASH_Length(NSSLOWHASHContext *context) |
| { |
| if (freebl_InitVector()) { |
| return (vector->p_NSSLOWHASH_Length)(context); |
| } |
| return -1; |
| } |