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