1 /*_############################################################################
3 _## eventlistholder.cpp
6 _## -----------------------------------------------
7 _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
9 _## This software is based on SNMP++2.6 from Hewlett Packard:
11 _## Copyright (c) 1996
12 _## Hewlett-Packard Company
14 _## ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
15 _## Permission to use, copy, modify, distribute and/or sell this software
16 _## and/or its documentation is hereby granted without fee. User agrees
17 _## to display the above copyright notice and this license notice in all
18 _## copies of the software and any documentation of the software. User
19 _## agrees to assume all liability for the use of the software;
20 _## Hewlett-Packard and Jochen Katz make no representations about the
21 _## suitability of this software for any purpose. It is provided
22 _## "AS-IS" without warranty of any kind, either express or implied. User
23 _## hereby grants a royalty-free license to any and all derivatives based
24 _## upon this software code base.
26 _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
28 _##########################################################################*/
30 char event_list_holder_version[]="@(#) SNMP++ $Id: eventlistholder.cpp 342 2008-08-29 22:00:19Z katz $";
32 #include "snmp_pp/eventlistholder.h"
33 #include "snmp_pp/eventlist.h"
34 #include "snmp_pp/msgqueue.h"
35 #include "snmp_pp/notifyqueue.h"
36 #include "snmp_pp/mp_v3.h"
37 #include "snmp_pp/v3.h"
39 #ifdef SNMP_PP_NAMESPACE
43 EventListHolder::EventListHolder(Snmp *snmp_session)
45 // Automaticly add the SNMP message queue
46 m_snmpMessageQueue = new CSNMPMessageQueue(this, snmp_session);
47 m_eventList.AddEntry(m_snmpMessageQueue);
49 // Automatically add the SNMP notification queue
50 m_notifyEventQueue = new CNotifyEventQueue(this, snmp_session);
51 m_eventList.AddEntry(m_notifyEventQueue);
54 //---------[ Block For Response ]-----------------------------------
55 // Wait for the completion of an outstanding SNMP event (msg).
56 // Handle any other events as they occur.
57 int EventListHolder::SNMPBlockForResponse(const unsigned long req_id,
64 SNMPProcessEvents(1000);
65 } while (!m_snmpMessageQueue->Done(req_id));
67 m_snmpMessageQueue->lock();
68 msg = m_snmpMessageQueue->GetEntry(req_id);
70 // we found our response
71 msg->GetPdu(status, pdu);
73 // Dequeue the message
74 m_snmpMessageQueue->DeleteEntry(req_id);
75 m_snmpMessageQueue->unlock();
79 // not in the send queue...must have timed out
80 m_snmpMessageQueue->unlock();
81 return SNMP_CLASS_TIMEOUT;
85 //---------[ Process Pending Events ]-------------------------------
86 #ifdef HAVE_POLL_SYSCALL
87 // Pull all available events out of their sockets - do not block
88 int EventListHolder::SNMPProcessPendingEvents()
92 struct pollfd *pollfds = 0;
100 timeout = 1; // chosen a very small timeout
101 // in order to avoid busy looping but keep overall performance
107 fdcount = m_eventList.GetFdCount();
108 if (pollfds) delete [] pollfds;
109 pollfds = new struct pollfd[fdcount + 1];
110 memset(pollfds, 0, (fdcount + 1) * sizeof(struct pollfd));
111 remaining = fdcount + 1;
112 } while (m_eventList.GetFdArray(pollfds, remaining) == false);
114 nfound = poll(pollfds, fdcount, timeout);
120 status = m_eventList.HandleEvents(pollfds, fdcount);
121 // TM should we do anything with bad status?
124 /* On Win32 select immediately returns -1 if all fd_sets are empty */
126 Sleep(1); /* prevent 100% CPU utilization */
128 } while (nfound > 0);
130 // go through the message queue and resend any messages
131 // which are past the timeout.
132 status = m_eventList.DoRetries(now);
134 pevents_mutex.unlock();
136 if (pollfds) delete [] pollfds;
141 // Block until an event shows up - then handle the event(s)
142 int EventListHolder::SNMPProcessEvents(const int max_block_milliseconds)
146 struct pollfd *pollfds = 0;
147 struct timeval fd_timeout;
149 msec now; // automatcally calls msec::refresh()
153 m_eventList.GetNextTimeout(sendTime);
154 now.GetDelta(sendTime, fd_timeout);
158 fdcount = m_eventList.GetFdCount();
159 if (pollfds) delete [] pollfds;
160 pollfds = new struct pollfd[fdcount + 1];
161 memset(pollfds, 0, (fdcount + 1) * sizeof(struct pollfd));
162 remaining = fdcount + 1;
163 } while (m_eventList.GetFdArray(pollfds, remaining) == false);
165 if ((max_block_milliseconds > 0) &&
166 ((fd_timeout.tv_sec > max_block_milliseconds / 1000) ||
167 ((fd_timeout.tv_sec == max_block_milliseconds / 1000) &&
168 (fd_timeout.tv_usec > (max_block_milliseconds % 1000) * 1000))))
170 fd_timeout.tv_sec = max_block_milliseconds / 1000;
171 fd_timeout.tv_usec = (max_block_milliseconds % 1000) * 1000;
174 /* Prevent endless sleep in case no fd is open */
175 if ((fdcount == 0) && (fd_timeout.tv_sec > 5))
176 fd_timeout.tv_sec = 5; /* sleep at max 5.99 seconds */
178 timeout = fd_timeout.tv_sec * 1000 + fd_timeout.tv_usec / 1000;
180 poll(pollfds, fdcount, timeout);
182 status = SNMPProcessPendingEvents();
184 if (pollfds) delete [] pollfds;
191 int EventListHolder::SNMPProcessPendingEvents()
198 struct timeval fd_timeout;
202 pevents_mutex.lock();
204 // do not allow select to block
205 fd_timeout.tv_sec = 0;
206 fd_timeout.tv_usec = 10; // chosen a very small timeout
207 // in order to avoid busy looping but keep overall performance
212 m_eventList.GetFdSets(maxfds, readfds, writefds, exceptfds);
214 nfound = select(maxfds, &readfds, &writefds, &exceptfds, &fd_timeout);
219 { // found something on select
220 status = m_eventList.HandleEvents(maxfds, readfds, writefds, exceptfds);
221 // TM should we do anything with bad status?
224 /* On Win32 select immediately returns -1 if all fd_sets are empty */
226 Sleep(1); /* prevent 100% CPU utilization */
228 } while (nfound > 0);
230 // go through the message queue and resend any messages
231 // which are past the timeout.
232 status = m_eventList.DoRetries(now);
234 pevents_mutex.unlock();
239 //---------[ Process Events ]------------------------------------------
240 // Block until an event shows up - then handle the event(s)
241 int EventListHolder::SNMPProcessEvents(const int max_block_milliseconds)
247 struct timeval fd_timeout;
248 msec now; // automatcally calls msec::refresh()
252 m_eventList.GetNextTimeout(sendTime);
253 now.GetDelta(sendTime, fd_timeout);
255 m_eventList.GetFdSets(maxfds, readfds, writefds, exceptfds);
257 if ((max_block_milliseconds > 0) &&
258 ((fd_timeout.tv_sec > max_block_milliseconds / 1000) ||
259 ((fd_timeout.tv_sec == max_block_milliseconds / 1000) &&
260 (fd_timeout.tv_usec > (max_block_milliseconds % 1000) * 1000))))
262 fd_timeout.tv_sec = max_block_milliseconds / 1000;
263 fd_timeout.tv_usec = (max_block_milliseconds % 1000) * 1000;
266 /* Prevent endless sleep in case no fd is open */
267 if ((maxfds == 0) && (fd_timeout.tv_sec > 5))
268 fd_timeout.tv_sec = 5; /* sleep at max 5.99 seconds */
270 select(maxfds, &readfds, &writefds, &exceptfds, &fd_timeout);
272 status = SNMPProcessPendingEvents();
279 //---------[ Main Loop ]------------------------------------------
280 // Infinite loop which blocks when there is nothing to do and handles
281 // any events as they occur.
282 void EventListHolder::SNMPMainLoop(const int max_block_milliseconds)
285 SNMPProcessEvents(max_block_milliseconds);
286 } while (!m_eventList.Done());
289 //---------[ Exit Main Loop ]---------------------------------------
290 // Force the SNMP Main Loop to terminate immediately
291 void EventListHolder::SNMPExitMainLoop()
293 m_eventList.SetDone();
296 #ifdef HAVE_POLL_SYSCALL
298 int EventListHolder::GetFdCount()
300 return m_eventList.GetFdCount();
303 bool EventListHolder::GetFdArray(struct pollfd *readfds, int &remaining)
305 return m_eventList.GetFdArray(readfds, remaining);
310 void EventListHolder::SNMPGetFdSets(int &maxfds,
315 m_eventList.GetFdSets(maxfds, readfds, writefds, exceptfds);
318 #endif // HAVE_POLL_SYSCALL
320 Uint32 EventListHolder::SNMPGetNextTimeout()
325 //TM: This function used to have an argument of sendTime and
326 // would simply call eventList.GetNextTimeout(sendTime) and
327 // return the status. However, to avoid exposing the msec
328 // class we now convert the msec to hundreths of seconds
329 // and return that as a unsigned long.
332 m_eventList.GetNextTimeout(sendTime);
333 if (sendTime.IsInfinite()) {
338 // Kludge: When this was first designed the units were millisecs
339 // However, later on the units for the target class were changed
340 // to hundreths of secs. Divide millisecs by 10 to create the
341 // hundreths of secs which the rest of the objects use.
344 // 21-May-02 DLD: Add check to avoid returning a negative interval
345 // Long eventlists seem to end up with events that are greater
346 // than the time when the event loop is started, but less than the
347 // time when this function is called. This check is analagous to
348 // what is done in msec::GetDelta() which is used in
349 // SNMPProcessEvents(), the library main loop.
351 // 21-May-02 DLD: Add 1/100 sec to time out to avoid returning a
352 // short time out interval. A short interval can result due to
353 // truncation of the millisec value when dividing by 10.
358 return ((((unsigned long) sendTime) / 10) + 1);
365 #ifdef SNMP_PP_NAMESPACE
366 }; // end of namespace Snmp_pp