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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2