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