version 1.6, 2005/01/26 23:09:09
|
version 1.21, 2005/11/18 18:38:35
|
|
|
//%2004//////////////////////////////////////////////////////////////////////// |
//%2005//////////////////////////////////////////////////////////////////////// |
// | // |
// Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development | // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development |
// Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems. | // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems. |
|
|
// IBM Corp.; EMC Corporation, The Open Group. | // IBM Corp.; EMC Corporation, The Open Group. |
// Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.; | // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.; |
// IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group. | // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group. |
|
// Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.; |
|
// EMC Corporation; VERITAS Software Corporation; The Open Group. |
// | // |
// Permission is hereby granted, free of charge, to any person obtaining a copy | // Permission is hereby granted, free of charge, to any person obtaining a copy |
// of this software and associated documentation files (the "Software"), to | // of this software and associated documentation files (the "Software"), to |
|
|
// Author: Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com) | // Author: Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com) |
// Jenny Yu, Hewlett-Packard Company (jenny_yu@hp.com) | // Jenny Yu, Hewlett-Packard Company (jenny_yu@hp.com) |
// | // |
// Modified By: |
// Modified By: Sean Keenan, Hewlett-Packard Company (sean.keenan@hp.com) |
|
// Carol Ann Krug Graves, Hewlett-Packard Company |
|
// (carolann_graves@hp.com) |
// | // |
//%///////////////////////////////////////////////////////////////////////////// | //%///////////////////////////////////////////////////////////////////////////// |
| |
|
|
| |
#if defined (PEGASUS_OS_TYPE_WINDOWS) | #if defined (PEGASUS_OS_TYPE_WINDOWS) |
#include <windows.h> // For CreateProcess() | #include <windows.h> // For CreateProcess() |
#else |
#elif defined (PEGASUS_OS_OS400) |
# if defined (PEGASUS_OS_OS400) |
|
# include <unistd.cleinc> | # include <unistd.cleinc> |
|
#elif defined (PEGASUS_OS_VMS) |
|
# include <perror.h> |
|
# include <climsgdef.h> |
|
# include <stdio.h> |
|
# include <stdlib.h> |
|
# include <string.h> |
|
# include <processes.h> |
|
# include <unixio.h> |
# else | # else |
# include <unistd.h> // For fork(), exec(), and _exit() | # include <unistd.h> // For fork(), exec(), and _exit() |
# endif |
|
#include <errno.h> | #include <errno.h> |
|
# include <sys/types.h> |
|
# if defined(PEGASUS_HAS_SIGNALS) |
|
# include <sys/wait.h> |
|
# endif |
#endif | #endif |
| |
#include "OOPProviderManagerRouter.h" | #include "OOPProviderManagerRouter.h" |
|
|
ProviderAgentContainer( | ProviderAgentContainer( |
const String & moduleName, | const String & moduleName, |
const String & userName, | const String & userName, |
PEGASUS_INDICATION_CALLBACK indicationCallback); |
PEGASUS_INDICATION_CALLBACK indicationCallback, |
|
Boolean subscriptionInitComplete); |
| |
~ProviderAgentContainer(); | ~ProviderAgentContainer(); |
| |
|
|
*/ | */ |
AutoPtr<AnonymousPipe> _pipeToAgent; | AutoPtr<AnonymousPipe> _pipeToAgent; |
| |
|
#if defined(PEGASUS_HAS_SIGNALS) |
|
/** |
|
Process ID of the active Provider Agent. |
|
*/ |
|
pid_t _pid; |
|
#endif |
|
|
/** | /** |
The _outstandingRequestTable holds an entry for each request that has | The _outstandingRequestTable holds an entry for each request that has |
been sent to this Provider Agent for which no response has been | been sent to this Provider Agent for which no response has been |
|
|
(active) at one time. | (active) at one time. |
*/ | */ |
static Uint32 _maxProviderProcesses; | static Uint32 _maxProviderProcesses; |
|
|
|
/** |
|
Indicates whether the Indication Service has completed initialization. |
|
|
|
For more information, please see the description of the |
|
ProviderManagerRouter::_subscriptionInitComplete member variable. |
|
*/ |
|
Boolean _subscriptionInitComplete; |
}; | }; |
| |
Uint32 ProviderAgentContainer::_numProviderProcesses = 0; | Uint32 ProviderAgentContainer::_numProviderProcesses = 0; |
|
|
ProviderAgentContainer::ProviderAgentContainer( | ProviderAgentContainer::ProviderAgentContainer( |
const String & moduleName, | const String & moduleName, |
const String & userName, | const String & userName, |
PEGASUS_INDICATION_CALLBACK indicationCallback) |
PEGASUS_INDICATION_CALLBACK indicationCallback, |
|
Boolean subscriptionInitComplete) |
: _moduleName(moduleName), | : _moduleName(moduleName), |
_userName(userName), | _userName(userName), |
_indicationCallback(indicationCallback), | _indicationCallback(indicationCallback), |
_isInitialized(false) |
_isInitialized(false), |
|
_subscriptionInitComplete(subscriptionInitComplete) |
{ | { |
PEG_METHOD_ENTER(TRC_PROVIDERMANAGER, | PEG_METHOD_ENTER(TRC_PROVIDERMANAGER, |
"ProviderAgentContainer::ProviderAgentContainer"); | "ProviderAgentContainer::ProviderAgentContainer"); |
|
|
// Ensure the destructor does not throw an exception | // Ensure the destructor does not throw an exception |
try | try |
{ | { |
|
if (isInitialized()) |
|
{ |
// Stop the responseProcessor thread by closing its connection | // Stop the responseProcessor thread by closing its connection |
_pipeFromAgent->closeReadHandle(); | _pipeFromAgent->closeReadHandle(); |
| |
|
|
pegasus_yield(); | pegasus_yield(); |
} | } |
} | } |
|
} |
catch (...) | catch (...) |
{ | { |
} | } |
|
|
PEG_METHOD_ENTER(TRC_PROVIDERMANAGER, | PEG_METHOD_ENTER(TRC_PROVIDERMANAGER, |
"ProviderAgentContainer::_startAgentProcess"); | "ProviderAgentContainer::_startAgentProcess"); |
| |
|
// |
|
// Serialize the starting of agent processes. If two agent processes are |
|
// started at the same time, they may get copies of each other's pipe |
|
// descriptors. If this happens, the cimserver will not get a pipe read |
|
// error when one of the agent processes exits, because the pipe will |
|
// still be writable by the other process. This locking control needs to |
|
// cover the period from where the pipes are created to where the agent |
|
// ends of the pipes are closed by the cimserver. |
|
// |
|
static Mutex agentStartupMutex; |
|
AutoMutex lock(agentStartupMutex); |
|
|
AutoPtr<AnonymousPipe> pipeFromAgent(new AnonymousPipe()); | AutoPtr<AnonymousPipe> pipeFromAgent(new AnonymousPipe()); |
AutoPtr<AnonymousPipe> pipeToAgent(new AnonymousPipe()); | AutoPtr<AnonymousPipe> pipeToAgent(new AnonymousPipe()); |
| |
|
|
| |
CloseHandle(piProcInfo.hProcess); | CloseHandle(piProcInfo.hProcess); |
CloseHandle(piProcInfo.hThread); | CloseHandle(piProcInfo.hThread); |
|
|
|
#elif defined (PEGASUS_OS_VMS) |
|
|
|
// |
|
// fork and exec the child process |
|
// |
|
int status; |
|
|
|
status = vfork (); |
|
switch (status) |
|
{ |
|
case 0: |
|
try |
|
{ |
|
// |
|
// Execute the cimprovagt program |
|
// |
|
String agentCommandPath = |
|
ConfigManager::getHomedPath(PEGASUS_PROVIDER_AGENT_PROC_NAME); |
|
CString agentCommandPathCString = agentCommandPath.getCString(); |
|
|
|
char readHandle[32]; |
|
char writeHandle[32]; |
|
pipeToAgent->exportReadHandle(readHandle); |
|
pipeFromAgent->exportWriteHandle(writeHandle); |
|
|
|
if ((status = execl(agentCommandPathCString, agentCommandPathCString, |
|
readHandle, writeHandle, |
|
(const char*)_moduleName.getCString(), (char*)0)) == -1); |
|
{ |
|
// If we're still here, there was an error |
|
Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"execl() failed. errno = %d.", errno); |
|
_exit(1); |
|
} |
|
} |
|
catch (...) |
|
{ |
|
// There's not much we can do here in no man's land |
|
try |
|
{ |
|
PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"Caught exception before calling execl()."); |
|
} |
|
catch (...) |
|
{ |
|
} |
|
_exit(1); |
|
} |
|
PEG_METHOD_EXIT(); |
|
return; |
|
break; |
|
|
|
case -1: |
|
Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2, |
|
"fork() failed. errno = %d.", errno); |
|
PEG_METHOD_EXIT(); |
|
throw Exception(MessageLoaderParms( |
|
"ProviderManager.OOPProviderManagerRouter.CIMPROVAGT_START_FAILED", |
|
"Failed to start cimprovagt \"$0\".", |
|
_moduleName)); |
|
break; |
|
|
|
default: |
|
// Close our copies of the agent's ends of the pipes |
|
pipeToAgent->closeReadHandle(); |
|
pipeFromAgent->closeWriteHandle(); |
|
|
|
_pipeToAgent.reset(pipeToAgent.release()); |
|
_pipeFromAgent.reset(pipeFromAgent.release()); |
|
|
|
PEG_METHOD_EXIT(); |
|
} |
|
#elif defined (PEGASUS_OS_OS400) |
|
|
|
//Out of provider support for OS400 goes here when needed. |
|
|
#else | #else |
pid_t pid = fork(); | pid_t pid = fork(); |
if (pid < 0) | if (pid < 0) |
|
|
pipeToAgent->exportReadHandle(readHandle); | pipeToAgent->exportReadHandle(readHandle); |
pipeFromAgent->exportWriteHandle(writeHandle); | pipeFromAgent->exportWriteHandle(writeHandle); |
| |
|
#ifndef PEGASUS_DISABLE_PROV_USERCTXT |
// Set the user context of the Provider Agent process | // Set the user context of the Provider Agent process |
if (_userName != System::getEffectiveUserName()) | if (_userName != System::getEffectiveUserName()) |
{ | { |
|
|
{ | { |
Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2, | Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
"System::changeUserContext() failed. userName = %s.", | "System::changeUserContext() failed. userName = %s.", |
_userName.getCString()); |
(const char*)_userName.getCString()); |
Logger::put_l(Logger::ERROR_LOG, System::CIMSERVER, | Logger::put_l(Logger::ERROR_LOG, System::CIMSERVER, |
Logger::WARNING, | Logger::WARNING, |
"ProviderManager.OOPProviderManagerRouter." | "ProviderManager.OOPProviderManagerRouter." |
|
|
_exit(1); | _exit(1); |
} | } |
} | } |
|
#endif |
| |
execl(agentCommandPathCString, agentCommandPathCString, | execl(agentCommandPathCString, agentCommandPathCString, |
readHandle, writeHandle, | readHandle, writeHandle, |
|
|
_exit(1); | _exit(1); |
} | } |
} | } |
|
# if defined(PEGASUS_HAS_SIGNALS) |
|
_pid = pid; |
|
# endif |
#endif | #endif |
| |
// | // |
|
|
configManager->getPegasusHome(), | configManager->getPegasusHome(), |
configProperties, | configProperties, |
System::bindVerbose, | System::bindVerbose, |
|
_subscriptionInitComplete, |
QueueIdStack())); | QueueIdStack())); |
| |
// | // |
|
|
{ | { |
_startAgentProcess(); | _startAgentProcess(); |
| |
_sendInitializationData(); |
|
|
|
_isInitialized = true; | _isInitialized = true; |
| |
|
_sendInitializationData(); |
|
|
// Start a thread to read and process responses from the Provider Agent | // Start a thread to read and process responses from the Provider Agent |
while (!MessageQueueService::get_thread_pool()->allocate_and_awaken( |
ThreadStatus rtn = PEGASUS_THREAD_OK; |
this, _responseProcessor)) |
while ((rtn = MessageQueueService::get_thread_pool()-> |
|
allocate_and_awaken(this, _responseProcessor)) != |
|
PEGASUS_THREAD_OK) |
|
{ |
|
if (rtn == PEGASUS_THREAD_INSUFFICIENT_RESOURCES) |
{ | { |
pegasus_yield(); | pegasus_yield(); |
} | } |
|
else |
|
{ |
|
Logger::put( |
|
Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE, |
|
"Not enough threads to process responses from the " |
|
"provider agent."); |
|
|
|
Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2, |
|
"Could not allocate thread to process responses from the " |
|
"provider agent."); |
|
|
|
throw Exception(MessageLoaderParms( |
|
"ProviderManager.OOPProviderManagerRouter." |
|
"CIMPROVAGT_THREAD_ALLOCATION_FAILED", |
|
"Failed to allocate thread for cimprovagt \"$0\".", |
|
_moduleName)); |
|
} |
|
} |
} | } |
catch (...) | catch (...) |
{ | { |
_isInitialized = false; |
// Closing the connection causes the agent process to exit |
_pipeToAgent.reset(); | _pipeToAgent.reset(); |
_pipeFromAgent.reset(); | _pipeFromAgent.reset(); |
| |
|
#if defined(PEGASUS_HAS_SIGNALS) |
|
if (_isInitialized) |
|
{ |
|
// Harvest the status of the agent process to prevent a zombie |
|
Boolean keepWaiting = false; |
|
do |
|
{ |
|
pid_t status = waitpid(_pid, 0, 0); |
|
if (status == -1) |
|
{ |
|
if (errno == EINTR) |
|
{ |
|
keepWaiting = true; |
|
} |
|
else |
|
{ |
|
Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"ProviderAgentContainer::_initialize(): " |
|
"waitpid failed; errno = %d.", errno); |
|
} |
|
} |
|
} while (keepWaiting); |
|
} |
|
#endif |
|
|
|
_isInitialized = false; |
|
|
{ | { |
AutoMutex lock(_numProviderProcessesMutex); | AutoMutex lock(_numProviderProcessesMutex); |
_numProviderProcesses--; | _numProviderProcesses--; |
|
|
_numProviderProcesses--; | _numProviderProcesses--; |
} | } |
| |
|
#if defined(PEGASUS_HAS_SIGNALS) |
|
// Harvest the status of the agent process to prevent a zombie |
|
Boolean keepWaiting = false; |
|
do |
|
{ |
|
pid_t status = waitpid(_pid, 0, 0); |
|
if (status == -1) |
|
{ |
|
if (errno == EINTR) |
|
{ |
|
keepWaiting = true; |
|
} |
|
else |
|
{ |
|
Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2, |
|
"ProviderAgentContainer::_uninitialize(): " |
|
"waitpid failed; errno = %d.", errno); |
|
} |
|
} |
|
} while (keepWaiting); |
|
#endif |
|
|
_isInitialized = false; | _isInitialized = false; |
| |
// | // |
|
|
} | } |
} | } |
| |
PEG_METHOD_EXIT(); |
|
} | } |
| |
PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL | PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL |
|
|
"OOPProviderManagerRouter::OOPProviderManagerRouter"); | "OOPProviderManagerRouter::OOPProviderManagerRouter"); |
| |
_indicationCallback = indicationCallback; | _indicationCallback = indicationCallback; |
|
_subscriptionInitComplete = false; |
| |
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
} | } |
|
|
providerModule = dmReq->providerModule; | providerModule = dmReq->providerModule; |
} | } |
else if ((request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE) || | else if ((request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE) || |
|
(request->getType() == |
|
CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE) || |
(request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE)) | (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE)) |
{ | { |
// This operation is not provider-specific | // This operation is not provider-specific |
|
|
// Just let the selecting thread notice when the agent connections | // Just let the selecting thread notice when the agent connections |
// are closed. | // are closed. |
} | } |
|
else if (request->getType () == |
|
CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE) |
|
{ |
|
_subscriptionInitComplete = true; |
|
|
|
// |
|
// Forward the CIMSubscriptionInitCompleteRequestMessage to |
|
// all providers |
|
// |
|
response.reset (_forwardRequestToAllAgents (request)); |
|
} |
else if (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE) | else if (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE) |
{ | { |
CIMNotifyConfigChangeRequestMessage* notifyRequest = | CIMNotifyConfigChangeRequestMessage* notifyRequest = |
|
|
PEGASUS_PROPERTYNAME_MODULE_USERCONTEXT); | PEGASUS_PROPERTYNAME_MODULE_USERCONTEXT); |
if (pos != PEG_NOT_FOUND) | if (pos != PEG_NOT_FOUND) |
{ | { |
providerModule.getProperty(pos).getValue().get(userContext); |
CIMValue userContextValue = |
|
providerModule.getProperty(pos).getValue(); |
|
if (!userContextValue.isNull()) |
|
{ |
|
userContextValue.get(userContext); |
|
} |
} | } |
| |
if (userContext == 0) | if (userContext == 0) |
|
|
if (!_providerAgentTable.lookup(key, pa)) | if (!_providerAgentTable.lookup(key, pa)) |
{ | { |
pa = new ProviderAgentContainer( | pa = new ProviderAgentContainer( |
moduleName, userName, _indicationCallback); |
moduleName, userName, _indicationCallback, |
|
_subscriptionInitComplete); |
_providerAgentTable.insert(key, pa); | _providerAgentTable.insert(key, pa); |
} | } |
return pa; | return pa; |