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