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
|