(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.20         PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL1,
 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 marek 1.19                 PEG_TRACE_CSTRING(TRC_PROVIDERMANAGER, Tracer::LEVEL1,
 570 kumpf 1.1                      "Could not allocate thread to process responses from the "
 571                                    "provider agent.");
 572            
 573                            throw Exception(MessageLoaderParms(
 574                                "ProviderManager.OOPProviderManagerRouter."
 575                                    "CIMPROVAGT_THREAD_ALLOCATION_FAILED",
 576                                "Failed to allocate thread for cimprovagt \"$0\".",
 577                                _moduleName));
 578                        }
 579                    }
 580                }
 581                catch (...)
 582                {
 583                    // Closing the connection causes the agent process to exit
 584                    _pipeToAgent.reset();
 585                    _pipeFromAgent.reset();
 586            
 587            #if defined(PEGASUS_HAS_SIGNALS)
 588                    if (_isInitialized)
 589                    {
 590                        // Harvest the status of the agent process to prevent a zombie
 591 kumpf 1.10             int status = Executor::reapProviderAgent(_pid);
 592 kumpf 1.4  
 593                        if (status == -1)
 594                        {
 595 marek 1.20                 PEG_TRACE((TRC_DISCARDED_DATA, Tracer::LEVEL1,
 596 kumpf 1.4                      "ProviderAgentContainer::_initialize(): "
 597 kumpf 1.10                         "Executor::reapProviderAgent() failed"));
 598 kumpf 1.4              }
 599 kumpf 1.1          }
 600            #endif
 601            
 602                    _isInitialized = false;
 603            
 604                    {
 605                        AutoMutex lock(_numProviderProcessesMutex);
 606                        _numProviderProcesses--;
 607                    }
 608            
 609                    PEG_METHOD_EXIT();
 610                    throw;
 611                }
 612            
 613                PEG_METHOD_EXIT();
 614            }
 615            
 616            Boolean ProviderAgentContainer::isInitialized()
 617            {
 618                AutoMutex lock(_agentMutex);
 619                return _isInitialized;
 620 kumpf 1.1  }
 621            
 622            void ProviderAgentContainer::_uninitialize(Boolean cleanShutdown)
 623            {
 624                PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 625                    "ProviderAgentContainer::_uninitialize");
 626            
 627 kumpf 1.7  #if defined(PEGASUS_HAS_SIGNALS)
 628 kumpf 1.14     pid_t pid = 0;
 629 kumpf 1.7  #endif
 630 kumpf 1.1  
 631                try
 632                {
 633 kumpf 1.7          AutoMutex lock(_agentMutex);
 634            
 635                    PEGASUS_ASSERT(_isInitialized);
 636            
 637 kumpf 1.1          // Close the connection with the Provider Agent
 638                    _pipeFromAgent.reset();
 639                    _pipeToAgent.reset();
 640            
 641                    _providerModuleCache = CIMInstance();
 642            
 643                    {
 644 kumpf 1.21             AutoMutex lock2(_numProviderProcessesMutex);
 645 kumpf 1.1              _numProviderProcesses--;
 646                    }
 647            
 648 kumpf 1.7          _isInitialized = false;
 649            
 650 kumpf 1.1  #if defined(PEGASUS_HAS_SIGNALS)
 651 kumpf 1.7          // Save the _pid so we can use it after we've released the _agentMutex
 652                    pid = _pid;
 653 kumpf 1.1  #endif
 654            
 655                    //
 656                    // Complete with null responses all outstanding requests on this
 657                    // connection
 658                    //
 659                    {
 660                        AutoMutex tableLock(_outstandingRequestTableMutex);
 661            
 662                        CIMResponseMessage* response =
 663                            cleanShutdown ? _REQUEST_NOT_PROCESSED : 0;
 664            
 665                        for (OutstandingRequestTable::Iterator i =
 666                                 _outstandingRequestTable.start();
 667                             i != 0; i++)
 668                        {
 669 thilo.boehm 1.22                 PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL4,
 670                                      "Completing messageId \"%s\" with a null response.",
 671                                      (const char*)i.key().getCString()));
 672 kumpf       1.1                  i.value()->responseMessage = response;
 673                                  i.value()->responseReady->signal();
 674                              }
 675                  
 676                              _outstandingRequestTable.clear();
 677 kumpf       1.3          }
 678 kumpf       1.1  
 679 kumpf       1.3          //
 680                          //  If not a clean shutdown, call the provider module failure callback
 681                          //
 682                          if (!cleanShutdown)
 683                          {
 684 kumpf       1.1              //
 685 kumpf       1.3              // Call the provider module failure callback to communicate
 686                              // the failure to the Provider Manager Service.  The Provider
 687                              // Manager Service will inform the Indication Service.
 688 kumpf       1.1              //
 689 kumpf       1.3              _providerModuleFailCallback(_moduleName, _userName, _userContext);
 690 kumpf       1.1          }
 691                      }
 692                      catch (...)
 693                      {
 694                          // We're uninitializing, so do not propagate the exception
 695 marek       1.9          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
 696 kumpf       1.1              "Ignoring _uninitialize() exception.");
 697                      }
 698                  
 699 kumpf       1.7  #if defined(PEGASUS_HAS_SIGNALS)
 700                      // Harvest the status of the agent process to prevent a zombie.  Do not
 701                      // hold the _agentMutex during this operation.
 702                  
 703 kumpf       1.14     if ((pid != 0) && (Executor::reapProviderAgent(pid) == -1))
 704 kumpf       1.7      {
 705 marek       1.9          PEG_TRACE((TRC_DISCARDED_DATA, Tracer::LEVEL2,
 706 kumpf       1.7              "ProviderAgentContainer::_uninitialize(): "
 707 kumpf       1.10                 "Executor::reapProviderAgent() failed."));
 708 kumpf       1.7      }
 709                  #endif
 710                  
 711 kumpf       1.1      PEG_METHOD_EXIT();
 712                  }
 713                  
 714                  String ProviderAgentContainer::getModuleName() const
 715                  {
 716                      return _moduleName;
 717                  }
 718                  
 719                  CIMResponseMessage* ProviderAgentContainer::processMessage(
 720                      CIMRequestMessage* request)
 721                  {
 722                      PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 723                          "ProviderAgentContainer::processMessage");
 724                  
 725                      CIMResponseMessage* response;
 726                  
 727                      do
 728                      {
 729                          response = _processMessage(request);
 730                  
 731                          if (response == _REQUEST_NOT_PROCESSED)
 732 kumpf       1.1          {
 733                              // Check for request message types that should not be retried.
 734                              if ((request->getType() ==
 735                                       CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE) ||
 736                                  (request->getType() ==
 737                                       CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE) ||
 738                                  (request->getType() ==
 739                                       CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE) ||
 740                                  (request->getType() ==
 741                                       CIM_DELETE_SUBSCRIPTION_REQUEST_MESSAGE))
 742                              {
 743                                  response = request->buildResponse();
 744                                  break;
 745                              }
 746                              else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
 747                              {
 748                                  CIMDisableModuleResponseMessage* dmResponse =
 749                                      dynamic_cast<CIMDisableModuleResponseMessage*>(response);
 750                                  PEGASUS_ASSERT(dmResponse != 0);
 751                  
 752                                  Array<Uint16> operationalStatus;
 753 kumpf       1.1                  operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_STOPPED);
 754                                  dmResponse->operationalStatus = operationalStatus;
 755                                  break;
 756                              }
 757                          }
 758                      } while (response == _REQUEST_NOT_PROCESSED);
 759                  
 760 kumpf       1.2      if (request->getType() == CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE)
 761                      {
 762                          _subscriptionInitComplete = true;
 763                      }
 764                  
 765 kumpf       1.1      PEG_METHOD_EXIT();
 766                      return response;
 767                  }
 768                  
 769                  CIMResponseMessage* ProviderAgentContainer::_processMessage(
 770                      CIMRequestMessage* request)
 771                  {
 772                      PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 773                          "ProviderAgentContainer::_processMessage");
 774                  
 775                      CIMResponseMessage* response;
 776                      String originalMessageId = request->messageId;
 777                  
 778                      // These three variables are used for the provider module optimization.
 779                      // See the _providerModuleCache member description for more information.
 780                      AutoPtr<ProviderIdContainer> origProviderId;
 781                      Boolean doProviderModuleOptimization = false;
 782                      Boolean updateProviderModuleCache = false;
 783                  
 784                      try
 785                      {
 786 kumpf       1.1          // The messageId attribute is used to correlate response messages
 787                          // from the Provider Agent with request messages, so it is imperative
 788                          // that the ID is unique for each request.  The incoming ID cannot be
 789                          // trusted to be unique, so we substitute a unique one.  The memory
 790                          // address of the request is used as the source of a unique piece of
 791                          // data.  (The message ID is only required to be unique while the
 792                          // request is outstanding.)
 793                          char messagePtrString[20];
 794                          sprintf(messagePtrString, "%p", request);
 795                          String uniqueMessageId = messagePtrString;
 796                  
 797                          //
 798                          // Set up the OutstandingRequestEntry for this request
 799                          //
 800                          Semaphore waitSemaphore(0);
 801                          OutstandingRequestEntry outstandingRequestEntry(
 802                              originalMessageId, request, response, &waitSemaphore);
 803                  
 804                          //
 805                          // Lock the Provider Agent Container while initializing the
 806                          // agent and writing the request to the connection
 807 kumpf       1.1          //
 808                          {
 809                              AutoMutex lock(_agentMutex);
 810                  
 811                              //
 812                              // Initialize the Provider Agent, if necessary
 813                              //
 814                              if (!_isInitialized)
 815                              {
 816                                  _initialize();
 817                              }
 818                  
 819                              //
 820                              // Add an entry to the OutstandingRequestTable for this request
 821                              //
 822                              {
 823                                  AutoMutex tableLock(_outstandingRequestTableMutex);
 824                  
 825                                  _outstandingRequestTable.insert(
 826                                      uniqueMessageId, &outstandingRequestEntry);
 827                              }
 828 kumpf       1.1  
 829                              // Get the provider module from the ProviderIdContainer to see if
 830                              // we can optimize out the transmission of this instance to the
 831                              // Provider Agent.  (See the _providerModuleCache description.)
 832 kumpf       1.6              if (request->operationContext.contains(ProviderIdContainer::NAME))
 833 kumpf       1.1              {
 834                                  ProviderIdContainer pidc = request->operationContext.get(
 835                                      ProviderIdContainer::NAME);
 836                                  origProviderId.reset(new ProviderIdContainer(
 837                                      pidc.getModule(), pidc.getProvider(),
 838                                      pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
 839                                  if (_providerModuleCache.isUninitialized() ||
 840                                      (!pidc.getModule().identical(_providerModuleCache)))
 841                                  {
 842                                      // We haven't sent this provider module instance to the
 843                                      // Provider Agent yet.  Update our cache after we send it.
 844                                      updateProviderModuleCache = true;
 845                                  }
 846                                  else
 847                                  {
 848                                      // Replace the provider module in the ProviderIdContainer
 849                                      // with an uninitialized instance.  We'll need to put the
 850                                      // original one back after the message is sent.
 851                                      request->operationContext.set(ProviderIdContainer(
 852                                          CIMInstance(), pidc.getProvider(),
 853                                          pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
 854 kumpf       1.1                      doProviderModuleOptimization = true;
 855                                  }
 856                              }
 857                  
 858                              //
 859                              // Write the message to the pipe
 860                              //
 861                              try
 862                              {
 863 thilo.boehm 1.22                 PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL3,
 864                                      "Sending request to agent with messageId %s",
 865                                      (const char*)uniqueMessageId.getCString()));
 866 kumpf       1.1  
 867                                  request->messageId = uniqueMessageId;
 868                                  AnonymousPipe::Status writeStatus =
 869                                      _pipeToAgent->writeMessage(request);
 870                                  request->messageId = originalMessageId;
 871                  
 872                                  if (doProviderModuleOptimization)
 873                                  {
 874                                      request->operationContext.set(*origProviderId.get());
 875                                  }
 876                  
 877                                  if (writeStatus != AnonymousPipe::STATUS_SUCCESS)
 878                                  {
 879 marek       1.20                     PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL1,
 880 kumpf       1.1                          "Failed to write message to pipe.  writeStatus = %d.",
 881 marek       1.9                          writeStatus));
 882 kumpf       1.1  
 883                                      request->messageId = originalMessageId;
 884                  
 885                                      if (doProviderModuleOptimization)
 886                                      {
 887                                          request->operationContext.set(*origProviderId.get());
 888                                      }
 889                  
 890                                      // Remove this OutstandingRequestTable entry
 891                                      {
 892                                          AutoMutex tableLock(_outstandingRequestTableMutex);
 893                                          Boolean removed =
 894                                              _outstandingRequestTable.remove(uniqueMessageId);
 895                                          PEGASUS_ASSERT(removed);
 896                                      }
 897                  
 898                                      // A response value of _REQUEST_NOT_PROCESSED indicates
 899                                      // that the request was not processed by the provider
 900                                      // agent, so it can be retried safely.
 901                                      PEG_METHOD_EXIT();
 902                                      return _REQUEST_NOT_PROCESSED;
 903 kumpf       1.1                  }
 904                  
 905                                  if (updateProviderModuleCache)
 906                                  {
 907                                      _providerModuleCache = origProviderId->getModule();
 908                                  }
 909                              }
 910                              catch (...)
 911                              {
 912                                  request->messageId = originalMessageId;
 913                  
 914                                  if (doProviderModuleOptimization)
 915                                  {
 916                                      request->operationContext.set(*origProviderId.get());
 917                                  }
 918                  
 919 marek       1.20                 PEG_TRACE_CSTRING(TRC_PROVIDERMANAGER, Tracer::LEVEL1,
 920 kumpf       1.1                      "Failed to write message to pipe.");
 921                                  // Remove the OutstandingRequestTable entry for this request
 922                                  {
 923                                      AutoMutex tableLock(_outstandingRequestTableMutex);
 924                                      Boolean removed =
 925                                          _outstandingRequestTable.remove(uniqueMessageId);
 926                                      PEGASUS_ASSERT(removed);
 927                                  }
 928                                  PEG_METHOD_EXIT();
 929                                  throw;
 930                              }
 931                          }
 932                  
 933                          //
 934                          // Wait for the response
 935                          //
 936                          try
 937                          {
 938                              // Must not hold _agentMutex while waiting for the response
 939                              waitSemaphore.wait();
 940                          }
 941 kumpf       1.1          catch (...)
 942                          {
 943                              // Remove the OutstandingRequestTable entry for this request
 944                              {
 945                                  AutoMutex tableLock(_outstandingRequestTableMutex);
 946                                  Boolean removed =
 947                                      _outstandingRequestTable.remove(uniqueMessageId);
 948                                  PEGASUS_ASSERT(removed);
 949                              }
 950                              PEG_METHOD_EXIT();
 951                              throw;
 952                          }
 953                  
 954                          // A response value of _REQUEST_NOT_PROCESSED indicates that the
 955                          // provider agent process was terminating when the request was sent.
 956 kumpf       1.6          // The request was not processed by the provider agent, so it can be
 957 kumpf       1.1          // retried safely.
 958                          if (response == _REQUEST_NOT_PROCESSED)
 959                          {
 960                              PEG_METHOD_EXIT();
 961                              return response;
 962                          }
 963                  
 964                          // A null response is returned when an agent connection is closed
 965                          // while requests remain outstanding.
 966                          if (response == 0)
 967                          {
 968                              response = request->buildResponse();
 969                              response->cimException = PEGASUS_CIM_EXCEPTION(
 970                                  CIM_ERR_FAILED,
 971                                  MessageLoaderParms(
 972                                      "ProviderManager.OOPProviderManagerRouter."
 973                                          "CIMPROVAGT_CONNECTION_LOST",
 974                                      "Lost connection with cimprovagt \"$0\".",
 975                                      _moduleName));
 976                          }
 977                      }
 978 kumpf       1.1      catch (CIMException& e)
 979                      {
 980 thilo.boehm 1.22         PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL1,
 981                              "Caught CIMException: %s",
 982                              (const char*)e.getMessage().getCString()));
 983 kumpf       1.1          response = request->buildResponse();
 984                          response->cimException = e;
 985                      }
 986                      catch (Exception& e)
 987                      {
 988 thilo.boehm 1.22         PEG_TRACE((TRC_PROVIDERMANAGER, Tracer::LEVEL1,
 989                              "Caught Exception: %s",
 990                              (const char*)e.getMessage().getCString()));
 991 kumpf       1.1          response = request->buildResponse();
 992                          response->cimException = PEGASUS_CIM_EXCEPTION(
 993                              CIM_ERR_FAILED, e.getMessage());
 994                      }
 995                      catch (...)
 996                      {
 997 marek       1.9          PEG_TRACE_CSTRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
 998 kumpf       1.1              "Caught unknown exception");
 999                          response = request->buildResponse();
1000                          response->cimException = PEGASUS_CIM_EXCEPTION(
1001                              CIM_ERR_FAILED, String::EMPTY);
1002                      }
1003                  
1004                      response->messageId = originalMessageId;
1005 kumpf       1.17     response->syncAttributes(request);
1006 kumpf       1.1  
1007                      PEG_METHOD_EXIT();
1008                      return response;
1009                  }
1010                  
1011                  void ProviderAgentContainer::unloadIdleProviders()
1012                  {
1013                      PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1014                          "ProviderAgentContainer::unloadIdleProviders");
1015                  
1016                      AutoMutex lock(_agentMutex);
1017                      if (_isInitialized)
1018                      {
1019                          // Send a "wake up" message to the Provider Agent.
1020                          // Don't bother checking whether the operation is successful.
1021                          Uint32 messageLength = 0;
1022                          _pipeToAgent->writeBuffer((const char*)&messageLength, sizeof(Uint32));
1023                      }
1024                  
1025                      PEG_METHOD_EXIT();
1026                  }
1027 kumpf       1.1  
1028                  void ProviderAgentContainer::_processResponses()
1029                  {
1030                      PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1031                          "ProviderAgentContainer::_processResponses");
1032                  
1033                      //
1034                      // Process responses until the pipe is closed
1035                      //
1036                      while (1)
1037                      {
1038                          try
1039                          {
1040                              CIMMessage* message;
1041                  
1042                              //
1043                              // Read a response from the Provider Agent
1044                              //
1045                              AnonymousPipe::Status readStatus =
1046                                  _pipeFromAgent->readMessage(message);
1047                  
1048 kumpf       1.1              // Ignore interrupts
1049                              if (readStatus == AnonymousPipe::STATUS_INTERRUPT)
1050                              {
1051                                  continue;
1052                              }
1053                  
1054                              // Handle an error the same way as a closed connection
1055                              if ((readStatus == AnonymousPipe::STATUS_ERROR) ||
1056                                  (readStatus == AnonymousPipe::STATUS_CLOSED))
1057                              {
1058                                  _uninitialize(false);
1059                                  return;
1060                              }
1061                  
1062                              // A null message indicates that the provider agent process has
1063                              // finished its processing and is ready to exit.
1064                              if (message == 0)
1065                              {
1066                                  _uninitialize(true);
1067                                  return;
1068                              }
1069 kumpf       1.1  
1070                              if (message->getType() == CIM_PROCESS_INDICATION_REQUEST_MESSAGE)
1071                              {
1072 kumpf       1.10                 // Process an indication message
1073                  
1074 kumpf       1.1                  _indicationCallback(
1075                                      reinterpret_cast<CIMProcessIndicationRequestMessage*>(
1076                                          message));
1077                              }
1078                              else if (!message->isComplete())
1079                              {
1080 kumpf       1.10                 // Process an incomplete response chunk
1081                  
1082 kumpf       1.1                  CIMResponseMessage* response;
1083                                  response = dynamic_cast<CIMResponseMessage*>(message);
1084                                  PEGASUS_ASSERT(response != 0);
1085                  
1086                                  // Get the OutstandingRequestEntry for this response chunk
1087                                  OutstandingRequestEntry* _outstandingRequestEntry = 0;
1088                                  {
1089                                      AutoMutex tableLock(_outstandingRequestTableMutex);
1090                                      Boolean foundEntry = _outstandingRequestTable.lookup(
1091                                          response->messageId, _outstandingRequestEntry);
1092                                      PEGASUS_ASSERT(foundEntry);
1093                                  }
1094                  
1095                                  // Put the original message ID into the response
1096                                  response->messageId =
1097                                      _outstandingRequestEntry->originalMessageId;
1098                  
1099                                  // Call the response chunk callback to process the chunk
1100                                  _responseChunkCallback(
1101                                      _outstandingRequestEntry->requestMessage, response);
1102                              }
1103 kumpf       1.1              else
1104                              {
1105 kumpf       1.10                 // Process a completed response
1106                  
1107 kumpf       1.1                  CIMResponseMessage* response;
1108                                  response = dynamic_cast<CIMResponseMessage*>(message);
1109                                  PEGASUS_ASSERT(response != 0);
1110                  
1111                                  // Give the response to the waiting OutstandingRequestEntry
1112                                  OutstandingRequestEntry* _outstandingRequestEntry = 0;
1113                                  {
1114                                      AutoMutex tableLock(_outstandingRequestTableMutex);
1115                                      Boolean foundEntry = _outstandingRequestTable.lookup(
1116                                          response->messageId, _outstandingRequestEntry);
1117                                      PEGASUS_ASSERT(foundEntry);
1118                  
1119                                      // Remove the completed request from the table
1120                                      Boolean removed =
1121                                          _outstandingRequestTable.remove(response->messageId);
1122                                      PEGASUS_ASSERT(removed);
1123                                  }
1124                  
1125                                  _outstandingRequestEntry->responseMessage = response;
1126                                  _outstandingRequestEntry->responseReady->signal();
1127                              }
1128 kumpf       1.1          }
1129                          catch (Exception& e)
1130                          {
1131 thilo.boehm 1.22             PEG_TRACE((TRC_DISCARDED_DATA, Tracer::LEVEL2,
1132                                  "Ignoring exception: %s",
1133                                  (const char*)e.getMessage().getCString()));
1134 kumpf       1.1          }
1135                          catch (...)
1136                          {
1137 marek       1.9              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
1138 kumpf       1.1                  "Ignoring exception");
1139                          }
1140                      }
1141                  
1142                  }
1143                  
1144                  ThreadReturnType PEGASUS_THREAD_CDECL
1145                  ProviderAgentContainer::_responseProcessor(void* arg)
1146                  {
1147                      ProviderAgentContainer* pa =
1148                          reinterpret_cast<ProviderAgentContainer*>(arg);
1149                  
1150                      pa->_processResponses();
1151                  
1152 kumpf       1.6      return ThreadReturnType(0);
1153 kumpf       1.1  }
1154                  
1155                  /////////////////////////////////////////////////////////////////////////////
1156                  // OOPProviderManagerRouter
1157                  /////////////////////////////////////////////////////////////////////////////
1158                  
1159                  OOPProviderManagerRouter::OOPProviderManagerRouter(
1160                      PEGASUS_INDICATION_CALLBACK_T indicationCallback,
1161                      PEGASUS_RESPONSE_CHUNK_CALLBACK_T responseChunkCallback,
1162                      PEGASUS_PROVIDERMODULEFAIL_CALLBACK_T providerModuleFailCallback)
1163                  {
1164                      PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1165                          "OOPProviderManagerRouter::OOPProviderManagerRouter");
1166                  
1167                      _indicationCallback = indicationCallback;
1168                      _responseChunkCallback = responseChunkCallback;
1169                      _providerModuleFailCallback = providerModuleFailCallback;
1170                      _subscriptionInitComplete = false;
1171                  
1172                      PEG_METHOD_EXIT();
1173                  }
1174 kumpf       1.1  
1175                  OOPProviderManagerRouter::~OOPProviderManagerRouter()
1176                  {
1177                      PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1178                          "OOPProviderManagerRouter::~OOPProviderManagerRouter");
1179                  
1180                      try
1181                      {
1182                          // Clean up the ProviderAgentContainers
1183                          AutoMutex lock(_providerAgentTableMutex);
1184                          ProviderAgentTable::Iterator i = _providerAgentTable.start();
1185 kumpf       1.6          for (; i != 0; i++)
1186 kumpf       1.1          {
1187                              delete i.value();
1188                          }
1189                      }
1190                      catch (...) {}
1191                  
1192                      PEG_METHOD_EXIT();
1193                  }
1194                  
1195                  Message* OOPProviderManagerRouter::processMessage(Message* message)
1196                  {
1197                      PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1198                          "OOPProviderManagerRouter::processMessage");
1199                  
1200                      CIMRequestMessage* request = dynamic_cast<CIMRequestMessage *>(message);
1201                      PEGASUS_ASSERT(request != 0);
1202                  
1203                      AutoPtr<CIMResponseMessage> response;
1204                  
1205                      //
1206                      // Get the provider information from the request
1207 kumpf       1.1      //
1208                      CIMInstance providerModule;
1209                  
1210                      if ((dynamic_cast<CIMOperationRequestMessage*>(request) != 0) ||
1211                          (dynamic_cast<CIMIndicationRequestMessage*>(request) != 0) ||
1212                          (request->getType() == CIM_EXPORT_INDICATION_REQUEST_MESSAGE))
1213                      {
1214                          // Provider information is in the OperationContext
1215                          ProviderIdContainer pidc = (ProviderIdContainer)
1216                              request->operationContext.get(ProviderIdContainer::NAME);
1217                          providerModule = pidc.getModule();
1218                      }
1219                      else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
1220                      {
1221                          CIMEnableModuleRequestMessage* emReq =
1222                              dynamic_cast<CIMEnableModuleRequestMessage*>(request);
1223                          providerModule = emReq->providerModule;
1224                      }
1225                      else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
1226                      {
1227                          CIMDisableModuleRequestMessage* dmReq =
1228 kumpf       1.1              dynamic_cast<CIMDisableModuleRequestMessage*>(request);
1229                          providerModule = dmReq->providerModule;
1230                      }
1231                      else if ((request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE) ||
1232                               (request->getType() ==
1233                                   CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE) ||
1234                               (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE))
1235                      {
1236                          // This operation is not provider-specific
1237                      }
1238                      else
1239                      {
1240                          // Unrecognized message type.  This should never happen.
1241                          PEGASUS_ASSERT(0);
1242                          response.reset(request->buildResponse());
1243                          response->cimException = PEGASUS_CIM_EXCEPTION(
1244                              CIM_ERR_FAILED, "Unrecognized message type.");
1245                          PEG_METHOD_EXIT();
1246                          return response.release();
1247                      }
1248                  
1249 kumpf       1.1      //
1250                      // Process the request message
1251                      //
1252                      if (request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE)
1253                      {
1254                          // Forward the CIMStopAllProvidersRequest to all providers
1255                          response.reset(_forwardRequestToAllAgents(request));
1256                  
1257                          // Note: Do not uninitialize the ProviderAgentContainers here.
1258                          // Just let the selecting thread notice when the agent connections
1259                          // are closed.
1260                      }
1261 kumpf       1.6      else if (request->getType () ==
1262 kumpf       1.1          CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE)
1263                      {
1264                          _subscriptionInitComplete = true;
1265                  
1266                          //
1267 kumpf       1.6          //  Forward the CIMSubscriptionInitCompleteRequestMessage to
1268 kumpf       1.1          //  all providers
1269                          //
1270                          response.reset (_forwardRequestToAllAgents (request));
1271                      }
1272                      else if (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE)
1273                      {
1274                          CIMNotifyConfigChangeRequestMessage* notifyRequest =
1275                              dynamic_cast<CIMNotifyConfigChangeRequestMessage*>(request);
1276                          PEGASUS_ASSERT(notifyRequest != 0);
1277                  
1278                          if (notifyRequest->currentValueModified)
1279                          {
1280                              // Forward the CIMNotifyConfigChangeRequestMessage to all providers
1281                              response.reset(_forwardRequestToAllAgents(request));
1282                          }
1283                          else
1284                          {
1285                              // No need to notify provider agents about changes to planned value
1286                              response.reset(request->buildResponse());
1287                          }
1288                      }
1289 kumpf       1.1      else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
1290                      {
1291                          // Fan out the request to all Provider Agent processes for this module
1292                  
1293                          // Retrieve the provider module name
1294                          String moduleName;
1295                          CIMValue nameValue = providerModule.getProperty(
1296 marek       1.23             providerModule.findProperty(PEGASUS_PROPERTYNAME_NAME)).getValue();
1297 kumpf       1.1          nameValue.get(moduleName);
1298                  
1299                          // Look up the Provider Agents for this module
1300                          Array<ProviderAgentContainer*> paArray =
1301                              _lookupProviderAgents(moduleName);
1302                  
1303                          for (Uint32 i=0; i<paArray.size(); i++)
1304                          {
1305                              //
1306                              // Do not start up an agent process just to disable the module
1307                              //
1308                              if (paArray[i]->isInitialized())
1309                              {
1310                                  //
1311                                  // Forward the request to the provider agent
1312                                  //
1313                                  response.reset(paArray[i]->processMessage(request));
1314                  
1315                                  // Note: Do not uninitialize the ProviderAgentContainer here
1316                                  // when a disable module operation is successful.  Just let the
1317                                  // selecting thread notice when the agent connection is closed.
1318 kumpf       1.1  
1319                                  // Determine the success of the disable module operation
1320                                  CIMDisableModuleResponseMessage* dmResponse =
1321                                      dynamic_cast<CIMDisableModuleResponseMessage*>(
1322                                          response.get());
1323                                  PEGASUS_ASSERT(dmResponse != 0);
1324                  
1325                                  Boolean isStopped = false;
1326 kumpf       1.21                 for (Uint32 j=0; j < dmResponse->operationalStatus.size(); j++)
1327 kumpf       1.1                  {
1328 kumpf       1.21                     if (dmResponse->operationalStatus[j] ==
1329 kumpf       1.1                          CIM_MSE_OPSTATUS_VALUE_STOPPED)
1330                                      {
1331                                          isStopped = true;
1332                                          break;
1333                                      }
1334                                  }
1335                  
1336                                  // If the operation is unsuccessful, stop and return the error
1337                                  if ((dmResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
1338                                      !isStopped)
1339                                  {
1340                                      break;
1341                                  }
1342                              }
1343                          }
1344                  
1345                          // Use a default response if no Provider Agents were called
1346                          if (!response.get())
1347                          {
1348                              response.reset(request->buildResponse());
1349                  
1350 kumpf       1.1              CIMDisableModuleResponseMessage* dmResponse =
1351                                  dynamic_cast<CIMDisableModuleResponseMessage*>(response.get());
1352                              PEGASUS_ASSERT(dmResponse != 0);
1353                  
1354                              Array<Uint16> operationalStatus;
1355                              operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_STOPPED);
1356                              dmResponse->operationalStatus = operationalStatus;
1357                          }
1358                      }
1359                      else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
1360                      {
1361                          // Fan out the request to all Provider Agent processes for this module
1362                  
1363                          // Retrieve the provider module name
1364                          String moduleName;
1365                          CIMValue nameValue = providerModule.getProperty(
1366 marek       1.23             providerModule.findProperty(PEGASUS_PROPERTYNAME_NAME)).getValue();
1367 kumpf       1.1          nameValue.get(moduleName);
1368                  
1369                          // Look up the Provider Agents for this module
1370                          Array<ProviderAgentContainer*> paArray =
1371                              _lookupProviderAgents(moduleName);
1372                  
1373                          for (Uint32 i=0; i<paArray.size(); i++)
1374                          {
1375                              //
1376                              // Do not start up an agent process just to enable the module
1377                              //
1378                              if (paArray[i]->isInitialized())
1379                              {
1380                                  //
1381                                  // Forward the request to the provider agent
1382                                  //
1383                                  response.reset(paArray[i]->processMessage(request));
1384                  
1385                                  // Determine the success of the enable module operation
1386                                  CIMEnableModuleResponseMessage* emResponse =
1387                                      dynamic_cast<CIMEnableModuleResponseMessage*>(
1388 kumpf       1.1                          response.get());
1389                                  PEGASUS_ASSERT(emResponse != 0);
1390                  
1391                                  Boolean isOk = false;
1392 kumpf       1.21                 for (Uint32 j=0; j < emResponse->operationalStatus.size(); j++)
1393 kumpf       1.1                  {
1394 kumpf       1.21                     if (emResponse->operationalStatus[j] ==
1395 kumpf       1.1                          CIM_MSE_OPSTATUS_VALUE_OK)
1396                                      {
1397                                          isOk = true;
1398                                          break;
1399                                      }
1400                                  }
1401                  
1402                                  // If the operation is unsuccessful, stop and return the error
1403                                  if ((emResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
1404                                      !isOk)
1405                                  {
1406                                      break;
1407                                  }
1408                              }
1409                          }
1410                  
1411                          // Use a default response if no Provider Agents were called
1412                          if (!response.get())
1413                          {
1414                              response.reset(request->buildResponse());
1415                  
1416 kumpf       1.1              CIMEnableModuleResponseMessage* emResponse =
1417                                  dynamic_cast<CIMEnableModuleResponseMessage*>(response.get());
1418                              PEGASUS_ASSERT(emResponse != 0);
1419                  
1420                              Array<Uint16> operationalStatus;
1421                              operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_OK);
1422                              emResponse->operationalStatus = operationalStatus;
1423                          }
1424                      }
1425                      else
1426                      {
1427                          //
1428                          // Look up the Provider Agent for this module instance and requesting
1429                          // user
1430                          //
1431                          ProviderAgentContainer* pa = _lookupProviderAgent(providerModule,
1432                              request);
1433                          PEGASUS_ASSERT(pa != 0);
1434                  
1435                          //
1436                          // Forward the request to the provider agent
1437 kumpf       1.1          //
1438                          response.reset(pa->processMessage(request));
1439                      }
1440                  
1441                      PEG_METHOD_EXIT();
1442                      return response.release();
1443                  }
1444                  
1445                  ProviderAgentContainer* OOPProviderManagerRouter::_lookupProviderAgent(
1446                      const CIMInstance& providerModule,
1447                      CIMRequestMessage* request)
1448                  {
1449                      // Retrieve the provider module name
1450                      String moduleName;
1451                      CIMValue nameValue = providerModule.getProperty(
1452 marek       1.23         providerModule.findProperty(PEGASUS_PROPERTYNAME_NAME)).getValue();
1453 kumpf       1.1      nameValue.get(moduleName);
1454                  
1455                      // Retrieve the provider user context configuration
1456                      Uint16 userContext = 0;
1457                      Uint32 pos = providerModule.findProperty(
1458                          PEGASUS_PROPERTYNAME_MODULE_USERCONTEXT);
1459                      if (pos != PEG_NOT_FOUND)
1460                      {
1461                          CIMValue userContextValue =
1462                              providerModule.getProperty(pos).getValue();
1463                          if (!userContextValue.isNull())
1464                          {
1465                              userContextValue.get(userContext);
1466                          }
1467                      }
1468                  
1469                      if (userContext == 0)
1470                      {
1471 ouyang.jian 1.15         // PASE has a default user context "QYCMCIMOM",
1472                          // so we leave userContext unset here.
1473                  #ifndef PEGASUS_OS_PASE
1474 kumpf       1.1          userContext = PEGASUS_DEFAULT_PROV_USERCTXT;
1475 ouyang.jian 1.15 #endif
1476 kumpf       1.1      }
1477                  
1478                      String userName;
1479                  
1480                      if (userContext == PG_PROVMODULE_USERCTXT_REQUESTOR)
1481                      {
1482 kumpf       1.6          if (request->operationContext.contains(IdentityContainer::NAME))
1483 kumpf       1.1          {
1484                              // User Name is in the OperationContext
1485                              IdentityContainer ic = (IdentityContainer)
1486                                  request->operationContext.get(IdentityContainer::NAME);
1487                              userName = ic.getUserName();
1488                          }
1489                          //else
1490                          //{
1491                          //    If no IdentityContainer is present, default to the CIM
1492                          //    Server's user context
1493                          //}
1494                  
1495                          // If authentication is disabled, use the CIM Server's user context
1496                          if (!userName.size())
1497                          {
1498                              userName = System::getEffectiveUserName();
1499                          }
1500                      }
1501                      else if (userContext == PG_PROVMODULE_USERCTXT_DESIGNATED)
1502                      {
1503                          // Retrieve the provider module designated user property value
1504 kumpf       1.1          providerModule.getProperty(providerModule.findProperty(
1505                              PEGASUS_PROPERTYNAME_MODULE_DESIGNATEDUSER)).getValue().
1506                              get(userName);
1507                      }
1508                      else if (userContext == PG_PROVMODULE_USERCTXT_CIMSERVER)
1509                      {
1510                          userName = System::getEffectiveUserName();
1511                      }
1512 ouyang.jian 1.15 #ifdef PEGASUS_OS_PASE // it might be unset user in PASE in this branch.
1513                      else if (userContext == 0)
1514                      {
1515                          userName = "QYCMCIMOM";
1516                      }
1517                  #endif
1518 kumpf       1.1      else    // Privileged User
1519                      {
1520                          PEGASUS_ASSERT(userContext == PG_PROVMODULE_USERCTXT_PRIVILEGED);
1521                          userName = System::getPrivilegedUserName();
1522                      }
1523                  
1524 marek       1.20     PEG_TRACE((
1525                          TRC_PROVIDERMANAGER,
1526                          Tracer::LEVEL4,
1527                          "Module name = %s, User context = %hd, User name = %s",
1528                          (const char*) moduleName.getCString(),
1529                          userContext,
1530                          (const char*) userName.getCString()));
1531                  
1532 kumpf       1.1  
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