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 #include "globus_i_service_engine.h"
18 #include "globus_soap_message.h"
19 #include "globus_soap_message_attrs.h"
20 #include "globus_xio_tcp_driver.h"
21 #include "globus_xio_http.h"
22 #include "globus_xio_gsi.h"
23 #include "globus_ws_addressing.h"
24 #include "globus_handler.h"
25 #include "globus_i_soap_message.h"
26 #include "globus_flavor.h"
27 #include "openssl/rand.h"
28 #include <syslog.h>
29
30 static
31 globus_bool_t
32 globus_l_service_engine_timeout_callback(
33 globus_xio_handle_t handle,
34 globus_xio_operation_type_t type,
35 void * user_arg);
36
37 /**
38 * Initialize a service engine
39 * @ingroup globus_service_engine
40 *
41 * Creates a new service engine. The service engine will be created on a
42 * new TCP port, but will not accept connections until either
43 * globus_service_engine_register_session() or
44 * globus_service_engine_register_start() is called.
45 *
46 * @param new_engine
47 * Pointer to a <code>globus_service_engine_t</code> which will contain
48 * the handle to the new engine after this function returns successfully.
49 * @param attrs
50 * Default @ref globus_soap_message_attrs "SOAP Message attributes" to
51 * use when this engine processes SOAP requests. This parameter may be
52 * NULL.
53 * @param port_contact
54 * String containing the TCP port number to use for this service engine.
55 * This parameter may be NULL. If the string "0" is used, then a port will
56 * be chosen automatically.
57 * @param handlers
58 * Chain of message handlers to use. If this is NULL, the handler chain
59 * will be derived from the default attributes. Experts only!
60 * @param enable_https
61 * Use transport-level security (TLS) to authenticate and protect messages
62 * sent and received by this engine.
63 *
64 * @retval GLOBUS_SUCCESS
65 * Engine initialized successfully.
66 * @retval GLOBUS_SERVICE_ENGINE_ERROR_TYPE_OUT_OF_MEMORY
67 * Insufficient memory to initialized the engine.
68 * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_NULL_PARAM
69 * The @a new_engine parameter is NULL.
70 * @retval GLOBUS_SERVICE_ENGINE_ERROR_TYPE_INIT_FAILED
71 * Internal error initializing the engine. The causal error will
72 * be generated by either
73 * - Globus XIO
74 * - Globus SOAP Message Attributes
75 * - Globus Handler Chain
76 * @retval GLOBUS_SERVICE_ENGINE_ERROR_TYPE_INVALID_CONTACT
77 * Invalid @a port_contact string.
78 *
79 */
80 globus_result_t
81 globus_service_engine_init(
82 globus_service_engine_t * new_engine,
83 globus_soap_message_attr_t attrs,
84 const char * port_contact,
85 globus_handler_chain_t handlers,
86 globus_bool_t enable_https)
87 303 {
88 303 globus_result_t result = GLOBUS_SUCCESS;
89 303 int port = 0;
90 303 globus_i_service_engine_t * engine = NULL;
91 303 globus_xio_attr_t server_attr = NULL;
92 303 char * contact = NULL;
93 303 void * timeout = NULL;
94 globus_soap_message_auth_method_t secattr;
95 int rc;
96 unsigned short randbytes;
97 GlobusFuncName(globus_service_engine_init);
98 303 GlobusServiceEngineDebugEnter();
99
100 303 if (new_engine == NULL)
101 {
102 0 result = GlobusSoapMessageErrorNullParam;
103
104 0 goto out;
105 }
106 303 engine = calloc(1, sizeof(globus_i_service_engine_t));
107 303 if(!engine)
108 {
109 0 result = GlobusServiceEngineErrorOutOfMemory;
110 0 goto out;
111 }
112 303 rc = globus_hashtable_init(
113 &engine->services,
114 13,
115 globus_hashtable_string_hash,
116 globus_hashtable_string_keyeq);
117 303 if (rc != GLOBUS_SUCCESS)
118 {
119 0 goto free_engine_out;
120 }
121 303 if(!attrs)
122 {
123 58 result = globus_soap_message_attr_init(&engine->attrs);
124 58 if(result != GLOBUS_SUCCESS)
125 {
126 0 result = GlobusServiceEngineErrorInitFailed(result);
127 0 goto free_engine_services_out;
128 }
129 }
130 else
131 {
132 245 result = globus_soap_message_attr_copy(
133 &engine->attrs, attrs);
134 245 if(result != GLOBUS_SUCCESS)
135 {
136 0 result = GlobusServiceEngineErrorInitFailed(result);
137 0 goto free_engine_services_out;
138 }
139 }
140
141 303 result = globus_xio_attr_init(&server_attr);
142 303 if(result != GLOBUS_SUCCESS)
143 {
144 0 result = GlobusServiceEngineErrorInitFailed(result);
145 0 goto free_engine_attrs_out;
146 }
147
148 303 if(port_contact)
149 {
150 236 port = atoi(port_contact);
151 236 if(port < 0)
152 {
153 0 result = GlobusServiceEngineErrorInvalidContact(port_contact);
154 0 goto free_server_attr_out;
155 }
156
157 236 result = globus_xio_attr_cntl(server_attr,
158 globus_i_soap_message_tcp_driver,
159 GLOBUS_XIO_TCP_SET_PORT, port);
160 236 if(result != GLOBUS_SUCCESS)
161 {
162 0 result = GlobusServiceEngineErrorInitFailed(result);
163 0 goto free_server_attr_out;
164 }
165
166 236 result = globus_xio_attr_cntl(server_attr,
167 globus_i_soap_message_tcp_driver,
168 GLOBUS_XIO_TCP_SET_REUSEADDR,
169 GLOBUS_TRUE);
170 236 if(result != GLOBUS_SUCCESS)
171 {
172 0 result = GlobusServiceEngineErrorInitFailed(result);
173 0 goto free_server_attr_out;
174 }
175 }
176 303 result = globus_xio_attr_cntl(server_attr,
177 globus_i_soap_message_tcp_driver,
178 GLOBUS_XIO_TCP_SET_NODELAY,
179 GLOBUS_TRUE);
180
181 303 if(result != GLOBUS_SUCCESS)
182 {
183 0 result = GlobusServiceEngineErrorInitFailed(result);
184
185 0 goto free_server_attr_out;
186 }
187
188
189 303 timeout = globus_soap_message_attr_get(
190 engine->attrs, GLOBUS_SOAP_MESSAGE_TIMEOUT_KEY);
191 303 if(timeout)
192 {
193 0 result = globus_xio_attr_cntl(
194 server_attr,
195 GLOBUS_NULL,
196 GLOBUS_XIO_ATTR_SET_TIMEOUT_ALL,
197 globus_l_service_engine_timeout_callback,
198 timeout,
199 GLOBUS_NULL);
200 0 if(result != GLOBUS_SUCCESS)
201 {
202 0 result = GlobusServiceEngineErrorInitFailed(result);
203 0 goto free_server_attr_out;
204 }
205 }
206 303 engine->logger = globus_soap_message_attr_get(
207 engine->attrs, GLOBUS_SOAP_MESSAGE_LOGGER_KEY);
208 303 if(enable_https)
209 {
210 5 engine->https = GLOBUS_TRUE;
211 5 result = globus_i_soap_message_setup_transport_security(
212 engine->attrs,
213 server_attr);
214 5 if(result != GLOBUS_SUCCESS)
215 {
216 0 result = GlobusServiceEngineErrorInitFailed(result);
217
218 0 goto free_server_attr_out;
219 }
220
221 5 result = globus_xio_server_create(
222 &engine->server,
223 server_attr,
224 globus_i_soap_message_xio_https_stack);
225 5 if(result != GLOBUS_SUCCESS)
226 {
227 0 result = GlobusServiceEngineErrorInitFailed(result);
228
229 0 goto free_server_attr_out;
230 }
231 }
232 else
233 {
234 298 result = globus_xio_server_create(&engine->server,
235 server_attr,
236 globus_i_soap_message_xio_stack);
237 298 if(result != GLOBUS_SUCCESS)
238 {
239 0 result = GlobusServiceEngineErrorInitFailed(result);
240
241 0 goto free_server_attr_out;
242 }
243 }
244
245 303 globus_mutex_init(&engine->mutex, NULL);
246
247 303 result = globus_xio_server_get_contact_string(engine->server, &contact);
248 303 if (result != GLOBUS_SUCCESS)
249 {
250 0 result = GlobusServiceEngineErrorInitFailed(result);
251
252 0 goto destroy_mutex_out;
253 }
254 303 engine->contact = globus_common_create_string(
255 "http%s://%s/",
256 (enable_https ? "s" : ""),
257 contact);
258 303 free(contact);
259 303 if (engine->contact == NULL)
260 {
261 0 result = GlobusServiceEngineErrorOutOfMemory;
262
263 0 goto destroy_mutex_out;
264 }
265
266 303 if(!handlers)
267 {
268 303 result = globus_handler_chain_init(&engine->handlers);
269 303 if (result != GLOBUS_SUCCESS)
270 {
271 0 result = GlobusServiceEngineErrorInitFailed(result);
272
273 0 goto free_engine_contact_out;
274 }
275
276 303 result = globus_handler_chain_push(
277 engine->handlers,
278 GLOBUS_HANDLER_TYPE_REQUEST_ALL,
279 GLOBUS_HANDLER_WS_ADDRESSING_SERVER);
280 303 if(result != GLOBUS_SUCCESS)
281 {
282 0 result = GlobusServiceEngineErrorInitFailed(result);
283
284 0 goto destroy_engine_handlers_out;
285 }
286
287 303 result = globus_handler_chain_push(
288 engine->handlers,
289 GLOBUS_HANDLER_TYPE_RESPONSE_ALL,
290 GLOBUS_HANDLER_WS_ADDRESSING_SERVER);
291 303 if(result != GLOBUS_SUCCESS)
292 {
293 0 result = GlobusServiceEngineErrorInitFailed(result);
294
295 0 goto destroy_engine_handlers_out;
296 }
297
298 303 secattr = (globus_soap_message_auth_method_t)
299 globus_soap_message_attr_get(
300 engine->attrs,
301 GLOBUS_SOAP_MESSAGE_AUTHENTICATION_METHOD_KEY);
302
303 303 if ((!enable_https) &&
304 (secattr == GLOBUS_SOAP_MESSAGE_AUTH_SECURE ||
305 secattr == GLOBUS_SOAP_MESSAGE_AUTH_SECURE_MESSAGE))
306 {
307 0 result = globus_handler_chain_push(
308 engine->handlers,
309 GLOBUS_HANDLER_TYPE_REQUEST,
310 "globus_handler_ws_secure_message_server");
311 0 if(result != GLOBUS_SUCCESS)
312 {
313 0 result = GlobusServiceEngineErrorInitFailed(result);
314
315 0 goto destroy_engine_handlers_out;
316 }
317
318 0 result = globus_handler_chain_push(
319 engine->handlers,
320 GLOBUS_HANDLER_TYPE_RESPONSE_ALL,
321 "globus_handler_ws_secure_message_server");
322 0 if(result != GLOBUS_SUCCESS)
323 {
324 0 result = GlobusServiceEngineErrorInitFailed(result);
325
326 0 goto destroy_engine_handlers_out;
327 }
328 }
329 }
330 else
331 {
332 0 result = globus_handler_chain_copy(&engine->handlers, handlers);
333 0 if (result != GLOBUS_SUCCESS)
334 {
335 0 result = GlobusServiceEngineErrorInitFailed(result);
336
337 0 goto free_engine_contact_out;
338 }
339 }
340
341 303 GlobusServiceEngineExtensionLock();
342 303 rc = globus_list_insert(&globus_i_service_engine_instances, engine);
343 303 GlobusServiceEngineExtensionUnlock();
344 303 if (rc != 0)
345 {
346 0 result = GlobusServiceEngineErrorOutOfMemory;
347
348 0 goto destroy_engine_handlers_out;
349 }
350
351 303 RAND_pseudo_bytes(&randbytes, sizeof(randbytes));
352 303 sprintf(engine->id, "%hu", randbytes);
353
354 303 globus_usage_stats_send(globus_i_service_engine_usage,
355 3,
356 "ID",
357 engine->id,
358 "EVENT",
359 "1",
360 "SERVICES",
361 globus_i_service_engine_service_list);
362
363 303 *new_engine = engine;
364
365 303 globus_logging_write(
366 engine->logger,
367 LOG_INFO,
368 "event=globus_service_engine.start "
369 "engine_id=%s "
370 "contact=%s\n",
371 engine->id,
372 engine->contact);
373
374 303 if (result != GLOBUS_SUCCESS)
375 {
376 0 destroy_engine_handlers_out:
377 0 globus_handler_chain_destroy(engine->handlers);
378 0 free_engine_contact_out:
379 0 free(engine->contact);
380 0 destroy_mutex_out:
381 0 globus_mutex_destroy(&engine->mutex);
382 0 globus_xio_server_close(engine->server);
383 0 free_server_attr_out:
384 0 globus_xio_attr_destroy(server_attr);
385 0 free_engine_attrs_out:
386 0 globus_soap_message_attr_destroy(engine->attrs);
387 0 free_engine_services_out:
388 0 globus_hashtable_destroy(&engine->services);
389 0 free_engine_out:
390 0 free(engine);
391 }
392 303 out:
393 303 GlobusServiceEngineDebugExit();
394 303 return result;
395 }
396 /* globus_service_engine_init() */
397
398 static
399 globus_bool_t
400 globus_l_service_engine_timeout_callback(
401 globus_xio_handle_t handle,
402 globus_xio_operation_type_t type,
403 void * user_arg)
404 0 {
405 0 return GLOBUS_TRUE;
406 }