mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-09 10:02:07 -04:00
add file descriptor watching functions, Unix only.
This commit is contained in:
parent
309a3b5808
commit
e6c3041c28
3 changed files with 231 additions and 15 deletions
|
|
@ -15,7 +15,7 @@
|
|||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: socket.h,v 1.62 2005/10/17 03:47:10 marka Exp $ */
|
||||
/* $Id: socket.h,v 1.63 2005/12/06 16:54:49 explorer Exp $ */
|
||||
|
||||
#ifndef ISC_SOCKET_H
|
||||
#define ISC_SOCKET_H 1
|
||||
|
|
@ -143,7 +143,8 @@ struct isc_socket_connev {
|
|||
typedef enum {
|
||||
isc_sockettype_udp = 1,
|
||||
isc_sockettype_tcp = 2,
|
||||
isc_sockettype_unix = 3
|
||||
isc_sockettype_unix = 3,
|
||||
isc_sockettype_fdwatch = 4,
|
||||
} isc_sockettype_t;
|
||||
|
||||
/*@{*/
|
||||
|
|
@ -174,6 +175,14 @@ typedef enum {
|
|||
#define ISC_SOCKFLAG_NORETRY 0x00000002 /*%< drop failed UDP sends */
|
||||
/*@}*/
|
||||
|
||||
/*@{*/
|
||||
/*!
|
||||
* Flags for fdwatchcreate.
|
||||
*/
|
||||
#define ISC_SOCKFDWATCH_READ 0x00000001 /*%< watch for readable */
|
||||
#define ISC_SOCKFDWATCH_WRITE 0x00000002 /*%< watch for writable */
|
||||
/*@}*/
|
||||
|
||||
/***
|
||||
*** Socket and Socket Manager Functions
|
||||
***
|
||||
|
|
@ -181,6 +190,45 @@ typedef enum {
|
|||
*** those functions which return an isc_result.
|
||||
***/
|
||||
|
||||
isc_result_t
|
||||
isc_socket_fdwatchcreate(isc_socketmgr_t *manager,
|
||||
int fd,
|
||||
int flags,
|
||||
isc_sockfdwatch_t callback,
|
||||
void *cbarg,
|
||||
isc_task_t *task,
|
||||
isc_socket_t **socketp);
|
||||
/*%<
|
||||
* Create a new file descriptor watch socket managed by 'manager'.
|
||||
*
|
||||
* Note:
|
||||
*
|
||||
*\li 'fd' is the already-opened file descriptor.
|
||||
*\li This function is not available on Windows.
|
||||
*\li The callback function is called "in-line" - this means the function
|
||||
* needs to return as fast as possible, as all other I/O will be suspended
|
||||
* until the callback completes.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li 'manager' is a valid manager
|
||||
*
|
||||
*\li 'socketp' is a valid pointer, and *socketp == NULL
|
||||
*
|
||||
*\li 'fd' be opened.
|
||||
*
|
||||
* Ensures:
|
||||
*
|
||||
* '*socketp' is attached to the newly created fdwatch socket
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
*\li #ISC_R_SUCCESS
|
||||
*\li #ISC_R_NOMEMORY
|
||||
*\li #ISC_R_NORESOURCES
|
||||
*\li #ISC_R_UNEXPECTED
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
isc_socket_create(isc_socketmgr_t *manager,
|
||||
int pf,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: types.h,v 1.37 2005/04/29 00:23:46 marka Exp $ */
|
||||
/* $Id: types.h,v 1.38 2005/12/06 16:54:49 explorer Exp $ */
|
||||
|
||||
#ifndef ISC_TYPES_H
|
||||
#define ISC_TYPES_H 1
|
||||
|
|
@ -86,6 +86,7 @@ typedef struct isc_timer isc_timer_t; /*%< Timer */
|
|||
typedef struct isc_timermgr isc_timermgr_t; /*%< Timer Manager */
|
||||
|
||||
typedef void (*isc_taskaction_t)(isc_task_t *, isc_event_t *);
|
||||
typedef int (*isc_sockfdwatch_t)(isc_task_t *, isc_socket_t *, void *);
|
||||
|
||||
/*% Resource */
|
||||
typedef enum {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: socket.c,v 1.257 2005/11/30 03:33:49 marka Exp $ */
|
||||
/* $Id: socket.c,v 1.258 2005/12/06 16:54:49 explorer Exp $ */
|
||||
|
||||
/*! \file */
|
||||
|
||||
|
|
@ -186,6 +186,11 @@ struct isc_socket {
|
|||
ISC_SOCKADDR_LEN_T recvcmsgbuflen;
|
||||
char *sendcmsgbuf;
|
||||
ISC_SOCKADDR_LEN_T sendcmsgbuflen;
|
||||
|
||||
void *fdwatcharg;
|
||||
isc_sockfdwatch_t fdwatchcb;
|
||||
int fdwatchflags;
|
||||
isc_task_t *fdwatchtask;
|
||||
};
|
||||
|
||||
#define SOCKET_MANAGER_MAGIC ISC_MAGIC('I', 'O', 'm', 'g')
|
||||
|
|
@ -240,6 +245,8 @@ static void internal_accept(isc_task_t *, isc_event_t *);
|
|||
static void internal_connect(isc_task_t *, isc_event_t *);
|
||||
static void internal_recv(isc_task_t *, isc_event_t *);
|
||||
static void internal_send(isc_task_t *, isc_event_t *);
|
||||
static void internal_fdwatch_write(isc_task_t *, isc_event_t *);
|
||||
static void internal_fdwatch_read(isc_task_t *, isc_event_t *);
|
||||
static void process_cmsg(isc_socket_t *, struct msghdr *, isc_socketevent_t *);
|
||||
static void build_msghdr_send(isc_socket_t *, isc_socketevent_t *,
|
||||
struct msghdr *, struct iovec *, size_t *);
|
||||
|
|
@ -1393,6 +1400,9 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
|
|||
case isc_sockettype_unix:
|
||||
sock->fd = socket(pf, SOCK_STREAM, 0);
|
||||
break;
|
||||
case isc_sockettype_fdwatch:
|
||||
INSIST(type != isc_sockettype_fdwatch);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef F_DUPFD
|
||||
|
|
@ -1596,6 +1606,62 @@ isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
|
|||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new 'type' socket managed by 'manager'. Events
|
||||
* will be posted to 'task' and when dispatched 'action' will be
|
||||
* called with 'arg' as the arg value. The new socket is returned
|
||||
* in 'socketp'.
|
||||
*/
|
||||
isc_result_t
|
||||
isc_socket_fdwatchcreate(isc_socketmgr_t *manager, int fd, int flags,
|
||||
isc_sockfdwatch_t callback, void *cbarg,
|
||||
isc_task_t *task, isc_socket_t **socketp)
|
||||
{
|
||||
isc_socket_t *sock = NULL;
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(VALID_MANAGER(manager));
|
||||
REQUIRE(socketp != NULL && *socketp == NULL);
|
||||
|
||||
result = allocate_socket(manager, isc_sockettype_fdwatch, &sock);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
sock->fd = fd;
|
||||
sock->fdwatcharg = cbarg;
|
||||
sock->fdwatchcb = callback;
|
||||
sock->fdwatchflags = flags;
|
||||
sock->fdwatchtask = task;
|
||||
|
||||
sock->references = 1;
|
||||
*socketp = sock;
|
||||
|
||||
LOCK(&manager->lock);
|
||||
|
||||
/*
|
||||
* Note we don't have to lock the socket like we normally would because
|
||||
* there are no external references to it yet.
|
||||
*/
|
||||
|
||||
manager->fds[sock->fd] = sock;
|
||||
manager->fdstate[sock->fd] = MANAGED;
|
||||
ISC_LIST_APPEND(manager->socklist, sock, link);
|
||||
if (manager->maxfd < sock->fd)
|
||||
manager->maxfd = sock->fd;
|
||||
|
||||
UNLOCK(&manager->lock);
|
||||
|
||||
if (flags & ISC_SOCKFDWATCH_READ)
|
||||
select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
|
||||
if (flags & ISC_SOCKFDWATCH_WRITE)
|
||||
select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE);
|
||||
|
||||
socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
|
||||
ISC_MSG_CREATED, "fdwatch-created");
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach to a socket. Caller must explicitly detach when it is done.
|
||||
*/
|
||||
|
|
@ -1649,25 +1715,37 @@ static void
|
|||
dispatch_recv(isc_socket_t *sock) {
|
||||
intev_t *iev;
|
||||
isc_socketevent_t *ev;
|
||||
isc_task_t *sender;
|
||||
|
||||
INSIST(!sock->pending_recv);
|
||||
|
||||
ev = ISC_LIST_HEAD(sock->recv_list);
|
||||
if (ev == NULL)
|
||||
return;
|
||||
if (sock->type != isc_sockettype_fdwatch) {
|
||||
ev = ISC_LIST_HEAD(sock->recv_list);
|
||||
if (ev == NULL) {
|
||||
socket_log(sock, NULL, EVENT, NULL, 0, 0,
|
||||
"dispatch_recv: no pending reads");
|
||||
return;
|
||||
}
|
||||
socket_log(sock, NULL, EVENT, NULL, 0, 0,
|
||||
"dispatch_recv: event %p -> task %p",
|
||||
ev, ev->ev_sender);
|
||||
sender = ev->ev_sender;
|
||||
} else {
|
||||
sender = sock->fdwatchtask;
|
||||
}
|
||||
|
||||
sock->pending_recv = 1;
|
||||
iev = &sock->readable_ev;
|
||||
|
||||
socket_log(sock, NULL, EVENT, NULL, 0, 0,
|
||||
"dispatch_recv: event %p -> task %p", ev, ev->ev_sender);
|
||||
|
||||
sock->references++;
|
||||
iev->ev_sender = sock;
|
||||
iev->ev_action = internal_recv;
|
||||
if (sock->type == isc_sockettype_fdwatch)
|
||||
iev->ev_action = internal_fdwatch_read;
|
||||
else
|
||||
iev->ev_action = internal_recv;
|
||||
iev->ev_arg = sock;
|
||||
|
||||
isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
|
||||
isc_task_send(sender, (isc_event_t **)&iev);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1689,7 +1767,10 @@ dispatch_send(isc_socket_t *sock) {
|
|||
|
||||
sock->references++;
|
||||
iev->ev_sender = sock;
|
||||
iev->ev_action = internal_send;
|
||||
if (sock->type == isc_sockettype_fdwatch)
|
||||
iev->ev_action = internal_fdwatch_write;
|
||||
else
|
||||
iev->ev_action = internal_send;
|
||||
iev->ev_arg = sock;
|
||||
|
||||
isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
|
||||
|
|
@ -2144,6 +2225,86 @@ internal_send(isc_task_t *me, isc_event_t *ev) {
|
|||
UNLOCK(&sock->lock);
|
||||
}
|
||||
|
||||
static void
|
||||
internal_fdwatch_write(isc_task_t *me, isc_event_t *ev) {
|
||||
isc_socket_t *sock;
|
||||
int more_data;
|
||||
|
||||
INSIST(ev->ev_type == ISC_SOCKEVENT_INTW);
|
||||
|
||||
/*
|
||||
* Find out what socket this is and lock it.
|
||||
*/
|
||||
sock = (isc_socket_t *)ev->ev_sender;
|
||||
INSIST(VALID_SOCKET(sock));
|
||||
|
||||
LOCK(&sock->lock);
|
||||
socket_log(sock, NULL, IOEVENT,
|
||||
isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND,
|
||||
"internal_fdwatch_write: task %p got event %p", me, ev);
|
||||
|
||||
INSIST(sock->pending_send == 1);
|
||||
|
||||
UNLOCK(&sock->lock);
|
||||
more_data = (sock->fdwatchcb)(me, sock, sock->fdwatcharg);
|
||||
LOCK(&sock->lock);
|
||||
|
||||
sock->pending_send = 0;
|
||||
|
||||
INSIST(sock->references > 0);
|
||||
sock->references--; /* the internal event is done with this socket */
|
||||
if (sock->references == 0) {
|
||||
UNLOCK(&sock->lock);
|
||||
destroy(&sock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (more_data)
|
||||
select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE);
|
||||
|
||||
UNLOCK(&sock->lock);
|
||||
}
|
||||
|
||||
static void
|
||||
internal_fdwatch_read(isc_task_t *me, isc_event_t *ev) {
|
||||
isc_socket_t *sock;
|
||||
int more_data;
|
||||
|
||||
INSIST(ev->ev_type == ISC_SOCKEVENT_INTR);
|
||||
|
||||
/*
|
||||
* Find out what socket this is and lock it.
|
||||
*/
|
||||
sock = (isc_socket_t *)ev->ev_sender;
|
||||
INSIST(VALID_SOCKET(sock));
|
||||
|
||||
LOCK(&sock->lock);
|
||||
socket_log(sock, NULL, IOEVENT,
|
||||
isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV,
|
||||
"internal_fdwatch_read: task %p got event %p", me, ev);
|
||||
|
||||
INSIST(sock->pending_recv == 1);
|
||||
|
||||
UNLOCK(&sock->lock);
|
||||
more_data = (sock->fdwatchcb)(me, sock, sock->fdwatcharg);
|
||||
LOCK(&sock->lock);
|
||||
|
||||
sock->pending_recv = 0;
|
||||
|
||||
INSIST(sock->references > 0);
|
||||
sock->references--; /* the internal event is done with this socket */
|
||||
if (sock->references == 0) {
|
||||
UNLOCK(&sock->lock);
|
||||
destroy(&sock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (more_data)
|
||||
select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
|
||||
|
||||
UNLOCK(&sock->lock);
|
||||
}
|
||||
|
||||
static void
|
||||
process_fds(isc_socketmgr_t *manager, int maxfd,
|
||||
fd_set *readfds, fd_set *writefds)
|
||||
|
|
@ -2164,6 +2325,9 @@ process_fds(isc_socketmgr_t *manager, int maxfd,
|
|||
continue;
|
||||
#endif /* ISC_PLATFORM_USETHREADS */
|
||||
|
||||
/*
|
||||
* If we need to close the socket, do it now.
|
||||
*/
|
||||
if (manager->fdstate[i] == CLOSE_PENDING) {
|
||||
manager->fdstate[i] = CLOSED;
|
||||
FD_CLR(i, &manager->read_fds);
|
||||
|
|
@ -2173,6 +2337,8 @@ process_fds(isc_socketmgr_t *manager, int maxfd,
|
|||
|
||||
continue;
|
||||
}
|
||||
if (manager->fdstate[i] != MANAGED)
|
||||
continue;
|
||||
|
||||
sock = manager->fds[i];
|
||||
unlock_sock = ISC_FALSE;
|
||||
|
|
@ -2279,8 +2445,9 @@ watcher(void *uap) {
|
|||
isc_msgcat_get(isc_msgcat,
|
||||
ISC_MSGSET_SOCKET,
|
||||
ISC_MSG_WATCHERMSG,
|
||||
"watcher got message %d"),
|
||||
msg);
|
||||
"watcher got message %d"
|
||||
" for socket %d"),
|
||||
msg, fd);
|
||||
|
||||
/*
|
||||
* Nothing to read?
|
||||
|
|
|
|||
Loading…
Reference in a new issue