1 martin 1.22 //%LICENSE////////////////////////////////////////////////////////////////
|
2 martin 1.23 //
|
3 martin 1.22 // Licensed to The Open Group (TOG) under one or more contributor license
4 // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with
5 // this work for additional information regarding copyright ownership.
6 // Each contributor licenses this file to you under the OpenPegasus Open
7 // Source License; you may not use this file except in compliance with the
8 // License.
|
9 martin 1.23 //
|
10 martin 1.22 // Permission is hereby granted, free of charge, to any person obtaining a
11 // copy of this software and associated documentation files (the "Software"),
12 // to deal in the Software without restriction, including without limitation
13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 // and/or sell copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following conditions:
|
16 martin 1.23 //
|
17 martin 1.22 // The above copyright notice and this permission notice shall be included
18 // in all copies or substantial portions of the Software.
|
19 martin 1.23 //
|
20 martin 1.22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
21 martin 1.23 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
22 martin 1.22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
27 martin 1.23 //
|
28 martin 1.22 //////////////////////////////////////////////////////////////////////////
|
29 h.sterling 1.1 //
30 //%/////////////////////////////////////////////////////////////////////////////
31
32 #include <Pegasus/Common/Config.h>
33 #include <Pegasus/Common/System.h>
|
34 kumpf 1.16 #include <Pegasus/Common/Time.h>
|
35 h.sterling 1.1
36 #include "ListenerService.h"
37
38 PEGASUS_NAMESPACE_BEGIN
39 PEGASUS_USING_STD;
40
41 static const int SHUTDOWN_TIMEOUT = 10; //seconds
42
|
43 kumpf 1.24 ListenerService::ListenerService(ConsumerManager* consumerManager) :
|
44 h.sterling 1.1 _consumerManager(consumerManager),
45 _dispatcher(0),
46 _portNumber(0),
47 _useSSL(false),
48 _sslContext(0),
49 _initialized(0),
50 _running(0),
51 _dieNow(0),
52 _shutdownSem(0),
53 _monitor(0),
|
54 venkat.puvvada 1.19 _ip6Acceptor(NULL),
55 _ip4Acceptor(NULL),
|
56 h.sterling 1.1 _responseEncoder(0),
57 _requestDecoder(0),
58 _listening_thread(0),
59 _polling_thread(0)
60 {
61 PEG_METHOD_ENTER(TRC_LISTENER, "ListenerService::ListenerService");
62
63
64 PEG_METHOD_EXIT();
65 }
66
67 ListenerService::~ListenerService()
68 {
69 PEG_METHOD_ENTER(TRC_LISTENER, "ListenerService::ListenerService");
70
71 if (_running)
72 {
73 shutdownListener();
74 }
75
76 if (_initialized)
77 h.sterling 1.1 {
78 //cleanup everything we initialized
79
|
80 kumpf 1.12 delete _sslContext;
|
81 h.sterling 1.1
|
82 kumpf 1.12 delete _dispatcher;
|
83 h.sterling 1.1
|
84 kumpf 1.12 delete _responseEncoder;
|
85 h.sterling 1.1
|
86 kumpf 1.12 delete _requestDecoder;
|
87 h.sterling 1.1
|
88 kumpf 1.12 delete _shutdownSem;
|
89 kumpf 1.24
|
90 h.sterling 1.1 //do not delete _consumerManager
91 //it is deleted by CIMListener
92 }
93
94 PEG_METHOD_EXIT();
95 }
96
97 ListenerService::ListenerService(const ListenerService& x)
98 {
99 }
100
|
101 kumpf 1.24 Boolean ListenerService::initializeListener(Uint32 portNumber,
|
102 venkat.puvvada 1.19 Boolean useSSL, SSLContext* sslContext)
|
103 h.sterling 1.1 {
104 PEG_METHOD_ENTER(TRC_LISTENER, "ListenerService::initializeListener");
105
106 if (_initialized)
107 {
|
108 venkat.puvvada 1.19 PEG_TRACE_CSTRING(TRC_LISTENER, Tracer::LEVEL2,
109 "Warning: The listener is already initialized.");
|
110 h.sterling 1.1 return true;
111 }
112
113 _portNumber = portNumber;
114 _useSSL = useSSL;
115 _sslContext = sslContext;
116
|
117 carson.hovey 1.2 if (_useSSL && (_sslContext == NULL))
|
118 h.sterling 1.1 {
|
119 venkat.puvvada 1.19 throw Exception(MessageLoaderParms(
120 "DynListener.ListenerService.INVALID_SSL_CONFIGURATION",
121 "Invalid SSL configuration: No SSLContext was specified."));
|
122 h.sterling 1.1 }
123
124 if (!_useSSL && _sslContext)
125 {
|
126 venkat.puvvada 1.19 PEG_TRACE_CSTRING(TRC_LISTENER, Tracer::LEVEL2,
127 "Warning: An SSLContext was specified for a non-SSL configuration.");
|
128 h.sterling 1.1 }
129
130 _dispatcher = new DynamicListenerIndicationDispatcher(_consumerManager);
131
132 _responseEncoder = new CIMExportResponseEncoder();
133
134 _requestDecoder = new CIMExportRequestDecoder(_dispatcher,
|
135 venkat.puvvada 1.19 _responseEncoder->getQueueId());
|
136 h.sterling 1.1
137 _shutdownSem = new Semaphore(0);
138
139 _initialized = true;
140
141 PEG_METHOD_EXIT();
142 return true;
143 }
144
145 Boolean ListenerService::runListener()
146 {
147 PEG_METHOD_ENTER(TRC_LISTENER, "ListenerService::runListener");
148
149 if (!_initialized)
150 {
|
151 venkat.puvvada 1.19 throw Exception(MessageLoaderParms(
152 "DynListener.ListenerService.NOT_INITIALIZED",
153 "Error: You must initialize the listener prior to running it."));
|
154 h.sterling 1.1 }
155
156 if (_running)
157 {
|
158 venkat.puvvada 1.19 throw Exception(MessageLoaderParms(
159 "DynListener.ListenerService.ALREADY_RUNNING",
160 "Error: The listener is already running."));
|
161 h.sterling 1.1 }
|
162 kumpf 1.24
|
163 h.sterling 1.1 _monitor = new Monitor();
164
|
165 dave.sudlik 1.18 #ifdef PEGASUS_ENABLE_IPV6
|
166 venkat.puvvada 1.19 if (System::isIPv6StackActive())
167 {
168 _ip6Acceptor = new HTTPAcceptor(
|
169 kumpf 1.24 _monitor,
170 _requestDecoder,
|
171 dave.sudlik 1.18 HTTPAcceptor::IPV6_CONNECTION,
|
172 kumpf 1.24 _portNumber,
|
173 h.sterling 1.1 _sslContext,
174 false);
|
175 venkat.puvvada 1.19 }
176 #ifndef PEGASUS_OS_TYPE_WINDOWS
177 else
178 #endif
|
179 dave.sudlik 1.18 #endif
|
180 venkat.puvvada 1.19 {
181 _ip4Acceptor = new HTTPAcceptor(
|
182 kumpf 1.24 _monitor,
183 _requestDecoder,
184 HTTPAcceptor::IPV4_CONNECTION,
185 _portNumber,
|
186 dave.sudlik 1.18 _sslContext,
187 false);
|
188 venkat.puvvada 1.19 }
|
189 h.sterling 1.1
190 //create listening thread
191 _listening_thread = new Thread(_listener_routine, this, 0);
192
193 //bind listener socket
|
194 venkat.puvvada 1.19 if (_ip6Acceptor)
195 {
196 _ip6Acceptor->bind();
197 }
198 if (_ip4Acceptor)
|
199 kumpf 1.24 {
|
200 venkat.puvvada 1.19 _ip4Acceptor->bind();
201 }
|
202 h.sterling 1.1
203 //start listening thread
|
204 konrad.r 1.9 ThreadStatus rtn = PEGASUS_THREAD_OK;
205 while ( (rtn = _listening_thread->run()) != PEGASUS_THREAD_OK)
|
206 h.sterling 1.1 {
|
207 venkat.puvvada 1.19 if (rtn == PEGASUS_THREAD_INSUFFICIENT_RESOURCES)
208 Threads::yield();
209 else {
|
210 kumpf 1.24 // We need to set _running to true so that we can shutdown the
|
211 venkat.puvvada 1.19 // rest of the classes
212 delete _listening_thread; _listening_thread = 0;
213 _running = true;
|
214 kumpf 1.24 shutdownListener();
|
215 venkat.puvvada 1.19 throw Exception(MessageLoaderParms(
216 "DynListener.ListenerService.CANNOT_ALLOCATE_THREAD",
217 "Error: Cannot allocate thread."));
218 }
|
219 kumpf 1.24
|
220 h.sterling 1.1 }
|
221 kumpf 1.24
|
222 h.sterling 1.1 if (_consumerManager->getEnableConsumerUnload())
223 {
224 //create polling thread
225 _polling_thread = new Thread(_polling_routine , this, 0);
|
226 kumpf 1.24
|
227 h.sterling 1.1 //start polling thread
|
228 konrad.r 1.9 while ( (rtn=_polling_thread->run()) != PEGASUS_THREAD_OK)
|
229 h.sterling 1.1 {
|
230 venkat.puvvada 1.19 if (rtn == PEGASUS_THREAD_INSUFFICIENT_RESOURCES)
231 Threads::yield();
232 else
233 {
234 /* We should delete them the objects, but there is a question
|
235 konrad.r 1.9 of how to turn of the _listening_thread? */
|
236 venkat.puvvada 1.19 delete _polling_thread; _polling_thread = 0;
237 _running = true;
|
238 kumpf 1.24 shutdownListener();
|
239 venkat.puvvada 1.19 throw Exception(MessageLoaderParms(
240 "DynListener.ListenerService.CANNOT_ALLOCATE_THREAD",
241 "Error: Cannot allocate thread."));
242 }
|
243 h.sterling 1.1 }
244 }
245
246 _running = true;
247
248 PEG_METHOD_EXIT();
249 return true;
250 }
251
|
252 kumpf 1.24 ThreadReturnType PEGASUS_THREAD_CDECL
|
253 venkat.puvvada 1.19 ListenerService::_listener_routine(void *param)
|
254 h.sterling 1.1 {
255 PEG_METHOD_ENTER(TRC_LISTENER, "ListenerService::_listener_routine");
256
257 Thread *myself = reinterpret_cast<Thread *>(param);
|
258 kumpf 1.24 ListenerService* listenerService =
|
259 venkat.puvvada 1.19 reinterpret_cast<ListenerService*>(myself->get_parm());
|
260 h.sterling 1.1
|
261 kumpf 1.15 while (!(listenerService->_dieNow))
|
262 h.sterling 1.1 {
|
263 kumpf 1.15 listenerService->_monitor->run(30000);
264 static struct timeval lastIdleCleanupTime = {0, 0};
265 struct timeval now;
|
266 kumpf 1.16 Time::gettimeofday(&now);
|
267 kumpf 1.15 if (now.tv_sec - lastIdleCleanupTime.tv_sec > 300)
268 {
269 lastIdleCleanupTime.tv_sec = now.tv_sec;
|
270 kumpf 1.24 try
|
271 kumpf 1.15 {
272 MessageQueueService::get_thread_pool()->cleanupIdleThreads();
273 }
274 catch(...)
275 {
276 }
277 }
278 }
279
|
280 kumpf 1.24 PEG_TRACE_CSTRING(TRC_LISTENER,
|
281 kumpf 1.15 Tracer::LEVEL4,
282 "ListenerService::Stopping _listener_routine");
|
283 h.sterling 1.1 PEG_METHOD_EXIT();
284 return 0; //success
285 }
286
287
|
288 kumpf 1.24 ThreadReturnType PEGASUS_THREAD_CDECL
|
289 venkat.puvvada 1.19 ListenerService::_polling_routine(void *param)
|
290 h.sterling 1.1 {
291 PEG_METHOD_ENTER(TRC_LISTENER, "ListenerService::_polling_routine");
292
293 Thread *myself = reinterpret_cast<Thread *>(param);
|
294 venkat.puvvada 1.19 ListenerService* listenerService =
295 reinterpret_cast<ListenerService*>(myself->get_parm());
|
296 h.sterling 1.1
297 while (true)
298 {
|
299 kumpf 1.21 //do a timed wait so we do can process a shutdown signal immediately
300 if (listenerService->_shutdownSem->time_wait(
301 listenerService->_consumerManager->getIdleTimeout()))
|
302 h.sterling 1.1 {
303 if (listenerService->_dieNow)
304 {
305 //shutdown
306 break;
307 }
|
308 venkat.puvvada 1.19 }
|
309 kumpf 1.21 else
|
310 h.sterling 1.1 {
311 //time to check for idle consumers
|
312 venkat.puvvada 1.19 PEG_TRACE_CSTRING(TRC_LISTENER, Tracer::LEVEL3,
313 "Unloading idle consumers");
|
314 h.sterling 1.1 listenerService->_consumerManager->unloadIdleConsumers();
315 }
316 }
317
318 PEG_METHOD_EXIT();
319 return 0; //success
320 }
321
322 Boolean ListenerService::shutdownListener()
323 {
324 PEG_METHOD_ENTER(TRC_LISTENER, "ListenerService::shutdownListener");
325
326 if (!_running)
327 {
|
328 marek 1.20 PEG_TRACE_CSTRING(TRC_LISTENER, Tracer::LEVEL2,
|
329 venkat.puvvada 1.19 "Warning: The listener is not currently running.");
|
330 h.sterling 1.1
331 return true;
332 }
333
334 Boolean gracefulShutdown = true;
335
336 //stop the monitor from accepting connections
337 _monitor->stopListeningForConnections(true);
338
|
339 venkat.puvvada 1.19 if (_ip6Acceptor)
340 {
341 _ip6Acceptor->closeConnectionSocket();
342 }
343 if (_ip4Acceptor)
344 {
345 _ip4Acceptor->closeConnectionSocket();
346 }
|
347 h.sterling 1.1
348 //allow client threads to complete, wait 10 sec max
|
349 venkat.puvvada 1.19 PEG_TRACE_CSTRING(TRC_LISTENER, Tracer::LEVEL4,
350 "ListenerService::Waiting for outstanding requests...");
|
351 h.sterling 1.1 Uint32 reqCount;
352 Uint32 countDown = SHUTDOWN_TIMEOUT;
353 for (; countDown > 0; countDown--)
354 {
|
355 dave.sudlik 1.18 reqCount = 0;
|
356 venkat.puvvada 1.19 if (_ip6Acceptor)
357 {
358 reqCount = _ip6Acceptor->getOutstandingRequestCount();
359 }
360 if (_ip4Acceptor)
361 {
362 reqCount += _ip4Acceptor->getOutstandingRequestCount();
363 }
|
364 h.sterling 1.1 if (reqCount > 0)
365 {
|
366 mike 1.13 Threads::sleep(1000);
|
367 h.sterling 1.1 } else
368 {
369 break;
370 }
371 }
372
|
373 venkat.puvvada 1.19 PEG_TRACE_CSTRING(TRC_LISTENER, Tracer::LEVEL4,
374 "ListenerService::Finished waiting for outstanding requests.");
|
375 h.sterling 1.1
376 if (reqCount > 0)
377 {
|
378 venkat.puvvada 1.19 PEG_TRACE_CSTRING(TRC_LISTENER, Tracer::LEVEL2,
379 "ListenerService::Did not successfully process"
380 " all incoming requests to the acceptor.");
|
381 h.sterling 1.1 gracefulShutdown = false;
382 }
383
384 //stop the monitor thread and idle thread
385 _dieNow = true;
386
387 //ATTN: This is ghetto and needs to be fixed
388 //signal twice, once for polling thread, once for listener thread
389 //have to signal before both join calls so we do not hit a deadlock
390 _shutdownSem->signal();
391 _shutdownSem->signal();
392
393 _monitor->tickle();
394
395 //stop listener thread
396 try
397 {
398 _listening_thread->join();
399 delete _listening_thread;
400 _listening_thread = 0;
401
|
402 venkat.puvvada 1.19 }
403 catch (...)
|
404 h.sterling 1.1 {
|
405 venkat.puvvada 1.19 PEG_TRACE_CSTRING(TRC_LISTENER, Tracer::LEVEL2,
406 "Did not successfully stop monitor thread");
|
407 h.sterling 1.1 gracefulShutdown = false;
408 }
409
410 //stop polling thread
411 if (_polling_thread) //may not be started if polling is disabled
412 {
413 try
414 {
415 _polling_thread->join();
416 delete _polling_thread;
417 _polling_thread = 0;
418
|
419 venkat.puvvada 1.19 }
420 catch (...)
|
421 h.sterling 1.1 {
|
422 venkat.puvvada 1.19 PEG_TRACE_CSTRING(TRC_LISTENER, Tracer::LEVEL2,
423 "Did not successfully stop polling thread");
|
424 h.sterling 1.1 gracefulShutdown = false;
425 }
426 }
|
427 h.sterling 1.8 //delete acceptor
|
428 dave.sudlik 1.18 delete _ip6Acceptor;
429 _ip6Acceptor = 0;
430 delete _ip4Acceptor;
431 _ip4Acceptor = 0;
|
432 h.sterling 1.8
|
433 h.sterling 1.1 //delete monitor
434 delete _monitor;
435 _monitor = 0;
436
|
437 marek 1.17 PEG_TRACE_CSTRING(TRC_LISTENER, Tracer::LEVEL2, "Listener stopped.");
|
438 h.sterling 1.1
439 //reset status values
440 _running = false;
441 _dieNow = false;
442
|
443 venkat.puvvada 1.19 if (gracefulShutdown)
444 {
|
445 marek 1.20 PEG_TRACE_CSTRING(TRC_LISTENER, Tracer::LEVEL3,
|
446 venkat.puvvada 1.19 "Listener shutdown gracefully");
|
447 kumpf 1.24 }
|
448 h.sterling 1.1
449 PEG_METHOD_EXIT();
450 return(gracefulShutdown);
451 }
452
|
453 aruran.ms 1.7 Boolean ListenerService::isAlive() const throw()
|
454 h.sterling 1.1 {
455 return _running;
456 }
457
458 //ATTN: Methods for old CIMListener interface...do we need them now?
459 Uint32 ListenerService::getPortNumber() const
460 {
461 return _portNumber;
462 }
463
464
465 PEGASUS_NAMESPACE_END
|