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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2