1 kumpf 1.1 //%2006////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
6 // IBM Corp.; EMC Corporation, The Open Group.
7 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
9 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
11 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
15 // of this software and associated documentation files (the "Software"), to
16 // deal in the Software without restriction, including without limitation the
17 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
18 // sell copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
20 //
21 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
22 kumpf 1.1 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
23 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
24 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 //==============================================================================
31 //
32 //%/////////////////////////////////////////////////////////////////////////////
33
34 #include <Pegasus/Common/Signal.h>
35 #include <Pegasus/Common/Config.h>
36 #include <Pegasus/Common/Constants.h>
37 #include <Pegasus/Common/AutoPtr.h>
38 #include <Pegasus/Common/ArrayInternal.h>
39 #include <Pegasus/Common/CIMMessage.h>
40 #include <Pegasus/Common/CIMMessageSerializer.h>
41 #include <Pegasus/Common/CIMMessageDeserializer.h>
42 #include <Pegasus/Common/OperationContextInternal.h>
43 kumpf 1.1 #include <Pegasus/Common/System.h>
44 #include <Pegasus/Common/AnonymousPipe.h>
45 #include <Pegasus/Common/Tracer.h>
46 #include <Pegasus/Common/Logger.h>
47 #include <Pegasus/Common/Thread.h>
48 #include <Pegasus/Common/MessageQueueService.h>
49 #include <Pegasus/Config/ConfigManager.h>
|
50 kumpf 1.10 #include <Pegasus/Common/Executor.h>
|
51 kumpf 1.1
52 #if defined (PEGASUS_OS_TYPE_WINDOWS)
53 # include <windows.h> // For CreateProcess()
54 #elif defined (PEGASUS_OS_VMS)
55 # include <perror.h>
56 # include <climsgdef.h>
57 # include <stdio.h>
58 # include <stdlib.h>
59 # include <string.h>
60 # include <processes.h>
61 # include <unixio.h>
62 #else
63 # include <unistd.h> // For fork(), exec(), and _exit()
64 # include <errno.h>
65 # include <sys/types.h>
|
66 kumpf 1.5 # include <sys/resource.h>
|
67 kumpf 1.1 # if defined(PEGASUS_HAS_SIGNALS)
68 # include <sys/wait.h>
69 # endif
70 #endif
71
72 #include "OOPProviderManagerRouter.h"
73
74 PEGASUS_USING_STD;
75
76 PEGASUS_NAMESPACE_BEGIN
77
78 /////////////////////////////////////////////////////////////////////////////
79 // OutstandingRequestTable and OutstandingRequestEntry
80 /////////////////////////////////////////////////////////////////////////////
81
82 /**
83 An OutstandingRequestEntry represents a request message sent to a
84 Provider Agent for which no response has been received. The request
85 sender provides the message ID and a location for the response to be
86 returned, and then waits on the semaphore. When a response matching
87 the message ID is received, it is placed into the specified location
88 kumpf 1.1 and the semaphore is signaled.
89 */
90 class OutstandingRequestEntry
91 {
92 public:
93 OutstandingRequestEntry(
94 String originalMessageId_,
95 CIMRequestMessage* requestMessage_,
96 CIMResponseMessage*& responseMessage_,
97 Semaphore* responseReady_)
98 : originalMessageId(originalMessageId_),
99 requestMessage(requestMessage_),
100 responseMessage(responseMessage_),
101 responseReady(responseReady_)
102 {
103 }
104
105 /**
106 A unique value is substituted as the request messageId attribute to
107 allow responses to be definitively correllated with requests.
108 The original messageId value is stored here to avoid a race condition
109 kumpf 1.1 between the processing of a response chunk and the resetting of the
110 original messageId in the request message.
111 */
112 String originalMessageId;
113 CIMRequestMessage* requestMessage;
114 CIMResponseMessage*& responseMessage;
115 Semaphore* responseReady;
116 };
117
118 typedef HashTable<String, OutstandingRequestEntry*, EqualFunc<String>,
119 HashFunc<String> > OutstandingRequestTable;
120
121
122 /////////////////////////////////////////////////////////////////////////////
123 // ProviderAgentContainer
124 /////////////////////////////////////////////////////////////////////////////
125
126 class ProviderAgentContainer
127 {
128 public:
129 ProviderAgentContainer(
130 kumpf 1.1 const String & moduleName,
131 const String & userName,
132 Uint16 userContext,
133 PEGASUS_INDICATION_CALLBACK_T indicationCallback,
134 PEGASUS_RESPONSE_CHUNK_CALLBACK_T responseChunkCallback,
135 PEGASUS_PROVIDERMODULEFAIL_CALLBACK_T providerModuleFailCallback,
136 Boolean subscriptionInitComplete);
137
138 ~ProviderAgentContainer();
139
140 Boolean isInitialized();
141
142 String getModuleName() const;
143
144 CIMResponseMessage* processMessage(CIMRequestMessage* request);
145 void unloadIdleProviders();
146
147 private:
148 //
149 // Private methods
150 //
151 kumpf 1.1
152 /** Unimplemented */
153 ProviderAgentContainer();
154 /** Unimplemented */
155 ProviderAgentContainer(const ProviderAgentContainer& pa);
156 /** Unimplemented */
157 ProviderAgentContainer& operator=(const ProviderAgentContainer& pa);
158
159 /**
160 Start a Provider Agent process and establish a pipe connection with it.
161 Note: The caller must lock the _agentMutex.
162 */
163 void _startAgentProcess();
164
165 /**
166 Send initialization data to the Provider Agent.
167 Note: The caller must lock the _agentMutex.
168 */
169 void _sendInitializationData();
170
171 /**
172 kumpf 1.1 Initialize the ProviderAgentContainer if it is not already
173 initialized. Initialization includes starting the Provider Agent
174 process, establishing a pipe connection with it, and starting a
175 thread to read response messages from the Provider Agent.
176
177 Note: The caller must lock the _agentMutex.
178 */
179 void _initialize();
180
181 /**
182 Uninitialize the ProviderAgentContainer if it is initialized.
183 The connection is closed and outstanding requests are completed
184 with an error result.
185
186 @param cleanShutdown Indicates whether the provider agent process
187 exited cleanly. A value of true indicates that responses have been
188 sent for all requests that have been processed. A value of false
189 indicates that one or more requests may have been partially processed.
190 */
191 void _uninitialize(Boolean cleanShutdown);
192
193 kumpf 1.1 /**
194 Performs the processMessage work, but does not retry on a transient
195 error.
196 */
197 CIMResponseMessage* _processMessage(CIMRequestMessage* request);
198
199 /**
200 Read and process response messages from the Provider Agent until
201 the connection is closed.
202 */
203 void _processResponses();
204 static ThreadReturnType PEGASUS_THREAD_CDECL
205 _responseProcessor(void* arg);
206
207 //
208 // Private data
209 //
210
211 /**
212 The _agentMutex must be locked whenever writing to the Provider
213 Agent connection, accessing the _isInitialized flag, or changing
214 kumpf 1.1 the Provider Agent state.
215 */
216 Mutex _agentMutex;
217
218 /**
219 Name of the provider module served by this Provider Agent.
220 */
221 String _moduleName;
222
223 /**
224 The user context in which this Provider Agent operates.
225 */
226 String _userName;
227
228 /**
229 User Context setting of the provider module served by this Provider
230 Agent.
231 */
232 Uint16 _userContext;
233
234 /**
235 kumpf 1.1 Callback function to which all generated indications are sent for
236 processing.
237 */
238 PEGASUS_INDICATION_CALLBACK_T _indicationCallback;
239
240 /**
241 Callback function to which response chunks are sent for processing.
242 */
243 PEGASUS_RESPONSE_CHUNK_CALLBACK_T _responseChunkCallback;
244
245 /**
246 Callback function to be called upon detection of failure of a
247 provider module.
248 */
249 PEGASUS_PROVIDERMODULEFAIL_CALLBACK_T _providerModuleFailCallback;
250
251 /**
252 Indicates whether the Provider Agent is active.
253 */
254 Boolean _isInitialized;
255
256 kumpf 1.1 /**
257 Pipe connection used to read responses from the Provider Agent.
258 */
259 AutoPtr<AnonymousPipe> _pipeFromAgent;
260 /**
261 Pipe connection used to write requests to the Provider Agent.
262 */
263 AutoPtr<AnonymousPipe> _pipeToAgent;
264
265 #if defined(PEGASUS_HAS_SIGNALS)
266 /**
267 Process ID of the active Provider Agent.
268 */
269 pid_t _pid;
270 #endif
271
272 /**
273 The _outstandingRequestTable holds an entry for each request that has
274 been sent to this Provider Agent for which no response has been
275 received. Entries are added (by the writing thread) when a request
276 is sent, and are removed (by the reading thread) when the response is
277 kumpf 1.1 received (or when it is determined that no response is forthcoming).
278 */
279 OutstandingRequestTable _outstandingRequestTable;
280 /**
281 The _outstandingRequestTableMutex must be locked whenever reading or
282 updating the _outstandingRequestTable.
283 */
284 Mutex _outstandingRequestTableMutex;
285
286 /**
287 Holds the last provider module instance sent to the Provider Agent in
288 a ProviderIdContainer. Since the provider module instance rarely
289 changes, an optimization is used to send it only when it differs from
290 the last provider module instance sent.
291 */
292 CIMInstance _providerModuleCache;
293
294 /**
295 The number of Provider Agent processes that are currently initialized
296 (active).
297 */
298 kumpf 1.1 static Uint32 _numProviderProcesses;
299
300 /**
301 The _numProviderProcessesMutex must be locked whenever reading or
302 updating the _numProviderProcesses count.
303 */
304 static Mutex _numProviderProcessesMutex;
305
306 /**
307 The maximum number of Provider Agent processes that may be initialized
308 (active) at one time.
309 */
310 static Uint32 _maxProviderProcesses;
311
312 /**
313 A value indicating that a request message has not been processed.
314 A CIMResponseMessage pointer with this value indicates that the
315 corresponding CIMRequestMessage has not been processed. This is
316 used to indicate that a provider agent exited without starting to
317 process the request, and that the request should be retried.
318 */
319 kumpf 1.1 static CIMResponseMessage* _REQUEST_NOT_PROCESSED;
320
321 /**
322 Indicates whether the Indication Service has completed initialization.
323
324 For more information, please see the description of the
325 ProviderManagerRouter::_subscriptionInitComplete member variable.
326 */
327 Boolean _subscriptionInitComplete;
328 };
329
330 Uint32 ProviderAgentContainer::_numProviderProcesses = 0;
331 Mutex ProviderAgentContainer::_numProviderProcessesMutex;
332 Uint32 ProviderAgentContainer::_maxProviderProcesses = PEG_NOT_FOUND;
333
334 // Set this to a value that no valid CIMResponseMessage* will have.
335 CIMResponseMessage* ProviderAgentContainer::_REQUEST_NOT_PROCESSED =
|
336 mike 1.16 static_cast<CIMResponseMessage*>((void*)&_REQUEST_NOT_PROCESSED);
|
337 kumpf 1.1
338 ProviderAgentContainer::ProviderAgentContainer(
339 const String & moduleName,
340 const String & userName,
341 Uint16 userContext,
342 PEGASUS_INDICATION_CALLBACK_T indicationCallback,
343 PEGASUS_RESPONSE_CHUNK_CALLBACK_T responseChunkCallback,
344 PEGASUS_PROVIDERMODULEFAIL_CALLBACK_T providerModuleFailCallback,
345 Boolean subscriptionInitComplete)
|
346 kumpf 1.10 :
347 _moduleName(moduleName),
|
348 kumpf 1.1 _userName(userName),
349 _userContext(userContext),
350 _indicationCallback(indicationCallback),
351 _responseChunkCallback(responseChunkCallback),
352 _providerModuleFailCallback(providerModuleFailCallback),
353 _isInitialized(false),
354 _subscriptionInitComplete(subscriptionInitComplete)
355 {
|
356 kumpf 1.10
|
357 kumpf 1.1 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
358 "ProviderAgentContainer::ProviderAgentContainer");
359 PEG_METHOD_EXIT();
360 }
361
362 ProviderAgentContainer::~ProviderAgentContainer()
363 {
364 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
365 "ProviderAgentContainer::~ProviderAgentContainer");
366
367 // Ensure the destructor does not throw an exception
368 try
369 {
370 if (isInitialized())
371 {
372 // Stop the responseProcessor thread by closing its connection
373 _pipeFromAgent->closeReadHandle();
374
375 // Wait for the responseProcessor thread to exit
376 while (isInitialized())
377 {
378 kumpf 1.1 Threads::yield();
379 }
380 }
381 }
382 catch (...)
383 {
384 }
385
386 PEG_METHOD_EXIT();
387 }
388
389 void ProviderAgentContainer::_startAgentProcess()
390 {
|
391 kumpf 1.10 PEG_METHOD_ENTER(
392 TRC_PROVIDERMANAGER, "ProviderAgentContainer::_startAgentProcess");
|
393 kumpf 1.1
|
394 kumpf 1.10 // Start the provider agent.
395
396 int pid;
397 AnonymousPipe* readPipe;
398 AnonymousPipe* writePipe;
399
400 int status = Executor::startProviderAgent(
401 (const char*)_moduleName.getCString(),
402 ConfigManager::getPegasusHome(),
403 _userName,
404 pid,
405 readPipe,
406 writePipe);
407
408 if (status != 0)
|
409 kumpf 1.1 {
|
410 marek 1.9 PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL2,
|
411 kumpf 1.10 "Executor::startProviderAgent() failed"));
|
412 kumpf 1.1 PEG_METHOD_EXIT();
413 throw Exception(MessageLoaderParms(
414 "ProviderManager.OOPProviderManagerRouter.CIMPROVAGT_START_FAILED",
415 "Failed to start cimprovagt \"$0\".",
416 _moduleName));
417 }
|
418 kumpf 1.5
|
419 kumpf 1.1 # if defined(PEGASUS_HAS_SIGNALS)
420 _pid = pid;
421 # endif
422
|
423 kumpf 1.10 _pipeFromAgent.reset(readPipe);
424 _pipeToAgent.reset(writePipe);
|
425 kumpf 1.1
426 PEG_METHOD_EXIT();
427 }
428
429 // Note: Caller must lock _agentMutex
430 void ProviderAgentContainer::_sendInitializationData()
431 {
432 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
433 "ProviderAgentContainer::_sendInitializationData");
434
435 //
436 // Gather config properties to pass to the Provider Agent
437 //
438 ConfigManager* configManager = ConfigManager::getInstance();
439 Array<Pair<String, String> > configProperties;
440
441 Array<String> configPropertyNames;
442 configManager->getAllPropertyNames(configPropertyNames, true);
443 for (Uint32 i = 0; i < configPropertyNames.size(); i++)
444 {
445 String configPropertyValue =
446 kumpf 1.1 configManager->getCurrentValue(configPropertyNames[i]);
447 String configPropertyDefaultValue =
448 configManager->getDefaultValue(configPropertyNames[i]);
449 if (configPropertyValue != configPropertyDefaultValue)
450 {
451 configProperties.append(Pair<String, String>(
452 configPropertyNames[i], configPropertyValue));
453 }
454 }
455
456 //
457 // Create a Provider Agent initialization message
458 //
459 AutoPtr<CIMInitializeProviderAgentRequestMessage> request(
460 new CIMInitializeProviderAgentRequestMessage(
461 String("0"), // messageId
462 configManager->getPegasusHome(),
463 configProperties,
464 System::bindVerbose,
465 _subscriptionInitComplete,
466 QueueIdStack()));
467 kumpf 1.1
468 //
469 // Write the initialization message to the pipe
470 //
471 AnonymousPipe::Status writeStatus =
472 _pipeToAgent->writeMessage(request.get());
473
474 if (writeStatus != AnonymousPipe::STATUS_SUCCESS)
475 {
476 PEG_METHOD_EXIT();
477 throw Exception(MessageLoaderParms(
478 "ProviderManager.OOPProviderManagerRouter."
479 "CIMPROVAGT_COMMUNICATION_FAILED",
480 "Failed to communicate with cimprovagt \"$0\".",
481 _moduleName));
482 }
483
484 // Wait for a null response from the Provider Agent indicating it has
485 // initialized successfully.
486
487 CIMMessage* message;
488 kumpf 1.1 AnonymousPipe::Status readStatus;
489 do
490 {
491 readStatus = _pipeFromAgent->readMessage(message);
|
492 kumpf 1.10
|
493 kumpf 1.1 } while (readStatus == AnonymousPipe::STATUS_INTERRUPT);
494
495 if (readStatus != AnonymousPipe::STATUS_SUCCESS)
496 {
497 PEG_METHOD_EXIT();
498 throw Exception(MessageLoaderParms(
499 "ProviderManager.OOPProviderManagerRouter."
500 "CIMPROVAGT_COMMUNICATION_FAILED",
501 "Failed to communicate with cimprovagt \"$0\".",
502 _moduleName));
503 }
504
505 PEGASUS_ASSERT(message == 0);
506
507 PEG_METHOD_EXIT();
508 }
509
510 // Note: Caller must lock _agentMutex
511 void ProviderAgentContainer::_initialize()
512 {
513 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
514 kumpf 1.1 "ProviderAgentContainer::_initialize");
515
516 if (_isInitialized)
517 {
518 PEGASUS_ASSERT(0);
519 PEG_METHOD_EXIT();
520 return;
521 }
522
523 if (_maxProviderProcesses == PEG_NOT_FOUND)
524 {
525 String maxProviderProcesses = ConfigManager::getInstance()->
526 getCurrentValue("maxProviderProcesses");
527 CString maxProviderProcessesString = maxProviderProcesses.getCString();
528 char* end = 0;
529 _maxProviderProcesses = strtol(maxProviderProcessesString, &end, 10);
530 }
531
532 {
533 AutoMutex lock(_numProviderProcessesMutex);
534 if ((_maxProviderProcesses != 0) &&
535 kumpf 1.1 (_numProviderProcesses >= _maxProviderProcesses))
536 {
537 throw PEGASUS_CIM_EXCEPTION(
538 CIM_ERR_FAILED,
539 MessageLoaderParms(
540 "ProviderManager.OOPProviderManagerRouter."
541 "MAX_PROVIDER_PROCESSES_REACHED",
542 "The maximum number of cimprovagt processes has been "
543 "reached."));
544 }
545 else
546 {
547 _numProviderProcesses++;
548 }
549 }
550
551 try
552 {
553 _startAgentProcess();
554 _isInitialized = true;
555 _sendInitializationData();
556 kumpf 1.1
557 // Start a thread to read and process responses from the Provider Agent
558 ThreadStatus rtn = PEGASUS_THREAD_OK;
559 while ((rtn = MessageQueueService::get_thread_pool()->
560 allocate_and_awaken(this, _responseProcessor)) !=
561 PEGASUS_THREAD_OK)
562 {
563 if (rtn == PEGASUS_THREAD_INSUFFICIENT_RESOURCES)
564 {
565 Threads::yield();
566 }
567 else
568 {
569 Logger::put(
570 Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
571 "Not enough threads to process responses from the "
572 "provider agent.");
|
573 kumpf 1.6
|
574 marek 1.9 PEG_TRACE_CSTRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
|
575 kumpf 1.1 "Could not allocate thread to process responses from the "
576 "provider agent.");
577
578 throw Exception(MessageLoaderParms(
579 "ProviderManager.OOPProviderManagerRouter."
580 "CIMPROVAGT_THREAD_ALLOCATION_FAILED",
581 "Failed to allocate thread for cimprovagt \"$0\".",
582 _moduleName));
583 }
584 }
585 }
586 catch (...)
587 {
588 // Closing the connection causes the agent process to exit
589 _pipeToAgent.reset();
590 _pipeFromAgent.reset();
591
592 #if defined(PEGASUS_HAS_SIGNALS)
593 if (_isInitialized)
594 {
595 // Harvest the status of the agent process to prevent a zombie
|
596 kumpf 1.10 int status = Executor::reapProviderAgent(_pid);
|
597 kumpf 1.4
598 if (status == -1)
599 {
|
600 marek 1.9 PEG_TRACE((TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
601 kumpf 1.4 "ProviderAgentContainer::_initialize(): "
|
602 kumpf 1.10 "Executor::reapProviderAgent() failed"));
|
603 kumpf 1.4 }
|
604 kumpf 1.1 }
605 #endif
606
607 _isInitialized = false;
608
609 {
610 AutoMutex lock(_numProviderProcessesMutex);
611 _numProviderProcesses--;
612 }
613
614 PEG_METHOD_EXIT();
615 throw;
616 }
617
618 PEG_METHOD_EXIT();
619 }
620
621 Boolean ProviderAgentContainer::isInitialized()
622 {
623 AutoMutex lock(_agentMutex);
624 return _isInitialized;
625 kumpf 1.1 }
626
627 void ProviderAgentContainer::_uninitialize(Boolean cleanShutdown)
628 {
629 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
630 "ProviderAgentContainer::_uninitialize");
631
|
632 kumpf 1.7 #if defined(PEGASUS_HAS_SIGNALS)
|
633 kumpf 1.14 pid_t pid = 0;
|
634 kumpf 1.7 #endif
|
635 kumpf 1.1
636 try
637 {
|
638 kumpf 1.7 AutoMutex lock(_agentMutex);
639
640 PEGASUS_ASSERT(_isInitialized);
641
|
642 kumpf 1.1 // Close the connection with the Provider Agent
643 _pipeFromAgent.reset();
644 _pipeToAgent.reset();
645
646 _providerModuleCache = CIMInstance();
647
648 {
649 AutoMutex lock(_numProviderProcessesMutex);
650 _numProviderProcesses--;
651 }
652
|
653 kumpf 1.7 _isInitialized = false;
654
|
655 kumpf 1.1 #if defined(PEGASUS_HAS_SIGNALS)
|
656 kumpf 1.7 // Save the _pid so we can use it after we've released the _agentMutex
657 pid = _pid;
|
658 kumpf 1.1 #endif
659
660 //
661 // Complete with null responses all outstanding requests on this
662 // connection
663 //
664 {
665 AutoMutex tableLock(_outstandingRequestTableMutex);
666
667 CIMResponseMessage* response =
668 cleanShutdown ? _REQUEST_NOT_PROCESSED : 0;
669
670 for (OutstandingRequestTable::Iterator i =
671 _outstandingRequestTable.start();
672 i != 0; i++)
673 {
674 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
675 String("Completing messageId \"") + i.key() +
676 "\" with a null response.");
677 i.value()->responseMessage = response;
678 i.value()->responseReady->signal();
679 kumpf 1.1 }
680
681 _outstandingRequestTable.clear();
|
682 kumpf 1.3 }
|
683 kumpf 1.1
|
684 kumpf 1.3 //
685 // If not a clean shutdown, call the provider module failure callback
686 //
687 if (!cleanShutdown)
688 {
|
689 kumpf 1.1 //
|
690 kumpf 1.3 // Call the provider module failure callback to communicate
691 // the failure to the Provider Manager Service. The Provider
692 // Manager Service will inform the Indication Service.
|
693 kumpf 1.1 //
|
694 kumpf 1.3 _providerModuleFailCallback(_moduleName, _userName, _userContext);
|
695 kumpf 1.1 }
696 }
697 catch (...)
698 {
699 // We're uninitializing, so do not propagate the exception
|
700 marek 1.9 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
701 kumpf 1.1 "Ignoring _uninitialize() exception.");
702 }
703
|
704 kumpf 1.7 #if defined(PEGASUS_HAS_SIGNALS)
705 // Harvest the status of the agent process to prevent a zombie. Do not
706 // hold the _agentMutex during this operation.
707
|
708 kumpf 1.14 if ((pid != 0) && (Executor::reapProviderAgent(pid) == -1))
|
709 kumpf 1.7 {
|
710 marek 1.9 PEG_TRACE((TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
711 kumpf 1.7 "ProviderAgentContainer::_uninitialize(): "
|
712 kumpf 1.10 "Executor::reapProviderAgent() failed."));
|
713 kumpf 1.7 }
714 #endif
715
|
716 kumpf 1.1 PEG_METHOD_EXIT();
717 }
718
719 String ProviderAgentContainer::getModuleName() const
720 {
721 return _moduleName;
722 }
723
724 CIMResponseMessage* ProviderAgentContainer::processMessage(
725 CIMRequestMessage* request)
726 {
727 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
728 "ProviderAgentContainer::processMessage");
729
730 CIMResponseMessage* response;
731
732 do
733 {
734 response = _processMessage(request);
735
736 if (response == _REQUEST_NOT_PROCESSED)
737 kumpf 1.1 {
738 // Check for request message types that should not be retried.
739 if ((request->getType() ==
740 CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE) ||
741 (request->getType() ==
742 CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE) ||
743 (request->getType() ==
744 CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE) ||
745 (request->getType() ==
746 CIM_DELETE_SUBSCRIPTION_REQUEST_MESSAGE))
747 {
748 response = request->buildResponse();
749 break;
750 }
751 else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
752 {
753 CIMDisableModuleResponseMessage* dmResponse =
754 dynamic_cast<CIMDisableModuleResponseMessage*>(response);
755 PEGASUS_ASSERT(dmResponse != 0);
756
757 Array<Uint16> operationalStatus;
758 kumpf 1.1 operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_STOPPED);
759 dmResponse->operationalStatus = operationalStatus;
760 break;
761 }
762 }
763 } while (response == _REQUEST_NOT_PROCESSED);
764
|
765 kumpf 1.2 if (request->getType() == CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE)
766 {
767 _subscriptionInitComplete = true;
768 }
769
|
770 kumpf 1.1 PEG_METHOD_EXIT();
771 return response;
772 }
773
774 CIMResponseMessage* ProviderAgentContainer::_processMessage(
775 CIMRequestMessage* request)
776 {
777 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
778 "ProviderAgentContainer::_processMessage");
779
780 CIMResponseMessage* response;
781 String originalMessageId = request->messageId;
782
783 // These three variables are used for the provider module optimization.
784 // See the _providerModuleCache member description for more information.
785 AutoPtr<ProviderIdContainer> origProviderId;
786 Boolean doProviderModuleOptimization = false;
787 Boolean updateProviderModuleCache = false;
788
789 try
790 {
791 kumpf 1.1 // The messageId attribute is used to correlate response messages
792 // from the Provider Agent with request messages, so it is imperative
793 // that the ID is unique for each request. The incoming ID cannot be
794 // trusted to be unique, so we substitute a unique one. The memory
795 // address of the request is used as the source of a unique piece of
796 // data. (The message ID is only required to be unique while the
797 // request is outstanding.)
798 char messagePtrString[20];
799 sprintf(messagePtrString, "%p", request);
800 String uniqueMessageId = messagePtrString;
801
802 //
803 // Set up the OutstandingRequestEntry for this request
804 //
805 Semaphore waitSemaphore(0);
806 OutstandingRequestEntry outstandingRequestEntry(
807 originalMessageId, request, response, &waitSemaphore);
808
809 //
810 // Lock the Provider Agent Container while initializing the
811 // agent and writing the request to the connection
812 kumpf 1.1 //
813 {
814 AutoMutex lock(_agentMutex);
815
816 //
817 // Initialize the Provider Agent, if necessary
818 //
819 if (!_isInitialized)
820 {
821 _initialize();
822 }
823
824 //
825 // Add an entry to the OutstandingRequestTable for this request
826 //
827 {
828 AutoMutex tableLock(_outstandingRequestTableMutex);
829
830 _outstandingRequestTable.insert(
831 uniqueMessageId, &outstandingRequestEntry);
832 }
833 kumpf 1.1
834 // Get the provider module from the ProviderIdContainer to see if
835 // we can optimize out the transmission of this instance to the
836 // Provider Agent. (See the _providerModuleCache description.)
|
837 kumpf 1.6 if (request->operationContext.contains(ProviderIdContainer::NAME))
|
838 kumpf 1.1 {
839 ProviderIdContainer pidc = request->operationContext.get(
840 ProviderIdContainer::NAME);
841 origProviderId.reset(new ProviderIdContainer(
842 pidc.getModule(), pidc.getProvider(),
843 pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
844 if (_providerModuleCache.isUninitialized() ||
845 (!pidc.getModule().identical(_providerModuleCache)))
846 {
847 // We haven't sent this provider module instance to the
848 // Provider Agent yet. Update our cache after we send it.
849 updateProviderModuleCache = true;
850 }
851 else
852 {
853 // Replace the provider module in the ProviderIdContainer
854 // with an uninitialized instance. We'll need to put the
855 // original one back after the message is sent.
856 request->operationContext.set(ProviderIdContainer(
857 CIMInstance(), pidc.getProvider(),
858 pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
859 kumpf 1.1 doProviderModuleOptimization = true;
860 }
861 }
862
863 //
864 // Write the message to the pipe
865 //
866 try
867 {
868 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL3,
869 String("Sending request to agent with messageId ") +
870 uniqueMessageId);
871
872 request->messageId = uniqueMessageId;
873 AnonymousPipe::Status writeStatus =
874 _pipeToAgent->writeMessage(request);
875 request->messageId = originalMessageId;
876
877 if (doProviderModuleOptimization)
878 {
879 request->operationContext.set(*origProviderId.get());
880 kumpf 1.1 }
881
882 if (writeStatus != AnonymousPipe::STATUS_SUCCESS)
883 {
|
884 marek 1.9 PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL2,
|
885 kumpf 1.1 "Failed to write message to pipe. writeStatus = %d.",
|
886 marek 1.9 writeStatus));
|
887 kumpf 1.1
888 request->messageId = originalMessageId;
889
890 if (doProviderModuleOptimization)
891 {
892 request->operationContext.set(*origProviderId.get());
893 }
894
895 // Remove this OutstandingRequestTable entry
896 {
897 AutoMutex tableLock(_outstandingRequestTableMutex);
898 Boolean removed =
899 _outstandingRequestTable.remove(uniqueMessageId);
900 PEGASUS_ASSERT(removed);
901 }
902
903 // A response value of _REQUEST_NOT_PROCESSED indicates
904 // that the request was not processed by the provider
905 // agent, so it can be retried safely.
906 PEG_METHOD_EXIT();
907 return _REQUEST_NOT_PROCESSED;
908 kumpf 1.1 }
909
910 if (updateProviderModuleCache)
911 {
912 _providerModuleCache = origProviderId->getModule();
913 }
914 }
915 catch (...)
916 {
917 request->messageId = originalMessageId;
918
919 if (doProviderModuleOptimization)
920 {
921 request->operationContext.set(*origProviderId.get());
922 }
923
|
924 marek 1.9 PEG_TRACE_CSTRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
|
925 kumpf 1.1 "Failed to write message to pipe.");
926 // Remove the OutstandingRequestTable entry for this request
927 {
928 AutoMutex tableLock(_outstandingRequestTableMutex);
929 Boolean removed =
930 _outstandingRequestTable.remove(uniqueMessageId);
931 PEGASUS_ASSERT(removed);
932 }
933 PEG_METHOD_EXIT();
934 throw;
935 }
936 }
937
938 //
939 // Wait for the response
940 //
941 try
942 {
943 // Must not hold _agentMutex while waiting for the response
944 waitSemaphore.wait();
945 }
946 kumpf 1.1 catch (...)
947 {
948 // Remove the OutstandingRequestTable entry for this request
949 {
950 AutoMutex tableLock(_outstandingRequestTableMutex);
951 Boolean removed =
952 _outstandingRequestTable.remove(uniqueMessageId);
953 PEGASUS_ASSERT(removed);
954 }
955 PEG_METHOD_EXIT();
956 throw;
957 }
958
959 // A response value of _REQUEST_NOT_PROCESSED indicates that the
960 // provider agent process was terminating when the request was sent.
|
961 kumpf 1.6 // The request was not processed by the provider agent, so it can be
|
962 kumpf 1.1 // retried safely.
963 if (response == _REQUEST_NOT_PROCESSED)
964 {
965 PEG_METHOD_EXIT();
966 return response;
967 }
968
969 // A null response is returned when an agent connection is closed
970 // while requests remain outstanding.
971 if (response == 0)
972 {
973 response = request->buildResponse();
974 response->cimException = PEGASUS_CIM_EXCEPTION(
975 CIM_ERR_FAILED,
976 MessageLoaderParms(
977 "ProviderManager.OOPProviderManagerRouter."
978 "CIMPROVAGT_CONNECTION_LOST",
979 "Lost connection with cimprovagt \"$0\".",
980 _moduleName));
981 }
982 }
983 kumpf 1.1 catch (CIMException& e)
984 {
985 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
986 String("Caught exception: ") + e.getMessage());
987 response = request->buildResponse();
988 response->cimException = e;
989 }
990 catch (Exception& e)
991 {
992 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
993 String("Caught exception: ") + e.getMessage());
994 response = request->buildResponse();
995 response->cimException = PEGASUS_CIM_EXCEPTION(
996 CIM_ERR_FAILED, e.getMessage());
997 }
998 catch (...)
999 {
|
1000 marek 1.9 PEG_TRACE_CSTRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
|
1001 kumpf 1.1 "Caught unknown exception");
1002 response = request->buildResponse();
1003 response->cimException = PEGASUS_CIM_EXCEPTION(
1004 CIM_ERR_FAILED, String::EMPTY);
1005 }
1006
1007 response->messageId = originalMessageId;
|
1008 kumpf 1.17 response->syncAttributes(request);
|
1009 kumpf 1.1
1010 PEG_METHOD_EXIT();
1011 return response;
1012 }
1013
1014 void ProviderAgentContainer::unloadIdleProviders()
1015 {
1016 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1017 "ProviderAgentContainer::unloadIdleProviders");
1018
1019 AutoMutex lock(_agentMutex);
1020 if (_isInitialized)
1021 {
1022 // Send a "wake up" message to the Provider Agent.
1023 // Don't bother checking whether the operation is successful.
1024 Uint32 messageLength = 0;
1025 _pipeToAgent->writeBuffer((const char*)&messageLength, sizeof(Uint32));
1026 }
1027
1028 PEG_METHOD_EXIT();
1029 }
1030 kumpf 1.1
1031 void ProviderAgentContainer::_processResponses()
1032 {
1033 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1034 "ProviderAgentContainer::_processResponses");
1035
1036 //
1037 // Process responses until the pipe is closed
1038 //
1039 while (1)
1040 {
1041 try
1042 {
1043 CIMMessage* message;
1044
1045 //
1046 // Read a response from the Provider Agent
1047 //
1048 AnonymousPipe::Status readStatus =
1049 _pipeFromAgent->readMessage(message);
1050
1051 kumpf 1.1 // Ignore interrupts
1052 if (readStatus == AnonymousPipe::STATUS_INTERRUPT)
1053 {
1054 continue;
1055 }
1056
1057 // Handle an error the same way as a closed connection
1058 if ((readStatus == AnonymousPipe::STATUS_ERROR) ||
1059 (readStatus == AnonymousPipe::STATUS_CLOSED))
1060 {
1061 _uninitialize(false);
1062 return;
1063 }
1064
1065 // A null message indicates that the provider agent process has
1066 // finished its processing and is ready to exit.
1067 if (message == 0)
1068 {
1069 _uninitialize(true);
1070 return;
1071 }
1072 kumpf 1.1
1073 if (message->getType() == CIM_PROCESS_INDICATION_REQUEST_MESSAGE)
1074 {
|
1075 kumpf 1.10 // Process an indication message
1076
|
1077 kumpf 1.1 _indicationCallback(
1078 reinterpret_cast<CIMProcessIndicationRequestMessage*>(
1079 message));
1080 }
1081 else if (!message->isComplete())
1082 {
|
1083 kumpf 1.10 // Process an incomplete response chunk
1084
|
1085 kumpf 1.1 CIMResponseMessage* response;
1086 response = dynamic_cast<CIMResponseMessage*>(message);
1087 PEGASUS_ASSERT(response != 0);
1088
1089 // Get the OutstandingRequestEntry for this response chunk
1090 OutstandingRequestEntry* _outstandingRequestEntry = 0;
1091 {
1092 AutoMutex tableLock(_outstandingRequestTableMutex);
1093 Boolean foundEntry = _outstandingRequestTable.lookup(
1094 response->messageId, _outstandingRequestEntry);
1095 PEGASUS_ASSERT(foundEntry);
1096 }
1097
1098 // Put the original message ID into the response
1099 response->messageId =
1100 _outstandingRequestEntry->originalMessageId;
1101
1102 // Call the response chunk callback to process the chunk
1103 _responseChunkCallback(
1104 _outstandingRequestEntry->requestMessage, response);
1105 }
1106 kumpf 1.1 else
1107 {
|
1108 kumpf 1.10 // Process a completed response
1109
|
1110 kumpf 1.1 CIMResponseMessage* response;
1111 response = dynamic_cast<CIMResponseMessage*>(message);
1112 PEGASUS_ASSERT(response != 0);
1113
1114 // Give the response to the waiting OutstandingRequestEntry
1115 OutstandingRequestEntry* _outstandingRequestEntry = 0;
1116 {
1117 AutoMutex tableLock(_outstandingRequestTableMutex);
1118 Boolean foundEntry = _outstandingRequestTable.lookup(
1119 response->messageId, _outstandingRequestEntry);
1120 PEGASUS_ASSERT(foundEntry);
1121
1122 // Remove the completed request from the table
1123 Boolean removed =
1124 _outstandingRequestTable.remove(response->messageId);
1125 PEGASUS_ASSERT(removed);
1126 }
1127
1128 _outstandingRequestEntry->responseMessage = response;
1129 _outstandingRequestEntry->responseReady->signal();
1130 }
1131 kumpf 1.1 }
1132 catch (Exception& e)
1133 {
1134 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
1135 String("Ignoring exception: ") + e.getMessage());
1136 }
1137 catch (...)
1138 {
|
1139 marek 1.9 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
1140 kumpf 1.1 "Ignoring exception");
1141 }
1142 }
1143
1144 }
1145
1146 ThreadReturnType PEGASUS_THREAD_CDECL
1147 ProviderAgentContainer::_responseProcessor(void* arg)
1148 {
1149 ProviderAgentContainer* pa =
1150 reinterpret_cast<ProviderAgentContainer*>(arg);
1151
1152 pa->_processResponses();
1153
|
1154 kumpf 1.6 return ThreadReturnType(0);
|
1155 kumpf 1.1 }
1156
1157 /////////////////////////////////////////////////////////////////////////////
1158 // OOPProviderManagerRouter
1159 /////////////////////////////////////////////////////////////////////////////
1160
1161 OOPProviderManagerRouter::OOPProviderManagerRouter(
1162 PEGASUS_INDICATION_CALLBACK_T indicationCallback,
1163 PEGASUS_RESPONSE_CHUNK_CALLBACK_T responseChunkCallback,
1164 PEGASUS_PROVIDERMODULEFAIL_CALLBACK_T providerModuleFailCallback)
1165 {
1166 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1167 "OOPProviderManagerRouter::OOPProviderManagerRouter");
1168
1169 _indicationCallback = indicationCallback;
1170 _responseChunkCallback = responseChunkCallback;
1171 _providerModuleFailCallback = providerModuleFailCallback;
1172 _subscriptionInitComplete = false;
1173
1174 PEG_METHOD_EXIT();
1175 }
1176 kumpf 1.1
1177 OOPProviderManagerRouter::~OOPProviderManagerRouter()
1178 {
1179 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1180 "OOPProviderManagerRouter::~OOPProviderManagerRouter");
1181
1182 try
1183 {
1184 // Clean up the ProviderAgentContainers
1185 AutoMutex lock(_providerAgentTableMutex);
1186 ProviderAgentTable::Iterator i = _providerAgentTable.start();
|
1187 kumpf 1.6 for (; i != 0; i++)
|
1188 kumpf 1.1 {
1189 delete i.value();
1190 }
1191 }
1192 catch (...) {}
1193
1194 PEG_METHOD_EXIT();
1195 }
1196
1197 Message* OOPProviderManagerRouter::processMessage(Message* message)
1198 {
1199 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1200 "OOPProviderManagerRouter::processMessage");
1201
1202 CIMRequestMessage* request = dynamic_cast<CIMRequestMessage *>(message);
1203 PEGASUS_ASSERT(request != 0);
1204
1205 AutoPtr<CIMResponseMessage> response;
1206
1207 //
1208 // Get the provider information from the request
1209 kumpf 1.1 //
1210 CIMInstance providerModule;
1211
1212 if ((dynamic_cast<CIMOperationRequestMessage*>(request) != 0) ||
1213 (dynamic_cast<CIMIndicationRequestMessage*>(request) != 0) ||
1214 (request->getType() == CIM_EXPORT_INDICATION_REQUEST_MESSAGE))
1215 {
1216 // Provider information is in the OperationContext
1217 ProviderIdContainer pidc = (ProviderIdContainer)
1218 request->operationContext.get(ProviderIdContainer::NAME);
1219 providerModule = pidc.getModule();
1220 }
1221 else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
1222 {
1223 CIMEnableModuleRequestMessage* emReq =
1224 dynamic_cast<CIMEnableModuleRequestMessage*>(request);
1225 providerModule = emReq->providerModule;
1226 }
1227 else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
1228 {
1229 CIMDisableModuleRequestMessage* dmReq =
1230 kumpf 1.1 dynamic_cast<CIMDisableModuleRequestMessage*>(request);
1231 providerModule = dmReq->providerModule;
1232 }
1233 else if ((request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE) ||
1234 (request->getType() ==
1235 CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE) ||
1236 (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE))
1237 {
1238 // This operation is not provider-specific
1239 }
1240 else
1241 {
1242 // Unrecognized message type. This should never happen.
1243 PEGASUS_ASSERT(0);
1244 response.reset(request->buildResponse());
1245 response->cimException = PEGASUS_CIM_EXCEPTION(
1246 CIM_ERR_FAILED, "Unrecognized message type.");
1247 PEG_METHOD_EXIT();
1248 return response.release();
1249 }
1250
1251 kumpf 1.1 //
1252 // Process the request message
1253 //
1254 if (request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE)
1255 {
1256 // Forward the CIMStopAllProvidersRequest to all providers
1257 response.reset(_forwardRequestToAllAgents(request));
1258
1259 // Note: Do not uninitialize the ProviderAgentContainers here.
1260 // Just let the selecting thread notice when the agent connections
1261 // are closed.
1262 }
|
1263 kumpf 1.6 else if (request->getType () ==
|
1264 kumpf 1.1 CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE)
1265 {
1266 _subscriptionInitComplete = true;
1267
1268 //
|
1269 kumpf 1.6 // Forward the CIMSubscriptionInitCompleteRequestMessage to
|
1270 kumpf 1.1 // all providers
1271 //
1272 response.reset (_forwardRequestToAllAgents (request));
1273 }
1274 else if (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE)
1275 {
1276 CIMNotifyConfigChangeRequestMessage* notifyRequest =
1277 dynamic_cast<CIMNotifyConfigChangeRequestMessage*>(request);
1278 PEGASUS_ASSERT(notifyRequest != 0);
1279
1280 if (notifyRequest->currentValueModified)
1281 {
1282 // Forward the CIMNotifyConfigChangeRequestMessage to all providers
1283 response.reset(_forwardRequestToAllAgents(request));
1284 }
1285 else
1286 {
1287 // No need to notify provider agents about changes to planned value
1288 response.reset(request->buildResponse());
1289 }
1290 }
1291 kumpf 1.1 else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
1292 {
1293 // Fan out the request to all Provider Agent processes for this module
1294
1295 // Retrieve the provider module name
1296 String moduleName;
1297 CIMValue nameValue = providerModule.getProperty(
1298 providerModule.findProperty("Name")).getValue();
1299 nameValue.get(moduleName);
1300
1301 // Look up the Provider Agents for this module
1302 Array<ProviderAgentContainer*> paArray =
1303 _lookupProviderAgents(moduleName);
1304
1305 for (Uint32 i=0; i<paArray.size(); i++)
1306 {
1307 //
1308 // Do not start up an agent process just to disable the module
1309 //
1310 if (paArray[i]->isInitialized())
1311 {
1312 kumpf 1.1 //
1313 // Forward the request to the provider agent
1314 //
1315 response.reset(paArray[i]->processMessage(request));
1316
1317 // Note: Do not uninitialize the ProviderAgentContainer here
1318 // when a disable module operation is successful. Just let the
1319 // selecting thread notice when the agent connection is closed.
1320
1321 // Determine the success of the disable module operation
1322 CIMDisableModuleResponseMessage* dmResponse =
1323 dynamic_cast<CIMDisableModuleResponseMessage*>(
1324 response.get());
1325 PEGASUS_ASSERT(dmResponse != 0);
1326
1327 Boolean isStopped = false;
1328 for (Uint32 i=0; i < dmResponse->operationalStatus.size(); i++)
1329 {
1330 if (dmResponse->operationalStatus[i] ==
1331 CIM_MSE_OPSTATUS_VALUE_STOPPED)
1332 {
1333 kumpf 1.1 isStopped = true;
1334 break;
1335 }
1336 }
1337
1338 // If the operation is unsuccessful, stop and return the error
1339 if ((dmResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
1340 !isStopped)
1341 {
1342 break;
1343 }
1344 }
1345 }
1346
1347 // Use a default response if no Provider Agents were called
1348 if (!response.get())
1349 {
1350 response.reset(request->buildResponse());
1351
1352 CIMDisableModuleResponseMessage* dmResponse =
1353 dynamic_cast<CIMDisableModuleResponseMessage*>(response.get());
1354 kumpf 1.1 PEGASUS_ASSERT(dmResponse != 0);
1355
1356 Array<Uint16> operationalStatus;
1357 operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_STOPPED);
1358 dmResponse->operationalStatus = operationalStatus;
1359 }
1360 }
1361 else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
1362 {
1363 // Fan out the request to all Provider Agent processes for this module
1364
1365 // Retrieve the provider module name
1366 String moduleName;
1367 CIMValue nameValue = providerModule.getProperty(
1368 providerModule.findProperty("Name")).getValue();
1369 nameValue.get(moduleName);
1370
1371 // Look up the Provider Agents for this module
1372 Array<ProviderAgentContainer*> paArray =
1373 _lookupProviderAgents(moduleName);
1374
1375 kumpf 1.1 for (Uint32 i=0; i<paArray.size(); i++)
1376 {
1377 //
1378 // Do not start up an agent process just to enable the module
1379 //
1380 if (paArray[i]->isInitialized())
1381 {
1382 //
1383 // Forward the request to the provider agent
1384 //
1385 response.reset(paArray[i]->processMessage(request));
1386
1387 // Determine the success of the enable module operation
1388 CIMEnableModuleResponseMessage* emResponse =
1389 dynamic_cast<CIMEnableModuleResponseMessage*>(
1390 response.get());
1391 PEGASUS_ASSERT(emResponse != 0);
1392
1393 Boolean isOk = false;
1394 for (Uint32 i=0; i < emResponse->operationalStatus.size(); i++)
1395 {
1396 kumpf 1.1 if (emResponse->operationalStatus[i] ==
1397 CIM_MSE_OPSTATUS_VALUE_OK)
1398 {
1399 isOk = true;
1400 break;
1401 }
1402 }
1403
1404 // If the operation is unsuccessful, stop and return the error
1405 if ((emResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
1406 !isOk)
1407 {
1408 break;
1409 }
1410 }
1411 }
1412
1413 // Use a default response if no Provider Agents were called
1414 if (!response.get())
1415 {
1416 response.reset(request->buildResponse());
1417 kumpf 1.1
1418 CIMEnableModuleResponseMessage* emResponse =
1419 dynamic_cast<CIMEnableModuleResponseMessage*>(response.get());
1420 PEGASUS_ASSERT(emResponse != 0);
1421
1422 Array<Uint16> operationalStatus;
1423 operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_OK);
1424 emResponse->operationalStatus = operationalStatus;
1425 }
1426 }
1427 else
1428 {
1429 //
1430 // Look up the Provider Agent for this module instance and requesting
1431 // user
1432 //
1433 ProviderAgentContainer* pa = _lookupProviderAgent(providerModule,
1434 request);
1435 PEGASUS_ASSERT(pa != 0);
1436
1437 //
1438 kumpf 1.1 // Forward the request to the provider agent
1439 //
1440 response.reset(pa->processMessage(request));
1441 }
1442
1443 PEG_METHOD_EXIT();
1444 return response.release();
1445 }
1446
1447 ProviderAgentContainer* OOPProviderManagerRouter::_lookupProviderAgent(
1448 const CIMInstance& providerModule,
1449 CIMRequestMessage* request)
1450 {
1451 // Retrieve the provider module name
1452 String moduleName;
1453 CIMValue nameValue = providerModule.getProperty(
1454 providerModule.findProperty("Name")).getValue();
1455 nameValue.get(moduleName);
1456
1457 // Retrieve the provider user context configuration
1458 Uint16 userContext = 0;
1459 kumpf 1.1 Uint32 pos = providerModule.findProperty(
1460 PEGASUS_PROPERTYNAME_MODULE_USERCONTEXT);
1461 if (pos != PEG_NOT_FOUND)
1462 {
1463 CIMValue userContextValue =
1464 providerModule.getProperty(pos).getValue();
1465 if (!userContextValue.isNull())
1466 {
1467 userContextValue.get(userContext);
1468 }
1469 }
1470
1471 if (userContext == 0)
1472 {
|
1473 ouyang.jian 1.15 // PASE has a default user context "QYCMCIMOM",
1474 // so we leave userContext unset here.
1475 #ifndef PEGASUS_OS_PASE
|
1476 kumpf 1.1 userContext = PEGASUS_DEFAULT_PROV_USERCTXT;
|
1477 ouyang.jian 1.15 #endif
|
1478 kumpf 1.1 }
1479
1480 String userName;
1481
1482 if (userContext == PG_PROVMODULE_USERCTXT_REQUESTOR)
1483 {
|
1484 kumpf 1.6 if (request->operationContext.contains(IdentityContainer::NAME))
|
1485 kumpf 1.1 {
1486 // User Name is in the OperationContext
1487 IdentityContainer ic = (IdentityContainer)
1488 request->operationContext.get(IdentityContainer::NAME);
1489 userName = ic.getUserName();
1490 }
1491 //else
1492 //{
1493 // If no IdentityContainer is present, default to the CIM
1494 // Server's user context
1495 //}
1496
1497 // If authentication is disabled, use the CIM Server's user context
1498 if (!userName.size())
1499 {
1500 userName = System::getEffectiveUserName();
1501 }
1502 }
1503 else if (userContext == PG_PROVMODULE_USERCTXT_DESIGNATED)
1504 {
1505 // Retrieve the provider module designated user property value
1506 kumpf 1.1 providerModule.getProperty(providerModule.findProperty(
1507 PEGASUS_PROPERTYNAME_MODULE_DESIGNATEDUSER)).getValue().
1508 get(userName);
1509 }
1510 else if (userContext == PG_PROVMODULE_USERCTXT_CIMSERVER)
1511 {
1512 userName = System::getEffectiveUserName();
1513 }
|
1514 ouyang.jian 1.15 #ifdef PEGASUS_OS_PASE // it might be unset user in PASE in this branch.
1515 else if (userContext == 0)
1516 {
1517 userName = "QYCMCIMOM";
1518 }
1519 #endif
|
1520 kumpf 1.1 else // Privileged User
1521 {
1522 PEGASUS_ASSERT(userContext == PG_PROVMODULE_USERCTXT_PRIVILEGED);
1523 userName = System::getPrivilegedUserName();
1524 }
1525
1526 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1527 "Module name = " + moduleName);
|
1528 marek 1.9 PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1529 "User context = %hd.", userContext));
|
1530 kumpf 1.1 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1531 "User name = " + userName);
1532
1533 ProviderAgentContainer* pa = 0;
|
1534 ouyang.jian 1.15 #ifdef PEGASUS_OS_PASE
1535 String userUpper = userName;
1536 userUpper.toUpper();
1537 String key = moduleName + ":" + userUpper;
1538 #else
|
1539 kumpf 1.1 String key = moduleName + ":" + userName;
|
1540 ouyang.jian 1.15 #endif
|
1541 kumpf 1.1
1542 AutoMutex lock(_providerAgentTableMutex);
1543 if (!_providerAgentTable.lookup(key, pa))
1544 {
1545 pa = new ProviderAgentContainer(
1546 moduleName, userName, userContext,
1547 _indicationCallback, _responseChunkCallback,
1548 _providerModuleFailCallback,
1549 _subscriptionInitComplete);
1550 _providerAgentTable.insert(key, pa);
1551 }
1552 return pa;
1553 }
1554
1555 Array<ProviderAgentContainer*> OOPProviderManagerRouter::_lookupProviderAgents(
1556 const String& moduleName)
1557 {
1558 Array<ProviderAgentContainer*> paArray;
1559
1560 AutoMutex lock(_providerAgentTableMutex);
1561 for (ProviderAgentTable::Iterator i = _providerAgentTable.start(); i; i++)
1562 kumpf 1.1 {
1563 if (i.value()->getModuleName() == moduleName)
1564 {
1565 paArray.append(i.value());
1566 }
1567 }
1568 return paArray;
1569 }
1570
1571 CIMResponseMessage* OOPProviderManagerRouter::_forwardRequestToAllAgents(
1572 CIMRequestMessage* request)
1573 {
1574 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1575 "OOPProviderManagerRouter::_forwardRequestToAllAgents");
1576
1577 // Get a list of the ProviderAgentContainers. We need our own array copy
1578 // because we cannot hold the _providerAgentTableMutex while calling
1579 // _ProviderAgentContainer::processMessage().
1580 Array<ProviderAgentContainer*> paContainerArray;
1581 {
1582 AutoMutex tableLock(_providerAgentTableMutex);
1583 kumpf 1.1 for (ProviderAgentTable::Iterator i = _providerAgentTable.start();
1584 i != 0; i++)
1585 {
1586 paContainerArray.append(i.value());
1587 }
1588 }
1589
1590 CIMException responseException;
1591
1592 // Forward the request to each of the initialized provider agents
1593 for (Uint32 j = 0; j < paContainerArray.size(); j++)
1594 {
1595 ProviderAgentContainer* pa = paContainerArray[j];
1596 if (pa->isInitialized())
1597 {
1598 // Note: The ProviderAgentContainer could become uninitialized
1599 // before _ProviderAgentContainer::processMessage() processes
1600 // this request. In this case, the Provider Agent process will
1601 // (unfortunately) be started to process this message.
1602 AutoPtr<CIMResponseMessage> response;
1603 response.reset(pa->processMessage(request));
1604 kumpf 1.1 if (response.get() != 0)
1605 {
1606 // If the operation failed, save the exception data
1607 if ((response->cimException.getCode() != CIM_ERR_SUCCESS) &&
1608 (responseException.getCode() == CIM_ERR_SUCCESS))
1609 {
1610 responseException = response->cimException;
1611 }
1612 }
1613 }
1614 }
1615
1616 CIMResponseMessage* response = request->buildResponse();
1617 response->cimException = responseException;
1618
1619 PEG_METHOD_EXIT();
1620 return response;
1621 }
1622
1623 void OOPProviderManagerRouter::unloadIdleProviders()
1624 {
1625 kumpf 1.1 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1626 "OOPProviderManagerRouter::unloadIdleProviders");
1627
|
1628 kumpf 1.7 // Get a list of the ProviderAgentContainers. We need our own array copy
1629 // because we cannot hold the _providerAgentTableMutex while calling
1630 // ProviderAgentContainer::unloadIdleProviders().
1631 Array<ProviderAgentContainer*> paContainerArray;
1632 {
1633 AutoMutex tableLock(_providerAgentTableMutex);
1634 for (ProviderAgentTable::Iterator i = _providerAgentTable.start();
1635 i != 0; i++)
1636 {
1637 paContainerArray.append(i.value());
1638 }
1639 }
1640
|
1641 kumpf 1.1 // Iterate through the _providerAgentTable unloading idle providers
|
1642 kumpf 1.7 for (Uint32 j = 0; j < paContainerArray.size(); j++)
|
1643 kumpf 1.1 {
|
1644 kumpf 1.7 paContainerArray[j]->unloadIdleProviders();
|
1645 kumpf 1.1 }
1646
1647 PEG_METHOD_EXIT();
1648 }
1649
1650 PEGASUS_NAMESPACE_END
|