1 karl 1.5 //%2004////////////////////////////////////////////////////////////////////////
|
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 kumpf 1.1 //
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to
12 // deal in the Software without restriction, including without limitation the
13 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
14 // sell copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
|
16 karl 1.5 //
|
17 kumpf 1.1 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
18 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
19 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
20 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
21 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 //
26 //==============================================================================
27 //
28 // Author: Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
29 // Jenny Yu, Hewlett-Packard Company (jenny_yu@hp.com)
30 //
31 // Modified By:
32 //
33 //%/////////////////////////////////////////////////////////////////////////////
34
35 #include <Pegasus/Common/Config.h>
36 #include <Pegasus/Common/Constants.h>
37 #include <Pegasus/Common/AutoPtr.h>
38 kumpf 1.1 #include <Pegasus/Common/ArrayInternal.h>
39 #include <Pegasus/Common/CIMMessage.h>
40 #include <Pegasus/Common/CIMMessageSerializer.h>
41 #include <Pegasus/Common/CIMMessageDeserializer.h>
42 #include <Pegasus/Common/OperationContextInternal.h>
43 #include <Pegasus/Common/System.h>
44 #include <Pegasus/Common/AnonymousPipe.h>
45 #include <Pegasus/Common/Tracer.h>
46 #include <Pegasus/Common/Logger.h>
47 #include <Pegasus/Common/Thread.h>
48 #include <Pegasus/Common/MessageQueueService.h>
49 #include <Pegasus/Config/ConfigManager.h>
50
51 #if defined (PEGASUS_OS_TYPE_WINDOWS)
52 #include <windows.h> // For CreateProcess()
53 #else
54 # if defined (PEGASUS_OS_OS400)
55 # include <unistd.cleinc>
56 # else
57 # include <unistd.h> // For fork(), exec(), and _exit()
58 # endif
59 kumpf 1.1 #include <errno.h>
60 #endif
61
62 #include "OOPProviderManagerRouter.h"
63
64 PEGASUS_USING_STD;
65
66 PEGASUS_NAMESPACE_BEGIN
67
68 /////////////////////////////////////////////////////////////////////////////
69 // OutstandingRequestTable and OutstandingRequestEntry
70 /////////////////////////////////////////////////////////////////////////////
71
72 /**
73 An OutstandingRequestEntry represents a request message sent to a
74 Provider Agent for which no response has been received. The request
75 sender provides the message ID and a location for the response to be
76 returned, and then waits on the semaphore. When a response matching
77 the message ID is received, it is placed into the specified location
78 and the semaphore is signaled.
79 */
80 kumpf 1.1 class OutstandingRequestEntry
81 {
82 public:
83 OutstandingRequestEntry(
84 String messageId_,
85 CIMResponseMessage*& responseMessage_,
86 Semaphore* responseReady_)
87 : messageId(messageId_),
88 responseMessage(responseMessage_),
89 responseReady(responseReady_)
90 {
91 }
92
93 String messageId;
94 CIMResponseMessage*& responseMessage;
95 Semaphore* responseReady;
96 };
97
98 typedef HashTable<String, OutstandingRequestEntry*, EqualFunc<String>,
99 HashFunc<String> > OutstandingRequestTable;
100
101 kumpf 1.1
102 /////////////////////////////////////////////////////////////////////////////
103 // ProviderAgentContainer
104 /////////////////////////////////////////////////////////////////////////////
105
106 class ProviderAgentContainer
107 {
108 public:
109 ProviderAgentContainer(
110 const String & moduleName,
111 PEGASUS_INDICATION_CALLBACK indicationCallback);
112
113 ~ProviderAgentContainer();
114
115 Boolean isInitialized();
116
117 CIMResponseMessage* processMessage(CIMRequestMessage* request);
118 void unloadIdleProviders();
119
120 private:
121 //
122 kumpf 1.1 // Private methods
123 //
124
125 /** Unimplemented */
126 ProviderAgentContainer();
127 /** Unimplemented */
128 ProviderAgentContainer(const ProviderAgentContainer& pa);
129 /** Unimplemented */
130 ProviderAgentContainer& operator=(const ProviderAgentContainer& pa);
131
132 /**
133 Start a Provider Agent process and establish a pipe connection with it.
134 Note: The caller must lock the _agentMutex.
135 */
136 void _startAgentProcess();
137
138 /**
139 Send initialization data to the Provider Agent.
140 Note: The caller must lock the _agentMutex.
141 */
142 void _sendInitializationData();
143 kumpf 1.1
144 /**
145 Initialize the ProviderAgentContainer if it is not already
146 initialized. Initialization includes starting the Provider Agent
147 process, establishing a pipe connection with it, and starting a
148 thread to read response messages from the Provider Agent.
149
150 Note: The caller must lock the _agentMutex.
151 */
152 void _initialize();
153
154 /**
155 Uninitialize the ProviderAgentContainer if it is initialized.
156 The connection is closed and outstanding requests are completed
157 with an error result.
158
159 Note: The caller must lock the _agentMutex.
160 */
161 void _uninitialize();
162
163 /**
164 kumpf 1.1 Read and process response messages from the Provider Agent until
165 the connection is closed.
166 */
167 void _processResponses();
168 static PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL
169 _responseProcessor(void* arg);
170
171 //
172 // Private data
173 //
174
175 /**
176 The _agentMutex must be locked whenever writing to the Provider
177 Agent connection, accessing the _isInitialized flag, or changing
178 the Provider Agent state.
179 */
180 Mutex _agentMutex;
181
182 /**
183 Name of the provider module served by this Provider Agent.
184 */
185 kumpf 1.1 String _moduleName;
186
187 /**
188 Callback function to which all generated indications are sent for
189 processing.
190 */
191 PEGASUS_INDICATION_CALLBACK _indicationCallback;
192
193 /**
194 Indicates whether the Provider Agent is active.
195 */
196 Boolean _isInitialized;
197
198 /**
199 Pipe connection used to read responses from the Provider Agent.
200 */
201 AutoPtr<AnonymousPipe> _pipeFromAgent;
202 /**
203 Pipe connection used to write requests to the Provider Agent.
204 */
205 AutoPtr<AnonymousPipe> _pipeToAgent;
206 kumpf 1.1
207 /**
208 The _outstandingRequestTable holds an entry for each request that has
209 been sent to this Provider Agent for which no response has been
210 received. Entries are added (by the writing thread) when a request
211 is sent, and are removed (by the reading thread) when the response is
212 received (or when it is determined that no response is forthcoming).
213 */
214 OutstandingRequestTable _outstandingRequestTable;
215 /**
216 The _outstandingRequestTableMutex must be locked whenever reading or
217 updating the _outstandingRequestTable.
218 */
219 Mutex _outstandingRequestTableMutex;
|
220 kumpf 1.2
221 /**
222 Holds the last provider module instance sent to the Provider Agent in
223 a ProviderIdContainer. Since the provider module instance rarely
224 changes, an optimization is used to send it only when it differs from
225 the last provider module instance sent.
226 */
227 CIMInstance _providerModuleCache;
|
228 kumpf 1.1 };
229
230 ProviderAgentContainer::ProviderAgentContainer(
231 const String & moduleName,
232 PEGASUS_INDICATION_CALLBACK indicationCallback)
233 : _moduleName(moduleName),
234 _indicationCallback(indicationCallback),
235 _isInitialized(false)
236 {
237 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
238 "ProviderAgentContainer::ProviderAgentContainer");
239 PEG_METHOD_EXIT();
240 }
241
242 ProviderAgentContainer::~ProviderAgentContainer()
243 {
244 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
245 "ProviderAgentContainer::~ProviderAgentContainer");
246
247 // Ensure the destructor does not throw an exception
248 try
249 kumpf 1.1 {
250 // Stop the responseProcessor thread by closing its connection
251 _pipeFromAgent->closeReadHandle();
252
253 // Wait for the responseProcessor thread to exit
254 while (isInitialized())
255 {
256 pegasus_yield();
257 }
258 }
259 catch (...)
260 {
261 }
262
263 PEG_METHOD_EXIT();
264 }
265
266 void ProviderAgentContainer::_startAgentProcess()
267 {
268 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
269 "ProviderAgentContainer::_startAgentProcess");
270 kumpf 1.1
271 AutoPtr<AnonymousPipe> pipeFromAgent(new AnonymousPipe());
272 AutoPtr<AnonymousPipe> pipeToAgent(new AnonymousPipe());
273
274 //
275 // Start a cimprovagt process for this provider module
276 //
277
278 #if defined (PEGASUS_OS_TYPE_WINDOWS)
279 //
280 // Set up members of the PROCESS_INFORMATION structure
281 //
282 PROCESS_INFORMATION piProcInfo;
283 ZeroMemory (&piProcInfo, sizeof (PROCESS_INFORMATION));
284
285 //
286 // Set up members of the STARTUPINFO structure
287 //
288 STARTUPINFO siStartInfo;
289 ZeroMemory (&siStartInfo, sizeof (STARTUPINFO));
290 siStartInfo.cb = sizeof (STARTUPINFO);
291 kumpf 1.1
292 //
293 // Generate the command line
294 //
295 char cmdLine[2048];
296 char readHandle[32];
297 char writeHandle[32];
298 pipeToAgent->exportReadHandle(readHandle);
299 pipeFromAgent->exportWriteHandle(writeHandle);
300
301 sprintf(cmdLine, "\"%s\" %s %s \"%s\"",
302 (const char*)ConfigManager::getHomedPath(
303 PEGASUS_PROVIDER_AGENT_PROC_NAME).getCString(),
304 readHandle, writeHandle, (const char*)_moduleName.getCString());
305
306 //
307 // Create the child process
308 //
309 if (!CreateProcess (
310 NULL, //
311 cmdLine, // command line
312 kumpf 1.1 NULL, // process security attributes
313 NULL, // primary thread security attributes
314 TRUE, // handles are inherited
315 0, // creation flags
316 NULL, // use parent's environment
317 NULL, // use parent's current directory
318 &siStartInfo, // STARTUPINFO
319 &piProcInfo)) // PROCESS_INFORMATION
320 {
321 Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
322 "CreateProcess() failed. errno = %d.", GetLastError());
323 PEG_METHOD_EXIT();
324 throw Exception(MessageLoaderParms(
325 "ProviderManager.OOPProviderManagerRouter.CIMPROVAGT_START_FAILED",
326 "Failed to start cimprovagt \"$0\".",
327 _moduleName));
328 }
329
330 CloseHandle(piProcInfo.hProcess);
331 CloseHandle(piProcInfo.hThread);
332 #else
333 kumpf 1.1 pid_t pid = fork();
334 if (pid < 0)
335 {
336 Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
337 "fork() failed. errno = %d.", errno);
338 PEG_METHOD_EXIT();
339 throw Exception(MessageLoaderParms(
340 "ProviderManager.OOPProviderManagerRouter.CIMPROVAGT_START_FAILED",
341 "Failed to start cimprovagt \"$0\".",
342 _moduleName));
343 }
344 else if (pid == 0)
345 {
346 //
347 // Child side of the fork
348 //
349
350 try
351 {
352 // Close our copies of the parent's ends of the pipes
353 pipeToAgent->closeWriteHandle();
354 kumpf 1.1 pipeFromAgent->closeReadHandle();
355
356 //
357 // Execute the cimprovagt program
358 //
359 String agentCommandPath =
360 ConfigManager::getHomedPath(PEGASUS_PROVIDER_AGENT_PROC_NAME);
361 CString agentCommandPathCString = agentCommandPath.getCString();
362
363 char readHandle[32];
364 char writeHandle[32];
365 pipeToAgent->exportReadHandle(readHandle);
366 pipeFromAgent->exportWriteHandle(writeHandle);
367
368 execl(agentCommandPathCString, agentCommandPathCString,
369 readHandle, writeHandle,
370 (const char*)_moduleName.getCString(), (char*)0);
371
372 // If we're still here, there was an error
373 Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
374 "execl() failed. errno = %d.", errno);
375 kumpf 1.1 _exit(1);
376 }
377 catch (...)
378 {
379 // There's not much we can do here in no man's land
380 try
381 {
382 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
383 "Caught exception before calling execl().");
384 }
385 catch (...) {}
386 _exit(1);
387 }
388 }
389 #endif
390
391 //
392 // CIM Server process
393 //
394
395 // Close our copies of the agent's ends of the pipes
396 kumpf 1.1 pipeToAgent->closeReadHandle();
397 pipeFromAgent->closeWriteHandle();
398
399 _pipeToAgent.reset(pipeToAgent.release());
400 _pipeFromAgent.reset(pipeFromAgent.release());
401
402 PEG_METHOD_EXIT();
403 }
404
405 // Note: Caller must lock _agentMutex
406 void ProviderAgentContainer::_sendInitializationData()
407 {
408 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
409 "ProviderAgentContainer::_sendInitializationData");
410
411 //
412 // Gather config properties to pass to the Provider Agent
413 //
414 ConfigManager* configManager = ConfigManager::getInstance();
415 Array<Pair<String, String> > configProperties;
416
417 kumpf 1.1 Array<String> configPropertyNames;
418 configManager->getAllPropertyNames(configPropertyNames, true);
419 for (Uint32 i = 0; i < configPropertyNames.size(); i++)
420 {
421 String configPropertyValue =
422 configManager->getCurrentValue(configPropertyNames[i]);
423 String configPropertyDefaultValue =
424 configManager->getDefaultValue(configPropertyNames[i]);
425 if (configPropertyValue != configPropertyDefaultValue)
426 {
427 configProperties.append(Pair<String, String>(
428 configPropertyNames[i], configPropertyValue));
429 }
430 }
431
432 //
433 // Create a Provider Agent initialization message
434 //
435 AutoPtr<CIMInitializeProviderAgentRequestMessage> request(
436 new CIMInitializeProviderAgentRequestMessage(
437 String("0"), // messageId
438 kumpf 1.1 configManager->getPegasusHome(),
439 configProperties,
440 System::bindVerbose,
441 QueueIdStack()));
442
443 //
444 // Write the initialization message to the pipe
445 //
446 AnonymousPipe::Status writeStatus =
447 _pipeToAgent->writeMessage(request.get());
448
449 if (writeStatus != AnonymousPipe::STATUS_SUCCESS)
450 {
451 PEG_METHOD_EXIT();
452 throw Exception(MessageLoaderParms(
453 "ProviderManager.OOPProviderManagerRouter."
454 "CIMPROVAGT_COMMUNICATION_FAILED",
455 "Failed to communicate with cimprovagt \"$0\".",
456 _moduleName));
457 }
458
459 kumpf 1.1 // Do not wait for a response from the Provider Agent. (It isn't coming.)
460
461 PEG_METHOD_EXIT();
462 }
463
464 // Note: Caller must lock _agentMutex
465 void ProviderAgentContainer::_initialize()
466 {
467 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
468 "ProviderAgentContainer::_initialize");
469
470 if (_isInitialized)
471 {
472 PEGASUS_ASSERT(0);
473 PEG_METHOD_EXIT();
474 return;
475 }
476
477 try
478 {
479 _startAgentProcess();
480 kumpf 1.1
481 _sendInitializationData();
482
483 _isInitialized = true;
484
485 // Start a thread to read and process responses from the Provider Agent
486 while (!MessageQueueService::get_thread_pool()->allocate_and_awaken(
487 this, _responseProcessor))
488 {
489 pegasus_yield();
490 }
491 }
492 catch (...)
493 {
494 _isInitialized = false;
495 _pipeToAgent.reset();
496 _pipeFromAgent.reset();
497 PEG_METHOD_EXIT();
498 throw;
499 }
500
501 kumpf 1.1 PEG_METHOD_EXIT();
502 }
503
504 Boolean ProviderAgentContainer::isInitialized()
505 {
506 AutoMutex lock(_agentMutex);
507 return _isInitialized;
508 }
509
510 // Note: Caller must lock _agentMutex
511 void ProviderAgentContainer::_uninitialize()
512 {
513 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
514 "ProviderAgentContainer::_uninitialize");
515
516 if (!_isInitialized)
517 {
518 PEGASUS_ASSERT(0);
519 PEG_METHOD_EXIT();
520 return;
521 }
522 kumpf 1.1
523 try
524 {
525 // Close the connection with the Provider Agent
526 _pipeFromAgent.reset();
527 _pipeToAgent.reset();
528
|
529 kumpf 1.2 _providerModuleCache = CIMInstance();
530
|
531 kumpf 1.1 _isInitialized = false;
532
533 //
534 // Complete with null responses all outstanding requests on this
535 // connection
536 //
537 {
538 AutoMutex tableLock(_outstandingRequestTableMutex);
539
540 for (OutstandingRequestTable::Iterator i =
541 _outstandingRequestTable.start();
542 i != 0; i++)
543 {
544 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
545 String("Completing messageId \"") + i.value()->messageId +
546 "\" with a null response.");
547 i.value()->responseMessage = 0;
548 i.value()->responseReady->signal();
549 }
550
551 _outstandingRequestTable.clear();
552 kumpf 1.1 }
553 }
554 catch (...)
555 {
556 // We're uninitializing, so do not propagate the exception
557 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
558 "Ignoring _uninitialize() exception.");
559 }
560
561 PEG_METHOD_EXIT();
562 }
563
564 CIMResponseMessage* ProviderAgentContainer::processMessage(
565 CIMRequestMessage* request)
566 {
567 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
568 "ProviderAgentContainer::processMessage");
569
570 CIMResponseMessage* response;
571 String originalMessageId = request->messageId;
572
|
573 kumpf 1.2 // These three variables are used for the provider module optimization.
574 // See the _providerModuleCache member description for more information.
575 AutoPtr<ProviderIdContainer> origProviderId;
576 Boolean doProviderModuleOptimization = false;
577 Boolean updateProviderModuleCache = false;
578
|
579 kumpf 1.1 try
580 {
581 // The messageId attribute is used to correlate response messages
582 // from the Provider Agent with request messages, so it is imperative
583 // that the ID is unique for each request. The incoming ID cannot be
584 // trusted to be unique, so we substitute a unique one. The memory
585 // address of the request is used as the source of a unique piece of
586 // data. (The message ID is only required to be unique while the
587 // request is outstanding.)
588 char messagePtrString[20];
589 sprintf(messagePtrString, "%p", request);
590 String uniqueMessageId = messagePtrString;
591
592 //
593 // Set up the OutstandingRequestEntry for this request
594 //
595 Semaphore waitSemaphore(0);
596 OutstandingRequestEntry outstandingRequestEntry(
597 uniqueMessageId, response, &waitSemaphore);
598
599 //
600 kumpf 1.1 // Lock the Provider Agent Container while initializing the
601 // agent and writing the request to the connection
602 //
603 {
604 AutoMutex lock(_agentMutex);
605
606 //
607 // Initialize the Provider Agent, if necessary
608 //
609 if (!_isInitialized)
610 {
611 _initialize();
612 }
613
614 //
615 // Add an entry to the OutstandingRequestTable for this request
616 //
617 {
618 AutoMutex tableLock(_outstandingRequestTableMutex);
619
620 _outstandingRequestTable.insert(
621 kumpf 1.1 uniqueMessageId, &outstandingRequestEntry);
622 }
623
|
624 kumpf 1.2 // Get the provider module from the ProviderIdContainer to see if
625 // we can optimize out the transmission of this instance to the
626 // Provider Agent. (See the _providerModuleCache description.)
627 try
628 {
629 ProviderIdContainer pidc = request->operationContext.get(
630 ProviderIdContainer::NAME);
631 origProviderId.reset(new ProviderIdContainer(
632 pidc.getModule(), pidc.getProvider(),
633 pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
634 if (_providerModuleCache.isUninitialized() ||
635 (!pidc.getModule().identical(_providerModuleCache)))
636 {
637 // We haven't sent this provider module instance to the
638 // Provider Agent yet. Update our cache after we send it.
639 updateProviderModuleCache = true;
640 }
641 else
642 {
643 // Replace the provider module in the ProviderIdContainer
644 // with an uninitialized instance. We'll need to put the
645 kumpf 1.2 // original one back after the message is sent.
646 request->operationContext.set(ProviderIdContainer(
647 CIMInstance(), pidc.getProvider(),
648 pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
649 doProviderModuleOptimization = true;
650 }
651 }
652 catch (...)
653 {
654 // No ProviderIdContainer to optimize
655 }
656
|
657 kumpf 1.1 //
658 // Write the message to the pipe
659 //
660 try
661 {
662 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL3,
663 String("Sending request to agent with messageId ") +
664 uniqueMessageId);
665
666 request->messageId = uniqueMessageId;
667 AnonymousPipe::Status writeStatus =
668 _pipeToAgent->writeMessage(request);
669 request->messageId = originalMessageId;
670
|
671 kumpf 1.2 if (doProviderModuleOptimization)
672 {
673 request->operationContext.set(*origProviderId.get());
674 }
675
|
676 kumpf 1.1 if (writeStatus != AnonymousPipe::STATUS_SUCCESS)
677 {
678 Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
679 "Failed to write message to pipe. writeStatus = %d.",
680 writeStatus);
681 throw Exception(MessageLoaderParms(
682 "ProviderManager.OOPProviderManagerRouter."
683 "CIMPROVAGT_COMMUNICATION_FAILED",
684 "Failed to communicate with cimprovagt \"$0\".",
685 _moduleName));
686 }
|
687 kumpf 1.2
688 if (updateProviderModuleCache)
689 {
690 _providerModuleCache = origProviderId->getModule();
691 }
|
692 kumpf 1.1 }
693 catch (...)
694 {
695 request->messageId = originalMessageId;
|
696 kumpf 1.2
697 if (doProviderModuleOptimization)
698 {
699 request->operationContext.set(*origProviderId.get());
700 }
701
|
702 kumpf 1.1 Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
703 "Failed to write message to pipe.");
704 // Remove the OutstandingRequestTable entry for this request
705 {
706 AutoMutex tableLock(_outstandingRequestTableMutex);
707 Boolean removed =
708 _outstandingRequestTable.remove(uniqueMessageId);
709 PEGASUS_ASSERT(removed);
710 }
711 throw;
712 }
713 }
714
715 //
716 // Wait for the response
717 //
718 try
719 {
720 // Must not hold _agentMutex while waiting for the response
721 waitSemaphore.wait();
722 }
723 kumpf 1.1 catch (...)
724 {
725 // Remove the OutstandingRequestTable entry for this request
726 {
727 AutoMutex tableLock(_outstandingRequestTableMutex);
728 Boolean removed =
729 _outstandingRequestTable.remove(uniqueMessageId);
730 PEGASUS_ASSERT(removed);
731 }
732 throw;
733 }
734
735 // A null response is returned when an agent connection is closed
736 // while requests remain outstanding.
737 if (response == 0)
738 {
739 response = request->buildResponse();
740 response->cimException = PEGASUS_CIM_EXCEPTION(
741 CIM_ERR_FAILED,
742 MessageLoaderParms(
743 "ProviderManager.OOPProviderManagerRouter."
744 kumpf 1.1 "CIMPROVAGT_CONNECTION_LOST",
745 "Lost connection with cimprovagt \"$0\".",
746 _moduleName));
747 }
748 }
749 catch (CIMException& e)
750 {
751 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
752 String("Caught exception: ") + e.getMessage());
753 response = request->buildResponse();
754 response->cimException = e;
755 }
756 catch (Exception& e)
757 {
758 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
759 String("Caught exception: ") + e.getMessage());
760 response = request->buildResponse();
761 response->cimException = PEGASUS_CIM_EXCEPTION(
762 CIM_ERR_FAILED, e.getMessage());
763 }
764 catch (...)
765 kumpf 1.1 {
766 PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
767 "Caught unknown exception");
768 response = request->buildResponse();
769 response->cimException = PEGASUS_CIM_EXCEPTION(
770 CIM_ERR_FAILED, String::EMPTY);
771 }
772
773 response->messageId = originalMessageId;
774
775 PEG_METHOD_EXIT();
776 return response;
777 }
778
779 void ProviderAgentContainer::unloadIdleProviders()
780 {
781 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
|
782 carolann.graves 1.4 "ProviderAgentContainer::unloadIdleProviders");
|
783 kumpf 1.1
784 AutoMutex lock(_agentMutex);
785 if (_isInitialized)
786 {
787 // Send a "wake up" message to the Provider Agent.
788 // Don't bother checking whether the operation is successful.
789 Uint32 messageLength = 0;
790 _pipeToAgent->writeBuffer((const char*)&messageLength, sizeof(Uint32));
791 }
792
793 PEG_METHOD_EXIT();
794 }
795
796 void ProviderAgentContainer::_processResponses()
797 {
798 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
799 "ProviderAgentContainer::_processResponses");
800
801 //
802 // Process responses until the pipe is closed
803 //
804 kumpf 1.1 while (1)
805 {
806 try
807 {
808 CIMMessage* message;
809
810 //
811 // Read a response from the Provider Agent
812 //
813 AnonymousPipe::Status readStatus =
814 _pipeFromAgent->readMessage(message);
815
816 // Ignore interrupts
817 if (readStatus == AnonymousPipe::STATUS_INTERRUPT)
818 {
819 continue;
820 }
821
822 // Handle an error the same way as a closed connection
823 if ((readStatus == AnonymousPipe::STATUS_ERROR) ||
824 (readStatus == AnonymousPipe::STATUS_CLOSED))
825 kumpf 1.1 {
826 AutoMutex lock(_agentMutex);
827 _uninitialize();
828 return;
829 }
830
831 if (message->getType() == CIM_PROCESS_INDICATION_REQUEST_MESSAGE)
832 {
833 // Forward indications to the indication callback
834 _indicationCallback(
835 reinterpret_cast<CIMProcessIndicationRequestMessage*>(
836 message));
837 }
838 else
839 {
840 CIMResponseMessage* response;
841 response = dynamic_cast<CIMResponseMessage*>(message);
842 PEGASUS_ASSERT(response != 0);
843
844 // Give the response to the waiting OutstandingRequestEntry
845 OutstandingRequestEntry* _outstandingRequestEntry = 0;
846 kumpf 1.1 {
847 AutoMutex tableLock(_outstandingRequestTableMutex);
848 Boolean foundEntry = _outstandingRequestTable.lookup(
849 response->messageId, _outstandingRequestEntry);
850 PEGASUS_ASSERT(foundEntry);
851
852 // Remove the completed request from the table
853 Boolean removed =
854 _outstandingRequestTable.remove(response->messageId);
855 PEGASUS_ASSERT(removed);
856 }
857
858 _outstandingRequestEntry->responseMessage = response;
859 _outstandingRequestEntry->responseReady->signal();
860 }
861 }
862 catch (Exception& e)
863 {
864 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
865 String("Ignoring exception: ") + e.getMessage());
866 }
867 kumpf 1.1 catch (...)
868 {
869 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
870 "Ignoring exception");
871 }
872 }
873
874 PEG_METHOD_EXIT();
875 }
876
877 PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL
878 ProviderAgentContainer::_responseProcessor(void* arg)
879 {
880 ProviderAgentContainer* pa =
881 reinterpret_cast<ProviderAgentContainer*>(arg);
882
883 pa->_processResponses();
884
885 return(PEGASUS_THREAD_RETURN(0));
886 }
887
888 kumpf 1.1 /////////////////////////////////////////////////////////////////////////////
889 // OOPProviderManagerRouter
890 /////////////////////////////////////////////////////////////////////////////
891
892 OOPProviderManagerRouter::OOPProviderManagerRouter(
893 PEGASUS_INDICATION_CALLBACK indicationCallback)
894 {
895 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
896 "OOPProviderManagerRouter::OOPProviderManagerRouter");
897
898 _indicationCallback = indicationCallback;
899
900 PEG_METHOD_EXIT();
901 }
902
903 OOPProviderManagerRouter::~OOPProviderManagerRouter()
904 {
905 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
906 "OOPProviderManagerRouter::~OOPProviderManagerRouter");
907
908 try
909 kumpf 1.1 {
910 // Clean up the ProviderAgentContainers
911 AutoMutex lock(_providerAgentTableMutex);
912 ProviderAgentTable::Iterator i = _providerAgentTable.start();
913 for(; i != 0; i++)
914 {
915 delete i.value();
916 }
917 }
918 catch (...) {}
919
920 PEG_METHOD_EXIT();
921 }
922
923 // Private, unimplemented constructor
924 OOPProviderManagerRouter::OOPProviderManagerRouter()
925 {
926 }
927
928 // Private, unimplemented constructor
929 OOPProviderManagerRouter::OOPProviderManagerRouter(
930 kumpf 1.1 const OOPProviderManagerRouter&)
|
931 david.dillard 1.3 : ProviderManagerRouter(*this)
|
932 kumpf 1.1 {
933 }
934
935 // Private, unimplemented assignment operator
936 OOPProviderManagerRouter& OOPProviderManagerRouter::operator=(
937 const OOPProviderManagerRouter&)
938 {
939 return *this;
940 }
941
942 Message* OOPProviderManagerRouter::processMessage(Message* message)
943 {
944 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
945 "OOPProviderManagerRouter::processMessage");
946
947 CIMRequestMessage* request = dynamic_cast<CIMRequestMessage *>(message);
948 PEGASUS_ASSERT(request != 0);
949
950 AutoPtr<CIMResponseMessage> response;
951
952 //
953 kumpf 1.1 // Get the provider information from the request
954 //
955 CIMInstance providerModule;
956
957 if ((dynamic_cast<CIMOperationRequestMessage*>(request) != 0) ||
958 (dynamic_cast<CIMIndicationRequestMessage*>(request) != 0) ||
959 (request->getType() == CIM_EXPORT_INDICATION_REQUEST_MESSAGE))
960 {
961 // Provider information is in the OperationContext
962 ProviderIdContainer pidc = (ProviderIdContainer)
963 request->operationContext.get(ProviderIdContainer::NAME);
964 providerModule = pidc.getModule();
965 }
966 else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
967 {
968 CIMEnableModuleRequestMessage* emReq =
969 dynamic_cast<CIMEnableModuleRequestMessage*>(request);
970 providerModule = emReq->providerModule;
971 }
972 else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
973 {
974 kumpf 1.1 CIMDisableModuleRequestMessage* dmReq =
975 dynamic_cast<CIMDisableModuleRequestMessage*>(request);
976 providerModule = dmReq->providerModule;
977 }
978 else if ((request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE) ||
979 (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE))
980 {
981 // This operation is not provider-specific
982 }
983 else
984 {
985 // Unrecognized message type. This should never happen.
986 PEGASUS_ASSERT(0);
987 response.reset(request->buildResponse());
988 response->cimException = PEGASUS_CIM_EXCEPTION(
989 CIM_ERR_FAILED, "Unrecognized message type.");
990 PEG_METHOD_EXIT();
991 return response.release();
992 }
993
994 //
995 kumpf 1.1 // Process the request message
996 //
997 if (request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE)
998 {
999 // Forward the CIMStopAllProvidersRequest to all providers
1000 response.reset(_forwardRequestToAllAgents(request));
1001
1002 // Note: Do not uninitialize the ProviderAgentContainers here.
1003 // Just let the selecting thread notice when the agent connections
1004 // are closed.
1005 }
1006 else if (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE)
1007 {
1008 CIMNotifyConfigChangeRequestMessage* notifyRequest =
1009 dynamic_cast<CIMNotifyConfigChangeRequestMessage*>(request);
1010 PEGASUS_ASSERT(notifyRequest != 0);
1011
1012 if (notifyRequest->currentValueModified)
1013 {
1014 // Forward the CIMNotifyConfigChangeRequestMessage to all providers
1015 response.reset(_forwardRequestToAllAgents(request));
1016 kumpf 1.1 }
1017 else
1018 {
1019 // No need to notify provider agents about changes to planned value
1020 response.reset(request->buildResponse());
1021 }
1022 }
1023 else
1024 {
1025 // Retrieve the provider module name
1026 String moduleName;
1027 CIMValue nameValue = providerModule.getProperty(
1028 providerModule.findProperty("Name")).getValue();
1029 nameValue.get(moduleName);
1030
1031 // Look up the Provider Agent for this module
1032 ProviderAgentContainer * pa = _lookupProviderAgent(moduleName);
1033 PEGASUS_ASSERT(pa != 0);
1034
1035 // Determine whether the Provider Agent has been initialized
1036 Boolean paInitialized = pa->isInitialized();
1037 kumpf 1.1
1038 if ((request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE) &&
1039 !paInitialized)
1040 {
1041 //
1042 // Do not start up an agent process just to disable the module
1043 //
1044 response.reset(request->buildResponse());
1045
1046 CIMDisableModuleResponseMessage* dmResponse =
1047 dynamic_cast<CIMDisableModuleResponseMessage*>(response.get());
1048 PEGASUS_ASSERT(dmResponse != 0);
1049
1050 Array<Uint16> operationalStatus;
1051 operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_STOPPED);
1052 dmResponse->operationalStatus = operationalStatus;
1053 }
1054 else if ((request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE) &&
1055 !paInitialized)
1056 {
1057 //
1058 kumpf 1.1 // Do not start up an agent process just to enable the module
1059 //
1060 response.reset(request->buildResponse());
1061
1062 CIMEnableModuleResponseMessage* emResponse =
1063 dynamic_cast<CIMEnableModuleResponseMessage*>(response.get());
1064 PEGASUS_ASSERT(emResponse != 0);
1065
1066 Array<Uint16> operationalStatus;
1067 operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_OK);
1068 emResponse->operationalStatus = operationalStatus;
1069 }
1070 else
1071 {
1072 //
1073 // Forward the request to the provider agent
1074 //
1075 response.reset(pa->processMessage(request));
1076
1077 // Note: Do not uninitialize the ProviderAgentContainer here when
1078 // a disable module operation is successful.) Just let the
1079 kumpf 1.1 // selecting thread notice when the agent connection is closed.
1080 }
1081 }
1082
1083 response->syncAttributes(request);
1084
1085 PEG_METHOD_EXIT();
1086 return response.release();
1087 }
1088
1089 ProviderAgentContainer* OOPProviderManagerRouter::_lookupProviderAgent(
1090 const String& moduleName)
1091 {
1092 ProviderAgentContainer* pa = 0;
1093
1094 AutoMutex lock(_providerAgentTableMutex);
1095 if (!_providerAgentTable.lookup(moduleName, pa))
1096 {
1097 pa = new ProviderAgentContainer(moduleName, _indicationCallback);
1098 _providerAgentTable.insert(moduleName, pa);
1099 }
1100 kumpf 1.1 return pa;
1101 }
1102
1103 CIMResponseMessage* OOPProviderManagerRouter::_forwardRequestToAllAgents(
1104 CIMRequestMessage* request)
1105 {
1106 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1107 "OOPProviderManagerRouter::_forwardRequestToAllAgents");
1108
1109 // Get a list of the ProviderAgentContainers. We need our own array copy
1110 // because we cannot hold the _providerAgentTableMutex while calling
1111 // _ProviderAgentContainer::processMessage().
1112 Array<ProviderAgentContainer*> paContainerArray;
1113 {
1114 AutoMutex tableLock(_providerAgentTableMutex);
1115 for (ProviderAgentTable::Iterator i = _providerAgentTable.start();
1116 i != 0; i++)
1117 {
1118 paContainerArray.append(i.value());
1119 }
1120 }
1121 kumpf 1.1
1122 CIMException responseException;
1123
1124 // Forward the request to each of the initialized provider agents
1125 for (Uint32 j = 0; j < paContainerArray.size(); j++)
1126 {
1127 ProviderAgentContainer* pa = paContainerArray[j];
1128 if (pa->isInitialized())
1129 {
1130 // Note: The ProviderAgentContainer could become uninitialized
1131 // before _ProviderAgentContainer::processMessage() processes
1132 // this request. In this case, the Provider Agent process will
1133 // (unfortunately) be started to process this message.
1134 AutoPtr<CIMResponseMessage> response;
1135 response.reset(pa->processMessage(request));
1136 if (response.get() != 0)
1137 {
1138 // If the operation failed, save the exception data
1139 if ((response->cimException.getCode() != CIM_ERR_SUCCESS) &&
1140 (responseException.getCode() == CIM_ERR_SUCCESS))
1141 {
1142 kumpf 1.1 responseException = response->cimException;
1143 }
1144 }
1145 }
1146 }
1147
1148 CIMResponseMessage* response = request->buildResponse();
1149 response->cimException = responseException;
1150
1151 PEG_METHOD_EXIT();
1152 return response;
1153 }
1154
1155 Boolean OOPProviderManagerRouter::hasActiveProviders()
1156 {
1157 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1158 "OOPProviderManagerRouter::hasActiveProviders");
1159
1160 // Iterate through the _providerAgentTable looking for initialized agents
1161 AutoMutex lock(_providerAgentTableMutex);
1162 ProviderAgentTable::Iterator i = _providerAgentTable.start();
1163 kumpf 1.1 for(; i != 0; i++)
1164 {
1165 if (i.value()->isInitialized())
1166 {
1167 PEG_METHOD_EXIT();
1168 return true;
1169 }
1170 }
1171
1172 // No initialized Provider Agents were found
1173 PEG_METHOD_EXIT();
1174 return false;
1175 }
1176
1177 void OOPProviderManagerRouter::unloadIdleProviders()
1178 {
1179 PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1180 "OOPProviderManagerRouter::unloadIdleProviders");
1181
1182 // Iterate through the _providerAgentTable unloading idle providers
1183 AutoMutex lock(_providerAgentTableMutex);
1184 kumpf 1.1 ProviderAgentTable::Iterator i = _providerAgentTable.start();
1185 for(; i != 0; i++)
1186 {
1187 i.value()->unloadIdleProviders();
1188 }
1189
1190 PEG_METHOD_EXIT();
1191 }
1192
1193 PEGASUS_NAMESPACE_END
|