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

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2