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 reinterpret_cast<CIMResponseMessage*>(&_REQUEST_NOT_PROCESSED);
337
338 ProviderAgentContainer::ProviderAgentContainer(
339 const String & moduleName,
340 kumpf 1.1 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
1009 PEG_METHOD_EXIT();
1010 return response;
1011 }
1012
1013 void ProviderAgentContainer::unloadIdleProviders()
1014 {
1015 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1016 "ProviderAgentContainer::unloadIdleProviders");
1017
1018 AutoMutex lock(_agentMutex);
1019 if (_isInitialized)
1020 {
1021 // Send a "wake up" message to the Provider Agent.
1022 kumpf 1.1 // Don't bother checking whether the operation is successful.
1023 Uint32 messageLength = 0;
1024 _pipeToAgent->writeBuffer((const char*)&messageLength, sizeof(Uint32));
1025 }
1026
1027 PEG_METHOD_EXIT();
1028 }
1029
1030 void ProviderAgentContainer::_processResponses()
1031 {
1032 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1033 "ProviderAgentContainer::_processResponses");
1034
1035 //
1036 // Process responses until the pipe is closed
1037 //
1038 while (1)
1039 {
1040 try
1041 {
1042 CIMMessage* message;
1043 kumpf 1.1
1044 //
1045 // Read a response from the Provider Agent
1046 //
1047 AnonymousPipe::Status readStatus =
1048 _pipeFromAgent->readMessage(message);
1049
1050 // Ignore interrupts
1051 if (readStatus == AnonymousPipe::STATUS_INTERRUPT)
1052 {
1053 continue;
1054 }
1055
1056 // Handle an error the same way as a closed connection
1057 if ((readStatus == AnonymousPipe::STATUS_ERROR) ||
1058 (readStatus == AnonymousPipe::STATUS_CLOSED))
1059 {
1060 _uninitialize(false);
1061 return;
1062 }
1063
1064 kumpf 1.1 // A null message indicates that the provider agent process has
1065 // finished its processing and is ready to exit.
1066 if (message == 0)
1067 {
1068 _uninitialize(true);
1069 return;
1070 }
1071
1072 if (message->getType() == CIM_PROCESS_INDICATION_REQUEST_MESSAGE)
1073 {
|
1074 kumpf 1.10 // Process an indication message
1075
|
1076 kumpf 1.1 _indicationCallback(
1077 reinterpret_cast<CIMProcessIndicationRequestMessage*>(
1078 message));
1079 }
1080 else if (!message->isComplete())
1081 {
|
1082 kumpf 1.10 // Process an incomplete response chunk
1083
|
1084 kumpf 1.1 CIMResponseMessage* response;
1085 response = dynamic_cast<CIMResponseMessage*>(message);
1086 PEGASUS_ASSERT(response != 0);
1087
1088 // Get the OutstandingRequestEntry for this response chunk
1089 OutstandingRequestEntry* _outstandingRequestEntry = 0;
1090 {
1091 AutoMutex tableLock(_outstandingRequestTableMutex);
1092 Boolean foundEntry = _outstandingRequestTable.lookup(
1093 response->messageId, _outstandingRequestEntry);
1094 PEGASUS_ASSERT(foundEntry);
1095 }
1096
1097 // Put the original message ID into the response
1098 response->messageId =
1099 _outstandingRequestEntry->originalMessageId;
1100
1101 // Call the response chunk callback to process the chunk
1102 _responseChunkCallback(
1103 _outstandingRequestEntry->requestMessage, response);
1104 }
1105 kumpf 1.1 else
1106 {
|
1107 kumpf 1.10 // Process a completed response
1108
|
1109 kumpf 1.1 CIMResponseMessage* response;
1110 response = dynamic_cast<CIMResponseMessage*>(message);
1111 PEGASUS_ASSERT(response != 0);
1112
1113 // Give the response to the waiting OutstandingRequestEntry
1114 OutstandingRequestEntry* _outstandingRequestEntry = 0;
1115 {
1116 AutoMutex tableLock(_outstandingRequestTableMutex);
1117 Boolean foundEntry = _outstandingRequestTable.lookup(
1118 response->messageId, _outstandingRequestEntry);
1119 PEGASUS_ASSERT(foundEntry);
1120
1121 // Remove the completed request from the table
1122 Boolean removed =
1123 _outstandingRequestTable.remove(response->messageId);
1124 PEGASUS_ASSERT(removed);
1125 }
1126
1127 _outstandingRequestEntry->responseMessage = response;
1128 _outstandingRequestEntry->responseReady->signal();
1129 }
1130 kumpf 1.1 }
1131 catch (Exception& e)
1132 {
1133 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
1134 String("Ignoring exception: ") + e.getMessage());
1135 }
1136 catch (...)
1137 {
|
1138 marek 1.9 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
1139 kumpf 1.1 "Ignoring exception");
1140 }
1141 }
1142
1143 }
1144
1145 ThreadReturnType PEGASUS_THREAD_CDECL
1146 ProviderAgentContainer::_responseProcessor(void* arg)
1147 {
1148 ProviderAgentContainer* pa =
1149 reinterpret_cast<ProviderAgentContainer*>(arg);
1150
1151 pa->_processResponses();
1152
|
1153 kumpf 1.6 return ThreadReturnType(0);
|
1154 kumpf 1.1 }
1155
1156 /////////////////////////////////////////////////////////////////////////////
1157 // OOPProviderManagerRouter
1158 /////////////////////////////////////////////////////////////////////////////
1159
1160 OOPProviderManagerRouter::OOPProviderManagerRouter(
1161 PEGASUS_INDICATION_CALLBACK_T indicationCallback,
1162 PEGASUS_RESPONSE_CHUNK_CALLBACK_T responseChunkCallback,
1163 PEGASUS_PROVIDERMODULEFAIL_CALLBACK_T providerModuleFailCallback)
1164 {
1165 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1166 "OOPProviderManagerRouter::OOPProviderManagerRouter");
1167
1168 _indicationCallback = indicationCallback;
1169 _responseChunkCallback = responseChunkCallback;
1170 _providerModuleFailCallback = providerModuleFailCallback;
1171 _subscriptionInitComplete = false;
1172
1173 PEG_METHOD_EXIT();
1174 }
1175 kumpf 1.1
1176 OOPProviderManagerRouter::~OOPProviderManagerRouter()
1177 {
1178 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1179 "OOPProviderManagerRouter::~OOPProviderManagerRouter");
1180
1181 try
1182 {
1183 // Clean up the ProviderAgentContainers
1184 AutoMutex lock(_providerAgentTableMutex);
1185 ProviderAgentTable::Iterator i = _providerAgentTable.start();
|
1186 kumpf 1.6 for (; i != 0; i++)
|
1187 kumpf 1.1 {
1188 delete i.value();
1189 }
1190 }
1191 catch (...) {}
1192
1193 PEG_METHOD_EXIT();
1194 }
1195
1196 Message* OOPProviderManagerRouter::processMessage(Message* message)
1197 {
1198 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1199 "OOPProviderManagerRouter::processMessage");
1200
1201 CIMRequestMessage* request = dynamic_cast<CIMRequestMessage *>(message);
1202 PEGASUS_ASSERT(request != 0);
1203
1204 AutoPtr<CIMResponseMessage> response;
1205
1206 //
1207 // Get the provider information from the request
1208 kumpf 1.1 //
1209 CIMInstance providerModule;
1210
1211 if ((dynamic_cast<CIMOperationRequestMessage*>(request) != 0) ||
1212 (dynamic_cast<CIMIndicationRequestMessage*>(request) != 0) ||
1213 (request->getType() == CIM_EXPORT_INDICATION_REQUEST_MESSAGE))
1214 {
1215 // Provider information is in the OperationContext
1216 ProviderIdContainer pidc = (ProviderIdContainer)
1217 request->operationContext.get(ProviderIdContainer::NAME);
1218 providerModule = pidc.getModule();
1219 }
1220 else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
1221 {
1222 CIMEnableModuleRequestMessage* emReq =
1223 dynamic_cast<CIMEnableModuleRequestMessage*>(request);
1224 providerModule = emReq->providerModule;
1225 }
1226 else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
1227 {
1228 CIMDisableModuleRequestMessage* dmReq =
1229 kumpf 1.1 dynamic_cast<CIMDisableModuleRequestMessage*>(request);
1230 providerModule = dmReq->providerModule;
1231 }
1232 else if ((request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE) ||
1233 (request->getType() ==
1234 CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE) ||
1235 (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE))
1236 {
1237 // This operation is not provider-specific
1238 }
1239 else
1240 {
1241 // Unrecognized message type. This should never happen.
1242 PEGASUS_ASSERT(0);
1243 response.reset(request->buildResponse());
1244 response->cimException = PEGASUS_CIM_EXCEPTION(
1245 CIM_ERR_FAILED, "Unrecognized message type.");
1246 PEG_METHOD_EXIT();
1247 return response.release();
1248 }
1249
1250 kumpf 1.1 //
1251 // Process the request message
1252 //
1253 if (request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE)
1254 {
1255 // Forward the CIMStopAllProvidersRequest to all providers
1256 response.reset(_forwardRequestToAllAgents(request));
1257
1258 // Note: Do not uninitialize the ProviderAgentContainers here.
1259 // Just let the selecting thread notice when the agent connections
1260 // are closed.
1261 }
|
1262 kumpf 1.6 else if (request->getType () ==
|
1263 kumpf 1.1 CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE)
1264 {
1265 _subscriptionInitComplete = true;
1266
1267 //
|
1268 kumpf 1.6 // Forward the CIMSubscriptionInitCompleteRequestMessage to
|
1269 kumpf 1.1 // all providers
1270 //
1271 response.reset (_forwardRequestToAllAgents (request));
1272 }
1273 else if (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE)
1274 {
1275 CIMNotifyConfigChangeRequestMessage* notifyRequest =
1276 dynamic_cast<CIMNotifyConfigChangeRequestMessage*>(request);
1277 PEGASUS_ASSERT(notifyRequest != 0);
1278
1279 if (notifyRequest->currentValueModified)
1280 {
1281 // Forward the CIMNotifyConfigChangeRequestMessage to all providers
1282 response.reset(_forwardRequestToAllAgents(request));
1283 }
1284 else
1285 {
1286 // No need to notify provider agents about changes to planned value
1287 response.reset(request->buildResponse());
1288 }
1289 }
1290 kumpf 1.1 else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
1291 {
1292 // Fan out the request to all Provider Agent processes for this module
1293
1294 // Retrieve the provider module name
1295 String moduleName;
1296 CIMValue nameValue = providerModule.getProperty(
1297 providerModule.findProperty("Name")).getValue();
1298 nameValue.get(moduleName);
1299
1300 // Look up the Provider Agents for this module
1301 Array<ProviderAgentContainer*> paArray =
1302 _lookupProviderAgents(moduleName);
1303
1304 for (Uint32 i=0; i<paArray.size(); i++)
1305 {
1306 //
1307 // Do not start up an agent process just to disable the module
1308 //
1309 if (paArray[i]->isInitialized())
1310 {
1311 kumpf 1.1 //
1312 // Forward the request to the provider agent
1313 //
1314 response.reset(paArray[i]->processMessage(request));
1315
1316 // Note: Do not uninitialize the ProviderAgentContainer here
1317 // when a disable module operation is successful. Just let the
1318 // selecting thread notice when the agent connection is closed.
1319
1320 // Determine the success of the disable module operation
1321 CIMDisableModuleResponseMessage* dmResponse =
1322 dynamic_cast<CIMDisableModuleResponseMessage*>(
1323 response.get());
1324 PEGASUS_ASSERT(dmResponse != 0);
1325
1326 Boolean isStopped = false;
1327 for (Uint32 i=0; i < dmResponse->operationalStatus.size(); i++)
1328 {
1329 if (dmResponse->operationalStatus[i] ==
1330 CIM_MSE_OPSTATUS_VALUE_STOPPED)
1331 {
1332 kumpf 1.1 isStopped = true;
1333 break;
1334 }
1335 }
1336
1337 // If the operation is unsuccessful, stop and return the error
1338 if ((dmResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
1339 !isStopped)
1340 {
1341 break;
1342 }
1343 }
1344 }
1345
1346 // Use a default response if no Provider Agents were called
1347 if (!response.get())
1348 {
1349 response.reset(request->buildResponse());
1350
1351 CIMDisableModuleResponseMessage* dmResponse =
1352 dynamic_cast<CIMDisableModuleResponseMessage*>(response.get());
1353 kumpf 1.1 PEGASUS_ASSERT(dmResponse != 0);
1354
1355 Array<Uint16> operationalStatus;
1356 operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_STOPPED);
1357 dmResponse->operationalStatus = operationalStatus;
1358 }
1359 }
1360 else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
1361 {
1362 // Fan out the request to all Provider Agent processes for this module
1363
1364 // Retrieve the provider module name
1365 String moduleName;
1366 CIMValue nameValue = providerModule.getProperty(
1367 providerModule.findProperty("Name")).getValue();
1368 nameValue.get(moduleName);
1369
1370 // Look up the Provider Agents for this module
1371 Array<ProviderAgentContainer*> paArray =
1372 _lookupProviderAgents(moduleName);
1373
1374 kumpf 1.1 for (Uint32 i=0; i<paArray.size(); i++)
1375 {
1376 //
1377 // Do not start up an agent process just to enable the module
1378 //
1379 if (paArray[i]->isInitialized())
1380 {
1381 //
1382 // Forward the request to the provider agent
1383 //
1384 response.reset(paArray[i]->processMessage(request));
1385
1386 // Determine the success of the enable module operation
1387 CIMEnableModuleResponseMessage* emResponse =
1388 dynamic_cast<CIMEnableModuleResponseMessage*>(
1389 response.get());
1390 PEGASUS_ASSERT(emResponse != 0);
1391
1392 Boolean isOk = false;
1393 for (Uint32 i=0; i < emResponse->operationalStatus.size(); i++)
1394 {
1395 kumpf 1.1 if (emResponse->operationalStatus[i] ==
1396 CIM_MSE_OPSTATUS_VALUE_OK)
1397 {
1398 isOk = true;
1399 break;
1400 }
1401 }
1402
1403 // If the operation is unsuccessful, stop and return the error
1404 if ((emResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
1405 !isOk)
1406 {
1407 break;
1408 }
1409 }
1410 }
1411
1412 // Use a default response if no Provider Agents were called
1413 if (!response.get())
1414 {
1415 response.reset(request->buildResponse());
1416 kumpf 1.1
1417 CIMEnableModuleResponseMessage* emResponse =
1418 dynamic_cast<CIMEnableModuleResponseMessage*>(response.get());
1419 PEGASUS_ASSERT(emResponse != 0);
1420
1421 Array<Uint16> operationalStatus;
1422 operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_OK);
1423 emResponse->operationalStatus = operationalStatus;
1424 }
1425 }
1426 else
1427 {
1428 //
1429 // Look up the Provider Agent for this module instance and requesting
1430 // user
1431 //
1432 ProviderAgentContainer* pa = _lookupProviderAgent(providerModule,
1433 request);
1434 PEGASUS_ASSERT(pa != 0);
1435
1436 //
1437 kumpf 1.1 // Forward the request to the provider agent
1438 //
1439 response.reset(pa->processMessage(request));
1440 }
1441
1442 response->syncAttributes(request);
1443
1444 PEG_METHOD_EXIT();
1445 return response.release();
1446 }
1447
1448 ProviderAgentContainer* OOPProviderManagerRouter::_lookupProviderAgent(
1449 const CIMInstance& providerModule,
1450 CIMRequestMessage* request)
1451 {
1452 // Retrieve the provider module name
1453 String moduleName;
1454 CIMValue nameValue = providerModule.getProperty(
1455 providerModule.findProperty("Name")).getValue();
1456 nameValue.get(moduleName);
1457
1458 kumpf 1.1 // Retrieve the provider user context configuration
1459 Uint16 userContext = 0;
1460 Uint32 pos = providerModule.findProperty(
1461 PEGASUS_PROPERTYNAME_MODULE_USERCONTEXT);
1462 if (pos != PEG_NOT_FOUND)
1463 {
1464 CIMValue userContextValue =
1465 providerModule.getProperty(pos).getValue();
1466 if (!userContextValue.isNull())
1467 {
1468 userContextValue.get(userContext);
1469 }
1470 }
1471
1472 if (userContext == 0)
1473 {
|
1474 ouyang.jian 1.15 // PASE has a default user context "QYCMCIMOM",
1475 // so we leave userContext unset here.
1476 #ifndef PEGASUS_OS_PASE
|
1477 kumpf 1.1 userContext = PEGASUS_DEFAULT_PROV_USERCTXT;
|
1478 ouyang.jian 1.15 #endif
|
1479 kumpf 1.1 }
1480
1481 String userName;
1482
1483 if (userContext == PG_PROVMODULE_USERCTXT_REQUESTOR)
1484 {
|
1485 kumpf 1.6 if (request->operationContext.contains(IdentityContainer::NAME))
|
1486 kumpf 1.1 {
1487 // User Name is in the OperationContext
1488 IdentityContainer ic = (IdentityContainer)
1489 request->operationContext.get(IdentityContainer::NAME);
1490 userName = ic.getUserName();
1491 }
1492 //else
1493 //{
1494 // If no IdentityContainer is present, default to the CIM
1495 // Server's user context
1496 //}
1497
1498 // If authentication is disabled, use the CIM Server's user context
1499 if (!userName.size())
1500 {
1501 userName = System::getEffectiveUserName();
1502 }
1503 }
1504 else if (userContext == PG_PROVMODULE_USERCTXT_DESIGNATED)
1505 {
1506 // Retrieve the provider module designated user property value
1507 kumpf 1.1 providerModule.getProperty(providerModule.findProperty(
1508 PEGASUS_PROPERTYNAME_MODULE_DESIGNATEDUSER)).getValue().
1509 get(userName);
1510 }
1511 else if (userContext == PG_PROVMODULE_USERCTXT_CIMSERVER)
1512 {
1513 userName = System::getEffectiveUserName();
1514 }
|
1515 ouyang.jian 1.15 #ifdef PEGASUS_OS_PASE // it might be unset user in PASE in this branch.
1516 else if (userContext == 0)
1517 {
1518 userName = "QYCMCIMOM";
1519 }
1520 #endif
|
1521 kumpf 1.1 else // Privileged User
1522 {
1523 PEGASUS_ASSERT(userContext == PG_PROVMODULE_USERCTXT_PRIVILEGED);
1524 userName = System::getPrivilegedUserName();
1525 }
1526
1527 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1528 "Module name = " + moduleName);
|
1529 marek 1.9 PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1530 "User context = %hd.", userContext));
|
1531 kumpf 1.1 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1532 "User name = " + userName);
1533
1534 ProviderAgentContainer* pa = 0;
|
1535 ouyang.jian 1.15 #ifdef PEGASUS_OS_PASE
1536 String userUpper = userName;
1537 userUpper.toUpper();
1538 String key = moduleName + ":" + userUpper;
1539 #else
|
1540 kumpf 1.1 String key = moduleName + ":" + userName;
|
1541 ouyang.jian 1.15 #endif
|
1542 kumpf 1.1
1543 AutoMutex lock(_providerAgentTableMutex);
1544 if (!_providerAgentTable.lookup(key, pa))
1545 {
1546 pa = new ProviderAgentContainer(
1547 moduleName, userName, userContext,
1548 _indicationCallback, _responseChunkCallback,
1549 _providerModuleFailCallback,
1550 _subscriptionInitComplete);
1551 _providerAgentTable.insert(key, pa);
1552 }
1553 return pa;
1554 }
1555
1556 Array<ProviderAgentContainer*> OOPProviderManagerRouter::_lookupProviderAgents(
1557 const String& moduleName)
1558 {
1559 Array<ProviderAgentContainer*> paArray;
1560
1561 AutoMutex lock(_providerAgentTableMutex);
1562 for (ProviderAgentTable::Iterator i = _providerAgentTable.start(); i; i++)
1563 kumpf 1.1 {
1564 if (i.value()->getModuleName() == moduleName)
1565 {
1566 paArray.append(i.value());
1567 }
1568 }
1569 return paArray;
1570 }
1571
1572 CIMResponseMessage* OOPProviderManagerRouter::_forwardRequestToAllAgents(
1573 CIMRequestMessage* request)
1574 {
1575 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1576 "OOPProviderManagerRouter::_forwardRequestToAllAgents");
1577
1578 // Get a list of the ProviderAgentContainers. We need our own array copy
1579 // because we cannot hold the _providerAgentTableMutex while calling
1580 // _ProviderAgentContainer::processMessage().
1581 Array<ProviderAgentContainer*> paContainerArray;
1582 {
1583 AutoMutex tableLock(_providerAgentTableMutex);
1584 kumpf 1.1 for (ProviderAgentTable::Iterator i = _providerAgentTable.start();
1585 i != 0; i++)
1586 {
1587 paContainerArray.append(i.value());
1588 }
1589 }
1590
1591 CIMException responseException;
1592
1593 // Forward the request to each of the initialized provider agents
1594 for (Uint32 j = 0; j < paContainerArray.size(); j++)
1595 {
1596 ProviderAgentContainer* pa = paContainerArray[j];
1597 if (pa->isInitialized())
1598 {
1599 // Note: The ProviderAgentContainer could become uninitialized
1600 // before _ProviderAgentContainer::processMessage() processes
1601 // this request. In this case, the Provider Agent process will
1602 // (unfortunately) be started to process this message.
1603 AutoPtr<CIMResponseMessage> response;
1604 response.reset(pa->processMessage(request));
1605 kumpf 1.1 if (response.get() != 0)
1606 {
1607 // If the operation failed, save the exception data
1608 if ((response->cimException.getCode() != CIM_ERR_SUCCESS) &&
1609 (responseException.getCode() == CIM_ERR_SUCCESS))
1610 {
1611 responseException = response->cimException;
1612 }
1613 }
1614 }
1615 }
1616
1617 CIMResponseMessage* response = request->buildResponse();
1618 response->cimException = responseException;
1619
1620 PEG_METHOD_EXIT();
1621 return response;
1622 }
1623
1624 void OOPProviderManagerRouter::unloadIdleProviders()
1625 {
1626 kumpf 1.1 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1627 "OOPProviderManagerRouter::unloadIdleProviders");
1628
|
1629 kumpf 1.7 // Get a list of the ProviderAgentContainers. We need our own array copy
1630 // because we cannot hold the _providerAgentTableMutex while calling
1631 // ProviderAgentContainer::unloadIdleProviders().
1632 Array<ProviderAgentContainer*> paContainerArray;
1633 {
1634 AutoMutex tableLock(_providerAgentTableMutex);
1635 for (ProviderAgentTable::Iterator i = _providerAgentTable.start();
1636 i != 0; i++)
1637 {
1638 paContainerArray.append(i.value());
1639 }
1640 }
1641
|
1642 kumpf 1.1 // Iterate through the _providerAgentTable unloading idle providers
|
1643 kumpf 1.7 for (Uint32 j = 0; j < paContainerArray.size(); j++)
|
1644 kumpf 1.1 {
|
1645 kumpf 1.7 paContainerArray[j]->unloadIdleProviders();
|
1646 kumpf 1.1 }
1647
1648 PEG_METHOD_EXIT();
1649 }
1650
1651 PEGASUS_NAMESPACE_END
|