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