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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2