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

  1 karl  1.28 //%2005////////////////////////////////////////////////////////////////////////
  2 kumpf 1.1  //
  3 karl  1.25 // 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 karl  1.12 // IBM Corp.; EMC Corporation, The Open Group.
  7 karl  1.25 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
  8            // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
  9 karl  1.28 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
 10            // EMC Corporation; VERITAS Software Corporation; The Open Group.
 11 kumpf 1.1  //
 12            // Permission is hereby granted, free of charge, to any person obtaining a copy
 13            // of this software and associated documentation files (the "Software"), to
 14            // deal in the Software without restriction, including without limitation the
 15            // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 16            // sell copies of the Software, and to permit persons to whom the Software is
 17            // furnished to do so, subject to the following conditions:
 18 kumpf 1.3  // 
 19 kumpf 1.1  // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
 20            // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
 21            // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 22            // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 23            // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 24            // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 25            // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 26            // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 27            //
 28            //==============================================================================
 29            //
 30 tony  1.8  // Author: Dong Xiang, EMC Corporation (xiang_dong@emc.com)
 31 kumpf 1.1  //
 32 dj.gorey 1.14 // Modified By:   Dan Gorey (djgorey@us.ibm.com)
 33 a.arora  1.21 //                Amit K Arora, IBM (amita@in.ibm.com) for PEP#183
 34 kumpf    1.26 //                Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
 35 kumpf    1.1  //
 36               //%/////////////////////////////////////////////////////////////////////////////
 37               
 38 tony     1.8  #include "CIMListener.h"
 39 kumpf    1.1  
 40 tony     1.8  #include <Pegasus/Common/Exception.h>
 41               #include <Pegasus/Common/SSLContext.h>
 42               #include <Pegasus/Common/Monitor.h>
 43 kumpf    1.1  #include <Pegasus/Common/HTTPAcceptor.h>
 44 kumpf    1.11 #include <Pegasus/Common/PegasusVersion.h>
 45 kumpf    1.2  
 46 kumpf    1.1  #include <Pegasus/ExportServer/CIMExportResponseEncoder.h>
 47               #include <Pegasus/ExportServer/CIMExportRequestDecoder.h>
 48               
 49 tony     1.8  #include <Pegasus/Consumer/CIMIndicationConsumer.h>
 50               #include <Pegasus/Listener/CIMListenerIndicationDispatcher.h>
 51               
 52               PEGASUS_NAMESPACE_BEGIN
 53               /////////////////////////////////////////////////////////////////////////////
 54               // CIMListenerService
 55               /////////////////////////////////////////////////////////////////////////////
 56               class CIMListenerService
 57               {
 58               public:
 59               	CIMListenerService(Uint32 portNumber, SSLContext* sslContext=NULL);
 60               	CIMListenerService(CIMListenerService& svc);
 61                 ~CIMListenerService();
 62               
 63               	void				init();
 64               	/** bind to the port
 65               	*/
 66               	void				bind();
 67               	/** runForever Main runloop for the server.
 68               	*/
 69               	void runForever();
 70 tony     1.8  	
 71               	/** Call to gracefully shutdown the server.  The server connection socket
 72               	will be closed to disable new connections from clients.
 73               	*/
 74               	void stopClientConnection();
 75               	
 76               	/** Call to gracefully shutdown the server.  It is called when the server
 77               	has been stopped and is ready to be shutdown.  Next time runForever()
 78               	is called, the server shuts down.
 79               	*/
 80               	void shutdown();
 81               	
 82               	/** Return true if the server has shutdown, false otherwise.
 83               	*/
 84               	Boolean terminated() { return _dieNow; };
 85               	
 86               	/** Call to resume the sever.
 87               	*/
 88               	void resume();
 89               	
 90               	/** Call to set the CIMServer state.  Also inform the appropriate
 91 tony     1.8  	message queues about the current state of the CIMServer.
 92               	*/
 93               	void setState(Uint32 state);
 94               	
 95               	Uint32 getOutstandingRequestCount();
 96               
 97               	/** Returns the indication listener dispatcher
 98               	 */
 99               	CIMListenerIndicationDispatcher* getIndicationDispatcher() const;
100               
101                 /** Returns the indication listener dispatcher
102               	 */
103               	void setIndicationDispatcher(CIMListenerIndicationDispatcher* dispatcher);
104               
105               	static PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL _listener_routine(void *param);
106               
107               private:
108               	Uint32			_portNumber;
109               	SSLContext* _sslContext;
110               	Monitor*				_monitor;
111                 HTTPAcceptor*   _acceptor;
112 dj.gorey 1.14 
113                 Boolean					_dieNow;
114 tony     1.8  
115                 CIMListenerIndicationDispatcher* _dispatcher;
116               
117                 CIMExportResponseEncoder* _responseEncoder;
118                 CIMExportRequestDecoder*  _requestDecoder;
119               
120               };
121               
122               CIMListenerService::CIMListenerService(Uint32 portNumber, SSLContext* sslContext)
123               :_portNumber(portNumber)
124               ,_sslContext(sslContext)
125               ,_monitor(NULL)
126               ,_acceptor(NULL)
127               ,_dieNow(false)
128               ,_dispatcher(NULL)
129               ,_responseEncoder(NULL)
130               ,_requestDecoder(NULL)
131               {
132               }
133               
134               CIMListenerService::CIMListenerService(CIMListenerService& svc)
135 tony     1.8  :_portNumber(svc._portNumber)
136               ,_sslContext(svc._sslContext)
137               ,_monitor(NULL)
138               ,_acceptor(NULL)
139               ,_dieNow(svc._dieNow)
140               ,_dispatcher(NULL)
141               ,_responseEncoder(NULL)
142               ,_requestDecoder(NULL)
143               {
144               }
145               CIMListenerService::~CIMListenerService()
146               {
147               	// if port is alive, clean up the port
148               	//if(_sslContext!=NULL)
149               	//	delete _sslContext;
150               
151               	if(_responseEncoder!=NULL)
152               		delete _responseEncoder;
153               
154               	if(_requestDecoder!=NULL)
155               		delete _requestDecoder;
156 kumpf    1.1  
157 tony     1.8  	//if(_dispatcher!=NULL)
158               	//	delete _dispatcher;
159 kumpf    1.1  
160 tony     1.8  	if(_monitor!=NULL)
161               		delete _monitor;
162 kumpf    1.1  
163 tony     1.8  	if(_acceptor!=NULL)
164               		delete _acceptor;
165               }
166 kumpf    1.1  
167 tony     1.8  void CIMListenerService::init()
168 kumpf    1.1  {
169 tony     1.8  	PEG_METHOD_ENTER(TRC_LISTENER, "CIMListenerService::init");
170 kumpf    1.1  
171 kumpf    1.27   _monitor = new Monitor();
172 dj.gorey 1.14   
173 tony     1.8  	//_dispatcher = new CIMListenerIndicationDispatcher();
174 kumpf    1.1  
175 chuck    1.20   _responseEncoder = new CIMExportResponseEncoder();
176 tony     1.8    _requestDecoder = new CIMExportRequestDecoder(
177               		_dispatcher,
178               		_responseEncoder->getQueueId());
179               
180 dj.gorey 1.14   _acceptor = new HTTPAcceptor(
181 tony     1.8  		 _monitor, 
182               		 _requestDecoder, 
183               		 false, 
184               		 _portNumber, 
185 kumpf    1.19 		 _sslContext,
186                                false);
187 kumpf    1.1  
188 chuck    1.20   bind();
189 kumpf    1.1  
190 chuck    1.20   PEG_METHOD_EXIT();
191 tony     1.8  }
192               void CIMListenerService::bind()
193               {
194 chuck    1.20   if(_acceptor!=NULL)
195                   { // Bind to the port
196                     _acceptor->bind();
197 tony     1.8  
198 chuck    1.20       PEGASUS_STD(cout) << "Listening on HTTP port " << _portNumber << PEGASUS_STD(endl);
199 tony     1.8  		
200 chuck    1.20       //listener.addAcceptor(false, portNumberHttp, false);
201                     Logger::put(Logger::STANDARD_LOG, System::CIMLISTENER, Logger::INFORMATION,
202 tony     1.8                          "Listening on HTTP port $0.", _portNumber);
203 kumpf    1.1  
204 chuck    1.20     }
205 tony     1.8  }
206 chuck    1.20 
207 tony     1.8  void CIMListenerService::runForever()
208               {
209 chuck    1.20   static int modulator = 0;
210 kumpf    1.1  
211 chuck    1.20   if(!_dieNow)
212 dj.gorey 1.14     {
213 a.arora  1.21       if(false == _monitor->run(500000)) 
214 chuck    1.20 	{	
215               	  modulator++;
216 a.arora  1.21       try 
217                     {
218               	     //MessageQueueService::_check_idle_flag = 1;
219               		 //MessageQueueService::_polling_sem.signal();
220               		 MessageQueueService::get_thread_pool()->kill_idle_threads();
221                     }
222               	  catch(...)
223                     {
224                     }
225 chuck    1.20 	}
226               /*
227                     if (handleShutdownSignal)
228                     {
229                       Tracer::trace(TRC_SERVER, Tracer::LEVEL3,
230               	"CIMServer::runForever - signal received.  Shutting down.");
231               
232               	ShutdownService::getInstance(this)->shutdown(true, 10, false);
233               	handleShutdownSignal = false;
234                     }
235 tony     1.8  */
236 chuck    1.20     }
237 tony     1.8  }
238 kumpf    1.1  
239 tony     1.8  void CIMListenerService::shutdown()
240               {
241                   PEG_METHOD_ENTER(TRC_LISTENER, "CIMListenerService::shutdown()");
242 kumpf    1.1  
243 tony     1.8      _dieNow = true;
244 a.arora  1.21     _monitor->tickle();
245 kumpf    1.1  
246 kumpf    1.4      PEG_METHOD_EXIT();
247 kumpf    1.1  }
248               
249 tony     1.8  void CIMListenerService::resume()
250 kumpf    1.1  {
251 tony     1.8      PEG_METHOD_ENTER(TRC_LISTENER, "CIMListenerService::resume()");
252 kumpf    1.1  
253 tony     1.8      if(_acceptor!=NULL)
254                       _acceptor->reopenConnectionSocket();
255 kumpf    1.1  
256 kumpf    1.4      PEG_METHOD_EXIT();
257 kumpf    1.1  }
258               
259 tony     1.8  void CIMListenerService::stopClientConnection()
260 kumpf    1.1  {
261 tony     1.8      PEG_METHOD_ENTER(TRC_LISTENER, "CIMListenerService::stopClientConnection()");
262 kumpf    1.1  
263 kumpf    1.10     // tell Monitor to stop listening for client connections
264 chuck    1.22     _monitor->stopListeningForConnections(true);
265 kumpf    1.10 
266                   //
267                   // Wait 150 milliseconds to allow time for the Monitor to stop
268                   // listening for client connections.
269                   //
270                   // This wait time is the timeout value for the select() call
271                   // in the Monitor's run() method (currently set to 100
272                   // milliseconds) plus a delta of 50 milliseconds.  The reason
273                   // for the wait here is to make sure that the Monitor entries
274                   // are updated before closing the connection sockets.
275                   //
276 a.arora  1.21     // pegasus_sleep(150); Not needed now due to the semaphore in the Monitor
277                   
278 tony     1.8      if(_acceptor!=NULL)
279                   _acceptor->closeConnectionSocket();
280 kumpf    1.1  
281 kumpf    1.4      PEG_METHOD_EXIT();
282 kumpf    1.1  }
283               
284 chuck    1.23 Uint32 CIMListenerService::getOutstandingRequestCount()
285               {
286                   return _acceptor->getOutstandingRequestCount();
287               }
288 tony     1.8  
289               CIMListenerIndicationDispatcher* CIMListenerService::getIndicationDispatcher() const
290 kumpf    1.1  {
291 tony     1.8  	return _dispatcher;
292               }
293               void CIMListenerService::setIndicationDispatcher(CIMListenerIndicationDispatcher* dispatcher)
294               {
295               	_dispatcher = dispatcher;
296 kumpf    1.1  }
297               
298 tony     1.8  PEGASUS_THREAD_RETURN PEGASUS_THREAD_CDECL CIMListenerService::_listener_routine(void *param)
299 kumpf    1.1  {
300 tony     1.8    CIMListenerService *svc = reinterpret_cast<CIMListenerService *>(param);
301 kumpf    1.1  
302 chuck    1.20   //svc->init(); bug 1394 
303                 while(!svc->terminated())
304                 {
305               #if defined(PEGASUS_PLATFORM_DARWIN_PPC_GNU)
306                   pthread_testcancel();
307               #endif
308                   svc->runForever();
309                 }
310 chuck    1.23 
311 chuck    1.20   delete svc;
312 tony     1.8  
313 chuck    1.20   return 0;
314 tony     1.8  }
315               static struct timeval create_time = {0, 1};
316               static struct timeval destroy_time = {15, 0};
317               static struct timeval deadlock_time = {0, 0};
318               
319               /////////////////////////////////////////////////////////////////////////////
320               // CIMListenerRep
321               /////////////////////////////////////////////////////////////////////////////
322               class CIMListenerRep
323               {
324               public:
325               	CIMListenerRep(Uint32 portNumber, SSLContext* sslContext=NULL);
326                 ~CIMListenerRep();
327               
328               	Uint32 getPortNumber() const;
329               
330               	SSLContext* getSSLContext() const;
331               	void setSSLContext(SSLContext* sslContext);
332               	
333               	void start();
334               	void stop();
335 tony     1.8  
336               	Boolean isAlive();
337               
338               	Boolean addConsumer(CIMIndicationConsumer* consumer);
339               	Boolean removeConsumer(CIMIndicationConsumer* consumer);
340               
341               private:
342 chuck    1.23   Boolean waitForPendingRequests(Uint32 shutdownTimeout);
343               
344                 Uint32 _portNumber;
345                 SSLContext* _sslContext;
346 tony     1.8  
347                 CIMListenerIndicationDispatcher* _dispatcher;
348 chuck    1.23   ThreadPool* _thread_pool;
349 chuck    1.20   CIMListenerService* _svc;  
350                 Semaphore *_listener_sem;
351 tony     1.8  };
352               
353               CIMListenerRep::CIMListenerRep(Uint32 portNumber, SSLContext* sslContext)
354               :_portNumber(portNumber)
355               ,_sslContext(sslContext)
356               ,_dispatcher(new CIMListenerIndicationDispatcher())
357               ,_thread_pool(NULL)
358 chuck    1.20 ,_svc(NULL)
359               ,_listener_sem(NULL)
360 tony     1.8  {
361               }
362               CIMListenerRep::~CIMListenerRep()
363               {
364 chuck    1.20   // if port is alive, clean up the port
365                 if (_thread_pool != NULL)
366                 {
367                   // Block incoming export requests and unbind the port
368                   _svc->stopClientConnection();
369 chuck    1.23 
370                   // Wait until pending export requests in the server are done.
371                   waitForPendingRequests(10);
372 chuck    1.20     
373                   // Shutdown the CIMListenerService
374                   _svc->shutdown();   
375                 }
376               
377                 if(_sslContext!=NULL)
378                   delete _sslContext;
379               
380                 if(_dispatcher!=NULL)
381                   delete _dispatcher;
382               
383                 if(_thread_pool!=NULL)
384                   delete _thread_pool;
385 tony     1.8  
386 chuck    1.20   if(_listener_sem!=NULL)
387                   delete _listener_sem;
388 tony     1.8  
389 chuck    1.20   // don't delete _svc, this is deleted by _listener_routine
390 tony     1.8  }
391               
392               Uint32 CIMListenerRep::getPortNumber() const
393               {
394               	return _portNumber;
395               }
396 kumpf    1.1  
397 tony     1.8  SSLContext* CIMListenerRep::getSSLContext() const
398               {
399               	return _sslContext;
400 kumpf    1.1  }
401 tony     1.8  void CIMListenerRep::setSSLContext(SSLContext* sslContext)
402               {
403               	if(_sslContext!=NULL)
404               		delete _sslContext;
405 kumpf    1.1  
406 tony     1.8  	_sslContext = sslContext;
407               }
408               void CIMListenerRep::start()
409 kumpf    1.1  {
410 chuck    1.20   // spawn a thread to do this
411                 if(_thread_pool==NULL)
412                 {
413                   CIMListenerService* svc = new CIMListenerService(_portNumber,_sslContext);
414                   try
415                   {
416                     // Try to initialize the service (bug 1394)
417                     svc->setIndicationDispatcher(_dispatcher);
418                     svc->init(); 
419                   }
420                   catch(...)
421                   {
422                     // Error. Exit without creating the ThreadPool, so that this listener
423                     // is not 'alive'
424                     delete svc;
425                     throw;
426                   }
427               
428                   _thread_pool = new ThreadPool(0, "Listener", 0, 1, 
429               				  create_time, destroy_time, deadlock_time);
430               
431 chuck    1.20     _listener_sem = new Semaphore(0);
432                   _thread_pool->allocate_and_awaken(svc,
433               				      CIMListenerService::_listener_routine,
434               				      _listener_sem);
435               
436                   _svc = svc;
437               
438                   Logger::put(Logger::STANDARD_LOG,System::CIMLISTENER,
439               		Logger::INFORMATION,
440               		"CIMListener started");
441 chuck    1.17 
442 chuck    1.20     PEGASUS_STD(cerr) << "CIMlistener started" << PEGASUS_STD(endl);
443                 }
444 tony     1.8  }
445 kumpf    1.1  
446 tony     1.8  void CIMListenerRep::stop()
447               {
448 chuck    1.20   if(_thread_pool!=NULL)
449                 { 
450                   //
451                   // Graceful shutdown of the listener service
452                   //
453               
454                   // Block incoming export requests and unbind the port
455                   _svc->stopClientConnection();
456 chuck    1.23 
457                   // Wait until pending export requests in the server are done.
458 chuck    1.24     waitForPendingRequests(10);
459 chuck    1.23    
460 chuck    1.20     // Shutdown the CIMListenerService
461                   _svc->shutdown();
462               
463                   // Wait for the _listener_routine thread to exit.
464                   // The thread could be delivering an export, so give it 3sec.
465                   // Note that _listener_routine deletes the CIMListenerService,
466                   // so no need to delete _svc.
467                   try
468                   {
469                     _listener_sem->time_wait(3000); 
470                   }
471                   catch (TimeOut &)
472                   {
473                     // No need to do anything, the thread pool will be deleted below
474                     // to cancel the _listener_routine thread if it is still running.
475                   }
476               
477                   delete _listener_sem;
478                   _listener_sem = NULL;
479                   
480                   // Delete the thread pool.  This cancels the listener thread if it is still
481 chuck    1.20     // running.
482                   delete _thread_pool;
483                   _thread_pool = NULL;
484               
485                   Logger::put(Logger::STANDARD_LOG,System::CIMLISTENER,
486               		Logger::INFORMATION,
487               		"CIMListener stopped");
488                 }
489 kumpf    1.1  }
490               
491 tony     1.8  Boolean CIMListenerRep::isAlive()
492 kumpf    1.1  {
493 tony     1.8  	return (_thread_pool!=NULL)?true:false;
494               }
495 kumpf    1.1  
496 tony     1.8  Boolean CIMListenerRep::addConsumer(CIMIndicationConsumer* consumer)
497               {
498               	return _dispatcher->addConsumer(consumer);
499               }
500               Boolean CIMListenerRep::removeConsumer(CIMIndicationConsumer* consumer)
501               {
502               	return _dispatcher->removeConsumer(consumer);
503               }
504 kumpf    1.1  
505 chuck    1.23 Boolean CIMListenerRep::waitForPendingRequests(Uint32 shutdownTimeout)
506               {
507                 // Wait for 10 sec max
508                 Uint32 reqCount;
509                 Uint32 countDown = shutdownTimeout * 10;
510                 for (; countDown > 0; countDown--)
511                 {
512                   reqCount = _svc->getOutstandingRequestCount();
513                   if (reqCount > 0)
514                     pegasus_sleep(100);
515                   else
516                     return true;
517                 }
518                 
519                 return false;
520               } 
521               
522 tony     1.8  /////////////////////////////////////////////////////////////////////////////
523               // CIMListener
524               /////////////////////////////////////////////////////////////////////////////
525               CIMListener::CIMListener(Uint32 portNumber, SSLContext* sslContext)
526               :_rep(new CIMListenerRep(portNumber,sslContext))
527               {
528               }
529               CIMListener::~CIMListener()
530               {
531               	if(_rep!=NULL)
532 tony     1.9  		delete static_cast<CIMListenerRep*>(_rep);
533 tony     1.8  	_rep=NULL;
534               }
535               	
536               Uint32 CIMListener::getPortNumber() const
537               {
538               	return static_cast<CIMListenerRep*>(_rep)->getPortNumber();
539 kumpf    1.1  }
540               
541 tony     1.8  SSLContext* CIMListener::getSSLContext() const
542               {
543               	return static_cast<CIMListenerRep*>(_rep)->getSSLContext();
544               }
545               void CIMListener::setSSLContext(SSLContext* sslContext)
546               {
547               	static_cast<CIMListenerRep*>(_rep)->setSSLContext(sslContext);
548               }
549               void CIMListener::start()
550 kumpf    1.1  {
551 tony     1.8  	static_cast<CIMListenerRep*>(_rep)->start();
552               }
553               void CIMListener::stop()
554               {
555               	static_cast<CIMListenerRep*>(_rep)->stop();
556               }
557 kumpf    1.1  
558 tony     1.8  Boolean CIMListener::isAlive()
559               {
560               	return static_cast<CIMListenerRep*>(_rep)->isAlive();
561               }
562 kumpf    1.1  
563 tony     1.8  Boolean CIMListener::addConsumer(CIMIndicationConsumer* consumer)
564               {
565               	return static_cast<CIMListenerRep*>(_rep)->addConsumer(consumer);
566               }
567               Boolean CIMListener::removeConsumer(CIMIndicationConsumer* consumer)
568               {
569               	return static_cast<CIMListenerRep*>(_rep)->removeConsumer(consumer);
570 kumpf    1.1  }
571               
572               PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2