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 kumpf 1.21 //
339 // Serialize the starting of agent processes. If two agent processes are
340 // started at the same time, they may get copies of each other's pipe
341 // descriptors. If this happens, the cimserver will not get a pipe read
342 // error when one of the agent processes exits, because the pipe will
343 // still be writable by the other process. This locking control needs to
344 // cover the period from where the pipes are created to where the agent
345 // ends of the pipes are closed by the cimserver.
346 //
347 static Mutex agentStartupMutex;
348 AutoMutex lock(agentStartupMutex);
349
|
350 kumpf 1.1 AutoPtr<AnonymousPipe> pipeFromAgent(new AnonymousPipe());
351 AutoPtr<AnonymousPipe> pipeToAgent(new AnonymousPipe());
352
353 //
354 // Start a cimprovagt process for this provider module
355 //
356
357 #if defined (PEGASUS_OS_TYPE_WINDOWS)
358 //
359 // Set up members of the PROCESS_INFORMATION structure
360 //
361 PROCESS_INFORMATION piProcInfo;
362 ZeroMemory (&piProcInfo, sizeof (PROCESS_INFORMATION));
363
364 //
365 // Set up members of the STARTUPINFO structure
366 //
367 STARTUPINFO siStartInfo;
368 ZeroMemory (&siStartInfo, sizeof (STARTUPINFO));
369 siStartInfo.cb = sizeof (STARTUPINFO);
370
371 kumpf 1.1 //
372 // Generate the command line
373 //
374 char cmdLine[2048];
375 char readHandle[32];
376 char writeHandle[32];
377 pipeToAgent->exportReadHandle(readHandle);
378 pipeFromAgent->exportWriteHandle(writeHandle);
379
380 sprintf(cmdLine, "\"%s\" %s %s \"%s\"",
381 (const char*)ConfigManager::getHomedPath(
382 PEGASUS_PROVIDER_AGENT_PROC_NAME).getCString(),
383 readHandle, writeHandle, (const char*)_moduleName.getCString());
384
385 //
386 // Create the child process
387 //
388 if (!CreateProcess (
389 NULL, //
390 cmdLine, // command line
391 NULL, // process security attributes
392 kumpf 1.1 NULL, // primary thread security attributes
393 TRUE, // handles are inherited
394 0, // creation flags
395 NULL, // use parent's environment
396 NULL, // use parent's current directory
397 &siStartInfo, // STARTUPINFO
398 &piProcInfo)) // PROCESS_INFORMATION
399 {
400 Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
401 "CreateProcess() failed. errno = %d.", GetLastError());
402 PEG_METHOD_EXIT();
403 throw Exception(MessageLoaderParms(
404 "ProviderManager.OOPProviderManagerRouter.CIMPROVAGT_START_FAILED",
405 "Failed to start cimprovagt \"$0\".",
406 _moduleName));
407 }
408
409 CloseHandle(piProcInfo.hProcess);
410 CloseHandle(piProcInfo.hThread);
|
411 gs.keenan 1.8
412 #elif defined (PEGASUS_OS_VMS)
413
|
414 gs.keenan 1.10 //
415 // fork and exec the child process
416 //
417 int status;
|
418 gs.keenan 1.8
|
419 gs.keenan 1.10 status = vfork ();
420 switch (status)
421 {
422 case 0:
423 try
|
424 gs.keenan 1.8 {
|
425 gs.keenan 1.10 //
426 // Execute the cimprovagt program
427 //
428 String agentCommandPath =
429 ConfigManager::getHomedPath(PEGASUS_PROVIDER_AGENT_PROC_NAME);
430 CString agentCommandPathCString = agentCommandPath.getCString();
431
432 char readHandle[32];
433 char writeHandle[32];
434 pipeToAgent->exportReadHandle(readHandle);
435 pipeFromAgent->exportWriteHandle(writeHandle);
436
437 if ((status = execl(agentCommandPathCString, agentCommandPathCString,
438 readHandle, writeHandle,
439 (const char*)_moduleName.getCString(), (char*)0)) == -1);
440 {
441 // If we're still here, there was an error
442 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
443 "execl() failed. errno = %d.", errno);
444 _exit(1);
445 }
446 gs.keenan 1.10 }
447 catch (...)
448 {
449 // There's not much we can do here in no man's land
450 try
451 {
452 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
453 "Caught exception before calling execl().");
454 }
455 catch (...)
456 {
457 }
458 _exit(1);
459 }
460 PEG_METHOD_EXIT();
461 return;
462 break;
463
464 case -1:
465 Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
466 "fork() failed. errno = %d.", errno);
467 gs.keenan 1.10 PEG_METHOD_EXIT();
468 throw Exception(MessageLoaderParms(
469 "ProviderManager.OOPProviderManagerRouter.CIMPROVAGT_START_FAILED",
470 "Failed to start cimprovagt \"$0\".",
471 _moduleName));
472 break;
473
474 default:
475 // Close our copies of the agent's ends of the pipes
476 pipeToAgent->closeReadHandle();
477 pipeFromAgent->closeWriteHandle();
|
478 gs.keenan 1.8
|
479 gs.keenan 1.10 _pipeToAgent.reset(pipeToAgent.release());
480 _pipeFromAgent.reset(pipeFromAgent.release());
|
481 gs.keenan 1.8
|
482 gs.keenan 1.10 PEG_METHOD_EXIT();
483 }
|
484 chuck 1.16 #elif defined (PEGASUS_OS_OS400)
485
486 //Out of provider support for OS400 goes here when needed.
487
|
488 kumpf 1.1 #else
489 pid_t pid = fork();
490 if (pid < 0)
491 {
492 Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
493 "fork() failed. errno = %d.", errno);
494 PEG_METHOD_EXIT();
495 throw Exception(MessageLoaderParms(
496 "ProviderManager.OOPProviderManagerRouter.CIMPROVAGT_START_FAILED",
497 "Failed to start cimprovagt \"$0\".",
498 _moduleName));
499 }
500 else if (pid == 0)
501 {
502 //
503 // Child side of the fork
504 //
505
506 try
507 {
508 // Close our copies of the parent's ends of the pipes
509 kumpf 1.1 pipeToAgent->closeWriteHandle();
510 pipeFromAgent->closeReadHandle();
511
512 //
513 // Execute the cimprovagt program
514 //
515 String agentCommandPath =
516 ConfigManager::getHomedPath(PEGASUS_PROVIDER_AGENT_PROC_NAME);
517 CString agentCommandPathCString = agentCommandPath.getCString();
518
519 char readHandle[32];
520 char writeHandle[32];
521 pipeToAgent->exportReadHandle(readHandle);
522 pipeFromAgent->exportWriteHandle(writeHandle);
523
|
524 kumpf 1.13 #ifndef PEGASUS_DISABLE_PROV_USERCTXT
|
525 kumpf 1.6 // Set the user context of the Provider Agent process
526 if (_userName != System::getEffectiveUserName())
527 {
528 if (!System::changeUserContext(_userName.getCString()))
529 {
530 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
531 "System::changeUserContext() failed. userName = %s.",
|
532 kumpf 1.9 (const char*)_userName.getCString());
|
533 kumpf 1.6 Logger::put_l(Logger::ERROR_LOG, System::CIMSERVER,
534 Logger::WARNING,
535 "ProviderManager.OOPProviderManagerRouter."
536 "USER_CONTEXT_CHANGE_FAILED",
537 "Unable to change user context to \"$0\".", _userName);
538 _exit(1);
539 }
540 }
|
541 kumpf 1.13 #endif
|
542 kumpf 1.6
|
543 kumpf 1.1 execl(agentCommandPathCString, agentCommandPathCString,
544 readHandle, writeHandle,
545 (const char*)_moduleName.getCString(), (char*)0);
546
547 // If we're still here, there was an error
548 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
549 "execl() failed. errno = %d.", errno);
550 _exit(1);
551 }
552 catch (...)
553 {
554 // There's not much we can do here in no man's land
555 try
556 {
557 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
558 "Caught exception before calling execl().");
559 }
560 catch (...) {}
561 _exit(1);
562 }
563 }
|
564 kumpf 1.18 # if defined(PEGASUS_HAS_SIGNALS)
565 _pid = pid;
566 # endif
|
567 kumpf 1.1 #endif
568
569 //
570 // CIM Server process
571 //
572
573 // Close our copies of the agent's ends of the pipes
574 pipeToAgent->closeReadHandle();
575 pipeFromAgent->closeWriteHandle();
576
577 _pipeToAgent.reset(pipeToAgent.release());
578 _pipeFromAgent.reset(pipeFromAgent.release());
579
|
580 gs.keenan 1.10 PEG_METHOD_EXIT();
|
581 kumpf 1.1 }
582
583 // Note: Caller must lock _agentMutex
584 void ProviderAgentContainer::_sendInitializationData()
585 {
586 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
587 "ProviderAgentContainer::_sendInitializationData");
588
589 //
590 // Gather config properties to pass to the Provider Agent
591 //
592 ConfigManager* configManager = ConfigManager::getInstance();
593 Array<Pair<String, String> > configProperties;
594
595 Array<String> configPropertyNames;
596 configManager->getAllPropertyNames(configPropertyNames, true);
597 for (Uint32 i = 0; i < configPropertyNames.size(); i++)
598 {
599 String configPropertyValue =
600 configManager->getCurrentValue(configPropertyNames[i]);
601 String configPropertyDefaultValue =
602 kumpf 1.1 configManager->getDefaultValue(configPropertyNames[i]);
603 if (configPropertyValue != configPropertyDefaultValue)
604 {
605 configProperties.append(Pair<String, String>(
606 configPropertyNames[i], configPropertyValue));
607 }
608 }
609
610 //
611 // Create a Provider Agent initialization message
612 //
613 AutoPtr<CIMInitializeProviderAgentRequestMessage> request(
614 new CIMInitializeProviderAgentRequestMessage(
615 String("0"), // messageId
616 configManager->getPegasusHome(),
617 configProperties,
618 System::bindVerbose,
|
619 carolann.graves 1.14 _subscriptionInitComplete,
|
620 kumpf 1.1 QueueIdStack()));
621
622 //
623 // Write the initialization message to the pipe
624 //
625 AnonymousPipe::Status writeStatus =
626 _pipeToAgent->writeMessage(request.get());
627
628 if (writeStatus != AnonymousPipe::STATUS_SUCCESS)
629 {
630 PEG_METHOD_EXIT();
631 throw Exception(MessageLoaderParms(
632 "ProviderManager.OOPProviderManagerRouter."
633 "CIMPROVAGT_COMMUNICATION_FAILED",
634 "Failed to communicate with cimprovagt \"$0\".",
635 _moduleName));
636 }
637
638 // Do not wait for a response from the Provider Agent. (It isn't coming.)
639
640 PEG_METHOD_EXIT();
641 kumpf 1.1 }
642
643 // Note: Caller must lock _agentMutex
644 void ProviderAgentContainer::_initialize()
645 {
646 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
647 "ProviderAgentContainer::_initialize");
648
649 if (_isInitialized)
650 {
651 PEGASUS_ASSERT(0);
652 PEG_METHOD_EXIT();
653 return;
654 }
655
|
656 kumpf 1.6 if (_maxProviderProcesses == PEG_NOT_FOUND)
657 {
658 String maxProviderProcesses = ConfigManager::getInstance()->getCurrentValue("maxProviderProcesses");
659 CString maxProviderProcessesString = maxProviderProcesses.getCString();
660 char* end = 0;
661 _maxProviderProcesses = strtol(maxProviderProcessesString, &end, 10);
662 }
663
664 {
665 AutoMutex lock(_numProviderProcessesMutex);
666 if ((_maxProviderProcesses != 0) &&
667 (_numProviderProcesses >= _maxProviderProcesses))
668 {
669 throw PEGASUS_CIM_EXCEPTION(
670 CIM_ERR_FAILED,
671 MessageLoaderParms(
672 "ProviderManager.OOPProviderManagerRouter."
673 "MAX_PROVIDER_PROCESSES_REACHED",
674 "The maximum number of cimprovagt processes has been "
675 "reached."));
676 }
677 kumpf 1.6 else
678 {
679 _numProviderProcesses++;
680 }
681 }
682
|
683 kumpf 1.1 try
684 {
685 _startAgentProcess();
686
|
687 kumpf 1.18 _isInitialized = true;
688
|
689 kumpf 1.1 _sendInitializationData();
690
691 // Start a thread to read and process responses from the Provider Agent
|
692 kumpf 1.20 ThreadStatus rtn = PEGASUS_THREAD_OK;
693 while ((rtn = MessageQueueService::get_thread_pool()->
694 allocate_and_awaken(this, _responseProcessor)) !=
695 PEGASUS_THREAD_OK)
696 {
697 if (rtn == PEGASUS_THREAD_INSUFFICIENT_RESOURCES)
698 {
699 pegasus_yield();
700 }
701 else
702 {
703 Logger::put(
704 Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
705 "Not enough threads to process responses from the "
706 "provider agent.");
|
707 konrad.r 1.19
|
708 kumpf 1.20 Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
709 "Could not allocate thread to process responses from the "
710 "provider agent.");
711
712 throw Exception(MessageLoaderParms(
713 "ProviderManager.OOPProviderManagerRouter."
714 "CIMPROVAGT_THREAD_ALLOCATION_FAILED",
715 "Failed to allocate thread for cimprovagt \"$0\".",
716 _moduleName));
717 }
718 }
|
719 kumpf 1.1 }
720 catch (...)
721 {
|
722 kumpf 1.20 // Closing the connection causes the agent process to exit
723 _pipeToAgent.reset();
724 _pipeFromAgent.reset();
725
|
726 kumpf 1.18 #if defined(PEGASUS_HAS_SIGNALS)
727 if (_isInitialized)
728 {
729 // Harvest the status of the agent process to prevent a zombie
730 Boolean keepWaiting = false;
731 do
732 {
733 pid_t status = waitpid(_pid, 0, 0);
734 if (status == -1)
735 {
736 if (errno == EINTR)
737 {
738 keepWaiting = true;
739 }
740 else
741 {
742 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
743 "ProviderAgentContainer::_initialize(): "
744 "waitpid failed; errno = %d.", errno);
745 }
746 }
747 kumpf 1.18 } while (keepWaiting);
748 }
749 #endif
750
|
751 kumpf 1.1 _isInitialized = false;
|
752 kumpf 1.6
753 {
754 AutoMutex lock(_numProviderProcessesMutex);
755 _numProviderProcesses--;
756 }
757
|
758 kumpf 1.1 PEG_METHOD_EXIT();
759 throw;
760 }
761
762 PEG_METHOD_EXIT();
763 }
764
765 Boolean ProviderAgentContainer::isInitialized()
766 {
767 AutoMutex lock(_agentMutex);
768 return _isInitialized;
769 }
770
771 // Note: Caller must lock _agentMutex
772 void ProviderAgentContainer::_uninitialize()
773 {
774 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
775 "ProviderAgentContainer::_uninitialize");
776
777 if (!_isInitialized)
778 {
779 kumpf 1.1 PEGASUS_ASSERT(0);
780 PEG_METHOD_EXIT();
781 return;
782 }
783
784 try
785 {
786 // Close the connection with the Provider Agent
787 _pipeFromAgent.reset();
788 _pipeToAgent.reset();
789
|
790 kumpf 1.2 _providerModuleCache = CIMInstance();
791
|
792 kumpf 1.6 {
793 AutoMutex lock(_numProviderProcessesMutex);
794 _numProviderProcesses--;
795 }
796
|
797 kumpf 1.18 #if defined(PEGASUS_HAS_SIGNALS)
798 // Harvest the status of the agent process to prevent a zombie
799 Boolean keepWaiting = false;
800 do
801 {
802 pid_t status = waitpid(_pid, 0, 0);
803 if (status == -1)
804 {
805 if (errno == EINTR)
806 {
807 keepWaiting = true;
808 }
809 else
810 {
811 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
812 "ProviderAgentContainer::_uninitialize(): "
813 "waitpid failed; errno = %d.", errno);
814 }
815 }
816 } while (keepWaiting);
817 #endif
818 kumpf 1.18
|
819 kumpf 1.1 _isInitialized = false;
820
821 //
822 // Complete with null responses all outstanding requests on this
823 // connection
824 //
825 {
826 AutoMutex tableLock(_outstandingRequestTableMutex);
827
828 for (OutstandingRequestTable::Iterator i =
829 _outstandingRequestTable.start();
830 i != 0; i++)
831 {
832 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
833 String("Completing messageId \"") + i.value()->messageId +
834 "\" with a null response.");
835 i.value()->responseMessage = 0;
836 i.value()->responseReady->signal();
837 }
838
839 _outstandingRequestTable.clear();
840 kumpf 1.1 }
841 }
842 catch (...)
843 {
844 // We're uninitializing, so do not propagate the exception
845 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
846 "Ignoring _uninitialize() exception.");
847 }
848
849 PEG_METHOD_EXIT();
850 }
851
|
852 kumpf 1.6 String ProviderAgentContainer::getModuleName() const
853 {
854 return _moduleName;
855 }
856
|
857 kumpf 1.1 CIMResponseMessage* ProviderAgentContainer::processMessage(
858 CIMRequestMessage* request)
859 {
860 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
861 "ProviderAgentContainer::processMessage");
862
863 CIMResponseMessage* response;
864 String originalMessageId = request->messageId;
865
|
866 kumpf 1.2 // These three variables are used for the provider module optimization.
867 // See the _providerModuleCache member description for more information.
868 AutoPtr<ProviderIdContainer> origProviderId;
869 Boolean doProviderModuleOptimization = false;
870 Boolean updateProviderModuleCache = false;
871
|
872 kumpf 1.1 try
873 {
874 // The messageId attribute is used to correlate response messages
875 // from the Provider Agent with request messages, so it is imperative
876 // that the ID is unique for each request. The incoming ID cannot be
877 // trusted to be unique, so we substitute a unique one. The memory
878 // address of the request is used as the source of a unique piece of
879 // data. (The message ID is only required to be unique while the
880 // request is outstanding.)
881 char messagePtrString[20];
882 sprintf(messagePtrString, "%p", request);
883 String uniqueMessageId = messagePtrString;
884
885 //
886 // Set up the OutstandingRequestEntry for this request
887 //
888 Semaphore waitSemaphore(0);
889 OutstandingRequestEntry outstandingRequestEntry(
890 uniqueMessageId, response, &waitSemaphore);
891
892 //
893 kumpf 1.1 // Lock the Provider Agent Container while initializing the
894 // agent and writing the request to the connection
895 //
896 {
897 AutoMutex lock(_agentMutex);
898
899 //
900 // Initialize the Provider Agent, if necessary
901 //
902 if (!_isInitialized)
903 {
904 _initialize();
905 }
906
907 //
908 // Add an entry to the OutstandingRequestTable for this request
909 //
910 {
911 AutoMutex tableLock(_outstandingRequestTableMutex);
912
913 _outstandingRequestTable.insert(
914 kumpf 1.1 uniqueMessageId, &outstandingRequestEntry);
915 }
916
|
917 kumpf 1.2 // Get the provider module from the ProviderIdContainer to see if
918 // we can optimize out the transmission of this instance to the
919 // Provider Agent. (See the _providerModuleCache description.)
920 try
921 {
922 ProviderIdContainer pidc = request->operationContext.get(
923 ProviderIdContainer::NAME);
924 origProviderId.reset(new ProviderIdContainer(
925 pidc.getModule(), pidc.getProvider(),
926 pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
927 if (_providerModuleCache.isUninitialized() ||
928 (!pidc.getModule().identical(_providerModuleCache)))
929 {
930 // We haven't sent this provider module instance to the
931 // Provider Agent yet. Update our cache after we send it.
932 updateProviderModuleCache = true;
933 }
934 else
935 {
936 // Replace the provider module in the ProviderIdContainer
937 // with an uninitialized instance. We'll need to put the
938 kumpf 1.2 // original one back after the message is sent.
939 request->operationContext.set(ProviderIdContainer(
940 CIMInstance(), pidc.getProvider(),
941 pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
942 doProviderModuleOptimization = true;
943 }
944 }
945 catch (...)
946 {
947 // No ProviderIdContainer to optimize
948 }
949
|
950 kumpf 1.1 //
951 // Write the message to the pipe
952 //
953 try
954 {
955 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL3,
956 String("Sending request to agent with messageId ") +
957 uniqueMessageId);
958
959 request->messageId = uniqueMessageId;
960 AnonymousPipe::Status writeStatus =
961 _pipeToAgent->writeMessage(request);
962 request->messageId = originalMessageId;
963
|
964 kumpf 1.2 if (doProviderModuleOptimization)
965 {
966 request->operationContext.set(*origProviderId.get());
967 }
968
|
969 kumpf 1.1 if (writeStatus != AnonymousPipe::STATUS_SUCCESS)
970 {
971 Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
972 "Failed to write message to pipe. writeStatus = %d.",
973 writeStatus);
974 throw Exception(MessageLoaderParms(
975 "ProviderManager.OOPProviderManagerRouter."
976 "CIMPROVAGT_COMMUNICATION_FAILED",
977 "Failed to communicate with cimprovagt \"$0\".",
978 _moduleName));
979 }
|
980 kumpf 1.2
981 if (updateProviderModuleCache)
982 {
983 _providerModuleCache = origProviderId->getModule();
984 }
|
985 kumpf 1.1 }
986 catch (...)
987 {
988 request->messageId = originalMessageId;
|
989 kumpf 1.2
990 if (doProviderModuleOptimization)
991 {
992 request->operationContext.set(*origProviderId.get());
993 }
994
|
995 kumpf 1.1 Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
996 "Failed to write message to pipe.");
997 // Remove the OutstandingRequestTable entry for this request
998 {
999 AutoMutex tableLock(_outstandingRequestTableMutex);
1000 Boolean removed =
1001 _outstandingRequestTable.remove(uniqueMessageId);
1002 PEGASUS_ASSERT(removed);
1003 }
1004 throw;
1005 }
1006 }
1007
1008 //
1009 // Wait for the response
1010 //
1011 try
1012 {
1013 // Must not hold _agentMutex while waiting for the response
1014 waitSemaphore.wait();
1015 }
1016 kumpf 1.1 catch (...)
1017 {
1018 // Remove the OutstandingRequestTable entry for this request
1019 {
1020 AutoMutex tableLock(_outstandingRequestTableMutex);
1021 Boolean removed =
1022 _outstandingRequestTable.remove(uniqueMessageId);
1023 PEGASUS_ASSERT(removed);
1024 }
1025 throw;
1026 }
1027
1028 // A null response is returned when an agent connection is closed
1029 // while requests remain outstanding.
1030 if (response == 0)
1031 {
1032 response = request->buildResponse();
1033 response->cimException = PEGASUS_CIM_EXCEPTION(
1034 CIM_ERR_FAILED,
1035 MessageLoaderParms(
1036 "ProviderManager.OOPProviderManagerRouter."
1037 kumpf 1.1 "CIMPROVAGT_CONNECTION_LOST",
1038 "Lost connection with cimprovagt \"$0\".",
1039 _moduleName));
1040 }
1041 }
1042 catch (CIMException& e)
1043 {
1044 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
1045 String("Caught exception: ") + e.getMessage());
1046 response = request->buildResponse();
1047 response->cimException = e;
1048 }
1049 catch (Exception& e)
1050 {
1051 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
1052 String("Caught exception: ") + e.getMessage());
1053 response = request->buildResponse();
1054 response->cimException = PEGASUS_CIM_EXCEPTION(
1055 CIM_ERR_FAILED, e.getMessage());
1056 }
1057 catch (...)
1058 kumpf 1.1 {
1059 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
1060 "Caught unknown exception");
1061 response = request->buildResponse();
1062 response->cimException = PEGASUS_CIM_EXCEPTION(
1063 CIM_ERR_FAILED, String::EMPTY);
1064 }
1065
1066 response->messageId = originalMessageId;
1067
1068 PEG_METHOD_EXIT();
1069 return response;
1070 }
1071
1072 void ProviderAgentContainer::unloadIdleProviders()
1073 {
1074 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
|
1075 carolann.graves 1.4 "ProviderAgentContainer::unloadIdleProviders");
|
1076 kumpf 1.1
1077 AutoMutex lock(_agentMutex);
1078 if (_isInitialized)
1079 {
1080 // Send a "wake up" message to the Provider Agent.
1081 // Don't bother checking whether the operation is successful.
1082 Uint32 messageLength = 0;
1083 _pipeToAgent->writeBuffer((const char*)&messageLength, sizeof(Uint32));
1084 }
1085
1086 PEG_METHOD_EXIT();
1087 }
1088
1089 void ProviderAgentContainer::_processResponses()
1090 {
1091 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1092 "ProviderAgentContainer::_processResponses");
1093
1094 //
1095 // Process responses until the pipe is closed
1096 //
1097 kumpf 1.1 while (1)
1098 {
1099 try
1100 {
1101 CIMMessage* message;
1102
1103 //
1104 // Read a response from the Provider Agent
1105 //
1106 AnonymousPipe::Status readStatus =
1107 _pipeFromAgent->readMessage(message);
1108
1109 // Ignore interrupts
1110 if (readStatus == AnonymousPipe::STATUS_INTERRUPT)
1111 {
1112 continue;
1113 }
1114
1115 // Handle an error the same way as a closed connection
1116 if ((readStatus == AnonymousPipe::STATUS_ERROR) ||
1117 (readStatus == AnonymousPipe::STATUS_CLOSED))
1118 kumpf 1.1 {
1119 AutoMutex lock(_agentMutex);
1120 _uninitialize();
1121 return;
1122 }
1123
1124 if (message->getType() == CIM_PROCESS_INDICATION_REQUEST_MESSAGE)
1125 {
1126 // Forward indications to the indication callback
1127 _indicationCallback(
1128 reinterpret_cast<CIMProcessIndicationRequestMessage*>(
1129 message));
1130 }
1131 else
1132 {
1133 CIMResponseMessage* response;
1134 response = dynamic_cast<CIMResponseMessage*>(message);
1135 PEGASUS_ASSERT(response != 0);
1136
1137 // Give the response to the waiting OutstandingRequestEntry
1138 OutstandingRequestEntry* _outstandingRequestEntry = 0;
1139 kumpf 1.1 {
1140 AutoMutex tableLock(_outstandingRequestTableMutex);
1141 Boolean foundEntry = _outstandingRequestTable.lookup(
1142 response->messageId, _outstandingRequestEntry);
1143 PEGASUS_ASSERT(foundEntry);
1144
1145 // Remove the completed request from the table
1146 Boolean removed =
1147 _outstandingRequestTable.remove(response->messageId);
1148 PEGASUS_ASSERT(removed);
1149 }
1150
1151 _outstandingRequestEntry->responseMessage = response;
1152 _outstandingRequestEntry->responseReady->signal();
1153 }
1154 }
1155 catch (Exception& e)
1156 {
1157 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
1158 String("Ignoring exception: ") + e.getMessage());
1159 }
1160 kumpf 1.1 catch (...)
1161 {
1162 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
1163 "Ignoring exception");
1164 }
1165 }
1166
1167 }
1168
1169 PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL
1170 ProviderAgentContainer::_responseProcessor(void* arg)
1171 {
1172 ProviderAgentContainer* pa =
1173 reinterpret_cast<ProviderAgentContainer*>(arg);
1174
1175 pa->_processResponses();
1176
1177 return(PEGASUS_THREAD_RETURN(0));
1178 }
1179
1180 /////////////////////////////////////////////////////////////////////////////
1181 kumpf 1.1 // OOPProviderManagerRouter
1182 /////////////////////////////////////////////////////////////////////////////
1183
1184 OOPProviderManagerRouter::OOPProviderManagerRouter(
1185 PEGASUS_INDICATION_CALLBACK indicationCallback)
1186 {
1187 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1188 "OOPProviderManagerRouter::OOPProviderManagerRouter");
1189
1190 _indicationCallback = indicationCallback;
|
1191 carolann.graves 1.14 _subscriptionInitComplete = false;
|
1192 kumpf 1.1
1193 PEG_METHOD_EXIT();
1194 }
1195
1196 OOPProviderManagerRouter::~OOPProviderManagerRouter()
1197 {
1198 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1199 "OOPProviderManagerRouter::~OOPProviderManagerRouter");
1200
1201 try
1202 {
1203 // Clean up the ProviderAgentContainers
1204 AutoMutex lock(_providerAgentTableMutex);
1205 ProviderAgentTable::Iterator i = _providerAgentTable.start();
1206 for(; i != 0; i++)
1207 {
1208 delete i.value();
1209 }
1210 }
1211 catch (...) {}
1212
1213 kumpf 1.1 PEG_METHOD_EXIT();
1214 }
1215
1216 // Private, unimplemented constructor
1217 OOPProviderManagerRouter::OOPProviderManagerRouter()
1218 {
1219 }
1220
1221 // Private, unimplemented constructor
1222 OOPProviderManagerRouter::OOPProviderManagerRouter(
1223 const OOPProviderManagerRouter&)
|
1224 david.dillard 1.3 : ProviderManagerRouter(*this)
|
1225 kumpf 1.1 {
1226 }
1227
1228 // Private, unimplemented assignment operator
1229 OOPProviderManagerRouter& OOPProviderManagerRouter::operator=(
1230 const OOPProviderManagerRouter&)
1231 {
1232 return *this;
1233 }
1234
1235 Message* OOPProviderManagerRouter::processMessage(Message* message)
1236 {
1237 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1238 "OOPProviderManagerRouter::processMessage");
1239
1240 CIMRequestMessage* request = dynamic_cast<CIMRequestMessage *>(message);
1241 PEGASUS_ASSERT(request != 0);
1242
1243 AutoPtr<CIMResponseMessage> response;
1244
1245 //
1246 kumpf 1.1 // Get the provider information from the request
1247 //
1248 CIMInstance providerModule;
1249
1250 if ((dynamic_cast<CIMOperationRequestMessage*>(request) != 0) ||
1251 (dynamic_cast<CIMIndicationRequestMessage*>(request) != 0) ||
1252 (request->getType() == CIM_EXPORT_INDICATION_REQUEST_MESSAGE))
1253 {
1254 // Provider information is in the OperationContext
1255 ProviderIdContainer pidc = (ProviderIdContainer)
1256 request->operationContext.get(ProviderIdContainer::NAME);
1257 providerModule = pidc.getModule();
1258 }
1259 else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
1260 {
1261 CIMEnableModuleRequestMessage* emReq =
1262 dynamic_cast<CIMEnableModuleRequestMessage*>(request);
1263 providerModule = emReq->providerModule;
1264 }
1265 else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
1266 {
1267 kumpf 1.1 CIMDisableModuleRequestMessage* dmReq =
1268 dynamic_cast<CIMDisableModuleRequestMessage*>(request);
1269 providerModule = dmReq->providerModule;
1270 }
1271 else if ((request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE) ||
|
1272 carolann.graves 1.14 (request->getType() ==
1273 CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE) ||
|
1274 kumpf 1.1 (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE))
1275 {
1276 // This operation is not provider-specific
1277 }
1278 else
1279 {
1280 // Unrecognized message type. This should never happen.
1281 PEGASUS_ASSERT(0);
1282 response.reset(request->buildResponse());
1283 response->cimException = PEGASUS_CIM_EXCEPTION(
1284 CIM_ERR_FAILED, "Unrecognized message type.");
1285 PEG_METHOD_EXIT();
1286 return response.release();
1287 }
1288
1289 //
1290 // Process the request message
1291 //
1292 if (request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE)
1293 {
1294 // Forward the CIMStopAllProvidersRequest to all providers
1295 kumpf 1.1 response.reset(_forwardRequestToAllAgents(request));
1296
1297 // Note: Do not uninitialize the ProviderAgentContainers here.
1298 // Just let the selecting thread notice when the agent connections
1299 // are closed.
1300 }
|
1301 carolann.graves 1.14 else if (request->getType () ==
1302 CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE)
1303 {
1304 _subscriptionInitComplete = true;
1305
1306 //
1307 // Forward the CIMSubscriptionInitCompleteRequestMessage to
1308 // all providers
1309 //
1310 response.reset (_forwardRequestToAllAgents (request));
1311 }
|
1312 kumpf 1.1 else if (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE)
1313 {
1314 CIMNotifyConfigChangeRequestMessage* notifyRequest =
1315 dynamic_cast<CIMNotifyConfigChangeRequestMessage*>(request);
1316 PEGASUS_ASSERT(notifyRequest != 0);
1317
1318 if (notifyRequest->currentValueModified)
1319 {
1320 // Forward the CIMNotifyConfigChangeRequestMessage to all providers
1321 response.reset(_forwardRequestToAllAgents(request));
1322 }
1323 else
1324 {
1325 // No need to notify provider agents about changes to planned value
1326 response.reset(request->buildResponse());
1327 }
1328 }
|
1329 kumpf 1.6 else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
|
1330 kumpf 1.1 {
|
1331 kumpf 1.6 // Fan out the request to all Provider Agent processes for this module
1332
|
1333 kumpf 1.1 // Retrieve the provider module name
1334 String moduleName;
1335 CIMValue nameValue = providerModule.getProperty(
1336 providerModule.findProperty("Name")).getValue();
1337 nameValue.get(moduleName);
1338
|
1339 kumpf 1.6 // Look up the Provider Agents for this module
1340 Array<ProviderAgentContainer*> paArray =
1341 _lookupProviderAgents(moduleName);
|
1342 kumpf 1.1
|
1343 kumpf 1.6 for (Uint32 i=0; i<paArray.size(); i++)
|
1344 kumpf 1.1 {
1345 //
1346 // Do not start up an agent process just to disable the module
1347 //
|
1348 kumpf 1.6 if (paArray[i]->isInitialized())
1349 {
1350 //
1351 // Forward the request to the provider agent
1352 //
1353 response.reset(paArray[i]->processMessage(request));
1354
1355 // Note: Do not uninitialize the ProviderAgentContainer here
1356 // when a disable module operation is successful. Just let the
1357 // selecting thread notice when the agent connection is closed.
1358
1359 // Determine the success of the disable module operation
1360 CIMDisableModuleResponseMessage* dmResponse =
1361 dynamic_cast<CIMDisableModuleResponseMessage*>(
1362 response.get());
1363 PEGASUS_ASSERT(dmResponse != 0);
1364
1365 Boolean isStopped = false;
1366 for (Uint32 i=0; i < dmResponse->operationalStatus.size(); i++)
1367 {
1368 if (dmResponse->operationalStatus[i] ==
1369 kumpf 1.6 CIM_MSE_OPSTATUS_VALUE_STOPPED)
1370 {
1371 isStopped = true;
1372 break;
1373 }
1374 }
1375
1376 // If the operation is unsuccessful, stop and return the error
1377 if ((dmResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
1378 !isStopped)
1379 {
1380 break;
1381 }
1382 }
1383 }
1384
1385 // Use a default response if no Provider Agents were called
1386 if (!response.get())
1387 {
|
1388 kumpf 1.1 response.reset(request->buildResponse());
1389
1390 CIMDisableModuleResponseMessage* dmResponse =
1391 dynamic_cast<CIMDisableModuleResponseMessage*>(response.get());
1392 PEGASUS_ASSERT(dmResponse != 0);
1393
1394 Array<Uint16> operationalStatus;
1395 operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_STOPPED);
1396 dmResponse->operationalStatus = operationalStatus;
1397 }
|
1398 kumpf 1.6 }
1399 else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
1400 {
1401 // Fan out the request to all Provider Agent processes for this module
1402
1403 // Retrieve the provider module name
1404 String moduleName;
1405 CIMValue nameValue = providerModule.getProperty(
1406 providerModule.findProperty("Name")).getValue();
1407 nameValue.get(moduleName);
1408
1409 // Look up the Provider Agents for this module
1410 Array<ProviderAgentContainer*> paArray =
1411 _lookupProviderAgents(moduleName);
1412
1413 for (Uint32 i=0; i<paArray.size(); i++)
|
1414 kumpf 1.1 {
1415 //
1416 // Do not start up an agent process just to enable the module
1417 //
|
1418 kumpf 1.6 if (paArray[i]->isInitialized())
1419 {
1420 //
1421 // Forward the request to the provider agent
1422 //
1423 response.reset(paArray[i]->processMessage(request));
1424
1425 // Determine the success of the enable module operation
1426 CIMEnableModuleResponseMessage* emResponse =
1427 dynamic_cast<CIMEnableModuleResponseMessage*>(
1428 response.get());
1429 PEGASUS_ASSERT(emResponse != 0);
1430
1431 Boolean isOk = false;
1432 for (Uint32 i=0; i < emResponse->operationalStatus.size(); i++)
1433 {
1434 if (emResponse->operationalStatus[i] ==
1435 CIM_MSE_OPSTATUS_VALUE_OK)
1436 {
1437 isOk = true;
1438 break;
1439 kumpf 1.6 }
1440 }
1441
1442 // If the operation is unsuccessful, stop and return the error
1443 if ((emResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
1444 !isOk)
1445 {
1446 break;
1447 }
1448 }
1449 }
1450
1451 // Use a default response if no Provider Agents were called
1452 if (!response.get())
1453 {
|
1454 kumpf 1.1 response.reset(request->buildResponse());
1455
1456 CIMEnableModuleResponseMessage* emResponse =
1457 dynamic_cast<CIMEnableModuleResponseMessage*>(response.get());
1458 PEGASUS_ASSERT(emResponse != 0);
1459
1460 Array<Uint16> operationalStatus;
1461 operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_OK);
1462 emResponse->operationalStatus = operationalStatus;
1463 }
|
1464 kumpf 1.6 }
1465 else
1466 {
1467 // Retrieve the provider module name
1468 String moduleName;
1469 CIMValue nameValue = providerModule.getProperty(
1470 providerModule.findProperty("Name")).getValue();
1471 nameValue.get(moduleName);
1472
1473 // Retrieve the provider user context configuration
1474 Uint16 userContext = 0;
1475 Uint32 pos = providerModule.findProperty(
1476 PEGASUS_PROPERTYNAME_MODULE_USERCONTEXT);
1477 if (pos != PEG_NOT_FOUND)
1478 {
|
1479 kumpf 1.12 CIMValue userContextValue =
1480 providerModule.getProperty(pos).getValue();
1481 if (!userContextValue.isNull())
1482 {
1483 userContextValue.get(userContext);
1484 }
|
1485 kumpf 1.6 }
1486
1487 if (userContext == 0)
1488 {
1489 userContext = PG_PROVMODULE_USERCTXT_PRIVILEGED;
1490 }
1491
1492 String userName;
1493
1494 if (userContext == PG_PROVMODULE_USERCTXT_REQUESTOR)
|
1495 kumpf 1.1 {
|
1496 kumpf 1.6 try
1497 {
1498 // User Name is in the OperationContext
1499 IdentityContainer ic = (IdentityContainer)
1500 request->operationContext.get(IdentityContainer::NAME);
1501 userName = ic.getUserName();
1502 }
1503 catch (Exception& e)
1504 {
1505 // If no IdentityContainer is present, default to the CIM
1506 // Server's user context
1507 }
|
1508 kumpf 1.1
|
1509 kumpf 1.6 // If authentication is disabled, use the CIM Server's user context
1510 if (!userName.size())
1511 {
1512 userName = System::getEffectiveUserName();
1513 }
1514 }
1515 else if (userContext == PG_PROVMODULE_USERCTXT_DESIGNATED)
1516 {
1517 // Retrieve the provider module name
1518 providerModule.getProperty(providerModule.findProperty(
1519 PEGASUS_PROPERTYNAME_MODULE_DESIGNATEDUSER)).getValue().
1520 get(userName);
1521 }
1522 else if (userContext == PG_PROVMODULE_USERCTXT_CIMSERVER)
1523 {
1524 userName = System::getEffectiveUserName();
1525 }
1526 else // Privileged User
1527 {
1528 PEGASUS_ASSERT(userContext == PG_PROVMODULE_USERCTXT_PRIVILEGED);
1529 userName = System::getPrivilegedUserName();
|
1530 kumpf 1.1 }
|
1531 kumpf 1.6
1532 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1533 "Module name = " + moduleName);
1534 Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1535 "User context = %hd.", userContext);
1536 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1537 "User name = " + userName);
1538
1539 // Look up the Provider Agent for this module and user
1540 ProviderAgentContainer* pa = _lookupProviderAgent(moduleName, userName);
1541 PEGASUS_ASSERT(pa != 0);
1542
1543 //
1544 // Forward the request to the provider agent
1545 //
1546 response.reset(pa->processMessage(request));
|
1547 kumpf 1.1 }
1548
1549 response->syncAttributes(request);
1550
1551 PEG_METHOD_EXIT();
1552 return response.release();
1553 }
1554
1555 ProviderAgentContainer* OOPProviderManagerRouter::_lookupProviderAgent(
|
1556 kumpf 1.6 const String& moduleName,
1557 const String& userName)
|
1558 kumpf 1.1 {
1559 ProviderAgentContainer* pa = 0;
|
1560 kumpf 1.6 String key = moduleName + ":" + userName;
|
1561 kumpf 1.1
1562 AutoMutex lock(_providerAgentTableMutex);
|
1563 kumpf 1.6 if (!_providerAgentTable.lookup(key, pa))
|
1564 kumpf 1.1 {
|
1565 kumpf 1.6 pa = new ProviderAgentContainer(
|
1566 carolann.graves 1.14 moduleName, userName, _indicationCallback,
1567 _subscriptionInitComplete);
|
1568 kumpf 1.6 _providerAgentTable.insert(key, pa);
|
1569 kumpf 1.1 }
1570 return pa;
1571 }
1572
|
1573 kumpf 1.6 Array<ProviderAgentContainer*> OOPProviderManagerRouter::_lookupProviderAgents(
1574 const String& moduleName)
1575 {
1576 Array<ProviderAgentContainer*> paArray;
1577
1578 AutoMutex lock(_providerAgentTableMutex);
1579 for (ProviderAgentTable::Iterator i = _providerAgentTable.start(); i; i++)
1580 {
1581 if (i.value()->getModuleName() == moduleName)
1582 {
1583 paArray.append(i.value());
1584 }
1585 }
1586 return paArray;
1587 }
1588
|
1589 kumpf 1.1 CIMResponseMessage* OOPProviderManagerRouter::_forwardRequestToAllAgents(
1590 CIMRequestMessage* request)
1591 {
1592 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1593 "OOPProviderManagerRouter::_forwardRequestToAllAgents");
1594
1595 // Get a list of the ProviderAgentContainers. We need our own array copy
1596 // because we cannot hold the _providerAgentTableMutex while calling
1597 // _ProviderAgentContainer::processMessage().
1598 Array<ProviderAgentContainer*> paContainerArray;
1599 {
1600 AutoMutex tableLock(_providerAgentTableMutex);
1601 for (ProviderAgentTable::Iterator i = _providerAgentTable.start();
1602 i != 0; i++)
1603 {
1604 paContainerArray.append(i.value());
1605 }
1606 }
1607
1608 CIMException responseException;
1609
1610 kumpf 1.1 // Forward the request to each of the initialized provider agents
1611 for (Uint32 j = 0; j < paContainerArray.size(); j++)
1612 {
1613 ProviderAgentContainer* pa = paContainerArray[j];
1614 if (pa->isInitialized())
1615 {
1616 // Note: The ProviderAgentContainer could become uninitialized
1617 // before _ProviderAgentContainer::processMessage() processes
1618 // this request. In this case, the Provider Agent process will
1619 // (unfortunately) be started to process this message.
1620 AutoPtr<CIMResponseMessage> response;
1621 response.reset(pa->processMessage(request));
1622 if (response.get() != 0)
1623 {
1624 // If the operation failed, save the exception data
1625 if ((response->cimException.getCode() != CIM_ERR_SUCCESS) &&
1626 (responseException.getCode() == CIM_ERR_SUCCESS))
1627 {
1628 responseException = response->cimException;
1629 }
1630 }
1631 kumpf 1.1 }
1632 }
1633
1634 CIMResponseMessage* response = request->buildResponse();
1635 response->cimException = responseException;
1636
1637 PEG_METHOD_EXIT();
1638 return response;
1639 }
1640
1641 Boolean OOPProviderManagerRouter::hasActiveProviders()
1642 {
1643 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1644 "OOPProviderManagerRouter::hasActiveProviders");
1645
1646 // Iterate through the _providerAgentTable looking for initialized agents
1647 AutoMutex lock(_providerAgentTableMutex);
1648 ProviderAgentTable::Iterator i = _providerAgentTable.start();
1649 for(; i != 0; i++)
1650 {
1651 if (i.value()->isInitialized())
1652 kumpf 1.1 {
1653 PEG_METHOD_EXIT();
1654 return true;
1655 }
1656 }
1657
1658 // No initialized Provider Agents were found
1659 PEG_METHOD_EXIT();
1660 return false;
1661 }
1662
1663 void OOPProviderManagerRouter::unloadIdleProviders()
1664 {
1665 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1666 "OOPProviderManagerRouter::unloadIdleProviders");
1667
1668 // Iterate through the _providerAgentTable unloading idle providers
1669 AutoMutex lock(_providerAgentTableMutex);
1670 ProviderAgentTable::Iterator i = _providerAgentTable.start();
1671 for(; i != 0; i++)
1672 {
1673 kumpf 1.1 i.value()->unloadIdleProviders();
1674 }
1675
1676 PEG_METHOD_EXIT();
1677 }
1678
1679 PEGASUS_NAMESPACE_END
|