1 martin 1.5 //%LICENSE////////////////////////////////////////////////////////////////
|
2 martin 1.6 //
|
3 martin 1.5 // Licensed to The Open Group (TOG) under one or more contributor license
4 // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with
5 // this work for additional information regarding copyright ownership.
6 // Each contributor licenses this file to you under the OpenPegasus Open
7 // Source License; you may not use this file except in compliance with the
8 // License.
|
9 martin 1.6 //
|
10 martin 1.5 // Permission is hereby granted, free of charge, to any person obtaining a
11 // copy of this software and associated documentation files (the "Software"),
12 // to deal in the Software without restriction, including without limitation
13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 // and/or sell copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following conditions:
|
16 martin 1.6 //
|
17 martin 1.5 // The above copyright notice and this permission notice shall be included
18 // in all copies or substantial portions of the Software.
|
19 martin 1.6 //
|
20 martin 1.5 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
21 martin 1.6 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
22 martin 1.5 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
27 martin 1.6 //
|
28 martin 1.5 //////////////////////////////////////////////////////////////////////////
|
29 kumpf 1.2 //
30 //%////////////////////////////////////////////////////////////////////////////
31
32 #include <cctype>
33 #include <cstdio>
34 #include <Pegasus/Common/Config.h>
35 #include <Pegasus/Common/Tracer.h>
36 #include <Pegasus/Common/MessageLoader.h>
|
37 kumpf 1.3 #include <Pegasus/Common/StringConversion.h>
|
38 kumpf 1.2 #include <Pegasus/Common/AutoPtr.h>
39 #include "WsmConstants.h"
|
40 kumpf 1.8 #include "SoapResponse.h"
|
41 kumpf 1.2 #include "WsmProcessor.h"
42
|
43 kumpf 1.3 PEGASUS_USING_STD;
44
|
45 kumpf 1.2 PEGASUS_NAMESPACE_BEGIN
46
|
47 kumpf 1.3 Uint64 WsmProcessor::_currentEnumContext = 0;
48
|
49 kumpf 1.2 WsmProcessor::WsmProcessor(
|
50 sahana.prabhakar 1.11 MessageQueue* cimOperationProcessorQueue,
|
51 kumpf 1.2 CIMRepository* repository)
|
52 sahana.prabhakar 1.11 : MessageQueue(PEGASUS_QUEUENAME_WSMPROCESSOR),
|
53 kumpf 1.2 _wsmResponseEncoder(),
54 _wsmRequestDecoder(this),
55 _cimOperationProcessorQueue(cimOperationProcessorQueue),
56 _repository(repository),
57 _wsmToCimRequestMapper(repository)
58 {
59 }
60
61 WsmProcessor::~WsmProcessor()
62 {
|
63 kumpf 1.4 // Clean up enumeration responses that have not been pulled or released.
64 for (EnumerationContextTable::Iterator i =
65 _enumerationContextTable.start(); i; i++)
66 {
67 delete i.value().response;
68 }
|
69 kumpf 1.2 }
70
71 void WsmProcessor::handleEnqueue(Message* message)
72 {
73 if (!message)
74 {
75 return;
76 }
77
78 PEGASUS_ASSERT(dynamic_cast<CIMResponseMessage*>(message) != 0);
79 handleResponse(dynamic_cast<CIMResponseMessage*>(message));
80 }
81
82 void WsmProcessor::handleEnqueue()
83 {
84 Message* message = dequeue();
85 handleEnqueue(message);
86 }
87
88 void WsmProcessor::handleRequest(WsmRequest* wsmRequest)
89 {
90 kumpf 1.2 PEG_METHOD_ENTER(TRC_WSMSERVER, "WsmProcessor::handleRequest()");
91
92 // Process requests by type. For now, only WS-Transfer operations are
93 // implemented, and they all are handled by forwarding to the CIM Server.
94
95 AutoPtr<WsmRequest> wsmRequestDestroyer(wsmRequest);
96
97 try
98 {
99 CIMOperationRequestMessage* cimRequest =
100 _wsmToCimRequestMapper.mapToCimRequest(wsmRequest);
101
|
102 kumpf 1.3 // Requests that do not have a CIM representation are mapped to NULL
103 // and are meant to be handled by the WSM processor itself.
104 if (cimRequest)
105 {
106 // Save the request until the response comes back.
107 // Note that the CIM request has its own unique message ID.
108 _requestTable.insert(cimRequest->messageId, wsmRequest);
109
110 cimRequest->queueIds.push(getQueueId());
111 _cimOperationProcessorQueue->enqueue(cimRequest);
|
112 kumpf 1.4
113 wsmRequestDestroyer.release();
|
114 kumpf 1.3 }
115 else
116 {
117 switch (wsmRequest->getType())
118 {
119 case WS_ENUMERATION_PULL:
120 _handlePullRequest((WsenPullRequest*) wsmRequest);
121 break;
122
123 case WS_ENUMERATION_RELEASE:
124 _handleReleaseRequest((WsenReleaseRequest*) wsmRequest);
125 break;
126
127 default:
128 break;
129 }
130 }
|
131 kumpf 1.2 }
132 catch (WsmFault& fault)
133 {
134 sendResponse(new WsmFaultResponse(wsmRequest, fault));
135 }
136 catch (CIMException& e)
137 {
138 sendResponse(new WsmFaultResponse(
139 wsmRequest,
140 _cimToWsmResponseMapper.mapCimExceptionToWsmFault(e)));
141 }
142 catch (Exception& e)
143 {
144 sendResponse(new WsmFaultResponse(
145 wsmRequest,
146 WsmFault(
147 WsmFault::wsman_InternalError,
148 e.getMessage(),
149 e.getContentLanguages())));
150 }
151 catch (PEGASUS_STD(exception)& e)
152 kumpf 1.2 {
153 sendResponse(new WsmFaultResponse(
154 wsmRequest,
155 WsmFault(WsmFault::wsman_InternalError, e.what())));
156 }
157 catch (...)
158 {
159 sendResponse(new WsmFaultResponse(
160 wsmRequest,
161 WsmFault(WsmFault::wsman_InternalError)));
162 }
163
164 // Note this requirement when Enumerate/Pull operations are supported:
165 // DSP0226 R6.3-5: For operations that span multiple message sequences,
166 // the wsman:Locale element is processed in the initial message only.
167 // It should be ignored in subsequent messages because the first
168 // message establishes the required locale. The service may issue a
169 // fault if the wsman:Locale is present in subsequent messages and the
170 // value is different from that used in the initiating request.
171
172 PEG_METHOD_EXIT();
173 kumpf 1.2 }
174
175 void WsmProcessor::handleResponse(CIMResponseMessage* cimResponse)
176 {
177 PEG_METHOD_ENTER(TRC_WSMSERVER, "WsmProcessor::handleResponse()");
178
179 AutoPtr<CIMResponseMessage> cimResponseDestroyer(cimResponse);
180
181 // Lookup the request this response corresponds to
182 WsmRequest* wsmRequest;
183 Boolean gotRequest =
184 _requestTable.lookup(cimResponse->messageId, wsmRequest);
185 PEGASUS_ASSERT(gotRequest);
186 AutoPtr<WsmRequest> wsmRequestDestroyer(wsmRequest);
|
187 kumpf 1.3 _requestTable.remove(cimResponse->messageId);
|
188 kumpf 1.2
189 try
190 {
|
191 kumpf 1.3 switch (wsmRequest->getType())
192 {
193 case WS_ENUMERATION_ENUMERATE:
194 _handleEnumerateResponse(
195 cimResponse,
196 (WsenEnumerateRequest*) wsmRequest);
197 break;
198
199 default:
200 _handleDefaultResponse(cimResponse, wsmRequest);
201 break;
202 }
|
203 kumpf 1.2 }
204 catch (WsmFault& fault)
205 {
206 sendResponse(new WsmFaultResponse(wsmRequest, fault));
207 }
208 catch (CIMException& e)
209 {
210 sendResponse(new WsmFaultResponse(
211 wsmRequest,
212 _cimToWsmResponseMapper.mapCimExceptionToWsmFault(e)));
213 }
214 catch (Exception& e)
215 {
216 sendResponse(new WsmFaultResponse(
217 wsmRequest,
218 WsmFault(
219 WsmFault::wsman_InternalError,
220 e.getMessage(),
221 e.getContentLanguages())));
222 }
223 catch (PEGASUS_STD(exception)& e)
224 kumpf 1.2 {
225 sendResponse(new WsmFaultResponse(
226 wsmRequest,
227 WsmFault(WsmFault::wsman_InternalError, e.what())));
228 }
229 catch (...)
230 {
231 sendResponse(new WsmFaultResponse(
232 wsmRequest,
233 WsmFault(WsmFault::wsman_InternalError)));
234 }
235
236 PEG_METHOD_EXIT();
237 }
238
239 void WsmProcessor::sendResponse(WsmResponse* wsmResponse)
240 {
241 PEG_METHOD_ENTER(TRC_WSMSERVER, "WsmProcessor::sendResponse()");
242
243 _wsmResponseEncoder.enqueue(wsmResponse);
244 delete wsmResponse;
245 kumpf 1.2
246 PEG_METHOD_EXIT();
247 }
248
249 Uint32 WsmProcessor::getWsmRequestDecoderQueueId()
250 {
251 return _wsmRequestDecoder.getQueueId();
252 }
253
|
254 kumpf 1.3 void WsmProcessor::_handleEnumerateResponse(
255 CIMResponseMessage* cimResponse,
256 WsenEnumerateRequest* wsmRequest)
257 {
258 if (cimResponse->cimException.getCode() != CIM_ERR_SUCCESS)
259 {
260 _handleDefaultResponse(cimResponse, wsmRequest);
|
261 kumpf 1.8 return;
|
262 kumpf 1.3 }
|
263 kumpf 1.8
264 AutoPtr<SoapResponse> soapResponse;
265
|
266 kumpf 1.3 {
267 AutoMutex lock(_enumerationContextTableLock);
268
269 AutoPtr<WsenEnumerateResponse> wsmResponse(
270 (WsenEnumerateResponse*) _cimToWsmResponseMapper.
271 mapToWsmResponse(wsmRequest, cimResponse));
272
273 // Get the enumeration expiration time
274 CIMDateTime expiration;
275 _getExpirationDatetime(wsmRequest->expiration, expiration);
276
277 // Create a new context
278 Uint64 contextId = _currentEnumContext++;
279 _enumerationContextTable.insert(
280 contextId,
281 EnumerationContext(
282 contextId,
|
283 kumpf 1.10 wsmRequest->userName,
|
284 kumpf 1.3 wsmRequest->enumerationMode,
|
285 kumpf 1.7 expiration,
|
286 kumpf 1.3 wsmRequest->epr,
287 wsmResponse.get()));
288 wsmResponse->setEnumerationContext(contextId);
289
290 // Get the requsted chunk of results
291 AutoPtr<WsenEnumerateResponse> splitResponse(
|
292 kumpf 1.7 _splitEnumerateResponse(wsmRequest, wsmResponse.get(),
|
293 kumpf 1.3 wsmRequest->optimized ? wsmRequest->maxElements : 0));
294 splitResponse->setEnumerationContext(contextId);
295
|
296 kumpf 1.8 // If no items are left in the original response, mark split
|
297 kumpf 1.3 // response as complete
298 if (wsmResponse->getSize() == 0)
299 {
300 splitResponse->setComplete();
301 }
302
|
303 kumpf 1.8 Uint32 numDataItemsEncoded = 0;
304 soapResponse.reset(_wsmResponseEncoder.encodeWsenEnumerateResponse(
305 splitResponse.get(), numDataItemsEncoded));
306
307 if (splitResponse->getSize() > numDataItemsEncoded)
|
308 kumpf 1.3 {
309 // Add unprocessed items back to the context
|
310 kumpf 1.9 splitResponse->remove(0, numDataItemsEncoded);
|
311 kumpf 1.3 wsmResponse->merge(splitResponse.get());
312 }
313
314 // Remove the context if there are no instances left
315 if (wsmResponse->getSize() == 0)
316 {
317 _enumerationContextTable.remove(contextId);
318 }
319 else
320 {
321 // If the context is not removed, the pointer to the response is
322 // now owned by the context
323 wsmResponse.release();
324 }
325 }
|
326 kumpf 1.8
327 _wsmResponseEncoder.sendResponse(soapResponse.get());
|
328 kumpf 1.3 }
329
330 void WsmProcessor::_handlePullRequest(WsenPullRequest* wsmRequest)
331 {
|
332 kumpf 1.8 AutoPtr<SoapResponse> soapResponse;
|
333 kumpf 1.3
334 {
|
335 kumpf 1.8 AutoMutex lock(_enumerationContextTableLock);
336 EnumerationContext* enumContext;
337
338 if (_enumerationContextTable.lookupReference(
339 wsmRequest->enumerationContext, enumContext))
|
340 kumpf 1.3 {
|
341 kumpf 1.8 // EPRs of the request and the enumeration context must match
342 if (wsmRequest->epr != enumContext->epr)
343 {
344 throw WsmFault(
345 WsmFault::wsa_MessageInformationHeaderRequired,
346 MessageLoaderParms(
347 "WsmServer.WsmProcessor.INVALID_PULL_EPR",
348 "EPR of a Pull request does not match that of "
349 "the enumeration context."));
350 }
351
|
352 kumpf 1.10 // User credentials of the request and the enumeration context must
353 // match.
354 if (wsmRequest->userName != enumContext->userName)
355 {
356 // DSP0226 R8.1-6: The wsen:Pull and wsen:Release operations
357 // are a continuation of the original wsen:Enumerate operation.
358 // The service should enforce the same authentication and
359 // authorization throughout the entire sequence of operations
360 // and should fault any attempt to change credentials during
361 // the sequence.
362
363 throw WsmFault(WsmFault::wsman_AccessDenied);
364 }
365
|
366 kumpf 1.8 AutoPtr<WsenPullResponse> wsmResponse(_splitPullResponse(
367 wsmRequest, enumContext->response, wsmRequest->maxElements));
368 wsmResponse->setEnumerationContext(enumContext->contextId);
369 if (enumContext->response->getSize() == 0)
370 {
371 wsmResponse->setComplete();
372 }
373
374 Uint32 numDataItemsEncoded = 0;
375 soapResponse.reset(_wsmResponseEncoder.encodeWsenPullResponse(
376 wsmResponse.get(), numDataItemsEncoded));
|
377 kumpf 1.3
|
378 kumpf 1.8 if (wsmResponse->getSize() > numDataItemsEncoded)
379 {
380 // Add unprocessed items back to the context
|
381 kumpf 1.9 wsmResponse->remove(0, numDataItemsEncoded);
|
382 kumpf 1.8 enumContext->response->merge(wsmResponse.get());
383 }
|
384 kumpf 1.3
|
385 kumpf 1.8 // Remove the context if there are no instances left
386 if (enumContext->response->getSize() == 0)
387 {
388 delete enumContext->response;
389 _enumerationContextTable.remove(wsmRequest->enumerationContext);
390 }
|
391 kumpf 1.3 }
|
392 kumpf 1.8 else
|
393 kumpf 1.3 {
|
394 kumpf 1.8 throw WsmFault(
395 WsmFault::wsen_InvalidEnumerationContext,
396 MessageLoaderParms(
397 "WsmServer.WsmProcessor.INVALID_ENUMERATION_CONTEXT",
398 "Enumeration context \"$0\" is not valid.",
399 wsmRequest->enumerationContext));
|
400 kumpf 1.3 }
401 }
|
402 kumpf 1.8
403 _wsmResponseEncoder.sendResponse(soapResponse.get());
|
404 kumpf 1.3 }
405
406 void WsmProcessor::_handleReleaseRequest(WsenReleaseRequest* wsmRequest)
407 {
|
408 kumpf 1.8 AutoPtr<WsenReleaseResponse> wsmResponse;
409
|
410 kumpf 1.3 {
|
411 kumpf 1.8 AutoMutex lock(_enumerationContextTableLock);
412
413 EnumerationContext enumContext;
414 if (_enumerationContextTable.lookup(
415 wsmRequest->enumerationContext, enumContext))
416 {
417 // EPRs of the request and the enumeration context must match
418 if (wsmRequest->epr != enumContext.epr)
419 {
420 throw WsmFault(
421 WsmFault::wsa_MessageInformationHeaderRequired,
422 MessageLoaderParms(
423 "WsmServer.WsmProcessor.INVALID_RELEASE_EPR",
424 "EPR of a Release request does not match that of "
425 "the enumeration context."));
426 }
427
|
428 kumpf 1.10 // User credentials of the request and the enumeration context must
429 // match.
430 if (wsmRequest->userName != enumContext.userName)
431 {
432 // DSP0226 R8.1-6: The wsen:Pull and wsen:Release operations
433 // are a continuation of the original wsen:Enumerate operation.
434 // The service should enforce the same authentication and
435 // authorization throughout the entire sequence of operations
436 // and should fault any attempt to change credentials during
437 // the sequence.
438
439 throw WsmFault(WsmFault::wsman_AccessDenied);
440 }
441
|
442 kumpf 1.8 wsmResponse.reset(new WsenReleaseResponse(
443 wsmRequest, enumContext.response->getContentLanguages()));
444
445 delete enumContext.response;
446 _enumerationContextTable.remove(wsmRequest->enumerationContext);
447 }
448 else
|
449 kumpf 1.3 {
450 throw WsmFault(
|
451 kumpf 1.8 WsmFault::wsen_InvalidEnumerationContext,
|
452 kumpf 1.3 MessageLoaderParms(
|
453 kumpf 1.8 "WsmServer.WsmProcessor.INVALID_ENUMERATION_CONTEXT",
454 "Enumeration context \"$0\" is not valid.",
455 wsmRequest->enumerationContext));
|
456 kumpf 1.3 }
|
457 kumpf 1.8 }
|
458 kumpf 1.3
|
459 kumpf 1.8 _wsmResponseEncoder.enqueue(wsmResponse.get());
|
460 kumpf 1.3 }
461
462 void WsmProcessor::_handleDefaultResponse(
463 CIMResponseMessage* cimResponse, WsmRequest* wsmRequest)
464 {
465 AutoPtr<WsmResponse> wsmResponse(
466 _cimToWsmResponseMapper.mapToWsmResponse(wsmRequest, cimResponse));
467
468 cimResponse->updateThreadLanguages();
469 cimResponse->queueIds.pop();
470
471 _wsmResponseEncoder.enqueue(wsmResponse.get());
472 }
473
474 WsenEnumerateResponse* WsmProcessor::_splitEnumerateResponse(
475 WsenEnumerateRequest* request, WsenEnumerateResponse* response, Uint32 num)
476 {
477 WsenEnumerationData splitData;
478 response->getEnumerationData().split(splitData, num);
479
480 return new WsenEnumerateResponse(splitData, response->getItemCount(),
481 kumpf 1.3 request, response->getContentLanguages());
482 }
483
484 WsenPullResponse* WsmProcessor::_splitPullResponse(
485 WsenPullRequest* request, WsenEnumerateResponse* response, Uint32 num)
486 {
487 WsenEnumerationData splitData;
488 response->getEnumerationData().split(splitData, num);
489
|
490 kumpf 1.7 return new WsenPullResponse(splitData, request,
|
491 kumpf 1.3 response->getContentLanguages());
492 }
493
494 void WsmProcessor::_getExpirationDatetime(
495 const String& wsmDT, CIMDateTime& cimDT)
496 {
497 CIMDateTime dt, currentDT;
498
|
499 kumpf 1.7 // Default expiration interval = 10 mins
|
500 kumpf 1.3 // ATTN WSMAN: what should the value be?
501 CIMDateTime maxInterval(0, 0, 10, 0, 0, 6);
502
503 // If expiration is not set, use the dafault.
504 if (wsmDT == String::EMPTY)
505 {
506 dt = maxInterval;
507 }
508 else
509 {
510 try
511 {
512 WsmToCimRequestMapper::convertWsmToCimDatetime(wsmDT, dt);
513 }
514 catch (...)
515 {
516 throw WsmFault(
517 WsmFault::wsen_InvalidExpirationTime,
518 MessageLoaderParms(
519 "WsmServer.WsmToCimRequestMapper.INVALID_EXPIRATION_TIME",
520 "The expiration time \"$0\" is not valid", wsmDT));
521 kumpf 1.3 }
522 }
523
524 currentDT = CIMDateTime::getCurrentDateTime();
525 if (dt.isInterval())
526 {
527 if (dt > maxInterval)
528 {
529 dt = maxInterval;
530 }
531 cimDT = currentDT + dt;
532 }
533 else
534 {
535 if ((dt <= currentDT))
536 {
537 throw WsmFault(
538 WsmFault::wsen_InvalidExpirationTime,
539 MessageLoaderParms(
540 "WsmServer.WsmToCimRequestMapper.INVALID_EXPIRATION_TIME",
541 "The expiration time \"$0\" is not valid", wsmDT));
542 kumpf 1.3 }
543
544 if (dt - currentDT > maxInterval)
545 {
546 cimDT = currentDT + maxInterval;
547 }
548 else
549 {
550 cimDT = dt;
551 }
552 }
553 }
554
555 void WsmProcessor::cleanupExpiredContexts()
556 {
557 CIMDateTime currentDT = CIMDateTime::getCurrentDateTime();
|
558 kumpf 1.4 Array<Uint64> expiredContextIds;
559 Array<WsenEnumerateResponse*> expiredResponses;
|
560 kumpf 1.3
561 AutoMutex lock(_enumerationContextTableLock);
562 for (EnumerationContextTable::Iterator i =
563 _enumerationContextTable.start (); i; i++)
564 {
565 EnumerationContext context = i.value();
566 if (context.expiration < currentDT)
567 {
|
568 kumpf 1.4 expiredContextIds.append(context.contextId);
569 expiredResponses.append(context.response);
|
570 kumpf 1.3 }
571 }
572
|
573 kumpf 1.4 for (Uint32 i = 0; i < expiredContextIds.size(); i++)
|
574 kumpf 1.3 {
|
575 kumpf 1.4 delete expiredResponses[i];
576 _enumerationContextTable.remove(expiredContextIds[i]);
|
577 kumpf 1.3 }
578 }
579
|
580 kumpf 1.2 PEGASUS_NAMESPACE_END
|