You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Di...@jrc.it on 1997/01/08 19:25:48 UTC
DLD modules / mod_dld.c
Does anyone use DL-ing ? I've put dlopen() type of support into the DLD
module; which means that it should work on almost all platforms; but
I can only test it on freebsd, osf and solaris 2.4. This would need
very wide support/testing as it is very system dependent.
Secondly; has anyone REALLY used add_module()/AddModule/ClearModule ?
I have some serious doubpts that the num_modules and total_modules
counters ever did work ? Anyone who uses this in a live situation ?
Dw.
Here is the mod_dld.c; it is _N_O_T_ to be used; unless you are in
for some serious testing and do not mind your kernel to panix :-)
Y've been warned. The only good bit about it is that you can put
an Add/Delete in; so you can debug a module; do a kill -1 on the
server and see it pulled in dynamically; which is kind of neat :-)
/* ====================================================================
* Copyright (c) 1995-1997 The Apache Group. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* 4. The names "Apache Server" and "Apache Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission.
*
* 5. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the Apache Group
* for use in the Apache HTTP server project (http://www.apache.org/)."
*
* THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Group and was originally based
* on public domain software written at the National Center for
* Supercomputing Applications, University of Illinois, Urbana-Champaign.
* For more information on the Apache Group and the Apache HTTP server
* project, please see <http://www.apache.org/>.
*
*/
/*
* A first stab at dynamic loading, using the GNU dld library
* (or at least, an embarassingly old version of it...).
*
* -dirkx- Added a second stab; using the dlopen/dlclose/dlsymb
* calls in FreeBSD. Not tested.
*/
#include "httpd.h"
#include "http_config.h"
#include "http_conf_globals.h" /* server_argv0. Sigh... */
#ifdef DLD
#include <dld.h>
#endif
#ifdef DLFCN
#include <dlfcn.h>
typedef struct dld_list {
struct dld_list * next;
void * modp; /* pointer to actual module vectors */
void * handle; /* Handle from dlopen() */
char * name; /* to keep general referencing easy */
char * filename;
char * modname;
} dld_list;
struct dld_list * dld_list_begin = NULL;
#endif
#ifdef DLD_MODULE_DEBUG
#define DLDDEBUG(x) { printf x ; }
#else
#define DLDDEBUG(x)
#endif
/*
* The hard part of implementing LoadModule is deciding what to do about
* rereading the config files. This proof-of-concept implementation takes the
* cheap way out: we only actually load the modules the first time through.
*/
static int been_there_done_that = 0; /* Loaded the modules yet? */
static int have_symbol_table = 0;
char *insure_dld_sane()
{
#ifdef DLD
int errcode;
char *bin_name;
#endif
#ifdef DLFCN
void *bin_ptr;
#endif
if (have_symbol_table) return NULL;
#ifdef DLD
bin_name = dld_find_executable (server_argv0);
if ((errcode = dld_init (bin_name))) {
dld_perror (server_argv0);
return "Cannot find server binary (needed for dynamic linking).";
}
#endif
#ifdef DLFCN
if (!(bin_ptr = dlopen(NULL,1)))
return dlerror();
#endif
have_symbol_table = 1;
return NULL;
}
#ifdef DLD
char *link_file (pool *p, char *filename)
{
int errcode;
filename = server_root_relative (p, filename);
if ((errcode = dld_link (filename))) {
dld_perror (server_argv0);
return pstrcat (p, "Cannot load ", filename, " into server", NULL);
}
return NULL;
}
#endif
#ifdef DLFCN
const char * add_dld_list(void * handle, char * filename, char * modname, void * modp, char * name )
{
dld_list * p = dld_list_begin;
/* Eeek ! Panix !
*
* yes, we do not use a palloc() here; cause this list is
* going to stay around for the ENTIRE lifetime of the server
* so we much rather do this kind of managing ourselfes; rather
* than wasting some poooled space.
*/
if (!( dld_list_begin=malloc( sizeof(dld_list) )))
return "Could not claim enough memory for a DLD entry";
dld_list_begin -> next=p;
dld_list_begin -> handle = handle;
dld_list_begin -> filename = filename;
dld_list_begin -> modname = modname;
dld_list_begin -> name = name;
dld_list_begin -> modp = modp;
return NULL;
}
#endif
const char *load_module (cmd_parms *cmd, void *dummy, char *modname, char *filename)
{
char *errname;
module *modp;
#ifdef DLFCN
void * handle;
#endif
DLDDEBUG(
(
"load_module Act='%s' of %s\n",
(been_there_done_that ? "Skip" : "Load"),
(filename ? filename : "<null ptr>"))
);
if (been_there_done_that) return NULL;
if ((errname = insure_dld_sane())) return errname;
#ifdef DLD
if ((errname = link_file (cmd->pool, filename))) return errname;
if (!(modp = (module *)dld_get_symbol (modname)))) {
return pstrcat (cmd->pool, "Can't find module symbol ", modname,
" in file ", filename, NULL);
}
#endif
#ifdef DLFCN
if (!(handle=dlopen(filename,1)))
return pstrcat (cmd->pool," Cannot dlopen() module ", filename,
" Failed with :",dlerror(), NULL);
if (!(modp = (module *) dlsym(handle,pstrcat(cmd->pool ,"_", modname, NULL))))
return pstrcat (cmd->pool, "Can't find module symbol ", modname,
" in file ", filename,
" with error : ",dlerror(),
NULL);
if (add_dld_list(handle, filename, modname, modp, modp->name ))
return "Could not add a DLD entry";
#endif
DLDDEBUG(("About to add_module on %s %d %s\n",filename,modp->version,modp->name));
add_module(modp);
DLDDEBUG((" # --> %d\n",modp->module_index));
/* Alethea Patch (rws,djw2) - need to run configuration functions
in new modules */
DLDDEBUG(("About to create_server_config %s %s\n",modp->create_server_config ? "DEF" : "SKIP", filename));
if (modp->create_server_config)
((void**)cmd->server->module_config)[modp->module_index]=
(*modp->create_server_config)(cmd->pool, cmd->server);
else ((void**)cmd->server->module_config)[modp->module_index]=NULL;
DLDDEBUG(("About to create_dir_config %s %s\n",modp->create_dir_config ? "DEF" : "SKIP", filename));
if (modp->create_dir_config)
((void**)cmd->server->lookup_defaults)[modp->module_index]=
(*modp->create_dir_config)(cmd->pool, NULL);
else ((void**)cmd->server->lookup_defaults)[modp->module_index]=NULL;
DLDDEBUG(("OK for %s\n",filename));
return NULL;
}
const char *load_file (cmd_parms *cmd, void *dummy, char *filename)
{
char *errname;
#ifdef DLFCN
void * handle;
#endif
DLDDEBUG(("load_file %s %s\n",
been_there_done_that ? "Skip" : "Load",
filename ? filename :"<null ptr>"));
if (been_there_done_that) return NULL;
if ((errname = insure_dld_sane())) return errname;
#ifdef DLD
if ((errname = link_file (cmd->pool, filename))) return errname;
#endif
#ifdef DLFCN
if (!(handle=dlopen(filename,1)))
return dlerror();
if (!(add_dld_list(handle,filename, NULL , NULL , NULL )))
return "Could not add a DLD entry";
#endif
return NULL;
}
const char *delete_dld (cmd_parms *cmd, char * dummy, char *one, char *two)
{
DLDDEBUG(("delete_dld %s %s %s\n",
been_there_done_that ? "Skip" : "Load",
one ? one : "<null ptr>",
two ? two :"<null ptr>"));
if (been_there_done_that) return NULL;
#ifdef DLD
fprintf(stderr,"Not YET implemented; feel free to do so in %s\n",
_FILE_);
exit(1);
#endif
#ifdef DLFCN
/* find our friend; on either of the two names
* and work out if we have a bin-ptr in our private
* list somewhere.
*/
{ dld_list * * p;
for( p=&dld_list_begin; (*p) != NULL ; p=&((*p)->next) ) {
fprintf(stderr,"DLD VS %s %s %s\n",
(*p)->name ? (*p)->name : "-" ,
(*p)->modname ? (*p)->modname: "-" ,
(*p)->filename ? (*p)->filename : "-"
);
if (
(((*p)->filename != NULL ) &&
(!strcmp(one,(*p)->filename ) || !strcmp(two,(*p)->filename) )) ||
(((*p)->modname != NULL ) &&
(!strcmp(one,(*p)->modname) || !strcmp(two,(*p)->modname) )) ||
(((*p)->name != NULL ) &&
(!strcmp(one,(*p)->name) || !strcmp(two,(*p)->name) ))
) { /* now just decrement the ref count, the crt.0 will
* do the real work of zapping it.. Treat any errors as
* a fatal !
*/
dld_list *r=(*p) -> next;
DLDDEBUG(("Looks like a %s\n",(*p)->modp ? "MOD" : "FILE"));
if ( (*p) -> modp != NULL ) {
DLDDEBUG(("Inactivting %s\n",(*p)->name));
rem_module( (*p) -> modp );
};
DLDDEBUG(("About to zap %s\n",(*p)->name));
if (dlclose((*p)->handle))
return pstrcat( cmd->pool,
"Barfing on dlclose of '",(*p)->name ? (*p)->name : "<null>","' with: ",dlerror(),
NULL);
free( *p );
(*p) =r;
DLDDEBUG(("And cleaned up\n"));
return NULL;
};
};
return "DLD to remove not found\n";
} /* dld list search */
#endif
return NULL;
}
void check_loaded_modules (server_rec *dummy, pool *p)
{
if (been_there_done_that) return;
#ifdef DLD
if (dld_undefined_sym_count > 0) {
/* Screwup. Do the best we can to inform the user, and exit */
char **bad_syms = dld_list_undefined_sym();
int i;
fprintf(stderr, "Dynamic linking error --- symbols left undefined.\n");
fprintf(stderr, "(It may help to relink libraries).\n");
fprintf(stderr, "Undefined symbols follow:\n");
for (i = 0; i < dld_undefined_sym_count; ++i)
fprintf (stderr, "%s\n", bad_syms[i]);
exit (1);
}
#endif
#ifdef DLFCN
/* we COULD call dlerror(), but that is not exactly neat;
* and is likely to interfere with any other modules or
* libaries (such as the Sybase one) which do dlopen()s
* themselves. So we rely on the dlXXX() calles themselves
* to be checked properly.
*/
#endif
been_there_done_that = 1;
}
command_rec dld_cmds[] = {
{ "LoadModule", load_module, NULL, RSRC_CONF, TAKE2,
"a module name, and the name of a file to load it from"},
{ "LoadFile", load_file, NULL, RSRC_CONF, ITERATE,
"files or libraries to link into the server at runtime"},
{ "DeleteModule", delete_dld, NULL, RSRC_CONF, TAKE12,
"a module name or the name of a module-file to remove it from"},
{ "DeleteFile", delete_dld, NULL, RSRC_CONF, TAKE12,
"files or libraries to remove from the server at runtime"},
{ NULL }
};
module dld_module = {
STANDARD_MODULE_STUFF,
check_loaded_modules, /* initializer */
NULL, /* create per-dir config */
NULL, /* merge per-dir config */
NULL, /* server config */
NULL, /* merge server config */
dld_cmds, /* command table */
NULL, /* handlers */
NULL, /* filename translation */
NULL, /* check_user_id */
NULL, /* check auth */
NULL, /* check access */
NULL, /* type_checker */
NULL /* logger */
};
http://ewse.ceo.org http://enrm.ceo.org
DWvGulik@Dialis.xs4all.nl Dirk.vanGulik@jrc.it
+39 332 78 0014 +39 332 78 9549
fax +39 332 78 9185
ISEI/ESBA; The Center For Earth Observation
Joint Research Centre of the European Communities, Ispra, Italy