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
|
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
|