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.20 PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL1,
|
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 marek 1.19 PEG_TRACE_CSTRING(TRC_PROVIDERMANAGER, Tracer::LEVEL1,
|
570 kumpf 1.1 "Could not allocate thread to process responses from the "
571 "provider agent.");
572
573 throw Exception(MessageLoaderParms(
574 "ProviderManager.OOPProviderManagerRouter."
575 "CIMPROVAGT_THREAD_ALLOCATION_FAILED",
576 "Failed to allocate thread for cimprovagt \"$0\".",
577 _moduleName));
578 }
579 }
580 }
581 catch (...)
582 {
583 // Closing the connection causes the agent process to exit
584 _pipeToAgent.reset();
585 _pipeFromAgent.reset();
586
587 #if defined(PEGASUS_HAS_SIGNALS)
588 if (_isInitialized)
589 {
590 // Harvest the status of the agent process to prevent a zombie
|
591 kumpf 1.10 int status = Executor::reapProviderAgent(_pid);
|
592 kumpf 1.4
593 if (status == -1)
594 {
|
595 marek 1.20 PEG_TRACE((TRC_DISCARDED_DATA, Tracer::LEVEL1,
|
596 kumpf 1.4 "ProviderAgentContainer::_initialize(): "
|
597 kumpf 1.10 "Executor::reapProviderAgent() failed"));
|
598 kumpf 1.4 }
|
599 kumpf 1.1 }
600 #endif
601
602 _isInitialized = false;
603
604 {
605 AutoMutex lock(_numProviderProcessesMutex);
606 _numProviderProcesses--;
607 }
608
609 PEG_METHOD_EXIT();
610 throw;
611 }
612
613 PEG_METHOD_EXIT();
614 }
615
616 Boolean ProviderAgentContainer::isInitialized()
617 {
618 AutoMutex lock(_agentMutex);
619 return _isInitialized;
620 kumpf 1.1 }
621
622 void ProviderAgentContainer::_uninitialize(Boolean cleanShutdown)
623 {
624 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
625 "ProviderAgentContainer::_uninitialize");
626
|
627 kumpf 1.7 #if defined(PEGASUS_HAS_SIGNALS)
|
628 kumpf 1.14 pid_t pid = 0;
|
629 kumpf 1.7 #endif
|
630 kumpf 1.1
631 try
632 {
|
633 kumpf 1.7 AutoMutex lock(_agentMutex);
634
635 PEGASUS_ASSERT(_isInitialized);
636
|
637 kumpf 1.1 // Close the connection with the Provider Agent
638 _pipeFromAgent.reset();
639 _pipeToAgent.reset();
640
641 _providerModuleCache = CIMInstance();
642
643 {
|
644 kumpf 1.21 AutoMutex lock2(_numProviderProcessesMutex);
|
645 kumpf 1.1 _numProviderProcesses--;
646 }
647
|
648 kumpf 1.7 _isInitialized = false;
649
|
650 kumpf 1.1 #if defined(PEGASUS_HAS_SIGNALS)
|
651 kumpf 1.7 // Save the _pid so we can use it after we've released the _agentMutex
652 pid = _pid;
|
653 kumpf 1.1 #endif
654
655 //
656 // Complete with null responses all outstanding requests on this
657 // connection
658 //
659 {
660 AutoMutex tableLock(_outstandingRequestTableMutex);
661
662 CIMResponseMessage* response =
663 cleanShutdown ? _REQUEST_NOT_PROCESSED : 0;
664
665 for (OutstandingRequestTable::Iterator i =
666 _outstandingRequestTable.start();
667 i != 0; i++)
668 {
|
669 thilo.boehm 1.22 PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL4,
670 "Completing messageId \"%s\" with a null response.",
671 (const char*)i.key().getCString()));
|
672 kumpf 1.1 i.value()->responseMessage = response;
673 i.value()->responseReady->signal();
674 }
675
676 _outstandingRequestTable.clear();
|
677 kumpf 1.3 }
|
678 kumpf 1.1
|
679 kumpf 1.3 //
680 // If not a clean shutdown, call the provider module failure callback
681 //
682 if (!cleanShutdown)
683 {
|
684 kumpf 1.1 //
|
685 kumpf 1.3 // Call the provider module failure callback to communicate
686 // the failure to the Provider Manager Service. The Provider
687 // Manager Service will inform the Indication Service.
|
688 kumpf 1.1 //
|
689 kumpf 1.3 _providerModuleFailCallback(_moduleName, _userName, _userContext);
|
690 kumpf 1.1 }
691 }
692 catch (...)
693 {
694 // We're uninitializing, so do not propagate the exception
|
695 marek 1.9 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
696 kumpf 1.1 "Ignoring _uninitialize() exception.");
697 }
698
|
699 kumpf 1.7 #if defined(PEGASUS_HAS_SIGNALS)
700 // Harvest the status of the agent process to prevent a zombie. Do not
701 // hold the _agentMutex during this operation.
702
|
703 kumpf 1.14 if ((pid != 0) && (Executor::reapProviderAgent(pid) == -1))
|
704 kumpf 1.7 {
|
705 marek 1.9 PEG_TRACE((TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
706 kumpf 1.7 "ProviderAgentContainer::_uninitialize(): "
|
707 kumpf 1.10 "Executor::reapProviderAgent() failed."));
|
708 kumpf 1.7 }
709 #endif
710
|
711 kumpf 1.1 PEG_METHOD_EXIT();
712 }
713
714 String ProviderAgentContainer::getModuleName() const
715 {
716 return _moduleName;
717 }
718
719 CIMResponseMessage* ProviderAgentContainer::processMessage(
720 CIMRequestMessage* request)
721 {
722 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
723 "ProviderAgentContainer::processMessage");
724
725 CIMResponseMessage* response;
726
727 do
728 {
729 response = _processMessage(request);
730
731 if (response == _REQUEST_NOT_PROCESSED)
732 kumpf 1.1 {
733 // Check for request message types that should not be retried.
734 if ((request->getType() ==
735 CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE) ||
736 (request->getType() ==
737 CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE) ||
738 (request->getType() ==
739 CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE) ||
740 (request->getType() ==
741 CIM_DELETE_SUBSCRIPTION_REQUEST_MESSAGE))
742 {
743 response = request->buildResponse();
744 break;
745 }
746 else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
747 {
748 CIMDisableModuleResponseMessage* dmResponse =
749 dynamic_cast<CIMDisableModuleResponseMessage*>(response);
750 PEGASUS_ASSERT(dmResponse != 0);
751
752 Array<Uint16> operationalStatus;
753 kumpf 1.1 operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_STOPPED);
754 dmResponse->operationalStatus = operationalStatus;
755 break;
756 }
757 }
758 } while (response == _REQUEST_NOT_PROCESSED);
759
|
760 kumpf 1.2 if (request->getType() == CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE)
761 {
762 _subscriptionInitComplete = true;
763 }
764
|
765 kumpf 1.1 PEG_METHOD_EXIT();
766 return response;
767 }
768
769 CIMResponseMessage* ProviderAgentContainer::_processMessage(
770 CIMRequestMessage* request)
771 {
772 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
773 "ProviderAgentContainer::_processMessage");
774
775 CIMResponseMessage* response;
776 String originalMessageId = request->messageId;
777
778 // These three variables are used for the provider module optimization.
779 // See the _providerModuleCache member description for more information.
780 AutoPtr<ProviderIdContainer> origProviderId;
781 Boolean doProviderModuleOptimization = false;
782 Boolean updateProviderModuleCache = false;
783
784 try
785 {
786 kumpf 1.1 // The messageId attribute is used to correlate response messages
787 // from the Provider Agent with request messages, so it is imperative
788 // that the ID is unique for each request. The incoming ID cannot be
789 // trusted to be unique, so we substitute a unique one. The memory
790 // address of the request is used as the source of a unique piece of
791 // data. (The message ID is only required to be unique while the
792 // request is outstanding.)
793 char messagePtrString[20];
794 sprintf(messagePtrString, "%p", request);
795 String uniqueMessageId = messagePtrString;
796
797 //
798 // Set up the OutstandingRequestEntry for this request
799 //
800 Semaphore waitSemaphore(0);
801 OutstandingRequestEntry outstandingRequestEntry(
802 originalMessageId, request, response, &waitSemaphore);
803
804 //
805 // Lock the Provider Agent Container while initializing the
806 // agent and writing the request to the connection
807 kumpf 1.1 //
808 {
809 AutoMutex lock(_agentMutex);
810
811 //
812 // Initialize the Provider Agent, if necessary
813 //
814 if (!_isInitialized)
815 {
816 _initialize();
817 }
818
819 //
820 // Add an entry to the OutstandingRequestTable for this request
821 //
822 {
823 AutoMutex tableLock(_outstandingRequestTableMutex);
824
825 _outstandingRequestTable.insert(
826 uniqueMessageId, &outstandingRequestEntry);
827 }
828 kumpf 1.1
829 // Get the provider module from the ProviderIdContainer to see if
830 // we can optimize out the transmission of this instance to the
831 // Provider Agent. (See the _providerModuleCache description.)
|
832 kumpf 1.6 if (request->operationContext.contains(ProviderIdContainer::NAME))
|
833 kumpf 1.1 {
834 ProviderIdContainer pidc = request->operationContext.get(
835 ProviderIdContainer::NAME);
836 origProviderId.reset(new ProviderIdContainer(
837 pidc.getModule(), pidc.getProvider(),
838 pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
839 if (_providerModuleCache.isUninitialized() ||
840 (!pidc.getModule().identical(_providerModuleCache)))
841 {
842 // We haven't sent this provider module instance to the
843 // Provider Agent yet. Update our cache after we send it.
844 updateProviderModuleCache = true;
845 }
846 else
847 {
848 // Replace the provider module in the ProviderIdContainer
849 // with an uninitialized instance. We'll need to put the
850 // original one back after the message is sent.
851 request->operationContext.set(ProviderIdContainer(
852 CIMInstance(), pidc.getProvider(),
853 pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
854 kumpf 1.1 doProviderModuleOptimization = true;
855 }
856 }
857
858 //
859 // Write the message to the pipe
860 //
861 try
862 {
|
863 thilo.boehm 1.22 PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL3,
864 "Sending request to agent with messageId %s",
865 (const char*)uniqueMessageId.getCString()));
|
866 kumpf 1.1
867 request->messageId = uniqueMessageId;
868 AnonymousPipe::Status writeStatus =
869 _pipeToAgent->writeMessage(request);
870 request->messageId = originalMessageId;
871
872 if (doProviderModuleOptimization)
873 {
874 request->operationContext.set(*origProviderId.get());
875 }
876
877 if (writeStatus != AnonymousPipe::STATUS_SUCCESS)
878 {
|
879 marek 1.20 PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL1,
|
880 kumpf 1.1 "Failed to write message to pipe. writeStatus = %d.",
|
881 marek 1.9 writeStatus));
|
882 kumpf 1.1
883 request->messageId = originalMessageId;
884
885 if (doProviderModuleOptimization)
886 {
887 request->operationContext.set(*origProviderId.get());
888 }
889
890 // Remove this OutstandingRequestTable entry
891 {
892 AutoMutex tableLock(_outstandingRequestTableMutex);
893 Boolean removed =
894 _outstandingRequestTable.remove(uniqueMessageId);
895 PEGASUS_ASSERT(removed);
896 }
897
898 // A response value of _REQUEST_NOT_PROCESSED indicates
899 // that the request was not processed by the provider
900 // agent, so it can be retried safely.
901 PEG_METHOD_EXIT();
902 return _REQUEST_NOT_PROCESSED;
903 kumpf 1.1 }
904
905 if (updateProviderModuleCache)
906 {
907 _providerModuleCache = origProviderId->getModule();
908 }
909 }
910 catch (...)
911 {
912 request->messageId = originalMessageId;
913
914 if (doProviderModuleOptimization)
915 {
916 request->operationContext.set(*origProviderId.get());
917 }
918
|
919 marek 1.20 PEG_TRACE_CSTRING(TRC_PROVIDERMANAGER, Tracer::LEVEL1,
|
920 kumpf 1.1 "Failed to write message to pipe.");
921 // Remove the OutstandingRequestTable entry for this request
922 {
923 AutoMutex tableLock(_outstandingRequestTableMutex);
924 Boolean removed =
925 _outstandingRequestTable.remove(uniqueMessageId);
926 PEGASUS_ASSERT(removed);
927 }
928 PEG_METHOD_EXIT();
929 throw;
930 }
931 }
932
933 //
934 // Wait for the response
935 //
936 try
937 {
938 // Must not hold _agentMutex while waiting for the response
939 waitSemaphore.wait();
940 }
941 kumpf 1.1 catch (...)
942 {
943 // Remove the OutstandingRequestTable entry for this request
944 {
945 AutoMutex tableLock(_outstandingRequestTableMutex);
946 Boolean removed =
947 _outstandingRequestTable.remove(uniqueMessageId);
948 PEGASUS_ASSERT(removed);
949 }
950 PEG_METHOD_EXIT();
951 throw;
952 }
953
954 // A response value of _REQUEST_NOT_PROCESSED indicates that the
955 // provider agent process was terminating when the request was sent.
|
956 kumpf 1.6 // The request was not processed by the provider agent, so it can be
|
957 kumpf 1.1 // retried safely.
958 if (response == _REQUEST_NOT_PROCESSED)
959 {
960 PEG_METHOD_EXIT();
961 return response;
962 }
963
964 // A null response is returned when an agent connection is closed
965 // while requests remain outstanding.
966 if (response == 0)
967 {
968 response = request->buildResponse();
969 response->cimException = PEGASUS_CIM_EXCEPTION(
970 CIM_ERR_FAILED,
971 MessageLoaderParms(
972 "ProviderManager.OOPProviderManagerRouter."
973 "CIMPROVAGT_CONNECTION_LOST",
974 "Lost connection with cimprovagt \"$0\".",
975 _moduleName));
976 }
977 }
978 kumpf 1.1 catch (CIMException& e)
979 {
|
980 thilo.boehm 1.22 PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL1,
981 "Caught CIMException: %s",
982 (const char*)e.getMessage().getCString()));
|
983 kumpf 1.1 response = request->buildResponse();
984 response->cimException = e;
985 }
986 catch (Exception& e)
987 {
|
988 thilo.boehm 1.22 PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL1,
989 "Caught Exception: %s",
990 (const char*)e.getMessage().getCString()));
|
991 kumpf 1.1 response = request->buildResponse();
992 response->cimException = PEGASUS_CIM_EXCEPTION(
993 CIM_ERR_FAILED, e.getMessage());
994 }
995 catch (...)
996 {
|
997 marek 1.9 PEG_TRACE_CSTRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
|
998 kumpf 1.1 "Caught unknown exception");
999 response = request->buildResponse();
1000 response->cimException = PEGASUS_CIM_EXCEPTION(
1001 CIM_ERR_FAILED, String::EMPTY);
1002 }
1003
1004 response->messageId = originalMessageId;
|
1005 kumpf 1.17 response->syncAttributes(request);
|
1006 kumpf 1.1
1007 PEG_METHOD_EXIT();
1008 return response;
1009 }
1010
1011 void ProviderAgentContainer::unloadIdleProviders()
1012 {
1013 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1014 "ProviderAgentContainer::unloadIdleProviders");
1015
1016 AutoMutex lock(_agentMutex);
1017 if (_isInitialized)
1018 {
1019 // Send a "wake up" message to the Provider Agent.
1020 // Don't bother checking whether the operation is successful.
1021 Uint32 messageLength = 0;
1022 _pipeToAgent->writeBuffer((const char*)&messageLength, sizeof(Uint32));
1023 }
1024
1025 PEG_METHOD_EXIT();
1026 }
1027 kumpf 1.1
1028 void ProviderAgentContainer::_processResponses()
1029 {
1030 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1031 "ProviderAgentContainer::_processResponses");
1032
1033 //
1034 // Process responses until the pipe is closed
1035 //
1036 while (1)
1037 {
1038 try
1039 {
1040 CIMMessage* message;
1041
1042 //
1043 // Read a response from the Provider Agent
1044 //
1045 AnonymousPipe::Status readStatus =
1046 _pipeFromAgent->readMessage(message);
1047
1048 kumpf 1.1 // Ignore interrupts
1049 if (readStatus == AnonymousPipe::STATUS_INTERRUPT)
1050 {
1051 continue;
1052 }
1053
1054 // Handle an error the same way as a closed connection
1055 if ((readStatus == AnonymousPipe::STATUS_ERROR) ||
1056 (readStatus == AnonymousPipe::STATUS_CLOSED))
1057 {
1058 _uninitialize(false);
1059 return;
1060 }
1061
1062 // A null message indicates that the provider agent process has
1063 // finished its processing and is ready to exit.
1064 if (message == 0)
1065 {
1066 _uninitialize(true);
1067 return;
1068 }
1069 kumpf 1.1
1070 if (message->getType() == CIM_PROCESS_INDICATION_REQUEST_MESSAGE)
1071 {
|
1072 kumpf 1.10 // Process an indication message
1073
|
1074 kumpf 1.1 _indicationCallback(
1075 reinterpret_cast<CIMProcessIndicationRequestMessage*>(
1076 message));
1077 }
1078 else if (!message->isComplete())
1079 {
|
1080 kumpf 1.10 // Process an incomplete response chunk
1081
|
1082 kumpf 1.1 CIMResponseMessage* response;
1083 response = dynamic_cast<CIMResponseMessage*>(message);
1084 PEGASUS_ASSERT(response != 0);
1085
1086 // Get the OutstandingRequestEntry for this response chunk
1087 OutstandingRequestEntry* _outstandingRequestEntry = 0;
1088 {
1089 AutoMutex tableLock(_outstandingRequestTableMutex);
1090 Boolean foundEntry = _outstandingRequestTable.lookup(
1091 response->messageId, _outstandingRequestEntry);
1092 PEGASUS_ASSERT(foundEntry);
1093 }
1094
1095 // Put the original message ID into the response
1096 response->messageId =
1097 _outstandingRequestEntry->originalMessageId;
1098
1099 // Call the response chunk callback to process the chunk
1100 _responseChunkCallback(
1101 _outstandingRequestEntry->requestMessage, response);
1102 }
1103 kumpf 1.1 else
1104 {
|
1105 kumpf 1.10 // Process a completed response
1106
|
1107 kumpf 1.1 CIMResponseMessage* response;
1108 response = dynamic_cast<CIMResponseMessage*>(message);
1109 PEGASUS_ASSERT(response != 0);
1110
1111 // Give the response to the waiting OutstandingRequestEntry
1112 OutstandingRequestEntry* _outstandingRequestEntry = 0;
1113 {
1114 AutoMutex tableLock(_outstandingRequestTableMutex);
1115 Boolean foundEntry = _outstandingRequestTable.lookup(
1116 response->messageId, _outstandingRequestEntry);
1117 PEGASUS_ASSERT(foundEntry);
1118
1119 // Remove the completed request from the table
1120 Boolean removed =
1121 _outstandingRequestTable.remove(response->messageId);
1122 PEGASUS_ASSERT(removed);
1123 }
1124
1125 _outstandingRequestEntry->responseMessage = response;
1126 _outstandingRequestEntry->responseReady->signal();
1127 }
1128 kumpf 1.1 }
1129 catch (Exception& e)
1130 {
|
1131 thilo.boehm 1.22 PEG_TRACE((TRC_DISCARDED_DATA, Tracer::LEVEL2,
1132 "Ignoring exception: %s",
1133 (const char*)e.getMessage().getCString()));
|
1134 kumpf 1.1 }
1135 catch (...)
1136 {
|
1137 marek 1.9 PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
|
1138 kumpf 1.1 "Ignoring exception");
1139 }
1140 }
1141
1142 }
1143
1144 ThreadReturnType PEGASUS_THREAD_CDECL
1145 ProviderAgentContainer::_responseProcessor(void* arg)
1146 {
1147 ProviderAgentContainer* pa =
1148 reinterpret_cast<ProviderAgentContainer*>(arg);
1149
1150 pa->_processResponses();
1151
|
1152 kumpf 1.6 return ThreadReturnType(0);
|
1153 kumpf 1.1 }
1154
1155 /////////////////////////////////////////////////////////////////////////////
1156 // OOPProviderManagerRouter
1157 /////////////////////////////////////////////////////////////////////////////
1158
1159 OOPProviderManagerRouter::OOPProviderManagerRouter(
1160 PEGASUS_INDICATION_CALLBACK_T indicationCallback,
1161 PEGASUS_RESPONSE_CHUNK_CALLBACK_T responseChunkCallback,
1162 PEGASUS_PROVIDERMODULEFAIL_CALLBACK_T providerModuleFailCallback)
1163 {
1164 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1165 "OOPProviderManagerRouter::OOPProviderManagerRouter");
1166
1167 _indicationCallback = indicationCallback;
1168 _responseChunkCallback = responseChunkCallback;
1169 _providerModuleFailCallback = providerModuleFailCallback;
1170 _subscriptionInitComplete = false;
1171
1172 PEG_METHOD_EXIT();
1173 }
1174 kumpf 1.1
1175 OOPProviderManagerRouter::~OOPProviderManagerRouter()
1176 {
1177 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1178 "OOPProviderManagerRouter::~OOPProviderManagerRouter");
1179
1180 try
1181 {
1182 // Clean up the ProviderAgentContainers
1183 AutoMutex lock(_providerAgentTableMutex);
1184 ProviderAgentTable::Iterator i = _providerAgentTable.start();
|
1185 kumpf 1.6 for (; i != 0; i++)
|
1186 kumpf 1.1 {
1187 delete i.value();
1188 }
1189 }
1190 catch (...) {}
1191
1192 PEG_METHOD_EXIT();
1193 }
1194
1195 Message* OOPProviderManagerRouter::processMessage(Message* message)
1196 {
1197 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1198 "OOPProviderManagerRouter::processMessage");
1199
1200 CIMRequestMessage* request = dynamic_cast<CIMRequestMessage *>(message);
1201 PEGASUS_ASSERT(request != 0);
1202
1203 AutoPtr<CIMResponseMessage> response;
1204
1205 //
1206 // Get the provider information from the request
1207 kumpf 1.1 //
1208 CIMInstance providerModule;
1209
1210 if ((dynamic_cast<CIMOperationRequestMessage*>(request) != 0) ||
1211 (dynamic_cast<CIMIndicationRequestMessage*>(request) != 0) ||
1212 (request->getType() == CIM_EXPORT_INDICATION_REQUEST_MESSAGE))
1213 {
1214 // Provider information is in the OperationContext
1215 ProviderIdContainer pidc = (ProviderIdContainer)
1216 request->operationContext.get(ProviderIdContainer::NAME);
1217 providerModule = pidc.getModule();
1218 }
1219 else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
1220 {
1221 CIMEnableModuleRequestMessage* emReq =
1222 dynamic_cast<CIMEnableModuleRequestMessage*>(request);
1223 providerModule = emReq->providerModule;
1224 }
1225 else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
1226 {
1227 CIMDisableModuleRequestMessage* dmReq =
1228 kumpf 1.1 dynamic_cast<CIMDisableModuleRequestMessage*>(request);
1229 providerModule = dmReq->providerModule;
1230 }
1231 else if ((request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE) ||
1232 (request->getType() ==
1233 CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE) ||
1234 (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE))
1235 {
1236 // This operation is not provider-specific
1237 }
1238 else
1239 {
1240 // Unrecognized message type. This should never happen.
1241 PEGASUS_ASSERT(0);
1242 response.reset(request->buildResponse());
1243 response->cimException = PEGASUS_CIM_EXCEPTION(
1244 CIM_ERR_FAILED, "Unrecognized message type.");
1245 PEG_METHOD_EXIT();
1246 return response.release();
1247 }
1248
1249 kumpf 1.1 //
1250 // Process the request message
1251 //
1252 if (request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE)
1253 {
1254 // Forward the CIMStopAllProvidersRequest to all providers
1255 response.reset(_forwardRequestToAllAgents(request));
1256
1257 // Note: Do not uninitialize the ProviderAgentContainers here.
1258 // Just let the selecting thread notice when the agent connections
1259 // are closed.
1260 }
|
1261 kumpf 1.6 else if (request->getType () ==
|
1262 kumpf 1.1 CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE)
1263 {
1264 _subscriptionInitComplete = true;
1265
1266 //
|
1267 kumpf 1.6 // Forward the CIMSubscriptionInitCompleteRequestMessage to
|
1268 kumpf 1.1 // all providers
1269 //
1270 response.reset (_forwardRequestToAllAgents (request));
1271 }
1272 else if (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE)
1273 {
1274 CIMNotifyConfigChangeRequestMessage* notifyRequest =
1275 dynamic_cast<CIMNotifyConfigChangeRequestMessage*>(request);
1276 PEGASUS_ASSERT(notifyRequest != 0);
1277
1278 if (notifyRequest->currentValueModified)
1279 {
1280 // Forward the CIMNotifyConfigChangeRequestMessage to all providers
1281 response.reset(_forwardRequestToAllAgents(request));
1282 }
1283 else
1284 {
1285 // No need to notify provider agents about changes to planned value
1286 response.reset(request->buildResponse());
1287 }
1288 }
1289 kumpf 1.1 else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
1290 {
1291 // Fan out the request to all Provider Agent processes for this module
1292
1293 // Retrieve the provider module name
1294 String moduleName;
1295 CIMValue nameValue = providerModule.getProperty(
|
1296 marek 1.23 providerModule.findProperty(PEGASUS_PROPERTYNAME_NAME)).getValue();
|
1297 kumpf 1.1 nameValue.get(moduleName);
1298
1299 // Look up the Provider Agents for this module
1300 Array<ProviderAgentContainer*> paArray =
1301 _lookupProviderAgents(moduleName);
1302
1303 for (Uint32 i=0; i<paArray.size(); i++)
1304 {
1305 //
1306 // Do not start up an agent process just to disable the module
1307 //
1308 if (paArray[i]->isInitialized())
1309 {
1310 //
1311 // Forward the request to the provider agent
1312 //
1313 response.reset(paArray[i]->processMessage(request));
1314
1315 // Note: Do not uninitialize the ProviderAgentContainer here
1316 // when a disable module operation is successful. Just let the
1317 // selecting thread notice when the agent connection is closed.
1318 kumpf 1.1
1319 // Determine the success of the disable module operation
1320 CIMDisableModuleResponseMessage* dmResponse =
1321 dynamic_cast<CIMDisableModuleResponseMessage*>(
1322 response.get());
1323 PEGASUS_ASSERT(dmResponse != 0);
1324
1325 Boolean isStopped = false;
|
1326 kumpf 1.21 for (Uint32 j=0; j < dmResponse->operationalStatus.size(); j++)
|
1327 kumpf 1.1 {
|
1328 kumpf 1.21 if (dmResponse->operationalStatus[j] ==
|
1329 kumpf 1.1 CIM_MSE_OPSTATUS_VALUE_STOPPED)
1330 {
1331 isStopped = true;
1332 break;
1333 }
1334 }
1335
1336 // If the operation is unsuccessful, stop and return the error
1337 if ((dmResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
1338 !isStopped)
1339 {
1340 break;
1341 }
1342 }
1343 }
1344
1345 // Use a default response if no Provider Agents were called
1346 if (!response.get())
1347 {
1348 response.reset(request->buildResponse());
1349
1350 kumpf 1.1 CIMDisableModuleResponseMessage* dmResponse =
1351 dynamic_cast<CIMDisableModuleResponseMessage*>(response.get());
1352 PEGASUS_ASSERT(dmResponse != 0);
1353
1354 Array<Uint16> operationalStatus;
1355 operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_STOPPED);
1356 dmResponse->operationalStatus = operationalStatus;
1357 }
1358 }
1359 else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
1360 {
1361 // Fan out the request to all Provider Agent processes for this module
1362
1363 // Retrieve the provider module name
1364 String moduleName;
1365 CIMValue nameValue = providerModule.getProperty(
|
1366 marek 1.23 providerModule.findProperty(PEGASUS_PROPERTYNAME_NAME)).getValue();
|
1367 kumpf 1.1 nameValue.get(moduleName);
1368
1369 // Look up the Provider Agents for this module
1370 Array<ProviderAgentContainer*> paArray =
1371 _lookupProviderAgents(moduleName);
1372
1373 for (Uint32 i=0; i<paArray.size(); i++)
1374 {
1375 //
1376 // Do not start up an agent process just to enable the module
1377 //
1378 if (paArray[i]->isInitialized())
1379 {
1380 //
1381 // Forward the request to the provider agent
1382 //
1383 response.reset(paArray[i]->processMessage(request));
1384
1385 // Determine the success of the enable module operation
1386 CIMEnableModuleResponseMessage* emResponse =
1387 dynamic_cast<CIMEnableModuleResponseMessage*>(
1388 kumpf 1.1 response.get());
1389 PEGASUS_ASSERT(emResponse != 0);
1390
1391 Boolean isOk = false;
|
1392 kumpf 1.21 for (Uint32 j=0; j < emResponse->operationalStatus.size(); j++)
|
1393 kumpf 1.1 {
|
1394 kumpf 1.21 if (emResponse->operationalStatus[j] ==
|
1395 kumpf 1.1 CIM_MSE_OPSTATUS_VALUE_OK)
1396 {
1397 isOk = true;
1398 break;
1399 }
1400 }
1401
1402 // If the operation is unsuccessful, stop and return the error
1403 if ((emResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
1404 !isOk)
1405 {
1406 break;
1407 }
1408 }
1409 }
1410
1411 // Use a default response if no Provider Agents were called
1412 if (!response.get())
1413 {
1414 response.reset(request->buildResponse());
1415
1416 kumpf 1.1 CIMEnableModuleResponseMessage* emResponse =
1417 dynamic_cast<CIMEnableModuleResponseMessage*>(response.get());
1418 PEGASUS_ASSERT(emResponse != 0);
1419
1420 Array<Uint16> operationalStatus;
1421 operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_OK);
1422 emResponse->operationalStatus = operationalStatus;
1423 }
1424 }
1425 else
1426 {
1427 //
1428 // Look up the Provider Agent for this module instance and requesting
1429 // user
1430 //
1431 ProviderAgentContainer* pa = _lookupProviderAgent(providerModule,
1432 request);
1433 PEGASUS_ASSERT(pa != 0);
1434
1435 //
1436 // Forward the request to the provider agent
1437 kumpf 1.1 //
1438 response.reset(pa->processMessage(request));
1439 }
1440
1441 PEG_METHOD_EXIT();
1442 return response.release();
1443 }
1444
1445 ProviderAgentContainer* OOPProviderManagerRouter::_lookupProviderAgent(
1446 const CIMInstance& providerModule,
1447 CIMRequestMessage* request)
1448 {
1449 // Retrieve the provider module name
1450 String moduleName;
1451 CIMValue nameValue = providerModule.getProperty(
|
1452 marek 1.23 providerModule.findProperty(PEGASUS_PROPERTYNAME_NAME)).getValue();
|
1453 kumpf 1.1 nameValue.get(moduleName);
1454
1455 // Retrieve the provider user context configuration
1456 Uint16 userContext = 0;
1457 Uint32 pos = providerModule.findProperty(
1458 PEGASUS_PROPERTYNAME_MODULE_USERCONTEXT);
1459 if (pos != PEG_NOT_FOUND)
1460 {
1461 CIMValue userContextValue =
1462 providerModule.getProperty(pos).getValue();
1463 if (!userContextValue.isNull())
1464 {
1465 userContextValue.get(userContext);
1466 }
1467 }
1468
1469 if (userContext == 0)
1470 {
|
1471 ouyang.jian 1.15 // PASE has a default user context "QYCMCIMOM",
1472 // so we leave userContext unset here.
1473 #ifndef PEGASUS_OS_PASE
|
1474 kumpf 1.1 userContext = PEGASUS_DEFAULT_PROV_USERCTXT;
|
1475 ouyang.jian 1.15 #endif
|
1476 kumpf 1.1 }
1477
1478 String userName;
1479
1480 if (userContext == PG_PROVMODULE_USERCTXT_REQUESTOR)
1481 {
|
1482 kumpf 1.6 if (request->operationContext.contains(IdentityContainer::NAME))
|
1483 kumpf 1.1 {
1484 // User Name is in the OperationContext
1485 IdentityContainer ic = (IdentityContainer)
1486 request->operationContext.get(IdentityContainer::NAME);
1487 userName = ic.getUserName();
1488 }
1489 //else
1490 //{
1491 // If no IdentityContainer is present, default to the CIM
1492 // Server's user context
1493 //}
1494
1495 // If authentication is disabled, use the CIM Server's user context
1496 if (!userName.size())
1497 {
1498 userName = System::getEffectiveUserName();
1499 }
1500 }
1501 else if (userContext == PG_PROVMODULE_USERCTXT_DESIGNATED)
1502 {
1503 // Retrieve the provider module designated user property value
1504 kumpf 1.1 providerModule.getProperty(providerModule.findProperty(
1505 PEGASUS_PROPERTYNAME_MODULE_DESIGNATEDUSER)).getValue().
1506 get(userName);
1507 }
1508 else if (userContext == PG_PROVMODULE_USERCTXT_CIMSERVER)
1509 {
1510 userName = System::getEffectiveUserName();
1511 }
|
1512 ouyang.jian 1.15 #ifdef PEGASUS_OS_PASE // it might be unset user in PASE in this branch.
1513 else if (userContext == 0)
1514 {
1515 userName = "QYCMCIMOM";
1516 }
1517 #endif
|
1518 kumpf 1.1 else // Privileged User
1519 {
1520 PEGASUS_ASSERT(userContext == PG_PROVMODULE_USERCTXT_PRIVILEGED);
1521 userName = System::getPrivilegedUserName();
1522 }
1523
|
1524 marek 1.20 PEG_TRACE((
1525 TRC_PROVIDERMANAGER,
1526 Tracer::LEVEL4,
1527 "Module name = %s, User context = %hd, User name = %s",
1528 (const char*) moduleName.getCString(),
1529 userContext,
1530 (const char*) userName.getCString()));
1531
|
1532 kumpf 1.1
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
|