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 12991 {
97 12991 globus_handler_chain_t chain = NULL;
98 12991 globus_result_t result = GLOBUS_SUCCESS;
99 globus_i_soap_client_request_handle_t *
100 12991 request = NULL;
101 12991 globus_service_engine_t engine = NULL;
102
103 12991 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 12991 globus_i_soap_client_request_handle_destroy(&client_handle->request);
115 12991 globus_i_soap_client_response_handle_destroy(&client_handle->response);
116
117 12991 result = globus_soap_message_handle_init(&client_handle->message, NULL);
118 12991 if (result != GLOBUS_SUCCESS)
119 {
120 0 result = GlobusSoapMessageErrorFailedClientInit(
121 result, operation->request_action);
122 0 goto error_exit;
123 }
124
125 12991 chain = client_handle->handler_chain;
126
127 12991 if (chain != NULL)
128 {
129 12991 globus_soap_message_set_handler_chain(client_handle->message, chain);
130 }
131
132 12991 request = &client_handle->request;
133
134 12991 globus_assert_string(endpoint, "NULL endpoint");
135
136 12991 request->endpoint = globus_libc_strdup(endpoint);
137 12991 request->callback = callback;
138 12991 request->args = user_args;
139 12991 operation->input_type_info->copy(&request->input, input);
140 12991 request->state = GLOBUS_SOAP_CLIENT_REQUEST_INIT;
141 12991 client_handle->operation = operation;
142
143 12991 globus_l_soap_client_request_reinit_handle(request);
144
145 12991 result = globus_service_engine_lookup(
146 endpoint, &engine);
147
148 12991 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 12991 result = globus_callback_register_oneshot(
166 &request->callback_handle,
167 NULL,
168 globus_l_soap_client_request_callback,
169 request);
170 12991 if(result != GLOBUS_SUCCESS)
171 {
172 0 result = GlobusSoapMessageErrorClientRequestFailed(
173 result, operation->request_action);
174 0 goto error_exit;
175 }
176
177 12991 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 12991 exit:
197
198 12991 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 25943 {
209 globus_i_soap_client_request_handle_t * request;
210
211 25943 request = args;
212 25943 globus_assert_string(request, "request handle in callback is NULL");
213
214 25943 globus_mutex_lock(&request->client_handle->mutex);
215 25943 request->result = result;
216 25943 request->done = 1;
217 25943 globus_mutex_unlock(&request->client_handle->mutex);
218
219 25943 globus_l_soap_client_request_callback(request);
220 25943 }
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 13459 {
229 globus_bool_t active;
230
231 13459 globus_assert_string(request, "request handle in callback is NULL");
232
233 13459 globus_mutex_lock(&request->client_handle->mutex);
234
235 13459 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 13459 if(request->input)
253 {
254 12933 if (request->client_handle->operation->input_type_info)
255 {
256 12933 request->client_handle->operation->input_type_info->destroy(request->input);
257 }
258
259 12933 request->input = NULL;
260 }
261
262 13459 if(request->endpoint)
263 {
264 12933 globus_free(request->endpoint);
265 12933 request->endpoint = NULL;
266 }
267 13459 out:
268 13459 globus_mutex_unlock(&request->client_handle->mutex);
269 13459 }
270 /* globus_i_soap_client_request_handle_destroy() */
271
272 static
273 void
274 globus_l_soap_client_request_callback(
275 void * args)
276 38934 {
277 38934 globus_soap_message_handle_t message_handle = NULL;
278 38934 globus_result_t result = GLOBUS_SUCCESS;
279 38934 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 38934 op_desc = NULL;
291 globus_result_t (*invoke_function)();
292 char * fault_name;
293 void * fault;
294 38934 globus_bool_t callback_registered = GLOBUS_FALSE;
295
296 38934 request = args;
297 38934 globus_assert_string(request, "request handle is NULL");
298
299 38934 operation = request->client_handle->operation;
300
301 38934 if (request->callback_handle != GLOBUS_NULL_HANDLE)
302 {
303 12991 globus_callback_unregister(
304 request->callback_handle,
305 NULL,
306 NULL,
307 NULL);
308 12991 request->callback_handle = GLOBUS_NULL_HANDLE;
309 }
310
311 38934 globus_mutex_lock(&request->client_handle->mutex);
312 do
313 {
314 77829 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 77829 switch(request->state)
321 {
322 case GLOBUS_SOAP_CLIENT_REQUEST_INIT:
323
324 12991 request->state = GLOBUS_SOAP_CLIENT_REQUEST_INIT_HANDLERS;
325
326 12991 result = globus_soap_message_get_handler_chain(
327 request->client_handle->message, &chain);
328 12991 if(result != GLOBUS_SUCCESS)
329 {
330 0 goto error_exit;
331 }
332
333 12991 if(chain)
334 {
335 12991 result = globus_handler_chain_invoke(
336 chain,
337 GLOBUS_HANDLER_TYPE_REQUEST_INIT,
338 request->client_handle->message);
339
340 12991 if (result != GLOBUS_SUCCESS)
341 {
342 0 goto error_exit;
343 }
344 }
345
346 12991 break;
347
348 case GLOBUS_SOAP_CLIENT_REQUEST_INIT_HANDLERS:
349 12991 request->state = GLOBUS_SOAP_CLIENT_REQUEST_OPENING;
350
351 12991 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 12991 if(result != GLOBUS_SUCCESS)
357 {
358 0 goto error_exit;
359 }
360 12991 callback_registered = GLOBUS_TRUE;
361
362 12991 break;
363
364 case GLOBUS_SOAP_CLIENT_REQUEST_OPENING:
365 12991 if(request->result != GLOBUS_SUCCESS)
366 {
367 39 result = request->result;
368 39 goto error_exit;
369 }
370
371 12952 request->state = GLOBUS_SOAP_CLIENT_REQUEST_INVOKING_HANDLERS;
372
373 12952 result = globus_soap_message_serialize_envelope(
374 request->client_handle->message);
375 12952 if(result != GLOBUS_SUCCESS)
376 {
377 0 goto error_exit;
378 }
379
380 12952 result = globus_soap_message_serialize_header(
381 request->client_handle->message);
382 12952 if(result != GLOBUS_SUCCESS)
383 {
384 0 goto error_exit;
385 }
386
387 12952 result = globus_soap_message_serialize_header_begin_close(
388 request->client_handle->message);
389 12952 if(result != GLOBUS_SUCCESS)
390 {
391 0 goto error_exit;
392 }
393
394 12952 result = globus_soap_message_set_marker(
395 request->client_handle->message,
396 GLOBUS_SOAP_MESSAGE_MARKER_HEADER_CONTENT);
397 12952 if(result != GLOBUS_SUCCESS)
398 {
399 0 goto error_exit;
400 }
401
402 12952 result = globus_soap_message_serialize_header_end(
403 request->client_handle->message);
404 12952 if(result != GLOBUS_SUCCESS)
405 {
406 0 goto error_exit;
407 }
408
409 12952 result = globus_soap_message_serialize_body(
410 request->client_handle->message);
411 12952 if(result != GLOBUS_SUCCESS)
412 {
413 0 goto error_exit;
414 }
415
416 12952 result = globus_soap_message_serialize_body_begin_close(
417 request->client_handle->message);
418 12952 if(result != GLOBUS_SUCCESS)
419 {
420 0 goto error_exit;
421 }
422
423 12952 subelement.Namespace = operation->input_element.Namespace;
424 12952 subelement.local = operation->input_element.local;
425
426 12952 result = operation->input_type_info->serialize(
427 &subelement,
428 request->input,
429 request->client_handle->message,
430 0);
431 12952 if(result != GLOBUS_SUCCESS)
432 {
433 0 goto error_exit;
434 }
435
436 12952 result = globus_soap_message_serialize_body_end(
437 request->client_handle->message);
438 12952 if(result != GLOBUS_SUCCESS)
439 {
440 0 goto error_exit;
441 }
442
443 12952 result = globus_soap_message_serialize_envelope_end(
444 request->client_handle->message);
445 12952 if(result != GLOBUS_SUCCESS)
446 {
447 0 goto error_exit;
448 }
449
450 12952 result = globus_soap_message_set_write_position_to_marker(
451 request->client_handle->message,
452 GLOBUS_SOAP_MESSAGE_MARKER_HEADER_CONTENT);
453 12952 if(result != GLOBUS_SUCCESS)
454 {
455 0 goto error_exit;
456 }
457
458 12952 result = globus_soap_message_get_handler_chain(
459 request->client_handle->message, &chain);
460 12952 if(result != GLOBUS_SUCCESS)
461 {
462 0 goto error_exit;
463 }
464
465 12952 if(chain)
466 {
467 12952 result = globus_handler_chain_invoke(
468 chain,
469 GLOBUS_HANDLER_TYPE_REQUEST,
470 request->client_handle->message);
471
472 12952 if (result != GLOBUS_SUCCESS)
473 {
474 0 goto error_exit;
475 }
476 }
477 12952 break;
478
479 case GLOBUS_SOAP_CLIENT_REQUEST_INVOKING_HANDLERS:
480
481 12952 if(request->result != GLOBUS_SUCCESS)
482 {
483 0 result = request->result;
484 0 goto error_exit;
485 }
486
487 12952 request->state = GLOBUS_SOAP_CLIENT_REQUEST_SENDING;
488
489 12952 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 12952 if(result != GLOBUS_SUCCESS)
496 {
497 0 goto error_exit;
498 }
499 12952 callback_registered = GLOBUS_TRUE;
500
501 12952 break;
502
503 case GLOBUS_SOAP_CLIENT_REQUEST_SENDING:
504 12952 if(request->result != GLOBUS_SUCCESS)
505 {
506 0 result = request->result;
507 0 goto error_exit;
508 }
509
510 12952 request->state = GLOBUS_SOAP_CLIENT_REQUEST_DESTROY_HANDLERS;
511
512 12952 result = globus_soap_message_get_handler_chain(
513 request->client_handle->message, &chain);
514 12952 if(result != GLOBUS_SUCCESS)
515 {
516 0 goto error_exit;
517 }
518
519 12952 if(chain)
520 {
521 12952 result = globus_handler_chain_invoke(
522 chain,
523 GLOBUS_HANDLER_TYPE_REQUEST_DESTROY,
524 request->client_handle->message);
525
526 12952 if (result != GLOBUS_SUCCESS)
527 {
528 0 goto error_exit;
529 }
530 }
531 12952 break;
532
533 case GLOBUS_SOAP_CLIENT_REQUEST_DESTROY_HANDLERS:
534 12952 if(request->result != GLOBUS_SUCCESS)
535 {
536 0 result = request->result;
537 0 goto error_exit;
538 }
539
540 12952 globus_mutex_unlock(&request->client_handle->mutex);
541
542 12952 request->callback(
543 request->client_handle,
544 request->args, GLOBUS_SUCCESS);
545
546 12952 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 64838 while (! callback_registered);
652
653 25943 globus_mutex_unlock(&request->client_handle->mutex);
654
655 25943 return;
656
657 39 error_exit:
658 39 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 39 result = GlobusSoapMessageErrorClientRequestFailed(
684 result, operation->request_action);
685
686 39 message_handle = request->client_handle->message;
687 39 request->client_handle->message = NULL;
688 39 globus_mutex_unlock(&request->client_handle->mutex);
689
690 39 request->callback(request->client_handle, request->args, result);
691
692 39 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 12991 {
702 12991 globus_result_t result = GLOBUS_SUCCESS;
703 const globus_soap_client_operation_t *
704 operation;
705
706 12991 operation = request->client_handle->operation;
707
708 12991 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 12991 if(result != GLOBUS_SUCCESS)
715 {
716 0 result = GlobusSoapMessageErrorClientRequestFailed(
717 result, operation->request_action);
718 0 goto error_exit;
719 }
720
721 12991 if (operation->request_action != NULL)
722 {
723 12991 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 12991 if(result != GLOBUS_SUCCESS)
730 {
731 0 result = GlobusSoapMessageErrorClientRequestFailed(
732 result, operation->request_action);
733 0 goto error_exit;
734 }
735
736 12991 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 12991 if(result != GLOBUS_SUCCESS)
744 {
745 0 result = GlobusSoapMessageErrorClientRequestFailed(
746 result, operation->request_action);
747 0 goto error_exit;
748 }
749 }
750
751 12991 result = globus_soap_message_handle_set_attrs(
752 request->client_handle->message, request->client_handle->attrs);
753 12991 if(result != GLOBUS_SUCCESS)
754 {
755 0 result = GlobusSoapMessageErrorClientRequestFailed(
756 result, operation->request_action);
757 }
758
759 goto exit;
760
761 12991 error_exit:
762 12991 exit:
763
764 12991 return result;
765 }