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 h.sterling 1.1 #include <Pegasus/Common/Config.h>
35 #include <Pegasus/Common/System.h>
|
36 kumpf 1.16 #include <Pegasus/Common/Time.h>
|
37 h.sterling 1.1
38 #include "ListenerService.h"
39
40 PEGASUS_NAMESPACE_BEGIN
41 PEGASUS_USING_STD;
42
43 static const int SHUTDOWN_TIMEOUT = 10; //seconds
44
45 ListenerService::ListenerService(ConsumerManager* consumerManager) :
46 _consumerManager(consumerManager),
47 _dispatcher(0),
48 _portNumber(0),
49 _useSSL(false),
50 _sslContext(0),
51 _initialized(0),
52 _running(0),
53 _dieNow(0),
54 _shutdownSem(0),
55 _monitor(0),
56 _acceptor(0),
57 _responseEncoder(0),
58 h.sterling 1.1 _requestDecoder(0),
59 _listening_thread(0),
60 _polling_thread(0)
61 {
62 PEG_METHOD_ENTER(TRC_LISTENER, "ListenerService::ListenerService");
63
64
65 PEG_METHOD_EXIT();
66 }
67
68 ListenerService::~ListenerService()
69 {
70 PEG_METHOD_ENTER(TRC_LISTENER, "ListenerService::ListenerService");
71
72 if (_running)
73 {
74 shutdownListener();
75 }
76
77 if (_initialized)
78 {
79 h.sterling 1.1 //cleanup everything we initialized
80
|
81 kumpf 1.12 delete _sslContext;
|
82 h.sterling 1.1
|
83 kumpf 1.12 delete _dispatcher;
|
84 h.sterling 1.1
|
85 kumpf 1.12 delete _responseEncoder;
|
86 h.sterling 1.1
|
87 kumpf 1.12 delete _requestDecoder;
|
88 h.sterling 1.1
|
89 kumpf 1.12 delete _shutdownSem;
|
90 h.sterling 1.1
91 //do not delete _consumerManager
92 //it is deleted by CIMListener
93 }
94
95 PEG_METHOD_EXIT();
96 }
97
98 ListenerService::ListenerService(const ListenerService& x)
99 {
100 }
101
102 Boolean ListenerService::initializeListener(Uint32 portNumber, Boolean useSSL, SSLContext* sslContext)
103 {
104 PEG_METHOD_ENTER(TRC_LISTENER, "ListenerService::initializeListener");
105
106 if (_initialized)
107 {
108 PEG_TRACE_STRING(TRC_LISTENER, Tracer::LEVEL2, "Warning: The listener is already initialized.");
109 return true;
110 }
111 h.sterling 1.1
112 _portNumber = portNumber;
113 _useSSL = useSSL;
114 _sslContext = sslContext;
115
|
116 carson.hovey 1.2 if (_useSSL && (_sslContext == NULL))
|
117 h.sterling 1.1 {
118 throw Exception(MessageLoaderParms("DynListener.ListenerService.INVALID_SSL_CONFIGURATION",
119 "Invalid SSL configuration: No SSLContext was specified."));
120 }
121
122 if (!_useSSL && _sslContext)
123 {
124 PEG_TRACE_STRING(TRC_LISTENER, Tracer::LEVEL2, "Warning: An SSLContext was specified for a non-SSL configuration.");
125 }
126
127 _dispatcher = new DynamicListenerIndicationDispatcher(_consumerManager);
128
129 _responseEncoder = new CIMExportResponseEncoder();
130
131 _requestDecoder = new CIMExportRequestDecoder(_dispatcher,
132 _responseEncoder->getQueueId());
133
134 _shutdownSem = new Semaphore(0);
135
136 _initialized = true;
137
138 h.sterling 1.1 PEG_METHOD_EXIT();
139 return true;
140 }
141
142 Boolean ListenerService::runListener()
143 {
144 PEG_METHOD_ENTER(TRC_LISTENER, "ListenerService::runListener");
145
146 if (!_initialized)
147 {
148 throw Exception(MessageLoaderParms("DynListener.ListenerService.NOT_INITIALIZED",
149 "Error: You must initialize the listener prior to running it."));
150 }
151
152 if (_running)
153 {
154 throw Exception(MessageLoaderParms("DynListener.ListenerService.ALREADY_RUNNING",
155 "Error: The listener is already running."));
156 }
157
158 _monitor = new Monitor();
159 h.sterling 1.1
160 _acceptor = new HTTPAcceptor(
161 _monitor,
162 _requestDecoder,
163 false,
164 _portNumber,
165 _sslContext,
166 false);
167
168 //create listening thread
169 _listening_thread = new Thread(_listener_routine, this, 0);
170
171 //bind listener socket
172 _acceptor->bind();
173
174 //start listening thread
|
175 konrad.r 1.9 ThreadStatus rtn = PEGASUS_THREAD_OK;
176 while ( (rtn = _listening_thread->run()) != PEGASUS_THREAD_OK)
|
177 h.sterling 1.1 {
|
178 konrad.r 1.9 if (rtn == PEGASUS_THREAD_INSUFFICIENT_RESOURCES)
|
179 mike 1.13 Threads::yield();
|
180 konrad.r 1.9 else {
181 // We need to set _running to true so that we can shutdown the
182 // rest of the classes
183 delete _listening_thread; _listening_thread = 0;
184 _running = true;
185 shutdownListener();
186 throw Exception(MessageLoaderParms("DynListener.ListenerService.CANNOT_ALLOCATE_THREAD",
187 "Error: Cannot allocate thread."));
188 }
189
|
190 h.sterling 1.1 }
191
192 if (_consumerManager->getEnableConsumerUnload())
193 {
194 //create polling thread
195 _polling_thread = new Thread(_polling_routine , this, 0);
196
197 //start polling thread
|
198 konrad.r 1.9 while ( (rtn=_polling_thread->run()) != PEGASUS_THREAD_OK)
|
199 h.sterling 1.1 {
|
200 konrad.r 1.9 if (rtn == PEGASUS_THREAD_INSUFFICIENT_RESOURCES)
|
201 mike 1.13 Threads::yield();
|
202 konrad.r 1.9 else
203 {
204 /* We should delete them the objects, but there is a question
205 of how to turn of the _listening_thread? */
206 delete _polling_thread; _polling_thread = 0;
207 _running = true;
208 shutdownListener();
209 throw Exception(MessageLoaderParms("DynListener.ListenerService.CANNOT_ALLOCATE_THREAD",
210 "Error: Cannot allocate thread."));
211 }
|
212 h.sterling 1.1 }
213 }
214
215 _running = true;
216
217 PEG_METHOD_EXIT();
218 return true;
219 }
220
|
221 mike 1.13 ThreadReturnType PEGASUS_THREAD_CDECL ListenerService::_listener_routine(void *param)
|
222 h.sterling 1.1 {
223 PEG_METHOD_ENTER(TRC_LISTENER, "ListenerService::_listener_routine");
224
225 Thread *myself = reinterpret_cast<Thread *>(param);
226 ListenerService* listenerService = reinterpret_cast<ListenerService*>(myself->get_parm());
227
|
228 kumpf 1.15 while (!(listenerService->_dieNow))
|
229 h.sterling 1.1 {
|
230 kumpf 1.15 listenerService->_monitor->run(30000);
231 static struct timeval lastIdleCleanupTime = {0, 0};
232 struct timeval now;
|
233 kumpf 1.16 Time::gettimeofday(&now);
|
234 kumpf 1.15 if (now.tv_sec - lastIdleCleanupTime.tv_sec > 300)
235 {
236 lastIdleCleanupTime.tv_sec = now.tv_sec;
237 try
238 {
239 MessageQueueService::get_thread_pool()->cleanupIdleThreads();
240 }
241 catch(...)
242 {
243 }
244 }
245 }
246
247 PEG_TRACE_STRING(TRC_LISTENER,
248 Tracer::LEVEL4,
249 "ListenerService::Stopping _listener_routine");
|
250 h.sterling 1.1 PEG_METHOD_EXIT();
251 return 0; //success
252 }
253
254
|
255 mike 1.13 ThreadReturnType PEGASUS_THREAD_CDECL ListenerService::_polling_routine(void *param)
|
256 h.sterling 1.1 {
257 PEG_METHOD_ENTER(TRC_LISTENER, "ListenerService::_polling_routine");
258
259 Thread *myself = reinterpret_cast<Thread *>(param);
260 ListenerService* listenerService = reinterpret_cast<ListenerService*>(myself->get_parm());
261
262 while (true)
263 {
264 try
265 {
266 //do a timed wait so we do can process a shutdown signal immediately
|
267 h.sterling 1.10 listenerService->_shutdownSem->time_wait(listenerService->_consumerManager->getIdleTimeout());
|
268 h.sterling 1.1
269 if (listenerService->_dieNow)
270 {
271 //shutdown
272 break;
273 }
274
|
275 kumpf 1.14 } catch (TimeOut&)
|
276 h.sterling 1.1 {
277 //time to check for idle consumers
278 PEG_TRACE_STRING(TRC_LISTENER, Tracer::LEVEL3, "Unloading idle consumers");
279 listenerService->_consumerManager->unloadIdleConsumers();
280 }
281 }
282
283 PEG_METHOD_EXIT();
284 return 0; //success
285 }
286
287 Boolean ListenerService::shutdownListener()
288 {
289 PEG_METHOD_ENTER(TRC_LISTENER, "ListenerService::shutdownListener");
290
291 if (!_running)
292 {
293 PEG_TRACE_STRING(TRC_LISTENER, Tracer::LEVEL4, "Warning: The listener is not currently running.");
294
295 return true;
296 }
297 h.sterling 1.1
298 Boolean gracefulShutdown = true;
299
300 //stop the monitor from accepting connections
301 _monitor->stopListeningForConnections(true);
302
303 _acceptor->closeConnectionSocket();
304
305 //allow client threads to complete, wait 10 sec max
306 PEG_TRACE_STRING(TRC_LISTENER, Tracer::LEVEL4, "ListenerService::Waiting for outstanding requests...");
307 Uint32 reqCount;
308 Uint32 countDown = SHUTDOWN_TIMEOUT;
309 for (; countDown > 0; countDown--)
310 {
311 reqCount = _acceptor->getOutstandingRequestCount();
312
313 if (reqCount > 0)
314 {
|
315 mike 1.13 Threads::sleep(1000);
|
316 h.sterling 1.1 } else
317 {
318 break;
319 }
320 }
321
322 PEG_TRACE_STRING(TRC_LISTENER, Tracer::LEVEL4, "ListenerService::Finished waiting for outstanding requests.");
323
324 if (reqCount > 0)
325 {
326 PEG_TRACE_STRING(TRC_LISTENER, Tracer::LEVEL2, "ListenerService::Did not successfully process all incoming requests to the acceptor.");
327 gracefulShutdown = false;
328 }
329
330 //stop the monitor thread and idle thread
331 _dieNow = true;
332
333 //ATTN: This is ghetto and needs to be fixed
334 //signal twice, once for polling thread, once for listener thread
335 //have to signal before both join calls so we do not hit a deadlock
336 _shutdownSem->signal();
337 h.sterling 1.1 _shutdownSem->signal();
338
339 _monitor->tickle();
340
341 //stop listener thread
342 try
343 {
344 _listening_thread->join();
345 delete _listening_thread;
346 _listening_thread = 0;
347
348 } catch (...)
349 {
350 PEG_TRACE_STRING(TRC_LISTENER, Tracer::LEVEL2, "Did not successfully stop monitor thread");
351 gracefulShutdown = false;
352 }
353
354 //stop polling thread
355 if (_polling_thread) //may not be started if polling is disabled
356 {
357 try
358 h.sterling 1.1 {
359 _polling_thread->join();
360 delete _polling_thread;
361 _polling_thread = 0;
362
363 } catch (...)
364 {
365 PEG_TRACE_STRING(TRC_LISTENER, Tracer::LEVEL2, "Did not successfully stop polling thread");
366 gracefulShutdown = false;
367 }
368 }
369
|
370 h.sterling 1.8 //delete acceptor
371 delete _acceptor;
372 _acceptor = 0;
373
|
374 h.sterling 1.1 //delete monitor
375 delete _monitor;
376 _monitor = 0;
377
378 PEG_TRACE_STRING(TRC_LISTENER, Tracer::LEVEL2, "Listener stopped.");
379
380 //reset status values
381 _running = false;
382 _dieNow = false;
383
|
384 h.sterling 1.6 if (gracefulShutdown)
385 {
386 PEG_TRACE_STRING(TRC_LISTENER, Tracer::LEVEL4, "Listener shutdown gracefully");
387 }
|
388 h.sterling 1.1
389 PEG_METHOD_EXIT();
390 return(gracefulShutdown);
391 }
392
|
393 aruran.ms 1.7 Boolean ListenerService::isAlive() const throw()
|
394 h.sterling 1.1 {
395 return _running;
396 }
397
398 //ATTN: Methods for old CIMListener interface...do we need them now?
399 Uint32 ListenerService::getPortNumber() const
400 {
401 return _portNumber;
402 }
403
404
405 PEGASUS_NAMESPACE_END
|