/****************************************************************************** * Copyright (c) 2000-2020 Ericsson Telecom AB * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * Contributors: * Balasko, Jeno * Delic, Adam * Raduly, Csaba * ******************************************************************************/ #include "LoggerPlugin.hh" #include "ILoggerPlugin.hh" #include <assert.h> #include <dlfcn.h> boolean str_ends_with(const char *str, const char *suffix) { if (!str || !suffix) return FALSE; size_t lenstr = strlen(str); size_t lensuffix = strlen(suffix); if (lensuffix > lenstr) return FALSE; return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0; } enum SoType { RT1_SINGLE, RT1_PARALLEL, RT2_SINGLE, RT2_PARALLEL }; // determine the library type from the name ending SoType get_so_type(const char* filename) { if (str_ends_with(filename, "-rt2.so")) { return str_ends_with(filename, "-parallel-rt2.so") ? RT2_PARALLEL : RT2_SINGLE; } else { // rt1 return str_ends_with(filename, "-parallel.so") ? RT1_PARALLEL : RT1_SINGLE; } } void LoggerPlugin::load() { if (this->filename_) { // determine the required library boolean single_mode = TTCN_Runtime::is_single(); #ifndef TITAN_RUNTIME_2 const SoType required_so_type = single_mode ? RT1_SINGLE : RT1_PARALLEL; const char* required_suffix_str = single_mode ? ".so" : "-parallel.so"; const char* required_runtime_str = single_mode ? "Load Test Single Mode Runtime" : "Load Test Parallel Mode Runtime"; #else const SoType required_so_type = single_mode ? RT2_SINGLE : RT2_PARALLEL; const char* required_suffix_str = single_mode ? "-rt2.so" : "-parallel-rt2.so"; const char* required_runtime_str = single_mode ? "Function Test Single Mode Runtime" : "Function Test Parallel Mode Runtime"; #endif // if the provided filename ends with .so it is assumed to be a full file name, // otherwise it's assumed to be the base of the file name that has to be suffixed automatically expstring_t real_filename = mcopystr(this->filename_); if (str_ends_with(this->filename_,".so")) { // check if the filename is correct if (get_so_type(this->filename_)!=required_so_type) { TTCN_Logger::fatal_error("Incorrect plugin file name was provided (%s). " "This executable is linked with the %s, the matching plugin file name must end with `%s'. " "Note: if the file name ending is omitted it will be automatically appended.", this->filename_, required_runtime_str, required_suffix_str); } } else { // add the appropriate suffix if the filename extension was not provided real_filename = mputstr(real_filename, required_suffix_str); } // Dynamic plug-in. Try to resolve all symbols, die early with RTLD_NOW. this->handle_ = dlopen(real_filename, RTLD_NOW); if (!this->handle_) { TTCN_Logger::fatal_error("Unable to load plug-in %s with file name %s (%s)", this->filename_, real_filename, dlerror()); } Free(real_filename); cb_create_plugin create_plugin = (cb_create_plugin)(unsigned long)dlsym(this->handle_, "create_plugin"); if (!create_plugin) return; this->ref_ = (*create_plugin)(); } else { // Static plug-in. We simply instantiate the class without any `dl*()'. assert(this->create_); this->ref_ = this->create_(); } this->ref_->init(); this->is_log2str_capable_ = this->ref_->is_log2str_capable(); } // Completely destroy the logger plug-in and make it useless. However, // reloading is possible. This should be called before the logger is // deleted. void LoggerPlugin::unload() { if (!this->ref_) return; this->ref_->fini(); if (this->filename_) { cb_destroy_plugin destroy_plugin = (cb_destroy_plugin)(unsigned long)dlsym(this->handle_, "destroy_plugin"); if (destroy_plugin) { (*destroy_plugin)(this->ref_); } dlclose(this->handle_); this->handle_ = NULL; } else { // For static plug-ins, it's simple. delete this->ref_; this->create_ = NULL; } this->ref_ = NULL; }