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_soap_message.h"
18 #include "globus_wsrf_resource.h"
19 #include "globus_service_engine.h"
20 #include "globus_operation_provider.h"
21 #include "globus_service_registry.h"
22 #include "globus_wsrf_core_tools.h"
23
24 #include "xsd_dateTime.h"
25
26 #include "wsrl_SetTerminationTimeType.h"
27 #include "wsrl_SetTerminationTimeResponseType.h"
28
29 #include "version.h"
30
31 /*
32  * This define causes the wsrl_i_faults.h to define faults relevant to this
33  * port type.
34  */
35 #define WSRL_SCHEDULED_RESOURCE_TERMINATION 1
36 /* We don't implement any sort of change policy, so we don't use this fault
37  * type.
38  */
39 #define NEED_TERMINATION_TIME_CHANGE_REJECTED_FAULT 0
40
41 #include "wsrl_i_faults.h"
42
43 /**
44  * @page wsrl_ScheduledResourceTermination_provider ScheduledResourceTermination Provider
45  *
46  * <h2>Provider Usage Overview</h2>
47  * This operation provider implements the ScheduledResourceTermination portType
48  * defined in
49  * http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceLifetime-1.2-draft-01.wsdl .
50  * This portType consists of the @a SetTerminationTime operation, @a
51  * TerminationTime and @a CurrentTime resource properties,  and
52  * related faults.
53  *
54  * The WSRF service engine will automatically register this provider to handle
55  * the SetTerminationTime operation for services which use the port type.
56  *
57  * <h2>Notes</h2>
58  * - The CurrentTime and TerminationTime resource properties are stored in GMT.
59  *
60  * <h2>Limitations</h2>
61  * - This provider does not implement any policies regarding what is an
62  * acceptable change of the TerminationTime. The
63  * TerminationTimeChangeRejectedFaultType is never issued by this provider.
64  */
65
66 /* Prototypes */
67 static
68 globus_result_t
69 wsrl_ScheduledResourceTermination_init_resource(
70     const struct wsa_EndpointReferenceType_s * epr);
71
72 static
73 globus_result_t
74 wsrl_SetTerminationTime_provider(
75     globus_service_engine_t             engine,
76     globus_soap_message_handle_t        handle,
77     globus_service_descriptor_t *       service,
78     wsrl_SetTerminationTimeType *       SetTerminationTime,
79     wsrl_SetTerminationTimeResponseType *
80                                         SetTerminationTimeResponse,
81     char **                             fault_name,
82     void **                             fault);
83
84 static
85 globus_bool_t
86 wsrl_deny_callback(
87     void *                              arg,
88     const xsd_QName *                   qname,
89     void *                              property);
90
91 static
92 void
93 wsrl_CurrentTime_callback(
94     void *                              arg,
95     const xsd_QName *                   qname,
96     void **                             property);
97
98 static
99 time_t
100 wsrl_l_timegm(
101     const struct tm *                   tm);
102
103 static
104 int
105 wsrl_ScheduledResourceTermination_activate(void);
106
107 static
108 int
109 wsrl_ScheduledResourceTermination_deactivate(void);
110
111 /* Local Variables */
112 static xsd_QName wsrl_SetTerminationTime_qname =
113 {
114     "http://www.globus.org/docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceLifetime-1.2-draft-01.wsdl",
115     "SetTerminationTime"
116 };
117
118 static xsd_QName wsrl_CurrentTime_qname =
119 {
120     "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceLifetime-1.2-draft-01.xsd",
121     "CurrentTime"
122 };
123
124 static xsd_QName wsrl_TerminationTime_qname =
125 {
126     "http://docs.oasis-open.org/wsrf/2004/06/wsrf-WS-ResourceLifetime-1.2-draft-01.xsd",
127     "TerminationTime"
128 };
129
130 static
131 globus_operation_provider_descriptor_t
132 wsrl_SetTerminationTime_descriptor =
133 {
134     &wsrl_SetTerminationTime_qname,
135     "SetTerminationTime",
136     (void *)wsrl_SetTerminationTime_provider,
137     wsrl_ScheduledResourceTermination_init_resource
138 };
139
140 GlobusExtensionDefineModule(globus_wsrl_ScheduledResourceTermination_provider) =
141 {
142     "globus_wsrl_ScheduledResourceTermination_provider",
143     wsrl_ScheduledResourceTermination_activate,
144     wsrl_ScheduledResourceTermination_deactivate,
145     NULL,
146     NULL,
147     &local_version
148 };
149
150 /* Implementation */
151 static
152 globus_result_t
153 wsrl_ScheduledResourceTermination_init_resource(
154     const struct wsa_EndpointReferenceType_s * epr)
155 93 {
156 93     globus_resource_t                   resource;
157 93     globus_result_t                     result;
158 93     globus_abstime_t                    destroy_time;
159 93     xsd_dateTime *                      destroy_time_value = NULL;
160 93     time_t                              destroy_time_t;
161 93     struct tm *                         tm_res;
162
163 93     result = globus_wsrf_core_get_resource_from_epr(epr, &resource);
164
165 93     if (result != GLOBUS_SUCCESS)
166     {
167 0         goto out;
168     }
169
170     /* Check if the destroy time was set before this provider was initialized.
171      * If so, we'll initialize our resource property to match that time.
172      */
173 93     result = globus_resource_get_destroy_time(
174             resource,
175             &destroy_time);
176
177 93     if (result != GLOBUS_SUCCESS)
178     {
179 0         goto finish_out;
180     }
181
182 93     if (destroy_time.tv_sec != 0 || destroy_time.tv_nsec != 0)
183     {
184 2         result = xsd_dateTime_init(&destroy_time_value);
185
186 2         if (result != GLOBUS_SUCCESS)
187         {
188 0             goto finish_out;
189         }
190
191 2         destroy_time_t = (time_t) destroy_time.tv_sec;
192
193 2         tm_res = globus_libc_gmtime_r(
194                 &destroy_time_t,
195                 destroy_time_value);
196
197 2         if (tm_res == NULL)
198         {
199 0             result = globus_error_put(GLOBUS_ERROR_NO_INFO);
200
201 0             goto finish_out;
202         }
203     }
204
205 93     result = globus_resource_create_property(
206         resource,
207         &wsrl_TerminationTime_qname,
208         &xsd_dateTime_info,
209         destroy_time_value);
210
211 93     if (result != GLOBUS_SUCCESS)
212     {
213 0         goto finish_out;
214     }
215
216     /* Current time property is created as a callback property so that
217      * each attempt to read the property will get the current time.
218      */
219 93     result = globus_resource_create_property_callback(
220         resource,
221         &wsrl_CurrentTime_qname,
222         &xsd_dateTime_info,
223         wsrl_CurrentTime_callback,
224         wsrl_deny_callback,
225         NULL);
226
227 finish_out:
228 93     globus_resource_finish(resource);
229 out:
230 93     return result;
231 }
232 /* wsrl_ScheduledResourceTermination_init_resource() */
233
234
235 static
236 globus_result_t
237 wsrl_SetTerminationTime_provider(
238     globus_service_engine_t             engine,
239     globus_soap_message_handle_t        handle,
240     globus_service_descriptor_t *       service,
241     wsrl_SetTerminationTimeType *       SetTerminationTime,
242     wsrl_SetTerminationTimeResponseType *
243                                         SetTerminationTimeResponse,
244     char **                             fault_name,
245     void **                             fault)
246 18 {
247 18     globus_result_t                     result = GLOBUS_SUCCESS;
248 18     globus_resource_t                   resource;
249 18     globus_abstime_t                    termination_time;
250 18     time_t                              now;
251 18     xsd_dateTime *                      termination_time_rp = NULL;
252
253 18     result = globus_wsrf_core_get_resource(handle, service, &resource);
254
255 18     if (result != GLOBUS_SUCCESS || resource == NULL)
256     {
257 0         result = wsrl_l_ResourceUnknownFaultType_create(
258                 fault_name,
259                 (wsrl_ResourceUnknownFaultType **) fault);
260
261 0         goto out;
262     }
263
264 18     if (SetTerminationTime->RequestedTerminationTime == NULL)
265     {
266 0         goto out;
267     }
268
269 18     termination_time.tv_sec = wsrl_l_timegm(
270             SetTerminationTime->RequestedTerminationTime);
271
272 18     termination_time.tv_nsec = 0;
273
274 18     result = globus_resource_set_destroy_time(resource, &termination_time);
275
276 18     if (result != GLOBUS_SUCCESS)
277     {
278 0         result = wsrl_l_UnableToSetTerminationTimeFaultType_create(
279                 fault_name,
280                 (wsrl_UnableToSetTerminationTimeFaultType **) fault);
281
282
283 0         goto finish_out;
284     }
285
286 18     now = time(NULL);
287
288 18     xsd_dateTime_copy(&SetTerminationTimeResponse->NewTerminationTime,
289                       SetTerminationTime->RequestedTerminationTime);
290
291 18     globus_libc_gmtime_r(&now, &SetTerminationTimeResponse->CurrentTime);
292
293 18     xsd_dateTime_copy(&termination_time_rp,
294            SetTerminationTime->RequestedTerminationTime);
295
296 18     result = globus_resource_set_property(
297             resource,
298             &wsrl_TerminationTime_qname,
299             termination_time_rp);
300
301 18     if (result != GLOBUS_SUCCESS)
302     {
303 0         goto finish_out;
304     }
305
306 18     result = globus_resource_finish(resource);
307
308 18     if (result != GLOBUS_SUCCESS)
309     {
310 0         goto out;
311     }
312 18     return GLOBUS_SUCCESS;
313
314 finish_out:
315 0     globus_resource_finish(resource);
316 out:
317 0     return result;
318 }
319 /* wsrl_SetTerminationTime_provider() */
320
321
322 static
323 globus_bool_t
324 wsrl_deny_callback(
325     void *                              arg,
326     const xsd_QName *                   qname,
327     void *                              property)
328 0 {
329 0     return GLOBUS_FALSE;
330 }
331 /* wsrl_deny_callback() */
332
333 static
334 void
335 wsrl_CurrentTime_callback(
336     void *                              arg,
337     const xsd_QName *                   qname,
338     void **                             property)
339 2 {
340 2     time_t                              now_time;
341 2     xsd_dateTime *                      now;
342
343 2     globus_assert(
344             strcmp(qname->Namespace,
345                     wsrl_CurrentTime_qname.Namespace) == 0);
346 2     globus_assert(
347             strcmp(qname->local,
348                     wsrl_CurrentTime_qname.local) == 0);
349
350 2     now_time = time(NULL);
351
352 2     xsd_dateTime_init((xsd_dateTime **) property);
353 2     now = *property;
354
355 2     globus_libc_gmtime_r(&now_time, now);
356
357     return;
358 }
359 /* wsrl_CurrentTime_callback() */
360
361 /**
362  * Convert a struct tm to a time_t without accounting for the local timezone
363  * or modifying the struct tm contents.
364  *
365  * This may get a little kooky when the TZ shift occurs near the DST change.
366  */
367 static
368 time_t
369 wsrl_l_timegm(
370     const struct tm *                   tm)
371 18 {
372 18     struct tm                           tmp;
373 18     struct tm                           local_tm;
374 18     time_t                              local_time;
375 18     time_t                              shifted_time;
376
377 18     memcpy(&tmp, tm, sizeof(struct tm));
378
379     /* convert the tm to time_t in the local timezone */
380 18     local_time = mktime(&tmp);
381
382     /* create a new tm with this time (but without the TZ-related parts of the
383      * tm set) */
384 18     globus_libc_gmtime_r(&local_time, &local_tm);
385
386     /* convert the time to local time again, causing it to be shifted by
387      * time zone twice
388      */
389 18     shifted_time = mktime(&local_tm);
390
391     /*
392      * The difference between shifted_time and local_time is the TZ correction.
393      */
394 18     return local_time + (local_time - shifted_time);
395 }
396 /* wsrl_l_timegm() */
397
398 static
399 int
400 wsrl_ScheduledResourceTermination_activate(void)
401 93 {
402 93     int                                 res = 0;
403 93     GlobusFuncName(wsrl_ScheduledResourceTermination_activate);
404     
405 93     res = globus_extension_registry_add(
406         GLOBUS_OPERATION_PROVIDER_REGISTRY,
407         &wsrl_SetTerminationTime_qname,
408         GlobusExtensionMyModule(globus_wsrl_ScheduledResourceTermination_provider),
409         &wsrl_SetTerminationTime_descriptor);
410
411 93     return res;
412 }
413 /* wsrl_ScheduledResourceTermination_activate() */
414
415 static
416 int
417 wsrl_ScheduledResourceTermination_deactivate(void)
418 21 {
419 21     GlobusFuncName(wsrl_ScheduledResourceTermination_deactivate);
420
421 21     globus_extension_registry_remove(
422         GLOBUS_OPERATION_PROVIDER_REGISTRY,
423         &wsrl_SetTerminationTime_qname);
424
425 21     return 0;
426 }