summaryrefslogtreecommitdiff
path: root/implementation/plugin/src/plugin_manager_impl.cpp
blob: bfaf27281e49f3e298fd6e6b74a0f4cfb89b4244 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
// Copyright (C) 2016-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// 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/.

#include <sstream>
#include <vector>
#include <stdlib.h>
#include <iomanip>
#include <iostream>

#ifdef _WIN32
    #ifndef _WINSOCKAPI_
        #include <Windows.h>
    #endif
#else
    #include <dlfcn.h>
#endif

#include <vsomeip/plugins/application_plugin.hpp>
#include <vsomeip/plugins/pre_configuration_plugin.hpp>
#include <vsomeip/internal/logger.hpp>

#include "../include/plugin_manager_impl.hpp"

#ifdef ANDROID
#include "../../configuration/include/internal_android.hpp"
#else
#include "../../configuration/include/internal.hpp"
#endif // ANDROID

#include "../../utility/include/utility.hpp"

namespace vsomeip_v3 {

std::shared_ptr<plugin_manager_impl> plugin_manager_impl::the_plugin_manager__ =
        std::make_shared<plugin_manager_impl>();

std::shared_ptr<plugin_manager_impl> plugin_manager_impl::get() {
    return the_plugin_manager__;
}

plugin_manager_impl::plugin_manager_impl() :
        plugins_loaded_(false) {
}

plugin_manager_impl::~plugin_manager_impl() {
    handles_.clear();
    plugins_.clear();
}

void plugin_manager_impl::load_plugins() {
    {
        std::lock_guard<std::mutex> its_lock_start_stop(loader_mutex_);
        if (plugins_loaded_) {
            return;
        }
        plugins_loaded_ = true;
    }

    // Get plug-ins libraries from environment
    std::vector<std::string> plugins;
    const char *its_plugins = getenv(VSOMEIP_ENV_LOAD_PLUGINS);
    if (nullptr != its_plugins) {
        std::string token;
        std::stringstream ss(its_plugins);
        while(std::getline(ss, token, ',')) {
            plugins.push_back(token);
        }
    }

    std::lock_guard<std::recursive_mutex> its_lock_start_stop(plugins_mutex_);
    // Load plug-in info from libraries parsed before
    for (const auto& plugin_name : plugins) {
        void* handle = load_library(plugin_name);
        plugin_init_func its_init_func =  reinterpret_cast<plugin_init_func>(
                load_symbol(handle, VSOMEIP_PLUGIN_INIT_SYMBOL));
        if (its_init_func) {
            create_plugin_func its_create_func = (*its_init_func)();
            if (its_create_func) {
                auto its_plugin = (*its_create_func)();
                if (its_plugin) {
                    handles_[its_plugin->get_plugin_type()][plugin_name] = handle;
                    switch (its_plugin->get_plugin_type()) {
                    case plugin_type_e::APPLICATION_PLUGIN:
                        if (its_plugin->get_plugin_version()
                                == VSOMEIP_APPLICATION_PLUGIN_VERSION) {
                            add_plugin(its_plugin, plugin_name);
                        } else {
                            VSOMEIP_ERROR << "Plugin version mismatch. "
                                    << "Ignoring application plugin "
                                    << its_plugin->get_plugin_name();
                        }
                        break;
                    case plugin_type_e::PRE_CONFIGURATION_PLUGIN:
                        if (its_plugin->get_plugin_version()
                                == VSOMEIP_PRE_CONFIGURATION_PLUGIN_VERSION) {
                            add_plugin(its_plugin, plugin_name);
                        } else {
                            VSOMEIP_ERROR << "Plugin version mismatch. Ignoring "
                                    << "pre-configuration plugin "
                                    << its_plugin->get_plugin_name();
                        }
                        break;
                    default:
                        break;
                    }
                }
            }
        }
    }
}

std::shared_ptr<plugin> plugin_manager_impl::get_plugin(plugin_type_e _type,
                                                                const std::string &_name) {
    std::lock_guard<std::recursive_mutex> its_lock_start_stop(plugins_mutex_);
    auto its_type = plugins_.find(_type);
    if (its_type != plugins_.end()) {
        auto its_name = its_type->second.find(_name);
        if (its_name != its_type->second.end()) {
            return its_name->second;
        }
    }
    return load_plugin(_name, _type, 1);
}

std::shared_ptr<plugin> plugin_manager_impl::load_plugin(const std::string& _library,
        plugin_type_e _type, uint32_t _version) {
    void* handle = load_library(_library);
    plugin_init_func its_init_func = reinterpret_cast<plugin_init_func>(
            load_symbol(handle, VSOMEIP_PLUGIN_INIT_SYMBOL));
    if (its_init_func) {
        create_plugin_func its_create_func = (*its_init_func)();
        if (its_create_func) {
            handles_[_type][_library] = handle;
            auto its_plugin = (*its_create_func)();
            if (its_plugin) {
                if (its_plugin->get_plugin_type() == _type
                        && its_plugin->get_plugin_version() == _version) {
                    add_plugin(its_plugin, _library);
                    return its_plugin;
                } else {
                    VSOMEIP_ERROR << "Plugin version mismatch. Ignoring plugin "
                            << its_plugin->get_plugin_name();
                }
            }
        }
    }
    return nullptr;
}

bool plugin_manager_impl::unload_plugin(plugin_type_e _type) {
    std::lock_guard<std::recursive_mutex> its_lock_start_stop(plugins_mutex_);
    const auto found_handle = handles_.find(_type);
    if (found_handle != handles_.end()) {
        for (const auto& its_name : found_handle->second) {
#ifdef _WIN32
            FreeLibrary((HMODULE)its_name.second);
#else
            if (dlclose(its_name.second)) {
                VSOMEIP_ERROR << "Unloading failed: (" << dlerror() << ")";
            }
#endif
        }
    } else {
        VSOMEIP_ERROR << "plugin_manager_impl::unload_plugin didn't find plugin"
                << " type:" << (int)_type;
        return false;
    }
    return plugins_.erase(_type);
}

void plugin_manager_impl::add_plugin(const std::shared_ptr<plugin> &_plugin, const std::string& _name) {
    plugins_[_plugin->get_plugin_type()][_name] = _plugin;
}

void * plugin_manager_impl::load_library(const std::string &_path) {
#ifdef _WIN32
    return LoadLibrary(_path.c_str());
#else
    return dlopen(_path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
#endif
}

void * plugin_manager_impl::load_symbol(void * _handle, const std::string &_symbol_name) {
    void* symbol = nullptr;
    if (_handle) {
#ifdef _WIN32
        symbol = GetProcAddress(reinterpret_cast<HMODULE>(_handle), _symbol_name.c_str());
#else
        symbol = dlsym(_handle, _symbol_name.c_str());
#endif

        if (!symbol) {
            char* error_message = nullptr;

#ifdef _WIN32
            DWORD error_code = GetLastError();
            FormatMessageA(
                FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                nullptr,
                error_code,
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                reinterpret_cast<LPSTR>(&error_message),
                0,
                nullptr
            );
#else
            error_message = dlerror();
#endif

            VSOMEIP_ERROR << "Cannot load symbol " << std::quoted(_symbol_name) << " because: " << error_message;

#ifdef _WIN32
            // Required to release memory allocated by FormatMessageA()
            LocalFree(error_message);
#endif
        }
    }
    return symbol;
}

void plugin_manager_impl::unload_library(void * _handle) {
    if (_handle) {
#ifdef _WIN32
        FreeLibrary(reinterpret_cast<HMODULE>(_handle));
#else
        dlclose(_handle);
#endif
    }
}

} // namespace vsomeip_v3