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

  1 kumpf 1.1 //%/////////////////////////////////////////////////////////////////////////////
  2           //
  3           // Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM,
  4           // The Open Group, Tivoli Systems
  5           //
  6           // Permission is hereby granted, free of charge, to any person obtaining a copy
  7           // of this software and associated documentation files (the "Software"), to
  8           // deal in the Software without restriction, including without limitation the
  9           // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 10           // sell copies of the Software, and to permit persons to whom the Software is
 11           // furnished to do so, subject to the following conditions:
 12           // 
 13           // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
 14           // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
 15           // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 16           // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 17           // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 18           // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 19           // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 20           // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 21           //
 22 kumpf 1.1 //==============================================================================
 23           //
 24           // Author: Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
 25           //         Jenny Yu, Hewlett-Packard Company (jenny_yu@hp.com)
 26           //
 27           // Modified By:
 28           //
 29           //%/////////////////////////////////////////////////////////////////////////////
 30           
 31           #include <Pegasus/Common/Array.h>
 32           #include <Pegasus/Common/AutoPtr.h>
 33           #include <Pegasus/Common/CIMMessageSerializer.h>
 34           #include <Pegasus/Common/CIMMessageDeserializer.h>
 35           #include <Pegasus/Common/Tracer.h>
 36           #include <Pegasus/Config/ConfigManager.h>
 37           
 38           #include "ProviderAgent.h"
 39           
 40           PEGASUS_USING_STD;
 41           
 42           PEGASUS_NAMESPACE_BEGIN
 43 kumpf 1.1 
 44           /////////////////////////////////////////////////////////////////////////////
 45           //
 46           // ProviderAgentRequest
 47           //
 48           /////////////////////////////////////////////////////////////////////////////
 49           
 50           /**
 51               This class encapsulates the data required by a work thread to process a
 52               request in a Provider Agent.
 53            */
 54           class ProviderAgentRequest
 55           {
 56           public:
 57               ProviderAgentRequest(ProviderAgent* agent_, CIMRequestMessage* request_)
 58               {
 59                   agent = agent_;
 60                   request = request_;
 61               }
 62           
 63               ProviderAgent* agent;
 64 kumpf 1.1     CIMRequestMessage* request;
 65           };
 66           
 67           
 68           /////////////////////////////////////////////////////////////////////////////
 69           //
 70           // ProviderAgent
 71           //
 72           /////////////////////////////////////////////////////////////////////////////
 73           
 74           // Time values used in ThreadPool construction
 75           static struct timeval create_time = {0, 1};
 76           static struct timeval destroy_time = {300, 0};
 77           static struct timeval deadlock_time = {0, 0};
 78           
 79           ProviderAgent* ProviderAgent::_providerAgent = 0;
 80           
 81           ProviderAgent::ProviderAgent(
 82               const String& agentId,
 83               AnonymousPipe* pipeFromServer,
 84               AnonymousPipe* pipeToServer)
 85 kumpf 1.1     : _providerManagerRouter(_indicationCallback),
 86                 _threadPool(0, "ProviderAgent", 0, 0,
 87                     create_time, destroy_time, deadlock_time)
 88           {
 89               PEG_METHOD_ENTER(TRC_PROVIDERAGENT, "ProviderAgent::ProviderAgent");
 90           
 91               _terminating = false;
 92               _agentId = agentId;
 93               _pipeFromServer = pipeFromServer;
 94               _pipeToServer = pipeToServer;
 95               _providerAgent = this;
 96           
 97               PEG_METHOD_EXIT();
 98           }
 99           
100           ProviderAgent::~ProviderAgent()
101           {
102               PEG_METHOD_ENTER(TRC_PROVIDERAGENT, "ProviderAgent::~ProviderAgent");
103           
104               _providerAgent = 0;
105           
106 kumpf 1.1     PEG_METHOD_EXIT();
107           }
108           
109           // Private, unimplemented constructor
110           ProviderAgent::ProviderAgent()
111               : _providerManagerRouter(0),
112                 _threadPool(0, "null", 0, 0, create_time, destroy_time, deadlock_time)
113           {
114           }
115           
116           // Private, unimplemented constructor
117           ProviderAgent::ProviderAgent(const ProviderAgent&)
118               : _providerManagerRouter(0),
119                 _threadPool(0, "null", 0, 0, create_time, destroy_time, deadlock_time)
120           {
121           }
122           
123           // Private, unimplemented assignment operator
124           ProviderAgent& ProviderAgent::operator=(const ProviderAgent&)
125           {
126               return *this;
127 kumpf 1.1 }
128           
129           void ProviderAgent::run()
130           {
131               PEG_METHOD_ENTER(TRC_PROVIDERAGENT, "ProviderAgent::run");
132           
133               // Enable the signal handler to terminate gracefully on SIGHUP and SIGTERM
134               getSigHandle()->registerHandler(PEGASUS_SIGHUP, _terminateSignalHandler);
135               getSigHandle()->activate(PEGASUS_SIGHUP);
136               getSigHandle()->registerHandler(PEGASUS_SIGTERM, _terminateSignalHandler);
137               getSigHandle()->activate(PEGASUS_SIGTERM);
138           
139               while (!_terminating)
140               {
141                   Boolean active = true;
142                   try
143                   {
144                       //
145                       // Read and process the next request
146                       //
147                       active = _readAndProcessRequest();
148 kumpf 1.1         }
149                   catch (Exception& e)
150                   {
151                       PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
152                           String("Unexpected exception from _readAndProcessRequest(): ") +
153                               e.getMessage());
154                       _terminating = true;
155                   }
156                   catch (...)
157                   {
158                       PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
159                           "Unexpected exception from _readAndProcessRequest().");
160                       _terminating = true;
161                   }
162           
163                   if (_terminating)
164                   {
165                       //
166                       // Stop all providers
167                       //
168                       CIMStopAllProvidersRequestMessage stopRequest("0", QueueIdStack(0));
169 kumpf 1.1             AutoPtr<Message> stopResponse(_processRequest(&stopRequest));
170                   }
171                   else if (!active)
172                   {
173                       //
174                       // Stop agent process when no more providers are loaded
175                       //
176                       try
177                       {
178                           if (!_providerManagerRouter.hasActiveProviders())
179                           {
180                               PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
181                                   "No active providers.  Exiting.");
182                               _terminating = true;
183                           }
184                       }
185                       catch (...)
186                       {
187                           // Do not terminate the agent on this exception
188                           PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
189                               "Unexpected exception from hasActiveProviders()");
190 kumpf 1.1             }
191                   }
192               }
193           
194               PEG_METHOD_EXIT();
195           }
196           
197           Boolean ProviderAgent::_readAndProcessRequest()
198           {
199               PEG_METHOD_ENTER(TRC_PROVIDERAGENT,
200                   "ProviderAgent::_readAndProcessRequest");
201           
202               CIMRequestMessage* request;
203           
204               //
205               // Read the request from CIM Server
206               //
207               CIMMessage* cimMessage;
208               AnonymousPipe::Status readStatus = _pipeFromServer->readMessage(cimMessage);
209               request = dynamic_cast<CIMRequestMessage*>(cimMessage);
210           
211 kumpf 1.1     // Read operation was interrupted
212               if (readStatus == AnonymousPipe::STATUS_INTERRUPT)
213               {
214                   PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
215                       "Read operation was interrupted.");
216                   PEG_METHOD_EXIT();
217                   return false;
218               }
219           
220               if (readStatus == AnonymousPipe::STATUS_CLOSED)
221               {
222                   // The CIM Server connection is closed
223                   PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
224                       "CIMServer connection closed. Exiting.");
225                   _terminating = true;
226                   PEG_METHOD_EXIT();
227                   return false;
228               }
229           
230               if (readStatus == AnonymousPipe::STATUS_ERROR)
231               {
232 kumpf 1.1         PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
233                       "Error reading from pipe. Exiting.");
234                   Logger::put_l(Logger::ERROR_LOG, System::CIMSERVER, Logger::WARNING,
235                       "ProviderManager.ProviderAgent.ProviderAgent."
236                           "CIMSERVER_COMMUNICATION_FAILED",
237                       "cimprovagt \"$0\" communication with CIM Server failed.  Exiting.",
238                       _agentId);
239                   _terminating = true;
240                   PEG_METHOD_EXIT();
241                   return false;
242               }
243           
244               // A "wake up" message means we should unload idle providers
245               if (request == 0)
246               {
247                   PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL4,
248                       "Got a wake up message.");
249                   try
250                   {
251                       _unloadIdleProviders();
252                   }
253 kumpf 1.1         catch (...)
254                   {
255                       // Ignore exceptions from idle provider unloading
256                       PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
257                           "Ignoring exception from _unloadIdleProviders()");
258                   }
259                   PEG_METHOD_EXIT();
260                   return false;
261               }
262           
263               PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL3,
264                   String("Received request from server with messageId ") +
265                       request->messageId);
266           
267 kumpf 1.2     // Get the ProviderIdContainer to complete the provider module instance
268               // optimization.  If the provider module instance is blank (optimized
269               // out), fill it in from our cache.  If it is not blank, update our
270               // cache.  (See the _providerModuleCache member description.)
271               try
272               {
273                   ProviderIdContainer pidc = request->operationContext.get(
274                       ProviderIdContainer::NAME);
275                   if (pidc.getModule().isUninitialized())
276                   {
277                       // Provider module is optimized out.  Fill it in from the cache.
278                       request->operationContext.set(ProviderIdContainer(
279                           _providerModuleCache, pidc.getProvider(),
280                           pidc.isRemoteNameSpace(), pidc.getRemoteInfo()));
281                   }
282                   else
283                   {
284                       // Update the cache with the new provider module instance.
285                       _providerModuleCache = pidc.getModule();
286                   }
287               }
288 kumpf 1.2     catch (...)
289               {
290                   // No ProviderIdContainer to optimize
291               }
292           
293 kumpf 1.1     //
294               // Check for messages to be handled by the Agent itself.
295               //
296               if (request->getType() == CIM_INITIALIZE_PROVIDER_AGENT_REQUEST_MESSAGE)
297               {
298                   // Process the request in this thread
299                   CIMInitializeProviderAgentRequestMessage* ipaRequest =
300                       dynamic_cast<CIMInitializeProviderAgentRequestMessage*>(request);
301                   PEGASUS_ASSERT(ipaRequest != 0);
302           
303                   ConfigManager* configManager = ConfigManager::getInstance();
304                   configManager->setPegasusHome(ipaRequest->pegasusHome);
305           
306                   // Initialize the configuration properties
307                   for (Uint32 i = 0; i < ipaRequest->configProperties.size(); i++)
308                   {
309                       configManager->initCurrentValue(
310                           ipaRequest->configProperties[i].first,
311                           ipaRequest->configProperties[i].second);
312                   }
313           
314 kumpf 1.1         // Set the default resource bundle directory for the MessageLoader
315                   MessageLoader::setPegasusMsgHome(ConfigManager::getHomedPath(
316                       configManager->getCurrentValue("messageDir")));
317           
318                   // Set the log file directory
319                   Logger::setHomeDirectory(ConfigManager::getHomedPath(
320                       configManager->getCurrentValue("logdir")));
321           
322                   System::bindVerbose = ipaRequest->bindVerbose;
323           
324                   PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
325                       "Processed the agent initialization message.");
326           
327                   // Do not write a response for this request
328               }
329               else if (request->getType() == CIM_NOTIFY_CONFIG_CHANGE_REQUEST_MESSAGE)
330               {
331                   // Process the request in this thread
332                   CIMNotifyConfigChangeRequestMessage* notifyRequest =
333                       dynamic_cast<CIMNotifyConfigChangeRequestMessage*>(request);
334                   PEGASUS_ASSERT(notifyRequest != 0);
335 kumpf 1.1 
336                   //
337                   // Update the ConfigManager with the new property value
338                   //
339                   ConfigManager* configManager = ConfigManager::getInstance();
340                   CIMException responseException;
341                   try
342                   {
343                       if (notifyRequest->currentValueModified)
344                       {
345                           configManager->updateCurrentValue(
346                               notifyRequest->propertyName,
347                               notifyRequest->newPropertyValue,
348                               false);
349                       }
350                       else
351                       {
352                           configManager->updatePlannedValue(
353                               notifyRequest->propertyName,
354                               notifyRequest->newPropertyValue,
355                               true);
356 kumpf 1.1             }
357                   }
358                   catch (Exception& e)
359                   {
360                       responseException = PEGASUS_CIM_EXCEPTION(
361                           CIM_ERR_FAILED, e.getMessage());
362                   }
363           
364                   CIMResponseMessage* response = notifyRequest->buildResponse();
365                   response->cimException = responseException;
366           
367                   // Return response to CIM Server
368                   _writeResponse(response);
369               }
370               else if ((request->getType() == CIM_DISABLE_MODULE_REQUEST_MESSAGE) ||
371                        (request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE))
372               {
373                   // Process the request in this thread
374                   Message* response = _processRequest(request);
375                   _writeResponse(response);
376           
377 kumpf 1.1         CIMResponseMessage * respMsg =
378                       dynamic_cast<CIMResponseMessage*>(response);
379           
380                   // If StopAllProviders, terminate the agent process.
381                   // If DisableModule not successful, leave agent process running.
382                   if ((respMsg->cimException.getCode() == CIM_ERR_SUCCESS) ||
383                       (request->getType() == CIM_STOP_ALL_PROVIDERS_REQUEST_MESSAGE))
384                   {
385                       // Operation is successful. End the agent process.
386                       _terminating = true;
387                   }
388               }
389               else
390               {
391                   // Start a new thread to process the request
392                   ProviderAgentRequest* agentRequest =
393                       new ProviderAgentRequest(this, request);
394           
395                   while (!_threadPool.allocate_and_awaken(
396                              agentRequest,
397                              ProviderAgent::_processRequestAndWriteResponse))
398 kumpf 1.1         {
399                       pegasus_yield();
400                   }
401               }
402           
403               PEG_METHOD_EXIT();
404               return true;
405           }
406           
407           Message* ProviderAgent::_processRequest(CIMRequestMessage* request)
408           {
409               PEG_METHOD_ENTER(TRC_PROVIDERAGENT, "ProviderAgent::_processRequest");
410           
411               Message* response = 0;
412           
413               try
414               {
415                   // Forward the request to the ProviderManager
416                   response = _providerManagerRouter.processMessage(request);
417               }
418               catch (Exception& e)
419 kumpf 1.1     {
420                   PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
421                       String("Caught exception while processing request: ") +
422                           e.getMessage());
423                   CIMResponseMessage* cimResponse = request->buildResponse();
424                   cimResponse->cimException = PEGASUS_CIM_EXCEPTION(
425                       CIM_ERR_FAILED, e.getMessage());
426                   response = cimResponse;
427               }
428               catch (...)
429               {
430                   PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
431                       "Caught exception while processing request.");
432                   CIMResponseMessage* cimResponse = request->buildResponse();
433                   cimResponse->cimException = PEGASUS_CIM_EXCEPTION(
434                       CIM_ERR_FAILED, String::EMPTY);
435                   response = cimResponse;
436               }
437           
438               PEG_METHOD_EXIT();
439               return response;
440 kumpf 1.1 }
441           
442           void ProviderAgent::_writeResponse(Message* message)
443           {
444               PEG_METHOD_ENTER(TRC_PROVIDERAGENT, "ProviderAgent::_writeResponse");
445           
446               CIMMessage* response = dynamic_cast<CIMMessage*>(message);
447               PEGASUS_ASSERT(response != 0);
448           
449               //
450               // Write the response message to the pipe
451               //
452               try
453               {
454                   // Use Mutex to prevent concurrent writes to the same pipe
455                   AutoMutex pipeLock(_pipeToServerMutex);
456           
457                   AnonymousPipe::Status writeStatus =
458                       _pipeToServer->writeMessage(response);
459           
460                   if (writeStatus != AnonymousPipe::STATUS_SUCCESS)
461 kumpf 1.1         {
462                       PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
463                           "Error writing response to pipe.");
464                       Logger::put_l(Logger::ERROR_LOG, System::CIMSERVER, Logger::WARNING,
465                           "ProviderManager.ProviderAgent.ProviderAgent."
466                               "CIMSERVER_COMMUNICATION_FAILED",
467                           "cimprovagt \"$0\" communication with CIM Server failed.  "
468                               "Exiting.",
469                           _agentId);
470                       _terminating = true;
471                   }
472               }
473               catch (...)
474               {
475                   PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
476                       "Caught exception while writing response.");
477                   Logger::put_l(Logger::ERROR_LOG, System::CIMSERVER, Logger::WARNING,
478                       "ProviderManager.ProviderAgent.ProviderAgent."
479                           "CIMSERVER_COMMUNICATION_FAILED",
480                       "cimprovagt \"$0\" communication with CIM Server failed.  Exiting.",
481                       _agentId);
482 kumpf 1.1         _terminating = true;
483               }
484           
485               PEG_METHOD_EXIT();
486           }
487           
488           PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL
489           ProviderAgent::_processRequestAndWriteResponse(void* arg)
490           {
491               PEG_METHOD_ENTER(TRC_PROVIDERAGENT,
492                   "ProviderAgent::_processRequestAndWriteResponse");
493           
494               AutoPtr<ProviderAgentRequest> agentRequest(
495                   reinterpret_cast<ProviderAgentRequest*>(arg));
496               PEGASUS_ASSERT(agentRequest.get() != 0);
497           
498               // Get the ProviderAgent and request message from the argument
499               ProviderAgent* agent = agentRequest->agent;
500               CIMRequestMessage* request = agentRequest->request;
501           
502               // Process the request
503 kumpf 1.1     Message* response = agent->_processRequest(request);
504           
505               // Write the response
506               agent->_writeResponse(response);
507           
508               PEG_METHOD_EXIT();
509               return(PEGASUS_THREAD_RETURN(0));
510           }
511           
512           void ProviderAgent::_indicationCallback(
513               CIMProcessIndicationRequestMessage* message)
514           {
515               PEG_METHOD_ENTER(TRC_PROVIDERAGENT, "ProviderAgent::_indicationCallback");
516           
517               // Send request back to the server to process
518               _providerAgent->_writeResponse(message);
519           
520               PEG_METHOD_EXIT();
521           }
522           
523           void ProviderAgent::_unloadIdleProviders()
524 kumpf 1.1 {
525               PEG_METHOD_ENTER(TRC_PROVIDERAGENT, "ProviderAgent::_unloadIdleProviders");
526           
527               // Ensure that only one _unloadIdleProvidersHandler thread runs at a time
528               _unloadIdleProvidersBusy++;
529               if ((_unloadIdleProvidersBusy.value() == 1) &&
530                   (_threadPool.allocate_and_awaken(
531                        (void*)this, ProviderAgent::_unloadIdleProvidersHandler)))
532               {
533                   // _unloadIdleProvidersBusy is decremented in
534                   // _unloadIdleProvidersHandler
535               }
536               else
537               {
538                   // If we fail to allocate a thread, don't retry now.
539                   _unloadIdleProvidersBusy--;
540               }
541           
542               PEG_METHOD_EXIT();
543           }
544           
545 kumpf 1.1 PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL
546           ProviderAgent::_unloadIdleProvidersHandler(void* arg) throw()
547           {
548               try
549               {
550                   PEG_METHOD_ENTER(TRC_PROVIDERAGENT,
551                       "ProviderAgent::unloadIdleProvidersHandler");
552           
553                   ProviderAgent* myself = reinterpret_cast<ProviderAgent*>(arg);
554           
555                   try
556                   {
557                       myself->_providerManagerRouter.unloadIdleProviders();
558                   }
559                   catch (...)
560                   {
561                       // Ignore errors
562                       PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
563                           "Unexpected exception in _unloadIdleProvidersHandler");
564                   }
565           
566 kumpf 1.1         myself->_unloadIdleProvidersBusy--;
567               }
568               catch (...)
569               {
570                   // Ignore errors
571                   try
572                   {
573                       PEG_TRACE_STRING(TRC_PROVIDERAGENT, Tracer::LEVEL2,
574                           "Unexpected exception in _unloadIdleProvidersHandler");
575                   }
576                   catch (...)
577                   {
578                   }
579               }
580           
581               // PEG_METHOD_EXIT();    // Note: This statement could throw an exception
582               return(PEGASUS_THREAD_RETURN(0));
583           }
584           
585           void ProviderAgent::_terminateSignalHandler(
586               int s_n, PEGASUS_SIGINFO_T* s_info, void* sig)
587 kumpf 1.1 {
588               PEG_METHOD_ENTER(TRC_PROVIDERAGENT,
589                   "ProviderAgent::_terminateSignalHandler");
590           
591               if (_providerAgent != 0)
592               {
593                   _providerAgent->_terminating = true;
594               }
595           
596               PEG_METHOD_EXIT();
597           }
598           
599           PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2