(file) Return to OOPProviderManagerRouter.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / ProviderManagerService

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2