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_soap_message_utils.h"
20 #include "globus_service_engine.h"
21
22 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
23 static
24 void
25 globus_l_soap_client_response_callback(
26 void * args);
27 #endif /* GLOBUS_DONT_DOCUMENT_INTERNAL */
28
29 /**
30 * Nonblocking SOAP response handling.
31 * @ingroup globus_soap_client_response
32 * @internal
33 *
34 * Processes the result of an operation previously invoked by calling
35 * globus_soap_client_register_request(). Once the reply has been completely
36 * processed, the @a callback function will be invoked. The application
37 * may then use the client handle to process a new operation, or destroy it.
38 *
39 * @param client_handle
40 * The SOAP client handle to use for state while processing the
41 * response.
42 * @param callback
43 * Callback function to invoke once the operation response has been handled.
44 * @param user_args
45 * Application-specific argument to the callback function.
46 *
47 * @retval GLOBUS_SUCCESS
48 * Processing of this response has begun successfully.
49 * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_INIT_FAILED
50 * Processing the operation failed because the client could not initialize
51 * some part of its data.
52 * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_CLIENT_REQUEST_FAILED
53 * Processing the operation failed because the client could not initialize
54 * some part of its data.
55 */
56
57 globus_result_t
58 globus_soap_client_register_response(
59 globus_soap_client_handle_t client_handle,
60 globus_soap_client_response_callback_func_t
61 callback,
62 void * user_args)
63 12892 {
64 12892 globus_result_t result = GLOBUS_SUCCESS;
65 globus_i_soap_client_response_handle_t *
66 response;
67 globus_service_engine_t engine;
68
69 12892 response = &client_handle->response;
70
71 12892 response->callback = callback;
72 12892 response->args = user_args;
73
74 12892 engine = globus_soap_message_attr_get(
75 client_handle->attrs,
76 GLOBUS_SOAP_CLIENT_LOCAL_INVOCATION_KEY);
77
78 12892 if (engine == NULL)
79 {
80 12892 response->output = NULL;
81 12892 response->state = GLOBUS_SOAP_CLIENT_RESPONSE_INIT;
82 }
83 else
84 {
85 0 response->state = GLOBUS_SOAP_CLIENT_RESPONSE_DONE;
86 }
87
88 12892 if (client_handle->operation->response_action != NULL)
89 {
90 12892 result = globus_soap_message_handle_set_attr(
91 client_handle->message,
92 WSADDR_ACTION_RESPONSE_KEY,
93 NULL,
94 NULL,
95 (void *) client_handle->operation->response_action);
96
97 12892 if(result != GLOBUS_SUCCESS)
98 {
99 0 if(!GlobusSoapMessageStatusCheck(result))
100 {
101 0 result = GlobusSoapMessageErrorClientRequestFailed(
102 result, client_handle->operation->response_action);
103 0 goto exit;
104 }
105 }
106 }
107
108 12892 result = globus_callback_register_oneshot(
109 &response->callback_handle,
110 NULL,
111 globus_l_soap_client_response_callback,
112 response);
113
114 12892 if(result != GLOBUS_SUCCESS)
115 {
116 0 result = GlobusSoapMessageErrorClientResponseFailed(
117 result, client_handle->operation->response_action);
118 0 goto exit;
119 }
120
121 12892 return result;
122
123 0 exit:
124 0 return result;
125 }
126 /* globus_soap_client_register_response() */
127
128 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
129 static
130 void
131 globus_l_soap_client_response_done_callback(
132 globus_result_t result,
133 void * args)
134 25780 {
135 globus_i_soap_client_response_handle_t * response;
136
137 25780 response = args;
138 25780 globus_assert_string(response, "response handle in callback is NULL");
139
140 25780 globus_mutex_lock(&response->client_handle->mutex);
141 25780 response->result = result;
142 25780 globus_mutex_unlock(&response->client_handle->mutex);
143
144 25780 globus_l_soap_client_response_callback(response);
145 25780 }
146 /* globus_l_soap_client_response_done_callback() */
147
148 extern
149 void
150 globus_i_soap_client_response_handle_destroy(
151 globus_i_soap_client_response_handle_t *
152 response)
153 12991 {
154 12991 globus_assert_string(response, "response handle in callback is NULL");
155
156 12991 if (response->output != NULL &&
157 response->client_handle->operation->output_type_info != NULL)
158 {
159 0 response->client_handle->operation->output_type_info->destroy(
160 response->output);
161
162 0 response->output = NULL;
163 }
164
165 12991 if(response->fault)
166 {
167 0 xsd_any_destroy(response->fault);
168 0 response->fault_type = 0;
169 0 response->fault = NULL;
170 }
171 12991 }
172 /* globus_i_soap_client_response_handle_destroy() */
173
174 static
175 void
176 globus_l_soap_client_response_callback(
177 void * args)
178 38672 {
179 38672 globus_soap_message_handle_t message_handle = NULL;
180 globus_soap_message_fault_t soap_fault;
181 38672 globus_result_t result = GLOBUS_SUCCESS;
182 38672 globus_handler_chain_t chain = NULL;
183 38672 xsd_QName * header_element = NULL;
184 int must;
185 globus_i_soap_client_response_handle_t *
186 response;
187 const globus_soap_client_operation_t *
188 operation;
189 globus_soap_client_response_callback_func_t
190 callback;
191 void * callback_arg;
192 38672 globus_bool_t callback_registered = GLOBUS_FALSE;
193
194 38672 response = args;
195 38672 globus_assert_string(response, "response handle in callback is NULL");
196
197 38672 operation = response->client_handle->operation;
198
199 38672 globus_mutex_lock(&response->client_handle->mutex);
200 do
201 {
202 167292 GlobusSoapMessageDebugPrintf(GLOBUS_SOAP_MESSAGE_DEBUG_DEBUG,
203 ("globus_l_soap_client_response_callback: state = %d, result = %p\n",
204 response->state,
205 (void *) response->result));
206 167292 switch(response->state)
207 {
208 case GLOBUS_SOAP_CLIENT_RESPONSE_INIT:
209
210 12892 response->state = GLOBUS_SOAP_CLIENT_RESPONSE_READING;
211
212 12892 result = globus_soap_message_register_read_response(
213 response->client_handle->message,
214 globus_l_soap_client_response_done_callback,
215 response);
216 12892 if(result != GLOBUS_SUCCESS)
217 {
218 0 goto error_exit;
219 }
220 12892 callback_registered = GLOBUS_TRUE;
221
222 12892 break;
223
224 case GLOBUS_SOAP_CLIENT_RESPONSE_READING:
225 12892 if(response->result != GLOBUS_SUCCESS)
226 {
227 1 if(GlobusSoapMessageErrorCheckFailedResponse(response->result)
228 || GlobusSoapMessageErrorCheckBadRequest(response->result))
229 {
230 0 response->result = GLOBUS_SUCCESS;
231 }
232 else
233 {
234 1 result = response->result;
235 1 goto error_exit;
236 }
237 }
238
239 12891 response->state = GLOBUS_SOAP_CLIENT_RESPONSE_TRIGGER_HANDLERS;
240
241 12891 result = globus_soap_message_deserialize_envelope(
242 response->client_handle->message);
243 12891 if(result != GLOBUS_SUCCESS)
244 {
245 0 goto error_exit;
246 }
247
248 12891 result = globus_soap_message_deserialize_element_begin_close(
249 response->client_handle->message);
250 12891 if(result != GLOBUS_SUCCESS)
251 {
252 0 goto error_exit;
253 }
254
255 12891 result = globus_soap_message_deserialize_header(
256 response->client_handle->message);
257 12893 if(result &&
258 GlobusSoapMessageStatusElementNotFoundCheck(result))
259 {
260 2 globus_soap_message_deserialize_push_element(
261 response->client_handle->message);
262 2 result = GLOBUS_SUCCESS;
263
264 2 response->state = GLOBUS_SOAP_CLIENT_RESPONSE_HEADER_FAILED;
265
266 2 result = globus_soap_message_deserialize_body(
267 response->client_handle->message);
268 2 if(result != GLOBUS_SUCCESS)
269 {
270 0 if(response->result != GLOBUS_SUCCESS)
271 {
272 0 result = response->result;
273 }
274 0 goto error_exit;
275 }
276 }
277 12889 else if (result)
278 {
279 0 goto error_exit;
280 }
281
282 12891 break;
283
284 case GLOBUS_SOAP_CLIENT_RESPONSE_TRIGGER_HANDLERS:
285 77323 if(response->result != GLOBUS_SUCCESS)
286 {
287 0 if(GlobusSoapMessageErrorCheckFailedResponse(
288 response->result) ||
289 GlobusSoapMessageErrorCheckBadRequest(response->result))
290 {
291 0 response->result = GLOBUS_SUCCESS;
292 }
293 else
294 {
295 0 result = response->result;
296 0 goto error_exit;
297 }
298 }
299
300 77323 response->state = GLOBUS_SOAP_CLIENT_RESPONSE_TRIGGER_HANDLERS;
301
302 77323 xsd_QName_init(&header_element);
303
304 77323 result = globus_soap_message_deserialize_element_unknown(
305 response->client_handle->message,
306 header_element);
307
308 77323 if(result && !GlobusSoapMessageStatusFailedElementCheck(result))
309 {
310 0 xsd_QName_destroy(header_element);
311 0 goto error_exit;
312 }
313 77323 else if (result)
314 {
315 12886 response->state =
316 GLOBUS_SOAP_CLIENT_RESPONSE_HANDLER_DESERIALIZE;
317
318 12886 xsd_QName_destroy(header_element);
319
320 12886 break;
321 }
322
323 64437 result = globus_soap_message_deserialize_int_attribute(
324 response->client_handle->message,
325 &soap_mustUnderstand_qname,
326 &must);
327 64437 if(result == GLOBUS_SUCCESS && (must == 1))
328 {
329 0 globus_soap_message_add_required_header_element(
330 response->client_handle->message,
331 header_element);
332 }
333 64437 else if(result != GLOBUS_SUCCESS &&
334 !GlobusSoapMessageStatusAttributeNotFoundCheck(result))
335 {
336 0 xsd_QName_destroy(header_element);
337 0 goto error_exit;
338 }
339
340 64437 globus_soap_message_deserialize_push_element(
341 response->client_handle->message);
342
343 64437 result = globus_soap_message_get_handler_chain(
344 response->client_handle->message, &chain);
345 64437 if(result != GLOBUS_SUCCESS)
346 {
347 0 goto error_exit;
348 }
349
350 64437 if(chain)
351 {
352 64437 result = globus_handler_chain_trigger(
353 chain,
354 response->client_handle->message,
355 header_element);
356 }
357
358 64437 xsd_QName_destroy(header_element);
359 64437 if(result != GLOBUS_SUCCESS)
360 {
361 3 goto error_exit;
362 }
363
364 64434 break;
365
366 case GLOBUS_SOAP_CLIENT_RESPONSE_HANDLER_DESERIALIZE:
367 12886 if(response->result != GLOBUS_SUCCESS)
368 {
369 0 result = response->result;
370 0 goto error_exit;
371 }
372
373 12886 response->state = GLOBUS_SOAP_CLIENT_RESPONSE_HEADER_FAILED;
374
375 12886 result = globus_soap_message_deserialize_header_end(
376 response->client_handle->message);
377 12886 if(result != GLOBUS_SUCCESS)
378 {
379 0 goto error_exit;
380 }
381
382 12886 result = globus_soap_message_deserialize_body(
383 response->client_handle->message);
384 12886 if(result != GLOBUS_SUCCESS)
385 {
386 0 goto error_exit;
387 }
388 12886 break;
389
390 case GLOBUS_SOAP_CLIENT_RESPONSE_HEADER_FAILED:
391 12888 if(response->result != GLOBUS_SUCCESS)
392 {
393 0 result = response->result;
394 0 goto error_exit;
395 }
396
397 12888 response->state = GLOBUS_SOAP_CLIENT_RESPONSE_INVOKING_HANDLERS;
398
399 12888 response->fault_type = 0;
400 12888 response->fault_result = GLOBUS_SUCCESS;
401
402 12888 if (operation->fault_callback != NULL)
403 {
404 12888 result = globus_soap_message_deserialize_fault(
405 response->client_handle->message,
406 &soap_fault,
407 operation->fault_callback,
408 &response->fault,
409 &response->fault_type);
410 12888 if(result != GLOBUS_SUCCESS)
411 {
412 0 if(response->result != GLOBUS_SUCCESS)
413 {
414 0 result = response->result;
415 }
416 0 goto error_exit;
417 }
418 }
419
420 25523 if(!soap_fault && response->fault_type == 0)
421 {
422 12635 if (operation->output_type_info != NULL)
423 {
424 12635 result = operation->output_type_info->deserialize(
425 &operation->output_element,
426 &response->output,
427 response->client_handle->message,
428 0);
429 12635 if(result != GLOBUS_SUCCESS)
430 {
431 0 goto error_exit;
432 }
433 }
434 }
435 else
436 {
437 253 if(soap_fault)
438 {
439 253 response->fault_result = GlobusSoapMessageErrorFault(
440 soap_fault);
441 }
442
443 253 result = globus_soap_message_deserialize_fault_end(
444 response->client_handle->message,
445 response->fault
446 ? response->fault->element
447 : &soap_fault_qname);
448 253 if(result != GLOBUS_SUCCESS)
449 {
450 0 goto error_exit;
451 }
452 }
453
454 12888 result = globus_soap_message_deserialize_body_end(
455 response->client_handle->message);
456 12888 if(result != GLOBUS_SUCCESS)
457 {
458 0 goto error_exit;
459 }
460
461 12888 result = globus_soap_message_deserialize_envelope_end(
462 response->client_handle->message);
463 12888 if(result != GLOBUS_SUCCESS)
464 {
465 0 goto error_exit;
466 }
467
468 25523 if(!soap_fault && response->fault_type == 0)
469 {
470 12635 result = globus_soap_message_get_handler_chain(
471 response->client_handle->message, &chain);
472 12635 if(result != GLOBUS_SUCCESS)
473 {
474 0 goto error_exit;
475 }
476
477 12635 if(chain)
478 {
479 12635 result = globus_handler_chain_invoke(
480 chain,
481 GLOBUS_HANDLER_TYPE_RESPONSE,
482 response->client_handle->message);
483
484 12635 if (result != GLOBUS_SUCCESS)
485 {
486 0 goto error_exit;
487 }
488 }
489 }
490 else
491 {
492 253 response->state = GLOBUS_SOAP_CLIENT_RESPONSE_CLOSE;
493 }
494
495 12888 break;
496
497 case GLOBUS_SOAP_CLIENT_RESPONSE_INVOKING_HANDLERS:
498 12635 if(response->result != GLOBUS_SUCCESS)
499 {
500 0 result = response->result;
501 0 goto error_exit;
502 }
503
504 12635 result = globus_soap_message_check_required_headers(
505 response->client_handle->message);
506 12635 if(result != GLOBUS_SUCCESS)
507 {
508 /* continue on in case fault was returned and
509 * no header elements exist
510 */
511 0 response->result = result;
512 }
513 12635 response->state = GLOBUS_SOAP_CLIENT_RESPONSE_CLOSE;
514
515 12635 break;
516
517 case GLOBUS_SOAP_CLIENT_RESPONSE_CLOSE:
518 12888 if(response->result != GLOBUS_SUCCESS)
519 {
520 0 result = response->result;
521 0 goto error_exit;
522 }
523
524 12888 response->state = GLOBUS_SOAP_CLIENT_RESPONSE_DONE;
525
526 12888 result = globus_soap_message_register_close(
527 response->client_handle->message,
528 globus_l_soap_client_response_done_callback,
529 response);
530 12888 if(result != GLOBUS_SUCCESS)
531 {
532 0 goto error_exit;
533 }
534 12888 callback_registered = GLOBUS_TRUE;
535 12888 break;
536
537 case GLOBUS_SOAP_CLIENT_RESPONSE_DONE:
538 12888 if(response->result != GLOBUS_SUCCESS)
539 {
540 0 result = response->result;
541 0 goto error_exit;
542 }
543
544 12888 message_handle = response->client_handle->message;
545 12888 response->client_handle->message = NULL;
546 12888 callback = response->callback;
547 12888 callback_arg = response->args;
548 12888 response->callback = NULL;
549 12888 response->args = NULL;
550 12888 globus_mutex_unlock(&response->client_handle->mutex);
551
552 12888 callback(
553 response->client_handle,
554 callback_arg,
555 response->fault_result,
556 response->output,
557 response->fault_type,
558 response->fault);
559
560 12888 globus_soap_message_handle_destroy(message_handle);
561
562 12888 return;
563
564 default:
565 0 globus_assert_string(NULL, "Unknown response state");
566 }
567 }
568 154400 while (! callback_registered);
569
570 25780 globus_mutex_unlock(&response->client_handle->mutex);
571
572 25780 return;
573
574 4 error_exit:
575
576 4 if(!GlobusSoapMessageStatusCheck(result))
577 {
578 4 result = GlobusSoapMessageErrorClientResponseFailed(
579 result, operation->response_action);
580 }
581
582 4 callback = response->callback;
583 4 callback_arg = response->args;
584 4 response->callback = NULL;
585 4 response->args = NULL;
586 4 message_handle = response->client_handle->message;
587 4 response->client_handle->message = NULL;
588 4 globus_mutex_unlock(&response->client_handle->mutex);
589
590 4 callback(
591 response->client_handle,
592 callback_arg,
593 result,
594 response->output,
595 response->fault_type,
596 response->fault);
597
598 4 globus_soap_message_handle_destroy(message_handle);
599 }
600 /* globus_l_soap_client_response_callback() */
601