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