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