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