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