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