(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 kumpf           1.21     //
 339                          // Serialize the starting of agent processes.  If two agent processes are
 340                          // started at the same time, they may get copies of each other's pipe
 341                          // descriptors.  If this happens, the cimserver will not get a pipe read
 342                          // error when one of the agent processes exits, because the pipe will
 343                          // still be writable by the other process.  This locking control needs to
 344                          // cover the period from where the pipes are created to where the agent
 345                          // ends of the pipes are closed by the cimserver.
 346                          //
 347                          static Mutex agentStartupMutex;
 348                          AutoMutex lock(agentStartupMutex);
 349                      
 350 kumpf           1.1      AutoPtr<AnonymousPipe> pipeFromAgent(new AnonymousPipe());
 351                          AutoPtr<AnonymousPipe> pipeToAgent(new AnonymousPipe());
 352                      
 353                          //
 354                          // Start a cimprovagt process for this provider module
 355                          //
 356                      
 357                      #if defined (PEGASUS_OS_TYPE_WINDOWS)
 358                          //
 359                          //  Set up members of the PROCESS_INFORMATION structure
 360                          //
 361                          PROCESS_INFORMATION piProcInfo;
 362                          ZeroMemory (&piProcInfo, sizeof (PROCESS_INFORMATION));
 363                      
 364                          //
 365                          //  Set up members of the STARTUPINFO structure
 366                          //
 367                          STARTUPINFO siStartInfo;
 368                          ZeroMemory (&siStartInfo, sizeof (STARTUPINFO));
 369                          siStartInfo.cb = sizeof (STARTUPINFO);
 370                      
 371 kumpf           1.1      //
 372                          //  Generate the command line
 373                          //
 374                          char cmdLine[2048];
 375                          char readHandle[32];
 376                          char writeHandle[32];
 377                          pipeToAgent->exportReadHandle(readHandle);
 378                          pipeFromAgent->exportWriteHandle(writeHandle);
 379                      
 380                          sprintf(cmdLine, "\"%s\" %s %s \"%s\"",
 381                              (const char*)ConfigManager::getHomedPath(
 382                                  PEGASUS_PROVIDER_AGENT_PROC_NAME).getCString(),
 383                              readHandle, writeHandle, (const char*)_moduleName.getCString());
 384                      
 385                          //
 386                          //  Create the child process
 387                          //
 388                          if (!CreateProcess (
 389                              NULL,          //
 390                              cmdLine,       //  command line
 391                              NULL,          //  process security attributes
 392 kumpf           1.1          NULL,          //  primary thread security attributes
 393                              TRUE,          //  handles are inherited
 394                              0,             //  creation flags
 395                              NULL,          //  use parent's environment
 396                              NULL,          //  use parent's current directory
 397                              &siStartInfo,  //  STARTUPINFO
 398                              &piProcInfo))  //  PROCESS_INFORMATION
 399                          {
 400                              Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
 401                                  "CreateProcess() failed.  errno = %d.", GetLastError());
 402                              PEG_METHOD_EXIT();
 403                              throw Exception(MessageLoaderParms(
 404                                  "ProviderManager.OOPProviderManagerRouter.CIMPROVAGT_START_FAILED",
 405                                  "Failed to start cimprovagt \"$0\".",
 406                                  _moduleName));
 407                          }
 408                      
 409                          CloseHandle(piProcInfo.hProcess);
 410                          CloseHandle(piProcInfo.hThread);
 411 gs.keenan       1.8  
 412                      #elif defined (PEGASUS_OS_VMS)
 413                      
 414 gs.keenan       1.10     //
 415                          //  fork and exec the child process
 416                          //
 417                          int status;
 418 gs.keenan       1.8  
 419 gs.keenan       1.10     status = vfork ();
 420                          switch (status)
 421                          {
 422                            case 0:
 423                              try
 424 gs.keenan       1.8          {
 425 gs.keenan       1.10           //
 426                                // Execute the cimprovagt program
 427                                //
 428                                String agentCommandPath =
 429                                    ConfigManager::getHomedPath(PEGASUS_PROVIDER_AGENT_PROC_NAME);
 430                                CString agentCommandPathCString = agentCommandPath.getCString();
 431                      
 432                                char readHandle[32];
 433                                char writeHandle[32];
 434                                pipeToAgent->exportReadHandle(readHandle);
 435                                pipeFromAgent->exportWriteHandle(writeHandle);
 436                      
 437                                if ((status = execl(agentCommandPathCString, agentCommandPathCString,
 438                                    readHandle, writeHandle,
 439                                    (const char*)_moduleName.getCString(), (char*)0)) == -1);
 440                                {
 441                                  // If we're still here, there was an error
 442                                  Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
 443                                      "execl() failed.  errno = %d.", errno);
 444                                  _exit(1);
 445                                }
 446 gs.keenan       1.10         }
 447                              catch (...)
 448                              {
 449                                // There's not much we can do here in no man's land
 450                                try
 451                                {
 452                                  PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
 453                                      "Caught exception before calling execl().");
 454                                }
 455                                catch (...) 
 456                                {
 457                                }
 458                               _exit(1);
 459                              }
 460                              PEG_METHOD_EXIT();
 461                              return;
 462                              break;
 463                      
 464                            case -1:
 465                              Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
 466                                  "fork() failed.  errno = %d.", errno);
 467 gs.keenan       1.10         PEG_METHOD_EXIT();
 468                              throw Exception(MessageLoaderParms(
 469                                  "ProviderManager.OOPProviderManagerRouter.CIMPROVAGT_START_FAILED",
 470                                  "Failed to start cimprovagt \"$0\".",
 471                                  _moduleName));
 472                              break;
 473                      
 474                            default:
 475                              // Close our copies of the agent's ends of the pipes
 476                              pipeToAgent->closeReadHandle();
 477                              pipeFromAgent->closeWriteHandle();
 478 gs.keenan       1.8  
 479 gs.keenan       1.10         _pipeToAgent.reset(pipeToAgent.release());
 480                              _pipeFromAgent.reset(pipeFromAgent.release());
 481 gs.keenan       1.8  
 482 gs.keenan       1.10         PEG_METHOD_EXIT();
 483                          }
 484 chuck           1.16 #elif defined (PEGASUS_OS_OS400)
 485                      
 486                          //Out of provider support for OS400 goes here when needed.
 487                      
 488 kumpf           1.1  #else
 489                          pid_t pid = fork();
 490                          if (pid < 0)
 491                          {
 492                              Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
 493                                  "fork() failed.  errno = %d.", errno);
 494                              PEG_METHOD_EXIT();
 495                              throw Exception(MessageLoaderParms(
 496                                  "ProviderManager.OOPProviderManagerRouter.CIMPROVAGT_START_FAILED",
 497                                  "Failed to start cimprovagt \"$0\".",
 498                                  _moduleName));
 499                          }
 500                          else if (pid == 0)
 501                          {
 502                              //
 503                              // Child side of the fork
 504                              //
 505                      
 506                              try
 507                              {
 508                                  // Close our copies of the parent's ends of the pipes
 509 kumpf           1.1              pipeToAgent->closeWriteHandle();
 510                                  pipeFromAgent->closeReadHandle();
 511                      
 512                                  //
 513                                  // Execute the cimprovagt program
 514                                  //
 515                                  String agentCommandPath =
 516                                      ConfigManager::getHomedPath(PEGASUS_PROVIDER_AGENT_PROC_NAME);
 517                                  CString agentCommandPathCString = agentCommandPath.getCString();
 518                      
 519                                  char readHandle[32];
 520                                  char writeHandle[32];
 521                                  pipeToAgent->exportReadHandle(readHandle);
 522                                  pipeFromAgent->exportWriteHandle(writeHandle);
 523                      
 524 kumpf           1.13 #ifndef PEGASUS_DISABLE_PROV_USERCTXT
 525 kumpf           1.6              // Set the user context of the Provider Agent process
 526                                  if (_userName != System::getEffectiveUserName())
 527                                  {
 528                                      if (!System::changeUserContext(_userName.getCString()))
 529                                      {
 530                                          Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
 531                                              "System::changeUserContext() failed.  userName = %s.",
 532 kumpf           1.9                          (const char*)_userName.getCString());
 533 kumpf           1.6                      Logger::put_l(Logger::ERROR_LOG, System::CIMSERVER,
 534                                              Logger::WARNING,
 535                                              "ProviderManager.OOPProviderManagerRouter."
 536                                                  "USER_CONTEXT_CHANGE_FAILED",
 537                                              "Unable to change user context to \"$0\".", _userName);
 538                                          _exit(1);
 539                                      }
 540                                  }
 541 kumpf           1.13 #endif
 542 kumpf           1.6  
 543 kumpf           1.1              execl(agentCommandPathCString, agentCommandPathCString,
 544                                      readHandle, writeHandle,
 545                                      (const char*)_moduleName.getCString(), (char*)0);
 546                      
 547                                  // If we're still here, there was an error
 548                                  Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
 549                                      "execl() failed.  errno = %d.", errno);
 550                                  _exit(1);
 551                              }
 552                              catch (...)
 553                              {
 554                                  // There's not much we can do here in no man's land
 555                                  try
 556                                  {
 557                                      PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
 558                                          "Caught exception before calling execl().");
 559                                  }
 560                                  catch (...) {}
 561                                  _exit(1);
 562                              }
 563                          }
 564 kumpf           1.18 # if defined(PEGASUS_HAS_SIGNALS)
 565                          _pid = pid;
 566                      # endif
 567 kumpf           1.1  #endif
 568                      
 569                          //
 570                          // CIM Server process
 571                          //
 572                      
 573                          // Close our copies of the agent's ends of the pipes
 574                          pipeToAgent->closeReadHandle();
 575                          pipeFromAgent->closeWriteHandle();
 576                      
 577                          _pipeToAgent.reset(pipeToAgent.release());
 578                          _pipeFromAgent.reset(pipeFromAgent.release());
 579                      
 580 gs.keenan       1.10     PEG_METHOD_EXIT();
 581 kumpf           1.1  }
 582                      
 583                      // Note: Caller must lock _agentMutex
 584                      void ProviderAgentContainer::_sendInitializationData()
 585                      {
 586                          PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 587                              "ProviderAgentContainer::_sendInitializationData");
 588                      
 589                          //
 590                          // Gather config properties to pass to the Provider Agent
 591                          //
 592                          ConfigManager* configManager = ConfigManager::getInstance();
 593                          Array<Pair<String, String> > configProperties;
 594                      
 595                          Array<String> configPropertyNames;
 596                          configManager->getAllPropertyNames(configPropertyNames, true);
 597                          for (Uint32 i = 0; i < configPropertyNames.size(); i++)
 598                          {
 599                              String configPropertyValue =
 600                                  configManager->getCurrentValue(configPropertyNames[i]);
 601                              String configPropertyDefaultValue =
 602 kumpf           1.1              configManager->getDefaultValue(configPropertyNames[i]);
 603                              if (configPropertyValue != configPropertyDefaultValue)
 604                              {
 605                                  configProperties.append(Pair<String, String>(
 606                                      configPropertyNames[i], configPropertyValue));
 607                              }
 608                          }
 609                      
 610                          //
 611                          // Create a Provider Agent initialization message
 612                          //
 613                          AutoPtr<CIMInitializeProviderAgentRequestMessage> request(
 614                              new CIMInitializeProviderAgentRequestMessage(
 615                                  String("0"),    // messageId
 616                                  configManager->getPegasusHome(),
 617                                  configProperties,
 618                                  System::bindVerbose,
 619 carolann.graves 1.14             _subscriptionInitComplete,
 620 kumpf           1.1              QueueIdStack()));
 621                      
 622                          //
 623                          // Write the initialization message to the pipe
 624                          //
 625                          AnonymousPipe::Status writeStatus =
 626                              _pipeToAgent->writeMessage(request.get());
 627                      
 628                          if (writeStatus != AnonymousPipe::STATUS_SUCCESS)
 629                          {
 630                              PEG_METHOD_EXIT();
 631                              throw Exception(MessageLoaderParms(
 632                                  "ProviderManager.OOPProviderManagerRouter."
 633                                      "CIMPROVAGT_COMMUNICATION_FAILED",
 634                                  "Failed to communicate with cimprovagt \"$0\".",
 635                                  _moduleName));
 636                          }
 637                      
 638                          // Do not wait for a response from the Provider Agent.  (It isn't coming.)
 639                      
 640                          PEG_METHOD_EXIT();
 641 kumpf           1.1  }
 642                      
 643                      // Note: Caller must lock _agentMutex
 644                      void ProviderAgentContainer::_initialize()
 645                      {
 646                          PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 647                              "ProviderAgentContainer::_initialize");
 648                      
 649                          if (_isInitialized)
 650                          {
 651                              PEGASUS_ASSERT(0);
 652                              PEG_METHOD_EXIT();
 653                              return;
 654                          }
 655                      
 656 kumpf           1.6      if (_maxProviderProcesses == PEG_NOT_FOUND)
 657                          {
 658                              String maxProviderProcesses = ConfigManager::getInstance()->getCurrentValue("maxProviderProcesses");
 659                              CString maxProviderProcessesString = maxProviderProcesses.getCString();
 660                              char* end = 0;
 661                              _maxProviderProcesses = strtol(maxProviderProcessesString, &end, 10);
 662                          }
 663                      
 664                          {
 665                              AutoMutex lock(_numProviderProcessesMutex);
 666                              if ((_maxProviderProcesses != 0) &&
 667                                  (_numProviderProcesses >= _maxProviderProcesses))
 668                              {
 669                                  throw PEGASUS_CIM_EXCEPTION(
 670                                      CIM_ERR_FAILED,
 671                                      MessageLoaderParms(
 672                                          "ProviderManager.OOPProviderManagerRouter."
 673                                              "MAX_PROVIDER_PROCESSES_REACHED",
 674                                          "The maximum number of cimprovagt processes has been "
 675                                              "reached."));
 676                              }
 677 kumpf           1.6          else
 678                              {
 679                                  _numProviderProcesses++;
 680                              }
 681                          }
 682                      
 683 kumpf           1.1      try
 684                          {
 685                              _startAgentProcess();
 686                      
 687 kumpf           1.18         _isInitialized = true;
 688                      
 689 kumpf           1.1          _sendInitializationData();
 690                      
 691                              // Start a thread to read and process responses from the Provider Agent
 692 kumpf           1.20         ThreadStatus rtn = PEGASUS_THREAD_OK;
 693                              while ((rtn = MessageQueueService::get_thread_pool()->
 694                                         allocate_and_awaken(this, _responseProcessor)) !=
 695                                     PEGASUS_THREAD_OK)
 696                              {
 697                                  if (rtn == PEGASUS_THREAD_INSUFFICIENT_RESOURCES)
 698                                  {
 699                                      pegasus_yield();
 700                                  }
 701                                  else
 702                                  {
 703                                      Logger::put(
 704                                          Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
 705                                          "Not enough threads to process responses from the "
 706                                              "provider agent.");
 707 konrad.r        1.19  
 708 kumpf           1.20                 Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
 709                                          "Could not allocate thread to process responses from the "
 710                                              "provider agent.");
 711                      
 712                                      throw Exception(MessageLoaderParms(
 713                                          "ProviderManager.OOPProviderManagerRouter."
 714                                              "CIMPROVAGT_THREAD_ALLOCATION_FAILED",
 715                                          "Failed to allocate thread for cimprovagt \"$0\".",
 716                                          _moduleName));
 717                                  }
 718                              }
 719 kumpf           1.1      }
 720                          catch (...)
 721                          {
 722 kumpf           1.20         // Closing the connection causes the agent process to exit
 723                              _pipeToAgent.reset();
 724                              _pipeFromAgent.reset();
 725                      
 726 kumpf           1.18 #if defined(PEGASUS_HAS_SIGNALS)
 727                              if (_isInitialized)
 728                              {
 729                                  // Harvest the status of the agent process to prevent a zombie
 730                                  Boolean keepWaiting = false;
 731                                  do
 732                                  {
 733                                      pid_t status = waitpid(_pid, 0, 0);
 734                                      if (status == -1)
 735                                      {
 736                                          if (errno == EINTR)
 737                                          {
 738                                              keepWaiting = true;
 739                                          }
 740                                          else
 741                                          {
 742                                              Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
 743                                                  "ProviderAgentContainer::_initialize(): "
 744                                                      "waitpid failed; errno = %d.", errno);
 745                                          }
 746                                      }
 747 kumpf           1.18             } while (keepWaiting);
 748                              }
 749                      #endif
 750                      
 751 kumpf           1.1          _isInitialized = false;
 752 kumpf           1.6  
 753                              {
 754                                  AutoMutex lock(_numProviderProcessesMutex);
 755                                  _numProviderProcesses--;
 756                              }
 757                      
 758 kumpf           1.1          PEG_METHOD_EXIT();
 759                              throw;
 760                          }
 761                      
 762                          PEG_METHOD_EXIT();
 763                      }
 764                      
 765                      Boolean ProviderAgentContainer::isInitialized()
 766                      {
 767                          AutoMutex lock(_agentMutex);
 768                          return _isInitialized;
 769                      }
 770                      
 771                      // Note: Caller must lock _agentMutex
 772                      void ProviderAgentContainer::_uninitialize()
 773                      {
 774                          PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 775                              "ProviderAgentContainer::_uninitialize");
 776                      
 777                          if (!_isInitialized)
 778                          {
 779 kumpf           1.1          PEGASUS_ASSERT(0);
 780                              PEG_METHOD_EXIT();
 781                              return;
 782                          }
 783                      
 784                          try
 785                          {
 786                              // Close the connection with the Provider Agent
 787                              _pipeFromAgent.reset();
 788                              _pipeToAgent.reset();
 789                      
 790 kumpf           1.2          _providerModuleCache = CIMInstance();
 791                      
 792 kumpf           1.6          {
 793                                  AutoMutex lock(_numProviderProcessesMutex);
 794                                  _numProviderProcesses--;
 795                              }
 796                      
 797 kumpf           1.18 #if defined(PEGASUS_HAS_SIGNALS)
 798                              // Harvest the status of the agent process to prevent a zombie
 799                              Boolean keepWaiting = false;
 800                              do
 801                              {
 802                                  pid_t status = waitpid(_pid, 0, 0);
 803                                  if (status == -1)
 804                                  {
 805                                      if (errno == EINTR)
 806                                      {
 807                                          keepWaiting = true;
 808                                      }
 809                                      else
 810                                      {
 811                                          Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
 812                                              "ProviderAgentContainer::_uninitialize(): "
 813                                                  "waitpid failed; errno = %d.", errno);
 814                                      }
 815                                  }
 816                              } while (keepWaiting);
 817                      #endif
 818 kumpf           1.18 
 819 kumpf           1.1          _isInitialized = false;
 820                      
 821                              //
 822                              // Complete with null responses all outstanding requests on this
 823                              // connection
 824                              //
 825                              {
 826                                  AutoMutex tableLock(_outstandingRequestTableMutex);
 827                      
 828                                  for (OutstandingRequestTable::Iterator i =
 829                                           _outstandingRequestTable.start();
 830                                       i != 0; i++)
 831                                  {
 832                                      PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
 833                                          String("Completing messageId \"") + i.value()->messageId +
 834                                              "\" with a null response.");
 835                                      i.value()->responseMessage = 0;
 836                                      i.value()->responseReady->signal();
 837                                  }
 838                      
 839                                  _outstandingRequestTable.clear();
 840 kumpf           1.1          }
 841                          }
 842                          catch (...)
 843                          {
 844                              // We're uninitializing, so do not propagate the exception
 845                              PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
 846                                  "Ignoring _uninitialize() exception.");
 847                          }
 848                      
 849                          PEG_METHOD_EXIT();
 850                      }
 851                      
 852 kumpf           1.6  String ProviderAgentContainer::getModuleName() const
 853                      {
 854                          return _moduleName;
 855                      }
 856                      
 857 kumpf           1.1  CIMResponseMessage* ProviderAgentContainer::processMessage(
 858                          CIMRequestMessage* request)
 859                      {
 860                          PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 861                              "ProviderAgentContainer::processMessage");
 862                      
 863                          CIMResponseMessage* response;
 864                          String originalMessageId = request->messageId;
 865                      
 866 kumpf           1.2      // These three variables are used for the provider module optimization.
 867                          // See the _providerModuleCache member description for more information.
 868                          AutoPtr<ProviderIdContainer> origProviderId;
 869                          Boolean doProviderModuleOptimization = false;
 870                          Boolean updateProviderModuleCache = false;
 871                      
 872 kumpf           1.1      try
 873                          {
 874                              // The messageId attribute is used to correlate response messages
 875                              // from the Provider Agent with request messages, so it is imperative
 876                              // that the ID is unique for each request.  The incoming ID cannot be
 877                              // trusted to be unique, so we substitute a unique one.  The memory
 878                              // address of the request is used as the source of a unique piece of
 879                              // data.  (The message ID is only required to be unique while the
 880                              // request is outstanding.)
 881                              char messagePtrString[20];
 882                              sprintf(messagePtrString, "%p", request);
 883                              String uniqueMessageId = messagePtrString;
 884                      
 885                              //
 886                              // Set up the OutstandingRequestEntry for this request
 887                              //
 888                              Semaphore waitSemaphore(0);
 889                              OutstandingRequestEntry outstandingRequestEntry(
 890                                  uniqueMessageId, response, &waitSemaphore);
 891                      
 892                              //
 893 kumpf           1.1          // Lock the Provider Agent Container while initializing the
 894                              // agent and writing the request to the connection
 895                              //
 896                              {
 897                                  AutoMutex lock(_agentMutex);
 898                      
 899                                  //
 900                                  // Initialize the Provider Agent, if necessary
 901                                  //
 902                                  if (!_isInitialized)
 903                                  {
 904                                      _initialize();
 905                                  }
 906                      
 907                                  //
 908                                  // Add an entry to the OutstandingRequestTable for this request
 909                                  //
 910                                  {
 911                                      AutoMutex tableLock(_outstandingRequestTableMutex);
 912                      
 913                                      _outstandingRequestTable.insert(
 914 kumpf           1.1                      uniqueMessageId, &outstandingRequestEntry);
 915                                  }
 916                      
 917 kumpf           1.2              // Get the provider module from the ProviderIdContainer to see if
 918                                  // we can optimize out the transmission of this instance to the
 919                                  // Provider Agent.  (See the _providerModuleCache description.)
 920                                  try
 921                                  {
 922                                      ProviderIdContainer pidc = request->operationContext.get(
 923                                          ProviderIdContainer::NAME);
 924                                      origProviderId.reset(new ProviderIdContainer(
 925                                          pidc.getModule(), pidc.getProvider(),
 926                                          pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
 927                                      if (_providerModuleCache.isUninitialized() ||
 928                                          (!pidc.getModule().identical(_providerModuleCache)))
 929                                      {
 930                                          // We haven't sent this provider module instance to the
 931                                          // Provider Agent yet.  Update our cache after we send it.
 932                                          updateProviderModuleCache = true;
 933                                      }
 934                                      else
 935                                      {
 936                                          // Replace the provider module in the ProviderIdContainer
 937                                          // with an uninitialized instance.  We'll need to put the
 938 kumpf           1.2                      // original one back after the message is sent.
 939                                          request->operationContext.set(ProviderIdContainer(
 940                                              CIMInstance(), pidc.getProvider(),
 941                                              pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
 942                                          doProviderModuleOptimization = true;
 943                                      }
 944                                  }
 945                                  catch (...)
 946                                  {
 947                                      // No ProviderIdContainer to optimize
 948                                  }
 949                      
 950 kumpf           1.1              //
 951                                  // Write the message to the pipe
 952                                  //
 953                                  try
 954                                  {
 955                                      PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL3,
 956                                          String("Sending request to agent with messageId ") +
 957                                              uniqueMessageId);
 958                      
 959                                      request->messageId = uniqueMessageId;
 960                                      AnonymousPipe::Status writeStatus =
 961                                          _pipeToAgent->writeMessage(request);
 962                                      request->messageId = originalMessageId;
 963                      
 964 kumpf           1.2                  if (doProviderModuleOptimization)
 965                                      {
 966                                          request->operationContext.set(*origProviderId.get());
 967                                      }
 968                      
 969 kumpf           1.1                  if (writeStatus != AnonymousPipe::STATUS_SUCCESS)
 970                                      {
 971                                          Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
 972                                              "Failed to write message to pipe.  writeStatus = %d.",
 973                                              writeStatus);
 974                                          throw Exception(MessageLoaderParms(
 975                                              "ProviderManager.OOPProviderManagerRouter."
 976                                                  "CIMPROVAGT_COMMUNICATION_FAILED",
 977                                              "Failed to communicate with cimprovagt \"$0\".",
 978                                              _moduleName));
 979                                      }
 980 kumpf           1.2  
 981                                      if (updateProviderModuleCache)
 982                                      {
 983                                          _providerModuleCache = origProviderId->getModule();
 984                                      }
 985 kumpf           1.1              }
 986                                  catch (...)
 987                                  {
 988                                      request->messageId = originalMessageId;
 989 kumpf           1.2  
 990                                      if (doProviderModuleOptimization)
 991                                      {
 992                                          request->operationContext.set(*origProviderId.get());
 993                                      }
 994                      
 995 kumpf           1.1                  Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
 996                                          "Failed to write message to pipe.");
 997                                      // Remove the OutstandingRequestTable entry for this request
 998                                      {
 999                                          AutoMutex tableLock(_outstandingRequestTableMutex);
1000                                          Boolean removed =
1001                                              _outstandingRequestTable.remove(uniqueMessageId);
1002                                          PEGASUS_ASSERT(removed);
1003                                      }
1004                                      throw;
1005                                  }
1006                              }
1007                      
1008                              //
1009                              // Wait for the response
1010                              //
1011                              try
1012                              {
1013                                  // Must not hold _agentMutex while waiting for the response
1014                                  waitSemaphore.wait();
1015                              }
1016 kumpf           1.1          catch (...)
1017                              {
1018                                  // Remove the OutstandingRequestTable entry for this request
1019                                  {
1020                                      AutoMutex tableLock(_outstandingRequestTableMutex);
1021                                      Boolean removed =
1022                                          _outstandingRequestTable.remove(uniqueMessageId);
1023                                      PEGASUS_ASSERT(removed);
1024                                  }
1025                                  throw;
1026                              }
1027                      
1028                              // A null response is returned when an agent connection is closed
1029                              // while requests remain outstanding.
1030                              if (response == 0)
1031                              {
1032                                  response = request->buildResponse();
1033                                  response->cimException = PEGASUS_CIM_EXCEPTION(
1034                                      CIM_ERR_FAILED,
1035                                      MessageLoaderParms(
1036                                          "ProviderManager.OOPProviderManagerRouter."
1037 kumpf           1.1                          "CIMPROVAGT_CONNECTION_LOST",
1038                                          "Lost connection with cimprovagt \"$0\".",
1039                                          _moduleName));
1040                              }
1041                          }
1042                          catch (CIMException& e)
1043                          {
1044                              PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
1045                                  String("Caught exception: ") + e.getMessage());
1046                              response = request->buildResponse();
1047                              response->cimException = e;
1048                          }
1049                          catch (Exception& e)
1050                          {
1051                              PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
1052                                  String("Caught exception: ") + e.getMessage());
1053                              response = request->buildResponse();
1054                              response->cimException = PEGASUS_CIM_EXCEPTION(
1055                                  CIM_ERR_FAILED, e.getMessage());
1056                          }
1057                          catch (...)
1058 kumpf           1.1      {
1059                              PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
1060                                  "Caught unknown exception");
1061                              response = request->buildResponse();
1062                              response->cimException = PEGASUS_CIM_EXCEPTION(
1063                                  CIM_ERR_FAILED, String::EMPTY);
1064                          }
1065                      
1066                          response->messageId = originalMessageId;
1067                      
1068                          PEG_METHOD_EXIT();
1069                          return response;
1070                      }
1071                      
1072                      void ProviderAgentContainer::unloadIdleProviders()
1073                      {
1074                          PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1075 carolann.graves 1.4          "ProviderAgentContainer::unloadIdleProviders");
1076 kumpf           1.1  
1077                          AutoMutex lock(_agentMutex);
1078                          if (_isInitialized)
1079                          {
1080                              // Send a "wake up" message to the Provider Agent.
1081                              // Don't bother checking whether the operation is successful.
1082                              Uint32 messageLength = 0;
1083                              _pipeToAgent->writeBuffer((const char*)&messageLength, sizeof(Uint32));
1084                          }
1085                      
1086                          PEG_METHOD_EXIT();
1087                      }
1088                      
1089                      void ProviderAgentContainer::_processResponses()
1090                      {
1091                          PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1092                              "ProviderAgentContainer::_processResponses");
1093                      
1094                          //
1095                          // Process responses until the pipe is closed
1096                          //
1097 kumpf           1.1      while (1)
1098                          {
1099                              try
1100                              {
1101                                  CIMMessage* message;
1102                      
1103                                  //
1104                                  // Read a response from the Provider Agent
1105                                  //
1106                                  AnonymousPipe::Status readStatus =
1107                                      _pipeFromAgent->readMessage(message);
1108                      
1109                                  // Ignore interrupts
1110                                  if (readStatus == AnonymousPipe::STATUS_INTERRUPT)
1111                                  {
1112                                      continue;
1113                                  }
1114                      
1115                                  // Handle an error the same way as a closed connection
1116                                  if ((readStatus == AnonymousPipe::STATUS_ERROR) ||
1117                                      (readStatus == AnonymousPipe::STATUS_CLOSED))
1118 kumpf           1.1              {
1119                                      AutoMutex lock(_agentMutex);
1120                                      _uninitialize();
1121                                      return;
1122                                  }
1123                      
1124                                  if (message->getType() == CIM_PROCESS_INDICATION_REQUEST_MESSAGE)
1125                                  {
1126                                      // Forward indications to the indication callback
1127                                      _indicationCallback(
1128                                          reinterpret_cast<CIMProcessIndicationRequestMessage*>(
1129                                              message));
1130                                  }
1131                                  else
1132                                  {
1133                                      CIMResponseMessage* response;
1134                                      response = dynamic_cast<CIMResponseMessage*>(message);
1135                                      PEGASUS_ASSERT(response != 0);
1136                      
1137                                      // Give the response to the waiting OutstandingRequestEntry
1138                                      OutstandingRequestEntry* _outstandingRequestEntry = 0;
1139 kumpf           1.1                  {
1140                                          AutoMutex tableLock(_outstandingRequestTableMutex);
1141                                          Boolean foundEntry = _outstandingRequestTable.lookup(
1142                                              response->messageId, _outstandingRequestEntry);
1143                                          PEGASUS_ASSERT(foundEntry);
1144                      
1145                                          // Remove the completed request from the table
1146                                          Boolean removed =
1147                                              _outstandingRequestTable.remove(response->messageId);
1148                                          PEGASUS_ASSERT(removed);
1149                                      }
1150                      
1151                                      _outstandingRequestEntry->responseMessage = response;
1152                                      _outstandingRequestEntry->responseReady->signal();
1153                                  }
1154                              }
1155                              catch (Exception& e)
1156                              {
1157                                  PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
1158                                      String("Ignoring exception: ") + e.getMessage());
1159                              }
1160 kumpf           1.1          catch (...)
1161                              {
1162                                  PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
1163                                      "Ignoring exception");
1164                              }
1165                          }
1166                      
1167                      }
1168                      
1169                      PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL
1170                      ProviderAgentContainer::_responseProcessor(void* arg)
1171                      {
1172                          ProviderAgentContainer* pa =
1173                              reinterpret_cast<ProviderAgentContainer*>(arg);
1174                      
1175                          pa->_processResponses();
1176                      
1177                          return(PEGASUS_THREAD_RETURN(0));
1178                      }
1179                      
1180                      /////////////////////////////////////////////////////////////////////////////
1181 kumpf           1.1  // OOPProviderManagerRouter
1182                      /////////////////////////////////////////////////////////////////////////////
1183                      
1184                      OOPProviderManagerRouter::OOPProviderManagerRouter(
1185                          PEGASUS_INDICATION_CALLBACK indicationCallback)
1186                      {
1187                          PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1188                              "OOPProviderManagerRouter::OOPProviderManagerRouter");
1189                      
1190                          _indicationCallback = indicationCallback;
1191 carolann.graves 1.14     _subscriptionInitComplete = false;
1192 kumpf           1.1  
1193                          PEG_METHOD_EXIT();
1194                      }
1195                      
1196                      OOPProviderManagerRouter::~OOPProviderManagerRouter()
1197                      {
1198                          PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1199                              "OOPProviderManagerRouter::~OOPProviderManagerRouter");
1200                      
1201                          try
1202                          {
1203                              // Clean up the ProviderAgentContainers
1204                              AutoMutex lock(_providerAgentTableMutex);
1205                              ProviderAgentTable::Iterator i = _providerAgentTable.start();
1206                              for(; i != 0; i++)
1207                              {
1208                                  delete i.value();
1209                              }
1210                          }
1211                          catch (...) {}
1212                      
1213 kumpf           1.1      PEG_METHOD_EXIT();
1214                      }
1215                      
1216                      // Private, unimplemented constructor
1217                      OOPProviderManagerRouter::OOPProviderManagerRouter()
1218                      {
1219                      }
1220                      
1221                      // Private, unimplemented constructor
1222                      OOPProviderManagerRouter::OOPProviderManagerRouter(
1223                          const OOPProviderManagerRouter&)
1224 david.dillard   1.3      : ProviderManagerRouter(*this)
1225 kumpf           1.1  {
1226                      }
1227                      
1228                      // Private, unimplemented assignment operator
1229                      OOPProviderManagerRouter& OOPProviderManagerRouter::operator=(
1230                          const OOPProviderManagerRouter&)
1231                      {
1232                          return *this;
1233                      }
1234                      
1235                      Message* OOPProviderManagerRouter::processMessage(Message* message)
1236                      {
1237                          PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1238                              "OOPProviderManagerRouter::processMessage");
1239                      
1240                          CIMRequestMessage* request = dynamic_cast<CIMRequestMessage *>(message);
1241                          PEGASUS_ASSERT(request != 0);
1242                      
1243                          AutoPtr<CIMResponseMessage> response;
1244                      
1245                          //
1246 kumpf           1.1      // Get the provider information from the request
1247                          //
1248                          CIMInstance providerModule;
1249                      
1250                          if ((dynamic_cast<CIMOperationRequestMessage*>(request) != 0) ||
1251                              (dynamic_cast<CIMIndicationRequestMessage*>(request) != 0) ||
1252                              (request->getType() == CIM_EXPORT_INDICATION_REQUEST_MESSAGE))
1253                          {
1254                              // Provider information is in the OperationContext
1255                              ProviderIdContainer pidc = (ProviderIdContainer)
1256                                  request->operationContext.get(ProviderIdContainer::NAME);
1257                              providerModule = pidc.getModule();
1258                          }
1259                          else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
1260                          {
1261                              CIMEnableModuleRequestMessage* emReq =
1262                                  dynamic_cast<CIMEnableModuleRequestMessage*>(request);
1263                              providerModule = emReq->providerModule;
1264                          }
1265                          else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
1266                          {
1267 kumpf           1.1          CIMDisableModuleRequestMessage* dmReq =
1268                                  dynamic_cast<CIMDisableModuleRequestMessage*>(request);
1269                              providerModule = dmReq->providerModule;
1270                          }
1271                          else if ((request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE) ||
1272 carolann.graves 1.14              (request->getType() ==
1273                                       CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE) ||
1274 kumpf           1.1               (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE))
1275                          {
1276                              // This operation is not provider-specific
1277                          }
1278                          else
1279                          {
1280                              // Unrecognized message type.  This should never happen.
1281                              PEGASUS_ASSERT(0);
1282                              response.reset(request->buildResponse());
1283                              response->cimException = PEGASUS_CIM_EXCEPTION(
1284                                  CIM_ERR_FAILED, "Unrecognized message type.");
1285                              PEG_METHOD_EXIT();
1286                              return response.release();
1287                          }
1288                      
1289                          //
1290                          // Process the request message
1291                          //
1292                          if (request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE)
1293                          {
1294                              // Forward the CIMStopAllProvidersRequest to all providers
1295 kumpf           1.1          response.reset(_forwardRequestToAllAgents(request));
1296                      
1297                              // Note: Do not uninitialize the ProviderAgentContainers here.
1298                              // Just let the selecting thread notice when the agent connections
1299                              // are closed.
1300                          }
1301 carolann.graves 1.14     else if (request->getType () == 
1302                              CIM_SUBSCRIPTION_INIT_COMPLETE_REQUEST_MESSAGE)
1303                          {
1304                              _subscriptionInitComplete = true;
1305                      
1306                              //
1307                              //  Forward the CIMSubscriptionInitCompleteRequestMessage to 
1308                              //  all providers
1309                              //
1310                              response.reset (_forwardRequestToAllAgents (request));
1311                          }
1312 kumpf           1.1      else if (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE)
1313                          {
1314                              CIMNotifyConfigChangeRequestMessage* notifyRequest =
1315                                  dynamic_cast<CIMNotifyConfigChangeRequestMessage*>(request);
1316                              PEGASUS_ASSERT(notifyRequest != 0);
1317                      
1318                              if (notifyRequest->currentValueModified)
1319                              {
1320                                  // Forward the CIMNotifyConfigChangeRequestMessage to all providers
1321                                  response.reset(_forwardRequestToAllAgents(request));
1322                              }
1323                              else
1324                              {
1325                                  // No need to notify provider agents about changes to planned value
1326                                  response.reset(request->buildResponse());
1327                              }
1328                          }
1329 kumpf           1.6      else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
1330 kumpf           1.1      {
1331 kumpf           1.6          // Fan out the request to all Provider Agent processes for this module
1332                      
1333 kumpf           1.1          // Retrieve the provider module name
1334                              String moduleName;
1335                              CIMValue nameValue = providerModule.getProperty(
1336                                  providerModule.findProperty("Name")).getValue();
1337                              nameValue.get(moduleName);
1338                      
1339 kumpf           1.6          // Look up the Provider Agents for this module
1340                              Array<ProviderAgentContainer*> paArray =
1341                                  _lookupProviderAgents(moduleName);
1342 kumpf           1.1  
1343 kumpf           1.6          for (Uint32 i=0; i<paArray.size(); i++)
1344 kumpf           1.1          {
1345                                  //
1346                                  // Do not start up an agent process just to disable the module
1347                                  //
1348 kumpf           1.6              if (paArray[i]->isInitialized())
1349                                  {
1350                                      //
1351                                      // Forward the request to the provider agent
1352                                      //
1353                                      response.reset(paArray[i]->processMessage(request));
1354                      
1355                                      // Note: Do not uninitialize the ProviderAgentContainer here
1356                                      // when a disable module operation is successful.  Just let the
1357                                      // selecting thread notice when the agent connection is closed.
1358                      
1359                                      // Determine the success of the disable module operation
1360                                      CIMDisableModuleResponseMessage* dmResponse =
1361                                          dynamic_cast<CIMDisableModuleResponseMessage*>(
1362                                              response.get());
1363                                      PEGASUS_ASSERT(dmResponse != 0);
1364                      
1365                                      Boolean isStopped = false;
1366                                      for (Uint32 i=0; i < dmResponse->operationalStatus.size(); i++)
1367                                      {
1368                                          if (dmResponse->operationalStatus[i] ==
1369 kumpf           1.6                          CIM_MSE_OPSTATUS_VALUE_STOPPED)
1370                                          {
1371                                              isStopped = true;
1372                                              break;
1373                                          }
1374                                      }
1375                      
1376                                      // If the operation is unsuccessful, stop and return the error
1377                                      if ((dmResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
1378                                          !isStopped)
1379                                      {
1380                                          break;
1381                                      }
1382                                  }
1383                              }
1384                      
1385                              // Use a default response if no Provider Agents were called
1386                              if (!response.get())
1387                              {
1388 kumpf           1.1              response.reset(request->buildResponse());
1389                      
1390                                  CIMDisableModuleResponseMessage* dmResponse =
1391                                      dynamic_cast<CIMDisableModuleResponseMessage*>(response.get());
1392                                  PEGASUS_ASSERT(dmResponse != 0);
1393                      
1394                                  Array<Uint16> operationalStatus;
1395                                  operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_STOPPED);
1396                                  dmResponse->operationalStatus = operationalStatus;
1397                              }
1398 kumpf           1.6      }
1399                          else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
1400                          {
1401                              // Fan out the request to all Provider Agent processes for this module
1402                      
1403                              // Retrieve the provider module name
1404                              String moduleName;
1405                              CIMValue nameValue = providerModule.getProperty(
1406                                  providerModule.findProperty("Name")).getValue();
1407                              nameValue.get(moduleName);
1408                      
1409                              // Look up the Provider Agents for this module
1410                              Array<ProviderAgentContainer*> paArray =
1411                                  _lookupProviderAgents(moduleName);
1412                      
1413                              for (Uint32 i=0; i<paArray.size(); i++)
1414 kumpf           1.1          {
1415                                  //
1416                                  // Do not start up an agent process just to enable the module
1417                                  //
1418 kumpf           1.6              if (paArray[i]->isInitialized())
1419                                  {
1420                                      //
1421                                      // Forward the request to the provider agent
1422                                      //
1423                                      response.reset(paArray[i]->processMessage(request));
1424                      
1425                                      // Determine the success of the enable module operation
1426                                      CIMEnableModuleResponseMessage* emResponse =
1427                                          dynamic_cast<CIMEnableModuleResponseMessage*>(
1428                                              response.get());
1429                                      PEGASUS_ASSERT(emResponse != 0);
1430                      
1431                                      Boolean isOk = false;
1432                                      for (Uint32 i=0; i < emResponse->operationalStatus.size(); i++)
1433                                      {
1434                                          if (emResponse->operationalStatus[i] ==
1435                                              CIM_MSE_OPSTATUS_VALUE_OK)
1436                                          {
1437                                              isOk = true;
1438                                              break;
1439 kumpf           1.6                      }
1440                                      }
1441                      
1442                                      // If the operation is unsuccessful, stop and return the error
1443                                      if ((emResponse->cimException.getCode() != CIM_ERR_SUCCESS) ||
1444                                          !isOk)
1445                                      {
1446                                          break;
1447                                      }
1448                                  }
1449                              }
1450                      
1451                              // Use a default response if no Provider Agents were called
1452                              if (!response.get())
1453                              {
1454 kumpf           1.1              response.reset(request->buildResponse());
1455                      
1456                                  CIMEnableModuleResponseMessage* emResponse =
1457                                      dynamic_cast<CIMEnableModuleResponseMessage*>(response.get());
1458                                  PEGASUS_ASSERT(emResponse != 0);
1459                      
1460                                  Array<Uint16> operationalStatus;
1461                                  operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_OK);
1462                                  emResponse->operationalStatus = operationalStatus;
1463                              }
1464 kumpf           1.6      }
1465                          else
1466                          {
1467                              // Retrieve the provider module name
1468                              String moduleName;
1469                              CIMValue nameValue = providerModule.getProperty(
1470                                  providerModule.findProperty("Name")).getValue();
1471                              nameValue.get(moduleName);
1472                      
1473                              // Retrieve the provider user context configuration
1474                              Uint16 userContext = 0;
1475                              Uint32 pos = providerModule.findProperty(
1476                                  PEGASUS_PROPERTYNAME_MODULE_USERCONTEXT);
1477                              if (pos != PEG_NOT_FOUND)
1478                              {
1479 kumpf           1.12             CIMValue userContextValue =
1480                                      providerModule.getProperty(pos).getValue();
1481                                  if (!userContextValue.isNull())
1482                                  {
1483                                      userContextValue.get(userContext);
1484                                  }
1485 kumpf           1.6          }
1486                      
1487                              if (userContext == 0)
1488                              {
1489                                  userContext = PG_PROVMODULE_USERCTXT_PRIVILEGED;
1490                              }
1491                      
1492                              String userName;
1493                      
1494                              if (userContext == PG_PROVMODULE_USERCTXT_REQUESTOR)
1495 kumpf           1.1          {
1496 kumpf           1.6              try
1497                                  {
1498                                      // User Name is in the OperationContext
1499                                      IdentityContainer ic = (IdentityContainer)
1500                                          request->operationContext.get(IdentityContainer::NAME);
1501                                      userName = ic.getUserName();
1502                                  }
1503                                  catch (Exception& e)
1504                                  {
1505                                      // If no IdentityContainer is present, default to the CIM
1506                                      // Server's user context
1507                                  }
1508 kumpf           1.1  
1509 kumpf           1.6              // If authentication is disabled, use the CIM Server's user context
1510                                  if (!userName.size())
1511                                  {
1512                                      userName = System::getEffectiveUserName();
1513                                  }
1514                              }
1515                              else if (userContext == PG_PROVMODULE_USERCTXT_DESIGNATED)
1516                              {
1517                                  // Retrieve the provider module name
1518                                  providerModule.getProperty(providerModule.findProperty(
1519                                      PEGASUS_PROPERTYNAME_MODULE_DESIGNATEDUSER)).getValue().
1520                                      get(userName);
1521                              }
1522                              else if (userContext == PG_PROVMODULE_USERCTXT_CIMSERVER)
1523                              {
1524                                  userName = System::getEffectiveUserName();
1525                              }
1526                              else    // Privileged User
1527                              {
1528                                  PEGASUS_ASSERT(userContext == PG_PROVMODULE_USERCTXT_PRIVILEGED);
1529                                  userName = System::getPrivilegedUserName();
1530 kumpf           1.1          }
1531 kumpf           1.6  
1532                              PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1533                                  "Module name = " + moduleName);
1534                              Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1535                                  "User context = %hd.", userContext);
1536                              PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL4,
1537                                  "User name = " + userName);
1538                      
1539                              // Look up the Provider Agent for this module and user
1540                              ProviderAgentContainer* pa = _lookupProviderAgent(moduleName, userName);
1541                              PEGASUS_ASSERT(pa != 0);
1542                      
1543                              //
1544                              // Forward the request to the provider agent
1545                              //
1546                              response.reset(pa->processMessage(request));
1547 kumpf           1.1      }
1548                      
1549                          response->syncAttributes(request);
1550                      
1551                          PEG_METHOD_EXIT();
1552                          return response.release();
1553                      }
1554                      
1555                      ProviderAgentContainer* OOPProviderManagerRouter::_lookupProviderAgent(
1556 kumpf           1.6      const String& moduleName,
1557                          const String& userName)
1558 kumpf           1.1  {
1559                          ProviderAgentContainer* pa = 0;
1560 kumpf           1.6      String key = moduleName + ":" + userName;
1561 kumpf           1.1  
1562                          AutoMutex lock(_providerAgentTableMutex);
1563 kumpf           1.6      if (!_providerAgentTable.lookup(key, pa))
1564 kumpf           1.1      {
1565 kumpf           1.6          pa = new ProviderAgentContainer(
1566 carolann.graves 1.14             moduleName, userName, _indicationCallback,
1567                                  _subscriptionInitComplete);
1568 kumpf           1.6          _providerAgentTable.insert(key, pa);
1569 kumpf           1.1      }
1570                          return pa;
1571                      }
1572                      
1573 kumpf           1.6  Array<ProviderAgentContainer*> OOPProviderManagerRouter::_lookupProviderAgents(
1574                          const String& moduleName)
1575                      {
1576                          Array<ProviderAgentContainer*> paArray;
1577                      
1578                          AutoMutex lock(_providerAgentTableMutex);
1579                          for (ProviderAgentTable::Iterator i = _providerAgentTable.start(); i; i++)
1580                          {
1581                              if (i.value()->getModuleName() == moduleName)
1582                              {
1583                                  paArray.append(i.value());
1584                              }
1585                          }
1586                          return paArray;
1587                      }
1588                      
1589 kumpf           1.1  CIMResponseMessage* OOPProviderManagerRouter::_forwardRequestToAllAgents(
1590                          CIMRequestMessage* request)
1591                      {
1592                          PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1593                              "OOPProviderManagerRouter::_forwardRequestToAllAgents");
1594                      
1595                          // Get a list of the ProviderAgentContainers.  We need our own array copy
1596                          // because we cannot hold the _providerAgentTableMutex while calling
1597                          // _ProviderAgentContainer::processMessage().
1598                          Array<ProviderAgentContainer*> paContainerArray;
1599                          {
1600                              AutoMutex tableLock(_providerAgentTableMutex);
1601                              for (ProviderAgentTable::Iterator i = _providerAgentTable.start();
1602                                   i != 0; i++)
1603                              {
1604                                  paContainerArray.append(i.value());
1605                              }
1606                          }
1607                      
1608                          CIMException responseException;
1609                      
1610 kumpf           1.1      // Forward the request to each of the initialized provider agents
1611                          for (Uint32 j = 0; j < paContainerArray.size(); j++)
1612                          {
1613                              ProviderAgentContainer* pa = paContainerArray[j];
1614                              if (pa->isInitialized())
1615                              {
1616                                  // Note: The ProviderAgentContainer could become uninitialized
1617                                  // before _ProviderAgentContainer::processMessage() processes
1618                                  // this request.  In this case, the Provider Agent process will
1619                                  // (unfortunately) be started to process this message.
1620                                  AutoPtr<CIMResponseMessage> response;
1621                                  response.reset(pa->processMessage(request));
1622                                  if (response.get() != 0)
1623                                  {
1624                                      // If the operation failed, save the exception data
1625                                      if ((response->cimException.getCode() != CIM_ERR_SUCCESS) &&
1626                                          (responseException.getCode() == CIM_ERR_SUCCESS))
1627                                      {
1628                                          responseException = response->cimException;
1629                                      }
1630                                  }
1631 kumpf           1.1          }
1632                          }
1633                      
1634                          CIMResponseMessage* response = request->buildResponse();
1635                          response->cimException = responseException;
1636                      
1637                          PEG_METHOD_EXIT();
1638                          return response;
1639                      }
1640                      
1641                      Boolean OOPProviderManagerRouter::hasActiveProviders()
1642                      {
1643                          PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1644                              "OOPProviderManagerRouter::hasActiveProviders");
1645                      
1646                          // Iterate through the _providerAgentTable looking for initialized agents
1647                          AutoMutex lock(_providerAgentTableMutex);
1648                          ProviderAgentTable::Iterator i = _providerAgentTable.start();
1649                          for(; i != 0; i++)
1650                          {
1651                              if (i.value()->isInitialized())
1652 kumpf           1.1          {
1653                                  PEG_METHOD_EXIT();
1654                                  return true;
1655                              }
1656                          }
1657                      
1658                          // No initialized Provider Agents were found
1659                          PEG_METHOD_EXIT();
1660                          return false;
1661                      }
1662                      
1663                      void OOPProviderManagerRouter::unloadIdleProviders()
1664                      {
1665                          PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1666                              "OOPProviderManagerRouter::unloadIdleProviders");
1667                      
1668                          // Iterate through the _providerAgentTable unloading idle providers
1669                          AutoMutex lock(_providerAgentTableMutex);
1670                          ProviderAgentTable::Iterator i = _providerAgentTable.start();
1671                          for(; i != 0; i++)
1672                          {
1673 kumpf           1.1          i.value()->unloadIdleProviders();
1674                          }
1675                      
1676                          PEG_METHOD_EXIT();
1677                      }
1678                      
1679                      PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2