version 1.5, 2002/06/10 20:33:51
|
version 1.29, 2005/03/10 00:38:21
|
|
|
//%///////////////////////////////////////////////////////////////////////////// |
//%2005//////////////////////////////////////////////////////////////////////// |
// | // |
// Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM, |
// Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development |
// The Open Group, Tivoli Systems |
// Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems. |
|
// Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.; |
|
// IBM Corp.; EMC Corporation, The Open Group. |
|
// Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.; |
|
// IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group. |
|
// Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.; |
|
// EMC Corporation; VERITAS Software Corporation; The Open Group. |
// | // |
// Permission is hereby granted, free of charge, to any person obtaining a copy | // Permission is hereby granted, free of charge, to any person obtaining a copy |
// of this software and associated documentation files (the "Software"), to | // of this software and associated documentation files (the "Software"), to |
|
|
// | // |
//============================================================================== | //============================================================================== |
// | // |
// Author: Mike Brasher (mbrasher@bmc.com) |
// Author: Dong Xiang, EMC Corporation (xiang_dong@emc.com) |
// | // |
// Modified By: |
// Modified By: Dan Gorey (djgorey@us.ibm.com) |
// Mike Day (mdday@us.ibm.com)s |
// Amit K Arora, IBM (amita@in.ibm.com) for PEP#183 |
// Nitin Upasani, Hewlett-Packard Company (Nitin_Upasani@hp.com) |
// Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com) |
// Nag Boranna, Hewlett-Packard Company (nagaraja_boranna@hp.com) |
|
// Yi Zhou, Hewlett-Packard Company (yi_zhou@hp.com) |
|
// Jenny Yu, Hewlett-Packard Company (jenny_yu@hp.com) |
|
// | // |
//%///////////////////////////////////////////////////////////////////////////// | //%///////////////////////////////////////////////////////////////////////////// |
| |
#include <Pegasus/Common/Config.h> |
#include "CIMListener.h" |
| |
#include <iostream> |
#include <Pegasus/Common/Exception.h> |
#include <cstdio> |
#include <Pegasus/Common/SSLContext.h> |
#include <cctype> |
#include <Pegasus/Common/Monitor.h> |
#include <ctime> |
|
#include <Pegasus/Common/FileSystem.h> |
|
#include <Pegasus/Common/HTTPAcceptor.h> | #include <Pegasus/Common/HTTPAcceptor.h> |
#include <Pegasus/Common/Tracer.h> |
|
#include <Pegasus/Common/PegasusVersion.h> | #include <Pegasus/Common/PegasusVersion.h> |
| |
#include <Pegasus/Repository/CIMRepository.h> |
|
#include <Pegasus/ExportServer/CIMExportRequestDispatcher.h> |
|
#include <Pegasus/ExportServer/CIMExportResponseEncoder.h> | #include <Pegasus/ExportServer/CIMExportResponseEncoder.h> |
#include <Pegasus/ExportServer/CIMExportRequestDecoder.h> | #include <Pegasus/ExportServer/CIMExportRequestDecoder.h> |
| |
#include "CIMListener.h" |
#include <Pegasus/Consumer/CIMIndicationConsumer.h> |
|
#include <Pegasus/Listener/CIMListenerIndicationDispatcher.h> |
|
|
|
PEGASUS_NAMESPACE_BEGIN |
|
///////////////////////////////////////////////////////////////////////////// |
|
// CIMListenerService |
|
///////////////////////////////////////////////////////////////////////////// |
|
class CIMListenerService |
|
{ |
|
public: |
|
CIMListenerService(Uint32 portNumber, SSLContext* sslContext=NULL); |
|
CIMListenerService(CIMListenerService& svc); |
|
~CIMListenerService(); |
|
|
|
void init(); |
|
/** bind to the port |
|
*/ |
|
void bind(); |
|
/** runForever Main runloop for the server. |
|
*/ |
|
void runForever(); |
|
|
|
/** Call to gracefully shutdown the server. The server connection socket |
|
will be closed to disable new connections from clients. |
|
*/ |
|
void stopClientConnection(); |
|
|
|
/** Call to gracefully shutdown the server. It is called when the server |
|
has been stopped and is ready to be shutdown. Next time runForever() |
|
is called, the server shuts down. |
|
*/ |
|
void shutdown(); |
|
|
|
/** Return true if the server has shutdown, false otherwise. |
|
*/ |
|
Boolean terminated() { return _dieNow; }; |
|
|
|
/** Call to resume the sever. |
|
*/ |
|
void resume(); |
|
|
|
/** Call to set the CIMServer state. Also inform the appropriate |
|
message queues about the current state of the CIMServer. |
|
*/ |
|
void setState(Uint32 state); |
|
|
|
Uint32 getOutstandingRequestCount(); |
|
|
|
/** Returns the indication listener dispatcher |
|
*/ |
|
CIMListenerIndicationDispatcher* getIndicationDispatcher() const; |
|
|
|
/** Returns the indication listener dispatcher |
|
*/ |
|
void setIndicationDispatcher(CIMListenerIndicationDispatcher* dispatcher); |
|
|
|
static PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL _listener_routine(void *param); |
|
|
|
private: |
|
Uint32 _portNumber; |
|
SSLContext* _sslContext; |
|
Monitor* _monitor; |
|
HTTPAcceptor* _acceptor; |
|
|
|
Boolean _dieNow; |
|
|
|
CIMListenerIndicationDispatcher* _dispatcher; |
|
|
|
CIMExportResponseEncoder* _responseEncoder; |
|
CIMExportRequestDecoder* _requestDecoder; |
|
|
|
}; |
|
|
|
CIMListenerService::CIMListenerService(Uint32 portNumber, SSLContext* sslContext) |
|
:_portNumber(portNumber) |
|
,_sslContext(sslContext) |
|
,_monitor(NULL) |
|
,_acceptor(NULL) |
|
,_dieNow(false) |
|
,_dispatcher(NULL) |
|
,_responseEncoder(NULL) |
|
,_requestDecoder(NULL) |
|
{ |
|
} |
|
|
|
CIMListenerService::CIMListenerService(CIMListenerService& svc) |
|
:_portNumber(svc._portNumber) |
|
,_sslContext(svc._sslContext) |
|
,_monitor(NULL) |
|
,_acceptor(NULL) |
|
,_dieNow(svc._dieNow) |
|
,_dispatcher(NULL) |
|
,_responseEncoder(NULL) |
|
,_requestDecoder(NULL) |
|
{ |
|
} |
|
CIMListenerService::~CIMListenerService() |
|
{ |
|
// if port is alive, clean up the port |
|
//if(_sslContext!=NULL) |
|
// delete _sslContext; |
| |
#define DDD(X) // X |
if(_responseEncoder!=NULL) |
|
delete _responseEncoder; |
| |
PEGASUS_USING_STD; |
if(_requestDecoder!=NULL) |
|
delete _requestDecoder; |
| |
PEGASUS_NAMESPACE_BEGIN |
//if(_dispatcher!=NULL) |
|
// delete _dispatcher; |
|
|
|
if(_monitor!=NULL) |
|
delete _monitor; |
| |
CIMListener::CIMListener( |
if(_acceptor!=NULL) |
Monitor* monitor, |
delete _acceptor; |
const String& rootPath, |
} |
Boolean dynamicReg, |
|
Boolean staticConsumers, |
void CIMListenerService::init() |
Boolean persistence) |
|
: _dieNow(false), _rootPath(rootPath), |
|
_dynamicReg(dynamicReg), |
|
_staticConsumers(staticConsumers), |
|
_persistence(persistence) |
|
{ | { |
PEG_METHOD_ENTER(TRC_SERVER, "CIMListener::CIMListener()"); |
PEG_METHOD_ENTER(TRC_LISTENER, "CIMListenerService::init"); |
| |
// -- Save the monitor or create a new one: |
_monitor = new Monitor(); |
| |
_monitor = monitor; |
//_dispatcher = new CIMListenerIndicationDispatcher(); |
| |
// -- Create a CIMListenerState object: |
_responseEncoder = new CIMExportResponseEncoder(); |
|
_requestDecoder = new CIMExportRequestDecoder( |
|
_dispatcher, |
|
_responseEncoder->getQueueId()); |
|
|
|
_acceptor = new HTTPAcceptor( |
|
_monitor, |
|
_requestDecoder, |
|
false, |
|
_portNumber, |
|
_sslContext, |
|
false); |
| |
_cimExportRequestDispatcher |
bind(); |
= new CIMExportRequestDispatcher(dynamicReg, staticConsumers, persistence); |
|
| |
_cimExportResponseEncoder |
PEG_METHOD_EXIT(); |
= new CIMExportResponseEncoder; |
} |
|
void CIMListenerService::bind() |
|
{ |
|
if(_acceptor!=NULL) |
|
{ // Bind to the port |
|
_acceptor->bind(); |
|
|
|
PEGASUS_STD(cout) << "Listening on HTTP port " << _portNumber << PEGASUS_STD(endl); |
|
|
|
//listener.addAcceptor(false, portNumberHttp, false); |
|
Logger::put(Logger::STANDARD_LOG, System::CIMLISTENER, Logger::INFORMATION, |
|
"Listening on HTTP port $0.", _portNumber); |
| |
_cimExportRequestDecoder = new CIMExportRequestDecoder( |
} |
_cimExportRequestDispatcher, |
} |
_cimExportResponseEncoder->getQueueId()); |
|
| |
SSLContext * sslcontext = NULL; |
void CIMListenerService::runForever() |
|
{ |
|
static int modulator = 0; |
| |
_acceptor = new HTTPAcceptor(_monitor, _cimExportRequestDecoder, sslcontext); |
if(!_dieNow) |
|
{ |
|
if(false == _monitor->run(500000)) |
|
{ |
|
modulator++; |
|
try |
|
{ |
|
//MessageQueueService::_check_idle_flag = 1; |
|
//MessageQueueService::_polling_sem.signal(); |
|
MessageQueueService::get_thread_pool()->kill_idle_threads(); |
|
} |
|
catch(...) |
|
{ |
|
} |
|
} |
|
/* |
|
if (handleShutdownSignal) |
|
{ |
|
Tracer::trace(TRC_SERVER, Tracer::LEVEL3, |
|
"CIMServer::runForever - signal received. Shutting down."); |
|
|
|
ShutdownService::getInstance(this)->shutdown(true, 10, false); |
|
handleShutdownSignal = false; |
|
} |
|
*/ |
|
} |
|
} |
|
|
|
void CIMListenerService::shutdown() |
|
{ |
|
PEG_METHOD_ENTER(TRC_LISTENER, "CIMListenerService::shutdown()"); |
|
|
|
_dieNow = true; |
|
_monitor->tickle(); |
| |
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
} | } |
| |
CIMListener::~CIMListener() |
void CIMListenerService::resume() |
{ | { |
PEG_METHOD_ENTER(TRC_SERVER, "CIMListener::~CIMListener()"); |
PEG_METHOD_ENTER(TRC_LISTENER, "CIMListenerService::resume()"); |
| |
// Note: do not delete the acceptor because it belongs to the Monitor |
if(_acceptor!=NULL) |
// which takes care of disposing of it. |
_acceptor->reopenConnectionSocket(); |
| |
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
} | } |
| |
void CIMListener::bind(Uint32 port) |
void CIMListenerService::stopClientConnection() |
{ | { |
PEG_METHOD_ENTER(TRC_SERVER, "CIMListener::bind()"); |
PEG_METHOD_ENTER(TRC_LISTENER, "CIMListenerService::stopClientConnection()"); |
| |
// not the best place to build the service url, but it works for now |
// tell Monitor to stop listening for client connections |
// because the address string is accessible mdday |
_monitor->stopListeningForConnections(true); |
| |
_acceptor->bind(port); |
// |
|
// Wait 150 milliseconds to allow time for the Monitor to stop |
|
// listening for client connections. |
|
// |
|
// This wait time is the timeout value for the select() call |
|
// in the Monitor's run() method (currently set to 100 |
|
// milliseconds) plus a delta of 50 milliseconds. The reason |
|
// for the wait here is to make sure that the Monitor entries |
|
// are updated before closing the connection sockets. |
|
// |
|
// pegasus_sleep(150); Not needed now due to the semaphore in the Monitor |
|
|
|
if(_acceptor!=NULL) |
|
_acceptor->closeConnectionSocket(); |
| |
PEG_METHOD_EXIT(); | PEG_METHOD_EXIT(); |
} | } |
| |
void CIMListener::runForever() |
Uint32 CIMListenerService::getOutstandingRequestCount() |
{ | { |
//ATTN: Do not add Trace code in this method. |
return _acceptor->getOutstandingRequestCount(); |
if(!_dieNow) |
|
_monitor->run(100); |
|
} | } |
| |
void CIMListener::stopClientConnection() |
CIMListenerIndicationDispatcher* CIMListenerService::getIndicationDispatcher() const |
|
{ |
|
return _dispatcher; |
|
} |
|
void CIMListenerService::setIndicationDispatcher(CIMListenerIndicationDispatcher* dispatcher) |
{ | { |
PEG_METHOD_ENTER(TRC_SERVER, "CIMListener::stopClientConnection()"); |
_dispatcher = dispatcher; |
|
} |
| |
_acceptor->closeConnectionSocket(); |
PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL CIMListenerService::_listener_routine(void *param) |
|
{ |
|
CIMListenerService *svc = reinterpret_cast<CIMListenerService *>(param); |
| |
PEG_METHOD_EXIT(); |
//svc->init(); bug 1394 |
|
while(!svc->terminated()) |
|
{ |
|
#if defined(PEGASUS_PLATFORM_DARWIN_PPC_GNU) |
|
pthread_testcancel(); |
|
#endif |
|
svc->runForever(); |
|
} |
|
|
|
delete svc; |
|
|
|
return 0; |
} | } |
|
static struct timeval create_time = {0, 1}; |
|
static struct timeval destroy_time = {15, 0}; |
| |
void CIMListener::shutdown() |
///////////////////////////////////////////////////////////////////////////// |
|
// CIMListenerRep |
|
///////////////////////////////////////////////////////////////////////////// |
|
class CIMListenerRep |
|
{ |
|
public: |
|
CIMListenerRep(Uint32 portNumber, SSLContext* sslContext=NULL); |
|
~CIMListenerRep(); |
|
|
|
Uint32 getPortNumber() const; |
|
|
|
SSLContext* getSSLContext() const; |
|
void setSSLContext(SSLContext* sslContext); |
|
|
|
void start(); |
|
void stop(); |
|
|
|
Boolean isAlive(); |
|
|
|
Boolean addConsumer(CIMIndicationConsumer* consumer); |
|
Boolean removeConsumer(CIMIndicationConsumer* consumer); |
|
|
|
private: |
|
Boolean waitForPendingRequests(Uint32 shutdownTimeout); |
|
|
|
Uint32 _portNumber; |
|
SSLContext* _sslContext; |
|
|
|
CIMListenerIndicationDispatcher* _dispatcher; |
|
ThreadPool* _thread_pool; |
|
CIMListenerService* _svc; |
|
Semaphore *_listener_sem; |
|
}; |
|
|
|
CIMListenerRep::CIMListenerRep(Uint32 portNumber, SSLContext* sslContext) |
|
:_portNumber(portNumber) |
|
,_sslContext(sslContext) |
|
,_dispatcher(new CIMListenerIndicationDispatcher()) |
|
,_thread_pool(NULL) |
|
,_svc(NULL) |
|
,_listener_sem(NULL) |
|
{ |
|
} |
|
CIMListenerRep::~CIMListenerRep() |
|
{ |
|
// if port is alive, clean up the port |
|
if (_thread_pool != NULL) |
{ | { |
PEG_METHOD_ENTER(TRC_SERVER, "CIMListener::shutdown()"); |
// Block incoming export requests and unbind the port |
|
_svc->stopClientConnection(); |
| |
_dieNow = true; |
// Wait until pending export requests in the server are done. |
|
waitForPendingRequests(10); |
| |
PEG_METHOD_EXIT(); |
// Shutdown the CIMListenerService |
|
_svc->shutdown(); |
|
} |
|
|
|
if(_sslContext!=NULL) |
|
delete _sslContext; |
|
|
|
if(_dispatcher!=NULL) |
|
delete _dispatcher; |
|
|
|
if(_thread_pool!=NULL) |
|
delete _thread_pool; |
|
|
|
if(_listener_sem!=NULL) |
|
delete _listener_sem; |
|
|
|
// don't delete _svc, this is deleted by _listener_routine |
} | } |
| |
void CIMListener::resume() |
Uint32 CIMListenerRep::getPortNumber() const |
{ | { |
PEG_METHOD_ENTER(TRC_SERVER, "CIMListener::resume()"); |
return _portNumber; |
|
} |
| |
_acceptor->reopenConnectionSocket(); |
SSLContext* CIMListenerRep::getSSLContext() const |
|
{ |
|
return _sslContext; |
|
} |
|
void CIMListenerRep::setSSLContext(SSLContext* sslContext) |
|
{ |
|
if(_sslContext!=NULL) |
|
delete _sslContext; |
| |
PEG_METHOD_EXIT(); |
_sslContext = sslContext; |
|
} |
|
void CIMListenerRep::start() |
|
{ |
|
// spawn a thread to do this |
|
if(_thread_pool==NULL) |
|
{ |
|
CIMListenerService* svc = new CIMListenerService(_portNumber,_sslContext); |
|
try |
|
{ |
|
// Try to initialize the service (bug 1394) |
|
svc->setIndicationDispatcher(_dispatcher); |
|
svc->init(); |
|
} |
|
catch(...) |
|
{ |
|
// Error. Exit without creating the ThreadPool, so that this listener |
|
// is not 'alive' |
|
delete svc; |
|
throw; |
|
} |
|
|
|
_thread_pool = new ThreadPool(0, "Listener", 0, 1, |
|
create_time, destroy_time); |
|
|
|
_listener_sem = new Semaphore(0); |
|
_thread_pool->allocate_and_awaken(svc, |
|
CIMListenerService::_listener_routine, |
|
_listener_sem); |
|
|
|
_svc = svc; |
|
|
|
Logger::put(Logger::STANDARD_LOG,System::CIMLISTENER, |
|
Logger::INFORMATION, |
|
"CIMListener started"); |
|
|
|
PEGASUS_STD(cerr) << "CIMlistener started" << PEGASUS_STD(endl); |
|
} |
} | } |
| |
CIMExportRequestDispatcher* CIMListener::getDispatcher() |
void CIMListenerRep::stop() |
|
{ |
|
if(_thread_pool!=NULL) |
{ | { |
PEG_METHOD_ENTER(TRC_SERVER, "CIMListener::getDispatcher()"); |
// |
|
// Graceful shutdown of the listener service |
|
// |
| |
PEG_METHOD_EXIT(); |
// Block incoming export requests and unbind the port |
|
_svc->stopClientConnection(); |
|
|
|
// Wait until pending export requests in the server are done. |
|
waitForPendingRequests(10); |
| |
return _cimExportRequestDispatcher; |
// Shutdown the CIMListenerService |
|
_svc->shutdown(); |
|
|
|
// Wait for the _listener_routine thread to exit. |
|
// The thread could be delivering an export, so give it 3sec. |
|
// Note that _listener_routine deletes the CIMListenerService, |
|
// so no need to delete _svc. |
|
try |
|
{ |
|
_listener_sem->time_wait(3000); |
|
} |
|
catch (TimeOut &) |
|
{ |
|
// No need to do anything, the thread pool will be deleted below |
|
// to cancel the _listener_routine thread if it is still running. |
|
} |
|
|
|
delete _listener_sem; |
|
_listener_sem = NULL; |
|
|
|
// Delete the thread pool. This cancels the listener thread if it is still |
|
// running. |
|
delete _thread_pool; |
|
_thread_pool = NULL; |
|
|
|
Logger::put(Logger::STANDARD_LOG,System::CIMLISTENER, |
|
Logger::INFORMATION, |
|
"CIMListener stopped"); |
|
} |
} | } |
| |
Uint32 CIMListener::getOutstandingRequestCount() |
Boolean CIMListenerRep::isAlive() |
{ | { |
PEG_METHOD_ENTER(TRC_SERVER, "CIMListener::getOutstandingRequestCount()"); |
return (_thread_pool!=NULL)?true:false; |
|
} |
| |
PEG_METHOD_EXIT(); |
Boolean CIMListenerRep::addConsumer(CIMIndicationConsumer* consumer) |
|
{ |
|
return _dispatcher->addConsumer(consumer); |
|
} |
|
Boolean CIMListenerRep::removeConsumer(CIMIndicationConsumer* consumer) |
|
{ |
|
return _dispatcher->removeConsumer(consumer); |
|
} |
|
|
|
Boolean CIMListenerRep::waitForPendingRequests(Uint32 shutdownTimeout) |
|
{ |
|
// Wait for 10 sec max |
|
Uint32 reqCount; |
|
Uint32 countDown = shutdownTimeout * 10; |
|
for (; countDown > 0; countDown--) |
|
{ |
|
reqCount = _svc->getOutstandingRequestCount(); |
|
if (reqCount > 0) |
|
pegasus_sleep(100); |
|
else |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// CIMListener |
|
///////////////////////////////////////////////////////////////////////////// |
|
CIMListener::CIMListener(Uint32 portNumber, SSLContext* sslContext) |
|
:_rep(new CIMListenerRep(portNumber,sslContext)) |
|
{ |
|
} |
|
CIMListener::~CIMListener() |
|
{ |
|
if(_rep!=NULL) |
|
delete static_cast<CIMListenerRep*>(_rep); |
|
_rep=NULL; |
|
} |
|
|
|
Uint32 CIMListener::getPortNumber() const |
|
{ |
|
return static_cast<CIMListenerRep*>(_rep)->getPortNumber(); |
|
} |
| |
return (_acceptor->getOutstandingRequestCount()); |
SSLContext* CIMListener::getSSLContext() const |
|
{ |
|
return static_cast<CIMListenerRep*>(_rep)->getSSLContext(); |
|
} |
|
void CIMListener::setSSLContext(SSLContext* sslContext) |
|
{ |
|
static_cast<CIMListenerRep*>(_rep)->setSSLContext(sslContext); |
|
} |
|
void CIMListener::start() |
|
{ |
|
static_cast<CIMListenerRep*>(_rep)->start(); |
|
} |
|
void CIMListener::stop() |
|
{ |
|
static_cast<CIMListenerRep*>(_rep)->stop(); |
|
} |
|
|
|
Boolean CIMListener::isAlive() |
|
{ |
|
return static_cast<CIMListenerRep*>(_rep)->isAlive(); |
|
} |
|
|
|
Boolean CIMListener::addConsumer(CIMIndicationConsumer* consumer) |
|
{ |
|
return static_cast<CIMListenerRep*>(_rep)->addConsumer(consumer); |
|
} |
|
Boolean CIMListener::removeConsumer(CIMIndicationConsumer* consumer) |
|
{ |
|
return static_cast<CIMListenerRep*>(_rep)->removeConsumer(consumer); |
} | } |
| |
PEGASUS_NAMESPACE_END | PEGASUS_NAMESPACE_END |