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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2