blob: f9cf08e8aa73aa0a18bf5ba26c4ed5bd21a9eb34 [file] [log] [blame]
/* UNIT: File Descriptor (FD) Event Manager */
#include <net-snmp/net-snmp-config.h>
#ifdef HAVE_SYS_SELECT
#include <sys/select.h>
#endif
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/net-snmp-features.h>
#include <net-snmp/library/snmp_api.h>
#include <net-snmp/library/fd_event_manager.h>
#include <net-snmp/library/snmp_logging.h>
#include <net-snmp/library/large_fd_set.h>
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 */