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