1 // Copyright (C) 2016-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
2 // This Source Code Form is subject to the terms of the Mozilla Public
3 // License, v. 2.0. If a copy of the MPL was not distributed with this
4 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
6 #include <sstream>
7 #include <vector>
8 #include <stdlib.h>
9 #include <iostream>
10
11 #ifdef _WIN32
12 #ifndef _WINSOCKAPI_
13 #include <Windows.h>
14 #endif
15 #else
16 #include <dlfcn.h>
17 #endif
18
19 #include <vsomeip/plugins/application_plugin.hpp>
20 #include <vsomeip/plugins/pre_configuration_plugin.hpp>
21 #include <vsomeip/internal/logger.hpp>
22
23 #include "../include/plugin_manager_impl.hpp"
24
25 #ifdef ANDROID
26 #include "../../configuration/include/internal_android.hpp"
27 #else
28 #include "../../configuration/include/internal.hpp"
29 #endif // ANDROID
30
31 #include "../../utility/include/utility.hpp"
32
33 namespace vsomeip_v3 {
34
35 std::shared_ptr<plugin_manager_impl> plugin_manager_impl::the_plugin_manager__ =
36 std::make_shared<plugin_manager_impl>();
37
get()38 std::shared_ptr<plugin_manager_impl> plugin_manager_impl::get() {
39 return the_plugin_manager__;
40 }
41
plugin_manager_impl()42 plugin_manager_impl::plugin_manager_impl() :
43 plugins_loaded_(false) {
44 }
45
~plugin_manager_impl()46 plugin_manager_impl::~plugin_manager_impl() {
47 handles_.clear();
48 plugins_.clear();
49 }
50
load_plugins()51 void plugin_manager_impl::load_plugins() {
52 {
53 std::lock_guard<std::mutex> its_lock_start_stop(loader_mutex_);
54 if (plugins_loaded_) {
55 return;
56 }
57 plugins_loaded_ = true;
58 }
59
60 // Get plug-ins libraries from environment
61 std::vector<std::string> plugins;
62 const char *its_plugins = getenv(VSOMEIP_ENV_LOAD_PLUGINS);
63 if (nullptr != its_plugins) {
64 std::string token;
65 std::stringstream ss(its_plugins);
66 while(std::getline(ss, token, ',')) {
67 plugins.push_back(token);
68 }
69 }
70
71 std::lock_guard<std::recursive_mutex> its_lock_start_stop(plugins_mutex_);
72 // Load plug-in info from libraries parsed before
73 for (const auto& plugin_name : plugins) {
74 void* handle = load_library(plugin_name);
75 plugin_init_func its_init_func = reinterpret_cast<plugin_init_func>(
76 load_symbol(handle, VSOMEIP_PLUGIN_INIT_SYMBOL));
77 if (its_init_func) {
78 create_plugin_func its_create_func = (*its_init_func)();
79 if (its_create_func) {
80 auto its_plugin = (*its_create_func)();
81 if (its_plugin) {
82 handles_[its_plugin->get_plugin_type()][plugin_name] = handle;
83 switch (its_plugin->get_plugin_type()) {
84 case plugin_type_e::APPLICATION_PLUGIN:
85 if (its_plugin->get_plugin_version()
86 == VSOMEIP_APPLICATION_PLUGIN_VERSION) {
87 add_plugin(its_plugin, plugin_name);
88 } else {
89 VSOMEIP_ERROR << "Plugin version mismatch. "
90 << "Ignoring application plugin "
91 << its_plugin->get_plugin_name();
92 }
93 break;
94 case plugin_type_e::PRE_CONFIGURATION_PLUGIN:
95 if (its_plugin->get_plugin_version()
96 == VSOMEIP_PRE_CONFIGURATION_PLUGIN_VERSION) {
97 add_plugin(its_plugin, plugin_name);
98 } else {
99 VSOMEIP_ERROR << "Plugin version mismatch. Ignoring "
100 << "pre-configuration plugin "
101 << its_plugin->get_plugin_name();
102 }
103 break;
104 default:
105 break;
106 }
107 }
108 }
109 }
110 }
111 }
112
get_plugin(plugin_type_e _type,std::string _name)113 std::shared_ptr<plugin> plugin_manager_impl::get_plugin(plugin_type_e _type, std::string _name) {
114 std::lock_guard<std::recursive_mutex> its_lock_start_stop(plugins_mutex_);
115 auto its_type = plugins_.find(_type);
116 if (its_type != plugins_.end()) {
117 auto its_name = its_type->second.find(_name);
118 if (its_name != its_type->second.end()) {
119 return its_name->second;
120 }
121 }
122 return load_plugin(_name, _type, 1);
123 }
124
load_plugin(const std::string & _library,plugin_type_e _type,uint32_t _version)125 std::shared_ptr<plugin> plugin_manager_impl::load_plugin(const std::string& _library,
126 plugin_type_e _type, uint32_t _version) {
127 void* handle = load_library(_library);
128 plugin_init_func its_init_func = reinterpret_cast<plugin_init_func>(
129 load_symbol(handle, VSOMEIP_PLUGIN_INIT_SYMBOL));
130 if (its_init_func) {
131 create_plugin_func its_create_func = (*its_init_func)();
132 if (its_create_func) {
133 handles_[_type][_library] = handle;
134 auto its_plugin = (*its_create_func)();
135 if (its_plugin) {
136 if (its_plugin->get_plugin_type() == _type
137 && its_plugin->get_plugin_version() == _version) {
138 add_plugin(its_plugin, _library);
139 return its_plugin;
140 } else {
141 VSOMEIP_ERROR << "Plugin version mismatch. Ignoring plugin "
142 << its_plugin->get_plugin_name();
143 }
144 }
145 }
146 }
147 return nullptr;
148 }
149
unload_plugin(plugin_type_e _type)150 bool plugin_manager_impl::unload_plugin(plugin_type_e _type) {
151 std::lock_guard<std::recursive_mutex> its_lock_start_stop(plugins_mutex_);
152 const auto found_handle = handles_.find(_type);
153 if (found_handle != handles_.end()) {
154 for (const auto& its_name : found_handle->second) {
155 #ifdef _WIN32
156 FreeLibrary((HMODULE)its_name.second);
157 #else
158 if (dlclose(its_name.second)) {
159 VSOMEIP_ERROR << "Unloading failed: (" << dlerror() << ")";
160 }
161 #endif
162 }
163 } else {
164 VSOMEIP_ERROR << "plugin_manager_impl::unload_plugin didn't find plugin"
165 << " type:" << (int)_type;
166 return false;
167 }
168 return plugins_.erase(_type);
169 }
170
add_plugin(const std::shared_ptr<plugin> & _plugin,const std::string & _name)171 void plugin_manager_impl::add_plugin(const std::shared_ptr<plugin> &_plugin, const std::string& _name) {
172 plugins_[_plugin->get_plugin_type()][_name] = _plugin;
173 }
174
load_library(const std::string & _path)175 void * plugin_manager_impl::load_library(const std::string &_path) {
176 #ifdef _WIN32
177 return LoadLibrary(_path.c_str());
178 #else
179 return dlopen(_path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
180 #endif
181 }
182
load_symbol(void * _handle,const std::string & _symbol)183 void * plugin_manager_impl::load_symbol(void * _handle,
184 const std::string &_symbol) {
185 void * its_symbol = 0;
186 #ifdef _WIN32
187 HINSTANCE hDLL = (HINSTANCE)_handle;
188 if (hDLL != NULL) {
189
190 typedef UINT(CALLBACK* LPFNDLLFUNC1)(DWORD, UINT);
191
192 LPFNDLLFUNC1 lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL, _symbol.c_str());
193 if (!lpfnDllFunc1) {
194 FreeLibrary(hDLL);
195 std::cerr << "Loading symbol \"" << _symbol << "\" failed (" << GetLastError() << ")" << std::endl;
196 }
197 else {
198 its_symbol = lpfnDllFunc1;
199 }
200 }
201 #else
202 if (0 != _handle) {
203 dlerror(); // Clear previous error
204 its_symbol = dlsym(_handle, _symbol.c_str());
205 const char *dlsym_error = dlerror();
206 if (dlsym_error) {
207 VSOMEIP_INFO << "Cannot load symbol : " << _symbol << " : " << dlsym_error;
208 dlclose(_handle);
209 }
210 } else {
211 VSOMEIP_ERROR << "Loading failed: (" << dlerror() << ")";
212 }
213 #endif
214 return (its_symbol);
215 }
216
217 } // namespace vsomeip_v3
218