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