예제 #1
0
/* 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;
}
예제 #2
0
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;
}
예제 #3
0
/**
 * \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;
}
예제 #4
0
/**
 * \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;
}