]> git.stg.codes - ssmd.git/blob - 3rdparty/snmp++/src/eventlistholder.cpp
Initial adding
[ssmd.git] / 3rdparty / snmp++ / src / eventlistholder.cpp
1 /*_############################################################################
2   _## 
3   _##  eventlistholder.cpp  
4   _##
5   _##  SNMP++v3.2.25
6   _##  -----------------------------------------------
7   _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
8   _##
9   _##  This software is based on SNMP++2.6 from Hewlett Packard:
10   _##  
11   _##    Copyright (c) 1996
12   _##    Hewlett-Packard Company
13   _##  
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. 
25   _##  
26   _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
27   _##  
28   _##########################################################################*/
29
30 char event_list_holder_version[]="@(#) SNMP++ $Id: eventlistholder.cpp 342 2008-08-29 22:00:19Z katz $";
31
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"
38
39 #ifdef SNMP_PP_NAMESPACE
40 namespace Snmp_pp {
41 #endif
42
43 EventListHolder::EventListHolder(Snmp *snmp_session)
44 {
45   // Automaticly add the SNMP message queue
46   m_snmpMessageQueue = new CSNMPMessageQueue(this, snmp_session);
47   m_eventList.AddEntry(m_snmpMessageQueue);
48
49   // Automatically add the SNMP notification queue
50   m_notifyEventQueue = new CNotifyEventQueue(this, snmp_session);
51   m_eventList.AddEntry(m_notifyEventQueue);
52 }
53
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,
58                                           Pdu &pdu)
59 {
60   CSNMPMessage *msg;
61   int status;
62
63   do {
64     SNMPProcessEvents(1000);
65   } while (!m_snmpMessageQueue->Done(req_id));
66
67   m_snmpMessageQueue->lock();
68   msg = m_snmpMessageQueue->GetEntry(req_id);
69   if (msg) {
70     // we found our response
71     msg->GetPdu(status, pdu);
72
73     // Dequeue the message
74     m_snmpMessageQueue->DeleteEntry(req_id);
75     m_snmpMessageQueue->unlock();
76     return  status;
77   }
78   else {
79     // not in the send queue...must have timed out
80     m_snmpMessageQueue->unlock();
81     return SNMP_CLASS_TIMEOUT;
82   }
83 }
84
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()
89 {
90   int fdcount;
91   int remaining;
92   struct pollfd *pollfds = 0;
93   int nfound = 0;
94   int timeout;
95   msec now(0, 0);
96   int status;
97
98   pevents_mutex.lock();
99
100   timeout = 1;  // chosen a very small timeout
101   // in order to avoid busy looping but keep overall performance
102
103   do
104   {
105     do
106     {
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);
113
114     nfound = poll(pollfds, fdcount, timeout);
115
116     now.refresh();
117
118     if (nfound > 0)
119     {
120       status = m_eventList.HandleEvents(pollfds, fdcount);
121       // TM should we do anything with bad status?
122     }
123 #ifdef WIN32
124     /* On Win32 select immediately returns -1 if all fd_sets are empty */
125     if (maxfds == 0)
126       Sleep(1); /* prevent 100% CPU utilization */
127 #endif
128   } while (nfound > 0);
129
130   // go through the message queue and resend any messages
131   // which are past the timeout.
132   status = m_eventList.DoRetries(now);
133
134   pevents_mutex.unlock();
135
136   if (pollfds) delete [] pollfds;
137
138   return status;
139 }
140
141 // Block until an event shows up - then handle the event(s)
142 int EventListHolder::SNMPProcessEvents(const int max_block_milliseconds)
143 {
144   int fdcount;
145   int remaining;
146   struct pollfd *pollfds = 0;
147   struct timeval fd_timeout;
148   int timeout;
149   msec now; // automatcally calls msec::refresh()
150   msec sendTime;
151   int status = 0;
152
153   m_eventList.GetNextTimeout(sendTime);
154   now.GetDelta(sendTime, fd_timeout);
155
156   do
157   {
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);
164
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))))
169   {
170     fd_timeout.tv_sec = max_block_milliseconds / 1000;
171     fd_timeout.tv_usec = (max_block_milliseconds % 1000) * 1000;
172   }
173
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 */
177
178   timeout = fd_timeout.tv_sec * 1000 + fd_timeout.tv_usec / 1000;
179
180   poll(pollfds, fdcount, timeout);
181
182   status = SNMPProcessPendingEvents();
183
184   if (pollfds) delete [] pollfds;
185
186   return status;
187 }
188
189 #else
190
191 int EventListHolder::SNMPProcessPendingEvents()
192 {
193   int maxfds;
194   fd_set readfds;
195   fd_set writefds;
196   fd_set exceptfds;
197   int nfound = 0;
198   struct timeval fd_timeout;
199   msec now(0, 0);
200   int status;
201
202   pevents_mutex.lock();
203
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
208
209   do {
210
211     // Set up Select
212     m_eventList.GetFdSets(maxfds, readfds, writefds, exceptfds);
213
214     nfound = select(maxfds, &readfds, &writefds, &exceptfds, &fd_timeout);
215
216     now.refresh();
217
218     if (nfound > 0)
219     { // found something on select
220       status = m_eventList.HandleEvents(maxfds, readfds, writefds, exceptfds);
221       // TM should we do anything with bad status?
222     }
223 #ifdef WIN32
224     /* On Win32 select immediately returns -1 if all fd_sets are empty */
225     if (maxfds == 0)
226       Sleep(1); /* prevent 100% CPU utilization */
227 #endif
228   } while (nfound > 0);
229
230   // go through the message queue and resend any messages
231   // which are past the timeout.
232   status = m_eventList.DoRetries(now);
233
234   pevents_mutex.unlock();
235
236   return status;
237 }
238
239 //---------[ Process Events ]------------------------------------------
240 // Block until an event shows up - then handle the event(s)
241 int EventListHolder::SNMPProcessEvents(const int max_block_milliseconds)
242 {
243   int maxfds;
244   fd_set readfds;
245   fd_set writefds;
246   fd_set exceptfds;
247   struct timeval fd_timeout;
248   msec now; // automatcally calls msec::refresh()
249   msec sendTime;
250   int status = 0;
251
252   m_eventList.GetNextTimeout(sendTime);
253   now.GetDelta(sendTime, fd_timeout);
254
255   m_eventList.GetFdSets(maxfds, readfds, writefds, exceptfds);
256
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))))
261   {
262     fd_timeout.tv_sec = max_block_milliseconds / 1000;
263     fd_timeout.tv_usec = (max_block_milliseconds % 1000) * 1000;
264   }
265
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 */
269
270   select(maxfds, &readfds, &writefds, &exceptfds, &fd_timeout);
271
272   status = SNMPProcessPendingEvents();
273
274   return status;
275 }
276
277 #endif
278
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)
283 {
284   do {
285     SNMPProcessEvents(max_block_milliseconds);
286   } while (!m_eventList.Done());
287 }
288
289 //---------[ Exit Main Loop ]---------------------------------------
290 // Force the SNMP Main Loop to terminate immediately
291 void EventListHolder::SNMPExitMainLoop()
292 {
293    m_eventList.SetDone();
294 }
295
296 #ifdef HAVE_POLL_SYSCALL
297
298 int EventListHolder::GetFdCount()
299 {
300   return m_eventList.GetFdCount();
301 }
302
303 bool EventListHolder::GetFdArray(struct pollfd *readfds, int &remaining)
304 {
305     return m_eventList.GetFdArray(readfds, remaining);
306 }
307
308 #else
309
310 void EventListHolder::SNMPGetFdSets(int    &maxfds,
311                                     fd_set &readfds,
312                                     fd_set &writefds,
313                                     fd_set &exceptfds)
314 {
315   m_eventList.GetFdSets(maxfds, readfds, writefds, exceptfds);
316 }
317
318 #endif // HAVE_POLL_SYSCALL
319
320 Uint32 EventListHolder::SNMPGetNextTimeout()
321 {
322   msec now;
323   msec sendTime(now);
324
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.
330 // 25-Jan-96 TM
331
332   m_eventList.GetNextTimeout(sendTime);
333   if (sendTime.IsInfinite()) {
334     return UINT_MAX;
335   }
336   else {
337
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.
342     // 25-Jan-96 TM
343
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.
350
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.
354
355     if (sendTime > now)
356     {
357       sendTime -= now;
358       return ((((unsigned long) sendTime) / 10) + 1);
359     }
360     else
361       return 0;
362   }
363 }
364
365 #ifdef SNMP_PP_NAMESPACE
366 }; // end of namespace Snmp_pp
367 #endif