1 /* UNIT: File Descriptor (FD) Event Manager                              */
2 #include <net-snmp/net-snmp-config.h>
3 #ifdef HAVE_SYS_SELECT
4 #include <sys/select.h>
5 #endif
6 #include <net-snmp/net-snmp-includes.h>
7 #include <net-snmp/net-snmp-features.h>
8 #include <net-snmp/library/snmp_api.h>
9 #include <net-snmp/library/fd_event_manager.h>
10 #include <net-snmp/library/snmp_logging.h>
11 #include <net-snmp/library/large_fd_set.h>
12 
13 netsnmp_feature_child_of(fd_event_manager, libnetsnmp);
14 
15 #ifndef NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER
16 int     external_readfd[NUM_EXTERNAL_FDS],   external_readfdlen   = 0;
17 int     external_writefd[NUM_EXTERNAL_FDS],  external_writefdlen  = 0;
18 int     external_exceptfd[NUM_EXTERNAL_FDS], external_exceptfdlen = 0;
19 void  (*external_readfdfunc[NUM_EXTERNAL_FDS]) (int, void *);
20 void  (*external_writefdfunc[NUM_EXTERNAL_FDS]) (int, void *);
21 void  (*external_exceptfdfunc[NUM_EXTERNAL_FDS]) (int, void *);
22 void   *external_readfd_data[NUM_EXTERNAL_FDS];
23 void   *external_writefd_data[NUM_EXTERNAL_FDS];
24 void   *external_exceptfd_data[NUM_EXTERNAL_FDS];
25 
26 static int external_fd_unregistered;
27 
28 /*
29  * Register a given fd for read events.  Call callback when events
30  * are received.
31  */
32 int
register_readfd(int fd,void (* func)(int,void *),void * data)33 register_readfd(int fd, void (*func) (int, void *), void *data)
34 {
35     if (external_readfdlen < NUM_EXTERNAL_FDS) {
36         external_readfd[external_readfdlen] = fd;
37         external_readfdfunc[external_readfdlen] = func;
38         external_readfd_data[external_readfdlen] = data;
39         external_readfdlen++;
40         DEBUGMSGTL(("fd_event_manager:register_readfd", "registered fd %d\n", fd));
41         return FD_REGISTERED_OK;
42     } else {
43         snmp_log(LOG_CRIT, "register_readfd: too many file descriptors\n");
44         return FD_REGISTRATION_FAILED;
45     }
46 }
47 
48 /*
49  * Register a given fd for write events.  Call callback when events
50  * are received.
51  */
52 int
register_writefd(int fd,void (* func)(int,void *),void * data)53 register_writefd(int fd, void (*func) (int, void *), void *data)
54 {
55     if (external_writefdlen < NUM_EXTERNAL_FDS) {
56         external_writefd[external_writefdlen] = fd;
57         external_writefdfunc[external_writefdlen] = func;
58         external_writefd_data[external_writefdlen] = data;
59         external_writefdlen++;
60         DEBUGMSGTL(("fd_event_manager:register_writefd", "registered fd %d\n", fd));
61         return FD_REGISTERED_OK;
62     } else {
63         snmp_log(LOG_CRIT,
64                  "register_writefd: too many file descriptors\n");
65         return FD_REGISTRATION_FAILED;
66     }
67 }
68 
69 /*
70  * Register a given fd for exception events.  Call callback when events
71  * are received.
72  */
73 int
register_exceptfd(int fd,void (* func)(int,void *),void * data)74 register_exceptfd(int fd, void (*func) (int, void *), void *data)
75 {
76     if (external_exceptfdlen < NUM_EXTERNAL_FDS) {
77         external_exceptfd[external_exceptfdlen] = fd;
78         external_exceptfdfunc[external_exceptfdlen] = func;
79         external_exceptfd_data[external_exceptfdlen] = data;
80         external_exceptfdlen++;
81         DEBUGMSGTL(("fd_event_manager:register_exceptfd", "registered fd %d\n", fd));
82         return FD_REGISTERED_OK;
83     } else {
84         snmp_log(LOG_CRIT,
85                  "register_exceptfd: too many file descriptors\n");
86         return FD_REGISTRATION_FAILED;
87     }
88 }
89 
90 /*
91  * Unregister a given fd for read events.
92  */
93 int
unregister_readfd(int fd)94 unregister_readfd(int fd)
95 {
96     int             i, j;
97 
98     for (i = 0; i < external_readfdlen; i++) {
99         if (external_readfd[i] == fd) {
100             external_readfdlen--;
101             for (j = i; j < external_readfdlen; j++) {
102                 external_readfd[j] = external_readfd[j + 1];
103                 external_readfdfunc[j] = external_readfdfunc[j + 1];
104                 external_readfd_data[j] = external_readfd_data[j + 1];
105             }
106             DEBUGMSGTL(("fd_event_manager:unregister_readfd", "unregistered fd %d\n", fd));
107             external_fd_unregistered = 1;
108             return FD_UNREGISTERED_OK;
109         }
110     }
111     return FD_NO_SUCH_REGISTRATION;
112 }
113 
114 /*
115  * Unregister a given fd for read events.
116  */
117 int
unregister_writefd(int fd)118 unregister_writefd(int fd)
119 {
120     int             i, j;
121 
122     for (i = 0; i < external_writefdlen; i++) {
123         if (external_writefd[i] == fd) {
124             external_writefdlen--;
125             for (j = i; j < external_writefdlen; j++) {
126                 external_writefd[j] = external_writefd[j + 1];
127                 external_writefdfunc[j] = external_writefdfunc[j + 1];
128                 external_writefd_data[j] = external_writefd_data[j + 1];
129             }
130             DEBUGMSGTL(("fd_event_manager:unregister_writefd", "unregistered fd %d\n", fd));
131             external_fd_unregistered = 1;
132             return FD_UNREGISTERED_OK;
133         }
134     }
135     return FD_NO_SUCH_REGISTRATION;
136 }
137 
138 /*
139  * Unregister a given fd for exception events.
140  */
141 int
unregister_exceptfd(int fd)142 unregister_exceptfd(int fd)
143 {
144     int             i, j;
145 
146     for (i = 0; i < external_exceptfdlen; i++) {
147         if (external_exceptfd[i] == fd) {
148             external_exceptfdlen--;
149             for (j = i; j < external_exceptfdlen; j++) {
150                 external_exceptfd[j] = external_exceptfd[j + 1];
151                 external_exceptfdfunc[j] = external_exceptfdfunc[j + 1];
152                 external_exceptfd_data[j] = external_exceptfd_data[j + 1];
153             }
154             DEBUGMSGTL(("fd_event_manager:unregister_exceptfd", "unregistered fd %d\n",
155                         fd));
156             external_fd_unregistered = 1;
157             return FD_UNREGISTERED_OK;
158         }
159     }
160     return FD_NO_SUCH_REGISTRATION;
161 }
162 
163 /*
164  * NET-SNMP External Event Info
165  */
netsnmp_external_event_info(int * numfds,fd_set * readfds,fd_set * writefds,fd_set * exceptfds)166 void netsnmp_external_event_info(int *numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
167 {
168   netsnmp_large_fd_set lreadfds;
169   netsnmp_large_fd_set lwritefds;
170   netsnmp_large_fd_set lexceptfds;
171 
172   netsnmp_large_fd_set_init(&lreadfds, FD_SETSIZE);
173   netsnmp_large_fd_set_init(&lwritefds, FD_SETSIZE);
174   netsnmp_large_fd_set_init(&lexceptfds, FD_SETSIZE);
175 
176   netsnmp_copy_fd_set_to_large_fd_set(&lreadfds, readfds);
177   netsnmp_copy_fd_set_to_large_fd_set(&lwritefds, writefds);
178   netsnmp_copy_fd_set_to_large_fd_set(&lexceptfds, exceptfds);
179 
180   netsnmp_external_event_info2(numfds, &lreadfds, &lwritefds, &lexceptfds);
181 
182   if (netsnmp_copy_large_fd_set_to_fd_set(readfds, &lreadfds) < 0
183       || netsnmp_copy_large_fd_set_to_fd_set(writefds, &lwritefds) < 0
184       || netsnmp_copy_large_fd_set_to_fd_set(exceptfds, &lexceptfds) < 0)
185   {
186     snmp_log(LOG_ERR,
187 	     "Use netsnmp_external_event_info2() for processing"
188 	     " large file descriptors\n");
189   }
190 
191   netsnmp_large_fd_set_cleanup(&lreadfds);
192   netsnmp_large_fd_set_cleanup(&lwritefds);
193   netsnmp_large_fd_set_cleanup(&lexceptfds);
194 }
195 
netsnmp_external_event_info2(int * numfds,netsnmp_large_fd_set * readfds,netsnmp_large_fd_set * writefds,netsnmp_large_fd_set * exceptfds)196 void netsnmp_external_event_info2(int *numfds,
197                                   netsnmp_large_fd_set *readfds,
198                                   netsnmp_large_fd_set *writefds,
199                                   netsnmp_large_fd_set *exceptfds)
200 {
201   int i;
202 
203   external_fd_unregistered = 0;
204 
205   for (i = 0; i < external_readfdlen; i++) {
206     NETSNMP_LARGE_FD_SET(external_readfd[i], readfds);
207     if (external_readfd[i] >= *numfds)
208       *numfds = external_readfd[i] + 1;
209   }
210   for (i = 0; i < external_writefdlen; i++) {
211     NETSNMP_LARGE_FD_SET(external_writefd[i], writefds);
212     if (external_writefd[i] >= *numfds)
213       *numfds = external_writefd[i] + 1;
214   }
215   for (i = 0; i < external_exceptfdlen; i++) {
216     NETSNMP_LARGE_FD_SET(external_exceptfd[i], exceptfds);
217     if (external_exceptfd[i] >= *numfds)
218       *numfds = external_exceptfd[i] + 1;
219   }
220 }
221 
222 /*
223  * NET-SNMP Dispatch External Events
224  */
netsnmp_dispatch_external_events(int * count,fd_set * readfds,fd_set * writefds,fd_set * exceptfds)225 void netsnmp_dispatch_external_events(int *count, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
226 {
227   netsnmp_large_fd_set lreadfds;
228   netsnmp_large_fd_set lwritefds;
229   netsnmp_large_fd_set lexceptfds;
230 
231   netsnmp_large_fd_set_init(&lreadfds, FD_SETSIZE);
232   netsnmp_large_fd_set_init(&lwritefds, FD_SETSIZE);
233   netsnmp_large_fd_set_init(&lexceptfds, FD_SETSIZE);
234 
235   netsnmp_copy_fd_set_to_large_fd_set(&lreadfds, readfds);
236   netsnmp_copy_fd_set_to_large_fd_set(&lwritefds, writefds);
237   netsnmp_copy_fd_set_to_large_fd_set(&lexceptfds, exceptfds);
238 
239   netsnmp_dispatch_external_events2(count, &lreadfds, &lwritefds, &lexceptfds);
240 
241   if (netsnmp_copy_large_fd_set_to_fd_set(readfds, &lreadfds) < 0
242       || netsnmp_copy_large_fd_set_to_fd_set(writefds,  &lwritefds) < 0
243       || netsnmp_copy_large_fd_set_to_fd_set(exceptfds, &lexceptfds) < 0)
244   {
245     snmp_log(LOG_ERR,
246 	     "Use netsnmp_dispatch_external_events2() for processing"
247 	     " large file descriptors\n");
248   }
249 
250   netsnmp_large_fd_set_cleanup(&lreadfds);
251   netsnmp_large_fd_set_cleanup(&lwritefds);
252   netsnmp_large_fd_set_cleanup(&lexceptfds);
253 }
254 
netsnmp_dispatch_external_events2(int * count,netsnmp_large_fd_set * readfds,netsnmp_large_fd_set * writefds,netsnmp_large_fd_set * exceptfds)255 void netsnmp_dispatch_external_events2(int *count,
256                                        netsnmp_large_fd_set *readfds,
257                                        netsnmp_large_fd_set *writefds,
258                                        netsnmp_large_fd_set *exceptfds)
259 {
260   int i;
261   for (i = 0;
262        *count && (i < external_readfdlen) && !external_fd_unregistered; i++) {
263       if (NETSNMP_LARGE_FD_ISSET(external_readfd[i], readfds)) {
264           DEBUGMSGTL(("fd_event_manager:netsnmp_dispatch_external_events",
265                      "readfd[%d] = %d\n", i, external_readfd[i]));
266           external_readfdfunc[i] (external_readfd[i],
267                                   external_readfd_data[i]);
268           NETSNMP_LARGE_FD_CLR(external_readfd[i], readfds);
269           (*count)--;
270       }
271   }
272   for (i = 0;
273        *count && (i < external_writefdlen) && !external_fd_unregistered; i++) {
274       if (NETSNMP_LARGE_FD_ISSET(external_writefd[i], writefds)) {
275           DEBUGMSGTL(("fd_event_manager:netsnmp_dispatch_external_events",
276                      "writefd[%d] = %d\n", i, external_writefd[i]));
277           external_writefdfunc[i] (external_writefd[i],
278                                    external_writefd_data[i]);
279           NETSNMP_LARGE_FD_CLR(external_writefd[i], writefds);
280           (*count)--;
281       }
282   }
283   for (i = 0;
284        *count && (i < external_exceptfdlen) && !external_fd_unregistered; i++) {
285       if (NETSNMP_LARGE_FD_ISSET(external_exceptfd[i], exceptfds)) {
286           DEBUGMSGTL(("fd_event_manager:netsnmp_dispatch_external_events",
287                      "exceptfd[%d] = %d\n", i, external_exceptfd[i]));
288           external_exceptfdfunc[i] (external_exceptfd[i],
289                                     external_exceptfd_data[i]);
290           NETSNMP_LARGE_FD_CLR(external_exceptfd[i], exceptfds);
291           (*count)--;
292       }
293   }
294 }
295 #else  /*  !NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER */
296 netsnmp_feature_unused(fd_event_manager);
297 #endif /*  !NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER */
298