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