(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 mike  1.16     static_cast<CIMResponseMessage*>((void*)&_REQUEST_NOT_PROCESSED);
 337 kumpf 1.1  
 338            ProviderAgentContainer::ProviderAgentContainer(
 339                const String & moduleName,
 340                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 kumpf 1.17     response->syncAttributes(request);
1009 kumpf 1.1  
1010                PEG_METHOD_EXIT();
1011                return response;
1012            }
1013            
1014            void ProviderAgentContainer::unloadIdleProviders()
1015            {
1016                PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1017                    "ProviderAgentContainer::unloadIdleProviders");
1018            
1019                AutoMutex lock(_agentMutex);
1020                if (_isInitialized)
1021                {
1022                    // Send a "wake up" message to the Provider Agent.
1023                    // Don't bother checking whether the operation is successful.
1024                    Uint32 messageLength = 0;
1025                    _pipeToAgent->writeBuffer((const char*)&messageLength, sizeof(Uint32));
1026                }
1027            
1028                PEG_METHOD_EXIT();
1029            }
1030 kumpf 1.1  
1031            void ProviderAgentContainer::_processResponses()
1032            {
1033                PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1034                    "ProviderAgentContainer::_processResponses");
1035            
1036                //
1037                // Process responses until the pipe is closed
1038                //
1039                while (1)
1040                {
1041                    try
1042                    {
1043                        CIMMessage* message;
1044            
1045                        //
1046                        // Read a response from the Provider Agent
1047                        //
1048                        AnonymousPipe::Status readStatus =
1049                            _pipeFromAgent->readMessage(message);
1050            
1051 kumpf 1.1              // Ignore interrupts
1052                        if (readStatus == AnonymousPipe::STATUS_INTERRUPT)
1053                        {
1054                            continue;
1055                        }
1056            
1057                        // Handle an error the same way as a closed connection
1058                        if ((readStatus == AnonymousPipe::STATUS_ERROR) ||
1059                            (readStatus == AnonymousPipe::STATUS_CLOSED))
1060                        {
1061                            _uninitialize(false);
1062                            return;
1063                        }
1064            
1065                        // A null message indicates that the provider agent process has
1066                        // finished its processing and is ready to exit.
1067                        if (message == 0)
1068                        {
1069                            _uninitialize(true);
1070                            return;
1071                        }
1072 kumpf 1.1  
1073                        if (message->getType() == CIM_PROCESS_INDICATION_REQUEST_MESSAGE)
1074                        {
1075 kumpf 1.10                 // Process an indication message
1076            
1077 kumpf 1.1                  _indicationCallback(
1078                                reinterpret_cast<CIMProcessIndicationRequestMessage*>(
1079                                    message));
1080                        }
1081                        else if (!message->isComplete())
1082                        {
1083 kumpf 1.10                 // Process an incomplete response chunk
1084            
1085 kumpf 1.1                  CIMResponseMessage* response;
1086                            response = dynamic_cast<CIMResponseMessage*>(message);
1087                            PEGASUS_ASSERT(response != 0);
1088            
1089                            // Get the OutstandingRequestEntry for this response chunk
1090                            OutstandingRequestEntry* _outstandingRequestEntry = 0;
1091                            {
1092                                AutoMutex tableLock(_outstandingRequestTableMutex);
1093                                Boolean foundEntry = _outstandingRequestTable.lookup(
1094                                    response->messageId, _outstandingRequestEntry);
1095                                PEGASUS_ASSERT(foundEntry);
1096                            }
1097            
1098                            // Put the original message ID into the response
1099                            response->messageId =
1100                                _outstandingRequestEntry->originalMessageId;
1101            
1102                            // Call the response chunk callback to process the chunk
1103                            _responseChunkCallback(
1104                                _outstandingRequestEntry->requestMessage, response);
1105                        }
1106 kumpf 1.1              else
1107                        {
1108 kumpf 1.10                 // Process a completed response
1109            
1110 kumpf 1.1                  CIMResponseMessage* response;
1111                            response = dynamic_cast<CIMResponseMessage*>(message);
1112                            PEGASUS_ASSERT(response != 0);
1113            
1114                            // Give the response to the waiting OutstandingRequestEntry
1115                            OutstandingRequestEntry* _outstandingRequestEntry = 0;
1116                            {
1117                                AutoMutex tableLock(_outstandingRequestTableMutex);
1118                                Boolean foundEntry = _outstandingRequestTable.lookup(
1119                                    response->messageId, _outstandingRequestEntry);
1120                                PEGASUS_ASSERT(foundEntry);
1121            
1122                                // Remove the completed request from the table
1123                                Boolean removed =
1124                                    _outstandingRequestTable.remove(response->messageId);
1125                                PEGASUS_ASSERT(removed);
1126                            }
1127            
1128                            _outstandingRequestEntry->responseMessage = response;
1129                            _outstandingRequestEntry->responseReady->signal();
1130                        }
1131 kumpf 1.1          }
1132                    catch (Exception& e)
1133                    {
1134                        PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
1135                            String("Ignoring exception: ") + e.getMessage());
1136                    }
1137                    catch (...)
1138                    {
1139 marek 1.9              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
1140 kumpf 1.1                  "Ignoring exception");
1141                    }
1142                }
1143            
1144            }
1145            
1146            ThreadReturnType PEGASUS_THREAD_CDECL
1147            ProviderAgentContainer::_responseProcessor(void* arg)
1148            {
1149                ProviderAgentContainer* pa =
1150                    reinterpret_cast<ProviderAgentContainer*>(arg);
1151            
1152                pa->_processResponses();
1153            
1154 kumpf 1.6      return ThreadReturnType(0);
1155 kumpf 1.1  }
1156            
1157            /////////////////////////////////////////////////////////////////////////////
1158            // OOPProviderManagerRouter
1159            /////////////////////////////////////////////////////////////////////////////
1160            
1161            OOPProviderManagerRouter::OOPProviderManagerRouter(
1162                PEGASUS_INDICATION_CALLBACK_T indicationCallback,
1163                PEGASUS_RESPONSE_CHUNK_CALLBACK_T responseChunkCallback,
1164                PEGASUS_PROVIDERMODULEFAIL_CALLBACK_T providerModuleFailCallback)
1165            {
1166                PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1167                    "OOPProviderManagerRouter::OOPProviderManagerRouter");
1168            
1169                _indicationCallback = indicationCallback;
1170                _responseChunkCallback = responseChunkCallback;
1171                _providerModuleFailCallback = providerModuleFailCallback;
1172                _subscriptionInitComplete = false;
1173            
1174                PEG_METHOD_EXIT();
1175            }
1176 kumpf 1.1  
1177            OOPProviderManagerRouter::~OOPProviderManagerRouter()
1178            {
1179                PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1180                    "OOPProviderManagerRouter::~OOPProviderManagerRouter");
1181            
1182                try
1183                {
1184                    // Clean up the ProviderAgentContainers
1185                    AutoMutex lock(_providerAgentTableMutex);
1186                    ProviderAgentTable::Iterator i = _providerAgentTable.start();
1187 kumpf 1.6          for (; i != 0; i++)
1188 kumpf 1.1          {
1189                        delete i.value();
1190                    }
1191                }
1192                catch (...) {}
1193            
1194                PEG_METHOD_EXIT();
1195            }
1196            
1197            Message* OOPProviderManagerRouter::processMessage(Message* message)
1198            {
1199                PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1200                    "OOPProviderManagerRouter::processMessage");
1201            
1202                CIMRequestMessage* request = dynamic_cast<CIMRequestMessage *>(message);
1203                PEGASUS_ASSERT(request != 0);
1204            
1205                AutoPtr<CIMResponseMessage> response;
1206            
1207                //
1208                // Get the provider information from the request
1209 kumpf 1.1      //
1210                CIMInstance providerModule;
1211            
1212                if ((dynamic_cast<CIMOperationRequestMessage*>(request) != 0) ||
1213                    (dynamic_cast<CIMIndicationRequestMessage*>(request) != 0) ||
1214                    (request->getType() == CIM_EXPORT_INDICATION_REQUEST_MESSAGE))
1215                {
1216                    // Provider information is in the OperationContext
1217                    ProviderIdContainer pidc = (ProviderIdContainer)
1218                        request->operationContext.get(ProviderIdContainer::NAME);
1219                    providerModule = pidc.getModule();
1220                }
1221                else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
1222                {
1223                    CIMEnableModuleRequestMessage* emReq =
1224                        dynamic_cast<CIMEnableModuleRequestMessage*>(request);
1225                    providerModule = emReq->providerModule;
1226                }
1227                else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
1228                {
1229                    CIMDisableModuleRequestMessage* dmReq =
1230 kumpf 1.1              dynamic_cast<CIMDisableModuleRequestMessage*>(request);
1231                    providerModule = dmReq->providerModule;
1232                }
1233                else if ((request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE) ||
1234                         (request->getType() ==
1235                             CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE) ||
1236                         (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE))
1237                {
1238                    // This operation is not provider-specific
1239                }
1240                else
1241                {
1242                    // Unrecognized message type.  This should never happen.
1243                    PEGASUS_ASSERT(0);
1244                    response.reset(request->buildResponse());
1245                    response->cimException = PEGASUS_CIM_EXCEPTION(
1246                        CIM_ERR_FAILED, "Unrecognized message type.");
1247                    PEG_METHOD_EXIT();
1248                    return response.release();
1249                }
1250            
1251 kumpf 1.1      //
1252                // Process the request message
1253                //
1254                if (request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE)
1255                {
1256                    // Forward the CIMStopAllProvidersRequest to all providers
1257                    response.reset(_forwardRequestToAllAgents(request));
1258            
1259                    // Note: Do not uninitialize the ProviderAgentContainers here.
1260                    // Just let the selecting thread notice when the agent connections
1261                    // are closed.
1262                }
1263 kumpf 1.6      else if (request->getType () ==
1264 kumpf 1.1          CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE)
1265                {
1266                    _subscriptionInitComplete = true;
1267            
1268                    //
1269 kumpf 1.6          //  Forward the CIMSubscriptionInitCompleteRequestMessage to
1270 kumpf 1.1          //  all providers
1271                    //
1272                    response.reset (_forwardRequestToAllAgents (request));
1273                }
1274                else if (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE)
1275                {
1276                    CIMNotifyConfigChangeRequestMessage* notifyRequest =
1277                        dynamic_cast<CIMNotifyConfigChangeRequestMessage*>(request);
1278                    PEGASUS_ASSERT(notifyRequest != 0);
1279            
1280                    if (notifyRequest->currentValueModified)
1281                    {
1282                        // Forward the CIMNotifyConfigChangeRequestMessage to all providers
1283                        response.reset(_forwardRequestToAllAgents(request));
1284                    }
1285                    else
1286                    {
1287                        // No need to notify provider agents about changes to planned value
1288                        response.reset(request->buildResponse());
1289                    }
1290                }
1291 kumpf 1.1      else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
1292                {
1293                    // Fan out the request to all Provider Agent processes for this module
1294            
1295                    // Retrieve the provider module name
1296                    String moduleName;
1297                    CIMValue nameValue = providerModule.getProperty(
1298                        providerModule.findProperty("Name")).getValue();
1299                    nameValue.get(moduleName);
1300            
1301                    // Look up the Provider Agents for this module
1302                    Array<ProviderAgentContainer*> paArray =
1303                        _lookupProviderAgents(moduleName);
1304            
1305                    for (Uint32 i=0; i<paArray.size(); i++)
1306                    {
1307                        //
1308                        // Do not start up an agent process just to disable the module
1309                        //
1310                        if (paArray[i]->isInitialized())
1311                        {
1312 kumpf 1.1                  //
1313                            // Forward the request to the provider agent
1314                            //
1315                            response.reset(paArray[i]->processMessage(request));
1316            
1317                            // Note: Do not uninitialize the ProviderAgentContainer here
1318                            // when a disable module operation is successful.  Just let the
1319                            // selecting thread notice when the agent connection is closed.
1320            
1321                            // Determine the success of the disable module operation
1322                            CIMDisableModuleResponseMessage* dmResponse =
1323                                dynamic_cast<CIMDisableModuleResponseMessage*>(
1324                                    response.get());
1325                            PEGASUS_ASSERT(dmResponse != 0);
1326            
1327                            Boolean isStopped = false;
1328                            for (Uint32 i=0; i < dmResponse->operationalStatus.size(); i++)
1329                            {
1330                                if (dmResponse->operationalStatus[i] ==
1331                                    CIM_MSE_OPSTATUS_VALUE_STOPPED)
1332                                {
1333 kumpf 1.1                          isStopped = true;
1334                                    break;
1335                                }
1336                            }
1337            
1338                            // If the operation is unsuccessful, stop and return the error
1339                            if ((dmResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
1340                                !isStopped)
1341                            {
1342                                break;
1343                            }
1344                        }
1345                    }
1346            
1347                    // Use a default response if no Provider Agents were called
1348                    if (!response.get())
1349                    {
1350                        response.reset(request->buildResponse());
1351            
1352                        CIMDisableModuleResponseMessage* dmResponse =
1353                            dynamic_cast<CIMDisableModuleResponseMessage*>(response.get());
1354 kumpf 1.1              PEGASUS_ASSERT(dmResponse != 0);
1355            
1356                        Array<Uint16> operationalStatus;
1357                        operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_STOPPED);
1358                        dmResponse->operationalStatus = operationalStatus;
1359                    }
1360                }
1361                else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
1362                {
1363                    // Fan out the request to all Provider Agent processes for this module
1364            
1365                    // Retrieve the provider module name
1366                    String moduleName;
1367                    CIMValue nameValue = providerModule.getProperty(
1368                        providerModule.findProperty("Name")).getValue();
1369                    nameValue.get(moduleName);
1370            
1371                    // Look up the Provider Agents for this module
1372                    Array<ProviderAgentContainer*> paArray =
1373                        _lookupProviderAgents(moduleName);
1374            
1375 kumpf 1.1          for (Uint32 i=0; i<paArray.size(); i++)
1376                    {
1377                        //
1378                        // Do not start up an agent process just to enable the module
1379                        //
1380                        if (paArray[i]->isInitialized())
1381                        {
1382                            //
1383                            // Forward the request to the provider agent
1384                            //
1385                            response.reset(paArray[i]->processMessage(request));
1386            
1387                            // Determine the success of the enable module operation
1388                            CIMEnableModuleResponseMessage* emResponse =
1389                                dynamic_cast<CIMEnableModuleResponseMessage*>(
1390                                    response.get());
1391                            PEGASUS_ASSERT(emResponse != 0);
1392            
1393                            Boolean isOk = false;
1394                            for (Uint32 i=0; i < emResponse->operationalStatus.size(); i++)
1395                            {
1396 kumpf 1.1                      if (emResponse->operationalStatus[i] ==
1397                                    CIM_MSE_OPSTATUS_VALUE_OK)
1398                                {
1399                                    isOk = true;
1400                                    break;
1401                                }
1402                            }
1403            
1404                            // If the operation is unsuccessful, stop and return the error
1405                            if ((emResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
1406                                !isOk)
1407                            {
1408                                break;
1409                            }
1410                        }
1411                    }
1412            
1413                    // Use a default response if no Provider Agents were called
1414                    if (!response.get())
1415                    {
1416                        response.reset(request->buildResponse());
1417 kumpf 1.1  
1418                        CIMEnableModuleResponseMessage* emResponse =
1419                            dynamic_cast<CIMEnableModuleResponseMessage*>(response.get());
1420                        PEGASUS_ASSERT(emResponse != 0);
1421            
1422                        Array<Uint16> operationalStatus;
1423                        operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_OK);
1424                        emResponse->operationalStatus = operationalStatus;
1425                    }
1426                }
1427                else
1428                {
1429                    //
1430                    // Look up the Provider Agent for this module instance and requesting
1431                    // user
1432                    //
1433                    ProviderAgentContainer* pa = _lookupProviderAgent(providerModule,
1434                        request);
1435                    PEGASUS_ASSERT(pa != 0);
1436            
1437                    //
1438 kumpf 1.1          // Forward the request to the provider agent
1439                    //
1440                    response.reset(pa->processMessage(request));
1441                }
1442            
1443                PEG_METHOD_EXIT();
1444                return response.release();
1445            }
1446            
1447            ProviderAgentContainer* OOPProviderManagerRouter::_lookupProviderAgent(
1448                const CIMInstance& providerModule,
1449                CIMRequestMessage* request)
1450            {
1451                // Retrieve the provider module name
1452                String moduleName;
1453                CIMValue nameValue = providerModule.getProperty(
1454                    providerModule.findProperty("Name")).getValue();
1455                nameValue.get(moduleName);
1456            
1457                // Retrieve the provider user context configuration
1458                Uint16 userContext = 0;
1459 kumpf 1.1      Uint32 pos = providerModule.findProperty(
1460                    PEGASUS_PROPERTYNAME_MODULE_USERCONTEXT);
1461                if (pos != PEG_NOT_FOUND)
1462                {
1463                    CIMValue userContextValue =
1464                        providerModule.getProperty(pos).getValue();
1465                    if (!userContextValue.isNull())
1466                    {
1467                        userContextValue.get(userContext);
1468                    }
1469                }
1470            
1471                if (userContext == 0)
1472                {
1473 ouyang.jian 1.15         // PASE has a default user context "QYCMCIMOM",
1474                          // so we leave userContext unset here.
1475                  #ifndef PEGASUS_OS_PASE
1476 kumpf       1.1          userContext = PEGASUS_DEFAULT_PROV_USERCTXT;
1477 ouyang.jian 1.15 #endif
1478 kumpf       1.1      }
1479                  
1480                      String userName;
1481                  
1482                      if (userContext == PG_PROVMODULE_USERCTXT_REQUESTOR)
1483                      {
1484 kumpf       1.6          if (request->operationContext.contains(IdentityContainer::NAME))
1485 kumpf       1.1          {
1486                              // User Name is in the OperationContext
1487                              IdentityContainer ic = (IdentityContainer)
1488                                  request->operationContext.get(IdentityContainer::NAME);
1489                              userName = ic.getUserName();
1490                          }
1491                          //else
1492                          //{
1493                          //    If no IdentityContainer is present, default to the CIM
1494                          //    Server's user context
1495                          //}
1496                  
1497                          // If authentication is disabled, use the CIM Server's user context
1498                          if (!userName.size())
1499                          {
1500                              userName = System::getEffectiveUserName();
1501                          }
1502                      }
1503                      else if (userContext == PG_PROVMODULE_USERCTXT_DESIGNATED)
1504                      {
1505                          // Retrieve the provider module designated user property value
1506 kumpf       1.1          providerModule.getProperty(providerModule.findProperty(
1507                              PEGASUS_PROPERTYNAME_MODULE_DESIGNATEDUSER)).getValue().
1508                              get(userName);
1509                      }
1510                      else if (userContext == PG_PROVMODULE_USERCTXT_CIMSERVER)
1511                      {
1512                          userName = System::getEffectiveUserName();
1513                      }
1514 ouyang.jian 1.15 #ifdef PEGASUS_OS_PASE // it might be unset user in PASE in this branch.
1515                      else if (userContext == 0)
1516                      {
1517                          userName = "QYCMCIMOM";
1518                      }
1519                  #endif
1520 kumpf       1.1      else    // Privileged User
1521                      {
1522                          PEGASUS_ASSERT(userContext == PG_PROVMODULE_USERCTXT_PRIVILEGED);
1523                          userName = System::getPrivilegedUserName();
1524                      }
1525                  
1526                      PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1527                          "Module name = " + moduleName);
1528 marek       1.9      PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1529                          "User context = %hd.", userContext));
1530 kumpf       1.1      PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1531                          "User name = " + userName);
1532                  
1533                      ProviderAgentContainer* pa = 0;
1534 ouyang.jian 1.15 #ifdef PEGASUS_OS_PASE
1535                      String userUpper = userName;
1536                      userUpper.toUpper();
1537                      String key = moduleName + ":" + userUpper;
1538                  #else
1539 kumpf       1.1      String key = moduleName + ":" + userName;
1540 ouyang.jian 1.15 #endif
1541 kumpf       1.1  
1542                      AutoMutex lock(_providerAgentTableMutex);
1543                      if (!_providerAgentTable.lookup(key, pa))
1544                      {
1545                          pa = new ProviderAgentContainer(
1546                              moduleName, userName, userContext,
1547                              _indicationCallback, _responseChunkCallback,
1548                              _providerModuleFailCallback,
1549                              _subscriptionInitComplete);
1550                          _providerAgentTable.insert(key, pa);
1551                      }
1552                      return pa;
1553                  }
1554                  
1555                  Array<ProviderAgentContainer*> OOPProviderManagerRouter::_lookupProviderAgents(
1556                      const String& moduleName)
1557                  {
1558                      Array<ProviderAgentContainer*> paArray;
1559                  
1560                      AutoMutex lock(_providerAgentTableMutex);
1561                      for (ProviderAgentTable::Iterator i = _providerAgentTable.start(); i; i++)
1562 kumpf       1.1      {
1563                          if (i.value()->getModuleName() == moduleName)
1564                          {
1565                              paArray.append(i.value());
1566                          }
1567                      }
1568                      return paArray;
1569                  }
1570                  
1571                  CIMResponseMessage* OOPProviderManagerRouter::_forwardRequestToAllAgents(
1572                      CIMRequestMessage* request)
1573                  {
1574                      PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1575                          "OOPProviderManagerRouter::_forwardRequestToAllAgents");
1576                  
1577                      // Get a list of the ProviderAgentContainers.  We need our own array copy
1578                      // because we cannot hold the _providerAgentTableMutex while calling
1579                      // _ProviderAgentContainer::processMessage().
1580                      Array<ProviderAgentContainer*> paContainerArray;
1581                      {
1582                          AutoMutex tableLock(_providerAgentTableMutex);
1583 kumpf       1.1          for (ProviderAgentTable::Iterator i = _providerAgentTable.start();
1584                               i != 0; i++)
1585                          {
1586                              paContainerArray.append(i.value());
1587                          }
1588                      }
1589                  
1590                      CIMException responseException;
1591                  
1592                      // Forward the request to each of the initialized provider agents
1593                      for (Uint32 j = 0; j < paContainerArray.size(); j++)
1594                      {
1595                          ProviderAgentContainer* pa = paContainerArray[j];
1596                          if (pa->isInitialized())
1597                          {
1598                              // Note: The ProviderAgentContainer could become uninitialized
1599                              // before _ProviderAgentContainer::processMessage() processes
1600                              // this request.  In this case, the Provider Agent process will
1601                              // (unfortunately) be started to process this message.
1602                              AutoPtr<CIMResponseMessage> response;
1603                              response.reset(pa->processMessage(request));
1604 kumpf       1.1              if (response.get() != 0)
1605                              {
1606                                  // If the operation failed, save the exception data
1607                                  if ((response->cimException.getCode() != CIM_ERR_SUCCESS) &&
1608                                      (responseException.getCode() == CIM_ERR_SUCCESS))
1609                                  {
1610                                      responseException = response->cimException;
1611                                  }
1612                              }
1613                          }
1614                      }
1615                  
1616                      CIMResponseMessage* response = request->buildResponse();
1617                      response->cimException = responseException;
1618                  
1619                      PEG_METHOD_EXIT();
1620                      return response;
1621                  }
1622                  
1623                  void OOPProviderManagerRouter::unloadIdleProviders()
1624                  {
1625 kumpf       1.1      PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1626                          "OOPProviderManagerRouter::unloadIdleProviders");
1627                  
1628 kumpf       1.7      // Get a list of the ProviderAgentContainers.  We need our own array copy
1629                      // because we cannot hold the _providerAgentTableMutex while calling
1630                      // ProviderAgentContainer::unloadIdleProviders().
1631                      Array<ProviderAgentContainer*> paContainerArray;
1632                      {
1633                          AutoMutex tableLock(_providerAgentTableMutex);
1634                          for (ProviderAgentTable::Iterator i = _providerAgentTable.start();
1635                               i != 0; i++)
1636                          {
1637                              paContainerArray.append(i.value());
1638                          }
1639                      }
1640                  
1641 kumpf       1.1      // Iterate through the _providerAgentTable unloading idle providers
1642 kumpf       1.7      for (Uint32 j = 0; j < paContainerArray.size(); j++)
1643 kumpf       1.1      {
1644 kumpf       1.7          paContainerArray[j]->unloadIdleProviders();
1645 kumpf       1.1      }
1646                  
1647                      PEG_METHOD_EXIT();
1648                  }
1649                  
1650                  PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2