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