/* UNIT: File Descriptor (FD) Event Manager */ #include #ifdef HAVE_SYS_SELECT #include #endif #include #include #include #include #include #include netsnmp_feature_child_of(fd_event_manager, libnetsnmp) #ifndef NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER int external_readfd[NUM_EXTERNAL_FDS], external_readfdlen = 0; int external_writefd[NUM_EXTERNAL_FDS], external_writefdlen = 0; int external_exceptfd[NUM_EXTERNAL_FDS], external_exceptfdlen = 0; void (*external_readfdfunc[NUM_EXTERNAL_FDS]) (int, void *); void (*external_writefdfunc[NUM_EXTERNAL_FDS]) (int, void *); void (*external_exceptfdfunc[NUM_EXTERNAL_FDS]) (int, void *); void *external_readfd_data[NUM_EXTERNAL_FDS]; void *external_writefd_data[NUM_EXTERNAL_FDS]; void *external_exceptfd_data[NUM_EXTERNAL_FDS]; static int external_fd_unregistered; /* * Register a given fd for read events. Call callback when events * are received. */ int register_readfd(int fd, void (*func) (int, void *), void *data) { if (external_readfdlen < NUM_EXTERNAL_FDS) { external_readfd[external_readfdlen] = fd; external_readfdfunc[external_readfdlen] = func; external_readfd_data[external_readfdlen] = data; external_readfdlen++; DEBUGMSGTL(("fd_event_manager:register_readfd", "registered fd %d\n", fd)); return FD_REGISTERED_OK; } else { snmp_log(LOG_CRIT, "register_readfd: too many file descriptors\n"); return FD_REGISTRATION_FAILED; } } /* * Register a given fd for write events. Call callback when events * are received. */ int register_writefd(int fd, void (*func) (int, void *), void *data) { if (external_writefdlen < NUM_EXTERNAL_FDS) { external_writefd[external_writefdlen] = fd; external_writefdfunc[external_writefdlen] = func; external_writefd_data[external_writefdlen] = data; external_writefdlen++; DEBUGMSGTL(("fd_event_manager:register_writefd", "registered fd %d\n", fd)); return FD_REGISTERED_OK; } else { snmp_log(LOG_CRIT, "register_writefd: too many file descriptors\n"); return FD_REGISTRATION_FAILED; } } /* * Register a given fd for exception events. Call callback when events * are received. */ int register_exceptfd(int fd, void (*func) (int, void *), void *data) { if (external_exceptfdlen < NUM_EXTERNAL_FDS) { external_exceptfd[external_exceptfdlen] = fd; external_exceptfdfunc[external_exceptfdlen] = func; external_exceptfd_data[external_exceptfdlen] = data; external_exceptfdlen++; DEBUGMSGTL(("fd_event_manager:register_exceptfd", "registered fd %d\n", fd)); return FD_REGISTERED_OK; } else { snmp_log(LOG_CRIT, "register_exceptfd: too many file descriptors\n"); return FD_REGISTRATION_FAILED; } } /* * Unregister a given fd for read events. */ int unregister_readfd(int fd) { int i, j; for (i = 0; i < external_readfdlen; i++) { if (external_readfd[i] == fd) { external_readfdlen--; for (j = i; j < external_readfdlen; j++) { external_readfd[j] = external_readfd[j + 1]; external_readfdfunc[j] = external_readfdfunc[j + 1]; external_readfd_data[j] = external_readfd_data[j + 1]; } DEBUGMSGTL(("fd_event_manager:unregister_readfd", "unregistered fd %d\n", fd)); external_fd_unregistered = 1; return FD_UNREGISTERED_OK; } } return FD_NO_SUCH_REGISTRATION; } /* * Unregister a given fd for read events. */ int unregister_writefd(int fd) { int i, j; for (i = 0; i < external_writefdlen; i++) { if (external_writefd[i] == fd) { external_writefdlen--; for (j = i; j < external_writefdlen; j++) { external_writefd[j] = external_writefd[j + 1]; external_writefdfunc[j] = external_writefdfunc[j + 1]; external_writefd_data[j] = external_writefd_data[j + 1]; } DEBUGMSGTL(("fd_event_manager:unregister_writefd", "unregistered fd %d\n", fd)); external_fd_unregistered = 1; return FD_UNREGISTERED_OK; } } return FD_NO_SUCH_REGISTRATION; } /* * Unregister a given fd for exception events. */ int unregister_exceptfd(int fd) { int i, j; for (i = 0; i < external_exceptfdlen; i++) { if (external_exceptfd[i] == fd) { external_exceptfdlen--; for (j = i; j < external_exceptfdlen; j++) { external_exceptfd[j] = external_exceptfd[j + 1]; external_exceptfdfunc[j] = external_exceptfdfunc[j + 1]; external_exceptfd_data[j] = external_exceptfd_data[j + 1]; } DEBUGMSGTL(("fd_event_manager:unregister_exceptfd", "unregistered fd %d\n", fd)); external_fd_unregistered = 1; return FD_UNREGISTERED_OK; } } return FD_NO_SUCH_REGISTRATION; } /* * NET-SNMP External Event Info */ void netsnmp_external_event_info(int *numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds) { netsnmp_large_fd_set lreadfds; netsnmp_large_fd_set lwritefds; netsnmp_large_fd_set lexceptfds; netsnmp_large_fd_set_init(&lreadfds, FD_SETSIZE); netsnmp_large_fd_set_init(&lwritefds, FD_SETSIZE); netsnmp_large_fd_set_init(&lexceptfds, FD_SETSIZE); netsnmp_copy_fd_set_to_large_fd_set(&lreadfds, readfds); netsnmp_copy_fd_set_to_large_fd_set(&lwritefds, writefds); netsnmp_copy_fd_set_to_large_fd_set(&lexceptfds, exceptfds); netsnmp_external_event_info2(numfds, &lreadfds, &lwritefds, &lexceptfds); if (netsnmp_copy_large_fd_set_to_fd_set(readfds, &lreadfds) < 0 || netsnmp_copy_large_fd_set_to_fd_set(writefds, &lwritefds) < 0 || netsnmp_copy_large_fd_set_to_fd_set(exceptfds, &lexceptfds) < 0) { snmp_log(LOG_ERR, "Use netsnmp_external_event_info2() for processing" " large file descriptors\n"); } netsnmp_large_fd_set_cleanup(&lreadfds); netsnmp_large_fd_set_cleanup(&lwritefds); netsnmp_large_fd_set_cleanup(&lexceptfds); } void netsnmp_external_event_info2(int *numfds, netsnmp_large_fd_set *readfds, netsnmp_large_fd_set *writefds, netsnmp_large_fd_set *exceptfds) { int i; external_fd_unregistered = 0; for (i = 0; i < external_readfdlen; i++) { NETSNMP_LARGE_FD_SET(external_readfd[i], readfds); if (external_readfd[i] >= *numfds) *numfds = external_readfd[i] + 1; } for (i = 0; i < external_writefdlen; i++) { NETSNMP_LARGE_FD_SET(external_writefd[i], writefds); if (external_writefd[i] >= *numfds) *numfds = external_writefd[i] + 1; } for (i = 0; i < external_exceptfdlen; i++) { NETSNMP_LARGE_FD_SET(external_exceptfd[i], exceptfds); if (external_exceptfd[i] >= *numfds) *numfds = external_exceptfd[i] + 1; } } /* * NET-SNMP Dispatch External Events */ void netsnmp_dispatch_external_events(int *count, fd_set *readfds, fd_set *writefds, fd_set *exceptfds) { netsnmp_large_fd_set lreadfds; netsnmp_large_fd_set lwritefds; netsnmp_large_fd_set lexceptfds; netsnmp_large_fd_set_init(&lreadfds, FD_SETSIZE); netsnmp_large_fd_set_init(&lwritefds, FD_SETSIZE); netsnmp_large_fd_set_init(&lexceptfds, FD_SETSIZE); netsnmp_copy_fd_set_to_large_fd_set(&lreadfds, readfds); netsnmp_copy_fd_set_to_large_fd_set(&lwritefds, writefds); netsnmp_copy_fd_set_to_large_fd_set(&lexceptfds, exceptfds); netsnmp_dispatch_external_events2(count, &lreadfds, &lwritefds, &lexceptfds); if (netsnmp_copy_large_fd_set_to_fd_set(readfds, &lreadfds) < 0 || netsnmp_copy_large_fd_set_to_fd_set(writefds, &lwritefds) < 0 || netsnmp_copy_large_fd_set_to_fd_set(exceptfds, &lexceptfds) < 0) { snmp_log(LOG_ERR, "Use netsnmp_dispatch_external_events2() for processing" " large file descriptors\n"); } netsnmp_large_fd_set_cleanup(&lreadfds); netsnmp_large_fd_set_cleanup(&lwritefds); netsnmp_large_fd_set_cleanup(&lexceptfds); } void netsnmp_dispatch_external_events2(int *count, netsnmp_large_fd_set *readfds, netsnmp_large_fd_set *writefds, netsnmp_large_fd_set *exceptfds) { int i; for (i = 0; *count && (i < external_readfdlen) && !external_fd_unregistered; i++) { if (NETSNMP_LARGE_FD_ISSET(external_readfd[i], readfds)) { DEBUGMSGTL(("fd_event_manager:netsnmp_dispatch_external_events", "readfd[%d] = %d\n", i, external_readfd[i])); external_readfdfunc[i] (external_readfd[i], external_readfd_data[i]); NETSNMP_LARGE_FD_CLR(external_readfd[i], readfds); (*count)--; } } for (i = 0; *count && (i < external_writefdlen) && !external_fd_unregistered; i++) { if (NETSNMP_LARGE_FD_ISSET(external_writefd[i], writefds)) { DEBUGMSGTL(("fd_event_manager:netsnmp_dispatch_external_events", "writefd[%d] = %d\n", i, external_writefd[i])); external_writefdfunc[i] (external_writefd[i], external_writefd_data[i]); NETSNMP_LARGE_FD_CLR(external_writefd[i], writefds); (*count)--; } } for (i = 0; *count && (i < external_exceptfdlen) && !external_fd_unregistered; i++) { if (NETSNMP_LARGE_FD_ISSET(external_exceptfd[i], exceptfds)) { DEBUGMSGTL(("fd_event_manager:netsnmp_dispatch_external_events", "exceptfd[%d] = %d\n", i, external_exceptfd[i])); external_exceptfdfunc[i] (external_exceptfd[i], external_exceptfd_data[i]); NETSNMP_LARGE_FD_CLR(external_exceptfd[i], exceptfds); (*count)--; } } } #else /* !NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER */ netsnmp_feature_unused(fd_event_manager); #endif /* !NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER */