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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2