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 #include "globus_i_soap_client.h"
19 #include "globus_service_registry.h"
20 #include "globus_i_service_engine.h"
21 #include "globus_i_soap_message.h"
22 #include "globus_xio_http.h"
23
24
25 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
26 static
27 void
28 globus_l_soap_client_request_done_callback(
29 globus_result_t result,
30 void * args);
31
32 static
33 void
34 globus_l_soap_client_request_callback(
35 void * args);
36
37 static
38 globus_result_t
39 globus_l_soap_client_request_reinit_handle(
40 globus_i_soap_client_request_handle_t *
41 request);
42 #endif
43
44 /**
45 * Nonblocking SOAP request invocation.
46 * @ingroup globus_soap_client_request
47 * @internal
48 *
49 * Invokes the operation described by the @a operation parameter on the
50 * container running at the named @a endpoint. Once the message has been
51 * sent by the client (and all applicable handlers have been invoked), the
52 * @a callback function will be invoked. Once that occurs, the application
53 * may call globus_soap_client_register_response() to begin to retrieve
54 * the result of the operation.
55 *
56 * @param client_handle
57 * The SOAP client handle to use for state while processing this
58 * request.
59 * @param endpoint
60 * The URI of the endpoint to send the SOAP operation request to.
61 * @param operation
62 * The description of the operation and its serializers and deserializers.
63 * This must not be modified until the operation and its response have
64 * been processed by the client handle.
65 * @param input
66 * The operation's input element value. A copy of this value will be made
67 * by this function, so this parameter's value may be freed or otherwise
68 * modified by the caller after this function returns.
69 * @param callback
70 * Callback function to invoke once the operation request has been sent.
71 * @param user_args
72 * Application-specific argument to the callback function.
73 *
74 * @retval GLOBUS_SUCCESS
75 * Processing of this operation has begun successfully.
76 * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_CLIENT_ALREADY_INVOKED
77 * Processing the operation failed because the client is already actively
78 * handling a request or response.
79 * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_INIT_FAILED
80 * Processing the operation failed because the client could not initialize
81 * some part of its data.
82 * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_CLIENT_REQUEST_FAILED
83 * Processing the operation failed because the client could not initialize
84 * some part of its data.
85 */
86 globus_result_t
87 globus_soap_client_register_request(
88 globus_soap_client_handle_t client_handle,
89 const char * endpoint,
90 const globus_soap_client_operation_t *
91 operation,
92 void * input,
93 globus_soap_client_request_callback_func_t
94 callback,
95 void * user_args)
96 11559 {
97 11559 globus_handler_chain_t chain = NULL;
98 11559 globus_result_t result = GLOBUS_SUCCESS;
99 globus_i_soap_client_request_handle_t *
100 11559 request = NULL;
101 11559 globus_service_engine_t engine = NULL;
102
103 11559 if (client_handle->message != NULL)
104 {
105 0 result = GlobusSoapMessageErrorClientAlreadyInvoked();
106 0 goto exit;
107 }
108
109 /* If this handle was used previously, then the response will
110 * contain a copy of the response if the operation was successful and
111 * there was a response and the call was not done with a blocking
112 * function.
113 */
114 11559 globus_i_soap_client_request_handle_destroy(&client_handle->request);
115 11559 globus_i_soap_client_response_handle_destroy(&client_handle->response);
116
117 11559 result = globus_soap_message_handle_init(&client_handle->message, NULL);
118 11559 if (result != GLOBUS_SUCCESS)
119 {
120 0 result = GlobusSoapMessageErrorFailedClientInit(
121 result, operation->request_action);
122 0 goto error_exit;
123 }
124
125 11559 chain = client_handle->handler_chain;
126
127 11559 if (chain != NULL)
128 {
129 11559 globus_soap_message_set_handler_chain(client_handle->message, chain);
130 }
131
132 11559 request = &client_handle->request;
133
134 11559 globus_assert_string(endpoint, "NULL endpoint");
135
136 11559 request->endpoint = globus_libc_strdup(endpoint);
137 11559 request->callback = callback;
138 11559 request->args = user_args;
139 11559 operation->input_type_info->copy(&request->input, input);
140 11559 request->state = GLOBUS_SOAP_CLIENT_REQUEST_INIT;
141 11559 client_handle->operation = operation;
142
143 11559 globus_l_soap_client_request_reinit_handle(request);
144
145 11559 result = globus_service_engine_lookup(
146 endpoint, &engine);
147
148 11559 if (engine != NULL)
149 {
150 /* Local invocation mode */
151 0 result = globus_soap_message_attr_set(
152 client_handle->attrs,
153 GLOBUS_SOAP_CLIENT_LOCAL_INVOCATION_KEY,
154 NULL,
155 NULL,
156 engine);
157
158 0 if (result != GLOBUS_SUCCESS)
159 {
160 0 goto exit;
161 }
162 0 request->state = GLOBUS_SOAP_CLIENT_REQUEST_LOCAL_INVOCATION;
163 }
164
165 11559 result = globus_callback_register_oneshot(
166 &request->callback_handle,
167 NULL,
168 globus_l_soap_client_request_callback,
169 request);
170 11559 if(result != GLOBUS_SUCCESS)
171 {
172 0 result = GlobusSoapMessageErrorClientRequestFailed(
173 result, operation->request_action);
174 0 goto error_exit;
175 }
176
177 11559 goto exit;
178
179 0 error_exit:
180
181 0 if(request->input && operation->input_type_info)
182 {
183 0 operation->input_type_info->destroy(request->input);
184 }
185 0 if(request->endpoint)
186 {
187 0 globus_free(request->endpoint);
188 }
189
190 0 if(client_handle->message)
191 {
192 0 globus_soap_message_handle_destroy(client_handle->message);
193 0 client_handle->message = NULL;
194 }
195
196 11559 exit:
197
198 11559 return result;
199 }
200 /* globus_soap_client_register_request() */
201
202 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
203 static
204 void
205 globus_l_soap_client_request_done_callback(
206 globus_result_t result,
207 void * args)
208 23090 {
209 globus_i_soap_client_request_handle_t * request;
210
211 23090 request = args;
212 23090 globus_assert_string(request, "request handle in callback is NULL");
213
214 23090 globus_mutex_lock(&request->client_handle->mutex);
215 23090 request->result = result;
216 23090 request->done = 1;
217 23090 globus_mutex_unlock(&request->client_handle->mutex);
218
219 23090 globus_l_soap_client_request_callback(request);
220 23090 }
221 /* globus_l_soap_client_request_done_callback() */
222
223 extern
224 void
225 globus_i_soap_client_request_handle_destroy(
226 globus_i_soap_client_request_handle_t *
227 request)
228 11995 {
229 globus_bool_t active;
230
231 11995 globus_assert_string(request, "request handle in callback is NULL");
232
233 11995 globus_mutex_lock(&request->client_handle->mutex);
234
235 11995 if (request->callback_handle)
236 {
237 0 globus_callback_unregister(
238 request->callback_handle,
239 NULL,
240 NULL,
241 &active);
242
243 0 if (active)
244 {
245 0 request->state = GLOBUS_SOAP_CLIENT_REQUEST_DESTROY_HANDLERS;
246 0 request->done = 0;
247
248 0 goto out;
249 }
250 0 request->callback_handle = GLOBUS_NULL_HANDLE;
251 }
252 11995 if(request->input)
253 {
254 11509 if (request->client_handle->operation->input_type_info)
255 {
256 11509 request->client_handle->operation->input_type_info->destroy(request->input);
257 }
258
259 11509 request->input = NULL;
260 }
261
262 11995 if(request->endpoint)
263 {
264 11509 globus_free(request->endpoint);
265 11509 request->endpoint = NULL;
266 }
267 11995 out:
268 11995 globus_mutex_unlock(&request->client_handle->mutex);
269 11995 }
270 /* globus_i_soap_client_request_handle_destroy() */
271
272 static
273 void
274 globus_l_soap_client_request_callback(
275 void * args)
276 34649 {
277 34649 globus_soap_message_handle_t message_handle = NULL;
278 34649 globus_result_t result = GLOBUS_SUCCESS;
279 34649 globus_handler_chain_t chain = NULL;
280 globus_i_soap_client_request_handle_t *
281 request;
282 const globus_soap_client_operation_t *
283 operation;
284 xsd_QName subelement;
285 globus_service_descriptor_t * service_desc;
286 globus_service_engine_t engine;
287 int rc;
288 globus_url_t url;
289 globus_service_operation_descriptor_t *
290 34649 op_desc = NULL;
291 globus_result_t (*invoke_function)();
292 char * fault_name;
293 void * fault;
294 34649 globus_bool_t callback_registered = GLOBUS_FALSE;
295
296 34649 request = args;
297 34649 globus_assert_string(request, "request handle is NULL");
298
299 34649 operation = request->client_handle->operation;
300
301 34649 if (request->callback_handle != GLOBUS_NULL_HANDLE)
302 {
303 11559 globus_callback_unregister(
304 request->callback_handle,
305 NULL,
306 NULL,
307 NULL);
308 11559 request->callback_handle = GLOBUS_NULL_HANDLE;
309 }
310
311 34649 globus_mutex_lock(&request->client_handle->mutex);
312 do
313 {
314 69270 GlobusSoapMessageDebugPrintf(GLOBUS_SOAP_MESSAGE_DEBUG_DEBUG,
315 ("globus_l_soap_client_request_callback: state = %d, "
316 "result = %p\n",
317 request->state,
318 (void *) request->result));
319
320 69270 switch(request->state)
321 {
322 case GLOBUS_SOAP_CLIENT_REQUEST_INIT:
323
324 11559 request->state = GLOBUS_SOAP_CLIENT_REQUEST_INIT_HANDLERS;
325
326 11559 result = globus_soap_message_get_handler_chain(
327 request->client_handle->message, &chain);
328 11559 if(result != GLOBUS_SUCCESS)
329 {
330 0 goto error_exit;
331 }
332
333 11559 if(chain)
334 {
335 11559 result = globus_handler_chain_invoke(
336 chain,
337 GLOBUS_HANDLER_TYPE_REQUEST_INIT,
338 request->client_handle->message);
339
340 11559 if (result != GLOBUS_SUCCESS)
341 {
342 0 goto error_exit;
343 }
344 }
345
346 11559 break;
347
348 case GLOBUS_SOAP_CLIENT_REQUEST_INIT_HANDLERS:
349 11559 request->state = GLOBUS_SOAP_CLIENT_REQUEST_OPENING;
350
351 11559 result = globus_soap_message_register_open(
352 request->client_handle->message,
353 request->endpoint,
354 globus_l_soap_client_request_done_callback,
355 request);
356 11559 if(result != GLOBUS_SUCCESS)
357 {
358 0 goto error_exit;
359 }
360 11559 callback_registered = GLOBUS_TRUE;
361
362 11559 break;
363
364 case GLOBUS_SOAP_CLIENT_REQUEST_OPENING:
365 11559 if(request->result != GLOBUS_SUCCESS)
366 {
367 28 result = request->result;
368 28 goto error_exit;
369 }
370
371 11531 request->state = GLOBUS_SOAP_CLIENT_REQUEST_INVOKING_HANDLERS;
372
373 11531 result = globus_soap_message_serialize_envelope(
374 request->client_handle->message);
375 11531 if(result != GLOBUS_SUCCESS)
376 {
377 0 goto error_exit;
378 }
379
380 11531 result = globus_soap_message_serialize_header(
381 request->client_handle->message);
382 11531 if(result != GLOBUS_SUCCESS)
383 {
384 0 goto error_exit;
385 }
386
387 11531 result = globus_soap_message_serialize_header_begin_close(
388 request->client_handle->message);
389 11531 if(result != GLOBUS_SUCCESS)
390 {
391 0 goto error_exit;
392 }
393
394 11531 result = globus_soap_message_set_marker(
395 request->client_handle->message,
396 GLOBUS_SOAP_MESSAGE_MARKER_HEADER_CONTENT);
397 11531 if(result != GLOBUS_SUCCESS)
398 {
399 0 goto error_exit;
400 }
401
402 11531 result = globus_soap_message_serialize_header_end(
403 request->client_handle->message);
404 11531 if(result != GLOBUS_SUCCESS)
405 {
406 0 goto error_exit;
407 }
408
409 11531 result = globus_soap_message_serialize_body(
410 request->client_handle->message);
411 11531 if(result != GLOBUS_SUCCESS)
412 {
413 0 goto error_exit;
414 }
415
416 11531 result = globus_soap_message_serialize_body_begin_close(
417 request->client_handle->message);
418 11531 if(result != GLOBUS_SUCCESS)
419 {
420 0 goto error_exit;
421 }
422
423 11531 subelement.Namespace = operation->input_element.Namespace;
424 11531 subelement.local = operation->input_element.local;
425
426 11531 result = operation->input_type_info->serialize(
427 &subelement,
428 request->input,
429 request->client_handle->message,
430 0);
431 11531 if(result != GLOBUS_SUCCESS)
432 {
433 0 goto error_exit;
434 }
435
436 11531 result = globus_soap_message_serialize_body_end(
437 request->client_handle->message);
438 11531 if(result != GLOBUS_SUCCESS)
439 {
440 0 goto error_exit;
441 }
442
443 11531 result = globus_soap_message_serialize_envelope_end(
444 request->client_handle->message);
445 11531 if(result != GLOBUS_SUCCESS)
446 {
447 0 goto error_exit;
448 }
449
450 11531 result = globus_soap_message_set_write_position_to_marker(
451 request->client_handle->message,
452 GLOBUS_SOAP_MESSAGE_MARKER_HEADER_CONTENT);
453 11531 if(result != GLOBUS_SUCCESS)
454 {
455 0 goto error_exit;
456 }
457
458 11531 result = globus_soap_message_get_handler_chain(
459 request->client_handle->message, &chain);
460 11531 if(result != GLOBUS_SUCCESS)
461 {
462 0 goto error_exit;
463 }
464
465 11531 if(chain)
466 {
467 11531 result = globus_handler_chain_invoke(
468 chain,
469 GLOBUS_HANDLER_TYPE_REQUEST,
470 request->client_handle->message);
471
472 11531 if (result != GLOBUS_SUCCESS)
473 {
474 0 goto error_exit;
475 }
476 }
477 11531 break;
478
479 case GLOBUS_SOAP_CLIENT_REQUEST_INVOKING_HANDLERS:
480
481 11531 if(request->result != GLOBUS_SUCCESS)
482 {
483 0 result = request->result;
484 0 goto error_exit;
485 }
486
487 11531 request->state = GLOBUS_SOAP_CLIENT_REQUEST_SENDING;
488
489 11531 result = globus_soap_message_register_write_request(
490 request->client_handle->message,
491 globus_l_soap_client_request_done_callback,
492 request,
493 operation->output_type_info != NULL ||
494 operation->response_action != NULL);
495 11531 if(result != GLOBUS_SUCCESS)
496 {
497 0 goto error_exit;
498 }
499 11531 callback_registered = GLOBUS_TRUE;
500
501 11531 break;
502
503 case GLOBUS_SOAP_CLIENT_REQUEST_SENDING:
504 11531 if(request->result != GLOBUS_SUCCESS)
505 {
506 0 result = request->result;
507 0 goto error_exit;
508 }
509
510 11531 request->state = GLOBUS_SOAP_CLIENT_REQUEST_DESTROY_HANDLERS;
511
512 11531 result = globus_soap_message_get_handler_chain(
513 request->client_handle->message, &chain);
514 11531 if(result != GLOBUS_SUCCESS)
515 {
516 0 goto error_exit;
517 }
518
519 11531 if(chain)
520 {
521 11531 result = globus_handler_chain_invoke(
522 chain,
523 GLOBUS_HANDLER_TYPE_REQUEST_DESTROY,
524 request->client_handle->message);
525
526 11531 if (result != GLOBUS_SUCCESS)
527 {
528 0 goto error_exit;
529 }
530 }
531 11531 break;
532
533 case GLOBUS_SOAP_CLIENT_REQUEST_DESTROY_HANDLERS:
534 11531 if(request->result != GLOBUS_SUCCESS)
535 {
536 0 result = request->result;
537 0 goto error_exit;
538 }
539
540 11531 globus_mutex_unlock(&request->client_handle->mutex);
541
542 11531 request->callback(
543 request->client_handle,
544 request->args, GLOBUS_SUCCESS);
545
546 11531 return;
547
548 case GLOBUS_SOAP_CLIENT_REQUEST_LOCAL_INVOCATION:
549 0 rc = globus_url_parse(request->endpoint, &url);
550
551 0 if (rc != 0)
552 {
553 0 goto error_exit;
554 }
555 0 result = globus_i_service_engine_get_descriptor(
556 url.url_path,
557 request->client_handle->message,
558 &service_desc);
559 0 globus_url_destroy(&url);
560 0 if (result != GLOBUS_SUCCESS || service_desc == NULL)
561 {
562 goto error_exit;
563 }
564
565 0 if(service_desc->op_mapper)
566 {
567 0 op_desc = globus_hashtable_lookup(
568 &service_desc->op_mapper,
569 (void *) &request->client_handle->operation->input_element);
570
571 0 result = globus_operation_table_get_operation(
572 service_desc->operations,
573 request->client_handle->operation->input_element.local,
574 (void **)&invoke_function);
575 }
576 0 engine = globus_soap_message_attr_get(
577 request->client_handle->attrs,
578 GLOBUS_SOAP_CLIENT_LOCAL_INVOCATION_KEY);
579
580 /* No-response operations will have a null output_type_info */
581 0 if (request->client_handle->operation->output_type_info)
582 {
583 0 request->client_handle->operation->output_type_info->initialize(
584 &request->client_handle->response.output);
585 }
586
587 0 if (op_desc->fault_type != NULL)
588 {
589 0 fault_name = NULL;
590 0 fault = NULL;
591
592 0 result = invoke_function(
593 engine,
594 request->client_handle->message,
595 service_desc,
596 request->input,
597 request->client_handle->response.output,
598 &fault_name,
599 &fault);
600
601 0 if (result == GLOBUS_SUCCESS && fault_name != NULL)
602 {
603 0 xsd_any * fault_any = NULL;
604 int fault_type;
605
606 0 xsd_any_init(&fault_any);
607
608 0 result = op_desc->fault_type(
609 fault_name,
610 &fault_type,
611 &fault_any->any_info);
612
613 0 fault_any->value = fault;
614
615 0 request->client_handle->response.fault = fault;
616 0 request->client_handle->response.fault_type = fault_type;
617 }
618 }
619 else
620 {
621 0 request->client_handle->response.result = result = invoke_function(
622 engine,
623 request->client_handle->message,
624 service_desc,
625 request->input);
626 }
627 0 request->client_handle->response.result = result;
628
629 0 globus_mutex_unlock(&request->client_handle->mutex);
630 0 request->callback(
631 request->client_handle,
632 request->args, GLOBUS_SUCCESS);
633 0 return;
634
635 case GLOBUS_SOAP_CLIENT_REQUEST_REINIT:
636 0 globus_soap_message_handle_reset(request->client_handle->message);
637 0 result = globus_l_soap_client_request_reinit_handle(request);
638 0 if (result != GLOBUS_SUCCESS)
639 {
640 0 goto error_exit;
641 }
642 0 request->state = GLOBUS_SOAP_CLIENT_REQUEST_INIT;
643 0 break;
644
645 default:
646
647 0 globus_assert_string(NULL, "Unkown request state");
648 break;
649 }
650 }
651 57711 while (! callback_registered);
652
653 23090 globus_mutex_unlock(&request->client_handle->mutex);
654
655 23090 return;
656
657 28 error_exit:
658 28 if (globus_soap_message_attr_get(
659 request->client_handle->attrs,
660 GLOBUS_SOAP_MESSAGE_RETRY_ON_DROP_KEY) &&
661 globus_xio_driver_error_match(
662 globus_i_soap_message_http_driver,
663 globus_error_peek(result),
664 GLOBUS_XIO_HTTP_ERROR_PERSISTENT_CONNECTION_DROPPED))
665 {
666 0 GlobusSoapMessageDebugPrintf(GLOBUS_SOAP_MESSAGE_DEBUG_DEBUG,
667 ("Server connection dropped... reinitializing\n"));
668 0 result = globus_soap_message_register_close(
669 request->client_handle->message,
670 globus_l_soap_client_request_done_callback,
671 request);
672
673 0 request->state = GLOBUS_SOAP_CLIENT_REQUEST_REINIT;
674 0 request->done = GLOBUS_FALSE;
675
676 0 if (result == GLOBUS_SUCCESS)
677 {
678 0 globus_mutex_unlock(&request->client_handle->mutex);
679 0 return;
680 }
681 }
682
683 28 result = GlobusSoapMessageErrorClientRequestFailed(
684 result, operation->request_action);
685
686 28 message_handle = request->client_handle->message;
687 28 request->client_handle->message = NULL;
688 28 globus_mutex_unlock(&request->client_handle->mutex);
689
690 28 request->callback(request->client_handle, request->args, result);
691
692 28 globus_soap_message_handle_destroy(message_handle);
693 }
694 /* globus_l_soap_client_request_callback() */
695
696 static
697 globus_result_t
698 globus_l_soap_client_request_reinit_handle(
699 globus_i_soap_client_request_handle_t *
700 request)
701 11559 {
702 11559 globus_result_t result = GLOBUS_SUCCESS;
703 const globus_soap_client_operation_t *
704 operation;
705
706 11559 operation = request->client_handle->operation;
707
708 11559 result = globus_soap_message_attr_set(
709 request->client_handle->attrs,
710 WSADDR_DESTINATION_KEY,
711 globus_soap_message_attr_copy_string,
712 globus_libc_free,
713 (void *)request->endpoint);
714 11559 if(result != GLOBUS_SUCCESS)
715 {
716 0 result = GlobusSoapMessageErrorClientRequestFailed(
717 result, operation->request_action);
718 0 goto error_exit;
719 }
720
721 11559 if (operation->request_action != NULL)
722 {
723 11559 result = globus_soap_message_attr_set(
724 request->client_handle->attrs,
725 WSADDR_ACTION_REQUEST_KEY,
726 NULL,
727 NULL,
728 (void *) operation->request_action);
729 11559 if(result != GLOBUS_SUCCESS)
730 {
731 0 result = GlobusSoapMessageErrorClientRequestFailed(
732 result, operation->request_action);
733 0 goto error_exit;
734 }
735
736 11559 result = globus_soap_message_attr_set(
737 request->client_handle->attrs,
738 GLOBUS_SOAP_MESSAGE_SOAP_ACTION_KEY,
739 NULL,
740 NULL,
741 (void *) operation->request_action);
742
743 11559 if(result != GLOBUS_SUCCESS)
744 {
745 0 result = GlobusSoapMessageErrorClientRequestFailed(
746 result, operation->request_action);
747 0 goto error_exit;
748 }
749 }
750
751 11559 result = globus_soap_message_handle_set_attrs(
752 request->client_handle->message, request->client_handle->attrs);
753 11559 if(result != GLOBUS_SUCCESS)
754 {
755 0 result = GlobusSoapMessageErrorClientRequestFailed(
756 result, operation->request_action);
757 }
758
759 goto exit;
760
761 11559 error_exit:
762 11559 exit:
763
764 11559 return result;
765 }