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
|