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