ADUC_Result ExtensionManager::LoadExtensionLibrary()

in src/extensions/extension_manager/src/extension_manager.cpp [68:189]


ADUC_Result ExtensionManager::LoadExtensionLibrary(
    const char* extensionName,
    const char* extensionPath,
    const char* extensionSubfolder,
    const char* extensionRegFileName,
    const char* requiredFunction,
    int facilityCode,
    int componentCode,
    void** libHandle)
{
    ADUC_Result result{ ADUC_GeneralResult_Failure };
    ADUC_FileEntity entity = {};
    SHAversion algVersion;

    std::stringstream path;
    path << extensionPath << "/" << extensionSubfolder << "/" << extensionRegFileName;

    Log_Info("Loading extension '%s'. Reg file : %s", extensionName, path.str().c_str());

    if (libHandle == nullptr)
    {
        Log_Error("Invalid argument(s).");
        result.ExtendedResultCode = ADUC_ERC_EXTENSION_CREATE_FAILURE_INVALID_ARG(facilityCode, componentCode);
        goto done;
    }

    // Try to find cached handler.
    if (ExtensionManager::_libs.count(extensionName) > 0)
    {
        try
        {
            *libHandle = ExtensionManager::_libs.at(extensionName);
            result.ResultCode = ADUC_Result_Success;
            goto done;
        }
        catch (const std::exception& ex)
        {
            Log_Debug("An exception occurred: %s", ex.what());
        }
        catch (...)
        {
            Log_Debug("Unknown exception occurred while try to reuse '%s'", extensionName);
        }
    }

    memset(&entity, 0, sizeof(entity));

    if (!GetExtensionFileEntity(path.str().c_str(), &entity))
    {
        Log_Info("Failed to load extension from '%s'.", path.str().c_str());
        result.ExtendedResultCode = ADUC_ERC_EXTENSION_CREATE_FAILURE_NOT_FOUND(facilityCode, componentCode);
        goto done;
    }

    // Validate file hash.
    if (!ADUC_HashUtils_GetShaVersionForTypeString(
            ADUC_HashUtils_GetHashType(entity.Hash, entity.HashCount, 0), &algVersion))
    {
        Log_Error(
            "FileEntity for %s has unsupported hash type %s",
            entity.TargetFilename,
            ADUC_HashUtils_GetHashType(entity.Hash, entity.HashCount, 0));
        result.ExtendedResultCode = ADUC_ERC_EXTENSION_CREATE_FAILURE_VALIDATE(facilityCode, componentCode);
        goto done;
    }

    if (!ADUC_HashUtils_IsValidFileHash(
            entity.TargetFilename,
            ADUC_HashUtils_GetHashValue(entity.Hash, entity.HashCount, 0),
            algVersion,
            true /* suppressErrorLog */))
    {
        Log_Error("Hash for %s is not valid", entity.TargetFilename);
        result.ExtendedResultCode = ADUC_ERC_EXTENSION_CREATE_FAILURE_VALIDATE(facilityCode, componentCode);
        goto done;
    }

    *libHandle = ADUCPAL_dlopen(entity.TargetFilename, RTLD_LAZY);

    if (*libHandle == nullptr)
    {
        Log_Error("Cannot load handler file %s. %s.", entity.TargetFilename, ADUCPAL_dlerror());
        result.ExtendedResultCode = ADUC_ERC_EXTENSION_CREATE_FAILURE_LOAD(facilityCode, componentCode);
        goto done;
    }

    ADUCPAL_dlerror(); // Clear any existing error

    // Only check whether required function exist, if specified.
    if (requiredFunction != nullptr && *requiredFunction != '\0')
    {
        void* reqFunc = ADUCPAL_dlsym(*libHandle, requiredFunction);

        if (reqFunc == nullptr)
        {
            Log_Error("The specified function ('%s') doesn't exist. %s", requiredFunction, ADUCPAL_dlerror());
            result.ExtendedResultCode =
                ADUC_ERC_EXTENSION_FAILURE_REQUIRED_FUNCTION_NOTIMPL(facilityCode, componentCode);
            goto done;
        }
    }

    // Cache the loaded library.
    ExtensionManager::_libs.emplace(extensionName, *libHandle);

    result = { ADUC_Result_Success };

done:
    if (IsAducResultCodeFailure(result.ResultCode))
    {
        if (*libHandle != nullptr)
        {
            ADUCPAL_dlclose(*libHandle);
            *libHandle = nullptr;
        }
    }

    // Done with file entity.
    ADUC_FileEntity_Uninit(&entity);

    return result;
}