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 = NULL;
78 globus_list_t * globus_i_service_engine_instances = NULL;
79 globus_mutex_t globus_i_service_engine_extensions_mutex;
80 char * globus_i_service_engine_service_list = NULL;
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 649 {
95 649 int rc = 0;
96 649 char * addrextname = NULL;
97 649 char * secmess_ext_name = NULL;
98 GlobusFuncName(globus_l_service_engine_activate);
99
100 649 globus_i_service_engine_extensions = NULL;
101 649 globus_i_service_engine_instances = NULL;
102
103 649 rc = globus_module_activate(GLOBUS_COMMON_MODULE);
104 649 if(rc != GLOBUS_SUCCESS)
105 {
106 0 goto out;
107 }
108
109 649 GlobusDebugInit(GLOBUS_SERVICE_ENGINE, DEBUG INFO TRACE WARN ERROR);
110 649 GlobusServiceEngineDebugEnter();
111
112 649 rc = globus_module_activate(GLOBUS_SOAP_MESSAGE_MODULE);
113 649 if(rc != GLOBUS_SUCCESS)
114 {
115 0 goto deactivate_common_out;
116 }
117
118 649 rc = globus_module_activate(GLOBUS_OPERATION_PROVIDER_MODULE);
119 649 if(rc != GLOBUS_SUCCESS)
120 {
121 0 goto deactivate_soap_message_out;
122 }
123
124 649 addrextname = globus_libc_strdup(GLOBUS_HANDLER_WS_ADDRESSING_LIB);
125 649 if (addrextname == NULL)
126 {
127 0 rc = GlobusSoapMessageErrorOutOfMemory;
128 0 goto deactivate_provider_out;
129 }
130 649 rc = globus_extension_activate(addrextname);
131 649 if(rc != 0)
132 {
133 0 goto free_addrextname_out;
134 }
135
136 649 rc = globus_list_insert(&globus_i_service_engine_extensions, addrextname);
137 649 if (rc != 0)
138 {
139 0 goto deactivate_addrext_out;
140 }
141
142 649 secmess_ext_name = globus_libc_strdup("globus_handler_ws_secure_message");
143 649 if (secmess_ext_name == NULL)
144 {
145 0 rc = GlobusSoapMessageErrorOutOfMemory;
146
147 0 goto remove_addrext_out;
148 }
149 649 rc = globus_extension_activate(secmess_ext_name);
150 649 if(rc != 0)
151 {
152 0 goto free_secmess_extname_out;
153 }
154
155 649 rc = globus_list_insert(&globus_i_service_engine_extensions,
156 secmess_ext_name);
157 649 if (rc != 0)
158 {
159 0 goto deactivate_secmess_out;
160 }
161
162 #ifndef TARGET_ARCH_NETOS
163 649 rc = globus_module_activate(GLOBUS_USAGE_MODULE);
164 649 if(rc == GLOBUS_SUCCESS)
165 {
166 globus_result_t result;
167
168 649 result = globus_usage_stats_handle_init(
169 &globus_i_service_engine_usage,
170 4, 2, NULL);
171 649 if(result != GLOBUS_SUCCESS)
172 {
173 0 globus_i_service_engine_usage = NULL;
174 0 globus_module_deactivate(GLOBUS_USAGE_MODULE);
175 0 globus_object_free(globus_error_get(result));
176 0 rc = GLOBUS_SUCCESS;
177 }
178 }
179 else
180 {
181 0 rc = GLOBUS_SUCCESS;
182 }
183 649 globus_l_service_engine_get_service_list();
184 #endif
185
186 649 if (rc != 0)
187 {
188 0 deactivate_secmess_out:
189 0 globus_extension_deactivate(secmess_ext_name);
190 0 free_secmess_extname_out:
191 0 free(secmess_ext_name);
192 0 remove_addrext_out:
193 0 globus_list_remove(&globus_i_service_engine_extensions,
194 globus_list_search(globus_i_service_engine_extensions,
195 addrextname));
196 0 deactivate_addrext_out:
197 0 globus_extension_deactivate(addrextname);
198 0 free_addrextname_out:
199 0 free(addrextname);
200 0 deactivate_provider_out:
201 0 globus_module_deactivate(GLOBUS_OPERATION_PROVIDER_MODULE);
202 0 deactivate_soap_message_out:
203 0 globus_module_deactivate(GLOBUS_SOAP_MESSAGE_MODULE);
204 0 deactivate_common_out:
205 0 globus_module_deactivate(GLOBUS_COMMON_MODULE);
206 }
207 649 out:
208 649 GlobusServiceEngineDebugExit();
209 649 return rc;
210 }
211 /* globus_l_service_engine_activate() */
212
213 static
214 void
215 globus_l_service_engine_extension_destroy(
216 void * sym)
217 252 {
218 252 char * symbol = (char *) sym;
219
220 252 globus_extension_deactivate(sym);
221 252 free(symbol);
222 252 }
223
224 static
225 void
226 globus_l_service_engine_destroy(
227 void * p)
228 27 {
229 27 globus_service_engine_t engine = p;
230 int res;
231
232 GlobusFuncName(globus_l_service_engine_destroy);
233 27 GlobusServiceEngineDebugEnter();
234
235 27 if(engine->handlers)
236 {
237 27 globus_handler_chain_destroy(engine->handlers);
238 }
239
240 27 if(engine->contact)
241 {
242 27 free(engine->contact);
243 }
244
245 27 if(engine->server)
246 {
247 27 globus_xio_server_close(engine->server);
248 }
249
250 27 res = globus_mutex_destroy(&engine->mutex);
251 27 globus_assert_string((res == 0), "Failed to destroy mutex");
252
253 27 if(engine->attrs)
254 {
255 27 globus_soap_message_attr_destroy(engine->attrs);
256 }
257
258 27 free(engine);
259 27 GlobusServiceEngineDebugExit();
260 27 }
261
262 static
263 int
264 globus_l_service_engine_deactivate(void)
265 126 {
266 126 int rc = 0;
267 GlobusFuncName(globus_l_service_engine_deactivate);
268 126 GlobusServiceEngineDebugEnter();
269
270 126 GlobusServiceEngineExtensionLock();
271 126 globus_list_destroy_all(globus_i_service_engine_extensions,
272 globus_l_service_engine_extension_destroy);
273 126 globus_list_destroy_all(globus_i_service_engine_instances,
274 globus_l_service_engine_destroy);
275 126 if (globus_i_service_engine_service_list)
276 {
277 126 free(globus_i_service_engine_service_list);
278 126 globus_i_service_engine_service_list = NULL;
279 }
280 126 GlobusServiceEngineExtensionUnlock();
281
282 #ifndef TARGET_ARCH_NETOS
283 126 if (globus_i_service_engine_usage != NULL)
284 {
285 126 globus_usage_stats_handle_destroy(globus_i_service_engine_usage);
286
287 126 rc = globus_module_deactivate(GLOBUS_USAGE_MODULE);
288 126 if(rc != GLOBUS_SUCCESS)
289 {
290 0 goto exit;
291 }
292 }
293 #endif
294
295 126 rc = globus_module_deactivate(GLOBUS_OPERATION_PROVIDER_MODULE);
296 126 if(rc != GLOBUS_SUCCESS)
297 {
298 0 goto exit;
299 }
300
301 126 rc = globus_module_deactivate(GLOBUS_SOAP_MESSAGE_MODULE);
302 if(rc != GLOBUS_SUCCESS)
303 {
304 126 goto exit;
305 }
306
307 126 exit:
308
309 126 GlobusServiceEngineDebugExit();
310 126 GlobusDebugDestroy(GLOBUS_SERVICE_ENGINE);
311 126 globus_module_deactivate(GLOBUS_COMMON_MODULE);
312
313 126 return rc;
314 }
315 /* globus_l_service_engine_deactivate() */
316
317 #ifdef WIN32
318 #define GLOBUS_LIBEXT ".dll"
319 #else
320 #define GLOBUS_LIBEXT ".so"
321 #endif
322
323 #define SERVICE_SUFFIX "_" GLOBUS_FLAVOR GLOBUS_LIBEXT
324 #define WSRF_SERVICES_PREFIX "/wsrf/services"
325
326 static
327 void
328 globus_l_service_engine_get_service_list(void)
329 649 {
330 globus_result_t result;
331 649 char * location = NULL;
332 char * dirpath;
333 DIR * d;
334 char * filename;
335 struct stat statbuf;
336 int rc;
337 649 globus_list_t * subdirs = NULL;
338 struct dirent *entryp;
339 649 char * service_list = NULL;
340 649 char suffix[] = SERVICE_SUFFIX;
341 size_t ignore_root;
342 649 size_t services_length = 0;
343
344 649 result = globus_location(&location);
345 649 if (result != GLOBUS_SUCCESS)
346 {
347 0 goto out;
348 }
349 649 dirpath = globus_common_create_string(
350 "%s/lib/%s",
351 location,
352 GLOBUS_SERVICE_ENGINE_MODULE_PATH_PREFIX WSRF_SERVICES_PREFIX);
353 649 ignore_root = strlen(dirpath);
354 649 globus_list_insert(&subdirs, dirpath);
355
356 1298 while (! globus_list_empty(subdirs))
357 {
358 649 dirpath = globus_list_remove(&subdirs, subdirs);
359 649 d = opendir(dirpath);
360 649 if (d == NULL)
361 {
362 0 goto free_subdirs_out;
363 }
364 649 for(rc = globus_libc_readdir_r(d, &entryp);
365 41536 rc == 0 && entryp;
366 40238 rc = globus_libc_readdir_r(d, &entryp))
367 {
368 40238 filename = globus_common_create_string("%s/%s",
369 dirpath, entryp->d_name);
370 40238 if (filename == NULL)
371 {
372 0 closedir(d);
373
374 0 free(entryp);
375 0 goto free_subdirs_out;
376 }
377 40238 rc = stat(filename, &statbuf);
378 40238 if (rc != 0)
379 {
380 0 free(filename);
381 0 closedir(d);
382 0 free(entryp);
383 0 goto free_subdirs_out;
384 }
385 40238 free(filename);
386
387 40238 if (statbuf.st_mode & S_IFREG)
388 {
389 size_t entry_len;
390 38940 entry_len = strlen(entryp->d_name);
391 38940 if (entry_len <= sizeof(suffix)-1)
392 {
393 0 free(entryp);
394 0 continue;
395 }
396 38940 if (strcmp(entryp->d_name + entry_len - sizeof(suffix) + 1,
397 suffix) != 0)
398 {
399 31152 free(entryp);
400 31152 continue;
401 }
402 7788 if (service_list == NULL)
403 {
404 649 service_list = malloc(
405 strlen(dirpath) + strlen(entryp->d_name)
406 + 2 - ignore_root);
407 }
408 else
409 {
410 char * s;
411 7139 s = realloc(
412 service_list,
413 services_length
414 + strlen(dirpath) + strlen(entryp->d_name)
415 + 2 - ignore_root);
416
417 7139 if (s == NULL)
418 {
419 0 closedir(d);
420
421 0 free(entryp);
422 0 goto free_subdirs_out;
423 }
424 7139 service_list = s;
425 7139 service_list[services_length++] = ',';
426 }
427 7788 services_length += sprintf(service_list+services_length,
428 "%s%s%s",
429 dirpath+ignore_root,
430 dirpath[ignore_root] == '\0' ? "" : "/",
431 entryp->d_name+3/*ignore lib*/);
432 7788 services_length -= sizeof(suffix) - 1;
433 7788 service_list[services_length] = 0;
434 }
435 1298 else if (statbuf.st_mode & S_IFDIR &&
436 strcmp(entryp->d_name, ".") &&
437 strcmp(entryp->d_name, ".."))
438 {
439 0 globus_list_insert(&subdirs,
440 globus_common_create_string(
441 "%s/%s",
442 dirpath,
443 entryp->d_name));
444 }
445 9086 free(entryp);
446 }
447 649 closedir(d);
448 649 if (rc != 0)
449 {
450 649 goto free_subdirs_out;
451 }
452 }
453
454 649 free_subdirs_out:
455 1298 while (!globus_list_empty(subdirs))
456 {
457 0 dirpath = globus_list_remove(&subdirs, subdirs);
458
459 0 free(dirpath);
460 }
461 649 globus_i_service_engine_service_list = service_list;
462 649 out:
463 649 if (globus_i_service_engine_service_list == NULL)
464 {
465 0 globus_i_service_engine_service_list = malloc(1);
466 0 globus_i_service_engine_service_list[0] = 0;
467 }
468 return;
469 }