242 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			242 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Yet another daemon library especially designed to be used
 | |
|  * with libsxmp based daemons.
 | |
|  *
 | |
|  * (c) Alexander Vdolainen 2016 <avdolainen@zoho.com>
 | |
|  *
 | |
|  * libsxmp is free software: you can redistribute it and/or modify it
 | |
|  * under the terms of the GNU Lesser General Public License as published
 | |
|  * by the Free Software Foundation, either version 3 of the License, or
 | |
|  * (at your option) any later version.
 | |
|  *
 | |
|  * libsxmp is distributed in the hope that it will be useful, but
 | |
|  * WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 | |
|  * See the GNU Lesser General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU Lesser General Public License
 | |
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.";
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <stdio.h>
 | |
| #include <errno.h>
 | |
| #include <string.h>
 | |
| #include <pthread.h>
 | |
| #include <ctype.h>
 | |
| #include <dlfcn.h>
 | |
| 
 | |
| #include <tdata/usrtc.h>
 | |
| #include <sexpr/sexp.h>
 | |
| 
 | |
| #include <ydaemon/ydaemon.h>
 | |
| 
 | |
| int yd_mod_add(yd_context_t *ctx, const char *name, yd_mod_type_t type)
 | |
| {
 | |
|   yd_mod_t *mod = malloc(sizeof(yd_mod_t));
 | |
|   usrtc_node_t *node = NULL;
 | |
|   int r = 0;
 | |
| 
 | |
|   if(!mod) return ENOMEM;
 | |
|   else if(!(mod->name = strdup(name))) {
 | |
|     free(mod);
 | |
|     return ENOMEM;
 | |
|   }
 | |
|   mod->type = type;
 | |
|   usrtc_node_init(&mod->node, mod);
 | |
| 
 | |
|   yd_mod_ctx_wrlock(ctx);
 | |
|   node = usrtc_lookup(ctx->modules, mod->name);
 | |
|   if(node) r = EEXIST;
 | |
|   else usrtc_insert(ctx->modules, &mod->node, mod->name);
 | |
|   yd_mod_ctx_unlock(ctx);
 | |
| 
 | |
|   return r;
 | |
| }
 | |
| 
 | |
| int yd_mod_load(yd_context_t *ctx, yd_mod_t *mod)
 | |
| {
 | |
|   char buf[256];
 | |
|   int r = 0;
 | |
| 
 | |
|   /* let's try to find it and load */
 | |
|   if(!mod->pathname || !mod->name) return EINVAL;
 | |
| 
 | |
|   if(!(mod->dlhandle = dlopen(mod->pathname, RTLD_LAZY|RTLD_GLOBAL)))
 | |
|     return ENOENT;
 | |
| 
 | |
|   /* ok now we can resolve all symbols */
 | |
|   snprintf(buf, 256, "%s_preinit", mod->prefix);
 | |
|   mod->preinit = dlsym(mod->dlhandle, buf);
 | |
|   if(!mod->preinit) {
 | |
|   __einval:
 | |
|     dlclose(mod->dlhandle);
 | |
|     return EINVAL;
 | |
|   }
 | |
| 
 | |
|   snprintf(buf, 256, "%s_init", mod->prefix);
 | |
|   if(!(mod->init = dlsym(mod->dlhandle, buf))) goto __einval;
 | |
|   snprintf(buf, 256, "%s_run", mod->prefix);
 | |
|   if(!(mod->run = dlsym(mod->dlhandle, buf))) goto __einval;
 | |
|   snprintf(buf, 256, "%s_shutdown", mod->prefix);
 | |
|   if(!(mod->shutdown = dlsym(mod->dlhandle, buf))) goto __einval;
 | |
|   snprintf(buf, 256, "%s_getobject", mod->prefix);
 | |
|   if(!(mod->getobject = dlsym(mod->dlhandle, buf))) goto __einval;
 | |
| 
 | |
|   if((r = mod->preinit(ctx))) {
 | |
|     blub;
 | |
|   __fail:
 | |
|     dlclose(mod->dlhandle);
 | |
|     return r;
 | |
|   }
 | |
| 
 | |
|   if(mod->cnfname) {
 | |
|     blub;
 | |
|     r = yd_eval_ctx(ctx, (const char *)mod->cnfname);
 | |
|     if(r) goto __fail;
 | |
|   }
 | |
| 
 | |
|   if((r = mod->init(ctx))) goto __fail;
 | |
| 
 | |
|   if(mod->type == YD_SERVICE_MUX) {
 | |
|     if((r = mod->run(ctx))) goto __fail;
 | |
|   }
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int yd_mod_get(yd_context_t *ctx, const char *name, yd_mod_t **rmod)
 | |
| {
 | |
|   int r = 0;
 | |
|   usrtc_node_t *node;
 | |
| 
 | |
|   yd_mod_ctx_rdlock(ctx);
 | |
|   node = usrtc_lookup(ctx->modules, name);
 | |
|   if(!node) r = ENOENT;
 | |
|   else *rmod = (yd_mod_t *)usrtc_node_getdata(node);
 | |
|   yd_mod_ctx_unlock(ctx);
 | |
| 
 | |
|   return r;
 | |
| }
 | |
| 
 | |
| int yd_mod_run(yd_context_t *ctx, yd_mod_t *mod)
 | |
| {
 | |
|   return mod->run(ctx);
 | |
| }
 | |
| 
 | |
| int yd_mod_shutdown(yd_context_t *ctx, yd_mod_t *mod)
 | |
| {
 | |
|   return mod->shutdown(ctx);
 | |
| }
 | |
| 
 | |
| void *yd_mod_getobject(yd_context_t *ctx, yd_mod_t *mod,
 | |
|                        void *priv, const char *name)
 | |
| {
 | |
|   return mod->getobject(priv, name);
 | |
| }
 | |
| 
 | |
| void *yd_mod_getsym(yd_context_t *ctx, yd_mod_t *mod, const char *name)
 | |
| {
 | |
|   return dlsym(mod->dlhandle, name);
 | |
| }
 | |
| 
 | |
| /* object store */
 | |
| 
 | |
| static long __cmp_cstr(const void *a, const void *b)
 | |
| {
 | |
|   return strcmp((const char *)a, (const char *)b);
 | |
| }
 | |
| 
 | |
| #define __obs_wrlock(s)  pthread_rwlock_wrlock(&((s)->rwlock))
 | |
| #define __obs_rdlock(s)  pthread_rwlock_rdlock(&((s)->rwlock))
 | |
| #define __obs_unlock(s)  pthread_rwlock_unlock(&((s)->rwlock))
 | |
| #define __obs_tree(s)    &((s)->objects)
 | |
| 
 | |
| int obj_store_init(obj_store_t *st)
 | |
| {
 | |
|   usrtc_t *tree = &st->objects;
 | |
| 
 | |
|   if(pthread_rwlock_init(&(st->rwlock), NULL)) return ENOMEM;
 | |
|   else usrtc_init(tree, USRTC_SPLAY, MAX_OBJECTS, __cmp_cstr);
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int obj_store_set(obj_store_t *st, const char *nm, void *od)
 | |
| {
 | |
|   usrtc_node_t *node = NULL;
 | |
|   obj_store_node_t *onode = NULL;
 | |
| 
 | |
|   __obs_rdlock(st);
 | |
|   node = usrtc_lookup(__obs_tree(st), nm);
 | |
|   __obs_unlock(st);
 | |
| 
 | |
|   if(!node) {
 | |
|     if(!(onode = malloc(sizeof(obj_store_node_t)))) return ENOMEM;
 | |
|     else memset(onode, 0, sizeof(obj_store_node_t));
 | |
| 
 | |
|     if(!(onode->name = strdup(nm))) {
 | |
|       free(onode);
 | |
|       return ENOMEM;
 | |
|     }
 | |
| 
 | |
|     onode->objdata = od;
 | |
|     node = &(onode->node);
 | |
|     usrtc_node_init(node, onode);
 | |
| 
 | |
|     __obs_wrlock(st);
 | |
|     usrtc_insert(__obs_tree(st), node, (const void *)onode->name);
 | |
|     __obs_unlock(st);
 | |
|   } else {
 | |
|     onode = (obj_store_node_t *)usrtc_node_getdata(node);
 | |
| 
 | |
|     __obs_wrlock(st);
 | |
|     onode->objdata = od;
 | |
|     __obs_unlock(st);
 | |
|   }
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int obj_store_get(obj_store_t *st, const char *nm, void **rod)
 | |
| {
 | |
|   usrtc_node_t *node = NULL;
 | |
|   obj_store_node_t *onode = NULL;
 | |
| 
 | |
|   __obs_rdlock(st);
 | |
|   node = usrtc_lookup(__obs_tree(st), nm);
 | |
|   __obs_unlock(st);
 | |
| 
 | |
|   if(!node) return ENOENT;
 | |
|   else onode = (obj_store_node_t *)usrtc_node_getdata(node);
 | |
| 
 | |
|   *rod = onode->objdata;
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int obj_store_remove(obj_store_t *st, const char *nm)
 | |
| {
 | |
|   usrtc_node_t *node = NULL;
 | |
|   obj_store_node_t *onode = NULL;
 | |
| 
 | |
|   __obs_rdlock(st);
 | |
|   node = usrtc_lookup(__obs_tree(st), nm);
 | |
|   __obs_unlock(st);
 | |
| 
 | |
|   if(!node) return ENOENT;
 | |
|   else {
 | |
|     __obs_wrlock(st);
 | |
|     usrtc_delete(__obs_tree(st), node);
 | |
|     __obs_unlock(st);
 | |
| 
 | |
|     onode = (obj_store_node_t *)usrtc_node_getdata(node);
 | |
|     if(onode->name) free(onode->name);
 | |
|     free(onode);
 | |
|   }
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 |