1 /**
2 * Copyright 2010 Christian Liesch
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /**
18 * @file
19 *
20 * @Author christian liesch <liesch@gmx.ch>
21 *
22 * Implementation of the HTTP Test Tool dso module
23 */
24
25 /************************************************************************
26 * Includes
27 ***********************************************************************/
28 #include <apr_dso.h>
29 #include "htt/dso.h"
30 #include "module.h"
31
32 /************************************************************************
33 * Definitions
34 ***********************************************************************/
35 typedef struct dso_gconf_s {
36 apr_hash_t *transport_objs;
37 } dso_gconf_t;
38
39 /************************************************************************
40 * Globals
41 ***********************************************************************/
42 const char * dso_module = "dso_module";
43
44 /************************************************************************
45 * Local
46 ***********************************************************************/
47 /**
48 * Get stat config from global
49 *
50 * @param global IN
51 * @return stat config
52 */
dso_get_global_config(global_t * global)53 static dso_gconf_t *dso_get_global_config(global_t *global) {
54 dso_gconf_t *config = module_get_config(global->config, dso_module);
55 if (config == NULL) {
56 config = apr_pcalloc(global->pool, sizeof(*config));
57 config->transport_objs = apr_hash_make(global->pool);
58 module_set_config(global->config, apr_pstrdup(global->pool, dso_module), config);
59 }
60 return config;
61 }
62
63 /**
64 * Get os socket descriptor
65 * @param data IN void pointer to socket
66 * @param desc OUT os socket descriptor
67 * @return apr status
68 */
dso_transport_os_desc_get(void * data,int * desc)69 static apr_status_t dso_transport_os_desc_get(void *data, int *desc) {
70 return APR_ENOTIMPL;
71 }
72
73 /**
74 * Set timeout
75 * @param data IN void pointer to socket
76 * @param desc OUT os socket descriptor
77 * @return apr status
78 */
dso_transport_set_timeout(void * data,apr_interval_time_t t)79 static apr_status_t dso_transport_set_timeout(void *data, apr_interval_time_t t) {
80 return APR_SUCCESS;
81 }
82
83 /**
84 * Set timeout
85 * @param data IN void pointer to socket
86 * @param desc OUT os socket descriptor
87 * @return apr status
88 */
dso_transport_get_timeout(void * data,apr_interval_time_t * t)89 static apr_status_t dso_transport_get_timeout(void *data, apr_interval_time_t *t) {
90 return APR_SUCCESS;
91 }
92
93 /**
94 * read from socket
95 * @param data IN void pointer to socket
96 * @param buf IN buffer
97 * @param size INOUT buffer len
98 * @return apr status
99 */
dso_transport_read(void * data,char * buf,apr_size_t * size)100 static apr_status_t dso_transport_read(void *data, char *buf, apr_size_t *size) {
101 transport_dso_t *transport_dso = data;
102 return transport_dso->read(transport_dso->custom_handle(), buf, size);
103 }
104
105 /**
106 * write to socket
107 * @param data IN void pointer to socket
108 * @param buf IN buffer
109 * @param size INOUT buffer len
110 * @return apr status
111 */
dso_transport_write(void * data,const char * buf,apr_size_t size)112 static apr_status_t dso_transport_write(void *data, const char *buf, apr_size_t size) {
113 transport_dso_t *transport_dso = data;
114 return transport_dso->write(transport_dso->custom_handle(), buf, size);
115 }
116
117 /************************************************************************
118 * Commands
119 ***********************************************************************/
120 /**
121 * Load transport object so
122 * @param worker IN callee
123 * @param parent IN caller
124 * @param ptmp IN temporary ptmp
125 * @return status
126 */
block_LOAD_TRANSPORT_DSO(worker_t * worker,worker_t * parent,apr_pool_t * ptmp)127 static apr_status_t block_LOAD_TRANSPORT_DSO(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) {
128 apr_status_t status;
129 const char *path;
130 const char *name;
131 apr_dso_handle_t *dso;
132 global_t *global = worker->global;
133 dso_gconf_t *gconf = dso_get_global_config(global);
134
135 if ((status = module_check_global(worker)) == APR_SUCCESS) {
136 worker_log(worker, LOG_INFO, "LOAD_TRANSPORT_DSO");
137 path = store_get(worker->params, "1");
138 if (!path) {
139 worker_log(worker, LOG_ERR, "Expect a path to shared library");
140 return APR_EINVAL;
141 }
142
143 name = store_get(worker->params, "2");
144 if (!name) {
145 worker_log(worker, LOG_ERR, "Expect a unique name for this object");
146 return APR_EINVAL;
147 }
148
149 if ((status = apr_dso_load(&dso, path, global->pool)) != APR_SUCCESS) {
150 char buf[BLOCK_MAX+1];
151 worker_log(worker, LOG_ERR, "Can not load \"%s\" library", path);
152 apr_dso_error(dso, buf, BLOCK_MAX);
153 worker_log_buf(worker, LOG_ERR, '+', buf, strlen(buf));
154 return status;
155 }
156
157 apr_hash_set(gconf->transport_objs, apr_pstrdup(global->pool, name), APR_HASH_KEY_STRING, dso);
158 }
159 return status;
160 }
161
162 /**
163 * Load transport object so
164 * @param worker IN callee
165 * @param parent IN caller
166 * @param ptmp IN temporary ptmp
167 * @return status
168 */
block_GET_TRANSPORT_OBJECT(worker_t * worker,worker_t * parent,apr_pool_t * ptmp)169 static apr_status_t block_GET_TRANSPORT_OBJECT(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) {
170 apr_status_t status = APR_SUCCESS;
171 const char *name;
172 const char *sym;
173 const char *config;
174 transport_t *transport;
175 apr_dso_handle_t *dso;
176 apr_dso_handle_sym_t dso_sym;
177 transport_dso_t *transport_dso;
178 global_t *global = worker->global;
179 dso_gconf_t *gconf = dso_get_global_config(global);
180
181 name = store_get(worker->params, "1");
182 if (!name) {
183 worker_log(worker, LOG_ERR, "Expect name loaded share library");
184 return APR_EINVAL;
185 }
186
187 if ((dso = apr_hash_get(gconf->transport_objs, name, APR_HASH_KEY_STRING)) == NULL) {
188 worker_log(worker, LOG_ERR, "Requested share library not found");
189 return APR_EINVAL;
190 }
191
192 sym = store_get(worker->params, "2");
193 if (!sym) {
194 worker_log(worker, LOG_ERR, "Expect a unique name for this object");
195 return APR_EINVAL;
196 }
197
198 if ((status = apr_dso_sym(&dso_sym, dso, sym)) != APR_SUCCESS) {
199 worker_log(worker, LOG_ERR, "Can not load \"%s\" object", sym);
200 return status;
201 }
202
203 transport_dso = (transport_dso_t *)dso_sym;
204
205 config = store_get(worker->params, "3");
206 if (config) {
207 if ((status = transport_dso->configure(transport_dso->custom_handle(),
208 config)) != APR_SUCCESS) {
209 worker_log(worker, LOG_ERR, "Configure failed, see logs of your dso module");
210 return status;
211 }
212 }
213
214 /* build up a httest transport object */
215 transport = transport_new(transport_dso, worker->pbody,
216 dso_transport_os_desc_get,
217 dso_transport_set_timeout,
218 dso_transport_get_timeout,
219 dso_transport_read,
220 dso_transport_write);
221
222 worker_get_socket(worker, name, apr_pstrcat(global->pool, "000:", sym, NULL));
223 transport_register(worker->socket, transport);
224
225 return status;
226 }
227
my_func(const char * string)228 apr_status_t my_func(const char *string) {
229 return APR_SUCCESS;
230 }
231
232 /**
233 * call a dso function of type apr_status_t func(const char *string)
234 * @param worker IN callee
235 * @param parent IN caller
236 * @param ptmp IN temporary ptmp
237 * @return status
238 */
block_FUNC(worker_t * worker,worker_t * parent,apr_pool_t * ptmp)239 static apr_status_t block_FUNC(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) {
240 apr_status_t status = APR_SUCCESS;
241 const char *sym;
242 const char *string;
243 apr_dso_handle_t *dso;
244 func_dso_f func;
245 apr_dso_handle_sym_t *func_sym_address = (apr_dso_handle_sym_t*)(&func);
246 global_t *global = worker->global;
247
248 sym = store_get(worker->params, "1");
249 if (!sym) {
250 worker_log(worker, LOG_ERR, "Expect function name");
251 return APR_EINVAL;
252 }
253
254 if ((status = apr_dso_load(&dso, NULL, global->pool)) != APR_SUCCESS) {
255 worker_log(worker, LOG_ERR, "Can not load \"%s\" object", sym);
256 return status;
257 }
258
259 /*Effectively fills 'func'*/
260 if ((status = apr_dso_sym(func_sym_address, dso, sym)) != APR_SUCCESS) {
261 worker_log(worker, LOG_ERR, "Can not call \"%s\" object", sym);
262 return status;
263 }
264
265 string= store_get(worker->params, "2");
266 if (!string) {
267 worker_log(worker, LOG_ERR, "Expect string to handover to function");
268 return APR_EINVAL;
269 }
270
271 return func(string);
272 }
273
274 /************************************************************************
275 * Module
276 ***********************************************************************/
dso_module_init(global_t * global)277 apr_status_t dso_module_init(global_t *global) {
278 apr_status_t status;
279 if ((status = module_command_new(global, "DSO", "LOAD_TRANSPORT_DSO",
280 "<path-to-transport-dso> <name>",
281 "A shared library which implents an own transport object will be loaded.\n"
282 "The dso is stored with a <name>.",
283 block_LOAD_TRANSPORT_DSO)) != APR_SUCCESS) {
284 return status;
285 }
286
287 if ((status = module_command_new(global, "DSO", "_GET_TRANSPORT_OBJECT",
288 "<name-of-transport-dso> <symbol-name>",
289 "Get transport object by its symbol name.",
290 block_GET_TRANSPORT_OBJECT)) != APR_SUCCESS) {
291 return status;
292 }
293
294 if ((status = module_command_new(global, "DSO", "_FUNC",
295 "<dso-function-to-call> <string>",
296 "The dso function is of type \'apr_status_t func(const char *string)\'.",
297 block_FUNC)) != APR_SUCCESS) {
298 return status;
299 }
300 return APR_SUCCESS;
301 }
302
303