1 a.dunfey 1.22.2.1 //%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 a.dunfey 1.22.2.1 // 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 // Do not wait for a response from the Provider Agent. (It isn't coming.)
665
666 PEG_METHOD_EXIT();
667 kumpf 1.1 }
668
669 // Note: Caller must lock _agentMutex
670 void ProviderAgentContainer::_initialize()
671 {
672 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
673 "ProviderAgentContainer::_initialize");
674
675 if (_isInitialized)
676 {
677 PEGASUS_ASSERT(0);
678 PEG_METHOD_EXIT();
679 return;
680 }
681
|
682 kumpf 1.6 if (_maxProviderProcesses == PEG_NOT_FOUND)
683 {
684 String maxProviderProcesses = ConfigManager::getInstance()->getCurrentValue("maxProviderProcesses");
685 CString maxProviderProcessesString = maxProviderProcesses.getCString();
686 char* end = 0;
687 _maxProviderProcesses = strtol(maxProviderProcessesString, &end, 10);
688 }
689
690 {
691 AutoMutex lock(_numProviderProcessesMutex);
692 if ((_maxProviderProcesses != 0) &&
693 (_numProviderProcesses >= _maxProviderProcesses))
694 {
695 throw PEGASUS_CIM_EXCEPTION(
696 CIM_ERR_FAILED,
697 MessageLoaderParms(
698 "ProviderManager.OOPProviderManagerRouter."
699 "MAX_PROVIDER_PROCESSES_REACHED",
700 "The maximum number of cimprovagt processes has been "
701 "reached."));
702 }
703 kumpf 1.6 else
704 {
705 _numProviderProcesses++;
706 }
707 }
708
|
709 kumpf 1.1 try
710 {
711 _startAgentProcess();
712
|
713 kumpf 1.18 _isInitialized = true;
714
|
715 kumpf 1.1 _sendInitializationData();
716
717 // Start a thread to read and process responses from the Provider Agent
|
718 kumpf 1.20 ThreadStatus rtn = PEGASUS_THREAD_OK;
719 while ((rtn = MessageQueueService::get_thread_pool()->
720 allocate_and_awaken(this, _responseProcessor)) !=
721 PEGASUS_THREAD_OK)
722 {
723 if (rtn == PEGASUS_THREAD_INSUFFICIENT_RESOURCES)
724 {
725 pegasus_yield();
726 }
727 else
728 {
729 Logger::put(
730 Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
731 "Not enough threads to process responses from the "
732 "provider agent.");
|
733 konrad.r 1.19
|
734 kumpf 1.20 Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
735 "Could not allocate thread to process responses from the "
736 "provider agent.");
737
738 throw Exception(MessageLoaderParms(
739 "ProviderManager.OOPProviderManagerRouter."
740 "CIMPROVAGT_THREAD_ALLOCATION_FAILED",
741 "Failed to allocate thread for cimprovagt \"$0\".",
742 _moduleName));
743 }
744 }
|
745 kumpf 1.1 }
746 catch (...)
747 {
|
748 kumpf 1.20 // Closing the connection causes the agent process to exit
749 _pipeToAgent.reset();
750 _pipeFromAgent.reset();
751
|
752 kumpf 1.18 #if defined(PEGASUS_HAS_SIGNALS)
753 if (_isInitialized)
754 {
755 // Harvest the status of the agent process to prevent a zombie
756 Boolean keepWaiting = false;
757 do
758 {
759 pid_t status = waitpid(_pid, 0, 0);
760 if (status == -1)
761 {
762 if (errno == EINTR)
763 {
764 keepWaiting = true;
765 }
766 else
767 {
768 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
769 "ProviderAgentContainer::_initialize(): "
770 "waitpid failed; errno = %d.", errno);
771 }
772 }
773 kumpf 1.18 } while (keepWaiting);
774 }
775 #endif
776
|
777 kumpf 1.1 _isInitialized = false;
|
778 kumpf 1.6
779 {
780 AutoMutex lock(_numProviderProcessesMutex);
781 _numProviderProcesses--;
782 }
783
|
784 kumpf 1.1 PEG_METHOD_EXIT();
785 throw;
786 }
787
788 PEG_METHOD_EXIT();
789 }
790
791 Boolean ProviderAgentContainer::isInitialized()
792 {
793 AutoMutex lock(_agentMutex);
794 return _isInitialized;
795 }
796
797 // Note: Caller must lock _agentMutex
|
798 kumpf 1.22 void ProviderAgentContainer::_uninitialize(Boolean cleanShutdown)
|
799 kumpf 1.1 {
800 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
801 "ProviderAgentContainer::_uninitialize");
802
803 if (!_isInitialized)
804 {
805 PEGASUS_ASSERT(0);
806 PEG_METHOD_EXIT();
807 return;
808 }
809
810 try
811 {
812 // Close the connection with the Provider Agent
813 _pipeFromAgent.reset();
814 _pipeToAgent.reset();
815
|
816 kumpf 1.2 _providerModuleCache = CIMInstance();
817
|
818 kumpf 1.6 {
819 AutoMutex lock(_numProviderProcessesMutex);
820 _numProviderProcesses--;
821 }
822
|
823 kumpf 1.18 #if defined(PEGASUS_HAS_SIGNALS)
824 // Harvest the status of the agent process to prevent a zombie
825 Boolean keepWaiting = false;
826 do
827 {
828 pid_t status = waitpid(_pid, 0, 0);
829 if (status == -1)
830 {
831 if (errno == EINTR)
832 {
833 keepWaiting = true;
834 }
835 else
836 {
837 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
838 "ProviderAgentContainer::_uninitialize(): "
839 "waitpid failed; errno = %d.", errno);
840 }
841 }
842 } while (keepWaiting);
843 #endif
844 kumpf 1.18
|
845 kumpf 1.1 _isInitialized = false;
846
847 //
848 // Complete with null responses all outstanding requests on this
849 // connection
850 //
851 {
852 AutoMutex tableLock(_outstandingRequestTableMutex);
853
|
854 kumpf 1.22 CIMResponseMessage* response =
855 cleanShutdown ? _REQUEST_NOT_PROCESSED : 0;
856
|
857 kumpf 1.1 for (OutstandingRequestTable::Iterator i =
858 _outstandingRequestTable.start();
859 i != 0; i++)
860 {
861 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
862 String("Completing messageId \"") + i.value()->messageId +
863 "\" with a null response.");
|
864 kumpf 1.22 i.value()->responseMessage = response;
|
865 kumpf 1.1 i.value()->responseReady->signal();
866 }
867
868 _outstandingRequestTable.clear();
869 }
870 }
871 catch (...)
872 {
873 // We're uninitializing, so do not propagate the exception
874 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
875 "Ignoring _uninitialize() exception.");
876 }
877
878 PEG_METHOD_EXIT();
879 }
880
|
881 kumpf 1.6 String ProviderAgentContainer::getModuleName() const
882 {
883 return _moduleName;
884 }
885
|
886 kumpf 1.1 CIMResponseMessage* ProviderAgentContainer::processMessage(
887 CIMRequestMessage* request)
888 {
889 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
890 "ProviderAgentContainer::processMessage");
891
892 CIMResponseMessage* response;
|
893 kumpf 1.22
894 do
895 {
896 response = _processMessage(request);
897 } while (response == _REQUEST_NOT_PROCESSED);
898
899 PEG_METHOD_EXIT();
900 return response;
901 }
902
903 CIMResponseMessage* ProviderAgentContainer::_processMessage(
904 CIMRequestMessage* request)
905 {
906 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
907 "ProviderAgentContainer::_processMessage");
908
909 CIMResponseMessage* response;
|
910 kumpf 1.1 String originalMessageId = request->messageId;
911
|
912 kumpf 1.2 // These three variables are used for the provider module optimization.
913 // See the _providerModuleCache member description for more information.
914 AutoPtr<ProviderIdContainer> origProviderId;
915 Boolean doProviderModuleOptimization = false;
916 Boolean updateProviderModuleCache = false;
917
|
918 kumpf 1.1 try
919 {
920 // The messageId attribute is used to correlate response messages
921 // from the Provider Agent with request messages, so it is imperative
922 // that the ID is unique for each request. The incoming ID cannot be
923 // trusted to be unique, so we substitute a unique one. The memory
924 // address of the request is used as the source of a unique piece of
925 // data. (The message ID is only required to be unique while the
926 // request is outstanding.)
927 char messagePtrString[20];
928 sprintf(messagePtrString, "%p", request);
929 String uniqueMessageId = messagePtrString;
930
931 //
932 // Set up the OutstandingRequestEntry for this request
933 //
934 Semaphore waitSemaphore(0);
935 OutstandingRequestEntry outstandingRequestEntry(
936 uniqueMessageId, response, &waitSemaphore);
937
938 //
939 kumpf 1.1 // Lock the Provider Agent Container while initializing the
940 // agent and writing the request to the connection
941 //
942 {
943 AutoMutex lock(_agentMutex);
944
945 //
946 // Initialize the Provider Agent, if necessary
947 //
948 if (!_isInitialized)
949 {
950 _initialize();
951 }
952
953 //
954 // Add an entry to the OutstandingRequestTable for this request
955 //
956 {
957 AutoMutex tableLock(_outstandingRequestTableMutex);
958
959 _outstandingRequestTable.insert(
960 kumpf 1.1 uniqueMessageId, &outstandingRequestEntry);
961 }
962
|
963 kumpf 1.2 // Get the provider module from the ProviderIdContainer to see if
964 // we can optimize out the transmission of this instance to the
965 // Provider Agent. (See the _providerModuleCache description.)
966 try
967 {
968 ProviderIdContainer pidc = request->operationContext.get(
969 ProviderIdContainer::NAME);
970 origProviderId.reset(new ProviderIdContainer(
971 pidc.getModule(), pidc.getProvider(),
972 pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
973 if (_providerModuleCache.isUninitialized() ||
974 (!pidc.getModule().identical(_providerModuleCache)))
975 {
976 // We haven't sent this provider module instance to the
977 // Provider Agent yet. Update our cache after we send it.
978 updateProviderModuleCache = true;
979 }
980 else
981 {
982 // Replace the provider module in the ProviderIdContainer
983 // with an uninitialized instance. We'll need to put the
984 kumpf 1.2 // original one back after the message is sent.
985 request->operationContext.set(ProviderIdContainer(
986 CIMInstance(), pidc.getProvider(),
987 pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
988 doProviderModuleOptimization = true;
989 }
990 }
991 catch (...)
992 {
993 // No ProviderIdContainer to optimize
994 }
995
|
996 kumpf 1.1 //
997 // Write the message to the pipe
998 //
999 try
1000 {
1001 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL3,
1002 String("Sending request to agent with messageId ") +
1003 uniqueMessageId);
1004
1005 request->messageId = uniqueMessageId;
1006 AnonymousPipe::Status writeStatus =
1007 _pipeToAgent->writeMessage(request);
1008 request->messageId = originalMessageId;
1009
|
1010 kumpf 1.2 if (doProviderModuleOptimization)
1011 {
1012 request->operationContext.set(*origProviderId.get());
1013 }
1014
|
1015 kumpf 1.1 if (writeStatus != AnonymousPipe::STATUS_SUCCESS)
1016 {
1017 Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
1018 "Failed to write message to pipe. writeStatus = %d.",
1019 writeStatus);
1020 throw Exception(MessageLoaderParms(
1021 "ProviderManager.OOPProviderManagerRouter."
1022 "CIMPROVAGT_COMMUNICATION_FAILED",
1023 "Failed to communicate with cimprovagt \"$0\".",
1024 _moduleName));
1025 }
|
1026 kumpf 1.2
1027 if (updateProviderModuleCache)
1028 {
1029 _providerModuleCache = origProviderId->getModule();
1030 }
|
1031 kumpf 1.1 }
1032 catch (...)
1033 {
1034 request->messageId = originalMessageId;
|
1035 kumpf 1.2
1036 if (doProviderModuleOptimization)
1037 {
1038 request->operationContext.set(*origProviderId.get());
1039 }
1040
|
1041 kumpf 1.1 Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
1042 "Failed to write message to pipe.");
1043 // Remove the OutstandingRequestTable entry for this request
1044 {
1045 AutoMutex tableLock(_outstandingRequestTableMutex);
1046 Boolean removed =
1047 _outstandingRequestTable.remove(uniqueMessageId);
1048 PEGASUS_ASSERT(removed);
1049 }
1050 throw;
1051 }
1052 }
1053
1054 //
1055 // Wait for the response
1056 //
1057 try
1058 {
1059 // Must not hold _agentMutex while waiting for the response
1060 waitSemaphore.wait();
1061 }
1062 kumpf 1.1 catch (...)
1063 {
1064 // Remove the OutstandingRequestTable entry for this request
1065 {
1066 AutoMutex tableLock(_outstandingRequestTableMutex);
1067 Boolean removed =
1068 _outstandingRequestTable.remove(uniqueMessageId);
1069 PEGASUS_ASSERT(removed);
1070 }
1071 throw;
1072 }
1073
|
1074 kumpf 1.22 // A response value of _REQUEST_NOT_PROCESSED indicates that the
1075 // provider agent process was terminating when the request was sent.
1076 // The request was not processed by the provider agent, so it can be
1077 // retried safely.
1078 if (response == _REQUEST_NOT_PROCESSED)
1079 {
1080 return response;
1081 }
1082
|
1083 kumpf 1.1 // A null response is returned when an agent connection is closed
1084 // while requests remain outstanding.
1085 if (response == 0)
1086 {
1087 response = request->buildResponse();
1088 response->cimException = PEGASUS_CIM_EXCEPTION(
1089 CIM_ERR_FAILED,
1090 MessageLoaderParms(
1091 "ProviderManager.OOPProviderManagerRouter."
1092 "CIMPROVAGT_CONNECTION_LOST",
1093 "Lost connection with cimprovagt \"$0\".",
1094 _moduleName));
1095 }
1096 }
1097 catch (CIMException& e)
1098 {
1099 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
1100 String("Caught exception: ") + e.getMessage());
1101 response = request->buildResponse();
1102 response->cimException = e;
1103 }
1104 kumpf 1.1 catch (Exception& e)
1105 {
1106 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
1107 String("Caught exception: ") + e.getMessage());
1108 response = request->buildResponse();
1109 response->cimException = PEGASUS_CIM_EXCEPTION(
1110 CIM_ERR_FAILED, e.getMessage());
1111 }
1112 catch (...)
1113 {
1114 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
1115 "Caught unknown exception");
1116 response = request->buildResponse();
1117 response->cimException = PEGASUS_CIM_EXCEPTION(
1118 CIM_ERR_FAILED, String::EMPTY);
1119 }
1120
1121 response->messageId = originalMessageId;
1122
1123 PEG_METHOD_EXIT();
1124 return response;
1125 kumpf 1.1 }
1126
1127 void ProviderAgentContainer::unloadIdleProviders()
1128 {
1129 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
|
1130 carolann.graves 1.4 "ProviderAgentContainer::unloadIdleProviders");
|
1131 kumpf 1.1
1132 AutoMutex lock(_agentMutex);
1133 if (_isInitialized)
1134 {
1135 // Send a "wake up" message to the Provider Agent.
1136 // Don't bother checking whether the operation is successful.
1137 Uint32 messageLength = 0;
1138 _pipeToAgent->writeBuffer((const char*)&messageLength, sizeof(Uint32));
1139 }
1140
1141 PEG_METHOD_EXIT();
1142 }
1143
1144 void ProviderAgentContainer::_processResponses()
1145 {
1146 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1147 "ProviderAgentContainer::_processResponses");
1148
1149 //
1150 // Process responses until the pipe is closed
1151 //
1152 kumpf 1.1 while (1)
1153 {
1154 try
1155 {
1156 CIMMessage* message;
1157
1158 //
1159 // Read a response from the Provider Agent
1160 //
1161 AnonymousPipe::Status readStatus =
1162 _pipeFromAgent->readMessage(message);
1163
1164 // Ignore interrupts
1165 if (readStatus == AnonymousPipe::STATUS_INTERRUPT)
1166 {
1167 continue;
1168 }
1169
1170 // Handle an error the same way as a closed connection
1171 if ((readStatus == AnonymousPipe::STATUS_ERROR) ||
1172 (readStatus == AnonymousPipe::STATUS_CLOSED))
1173 kumpf 1.1 {
1174 AutoMutex lock(_agentMutex);
|
1175 kumpf 1.22 _uninitialize(false);
1176 return;
1177 }
1178
1179 // A null message indicates that the provider agent process has
1180 // finished its processing and is ready to exit.
1181 if (message == 0)
1182 {
1183 AutoMutex lock(_agentMutex);
1184 _uninitialize(true);
|
1185 kumpf 1.1 return;
1186 }
1187
1188 if (message->getType() == CIM_PROCESS_INDICATION_REQUEST_MESSAGE)
1189 {
1190 // Forward indications to the indication callback
1191 _indicationCallback(
1192 reinterpret_cast<CIMProcessIndicationRequestMessage*>(
1193 message));
1194 }
1195 else
1196 {
1197 CIMResponseMessage* response;
1198 response = dynamic_cast<CIMResponseMessage*>(message);
1199 PEGASUS_ASSERT(response != 0);
1200
1201 // Give the response to the waiting OutstandingRequestEntry
1202 OutstandingRequestEntry* _outstandingRequestEntry = 0;
1203 {
1204 AutoMutex tableLock(_outstandingRequestTableMutex);
1205 Boolean foundEntry = _outstandingRequestTable.lookup(
1206 kumpf 1.1 response->messageId, _outstandingRequestEntry);
1207 PEGASUS_ASSERT(foundEntry);
1208
1209 // Remove the completed request from the table
1210 Boolean removed =
1211 _outstandingRequestTable.remove(response->messageId);
1212 PEGASUS_ASSERT(removed);
1213 }
1214
1215 _outstandingRequestEntry->responseMessage = response;
1216 _outstandingRequestEntry->responseReady->signal();
1217 }
1218 }
1219 catch (Exception& e)
1220 {
1221 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
1222 String("Ignoring exception: ") + e.getMessage());
1223 }
1224 catch (...)
1225 {
1226 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
1227 kumpf 1.1 "Ignoring exception");
1228 }
1229 }
1230
1231 }
1232
1233 PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL
1234 ProviderAgentContainer::_responseProcessor(void* arg)
1235 {
1236 ProviderAgentContainer* pa =
1237 reinterpret_cast<ProviderAgentContainer*>(arg);
1238
1239 pa->_processResponses();
1240
1241 return(PEGASUS_THREAD_RETURN(0));
1242 }
1243
1244 /////////////////////////////////////////////////////////////////////////////
1245 // OOPProviderManagerRouter
1246 /////////////////////////////////////////////////////////////////////////////
1247
1248 kumpf 1.1 OOPProviderManagerRouter::OOPProviderManagerRouter(
1249 PEGASUS_INDICATION_CALLBACK indicationCallback)
1250 {
1251 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1252 "OOPProviderManagerRouter::OOPProviderManagerRouter");
1253
1254 _indicationCallback = indicationCallback;
|
1255 carolann.graves 1.14 _subscriptionInitComplete = false;
|
1256 kumpf 1.1
1257 PEG_METHOD_EXIT();
1258 }
1259
1260 OOPProviderManagerRouter::~OOPProviderManagerRouter()
1261 {
1262 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1263 "OOPProviderManagerRouter::~OOPProviderManagerRouter");
1264
1265 try
1266 {
1267 // Clean up the ProviderAgentContainers
1268 AutoMutex lock(_providerAgentTableMutex);
1269 ProviderAgentTable::Iterator i = _providerAgentTable.start();
1270 for(; i != 0; i++)
1271 {
1272 delete i.value();
1273 }
1274 }
1275 catch (...) {}
1276
1277 kumpf 1.1 PEG_METHOD_EXIT();
1278 }
1279
1280 Message* OOPProviderManagerRouter::processMessage(Message* message)
1281 {
1282 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1283 "OOPProviderManagerRouter::processMessage");
1284
1285 CIMRequestMessage* request = dynamic_cast<CIMRequestMessage *>(message);
1286 PEGASUS_ASSERT(request != 0);
1287
1288 AutoPtr<CIMResponseMessage> response;
1289
1290 //
1291 // Get the provider information from the request
1292 //
1293 CIMInstance providerModule;
1294
1295 if ((dynamic_cast<CIMOperationRequestMessage*>(request) != 0) ||
1296 (dynamic_cast<CIMIndicationRequestMessage*>(request) != 0) ||
1297 (request->getType() == CIM_EXPORT_INDICATION_REQUEST_MESSAGE))
1298 kumpf 1.1 {
1299 // Provider information is in the OperationContext
1300 ProviderIdContainer pidc = (ProviderIdContainer)
1301 request->operationContext.get(ProviderIdContainer::NAME);
1302 providerModule = pidc.getModule();
1303 }
1304 else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
1305 {
1306 CIMEnableModuleRequestMessage* emReq =
1307 dynamic_cast<CIMEnableModuleRequestMessage*>(request);
1308 providerModule = emReq->providerModule;
1309 }
1310 else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
1311 {
1312 CIMDisableModuleRequestMessage* dmReq =
1313 dynamic_cast<CIMDisableModuleRequestMessage*>(request);
1314 providerModule = dmReq->providerModule;
1315 }
1316 else if ((request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE) ||
|
1317 carolann.graves 1.14 (request->getType() ==
1318 CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE) ||
|
1319 kumpf 1.1 (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE))
1320 {
1321 // This operation is not provider-specific
1322 }
1323 else
1324 {
1325 // Unrecognized message type. This should never happen.
1326 PEGASUS_ASSERT(0);
1327 response.reset(request->buildResponse());
1328 response->cimException = PEGASUS_CIM_EXCEPTION(
1329 CIM_ERR_FAILED, "Unrecognized message type.");
1330 PEG_METHOD_EXIT();
1331 return response.release();
1332 }
1333
1334 //
1335 // Process the request message
1336 //
1337 if (request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE)
1338 {
1339 // Forward the CIMStopAllProvidersRequest to all providers
1340 kumpf 1.1 response.reset(_forwardRequestToAllAgents(request));
1341
1342 // Note: Do not uninitialize the ProviderAgentContainers here.
1343 // Just let the selecting thread notice when the agent connections
1344 // are closed.
1345 }
|
1346 carolann.graves 1.14 else if (request->getType () ==
1347 CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE)
1348 {
1349 _subscriptionInitComplete = true;
1350
1351 //
1352 // Forward the CIMSubscriptionInitCompleteRequestMessage to
1353 // all providers
1354 //
1355 response.reset (_forwardRequestToAllAgents (request));
1356 }
|
1357 kumpf 1.1 else if (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE)
1358 {
1359 CIMNotifyConfigChangeRequestMessage* notifyRequest =
1360 dynamic_cast<CIMNotifyConfigChangeRequestMessage*>(request);
1361 PEGASUS_ASSERT(notifyRequest != 0);
1362
1363 if (notifyRequest->currentValueModified)
1364 {
1365 // Forward the CIMNotifyConfigChangeRequestMessage to all providers
1366 response.reset(_forwardRequestToAllAgents(request));
1367 }
1368 else
1369 {
1370 // No need to notify provider agents about changes to planned value
1371 response.reset(request->buildResponse());
1372 }
1373 }
|
1374 kumpf 1.6 else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
|
1375 kumpf 1.1 {
|
1376 kumpf 1.6 // Fan out the request to all Provider Agent processes for this module
1377
|
1378 kumpf 1.1 // Retrieve the provider module name
1379 String moduleName;
1380 CIMValue nameValue = providerModule.getProperty(
1381 providerModule.findProperty("Name")).getValue();
1382 nameValue.get(moduleName);
1383
|
1384 kumpf 1.6 // Look up the Provider Agents for this module
1385 Array<ProviderAgentContainer*> paArray =
1386 _lookupProviderAgents(moduleName);
|
1387 kumpf 1.1
|
1388 kumpf 1.6 for (Uint32 i=0; i<paArray.size(); i++)
|
1389 kumpf 1.1 {
1390 //
1391 // Do not start up an agent process just to disable the module
1392 //
|
1393 kumpf 1.6 if (paArray[i]->isInitialized())
1394 {
1395 //
1396 // Forward the request to the provider agent
1397 //
1398 response.reset(paArray[i]->processMessage(request));
1399
1400 // Note: Do not uninitialize the ProviderAgentContainer here
1401 // when a disable module operation is successful. Just let the
1402 // selecting thread notice when the agent connection is closed.
1403
1404 // Determine the success of the disable module operation
1405 CIMDisableModuleResponseMessage* dmResponse =
1406 dynamic_cast<CIMDisableModuleResponseMessage*>(
1407 response.get());
1408 PEGASUS_ASSERT(dmResponse != 0);
1409
1410 Boolean isStopped = false;
1411 for (Uint32 i=0; i < dmResponse->operationalStatus.size(); i++)
1412 {
1413 if (dmResponse->operationalStatus[i] ==
1414 kumpf 1.6 CIM_MSE_OPSTATUS_VALUE_STOPPED)
1415 {
1416 isStopped = true;
1417 break;
1418 }
1419 }
1420
1421 // If the operation is unsuccessful, stop and return the error
1422 if ((dmResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
1423 !isStopped)
1424 {
1425 break;
1426 }
1427 }
1428 }
1429
1430 // Use a default response if no Provider Agents were called
1431 if (!response.get())
1432 {
|
1433 kumpf 1.1 response.reset(request->buildResponse());
1434
1435 CIMDisableModuleResponseMessage* dmResponse =
1436 dynamic_cast<CIMDisableModuleResponseMessage*>(response.get());
1437 PEGASUS_ASSERT(dmResponse != 0);
1438
1439 Array<Uint16> operationalStatus;
1440 operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_STOPPED);
1441 dmResponse->operationalStatus = operationalStatus;
1442 }
|
1443 kumpf 1.6 }
1444 else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
1445 {
1446 // Fan out the request to all Provider Agent processes for this module
1447
1448 // Retrieve the provider module name
1449 String moduleName;
1450 CIMValue nameValue = providerModule.getProperty(
1451 providerModule.findProperty("Name")).getValue();
1452 nameValue.get(moduleName);
1453
1454 // Look up the Provider Agents for this module
1455 Array<ProviderAgentContainer*> paArray =
1456 _lookupProviderAgents(moduleName);
1457
1458 for (Uint32 i=0; i<paArray.size(); i++)
|
1459 kumpf 1.1 {
1460 //
1461 // Do not start up an agent process just to enable the module
1462 //
|
1463 kumpf 1.6 if (paArray[i]->isInitialized())
1464 {
1465 //
1466 // Forward the request to the provider agent
1467 //
1468 response.reset(paArray[i]->processMessage(request));
1469
1470 // Determine the success of the enable module operation
1471 CIMEnableModuleResponseMessage* emResponse =
1472 dynamic_cast<CIMEnableModuleResponseMessage*>(
1473 response.get());
1474 PEGASUS_ASSERT(emResponse != 0);
1475
1476 Boolean isOk = false;
1477 for (Uint32 i=0; i < emResponse->operationalStatus.size(); i++)
1478 {
1479 if (emResponse->operationalStatus[i] ==
1480 CIM_MSE_OPSTATUS_VALUE_OK)
1481 {
1482 isOk = true;
1483 break;
1484 kumpf 1.6 }
1485 }
1486
1487 // If the operation is unsuccessful, stop and return the error
1488 if ((emResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
1489 !isOk)
1490 {
1491 break;
1492 }
1493 }
1494 }
1495
1496 // Use a default response if no Provider Agents were called
1497 if (!response.get())
1498 {
|
1499 kumpf 1.1 response.reset(request->buildResponse());
1500
1501 CIMEnableModuleResponseMessage* emResponse =
1502 dynamic_cast<CIMEnableModuleResponseMessage*>(response.get());
1503 PEGASUS_ASSERT(emResponse != 0);
1504
1505 Array<Uint16> operationalStatus;
1506 operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_OK);
1507 emResponse->operationalStatus = operationalStatus;
1508 }
|
1509 kumpf 1.6 }
1510 else
1511 {
1512 // Retrieve the provider module name
1513 String moduleName;
1514 CIMValue nameValue = providerModule.getProperty(
1515 providerModule.findProperty("Name")).getValue();
1516 nameValue.get(moduleName);
1517
1518 // Retrieve the provider user context configuration
1519 Uint16 userContext = 0;
1520 Uint32 pos = providerModule.findProperty(
1521 PEGASUS_PROPERTYNAME_MODULE_USERCONTEXT);
1522 if (pos != PEG_NOT_FOUND)
1523 {
|
1524 kumpf 1.12 CIMValue userContextValue =
1525 providerModule.getProperty(pos).getValue();
1526 if (!userContextValue.isNull())
1527 {
1528 userContextValue.get(userContext);
1529 }
|
1530 kumpf 1.6 }
1531
1532 if (userContext == 0)
1533 {
1534 userContext = PG_PROVMODULE_USERCTXT_PRIVILEGED;
1535 }
1536
1537 String userName;
1538
1539 if (userContext == PG_PROVMODULE_USERCTXT_REQUESTOR)
|
1540 kumpf 1.1 {
|
1541 kumpf 1.6 try
1542 {
1543 // User Name is in the OperationContext
1544 IdentityContainer ic = (IdentityContainer)
1545 request->operationContext.get(IdentityContainer::NAME);
1546 userName = ic.getUserName();
1547 }
1548 catch (Exception& e)
1549 {
1550 // If no IdentityContainer is present, default to the CIM
1551 // Server's user context
1552 }
|
1553 kumpf 1.1
|
1554 kumpf 1.6 // If authentication is disabled, use the CIM Server's user context
1555 if (!userName.size())
1556 {
1557 userName = System::getEffectiveUserName();
1558 }
1559 }
1560 else if (userContext == PG_PROVMODULE_USERCTXT_DESIGNATED)
1561 {
1562 // Retrieve the provider module name
1563 providerModule.getProperty(providerModule.findProperty(
1564 PEGASUS_PROPERTYNAME_MODULE_DESIGNATEDUSER)).getValue().
1565 get(userName);
1566 }
1567 else if (userContext == PG_PROVMODULE_USERCTXT_CIMSERVER)
1568 {
1569 userName = System::getEffectiveUserName();
1570 }
1571 else // Privileged User
1572 {
1573 PEGASUS_ASSERT(userContext == PG_PROVMODULE_USERCTXT_PRIVILEGED);
1574 userName = System::getPrivilegedUserName();
|
1575 kumpf 1.1 }
|
1576 kumpf 1.6
1577 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1578 "Module name = " + moduleName);
1579 Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1580 "User context = %hd.", userContext);
1581 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1582 "User name = " + userName);
1583
1584 // Look up the Provider Agent for this module and user
1585 ProviderAgentContainer* pa = _lookupProviderAgent(moduleName, userName);
1586 PEGASUS_ASSERT(pa != 0);
1587
1588 //
1589 // Forward the request to the provider agent
1590 //
1591 response.reset(pa->processMessage(request));
|
1592 kumpf 1.1 }
1593
1594 response->syncAttributes(request);
1595
1596 PEG_METHOD_EXIT();
1597 return response.release();
1598 }
1599
1600 ProviderAgentContainer* OOPProviderManagerRouter::_lookupProviderAgent(
|
1601 kumpf 1.6 const String& moduleName,
1602 const String& userName)
|
1603 kumpf 1.1 {
1604 ProviderAgentContainer* pa = 0;
|
1605 kumpf 1.6 String key = moduleName + ":" + userName;
|
1606 kumpf 1.1
1607 AutoMutex lock(_providerAgentTableMutex);
|
1608 kumpf 1.6 if (!_providerAgentTable.lookup(key, pa))
|
1609 kumpf 1.1 {
|
1610 kumpf 1.6 pa = new ProviderAgentContainer(
|
1611 carolann.graves 1.14 moduleName, userName, _indicationCallback,
1612 _subscriptionInitComplete);
|
1613 kumpf 1.6 _providerAgentTable.insert(key, pa);
|
1614 kumpf 1.1 }
1615 return pa;
1616 }
1617
|
1618 kumpf 1.6 Array<ProviderAgentContainer*> OOPProviderManagerRouter::_lookupProviderAgents(
1619 const String& moduleName)
1620 {
1621 Array<ProviderAgentContainer*> paArray;
1622
1623 AutoMutex lock(_providerAgentTableMutex);
1624 for (ProviderAgentTable::Iterator i = _providerAgentTable.start(); i; i++)
1625 {
1626 if (i.value()->getModuleName() == moduleName)
1627 {
1628 paArray.append(i.value());
1629 }
1630 }
1631 return paArray;
1632 }
1633
|
1634 kumpf 1.1 CIMResponseMessage* OOPProviderManagerRouter::_forwardRequestToAllAgents(
1635 CIMRequestMessage* request)
1636 {
1637 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1638 "OOPProviderManagerRouter::_forwardRequestToAllAgents");
1639
1640 // Get a list of the ProviderAgentContainers. We need our own array copy
1641 // because we cannot hold the _providerAgentTableMutex while calling
1642 // _ProviderAgentContainer::processMessage().
1643 Array<ProviderAgentContainer*> paContainerArray;
1644 {
1645 AutoMutex tableLock(_providerAgentTableMutex);
1646 for (ProviderAgentTable::Iterator i = _providerAgentTable.start();
1647 i != 0; i++)
1648 {
1649 paContainerArray.append(i.value());
1650 }
1651 }
1652
1653 CIMException responseException;
1654
1655 kumpf 1.1 // Forward the request to each of the initialized provider agents
1656 for (Uint32 j = 0; j < paContainerArray.size(); j++)
1657 {
1658 ProviderAgentContainer* pa = paContainerArray[j];
1659 if (pa->isInitialized())
1660 {
1661 // Note: The ProviderAgentContainer could become uninitialized
1662 // before _ProviderAgentContainer::processMessage() processes
1663 // this request. In this case, the Provider Agent process will
1664 // (unfortunately) be started to process this message.
1665 AutoPtr<CIMResponseMessage> response;
1666 response.reset(pa->processMessage(request));
1667 if (response.get() != 0)
1668 {
1669 // If the operation failed, save the exception data
1670 if ((response->cimException.getCode() != CIM_ERR_SUCCESS) &&
1671 (responseException.getCode() == CIM_ERR_SUCCESS))
1672 {
1673 responseException = response->cimException;
1674 }
1675 }
1676 kumpf 1.1 }
1677 }
1678
1679 CIMResponseMessage* response = request->buildResponse();
1680 response->cimException = responseException;
1681
1682 PEG_METHOD_EXIT();
1683 return response;
1684 }
1685
1686 Boolean OOPProviderManagerRouter::hasActiveProviders()
1687 {
1688 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1689 "OOPProviderManagerRouter::hasActiveProviders");
1690
1691 // Iterate through the _providerAgentTable looking for initialized agents
1692 AutoMutex lock(_providerAgentTableMutex);
1693 ProviderAgentTable::Iterator i = _providerAgentTable.start();
1694 for(; i != 0; i++)
1695 {
1696 if (i.value()->isInitialized())
1697 kumpf 1.1 {
1698 PEG_METHOD_EXIT();
1699 return true;
1700 }
1701 }
1702
1703 // No initialized Provider Agents were found
1704 PEG_METHOD_EXIT();
1705 return false;
1706 }
1707
1708 void OOPProviderManagerRouter::unloadIdleProviders()
1709 {
1710 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1711 "OOPProviderManagerRouter::unloadIdleProviders");
1712
1713 // Iterate through the _providerAgentTable unloading idle providers
1714 AutoMutex lock(_providerAgentTableMutex);
1715 ProviderAgentTable::Iterator i = _providerAgentTable.start();
1716 for(; i != 0; i++)
1717 {
1718 kumpf 1.1 i.value()->unloadIdleProviders();
1719 }
1720
1721 PEG_METHOD_EXIT();
1722 }
1723
1724 PEGASUS_NAMESPACE_END
|