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