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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2