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

   1 karl  1.5 //%2004////////////////////////////////////////////////////////////////////////
   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 kumpf 1.1 //
  10           // Permission is hereby granted, free of charge, to any person obtaining a copy
  11           // of this software and associated documentation files (the "Software"), to
  12           // deal in the Software without restriction, including without limitation the
  13           // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  14           // sell copies of the Software, and to permit persons to whom the Software is
  15           // furnished to do so, subject to the following conditions:
  16 karl  1.5 // 
  17 kumpf 1.1 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
  18           // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
  19           // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
  20           // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  21           // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  22           // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  23           // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  24           // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25           //
  26           //==============================================================================
  27           //
  28           // Author: Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
  29           //         Jenny Yu, Hewlett-Packard Company (jenny_yu@hp.com)
  30           //
  31           // Modified By:
  32           //
  33           //%/////////////////////////////////////////////////////////////////////////////
  34           
  35           #include <Pegasus/Common/Config.h>
  36           #include <Pegasus/Common/Constants.h>
  37           #include <Pegasus/Common/AutoPtr.h>
  38 kumpf 1.1 #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           #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           #else
  54           # if defined (PEGASUS_OS_OS400)
  55           #  include <unistd.cleinc>
  56           # else
  57           #  include <unistd.h>  // For fork(), exec(), and _exit()
  58           # endif
  59 kumpf 1.1 #include <errno.h>
  60           #endif
  61           
  62           #include "OOPProviderManagerRouter.h"
  63           
  64           PEGASUS_USING_STD;
  65           
  66           PEGASUS_NAMESPACE_BEGIN
  67           
  68           /////////////////////////////////////////////////////////////////////////////
  69           // OutstandingRequestTable and OutstandingRequestEntry
  70           /////////////////////////////////////////////////////////////////////////////
  71           
  72           /**
  73               An OutstandingRequestEntry represents a request message sent to a
  74               Provider Agent for which no response has been received.  The request
  75               sender provides the message ID and a location for the response to be
  76               returned, and then waits on the semaphore.  When a response matching
  77               the message ID is received, it is placed into the specified location
  78               and the semaphore is signaled.
  79            */
  80 kumpf 1.1 class OutstandingRequestEntry
  81           {
  82           public:
  83               OutstandingRequestEntry(
  84                   String messageId_,
  85                   CIMResponseMessage*& responseMessage_,
  86                   Semaphore* responseReady_)
  87                   : messageId(messageId_),
  88                     responseMessage(responseMessage_),
  89                     responseReady(responseReady_)
  90               {
  91               }
  92           
  93               String messageId;
  94               CIMResponseMessage*& responseMessage;
  95               Semaphore* responseReady;
  96           };
  97           
  98           typedef HashTable<String, OutstandingRequestEntry*, EqualFunc<String>,
  99               HashFunc<String> > OutstandingRequestTable;
 100           
 101 kumpf 1.1 
 102           /////////////////////////////////////////////////////////////////////////////
 103           // ProviderAgentContainer
 104           /////////////////////////////////////////////////////////////////////////////
 105           
 106           class ProviderAgentContainer
 107           {
 108           public:
 109               ProviderAgentContainer(
 110                   const String & moduleName,
 111                   PEGASUS_INDICATION_CALLBACK indicationCallback);
 112           
 113               ~ProviderAgentContainer();
 114           
 115               Boolean isInitialized();
 116           
 117               CIMResponseMessage* processMessage(CIMRequestMessage* request);
 118               void unloadIdleProviders();
 119           
 120           private:
 121               //
 122 kumpf 1.1     // Private methods
 123               //
 124           
 125               /** Unimplemented */
 126               ProviderAgentContainer();
 127               /** Unimplemented */
 128               ProviderAgentContainer(const ProviderAgentContainer& pa);
 129               /** Unimplemented */
 130               ProviderAgentContainer& operator=(const ProviderAgentContainer& pa);
 131           
 132               /**
 133                   Start a Provider Agent process and establish a pipe connection with it.
 134                   Note: The caller must lock the _agentMutex.
 135                */
 136               void _startAgentProcess();
 137           
 138               /**
 139                   Send initialization data to the Provider Agent.
 140                   Note: The caller must lock the _agentMutex.
 141                */
 142               void _sendInitializationData();
 143 kumpf 1.1 
 144               /**
 145                   Initialize the ProviderAgentContainer if it is not already
 146                   initialized.  Initialization includes starting the Provider Agent
 147                   process, establishing a pipe connection with it, and starting a
 148                   thread to read response messages from the Provider Agent.
 149           
 150                   Note: The caller must lock the _agentMutex.
 151                */
 152               void _initialize();
 153           
 154               /**
 155                   Uninitialize the ProviderAgentContainer if it is initialized.
 156                   The connection is closed and outstanding requests are completed
 157                   with an error result.
 158           
 159                   Note: The caller must lock the _agentMutex.
 160                */
 161               void _uninitialize();
 162           
 163               /**
 164 kumpf 1.1         Read and process response messages from the Provider Agent until
 165                   the connection is closed.
 166                */
 167               void _processResponses();
 168               static PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL
 169                   _responseProcessor(void* arg);
 170           
 171               //
 172               // Private data
 173               //
 174           
 175               /**
 176                   The _agentMutex must be locked whenever writing to the Provider
 177                   Agent connection, accessing the _isInitialized flag, or changing
 178                   the Provider Agent state.
 179                */
 180               Mutex _agentMutex;
 181           
 182               /**
 183                   Name of the provider module served by this Provider Agent.
 184                */
 185 kumpf 1.1     String _moduleName;
 186           
 187               /**
 188                   Callback function to which all generated indications are sent for
 189                   processing.
 190                */
 191               PEGASUS_INDICATION_CALLBACK _indicationCallback;
 192           
 193               /**
 194                   Indicates whether the Provider Agent is active.
 195                */
 196               Boolean _isInitialized;
 197           
 198               /**
 199                   Pipe connection used to read responses from the Provider Agent.
 200                */
 201               AutoPtr<AnonymousPipe> _pipeFromAgent;
 202               /**
 203                   Pipe connection used to write requests to the Provider Agent.
 204                */
 205               AutoPtr<AnonymousPipe> _pipeToAgent;
 206 kumpf 1.1 
 207               /**
 208                   The _outstandingRequestTable holds an entry for each request that has
 209                   been sent to this Provider Agent for which no response has been
 210                   received.  Entries are added (by the writing thread) when a request
 211                   is sent, and are removed (by the reading thread) when the response is
 212                   received (or when it is determined that no response is forthcoming).
 213                */
 214               OutstandingRequestTable _outstandingRequestTable;
 215               /**
 216                   The _outstandingRequestTableMutex must be locked whenever reading or
 217                   updating the _outstandingRequestTable.
 218                */
 219               Mutex _outstandingRequestTableMutex;
 220 kumpf 1.2 
 221               /**
 222                   Holds the last provider module instance sent to the Provider Agent in
 223                   a ProviderIdContainer.  Since the provider module instance rarely
 224                   changes, an optimization is used to send it only when it differs from
 225                   the last provider module instance sent.
 226                */
 227               CIMInstance _providerModuleCache;
 228 kumpf 1.1 };
 229           
 230           ProviderAgentContainer::ProviderAgentContainer(
 231               const String & moduleName,
 232               PEGASUS_INDICATION_CALLBACK indicationCallback)
 233               : _moduleName(moduleName),
 234                 _indicationCallback(indicationCallback),
 235                 _isInitialized(false)
 236           {
 237               PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 238                   "ProviderAgentContainer::ProviderAgentContainer");
 239               PEG_METHOD_EXIT();
 240           }
 241           
 242           ProviderAgentContainer::~ProviderAgentContainer()
 243           {
 244               PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 245                   "ProviderAgentContainer::~ProviderAgentContainer");
 246           
 247               // Ensure the destructor does not throw an exception
 248               try
 249 kumpf 1.1     {
 250                   // Stop the responseProcessor thread by closing its connection
 251                   _pipeFromAgent->closeReadHandle();
 252           
 253                   // Wait for the responseProcessor thread to exit
 254                   while (isInitialized())
 255                   {
 256                       pegasus_yield();
 257                   }
 258               }
 259               catch (...)
 260               {
 261               }
 262           
 263               PEG_METHOD_EXIT();
 264           }
 265           
 266           void ProviderAgentContainer::_startAgentProcess()
 267           {
 268               PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 269                   "ProviderAgentContainer::_startAgentProcess");
 270 kumpf 1.1 
 271               AutoPtr<AnonymousPipe> pipeFromAgent(new AnonymousPipe());
 272               AutoPtr<AnonymousPipe> pipeToAgent(new AnonymousPipe());
 273           
 274               //
 275               // Start a cimprovagt process for this provider module
 276               //
 277           
 278           #if defined (PEGASUS_OS_TYPE_WINDOWS)
 279               //
 280               //  Set up members of the PROCESS_INFORMATION structure
 281               //
 282               PROCESS_INFORMATION piProcInfo;
 283               ZeroMemory (&piProcInfo, sizeof (PROCESS_INFORMATION));
 284           
 285               //
 286               //  Set up members of the STARTUPINFO structure
 287               //
 288               STARTUPINFO siStartInfo;
 289               ZeroMemory (&siStartInfo, sizeof (STARTUPINFO));
 290               siStartInfo.cb = sizeof (STARTUPINFO);
 291 kumpf 1.1 
 292               //
 293               //  Generate the command line
 294               //
 295               char cmdLine[2048];
 296               char readHandle[32];
 297               char writeHandle[32];
 298               pipeToAgent->exportReadHandle(readHandle);
 299               pipeFromAgent->exportWriteHandle(writeHandle);
 300           
 301               sprintf(cmdLine, "\"%s\" %s %s \"%s\"",
 302                   (const char*)ConfigManager::getHomedPath(
 303                       PEGASUS_PROVIDER_AGENT_PROC_NAME).getCString(),
 304                   readHandle, writeHandle, (const char*)_moduleName.getCString());
 305           
 306               //
 307               //  Create the child process
 308               //
 309               if (!CreateProcess (
 310                   NULL,          //
 311                   cmdLine,       //  command line
 312 kumpf 1.1         NULL,          //  process security attributes
 313                   NULL,          //  primary thread security attributes
 314                   TRUE,          //  handles are inherited
 315                   0,             //  creation flags
 316                   NULL,          //  use parent's environment
 317                   NULL,          //  use parent's current directory
 318                   &siStartInfo,  //  STARTUPINFO
 319                   &piProcInfo))  //  PROCESS_INFORMATION
 320               {
 321                   Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
 322                       "CreateProcess() failed.  errno = %d.", GetLastError());
 323                   PEG_METHOD_EXIT();
 324                   throw Exception(MessageLoaderParms(
 325                       "ProviderManager.OOPProviderManagerRouter.CIMPROVAGT_START_FAILED",
 326                       "Failed to start cimprovagt \"$0\".",
 327                       _moduleName));
 328               }
 329           
 330               CloseHandle(piProcInfo.hProcess);
 331               CloseHandle(piProcInfo.hThread);
 332           #else
 333 kumpf 1.1     pid_t pid = fork();
 334               if (pid < 0)
 335               {
 336                   Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
 337                       "fork() failed.  errno = %d.", errno);
 338                   PEG_METHOD_EXIT();
 339                   throw Exception(MessageLoaderParms(
 340                       "ProviderManager.OOPProviderManagerRouter.CIMPROVAGT_START_FAILED",
 341                       "Failed to start cimprovagt \"$0\".",
 342                       _moduleName));
 343               }
 344               else if (pid == 0)
 345               {
 346                   //
 347                   // Child side of the fork
 348                   //
 349           
 350                   try
 351                   {
 352                       // Close our copies of the parent's ends of the pipes
 353                       pipeToAgent->closeWriteHandle();
 354 kumpf 1.1             pipeFromAgent->closeReadHandle();
 355           
 356                       //
 357                       // Execute the cimprovagt program
 358                       //
 359                       String agentCommandPath =
 360                           ConfigManager::getHomedPath(PEGASUS_PROVIDER_AGENT_PROC_NAME);
 361                       CString agentCommandPathCString = agentCommandPath.getCString();
 362           
 363                       char readHandle[32];
 364                       char writeHandle[32];
 365                       pipeToAgent->exportReadHandle(readHandle);
 366                       pipeFromAgent->exportWriteHandle(writeHandle);
 367           
 368                       execl(agentCommandPathCString, agentCommandPathCString,
 369                           readHandle, writeHandle,
 370                           (const char*)_moduleName.getCString(), (char*)0);
 371           
 372                       // If we're still here, there was an error
 373                       Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2,
 374                           "execl() failed.  errno = %d.", errno);
 375 kumpf 1.1             _exit(1);
 376                   }
 377                   catch (...)
 378                   {
 379                       // There's not much we can do here in no man's land
 380                       try
 381                       {
 382                           PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
 383                               "Caught exception before calling execl().");
 384                       }
 385                       catch (...) {}
 386                       _exit(1);
 387                   }
 388               }
 389           #endif
 390           
 391               //
 392               // CIM Server process
 393               //
 394           
 395               // Close our copies of the agent's ends of the pipes
 396 kumpf 1.1     pipeToAgent->closeReadHandle();
 397               pipeFromAgent->closeWriteHandle();
 398           
 399               _pipeToAgent.reset(pipeToAgent.release());
 400               _pipeFromAgent.reset(pipeFromAgent.release());
 401           
 402               PEG_METHOD_EXIT();
 403           }
 404           
 405           // Note: Caller must lock _agentMutex
 406           void ProviderAgentContainer::_sendInitializationData()
 407           {
 408               PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 409                   "ProviderAgentContainer::_sendInitializationData");
 410           
 411               //
 412               // Gather config properties to pass to the Provider Agent
 413               //
 414               ConfigManager* configManager = ConfigManager::getInstance();
 415               Array<Pair<String, String> > configProperties;
 416           
 417 kumpf 1.1     Array<String> configPropertyNames;
 418               configManager->getAllPropertyNames(configPropertyNames, true);
 419               for (Uint32 i = 0; i < configPropertyNames.size(); i++)
 420               {
 421                   String configPropertyValue =
 422                       configManager->getCurrentValue(configPropertyNames[i]);
 423                   String configPropertyDefaultValue =
 424                       configManager->getDefaultValue(configPropertyNames[i]);
 425                   if (configPropertyValue != configPropertyDefaultValue)
 426                   {
 427                       configProperties.append(Pair<String, String>(
 428                           configPropertyNames[i], configPropertyValue));
 429                   }
 430               }
 431           
 432               //
 433               // Create a Provider Agent initialization message
 434               //
 435               AutoPtr<CIMInitializeProviderAgentRequestMessage> request(
 436                   new CIMInitializeProviderAgentRequestMessage(
 437                       String("0"),    // messageId
 438 kumpf 1.1             configManager->getPegasusHome(),
 439                       configProperties,
 440                       System::bindVerbose,
 441                       QueueIdStack()));
 442           
 443               //
 444               // Write the initialization message to the pipe
 445               //
 446               AnonymousPipe::Status writeStatus =
 447                   _pipeToAgent->writeMessage(request.get());
 448           
 449               if (writeStatus != AnonymousPipe::STATUS_SUCCESS)
 450               {
 451                   PEG_METHOD_EXIT();
 452                   throw Exception(MessageLoaderParms(
 453                       "ProviderManager.OOPProviderManagerRouter."
 454                           "CIMPROVAGT_COMMUNICATION_FAILED",
 455                       "Failed to communicate with cimprovagt \"$0\".",
 456                       _moduleName));
 457               }
 458           
 459 kumpf 1.1     // Do not wait for a response from the Provider Agent.  (It isn't coming.)
 460           
 461               PEG_METHOD_EXIT();
 462           }
 463           
 464           // Note: Caller must lock _agentMutex
 465           void ProviderAgentContainer::_initialize()
 466           {
 467               PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 468                   "ProviderAgentContainer::_initialize");
 469           
 470               if (_isInitialized)
 471               {
 472                   PEGASUS_ASSERT(0);
 473                   PEG_METHOD_EXIT();
 474                   return;
 475               }
 476           
 477               try
 478               {
 479                   _startAgentProcess();
 480 kumpf 1.1 
 481                   _sendInitializationData();
 482           
 483                   _isInitialized = true;
 484           
 485                   // Start a thread to read and process responses from the Provider Agent
 486                   while (!MessageQueueService::get_thread_pool()->allocate_and_awaken(
 487                              this, _responseProcessor))
 488                   {
 489                       pegasus_yield();
 490                   }
 491               }
 492               catch (...)
 493               {
 494                   _isInitialized = false;
 495                   _pipeToAgent.reset();
 496                   _pipeFromAgent.reset();
 497                   PEG_METHOD_EXIT();
 498                   throw;
 499               }
 500           
 501 kumpf 1.1     PEG_METHOD_EXIT();
 502           }
 503           
 504           Boolean ProviderAgentContainer::isInitialized()
 505           {
 506               AutoMutex lock(_agentMutex);
 507               return _isInitialized;
 508           }
 509           
 510           // Note: Caller must lock _agentMutex
 511           void ProviderAgentContainer::_uninitialize()
 512           {
 513               PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 514                   "ProviderAgentContainer::_uninitialize");
 515           
 516               if (!_isInitialized)
 517               {
 518                   PEGASUS_ASSERT(0);
 519                   PEG_METHOD_EXIT();
 520                   return;
 521               }
 522 kumpf 1.1 
 523               try
 524               {
 525                   // Close the connection with the Provider Agent
 526                   _pipeFromAgent.reset();
 527                   _pipeToAgent.reset();
 528           
 529 kumpf 1.2         _providerModuleCache = CIMInstance();
 530           
 531 kumpf 1.1         _isInitialized = false;
 532           
 533                   //
 534                   // Complete with null responses all outstanding requests on this
 535                   // connection
 536                   //
 537                   {
 538                       AutoMutex tableLock(_outstandingRequestTableMutex);
 539           
 540                       for (OutstandingRequestTable::Iterator i =
 541                                _outstandingRequestTable.start();
 542                            i != 0; i++)
 543                       {
 544                           PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
 545                               String("Completing messageId \"") + i.value()->messageId +
 546                                   "\" with a null response.");
 547                           i.value()->responseMessage = 0;
 548                           i.value()->responseReady->signal();
 549                       }
 550           
 551                       _outstandingRequestTable.clear();
 552 kumpf 1.1         }
 553               }
 554               catch (...)
 555               {
 556                   // We're uninitializing, so do not propagate the exception
 557                   PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
 558                       "Ignoring _uninitialize() exception.");
 559               }
 560           
 561               PEG_METHOD_EXIT();
 562           }
 563           
 564           CIMResponseMessage* ProviderAgentContainer::processMessage(
 565               CIMRequestMessage* request)
 566           {
 567               PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 568                   "ProviderAgentContainer::processMessage");
 569           
 570               CIMResponseMessage* response;
 571               String originalMessageId = request->messageId;
 572           
 573 kumpf 1.2     // These three variables are used for the provider module optimization.
 574               // See the _providerModuleCache member description for more information.
 575               AutoPtr<ProviderIdContainer> origProviderId;
 576               Boolean doProviderModuleOptimization = false;
 577               Boolean updateProviderModuleCache = false;
 578           
 579 kumpf 1.1     try
 580               {
 581                   // The messageId attribute is used to correlate response messages
 582                   // from the Provider Agent with request messages, so it is imperative
 583                   // that the ID is unique for each request.  The incoming ID cannot be
 584                   // trusted to be unique, so we substitute a unique one.  The memory
 585                   // address of the request is used as the source of a unique piece of
 586                   // data.  (The message ID is only required to be unique while the
 587                   // request is outstanding.)
 588                   char messagePtrString[20];
 589                   sprintf(messagePtrString, "%p", request);
 590                   String uniqueMessageId = messagePtrString;
 591           
 592                   //
 593                   // Set up the OutstandingRequestEntry for this request
 594                   //
 595                   Semaphore waitSemaphore(0);
 596                   OutstandingRequestEntry outstandingRequestEntry(
 597                       uniqueMessageId, response, &waitSemaphore);
 598           
 599                   //
 600 kumpf 1.1         // Lock the Provider Agent Container while initializing the
 601                   // agent and writing the request to the connection
 602                   //
 603                   {
 604                       AutoMutex lock(_agentMutex);
 605           
 606                       //
 607                       // Initialize the Provider Agent, if necessary
 608                       //
 609                       if (!_isInitialized)
 610                       {
 611                           _initialize();
 612                       }
 613           
 614                       //
 615                       // Add an entry to the OutstandingRequestTable for this request
 616                       //
 617                       {
 618                           AutoMutex tableLock(_outstandingRequestTableMutex);
 619           
 620                           _outstandingRequestTable.insert(
 621 kumpf 1.1                     uniqueMessageId, &outstandingRequestEntry);
 622                       }
 623           
 624 kumpf 1.2             // Get the provider module from the ProviderIdContainer to see if
 625                       // we can optimize out the transmission of this instance to the
 626                       // Provider Agent.  (See the _providerModuleCache description.)
 627                       try
 628                       {
 629                           ProviderIdContainer pidc = request->operationContext.get(
 630                               ProviderIdContainer::NAME);
 631                           origProviderId.reset(new ProviderIdContainer(
 632                               pidc.getModule(), pidc.getProvider(),
 633                               pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
 634                           if (_providerModuleCache.isUninitialized() ||
 635                               (!pidc.getModule().identical(_providerModuleCache)))
 636                           {
 637                               // We haven't sent this provider module instance to the
 638                               // Provider Agent yet.  Update our cache after we send it.
 639                               updateProviderModuleCache = true;
 640                           }
 641                           else
 642                           {
 643                               // Replace the provider module in the ProviderIdContainer
 644                               // with an uninitialized instance.  We'll need to put the
 645 kumpf 1.2                     // original one back after the message is sent.
 646                               request->operationContext.set(ProviderIdContainer(
 647                                   CIMInstance(), pidc.getProvider(),
 648                                   pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
 649                               doProviderModuleOptimization = true;
 650                           }
 651                       }
 652                       catch (...)
 653                       {
 654                           // No ProviderIdContainer to optimize
 655                       }
 656           
 657 kumpf 1.1             //
 658                       // Write the message to the pipe
 659                       //
 660                       try
 661                       {
 662                           PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL3,
 663                               String("Sending request to agent with messageId ") +
 664                                   uniqueMessageId);
 665           
 666                           request->messageId = uniqueMessageId;
 667                           AnonymousPipe::Status writeStatus =
 668                               _pipeToAgent->writeMessage(request);
 669                           request->messageId = originalMessageId;
 670           
 671 kumpf 1.2                 if (doProviderModuleOptimization)
 672                           {
 673                               request->operationContext.set(*origProviderId.get());
 674                           }
 675           
 676 kumpf 1.1                 if (writeStatus != AnonymousPipe::STATUS_SUCCESS)
 677                           {
 678                               Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
 679                                   "Failed to write message to pipe.  writeStatus = %d.",
 680                                   writeStatus);
 681                               throw Exception(MessageLoaderParms(
 682                                   "ProviderManager.OOPProviderManagerRouter."
 683                                       "CIMPROVAGT_COMMUNICATION_FAILED",
 684                                   "Failed to communicate with cimprovagt \"$0\".",
 685                                   _moduleName));
 686                           }
 687 kumpf 1.2 
 688                           if (updateProviderModuleCache)
 689                           {
 690                               _providerModuleCache = origProviderId->getModule();
 691                           }
 692 kumpf 1.1             }
 693                       catch (...)
 694                       {
 695                           request->messageId = originalMessageId;
 696 kumpf 1.2 
 697                           if (doProviderModuleOptimization)
 698                           {
 699                               request->operationContext.set(*origProviderId.get());
 700                           }
 701           
 702 kumpf 1.1                 Tracer::trace(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
 703                               "Failed to write message to pipe.");
 704                           // Remove the OutstandingRequestTable entry for this request
 705                           {
 706                               AutoMutex tableLock(_outstandingRequestTableMutex);
 707                               Boolean removed =
 708                                   _outstandingRequestTable.remove(uniqueMessageId);
 709                               PEGASUS_ASSERT(removed);
 710                           }
 711                           throw;
 712                       }
 713                   }
 714           
 715                   //
 716                   // Wait for the response
 717                   //
 718                   try
 719                   {
 720                       // Must not hold _agentMutex while waiting for the response
 721                       waitSemaphore.wait();
 722                   }
 723 kumpf 1.1         catch (...)
 724                   {
 725                       // Remove the OutstandingRequestTable entry for this request
 726                       {
 727                           AutoMutex tableLock(_outstandingRequestTableMutex);
 728                           Boolean removed =
 729                               _outstandingRequestTable.remove(uniqueMessageId);
 730                           PEGASUS_ASSERT(removed);
 731                       }
 732                       throw;
 733                   }
 734           
 735                   // A null response is returned when an agent connection is closed
 736                   // while requests remain outstanding.
 737                   if (response == 0)
 738                   {
 739                       response = request->buildResponse();
 740                       response->cimException = PEGASUS_CIM_EXCEPTION(
 741                           CIM_ERR_FAILED,
 742                           MessageLoaderParms(
 743                               "ProviderManager.OOPProviderManagerRouter."
 744 kumpf 1.1                         "CIMPROVAGT_CONNECTION_LOST",
 745                               "Lost connection with cimprovagt \"$0\".",
 746                               _moduleName));
 747                   }
 748               }
 749               catch (CIMException& e)
 750               {
 751                   PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
 752                       String("Caught exception: ") + e.getMessage());
 753                   response = request->buildResponse();
 754                   response->cimException = e;
 755               }
 756               catch (Exception& e)
 757               {
 758                   PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
 759                       String("Caught exception: ") + e.getMessage());
 760                   response = request->buildResponse();
 761                   response->cimException = PEGASUS_CIM_EXCEPTION(
 762                       CIM_ERR_FAILED, e.getMessage());
 763               }
 764               catch (...)
 765 kumpf 1.1     {
 766                   PEG_TRACE_STRING(TRC_PROVIDERMANAGER, Tracer::LEVEL2,
 767                       "Caught unknown exception");
 768                   response = request->buildResponse();
 769                   response->cimException = PEGASUS_CIM_EXCEPTION(
 770                       CIM_ERR_FAILED, String::EMPTY);
 771               }
 772           
 773               response->messageId = originalMessageId;
 774           
 775               PEG_METHOD_EXIT();
 776               return response;
 777           }
 778           
 779           void ProviderAgentContainer::unloadIdleProviders()
 780           {
 781               PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 782 carolann.graves 1.4         "ProviderAgentContainer::unloadIdleProviders");
 783 kumpf           1.1 
 784                         AutoMutex lock(_agentMutex);
 785                         if (_isInitialized)
 786                         {
 787                             // Send a "wake up" message to the Provider Agent.
 788                             // Don't bother checking whether the operation is successful.
 789                             Uint32 messageLength = 0;
 790                             _pipeToAgent->writeBuffer((const char*)&messageLength, sizeof(Uint32));
 791                         }
 792                     
 793                         PEG_METHOD_EXIT();
 794                     }
 795                     
 796                     void ProviderAgentContainer::_processResponses()
 797                     {
 798                         PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 799                             "ProviderAgentContainer::_processResponses");
 800                     
 801                         //
 802                         // Process responses until the pipe is closed
 803                         //
 804 kumpf           1.1     while (1)
 805                         {
 806                             try
 807                             {
 808                                 CIMMessage* message;
 809                     
 810                                 //
 811                                 // Read a response from the Provider Agent
 812                                 //
 813                                 AnonymousPipe::Status readStatus =
 814                                     _pipeFromAgent->readMessage(message);
 815                     
 816                                 // Ignore interrupts
 817                                 if (readStatus == AnonymousPipe::STATUS_INTERRUPT)
 818                                 {
 819                                     continue;
 820                                 }
 821                     
 822                                 // Handle an error the same way as a closed connection
 823                                 if ((readStatus == AnonymousPipe::STATUS_ERROR) ||
 824                                     (readStatus == AnonymousPipe::STATUS_CLOSED))
 825 kumpf           1.1             {
 826                                     AutoMutex lock(_agentMutex);
 827                                     _uninitialize();
 828                                     return;
 829                                 }
 830                     
 831                                 if (message->getType() == CIM_PROCESS_INDICATION_REQUEST_MESSAGE)
 832                                 {
 833                                     // Forward indications to the indication callback
 834                                     _indicationCallback(
 835                                         reinterpret_cast<CIMProcessIndicationRequestMessage*>(
 836                                             message));
 837                                 }
 838                                 else
 839                                 {
 840                                     CIMResponseMessage* response;
 841                                     response = dynamic_cast<CIMResponseMessage*>(message);
 842                                     PEGASUS_ASSERT(response != 0);
 843                     
 844                                     // Give the response to the waiting OutstandingRequestEntry
 845                                     OutstandingRequestEntry* _outstandingRequestEntry = 0;
 846 kumpf           1.1                 {
 847                                         AutoMutex tableLock(_outstandingRequestTableMutex);
 848                                         Boolean foundEntry = _outstandingRequestTable.lookup(
 849                                             response->messageId, _outstandingRequestEntry);
 850                                         PEGASUS_ASSERT(foundEntry);
 851                     
 852                                         // Remove the completed request from the table
 853                                         Boolean removed =
 854                                             _outstandingRequestTable.remove(response->messageId);
 855                                         PEGASUS_ASSERT(removed);
 856                                     }
 857                     
 858                                     _outstandingRequestEntry->responseMessage = response;
 859                                     _outstandingRequestEntry->responseReady->signal();
 860                                 }
 861                             }
 862                             catch (Exception& e)
 863                             {
 864                                 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
 865                                     String("Ignoring exception: ") + e.getMessage());
 866                             }
 867 kumpf           1.1         catch (...)
 868                             {
 869                                 PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
 870                                     "Ignoring exception");
 871                             }
 872                         }
 873                     
 874                         PEG_METHOD_EXIT();
 875                     }
 876                     
 877                     PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL
 878                     ProviderAgentContainer::_responseProcessor(void* arg)
 879                     {
 880                         ProviderAgentContainer* pa =
 881                             reinterpret_cast<ProviderAgentContainer*>(arg);
 882                     
 883                         pa->_processResponses();
 884                     
 885                         return(PEGASUS_THREAD_RETURN(0));
 886                     }
 887                     
 888 kumpf           1.1 /////////////////////////////////////////////////////////////////////////////
 889                     // OOPProviderManagerRouter
 890                     /////////////////////////////////////////////////////////////////////////////
 891                     
 892                     OOPProviderManagerRouter::OOPProviderManagerRouter(
 893                         PEGASUS_INDICATION_CALLBACK indicationCallback)
 894                     {
 895                         PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 896                             "OOPProviderManagerRouter::OOPProviderManagerRouter");
 897                     
 898                         _indicationCallback = indicationCallback;
 899                     
 900                         PEG_METHOD_EXIT();
 901                     }
 902                     
 903                     OOPProviderManagerRouter::~OOPProviderManagerRouter()
 904                     {
 905                         PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 906                             "OOPProviderManagerRouter::~OOPProviderManagerRouter");
 907                     
 908                         try
 909 kumpf           1.1     {
 910                             // Clean up the ProviderAgentContainers
 911                             AutoMutex lock(_providerAgentTableMutex);
 912                             ProviderAgentTable::Iterator i = _providerAgentTable.start();
 913                             for(; i != 0; i++)
 914                             {
 915                                 delete i.value();
 916                             }
 917                         }
 918                         catch (...) {}
 919                     
 920                         PEG_METHOD_EXIT();
 921                     }
 922                     
 923                     // Private, unimplemented constructor
 924                     OOPProviderManagerRouter::OOPProviderManagerRouter()
 925                     {
 926                     }
 927                     
 928                     // Private, unimplemented constructor
 929                     OOPProviderManagerRouter::OOPProviderManagerRouter(
 930 kumpf           1.1     const OOPProviderManagerRouter&)
 931 david.dillard   1.3     : ProviderManagerRouter(*this)
 932 kumpf           1.1 {
 933                     }
 934                     
 935                     // Private, unimplemented assignment operator
 936                     OOPProviderManagerRouter& OOPProviderManagerRouter::operator=(
 937                         const OOPProviderManagerRouter&)
 938                     {
 939                         return *this;
 940                     }
 941                     
 942                     Message* OOPProviderManagerRouter::processMessage(Message* message)
 943                     {
 944                         PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
 945                             "OOPProviderManagerRouter::processMessage");
 946                     
 947                         CIMRequestMessage* request = dynamic_cast<CIMRequestMessage *>(message);
 948                         PEGASUS_ASSERT(request != 0);
 949                     
 950                         AutoPtr<CIMResponseMessage> response;
 951                     
 952                         //
 953 kumpf           1.1     // Get the provider information from the request
 954                         //
 955                         CIMInstance providerModule;
 956                     
 957                         if ((dynamic_cast<CIMOperationRequestMessage*>(request) != 0) ||
 958                             (dynamic_cast<CIMIndicationRequestMessage*>(request) != 0) ||
 959                             (request->getType() == CIM_EXPORT_INDICATION_REQUEST_MESSAGE))
 960                         {
 961                             // Provider information is in the OperationContext
 962                             ProviderIdContainer pidc = (ProviderIdContainer)
 963                                 request->operationContext.get(ProviderIdContainer::NAME);
 964                             providerModule = pidc.getModule();
 965                         }
 966                         else if (request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE)
 967                         {
 968                             CIMEnableModuleRequestMessage* emReq =
 969                                 dynamic_cast<CIMEnableModuleRequestMessage*>(request);
 970                             providerModule = emReq->providerModule;
 971                         }
 972                         else if (request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE)
 973                         {
 974 kumpf           1.1         CIMDisableModuleRequestMessage* dmReq =
 975                                 dynamic_cast<CIMDisableModuleRequestMessage*>(request);
 976                             providerModule = dmReq->providerModule;
 977                         }
 978                         else if ((request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE) ||
 979                                  (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE))
 980                         {
 981                             // This operation is not provider-specific
 982                         }
 983                         else
 984                         {
 985                             // Unrecognized message type.  This should never happen.
 986                             PEGASUS_ASSERT(0);
 987                             response.reset(request->buildResponse());
 988                             response->cimException = PEGASUS_CIM_EXCEPTION(
 989                                 CIM_ERR_FAILED, "Unrecognized message type.");
 990                             PEG_METHOD_EXIT();
 991                             return response.release();
 992                         }
 993                     
 994                         //
 995 kumpf           1.1     // Process the request message
 996                         //
 997                         if (request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE)
 998                         {
 999                             // Forward the CIMStopAllProvidersRequest to all providers
1000                             response.reset(_forwardRequestToAllAgents(request));
1001                     
1002                             // Note: Do not uninitialize the ProviderAgentContainers here.
1003                             // Just let the selecting thread notice when the agent connections
1004                             // are closed.
1005                         }
1006                         else if (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE)
1007                         {
1008                             CIMNotifyConfigChangeRequestMessage* notifyRequest =
1009                                 dynamic_cast<CIMNotifyConfigChangeRequestMessage*>(request);
1010                             PEGASUS_ASSERT(notifyRequest != 0);
1011                     
1012                             if (notifyRequest->currentValueModified)
1013                             {
1014                                 // Forward the CIMNotifyConfigChangeRequestMessage to all providers
1015                                 response.reset(_forwardRequestToAllAgents(request));
1016 kumpf           1.1         }
1017                             else
1018                             {
1019                                 // No need to notify provider agents about changes to planned value
1020                                 response.reset(request->buildResponse());
1021                             }
1022                         }
1023                         else
1024                         {
1025                             // Retrieve the provider module name
1026                             String moduleName;
1027                             CIMValue nameValue = providerModule.getProperty(
1028                                 providerModule.findProperty("Name")).getValue();
1029                             nameValue.get(moduleName);
1030                     
1031                             // Look up the Provider Agent for this module
1032                             ProviderAgentContainer * pa = _lookupProviderAgent(moduleName);
1033                             PEGASUS_ASSERT(pa != 0);
1034                     
1035                             // Determine whether the Provider Agent has been initialized
1036                             Boolean paInitialized = pa->isInitialized();
1037 kumpf           1.1 
1038                             if ((request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE) &&
1039                                 !paInitialized)
1040                             {
1041                                 //
1042                                 // Do not start up an agent process just to disable the module
1043                                 //
1044                                 response.reset(request->buildResponse());
1045                     
1046                                 CIMDisableModuleResponseMessage* dmResponse =
1047                                     dynamic_cast<CIMDisableModuleResponseMessage*>(response.get());
1048                                 PEGASUS_ASSERT(dmResponse != 0);
1049                     
1050                                 Array<Uint16> operationalStatus;
1051                                 operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_STOPPED);
1052                                 dmResponse->operationalStatus = operationalStatus;
1053                             }
1054                             else if ((request->getType() == CIM_ENABLE_MODULE_REQUEST_MESSAGE) &&
1055                                      !paInitialized)
1056                             {
1057                                 //
1058 kumpf           1.1             // Do not start up an agent process just to enable the module
1059                                 //
1060                                 response.reset(request->buildResponse());
1061                     
1062                                 CIMEnableModuleResponseMessage* emResponse =
1063                                     dynamic_cast<CIMEnableModuleResponseMessage*>(response.get());
1064                                 PEGASUS_ASSERT(emResponse != 0);
1065                     
1066                                 Array<Uint16> operationalStatus;
1067                                 operationalStatus.append(CIM_MSE_OPSTATUS_VALUE_OK);
1068                                 emResponse->operationalStatus = operationalStatus;
1069                             }
1070                             else
1071                             {
1072                                 //
1073                                 // Forward the request to the provider agent
1074                                 //
1075                                 response.reset(pa->processMessage(request));
1076                     
1077                                 // Note: Do not uninitialize the ProviderAgentContainer here when
1078                                 // a disable module operation is successful.)  Just let the
1079 kumpf           1.1             // selecting thread notice when the agent connection is closed.
1080                             }
1081                         }
1082                     
1083                         response->syncAttributes(request);
1084                     
1085                         PEG_METHOD_EXIT();
1086                         return response.release();
1087                     }
1088                     
1089                     ProviderAgentContainer* OOPProviderManagerRouter::_lookupProviderAgent(
1090                         const String& moduleName)
1091                     {
1092                         ProviderAgentContainer* pa = 0;
1093                     
1094                         AutoMutex lock(_providerAgentTableMutex);
1095                         if (!_providerAgentTable.lookup(moduleName, pa))
1096                         {
1097                             pa = new ProviderAgentContainer(moduleName, _indicationCallback);
1098                             _providerAgentTable.insert(moduleName, pa);
1099                         }
1100 kumpf           1.1     return pa;
1101                     }
1102                     
1103                     CIMResponseMessage* OOPProviderManagerRouter::_forwardRequestToAllAgents(
1104                         CIMRequestMessage* request)
1105                     {
1106                         PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1107                             "OOPProviderManagerRouter::_forwardRequestToAllAgents");
1108                     
1109                         // Get a list of the ProviderAgentContainers.  We need our own array copy
1110                         // because we cannot hold the _providerAgentTableMutex while calling
1111                         // _ProviderAgentContainer::processMessage().
1112                         Array<ProviderAgentContainer*> paContainerArray;
1113                         {
1114                             AutoMutex tableLock(_providerAgentTableMutex);
1115                             for (ProviderAgentTable::Iterator i = _providerAgentTable.start();
1116                                  i != 0; i++)
1117                             {
1118                                 paContainerArray.append(i.value());
1119                             }
1120                         }
1121 kumpf           1.1 
1122                         CIMException responseException;
1123                     
1124                         // Forward the request to each of the initialized provider agents
1125                         for (Uint32 j = 0; j < paContainerArray.size(); j++)
1126                         {
1127                             ProviderAgentContainer* pa = paContainerArray[j];
1128                             if (pa->isInitialized())
1129                             {
1130                                 // Note: The ProviderAgentContainer could become uninitialized
1131                                 // before _ProviderAgentContainer::processMessage() processes
1132                                 // this request.  In this case, the Provider Agent process will
1133                                 // (unfortunately) be started to process this message.
1134                                 AutoPtr<CIMResponseMessage> response;
1135                                 response.reset(pa->processMessage(request));
1136                                 if (response.get() != 0)
1137                                 {
1138                                     // If the operation failed, save the exception data
1139                                     if ((response->cimException.getCode() != CIM_ERR_SUCCESS) &&
1140                                         (responseException.getCode() == CIM_ERR_SUCCESS))
1141                                     {
1142 kumpf           1.1                     responseException = response->cimException;
1143                                     }
1144                                 }
1145                             }
1146                         }
1147                     
1148                         CIMResponseMessage* response = request->buildResponse();
1149                         response->cimException = responseException;
1150                     
1151                         PEG_METHOD_EXIT();
1152                         return response;
1153                     }
1154                     
1155                     Boolean OOPProviderManagerRouter::hasActiveProviders()
1156                     {
1157                         PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1158                             "OOPProviderManagerRouter::hasActiveProviders");
1159                     
1160                         // Iterate through the _providerAgentTable looking for initialized agents
1161                         AutoMutex lock(_providerAgentTableMutex);
1162                         ProviderAgentTable::Iterator i = _providerAgentTable.start();
1163 kumpf           1.1     for(; i != 0; i++)
1164                         {
1165                             if (i.value()->isInitialized())
1166                             {
1167                                 PEG_METHOD_EXIT();
1168                                 return true;
1169                             }
1170                         }
1171                     
1172                         // No initialized Provider Agents were found
1173                         PEG_METHOD_EXIT();
1174                         return false;
1175                     }
1176                     
1177                     void OOPProviderManagerRouter::unloadIdleProviders()
1178                     {
1179                         PEG_METHOD_ENTER(TRC_PROVIDERMANAGER,
1180                             "OOPProviderManagerRouter::unloadIdleProviders");
1181                     
1182                         // Iterate through the _providerAgentTable unloading idle providers
1183                         AutoMutex lock(_providerAgentTableMutex);
1184 kumpf           1.1     ProviderAgentTable::Iterator i = _providerAgentTable.start();
1185                         for(; i != 0; i++)
1186                         {
1187                             i.value()->unloadIdleProviders();
1188                         }
1189                     
1190                         PEG_METHOD_EXIT();
1191                     }
1192                     
1193                     PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2