/* returns 0 on success , <0 on error */ int sr_load_module(char* path) { void* handle; unsigned int moddlflags; char* error; struct module_exports* exp; struct sr_module* t; /* load module */ handle=dlopen(path, OPENSIPS_DLFLAGS); /* resolve all symbols now */ if (handle==0){ LM_ERR("could not open module <%s>: %s\n", path, dlerror() ); goto error; } /* check for duplicates */ for(t=modules;t; t=t->next){ if (t->handle==handle){ LM_WARN("attempting to load the same module twice (%s)\n", path); goto skip; } } /* import module interface */ exp = (struct module_exports*)dlsym(handle, DLSYM_PREFIX "exports"); if ( (error =(char*)dlerror())!=0 ){ LM_ERR("load_module: %s\n", error); goto error1; } if(exp->dlflags!=DEFAULT_DLFLAGS && exp->dlflags!=OPENSIPS_DLFLAGS) { moddlflags = exp->dlflags; dlclose(handle); LM_DBG("reloading module %s with flags %d\n", path, moddlflags); handle = dlopen(path, moddlflags); if (handle==0){ LM_ERR("could not open module <%s>: %s\n", path, dlerror() ); goto error; } exp = (struct module_exports*)dlsym(handle, DLSYM_PREFIX "exports"); if ( (error =(char*)dlerror())!=0 ){ LM_ERR("failed to load module : %s\n", error); goto error1; } } /* version control */ if (!version_control(exp, path)) { exit(0); } /* launch register */ if (register_module(exp, path, handle)<0) goto error1; return 0; error1: dlclose(handle); error: skip: return -1; }
static int load_static_module(char *path) { int len = strlen(path); char *end = path + len; struct sr_module* t; unsigned int i; /* eliminate the .so, if found */ if (len > 3 && strncmp(end - 3, ".so", 3)==0) { end -= 3; len -= 3; } /* we check whether the protocol is found within the static_modules */ for (i = 0; i < (sizeof(static_modules)/sizeof(static_modules[0])); i++) { if (len >= static_modules[i].name.len && /* the path ends in the module's name */ memcmp(end - static_modules[i].name.len, static_modules[i].name.s, static_modules[i].name.len) == 0 && /* check if the previous char is '/' or nothing */ (len == static_modules[i].name.len || (*(end-len-1) == '/'))) { /* yey, found the module - check if it was loaded twice */ for(t=modules;t; t=t->next){ if (t->handle==static_modules[i].exp){ LM_WARN("attempting to load the same module twice (%s)\n", path); return 0; } } /* version control */ if (!version_control(static_modules[i].exp, path)) { exit(0); } /* launch register */ if (register_module(static_modules[i].exp, path, static_modules[i].exp)<0) return -1; return 0; } } return -1; }
/** * \brief load a sr module * * tries to load the module specified by mod_path. * If mod_path is 'modname' or 'modname.so' then * \<MODS_DIR\>/\<modname\>.so will be tried and if this fails * \<MODS_DIR\>/\<modname\>/\<modname\>.so * If mod_path contain a '/' it is assumed to be the * path to the module and tried first. If fails and mod_path is not * absolute path (not starting with '/') then will try: * \<MODS_DIR\>/mod_path * @param mod_path path or module name * @return 0 on success , <0 on error */ int load_module(char* mod_path) { void* handle; char* error; mod_register_function mr; module_exports_t* exp; struct sr_module* t; struct stat stat_buf; str modname; char* mdir; char* nxt_mdir; char* path; int mdir_len; int len; int dlflags; int new_dlflags; int retries; int path_type; str expref; char exbuf[64]; #ifndef RTLD_NOW /* for openbsd */ #define RTLD_NOW DL_LAZY #endif path=mod_path; path_type = 0; modname.s = path; modname.len = strlen(mod_path); if(modname.len>3 && strcmp(modname.s+modname.len-3, ".so")==0) { path_type = 1; modname.len -= 3; } if (!strchr(path, '/')) path_type |= 2; if((path_type&2) || path[0] != '/') { /* module name was given, we try to construct the path */ mdir=mods_dir; /* search path */ do{ nxt_mdir=strchr(mdir, ':'); if (nxt_mdir) mdir_len=(int)(nxt_mdir-mdir); else mdir_len=strlen(mdir); if(path_type&2) { /* try path <MODS_DIR>/<modname>.so */ path = (char*)pkg_malloc(mdir_len + 1 /* "/" */ + modname.len + 3 /* ".so" */ + 1); if (path==0) goto error; memcpy(path, mdir, mdir_len); len = mdir_len; if (len != 0 && path[len - 1] != '/'){ path[len]='/'; len++; } path[len]=0; strcat(path, modname.s); if(!(path_type&1)) strcat(path, ".so"); if (stat(path, &stat_buf) == -1) { LM_DBG("module file not found <%s>\n", path); pkg_free(path); /* try path <MODS_DIR>/<modname>/<modname>.so */ path = (char*)pkg_malloc( mdir_len + 1 /* "/" */ + modname.len + 1 /* "/" */ + modname.len + 3 /* ".so" */ + 1); if (path==0) goto error; memcpy(path, mdir, mdir_len); len = mdir_len; if (len != 0 && path[len - 1] != '/') { path[len]='/'; len++; } path[len]=0; strncat(path, modname.s, modname.len); strcat(path, "/"); strcat(path, modname.s); if(!(path_type&1)) strcat(path, ".so"); if (stat(path, &stat_buf) == -1) { LM_DBG("module file not found <%s>\n", path); pkg_free(path); path=0; } } } else { /* try mod_path - S compat */ if(path==mod_path) { if (stat(path, &stat_buf) == -1) { LM_DBG("module file not found <%s>\n", path); path=0; } } if(path==0) { /* try path <MODS_DIR>/mod_path - K compat */ path = (char*)pkg_malloc(mdir_len + 1 /* "/" */ + strlen(mod_path) + 1); if (path==0) goto error; memcpy(path, mdir, mdir_len); len = mdir_len; if (len != 0 && path[len - 1] != '/'){ path[len]='/'; len++; } path[len]=0; strcat(path, mod_path); if (stat(path, &stat_buf) == -1) { LM_DBG("module file not found <%s>\n", path); pkg_free(path); path=0; } } } mdir=nxt_mdir?nxt_mdir+1:0; }while(path==0 && mdir); if (path==0){ LM_ERR("could not find module <%.*s> in <%s>\n", modname.len, modname.s, mods_dir); goto error; } } LM_DBG("trying to load <%s>\n", path); retries=2; dlflags=RTLD_NOW; reload: handle=dlopen(path, dlflags); /* resolve all symbols now */ if (handle==0){ LM_ERR("could not open module <%s>: %s\n", path, dlerror()); goto error; } for(t=modules;t; t=t->next){ if (t->handle==handle){ LM_WARN("attempting to load the same module twice (%s)\n", path); goto skip; } } /* version control */ if (!version_control(handle, path)) { exit(-1); } /* launch register */ mr = (mod_register_function)dlsym(handle, "mod_register"); if (((error =(char*)dlerror())==0) && mr) { /* no error call it */ new_dlflags=dlflags; if (mr(path, &new_dlflags, 0, 0)!=0) { LM_ERR("%s: mod_register failed\n", path); goto error1; } if (new_dlflags!=dlflags && new_dlflags!=0) { /* we have to reload the module */ dlclose(handle); dlflags=new_dlflags; retries--; if (retries>0) goto reload; LM_ERR("%s: cannot agree on the dlflags\n", path); goto error; } } exp = (module_exports_t*)dlsym(handle, "exports"); if(exp==NULL) { error =(char*)dlerror(); LM_DBG("attempt to lookup exports structure failed - dlerror: %s\n", (error)?error:"none"); /* 'exports' structure not found, look up for '_modulename_exports' */ mdir = strrchr(mod_path, '/'); if (!mdir) { expref.s = mod_path; } else { expref.s = mdir+1; } expref.len = strlen(expref.s); if(expref.len>3 && strcmp(expref.s+expref.len-3, ".so")==0) expref.len -= 3; snprintf(exbuf, 62, "_%.*s_exports", expref.len, expref.s); LM_DBG("looking up exports with name: %s\n", exbuf); exp = (module_exports_t*)dlsym(handle, exbuf); if(exp==NULL || (error =(char*)dlerror())!=0 ){ LM_ERR("failure for exports symbol: %s - dlerror: %s\n", exbuf, (error)?error:"none"); goto error1; } } /* hack to allow for kamailio style dlflags inside exports */ new_dlflags = exp->dlflags; if (new_dlflags!=dlflags && new_dlflags!=DEFAULT_DLFLAGS) { /* we have to reload the module */ dlclose(handle); DEBUG("%s: exports dlflags interface is deprecated and it will not" " be supported in newer versions; consider using" " mod_register() instead\n", path); dlflags=new_dlflags; retries--; if (retries>0) goto reload; LM_ERR("%s: cannot agree on the dlflags\n", path); goto error; } if (register_module(exp, path, handle)<0) goto error1; return 0; error1: dlclose(handle); error: skip: if (path && path!=mod_path) pkg_free(path); return -1; }
/** * \brief load a sr module * * tries to load the module specified by mod_path. * If mod_path is 'modname' or 'modname.so' then * \<MODS_DIR\>/\<modname\>.so will be tried and if this fails * \<MODS_DIR\>/\<modname\>/\<modname\>.so * If mod_path contain a '/' it is assumed to be the * path to the module and tried first. If fails and mod_path is not * absolute path (not starting with '/') then will try: * \<MODS_DIR\>/mod_path * @param mod_path path or module name * @return 0 on success , <0 on error */ int load_module(char* mod_path) { void* handle; char* error; mod_register_function mr; union module_exports_u* exp; unsigned* mod_if_ver; struct sr_module* t; struct stat stat_buf; str modname; char* mdir; char* nxt_mdir; char* path; int mdir_len; int len; int dlflags; int new_dlflags; int retries; int path_type; #ifndef RTLD_NOW /* for openbsd */ #define RTLD_NOW DL_LAZY #endif path=mod_path; path_type = 0; modname.s = path; modname.len = strlen(mod_path); if(modname.len>3 && strcmp(modname.s+modname.len-3, ".so")==0) { path_type = 1; modname.len -= 3; } if (!strchr(path, '/')) path_type |= 2; if((path_type&2) || path[0] != '/') { /* module name was given, we try to construct the path */ mdir=mods_dir; /* search path */ do{ nxt_mdir=strchr(mdir, ':'); if (nxt_mdir) mdir_len=(int)(nxt_mdir-mdir); else mdir_len=strlen(mdir); if(path_type&2) { /* try path <MODS_DIR>/<modname>.so */ path = (char*)pkg_malloc(mdir_len + 1 /* "/" */ + modname.len + 3 /* ".so" */ + 1); if (path==0) goto error; memcpy(path, mdir, mdir_len); len = mdir_len; if (len != 0 && path[len - 1] != '/'){ path[len]='/'; len++; } path[len]=0; strcat(path, modname.s); if(!(path_type&1)) strcat(path, ".so"); if (stat(path, &stat_buf) == -1) { DBG("load_module: module file not found <%s>\n", path); pkg_free(path); /* try path <MODS_DIR>/<modname>/<modname>.so */ path = (char*)pkg_malloc( mdir_len + 1 /* "/" */ + modname.len + 1 /* "/" */ + modname.len + 3 /* ".so" */ + 1); if (path==0) goto error; memcpy(path, mdir, mdir_len); len = mdir_len; if (len != 0 && path[len - 1] != '/') { path[len]='/'; len++; } path[len]=0; strncat(path, modname.s, modname.len); strcat(path, "/"); strcat(path, modname.s); if(!(path_type&1)) strcat(path, ".so"); if (stat(path, &stat_buf) == -1) { DBG("load_module: module file not found <%s>\n", path); pkg_free(path); path=0; } } } else { /* try mod_path - S compat */ if(path==mod_path) { if (stat(path, &stat_buf) == -1) { DBG("load_module: module file not found <%s>\n", path); path=0; } } if(path==0) { /* try path <MODS_DIR>/mod_path - K compat */ path = (char*)pkg_malloc(mdir_len + 1 /* "/" */ + strlen(mod_path) + 1); if (path==0) goto error; memcpy(path, mdir, mdir_len); len = mdir_len; if (len != 0 && path[len - 1] != '/'){ path[len]='/'; len++; } path[len]=0; strcat(path, mod_path); if (stat(path, &stat_buf) == -1) { DBG("load_module: module file not found <%s>\n", path); pkg_free(path); path=0; } } } mdir=nxt_mdir?nxt_mdir+1:0; }while(path==0 && mdir); if (path==0){ LOG(L_ERR, "ERROR: load_module: could not find module <%.*s> in" " <%s>\n", modname.len, modname.s, mods_dir); goto error; } } DBG("load_module: trying to load <%s>\n", path); retries=2; dlflags=RTLD_NOW; reload: handle=dlopen(path, dlflags); /* resolve all symbols now */ if (handle==0){ LOG(L_ERR, "ERROR: load_module: could not open module <%s>: %s\n", path, dlerror()); goto error; } for(t=modules;t; t=t->next){ if (t->handle==handle){ LOG(L_WARN, "WARNING: load_module: attempting to load the same" " module twice (%s)\n", path); goto skip; } } /* version control */ if (!version_control(handle, path)) { exit(0); } mod_if_ver = (unsigned *)dlsym(handle, DLSYM_PREFIX "module_interface_ver"); if ( (error =(char*)dlerror())!=0 ){ LOG(L_ERR, "ERROR: no module interface version in module <%s>\n", path ); goto error1; } /* launch register */ mr = (mod_register_function)dlsym(handle, DLSYM_PREFIX "mod_register"); if (((error =(char*)dlerror())==0) && mr) { /* no error call it */ new_dlflags=dlflags; if (mr(path, &new_dlflags, 0, 0)!=0) { LOG(L_ERR, "ERROR: load_module: %s: mod_register failed\n", path); goto error1; } if (new_dlflags!=dlflags && new_dlflags!=0) { /* we have to reload the module */ dlclose(handle); dlflags=new_dlflags; retries--; if (retries>0) goto reload; LOG(L_ERR, "ERROR: load_module: %s: cannot agree" " on the dlflags\n", path); goto error; } } exp = (union module_exports_u*)dlsym(handle, DLSYM_PREFIX "exports"); if ( (error =(char*)dlerror())!=0 ){ LOG(L_ERR, "ERROR: load_module: %s\n", error); goto error1; } /* hack to allow for kamailio style dlflags inside exports */ if (*mod_if_ver == 1) { new_dlflags = exp->v1.dlflags; if (new_dlflags!=dlflags && new_dlflags!=DEFAULT_DLFLAGS) { /* we have to reload the module */ dlclose(handle); NOTICE("%s: exports dlflags interface is deprecated and it will not" " be supported in newer versions; consider using" " mod_register() instead\n", path); dlflags=new_dlflags; retries--; if (retries>0) goto reload; LOG(L_ERR, "ERROR: load_module: %s: cannot agree" " on the dlflags\n", path); goto error; } } if (register_module(*mod_if_ver, exp, path, handle)<0) goto error1; return 0; error1: dlclose(handle); error: skip: if (path && path!=mod_path) pkg_free(path); return -1; }