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