]> git.stg.codes - ssmd.git/blob - 3rdparty/snmp++/src/notifyqueue.cpp
Initial adding
[ssmd.git] / 3rdparty / snmp++ / src / notifyqueue.cpp
1 /*_############################################################################
2   _## 
3   _##  notifyqueue.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
31   Copyright (c) 1999
32   Hewlett-Packard Company
33
34   ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
35   Permission to use, copy, modify, distribute and/or sell this software
36   and/or its documentation is hereby granted without fee. User agrees
37   to display the above copyright notice and this license notice in all
38   copies of the software and any documentation of the software. User
39   agrees to assume all liability for the use of the software; Hewlett-Packard
40   makes no representations about the suitability of this software for any
41   purpose. It is provided "AS-IS" without warranty of any kind,either express
42   or implied. User hereby grants a royalty-free license to any and all
43   derivatives based upon this software code base.
44
45       N O T I F Y Q U E U E . C P P
46
47       CNotifyEventQueue CLASS DEFINITION
48
49       COPYRIGHT HEWLETT PACKARD COMPANY 1999
50
51       INFORMATION NETWORKS DIVISION
52
53       NETWORK MANAGEMENT SECTION
54
55       DESIGN + AUTHOR:        Tom Murray
56
57       DESCRIPTION:
58         Queue for holding callback associated with user defined
59         timeouts
60
61 =====================================================================*/
62 char notifyqueue_version[]="#(@) SNMP++ $Id: notifyqueue.cpp 1826 2010-08-29 20:19:59Z katz $";
63
64 //-----[ includes ]----------------------------------------------------
65 #include <errno.h>
66
67 #if defined (CPU) && CPU == PPC603
68 #include <sockLib.h> 
69 #endif
70
71 #if defined(__APPLE__)
72 #include <sys/types.h>
73 #include <sys/socket.h>
74 #include <netinet/in.h>
75 #include <arpa/inet.h>
76 #include <unistd.h>
77 #endif
78
79 //----[ snmp++ includes ]----------------------------------------------
80
81 #include "snmp_pp/config_snmp_pp.h"
82 #include "snmp_pp/v3.h"
83 #include "snmp_pp/notifyqueue.h" // queue for holding sessions waiting for async notifications
84 #include "snmp_pp/eventlistholder.h"
85 #include "snmp_pp/uxsnmp.h"
86 #include "snmp_pp/snmperrs.h"
87 #include "snmp_pp/pdu.h"
88 #include "snmp_pp/log.h"
89
90 #ifdef SNMP_PP_NAMESPACE
91 namespace Snmp_pp {
92 #endif
93
94 //--------[ externs ]---------------------------------------------------
95 extern int receive_snmp_notification(SnmpSocket sock, Snmp &snmp_session,
96                                      Pdu &pdu, SnmpTarget **target);
97
98 //-----[ macros ]------------------------------------------------------
99 // should be in snmp.h...
100 #define SNMP_PORT 161         // standard port # for SNMP
101 #define SNMP_TRAP_PORT 162    // standard port # for SNMP traps
102
103 #ifdef WIN32
104 #define close closesocket
105 #elif defined(_AIX)
106 #include <unistd.h>
107 #endif
108
109 //----[ CNotifyEvent class ]------------------------------------------------
110
111 CNotifyEvent::CNotifyEvent(Snmp *snmp,
112                            const OidCollection &trapids,
113                            const TargetCollection &targets)
114   : m_snmp(snmp)
115 {
116   // create new collections using parms passed in
117   notify_ids       = new OidCollection(trapids);
118   notify_targets   = new TargetCollection(targets);
119 }
120
121 CNotifyEvent::~CNotifyEvent()
122 {
123   // free up local collections
124   if (notify_ids)       { delete notify_ids;       notify_ids       = 0; }
125   if (notify_targets)   { delete notify_targets;   notify_targets   = 0; }
126 }
127
128 int CNotifyEvent::notify_filter(const Oid &trapid, SnmpTarget &target) const
129 {
130   int target_count, has_target = FALSE, target_matches = FALSE;
131   int trapid_count, has_trapid = FALSE, trapid_matches = FALSE;
132   GenAddress targetaddr, tmpaddr;
133
134   // figure out how many targets, handle empty case as all targets
135   if ((notify_targets) && ((target_count = notify_targets->size())))
136   {
137     SnmpTarget *tmptarget = 0;
138     has_target = TRUE;
139
140     target.get_address(targetaddr);
141
142     if (targetaddr.valid()) {
143       // loop through all targets in the collection
144       SnmpTarget::target_type target_type = target.get_type();
145       SnmpTarget::target_type tmptarget_type;
146
147       for ( int x = 0; x < target_count; x++)       // for all targets
148       {
149         if (notify_targets->get_element(tmptarget, x))
150           continue;
151
152         tmptarget->get_address(tmpaddr);
153         if ((tmpaddr.valid())) {
154           int addr_equal = 0;
155
156           /* check for types of Address */
157           if ((tmpaddr.get_type() == Address::type_ip) &&
158               (targetaddr.get_type() == Address::type_udp))
159           {
160             /* special case that works for UdpAddress == IpAddress */
161             IpAddress ip1(targetaddr);
162             IpAddress ip2(tmpaddr);
163
164             addr_equal = (ip1.valid() && ip2.valid() && (ip1 == ip2));
165           }
166           else
167           {
168             addr_equal = (targetaddr == tmpaddr);
169           }
170
171           if (addr_equal) {
172             tmptarget_type = tmptarget->get_type();
173             if (target_type == SnmpTarget::type_utarget) {
174               // target is a UTarget
175               if (tmptarget_type == SnmpTarget::type_utarget) {
176                 // both are UTarget
177                 if ((((UTarget*)(&target))->get_security_name() ==
178                      ((UTarget*)tmptarget)->get_security_name()) &&
179                     (((UTarget*)(&target))->get_security_model() ==
180                      ((UTarget*)tmptarget)->get_security_model())) {
181                   target_matches = TRUE;
182                   break;
183                 }
184               }
185               else
186                 if (tmptarget_type == SnmpTarget::type_ctarget)
187                   // in case utarget is used with v1 or v2:
188                   if ((tmptarget->get_version() == target.get_version()) &&
189                       (((UTarget*)(&target))->get_security_name() ==
190                        OctetStr(((CTarget*)tmptarget)->
191                                 get_readcommunity()))) {
192                     target_matches = TRUE;
193                     break;
194                   }
195             }
196             else {
197               if (target_type == SnmpTarget::type_ctarget) {
198                 // target is a CTarget
199                 if (tmptarget_type == SnmpTarget::type_ctarget) {
200                   // both are CTarget
201                   if (!strcmp(((CTarget*)(&target))->get_readcommunity(),
202                               ((CTarget*)tmptarget)->get_readcommunity())) {
203                     target_matches = TRUE;
204                     break;
205                   }
206                 }
207                 else
208                   if (tmptarget_type == SnmpTarget::type_utarget) {
209                     if ((tmptarget->get_version() == target.get_version()) &&
210                         (OctetStr(((CTarget*)(&target))->get_readcommunity()) ==
211                          ((UTarget*)tmptarget)->get_security_name())) {
212                       target_matches = TRUE;
213                       break;
214                     }
215                   }
216               }
217             }
218           } // end if (add_equal)
219         } // end if tmpaddr.valid()...
220       }
221     }
222   }
223   // else no targets means all targets
224
225   // figure out how many trapids, handle empty case as all trapids
226   if ((notify_ids) && ((trapid_count = notify_ids->size()))) {
227     Oid tmpoid;
228     has_trapid = TRUE;
229     // loop through all trapids in the collection
230     for (int y=0; y < trapid_count; y++)       // for all trapids
231     {
232       if (notify_ids->get_element(tmpoid, y))
233         continue;
234       if (trapid == tmpoid) {
235         trapid_matches = TRUE;
236         break;
237       }
238     }
239   }
240   // else no trapids means all traps
241
242   // Make the callback if the trap passed the filters
243   if ((has_target && !target_matches) || (has_trapid && !trapid_matches))
244     return FALSE;
245   return TRUE;
246 }
247
248
249 int CNotifyEvent::Callback(SnmpTarget &target, Pdu &pdu, SnmpSocket fd, int status)
250 {
251   Oid trapid;
252   pdu.get_notify_id(trapid);
253
254   // Make the callback if the trap passed the filters
255   if ((m_snmp) && (notify_filter(trapid, target)))
256   {
257     int reason;
258
259     if (SNMP_CLASS_TL_FAILED == status)
260       reason = SNMP_CLASS_TL_FAILED;
261     else
262       reason = SNMP_CLASS_NOTIFICATION;
263
264     //------[ call into the callback function ]-------------------------
265     if (m_snmp->get_notify_callback())
266       (m_snmp->get_notify_callback())(
267           reason,
268           m_snmp,                       // snmp++ session who owns the req
269           pdu,                  // trap pdu
270           target,                       // target
271           m_snmp->get_notify_callback_data()); // callback data
272   }
273   return SNMP_CLASS_SUCCESS;
274 }
275
276
277 //----[ CNotifyEventQueueElt class ]--------------------------------------
278
279 CNotifyEventQueue::CNotifyEventQueueElt::CNotifyEventQueueElt(
280                                            CNotifyEvent *notifyevent,
281                                            CNotifyEventQueueElt *next,
282                                            CNotifyEventQueueElt *previous)
283   : m_notifyevent(notifyevent), m_Next(next), m_previous(previous)
284 {
285   /* Finish insertion into doubly linked list */
286   if (m_Next)     m_Next->m_previous = this;
287   if (m_previous) m_previous->m_Next = this;
288 }
289
290 CNotifyEventQueue::CNotifyEventQueueElt::~CNotifyEventQueueElt()
291 {
292   /* Do deletion form doubly linked list */
293   if (m_Next)        m_Next->m_previous = m_previous;
294   if (m_previous)    m_previous->m_Next = m_Next;
295   if (m_notifyevent) delete m_notifyevent;
296 }
297
298 CNotifyEvent *CNotifyEventQueue::CNotifyEventQueueElt::TestId(Snmp *snmp)
299 {
300   if (m_notifyevent && (m_notifyevent->GetId() == snmp))
301     return m_notifyevent;
302   return 0;
303 }
304
305
306 //----[ CNotifyEventQueue class ]--------------------------------------
307 CNotifyEventQueue::CNotifyEventQueue(EventListHolder *holder, Snmp *session)
308   : m_head(NULL,NULL,NULL), m_msgCount(0), m_notify_fd(INVALID_SOCKET),
309     m_listen_port(SNMP_TRAP_PORT),
310     my_holder(holder), m_snmpSession(session)
311 {
312 //TM: could do the trap registration setup here but seems better to
313 //wait until the app actually requests trap receives by calling
314 //notify_register().
315 }
316
317 CNotifyEventQueue::~CNotifyEventQueue()
318 {
319   CNotifyEventQueueElt *leftOver;
320
321   /* walk the list deleting any elements still on the queue */
322   lock();
323   while ((leftOver = m_head.GetNext()))
324     delete leftOver;
325   unlock();
326 }
327
328 SnmpSocket CNotifyEventQueue::get_notify_fd() const
329 {
330   return m_notify_fd;
331 }
332
333 int CNotifyEventQueue::AddEntry(Snmp *snmp,
334                                 const OidCollection &trapids,
335                                 const TargetCollection &targets)
336 {
337   SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
338
339   if (snmp != m_snmpSession)
340   {
341     debugprintf(0, "WARNING: Adding notification event for other Snmp object");
342   }
343
344   if (!m_msgCount)
345   {
346     m_notify_addr = snmp->get_listen_address();
347     m_notify_addr.set_port(m_listen_port);
348
349     int status = SNMP_CLASS_SUCCESS;
350
351     // This is the first request to receive notifications
352     // Set up the socket for the snmp trap port (162) or the
353     // specified port through set_listen_port()
354     bool is_v4_address = (m_notify_addr.get_ip_version() == Address::version_ipv4);
355     if (is_v4_address)
356     {
357       struct sockaddr_in mgr_addr;
358
359       // open a socket to be used for the session
360       if ((m_notify_fd = socket(AF_INET, SOCK_DGRAM,0)) < 0)
361       {
362 #ifdef WIN32
363         int werr = WSAGetLastError();
364         if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
365           status = SNMP_CLASS_RESOURCE_UNAVAIL;
366         else if (WSAEHOSTDOWN == werr)
367           status = SNMP_CLASS_TL_FAILED;
368         else
369           status = SNMP_CLASS_TL_UNSUPPORTED;
370 #else
371         if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
372           status = SNMP_CLASS_RESOURCE_UNAVAIL;
373         else if (EHOSTDOWN == errno)
374           status = SNMP_CLASS_TL_FAILED;
375         else
376           status = SNMP_CLASS_TL_UNSUPPORTED;
377 #endif
378         cleanup();
379         return status;
380       }
381
382       // set up the manager socket attributes
383       unsigned long inaddr = inet_addr(IpAddress(m_notify_addr).get_printable());
384       memset(&mgr_addr, 0, sizeof(mgr_addr));
385       mgr_addr.sin_family = AF_INET;
386       mgr_addr.sin_addr.s_addr = inaddr; // was htonl( INADDR_ANY);
387       mgr_addr.sin_port = htons(m_notify_addr.get_port());
388 #ifdef CYGPKG_NET_OPENBSD_STACK
389       mgr_addr.sin_len = sizeof(mgr_addr);
390 #endif
391
392       // bind the socket
393       if (bind(m_notify_fd, (struct sockaddr *) &mgr_addr,
394                sizeof(mgr_addr)) < 0)
395       {
396 #ifdef WIN32
397         int werr = WSAGetLastError();
398         if (WSAEADDRINUSE  == werr)
399           status = SNMP_CLASS_TL_IN_USE;
400         else if (WSAENOBUFS == werr)
401           status = SNMP_CLASS_RESOURCE_UNAVAIL;
402         else if (werr == WSAEAFNOSUPPORT)
403           status = SNMP_CLASS_TL_UNSUPPORTED;
404         else if (werr == WSAENETUNREACH)
405           status = SNMP_CLASS_TL_FAILED;
406         else if (werr == EACCES)
407           status = SNMP_CLASS_TL_ACCESS_DENIED;
408         else
409           status = SNMP_CLASS_INTERNAL_ERROR;
410 #else
411         if (EADDRINUSE  == errno)
412           status = SNMP_CLASS_TL_IN_USE;
413         else if (ENOBUFS == errno)
414           status = SNMP_CLASS_RESOURCE_UNAVAIL;
415         else if (errno == EAFNOSUPPORT)
416           status = SNMP_CLASS_TL_UNSUPPORTED;
417         else if (errno == ENETUNREACH)
418           status = SNMP_CLASS_TL_FAILED;
419         else if (errno == EACCES)
420           status = SNMP_CLASS_TL_ACCESS_DENIED;
421         else
422         {
423           debugprintf(0, "Uncatched errno value %d, returning internal error.",
424                       errno);
425           status = SNMP_CLASS_INTERNAL_ERROR;
426         }
427 #endif
428         debugprintf(0, "Fatal: could not bind to %s",
429                     m_notify_addr.get_printable());
430         cleanup();
431         return status;
432       }
433
434       debugprintf(3, "Bind to %s for notifications, fd %d.",
435                   m_notify_addr.get_printable(), m_notify_fd);
436     } // is_v4_address
437     else
438     {
439       // not is_v4_address
440 #ifdef SNMP_PP_IPv6
441       // open a socket to be used for the session
442       if ((m_notify_fd = socket(AF_INET6, SOCK_DGRAM,0)) < 0)
443       {
444 #ifdef WIN32
445         int werr = WSAGetLastError();
446         if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
447           status = SNMP_CLASS_RESOURCE_UNAVAIL;
448         else if (WSAEHOSTDOWN == werr)
449           status = SNMP_CLASS_TL_FAILED;
450         else
451           status = SNMP_CLASS_TL_UNSUPPORTED;
452 #else
453         if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
454           status = SNMP_CLASS_RESOURCE_UNAVAIL;
455         else if (EHOSTDOWN == errno)
456           status = SNMP_CLASS_TL_FAILED;
457         else
458           status = SNMP_CLASS_TL_UNSUPPORTED;
459 #endif
460         cleanup();
461         return status;
462       }
463
464       // set up the manager socket attributes
465       struct sockaddr_in6 mgr_addr;
466       memset(&mgr_addr, 0, sizeof(mgr_addr));
467
468       unsigned int scope = 0;
469
470       OctetStr addrstr = ((IpAddress &)m_notify_addr).IpAddress::get_printable();
471
472       if (m_notify_addr.has_ipv6_scope())
473       {
474         scope = m_notify_addr.get_scope();
475
476         int y = addrstr.len() - 1;
477         while ((y>0) && (addrstr[y] != '%'))
478         {
479           addrstr.set_len(addrstr.len() - 1);
480           y--;
481         }
482         if (addrstr[y] == '%')
483           addrstr.set_len(addrstr.len() - 1);
484       }
485
486       if (inet_pton(AF_INET6, addrstr.get_printable(),
487                     &mgr_addr.sin6_addr) < 0)
488       {
489         LOG_BEGIN(ERROR_LOG | 1);
490         LOG("Notify transport: inet_pton returns (errno) (str)");
491         LOG(errno);
492         LOG(strerror(errno));
493         LOG_END;
494         cleanup();
495         return SNMP_CLASS_INVALID_ADDRESS;
496       }
497
498       mgr_addr.sin6_family = AF_INET6;
499       mgr_addr.sin6_port = htons(m_notify_addr.get_port());
500       mgr_addr.sin6_scope_id = scope;
501
502       // bind the socket
503       if (bind(m_notify_fd, (struct sockaddr *) &mgr_addr,
504                sizeof(mgr_addr)) < 0)
505       {
506 #ifdef WIN32
507         int werr = WSAGetLastError();
508         if (WSAEADDRINUSE  == werr)
509           status = SNMP_CLASS_TL_IN_USE;
510         else if (WSAENOBUFS == werr)
511           status = SNMP_CLASS_RESOURCE_UNAVAIL;
512         else if (werr == WSAEAFNOSUPPORT)
513           status = SNMP_CLASS_TL_UNSUPPORTED;
514         else if (werr == WSAENETUNREACH)
515           status = SNMP_CLASS_TL_FAILED;
516         else if (werr == EACCES)
517           status = SNMP_CLASS_TL_ACCESS_DENIED;
518         else
519           status = SNMP_CLASS_INTERNAL_ERROR;
520 #else
521         if (EADDRINUSE  == errno)
522           status = SNMP_CLASS_TL_IN_USE;
523         else if (ENOBUFS == errno)
524           status = SNMP_CLASS_RESOURCE_UNAVAIL;
525         else if (errno == EAFNOSUPPORT)
526           status = SNMP_CLASS_TL_UNSUPPORTED;
527         else if (errno == ENETUNREACH)
528           status = SNMP_CLASS_TL_FAILED;
529         else if (errno == EACCES)
530           status = SNMP_CLASS_TL_ACCESS_DENIED;
531         else
532         {
533           debugprintf(0, "Uncatched errno value %d, returning internal error.",
534                       errno);
535           status = SNMP_CLASS_INTERNAL_ERROR;
536           return status;
537         }
538 #endif
539         debugprintf(0, "Fatal: could not bind to %s",
540                     m_notify_addr.get_printable());
541         cleanup();
542         return status;
543       }
544       debugprintf(3, "Bind to %s for notifications, fd %d.",
545                   m_notify_addr.get_printable(), m_notify_fd);
546 #else
547       debugprintf(0, "User error: Enable IPv6 and recompile snmp++.");
548       cleanup();
549       return SNMP_CLASS_TL_UNSUPPORTED;
550 #endif
551     } // not is_v4_address
552   }
553
554   CNotifyEvent *newEvent = new CNotifyEvent(snmp, trapids, targets);
555
556   /*---------------------------------------------------------*/
557   /* Insert entry at head of list, done automagically by the */
558   /* constructor function, so don't use the return value.    */
559   /*---------------------------------------------------------*/
560   (void) new CNotifyEventQueueElt(newEvent, m_head.GetNext(), &m_head);
561   m_msgCount++;
562
563   return SNMP_CLASS_SUCCESS;
564 }
565
566 void CNotifyEventQueue::cleanup()
567 {
568   if (m_notify_fd != INVALID_SOCKET)
569   {
570     close(m_notify_fd);
571     m_notify_fd = INVALID_SOCKET;
572   }
573   m_notify_addr.clear();
574 }
575
576 CNotifyEvent *CNotifyEventQueue::GetEntry(Snmp * snmp) REENTRANT ({
577   CNotifyEventQueueElt *msgEltPtr = m_head.GetNext();
578   CNotifyEvent *returnVal = NULL;
579
580   while (msgEltPtr){
581     if ((returnVal = msgEltPtr->TestId(snmp)))
582       return returnVal;
583     msgEltPtr = msgEltPtr->GetNext();
584   }
585   return 0;
586 })
587
588 void CNotifyEventQueue::DeleteEntry(Snmp *snmp)
589 {
590   lock();
591   CNotifyEventQueueElt *msgEltPtr = m_head.GetNext();
592
593   while (msgEltPtr){
594     if (msgEltPtr->TestId(snmp)){
595       delete msgEltPtr;
596       m_msgCount--;
597       break;
598     }
599     msgEltPtr = msgEltPtr->GetNext();
600   }
601
602   if (m_msgCount <= 0)
603   {
604     // shut down the trap socket (if valid) if not using it.
605     if (m_notify_fd != INVALID_SOCKET)
606     {
607       debugprintf(3, "Closing notifications port %s, fd %d.",
608                   m_notify_addr.get_printable(), m_notify_fd);
609       close(m_notify_fd);
610       m_notify_fd = INVALID_SOCKET;
611     }
612     m_notify_addr.clear();
613   }
614   unlock();
615 }
616
617 #ifdef HAVE_POLL_SYSCALL
618 int CNotifyEventQueue::GetFdCount()
619 {
620   SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
621   if (m_notify_fd == INVALID_SOCKET)
622     return 0;
623   return 1;
624 }
625
626 bool CNotifyEventQueue::GetFdArray(struct pollfd *readfds,
627                                    int &remaining)
628 {
629   SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
630
631   if (m_notify_fd != INVALID_SOCKET)
632   {
633     if (remaining == 0)
634       return false;
635     readfds[0].fd = m_notify_fd;
636     readfds[0].events = POLLIN;
637     remaining--;
638   }
639   return true;
640 }
641
642 int CNotifyEventQueue::HandleEvents(const struct pollfd *readfds,
643                                     const int fds)
644 {
645   SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
646
647   int status = SNMP_CLASS_SUCCESS;
648
649   if (m_notify_fd == INVALID_SOCKET)
650     return status;
651
652   for (int i=0; i < fds; i++)
653   {
654     Pdu pdu;
655     SnmpTarget *target = NULL;
656
657     if ((readfds[i].revents & POLLIN) == 0)
658       continue; // nothing to receive
659
660     if (readfds[i].fd != m_notify_fd)
661       continue; // not our socket
662
663     status = receive_snmp_notification(m_notify_fd, *m_snmpSession,
664                                        pdu, &target);
665
666     if ((SNMP_CLASS_SUCCESS == status) ||
667         (SNMP_CLASS_TL_FAILED == status))
668     {
669       // If we have transport layer failure, the app will want to
670       // know about it.
671       // Go through each snmp object and check the filters, making
672       // callbacks as necessary
673       if (!target) target = new SnmpTarget();
674
675       CNotifyEventQueueElt *notifyEltPtr = m_head.GetNext();
676       while (notifyEltPtr)
677       {
678         notifyEltPtr->GetNotifyEvent()->Callback(*target, pdu,
679                                                  m_notify_fd, status);
680         notifyEltPtr = notifyEltPtr->GetNext();
681       } // for each snmp object
682     }
683     if (target) // receive_snmp_notification calls new
684       delete target;
685   }
686
687   return status;
688 }
689
690 #else
691
692 void CNotifyEventQueue::GetFdSets(int &maxfds, fd_set &readfds,
693                                   fd_set &/*writefds*/,
694                                   fd_set &/*exceptfds*/)
695 {
696   SnmpSynchronize _synchronize(*this); // REENTRANT
697   if (m_notify_fd != INVALID_SOCKET)
698   {
699     FD_SET(m_notify_fd, &readfds);
700     if (maxfds < SAFE_INT_CAST(m_notify_fd + 1))
701       maxfds = SAFE_INT_CAST(m_notify_fd + 1);
702   }
703   return;
704 }
705
706 int CNotifyEventQueue::HandleEvents(const int /*maxfds*/,
707                                     const fd_set &readfds,
708                                     const fd_set &/*writefds*/,
709                                     const fd_set &/*exceptfds*/)
710 {
711   SnmpSynchronize _synchronize(*this); // REENTRANT
712   int status = SNMP_CLASS_SUCCESS;
713
714   if (m_notify_fd == INVALID_SOCKET)
715     return status;
716
717   Pdu pdu;
718   SnmpTarget *target = NULL;
719
720   // pull the notifiaction off the socket
721   if (FD_ISSET(m_notify_fd, (fd_set*)&readfds)) {
722     status = receive_snmp_notification(m_notify_fd, *m_snmpSession,
723                                        pdu, &target);
724
725     if ((SNMP_CLASS_SUCCESS == status) ||
726         (SNMP_CLASS_TL_FAILED == status))
727     {
728       // If we have transport layer failure, the app will want to
729       // know about it.
730       // Go through each snmp object and check the filters, making
731       // callbacks as necessary
732
733       // On failure target will be NULL
734       if (!target)
735         target = new SnmpTarget();
736
737       CNotifyEventQueueElt *notifyEltPtr = m_head.GetNext();
738       while (notifyEltPtr)
739       {
740         notifyEltPtr->GetNotifyEvent()->Callback(*target, pdu,
741                                                  m_notify_fd, status);
742         notifyEltPtr = notifyEltPtr->GetNext();
743       } // for each snmp object
744     }
745     if (target) // receive_snmp_notification calls new
746       delete target;
747   }
748   return status;
749 }
750
751 #endif // HAVE_POLL_SYSCALL
752
753 #ifdef SNMP_PP_NAMESPACE
754 }; // end of namespace Snmp_pp
755 #endif