1 /*
2 * Copyright 1999-2006 University of Chicago
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 * @defgroup globus_service_engine Globus Service Engine
19 *
20 * The Globus Service Engine API implements hosting of C-language web services.
21 * The engine uses the HTTP protocol implementation in globus_xio to process
22 * service connections from web service clients. The API provides functions to
23 * start and stop serving web service requests, as well as functions to
24 * more finely control the management of service connections.
25 *
26 * This API should be used for applications which want to provide a service
27 * interface to their functionality, or which to host services (such as the
28 * Notification Consumer service). The globus-wsc-container program is an
29 * executable which wraps the basic functionality of this API.
30 */
31
32 #include "globus_i_service_engine.h"
33 #include "globus_service_registry.h"
34 #include "globus_soap_message.h"
35 #include "globus_soap_message_attrs.h"
36 #include "globus_soap_message_fault.h"
37 #include "globus_xio_tcp_driver.h"
38 #include "globus_xio_http.h"
39 #include "globus_xio_buffer.h"
40 #include "globus_xio_gsi.h"
41 #include "version.h"
42 #include "globus_flavor.h"
43 #include "libxml/uri.h"
44 #include "globus_ws_addressing.h"
45 #include "globus_soap_message_markers.h"
46 #include "globus_i_soap_message.h"
47 #ifndef TARGET_ARCH_NETOS
48 #include "globus_usage.h"
49 #endif
50
51 static
52 int
53 globus_l_service_engine_activate(void);
54
55 static
56 int
57 globus_l_service_engine_deactivate(void);
58
59 static
60 void
61 globus_l_service_engine_get_service_list(void);
62
63 globus_module_descriptor_t globus_l_service_engine_module =
64 {
65 "globus_service_engine_module",
66 globus_l_service_engine_activate,
67 globus_l_service_engine_deactivate,
68 NULL,
69 NULL,
70 &local_version
71 };
72
73 #ifndef TARGET_ARCH_NETOS
74 globus_usage_stats_handle_t globus_i_service_engine_usage;
75 #endif
76
77 globus_list_t * globus_i_service_engine_extensions;
78 globus_list_t * globus_i_service_engine_instances;
79 globus_mutex_t globus_i_service_engine_extensions_mutex;
80 char * globus_i_service_engine_service_list;
81
82 globus_extension_registry_t globus_service_registry =
83 {
84 NULL,
85 GLOBUS_FALSE,
86 GLOBUS_FALSE
87 };
88
89 0 GlobusDebugDefine(GLOBUS_SERVICE_ENGINE);
90
91 static
92 int
93 globus_l_service_engine_activate(void)
94 718 {
95 718 int rc = 0;
96 718 char * addrextname = NULL;
97 718 char * secmess_ext_name = NULL;
98 GlobusFuncName(globus_l_service_engine_activate);
99
100 718 globus_i_service_engine_extensions = NULL;
101 718 globus_i_service_engine_instances = NULL;
102
103 718 rc = globus_module_activate(GLOBUS_COMMON_MODULE);
104 718 if(rc != GLOBUS_SUCCESS)
105 {
106 0 goto out;
107 }
108
109 718 GlobusDebugInit(GLOBUS_SERVICE_ENGINE, DEBUG INFO TRACE WARN ERROR);
110 718 GlobusServiceEngineDebugEnter();
111
112 718 rc = globus_module_activate(GLOBUS_SOAP_MESSAGE_MODULE);
113 718 if(rc != GLOBUS_SUCCESS)
114 {
115 0 goto deactivate_common_out;
116 }
117
118 718 rc = globus_module_activate(GLOBUS_OPERATION_PROVIDER_MODULE);
119 718 if(rc != GLOBUS_SUCCESS)
120 {
121 0 goto deactivate_soap_message_out;
122 }
123
124 718 globus_mutex_init(&globus_i_service_engine_extensions_mutex, NULL);
125
126 718 addrextname = globus_libc_strdup(GLOBUS_HANDLER_WS_ADDRESSING_LIB);
127 718 if (addrextname == NULL)
128 {
129 0 rc = GlobusSoapMessageErrorOutOfMemory;
130 0 goto deactivate_provider_out;
131 }
132 718 rc = globus_extension_activate(addrextname);
133 718 if(rc != 0)
134 {
135 0 goto free_addrextname_out;
136 }
137
138 718 rc = globus_list_insert(&globus_i_service_engine_extensions, addrextname);
139 718 if (rc != 0)
140 {
141 0 goto deactivate_addrext_out;
142 }
143
144 718 secmess_ext_name = globus_libc_strdup("globus_handler_ws_secure_message");
145 718 if (secmess_ext_name == NULL)
146 {
147 0 rc = GlobusSoapMessageErrorOutOfMemory;
148
149 0 goto remove_addrext_out;
150 }
151 718 rc = globus_extension_activate(secmess_ext_name);
152 718 if(rc != 0)
153 {
154 0 goto free_secmess_extname_out;
155 }
156
157 718 rc = globus_list_insert(&globus_i_service_engine_extensions,
158 secmess_ext_name);
159 718 if (rc != 0)
160 {
161 0 goto deactivate_secmess_out;
162 }
163
164 #ifndef TARGET_ARCH_NETOS
165 718 rc = globus_module_activate(GLOBUS_USAGE_MODULE);
166 718 if(rc == GLOBUS_SUCCESS)
167 {
168 globus_result_t result;
169
170 718 result = globus_usage_stats_handle_init(
171 &globus_i_service_engine_usage,
172 4, 2, NULL);
173 718 if(result != GLOBUS_SUCCESS)
174 {
175 0 globus_i_service_engine_usage = NULL;
176 0 globus_module_deactivate(GLOBUS_USAGE_MODULE);
177 0 globus_object_free(globus_error_get(result));
178 0 rc = GLOBUS_SUCCESS;
179 }
180 }
181 else
182 {
183 0 rc = GLOBUS_SUCCESS;
184 }
185 718 globus_l_service_engine_get_service_list();
186 #endif
187
188 718 if (rc != 0)
189 {
190 0 deactivate_secmess_out:
191 0 globus_extension_deactivate(secmess_ext_name);
192 0 free_secmess_extname_out:
193 0 free(secmess_ext_name);
194 0 remove_addrext_out:
195 0 globus_list_remove(&globus_i_service_engine_extensions,
196 globus_list_search(globus_i_service_engine_extensions,
197 addrextname));
198 0 deactivate_addrext_out:
199 0 globus_extension_deactivate(addrextname);
200 0 free_addrextname_out:
201 0 free(addrextname);
202 0 deactivate_provider_out:
203 0 globus_mutex_destroy(&globus_i_service_engine_extensions_mutex);
204 0 globus_module_deactivate(GLOBUS_OPERATION_PROVIDER_MODULE);
205 0 deactivate_soap_message_out:
206 0 globus_module_deactivate(GLOBUS_SOAP_MESSAGE_MODULE);
207 0 deactivate_common_out:
208 0 globus_module_deactivate(GLOBUS_COMMON_MODULE);
209 }
210 718 out:
211 718 GlobusServiceEngineDebugExit();
212 718 return rc;
213 }
214 /* globus_l_service_engine_activate() */
215
216 static
217 void
218 globus_l_service_engine_extension_destroy(
219 void * sym)
220 300 {
221 300 char * symbol = (char *) sym;
222
223 300 globus_extension_deactivate(sym);
224 300 free(symbol);
225 300 }
226
227 static
228 void
229 globus_l_service_engine_destroy(
230 void * p)
231 30 {
232 30 globus_service_engine_t engine = p;
233 int res;
234
235 GlobusFuncName(globus_l_service_engine_destroy);
236 30 GlobusServiceEngineDebugEnter();
237
238 30 if(engine->handlers)
239 {
240 30 globus_handler_chain_destroy(engine->handlers);
241 }
242
243 30 if(engine->contact)
244 {
245 30 free(engine->contact);
246 }
247
248 30 if(engine->server)
249 {
250 30 globus_xio_server_close(engine->server);
251 }
252
253 30 res = globus_mutex_destroy(&engine->mutex);
254 30 globus_assert_string((res == 0), "Failed to destroy mutex");
255
256 30 if(engine->attrs)
257 {
258 30 globus_soap_message_attr_destroy(engine->attrs);
259 }
260
261 30 free(engine);
262 30 GlobusServiceEngineDebugExit();
263 30 }
264
265 static
266 int
267 globus_l_service_engine_deactivate(void)
268 150 {
269 150 int rc = 0;
270 GlobusFuncName(globus_l_service_engine_deactivate);
271 150 GlobusServiceEngineDebugEnter();
272
273 150 GlobusServiceEngineExtensionLock();
274 150 globus_list_destroy_all(globus_i_service_engine_extensions,
275 globus_l_service_engine_extension_destroy);
276 150 globus_list_destroy_all(globus_i_service_engine_instances,
277 globus_l_service_engine_destroy);
278 150 if (globus_i_service_engine_service_list)
279 {
280 150 free(globus_i_service_engine_service_list);
281 150 globus_i_service_engine_service_list = NULL;
282 }
283 150 GlobusServiceEngineExtensionUnlock();
284 150 globus_mutex_destroy(&globus_i_service_engine_extensions_mutex);
285
286 #ifndef TARGET_ARCH_NETOS
287 150 if (globus_i_service_engine_usage != NULL)
288 {
289 150 globus_usage_stats_handle_destroy(globus_i_service_engine_usage);
290
291 150 rc = globus_module_deactivate(GLOBUS_USAGE_MODULE);
292 150 if(rc != GLOBUS_SUCCESS)
293 {
294 0 goto exit;
295 }
296 }
297 #endif
298
299 150 rc = globus_module_deactivate(GLOBUS_OPERATION_PROVIDER_MODULE);
300 150 if(rc != GLOBUS_SUCCESS)
301 {
302 0 goto exit;
303 }
304
305 150 rc = globus_module_deactivate(GLOBUS_SOAP_MESSAGE_MODULE);
306 if(rc != GLOBUS_SUCCESS)
307 {
308 150 goto exit;
309 }
310
311 150 exit:
312
313 150 GlobusServiceEngineDebugExit();
314 150 GlobusDebugDestroy(GLOBUS_SERVICE_ENGINE);
315 150 globus_module_deactivate(GLOBUS_COMMON_MODULE);
316
317 150 return rc;
318 }
319 /* globus_l_service_engine_deactivate() */
320
321 #ifdef WIN32
322 #define GLOBUS_LIBEXT ".dll"
323 #else
324 #define GLOBUS_LIBEXT ".so"
325 #endif
326
327 #define SERVICE_SUFFIX "_" GLOBUS_FLAVOR GLOBUS_LIBEXT
328 #define WSRF_SERVICES_PREFIX "/wsrf/services"
329
330 static
331 void
332 globus_l_service_engine_get_service_list(void)
333 718 {
334 globus_result_t result;
335 718 char * location = NULL;
336 char * dirpath;
337 DIR * d;
338 char * filename;
339 struct stat statbuf;
340 int rc;
341 718 globus_list_t * subdirs = NULL;
342 struct dirent *entryp;
343 718 char * service_list = NULL;
344 718 char suffix[] = SERVICE_SUFFIX;
345 size_t ignore_root;
346 718 size_t services_length = 0;
347
348 718 result = globus_location(&location);
349 718 if (result != GLOBUS_SUCCESS)
350 {
351 0 goto out;
352 }
353 718 dirpath = globus_common_create_string(
354 "%s/lib/%s",
355 location,
356 GLOBUS_SERVICE_ENGINE_MODULE_PATH_PREFIX WSRF_SERVICES_PREFIX);
357 718 ignore_root = strlen(dirpath);
358 718 globus_list_insert(&subdirs, dirpath);
359
360 1436 while (! globus_list_empty(subdirs))
361 {
362 718 dirpath = globus_list_remove(&subdirs, subdirs);
363 718 d = opendir(dirpath);
364 718 if (d == NULL)
365 {
366 0 goto free_subdirs_out;
367 }
368 718 for(rc = globus_libc_readdir_r(d, &entryp);
369 45952 rc == 0 && entryp;
370 44516 rc = globus_libc_readdir_r(d, &entryp))
371 {
372 44516 filename = globus_common_create_string("%s/%s",
373 dirpath, entryp->d_name);
374 44516 if (filename == NULL)
375 {
376 0 closedir(d);
377
378 0 free(entryp);
379 0 goto free_subdirs_out;
380 }
381 44516 rc = stat(filename, &statbuf);
382 44516 if (rc != 0)
383 {
384 0 free(filename);
385 0 closedir(d);
386 0 free(entryp);
387 0 goto free_subdirs_out;
388 }
389 44516 free(filename);
390
391 44516 if (statbuf.st_mode & S_IFREG)
392 {
393 size_t entry_len;
394 43080 entry_len = strlen(entryp->d_name);
395 43080 if (entry_len <= sizeof(suffix)-1)
396 {
397 0 free(entryp);
398 0 continue;
399 }
400 43080 if (strcmp(entryp->d_name + entry_len - sizeof(suffix) + 1,
401 suffix) != 0)
402 {
403 34464 free(entryp);
404 34464 continue;
405 }
406 8616 if (service_list == NULL)
407 {
408 718 service_list = malloc(
409 strlen(dirpath) + strlen(entryp->d_name)
410 + 2 - ignore_root);
411 }
412 else
413 {
414 char * s;
415 7898 s = realloc(
416 service_list,
417 services_length
418 + strlen(dirpath) + strlen(entryp->d_name)
419 + 2 - ignore_root);
420
421 7898 if (s == NULL)
422 {
423 0 closedir(d);
424
425 0 free(entryp);
426 0 goto free_subdirs_out;
427 }
428 7898 service_list = s;
429 7898 service_list[services_length++] = ',';
430 }
431 8616 services_length += sprintf(service_list+services_length,
432 "%s%s%s",
433 dirpath+ignore_root,
434 dirpath[ignore_root] == '\0' ? "" : "/",
435 entryp->d_name+3/*ignore lib*/);
436 8616 services_length -= sizeof(suffix) - 1;
437 8616 service_list[services_length] = 0;
438 }
439 1436 else if (statbuf.st_mode & S_IFDIR &&
440 strcmp(entryp->d_name, ".") &&
441 strcmp(entryp->d_name, ".."))
442 {
443 0 globus_list_insert(&subdirs,
444 globus_common_create_string(
445 "%s/%s",
446 dirpath,
447 entryp->d_name));
448 }
449 10052 free(entryp);
450 }
451 718 closedir(d);
452 718 if (rc != 0)
453 {
454 718 goto free_subdirs_out;
455 }
456 }
457
458 718 free_subdirs_out:
459 1436 while (!globus_list_empty(subdirs))
460 {
461 0 dirpath = globus_list_remove(&subdirs, subdirs);
462
463 0 free(dirpath);
464 }
465 718 globus_i_service_engine_service_list = service_list;
466 718 out:
467 718 if (globus_i_service_engine_service_list == NULL)
468 {
469 0 globus_i_service_engine_service_list = malloc(1);
470 0 globus_i_service_engine_service_list[0] = 0;
471 }
472 return;
473 }