1 /* Shared object scripts.
2 * - by Richard W.M. Jones <rich@annexia.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 * $Id: exec_so.c,v 1.10 2003/01/31 14:36:22 rich Exp $
37 #include <pthr_pseudothread.h>
38 #include <pthr_iolib.h>
39 #include <pthr_http.h>
42 #include "rws_request.h"
43 #include "process_rq.h"
48 /* XXX make+ configure should figure this out. */
50 #define HANDLE_REQUEST_SYM "handle_request"
52 #define HANDLE_REQUEST_SYM "_handle_request"
55 static shash cache = 0;
58 void *dl_handle; /* Handle returned by dlopen(3) */
59 /* Pointer to 'handle_request' fn. */
60 int (*handle_request) (rws_request rq);
61 time_t mtime; /* Modification time of this file at load. */
62 int use_count; /* Number of current users. */
65 /* This structure is used when jumping into the handle_request function,
66 * so we can catch errors and return values from this function.
70 struct shared_object *so; /* Parameter to the call. */
71 rws_request rq; /* Parameter to the call. */
72 int close; /* Return value from the call. */
75 static void call_handle_request (void *data);
76 static int do_error (process_rq p, const char *msg);
81 cache = new_shash (global_pool, struct shared_object *);
85 exec_so_file (process_rq p)
87 struct shared_object *so;
90 struct fn_result fn_result;
92 /* Check our cache of currently loaded .so files to see if this one
93 * has already been loaded.
95 if (!shash_get (cache, p->file_path, so))
97 /* No: Need to dlopen this file. */
98 so = pmalloc (global_pool, sizeof *so);
101 so->dl_handle = dlopen (p->file_path,
108 if (so->dl_handle == 0)
110 fprintf (stderr, "%s\n", dlerror ());
111 return bad_request_error (p,
112 "failed to load shared object file");
115 /* Check it contains the 'handle_request' function. */
116 so->handle_request = dlsym (so->dl_handle, HANDLE_REQUEST_SYM);
117 if ((error = dlerror ()) != 0)
119 fprintf (stderr, "%s\n", error);
120 dlclose (so->dl_handle);
121 return bad_request_error (p,
122 "shared object file does not contain "
123 "handle_request function");
126 so->mtime = p->statbuf.st_mtime;
129 /* Add it to the cache. */
130 shash_insert (cache, p->file_path, so);
133 /* Check the modification time. We may need to reload this script if it's
134 * changed on disk. But if there are other current users, then we can't
135 * safely unload the library, so don't try (a later request will reload
136 * it when it's quiet anyway).
138 if (p->statbuf.st_mtime > so->mtime && so->use_count == 0)
140 shash_erase (cache, p->file_path);
141 dlclose (so->dl_handle);
145 /* OK, we're now about to use this file. */
148 /* Generate the rws_request object. */
149 rq = new_rws_request (p->pool,
161 /* Call the 'handle_request' function.
162 * XXX We could pass environment parameters here, but this requires
163 * a change to pthrlib to allow environment variables to be handled
164 * across context switches.
168 error = pth_catch (call_handle_request, &fn_result);
170 /* Finished using the file. */
174 return do_error (p, error);
176 return fn_result.close;
180 call_handle_request (void *data)
182 struct fn_result *fn_result = (struct fn_result *) data;
184 fn_result->close = fn_result->so->handle_request (fn_result->rq);
188 do_error (process_rq p, const char *msg)
190 /* XXX In the future, we'd like to extend this function so that
191 * other non-500 errors can be displayed (particularly for 404
192 * Page Not Found errors).
194 return bad_request_error (p, msg);