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