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