Branch data Line data Source code
1 : : // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
2 : : //
3 : : // Permission to use, copy, modify, and/or distribute this software for any
4 : : // purpose with or without fee is hereby granted, provided that the above
5 : : // copyright notice and this permission notice appear in all copies.
6 : : //
7 : : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
8 : : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9 : : // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
10 : : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11 : : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
12 : : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13 : : // PERFORMANCE OF THIS SOFTWARE.
14 : :
15 : : #include "factory.h"
16 : :
17 : : #include "data_source.h"
18 : : #include "database.h"
19 : : #include "sqlite3_accessor.h"
20 : : #include "memory_datasrc.h"
21 : :
22 : : #include "datasrc_config.h"
23 : :
24 : : #include <datasrc/logger.h>
25 : :
26 : : #include <dlfcn.h>
27 : : #include <cstdlib>
28 : :
29 : : using namespace std;
30 : : using namespace isc::data;
31 : : using namespace isc::datasrc;
32 : :
33 : : namespace {
34 : : // This helper function takes the 'type' string as passed to
35 : : // the DataSourceClient container below, and, unless it
36 : : // already specifies a specific loadable .so file, will
37 : : // convert the short-name to the full file.
38 : : // I.e. it will add '_ds.so' (if necessary), and prepend
39 : : // it with an absolute path (if necessary).
40 : : // Returns the resulting string to use with LibraryContainer.
41 : : const std::string
42 : 135 : getDataSourceLibFile(const std::string& type) {
43 [ + + ]: 135 : if (type.empty()) {
44 [ + - ]: 2 : isc_throw(DataSourceLibraryError,
45 : : "DataSourceClient container called with empty type value");
46 : : }
47 [ + + ]: 134 : if (type == ".so") {
48 [ + - ]: 2 : isc_throw(DataSourceLibraryError, "DataSourceClient container called "
49 : : "with bad type or file name");
50 : : }
51 : :
52 : : // Type can be either a short name, in which case we need to
53 : : // append "_ds.so", or it can be a direct .so library.
54 : 133 : std::string lib_file = type;
55 [ + - ]: 133 : const int ext_pos = lib_file.rfind(".so");
56 [ + + ][ + + ]: 133 : if (ext_pos == std::string::npos || ext_pos + 3 != lib_file.length()) {
[ + + ]
57 [ + - ]: 128 : lib_file.append("_ds.so");
58 : : }
59 : : // And if it is not an absolute path, prepend it with our
60 : : // loadable backend library path
61 [ + + ]: 133 : if (type[0] != '/') {
62 : : // When running from the build tree, we do NOT want
63 : : // to load the installed loadable library
64 [ + + ]: 128 : if (getenv("B10_FROM_BUILD") != NULL) {
65 : 254 : lib_file = std::string(getenv("B10_FROM_BUILD")) +
66 [ + - ][ + - ]: 254 : "/src/lib/datasrc/.libs/" + lib_file;
67 : : } else {
68 [ + - ]: 2 : lib_file = isc::datasrc::BACKEND_LIBRARY_PATH + lib_file;
69 : : }
70 : : }
71 : 133 : return (lib_file);
72 : : }
73 : : } // end anonymous namespace
74 : :
75 : : namespace isc {
76 : : namespace datasrc {
77 : :
78 : 133 : LibraryContainer::LibraryContainer(const std::string& name) {
79 : : // use RTLD_GLOBAL so that shared symbols (e.g. exceptions)
80 : : // are recognized as such
81 : 133 : ds_lib_ = dlopen(name.c_str(), RTLD_NOW | RTLD_GLOBAL);
82 [ + + ]: 133 : if (ds_lib_ == NULL) {
83 : : // This may cause the filename to appear twice in the actual
84 : : // error, but the output of dlerror is implementation-dependent
85 [ + - ][ + - ]: 24 : isc_throw(DataSourceLibraryError, "dlopen failed for " << name <<
[ + - ][ + - ]
86 : : ": " << dlerror());
87 : : }
88 : 121 : }
89 : :
90 : 121 : LibraryContainer::~LibraryContainer() {
91 : 121 : dlclose(ds_lib_);
92 : 121 : }
93 : :
94 : : void*
95 : 242 : LibraryContainer::getSym(const char* name) {
96 : : // Since dlsym can return NULL on success, we check for errors by
97 : : // first clearing any existing errors with dlerror(), then calling dlsym,
98 : : // and finally checking for errors with dlerror()
99 : 242 : dlerror();
100 : :
101 : 242 : void *sym = dlsym(ds_lib_, name);
102 : :
103 : 242 : const char* dlsym_error = dlerror();
104 [ - + ]: 242 : if (dlsym_error != NULL) {
105 [ # # ]: 0 : isc_throw(DataSourceLibrarySymbolError, dlsym_error);
106 : : }
107 : :
108 : 242 : return (sym);
109 : : }
110 : :
111 : 135 : DataSourceClientContainer::DataSourceClientContainer(const std::string& type,
112 : : ConstElementPtr config)
113 [ + + ]: 164 : : ds_lib_(getDataSourceLibFile(type))
114 : : {
115 : : // We are casting from a data to a function pointer here
116 : : // Some compilers (rightfully) complain about that, but
117 : : // c-style casts are accepted the most here. If we run
118 : : // into any that also don't like this, we might need to
119 : : // use some form of union cast or memory copy to get
120 : : // from the void* to the function pointer.
121 [ + - ]: 121 : ds_creator* ds_create = (ds_creator*)ds_lib_.getSym("createInstance");
122 [ + - ]: 121 : destructor_ = (ds_destructor*)ds_lib_.getSym("destroyInstance");
123 : :
124 : 121 : std::string error;
125 : : try {
126 [ + - ]: 121 : instance_ = ds_create(config, error);
127 [ + + ]: 121 : if (instance_ == NULL) {
128 [ + - ][ + - ]: 58 : isc_throw(DataSourceError, error);
129 : : }
130 : 58 : } catch (const std::exception& exc) {
131 [ - + ][ - + ]: 58 : isc_throw(DataSourceError, "Unknown uncaught exception from " + type +
[ - + ][ - + ]
[ - + ]
132 : : " createInstance: " + exc.what());
133 [ + - ]: 29 : } catch (...) {
134 [ # # ][ # # ]: 0 : isc_throw(DataSourceError, "Unknown uncaught exception from " + type);
[ # # ]
135 : : }
136 : 92 : }
137 : :
138 : 92 : DataSourceClientContainer::~DataSourceClientContainer() {
139 [ + - ]: 92 : destructor_(instance_);
140 : 92 : }
141 : :
142 : : } // end namespace datasrc
143 : 107 : } // end namespace isc
144 : :
|