00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "DynamicLoader.h"
00026
00027 namespace cmlabs {
00028
00029
00030
00031
00032
00033 DynamicLoader::DynamicLoader() {
00034 clearErrors();
00035 }
00036
00037 DynamicLoader::~DynamicLoader() {
00038 closeAllHandles();
00039 }
00040
00041
00042 bool DynamicLoader::clearErrors() {
00043 #ifdef WIN32
00044 #else // WIN32
00045 dlerror();
00046 dlopen("test", RTLD_NOW);
00047 dlerror();
00048 #endif // WIN32
00049 return true;
00050 }
00051
00052 DLLHandle DynamicLoader::openHandle(JString libname) {
00053
00054
00055 if (libname.length() == 0)
00056 return NULL;
00057
00058 lastErrorMessage = "";
00059 DLLHandle handle = NULL;
00060
00061 #ifdef WIN32
00062 LPVOID lpMsgBuf;
00063 handle = LoadLibrary(libname);
00064 if (handle == NULL) {
00065 FormatMessage(
00066 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
00067 NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00068 (LPTSTR) &lpMsgBuf, 0, NULL);
00069 lastErrorMessage = JString::format("Could not load library '%s': %s\n", (char*) libname, (char*) lpMsgBuf);
00070 LocalFree(lpMsgBuf);
00071
00072 if (!libname.endsWithIgnoreCase(".dll"))
00073 libname += ".dll";
00074
00075 handle = LoadLibrary(libname);
00076 if (handle == NULL) {
00077 FormatMessage(
00078 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
00079 NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00080 (LPTSTR) &lpMsgBuf, 0, NULL);
00081 lastErrorMessage += JString::format("Could not load library '%s': %s\n", (char*) libname, (char*) lpMsgBuf);
00082 LocalFree(lpMsgBuf);
00083
00084 libname = JString::format("../%s", (char*) libname);
00085 handle = LoadLibrary(libname);
00086 if (handle == NULL) {
00087 FormatMessage(
00088 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
00089 NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00090 (LPTSTR) &lpMsgBuf, 0, NULL);
00091 lastErrorMessage += JString::format("Could not load library '%s': %s\n", (char*) libname, (char*) lpMsgBuf);
00092 LocalFree(lpMsgBuf);
00093 }
00094 else
00095 lastErrorMessage = "";
00096 }
00097 else
00098 lastErrorMessage = "";
00099 }
00100 #else // WIN32
00101
00102 const char* errmsg;
00103
00104 JString realLibName;
00105
00106 if (libname.endsWith(".so")) {
00107 realLibName = libname;
00108 }
00109 else {
00110 realLibName = libname + ".so";
00111 if (DEBUGLEVEL(DEBUG)) {
00112 printf("Info: Adding .so to filename: %s\n", (char*)realLibName);
00113 }
00114 }
00115
00116
00117 dlerror();
00118 handle = dlopen(realLibName, RTLD_NOW | RTLD_GLOBAL);
00119 if (handle != NULL)
00120 return handle;
00121 errmsg = dlerror();
00122 lastErrorMessage = JString::format("Could not load library '%s': %s\n", (char*) realLibName, (char*) errmsg);
00123 if (DEBUGLEVEL(DEBUG)) {
00124 printf("Info: First dlopen failed with: %s\n", errmsg);
00125 }
00126
00127 Collection path = realLibName.split("/");
00128 JString rawname = path.getLast();
00129 if (!rawname.startsWith("lib")) {
00130 rawname = JString("lib") + rawname;
00131 path.removeLast();
00132 path.addLast(rawname);
00133 realLibName = path.printListLine("/");
00134 if (DEBUGLEVEL(DEBUG)) {
00135 printf("Info: Adding lib to filename: %s\n", (char*)realLibName);
00136 }
00137 }
00138
00139
00140 dlerror();
00141 handle = dlopen(realLibName, RTLD_NOW);
00142 if (handle != NULL) {
00143 lastErrorMessage = "";
00144 return handle;
00145 }
00146 errmsg = dlerror();
00147 lastErrorMessage += JString::format("Could not load library '%s': %s\n", (char*) realLibName, (char*) errmsg);
00148 if (DEBUGLEVEL(DEBUG)) {
00149 printf("Info: Second dlopen failed with: %s\n", errmsg);
00150 }
00151
00152
00153 realLibName = JString("./") + realLibName;
00154 if (DEBUGLEVEL(DEBUG)) {
00155 printf("Info: Adding ./ to filename: %s\n", (char*)realLibName);
00156 }
00157 dlerror();
00158 handle = dlopen(realLibName, RTLD_NOW);
00159 if (handle != NULL) {
00160 lastErrorMessage = "";
00161 if (DEBUGLEVEL(STATUS)) {
00162 printf("Info: Fetched %s locally by adding ./\n", (char*)realLibName);
00163 }
00164 return handle;
00165 }
00166 errmsg = dlerror();
00167 lastErrorMessage += JString::format("Could not load library '%s': %s\n", (char*) realLibName, (char*) errmsg);
00168
00169 if (DEBUGLEVEL(STATUS)) {
00170 printf("%s\n", (char*) lastErrorMessage);
00171 }
00172 if (handle != NULL)
00173 lastErrorMessage = "";
00174
00175 #endif // WIN32
00176
00177 return handle;
00178 }
00179
00180 bool DynamicLoader::closeHandle(DLLHandle handle) {
00181
00182 if (handle == NULL)
00183 return false;
00184
00185 lastErrorMessage = "";
00186
00187 #ifdef WIN32
00188 FreeLibrary(handle);
00189 #else // WIN32
00190
00191
00192
00193 dlclose(handle);
00194 #endif // WIN32
00195
00196 return true;
00197 }
00198
00199 DLLFunction DynamicLoader::getFunction(DLLHandle handle, JString funcname) {
00200
00201 lastErrorMessage = "";
00202
00203 if (handle == NULL)
00204 return NULL;
00205 if (funcname.length() == 0)
00206 return NULL;
00207
00208 DLLFunction func;
00209
00210 #ifdef WIN32
00211 func = (DLLFunction)GetProcAddress(handle, funcname);
00212 if (func == NULL) {
00213 LPVOID lpMsgBuf;
00214
00215 FormatMessage(
00216 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
00217 NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00218 (LPTSTR) &lpMsgBuf, 0, NULL);
00219 lastErrorMessage = JString::format("Could not find function: %s: %s", (char*) funcname, (char*) lpMsgBuf);
00220
00221 LocalFree(lpMsgBuf);
00222 return NULL;
00223 }
00224 #else // WIN32
00225 const char* errmsg;
00226 dlerror();
00227 func = (DLLFunction)dlsym(handle, funcname);
00228 errmsg = dlerror();
00229 if (errmsg != NULL) {
00230 lastErrorMessage = JString::format("Could not find function: %s: %s", (char*) funcname, (char*) errmsg);
00231 return NULL;
00232 }
00233 #endif // WIN32
00234
00235 return func;
00236 }
00237
00238 bool DynamicLoader::didErrorHappen() {
00239 return (lastErrorMessage.length() > 0);
00240 }
00241
00242 JString DynamicLoader::getLastErrorMessage() {
00243 return lastErrorMessage;
00244 }
00245
00246 bool DynamicLoader::closeAllHandles() {
00247
00248 if (!libMutex.EnterMutex(2000))
00249 return false;
00250
00251 JString key;
00252 LibHandle* lh;
00253 for (int n=0; n<libHandles.getCount(); n++) {
00254 key = libHandles.getKey(n);
00255 lh = (LibHandle*) libHandles.get(key);
00256 if (lh != NULL) {
00257 closeHandle(lh->handle);
00258 }
00259 }
00260 libHandles.removeAll();
00261 libMutex.LeaveMutex();
00262 return true;
00263 }
00264
00265 bool DynamicLoader::loadLibrary(JString libname) {
00266
00267 if (libname.length() == 0)
00268 return false;
00269
00270 if (libHandles.contains(libname)) {
00271 libMutex.LeaveMutex();
00272 return true;
00273 }
00274
00275 if (!libMutex.EnterMutex(2000))
00276 return false;
00277
00278 DLLHandle handle = openHandle(libname);
00279
00280 if (handle == NULL) {
00281 printf("Error: Could not load library '%s' even with advanced name search:\n%s\n", (char*) libname, (char*) lastErrorMessage);
00282 libMutex.LeaveMutex();
00283 return false;
00284 }
00285
00286 LibHandle* lh = new LibHandle();
00287 lh->name = libname;
00288 lh->handle = handle;
00289
00290 libHandles.put(libname, lh);
00291 libMutex.LeaveMutex();
00292 checkLibraryVersion(libname);
00293 return true;
00294 }
00295
00296 bool DynamicLoader::unloadLibrary(JString libname) {
00297
00298 if (libname.length() == 0)
00299 return false;
00300
00301 if (!libMutex.EnterMutex(2000))
00302 return false;
00303
00304 LibHandle* lh = (LibHandle*) libHandles.get(libname);
00305 if (lh == NULL) {
00306 libMutex.LeaveMutex();
00307 return false;
00308 }
00309
00310 closeHandle(lh->handle);
00311 libHandles.remove(libname);
00312 libMutex.LeaveMutex();
00313 return true;
00314 }
00315
00316 bool DynamicLoader::checkLibraryVersion(const JString& libname) {
00317
00318 DLLCheckFunction checkFunc = (DLLCheckFunction)getFunction(libname, "GetLibraryVersion");
00319 JString localVersion = Object::getCoreLibraryVersion();
00320 JString warning;
00321 char* str = NULL;
00322
00323 if (checkFunc == NULL) {
00324 warning = JString::format("Loaded Library CoreLibrary version\ndoes not match the local version: %s\nand is older than version: 1.2.0",
00325 (char*) localVersion);
00326 }
00327 else {
00328 str = checkFunc();
00329 if ((str == NULL) || (strlen(str) == 0)) {
00330 warning = JString::format("Loaded Library CoreLibrary version\ndoes not match the local version: %s\nand is older than version: 1.2.0",
00331 (char*) localVersion);
00332 }
00333 else {
00334 JString version = str;
00335 if (!version.equalsIgnoreCase(localVersion)) {
00336 warning = JString::format("Loaded Library CoreLibrary version: %s\ndoes not match the local version: %s",
00337 (char*) version, (char*) localVersion);
00338 }
00339 }
00340 }
00341 delete [] str;
00342 if (warning.length() > 0) {
00343 printf("\n%s\n\n", (char*) JString::asciiMessage(JString::format("CoreLibrary Version Mismatch: Library '%s'", (char*) libname), warning));
00344 return false;
00345 }
00346 else
00347 return true;
00348 }
00349
00350
00351 DLLFunction DynamicLoader::getFunction(JString libname, JString funcname) {
00352
00353 if (libname.length() == 0)
00354 return NULL;
00355
00356 if (!libMutex.EnterMutex(2000))
00357 return false;
00358 LibHandle* lh = (LibHandle*) libHandles.get(libname);
00359 libMutex.LeaveMutex();
00360 if (lh == NULL) {
00361 loadLibrary(libname);
00362 lh = (LibHandle*) libHandles.get(libname);
00363 if (lh == NULL)
00364 return NULL;
00365 }
00366 return getFunction(lh->handle, funcname);
00367 }
00368
00369 DLLFunction DynamicLoader::getFunction(JString funcname) {
00370
00371 JString libName;
00372
00373 if (funcname.contains("::")) {
00374 Collection oc = funcname.split("::");
00375 libName = oc.get(0);
00376 funcname = oc.get(1);
00377 return getFunction(libName, funcname);
00378 }
00379
00380 DLLFunction func = NULL;
00381 JString key;
00382 for (int n=0; n<libHandles.getCount(); n++) {
00383 key = libHandles.getKey(n);
00384 func = getFunction(key, funcname);
00385 if (func != NULL)
00386 return func;
00387 }
00388 return NULL;
00389 }
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405 LibHandle::LibHandle() : Object() {
00406 handle = NULL;
00407 }
00408
00409 LibHandle::~LibHandle() {
00410 }
00411
00412
00413
00414
00415 bool DynamicLoader::setTestLib(JString lib) {
00416 testlib = lib;
00417 return true;
00418 }
00419
00420 bool DynamicLoader::unitTest() {
00421
00422 DynamicLoader loader;
00423 if (!loader.loadLibrary(testlib)) {
00424 this->addUnitTestLog(JString("Could not load library ") + testlib);
00425 return false;
00426 }
00427
00428 DLLUnitTestFunction func;
00429 func = (DLLUnitTestFunction) loader.getFunction(testlib, "nonexistingfunction");
00430 if (func != NULL) {
00431 this->addUnitTestLog(JString("Could load non-existing function from library ") + testlib);
00432 return false;
00433 }
00434
00435 func = (DLLUnitTestFunction) loader.getFunction(testlib, "unitTest");
00436 if (func == NULL) {
00437 this->addUnitTestLog(JString("Could not load function unittest from library ") + testlib);
00438 return false;
00439 }
00440
00441 ObjectCollection* testCol = new ObjectCollection();
00442 testCol->add(new Message("From", "To", "Type", new TCPLocation("Test", 10000, "Test")));
00443 int ret = func(testCol);
00444 if (ret < 0) {
00445 this->addUnitTestLog(JString("Could not run function unittest from library ") + testlib);
00446 return false;
00447 }
00448
00449 delete(testCol);
00450 testCol = new ObjectCollection();
00451 testCol->add(new Message("From", "To", "Type", new TCPLocation("Test", 10000, "Test")));
00452
00453 for (int n=0; n<100; n++) {
00454 ret = func(testCol);
00455 if (ret < 0) {
00456 this->addUnitTestLog(JString("Could not run function unittest from library ") + testlib);
00457 return false;
00458 }
00459 delete(testCol);
00460 testCol = new ObjectCollection();
00461 testCol->add(new Message("From", "To", "Type", new TCPLocation("Test", 10000, "Test")));
00462 }
00463
00464 delete(testCol);
00465 return true;
00466 }
00467
00468
00469
00470
00471 }