convert rndc and control channel to use netmgr

- updated libisccc to use netmgr events
- updated rndc to use isc_nm_tcpconnect() to establish connections
- updated control channel to use isc_nm_listentcp()

open issues:

- the control channel timeout was previously 60 seconds, but it is now
  overridden by the TCP idle timeout setting, which defaults to 30
  seconds. we should add a function that sets the timeout value for
  a specific listener socket, instead of always using the global value
  set in the netmgr. (for the moment, since 30 seconds is a reasonable
  timeout for the control channel, I'm not prioritizing this.)
- the netmgr currently has no support for UNIX-domain sockets; until
  this is addressed, it will not be possible to configure rndc to use
  them. we will need to either fix this or document the change in
  behavior.
This commit is contained in:
Evan Hunt
2020-04-16 13:06:42 -07:00
parent 002c328437
commit 3551d3ffd2
5 changed files with 430 additions and 522 deletions

View File

@@ -28,8 +28,9 @@
#include <inttypes.h>
#include <isc/mem.h>
#include <isc/netmgr.h>
#include <isc/result.h>
#include <isc/task.h>
#include <isc/string.h>
#include <isc/util.h>
#include <isccc/ccmsg.h>
@@ -39,109 +40,140 @@
#define VALID_CCMSG(foo) ISC_MAGIC_VALID(foo, CCMSG_MAGIC)
static void
recv_length(isc_task_t *, isc_event_t *);
static void
recv_message(isc_task_t *, isc_event_t *);
recv_message(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
void *arg);
static void
recv_length(isc_task_t *task, isc_event_t *ev_in) {
isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
isc_event_t *dev = NULL;
isccc_ccmsg_t *ccmsg = ev_in->ev_arg;
isc_region_t region;
recv_nonce(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
void *arg) {
isccc_ccmsg_t *ccmsg = arg;
isc_result_t result;
if (eresult == ISC_R_CANCELED || eresult == ISC_R_EOF) {
ccmsg->result = eresult;
goto done;
}
INSIST(VALID_CCMSG(ccmsg));
dev = &ccmsg->event;
if (ev->result != ISC_R_SUCCESS) {
ccmsg->result = ev->result;
goto send_and_free;
if (region == NULL && eresult == ISC_R_SUCCESS) {
ccmsg->result = ISC_R_EOF;
goto done;
} else if (eresult != ISC_R_SUCCESS) {
ccmsg->result = eresult;
goto done;
} else {
ccmsg->result = eresult;
}
/*
* Success.
*/
ccmsg->size = ntohl(ccmsg->size);
if (region->length < sizeof(uint32_t)) {
ccmsg->result = ISC_R_UNEXPECTEDEND;
goto done;
}
ccmsg->size = ntohl(*(uint32_t *)region->base);
if (ccmsg->size == 0) {
ccmsg->result = ISC_R_UNEXPECTEDEND;
goto send_and_free;
goto done;
}
if (ccmsg->size > ccmsg->maxsize) {
ccmsg->result = ISC_R_RANGE;
goto send_and_free;
goto done;
}
region.base = isc_mem_get(ccmsg->mctx, ccmsg->size);
region.length = ccmsg->size;
if (region.base == NULL) {
ccmsg->result = ISC_R_NOMEMORY;
goto send_and_free;
isc_region_consume(region, sizeof(uint32_t));
isc_buffer_allocate(ccmsg->mctx, &ccmsg->buffer, ccmsg->size);
/*
* If there's more of the message waiting, pass it to
* recv_message() directly.
*/
if (region->length != 0) {
recv_message(handle, ISC_R_SUCCESS, region, ccmsg);
return;
}
isc_buffer_init(&ccmsg->buffer, region.base, region.length);
result = isc_socket_recv(ccmsg->sock, &region, 0, task, recv_message,
ccmsg);
if (result != ISC_R_SUCCESS) {
ccmsg->result = result;
goto send_and_free;
/*
* Otherwise, continue reading and handle it in
* recv_message().
*/
result = isc_nm_read(handle, recv_message, ccmsg);
if (result == ISC_R_SUCCESS) {
return;
}
isc_event_free(&ev_in);
return;
ccmsg->result = result;
send_and_free:
isc_task_send(ccmsg->task, &dev);
ccmsg->task = NULL;
isc_event_free(&ev_in);
return;
done:
ccmsg->cb(handle, ccmsg->result, ccmsg->cbarg);
isc_nmhandle_unref(handle);
}
static void
recv_message(isc_task_t *task, isc_event_t *ev_in) {
isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
isc_event_t *dev = NULL;
isccc_ccmsg_t *ccmsg = ev_in->ev_arg;
recv_message(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
void *arg) {
isc_result_t result;
isccc_ccmsg_t *ccmsg = arg;
size_t size;
UNUSED(task);
if (eresult == ISC_R_CANCELED || eresult == ISC_R_EOF) {
ccmsg->result = eresult;
goto done;
}
INSIST(VALID_CCMSG(ccmsg));
dev = &ccmsg->event;
if (ev->result != ISC_R_SUCCESS) {
ccmsg->result = ev->result;
goto send_and_free;
if (region == NULL && eresult == ISC_R_SUCCESS) {
ccmsg->result = ISC_R_EOF;
goto done;
} else if (eresult != ISC_R_SUCCESS) {
ccmsg->result = eresult;
goto done;
} else {
ccmsg->result = eresult;
}
ccmsg->result = ISC_R_SUCCESS;
isc_buffer_add(&ccmsg->buffer, ev->n);
ccmsg->address = ev->address;
if (region->length == 0) {
ccmsg->result = ISC_R_UNEXPECTEDEND;
goto done;
}
send_and_free:
isc_task_send(ccmsg->task, &dev);
ccmsg->task = NULL;
isc_event_free(&ev_in);
size = ISC_MIN(isc_buffer_availablelength(ccmsg->buffer),
region->length);
isc_buffer_putmem(ccmsg->buffer, region->base, size);
isc_region_consume(region, size);
if (isc_buffer_usedlength(ccmsg->buffer) == ccmsg->size) {
ccmsg->result = ISC_R_SUCCESS;
goto done;
}
result = isc_nm_read(handle, recv_message, ccmsg);
if (result == ISC_R_SUCCESS) {
return;
}
ccmsg->result = result;
done:
ccmsg->cb(handle, ccmsg->result, ccmsg->cbarg);
isc_nmhandle_unref(handle);
}
void
isccc_ccmsg_init(isc_mem_t *mctx, isc_socket_t *sock, isccc_ccmsg_t *ccmsg) {
isccc_ccmsg_init(isc_mem_t *mctx, isc_nmhandle_t *handle,
isccc_ccmsg_t *ccmsg) {
REQUIRE(mctx != NULL);
REQUIRE(sock != NULL);
REQUIRE(handle != NULL);
REQUIRE(ccmsg != NULL);
*ccmsg = (isccc_ccmsg_t){
.magic = CCMSG_MAGIC,
.maxsize = 0xffffffffU, /* Largest message possible. */
.mctx = mctx,
.sock = sock,
.handle = handle,
.result = ISC_R_UNEXPECTED /* None yet. */
};
/*
* Should probably initialize the event here, but it can wait.
*/
}
void
@@ -152,37 +184,23 @@ isccc_ccmsg_setmaxsize(isccc_ccmsg_t *ccmsg, unsigned int maxsize) {
}
isc_result_t
isccc_ccmsg_readmessage(isccc_ccmsg_t *ccmsg, isc_task_t *task,
isc_taskaction_t action, void *arg) {
isccc_ccmsg_readmessage(isccc_ccmsg_t *ccmsg, isc_nm_cb_t cb, void *cbarg) {
isc_result_t result;
isc_region_t region;
REQUIRE(VALID_CCMSG(ccmsg));
REQUIRE(task != NULL);
REQUIRE(ccmsg->task == NULL); /* not currently in use */
if (ccmsg->buffer.base != NULL) {
isc_mem_put(ccmsg->mctx, ccmsg->buffer.base,
ccmsg->buffer.length);
ccmsg->buffer.base = NULL;
ccmsg->buffer.length = 0;
if (ccmsg->buffer != NULL) {
isc_buffer_free(&ccmsg->buffer);
}
ccmsg->task = task;
ccmsg->action = action;
ccmsg->arg = arg;
ccmsg->cb = cb;
ccmsg->cbarg = cbarg;
ccmsg->result = ISC_R_UNEXPECTED; /* unknown right now */
ISC_EVENT_INIT(&ccmsg->event, sizeof(isc_event_t), 0, 0,
ISCCC_EVENT_CCMSG, action, arg, ccmsg, NULL, NULL);
region.base = (unsigned char *)&ccmsg->size;
region.length = 4; /* uint32_t */
result = isc_socket_recv(ccmsg->sock, &region, 0, ccmsg->task,
recv_length, ccmsg);
isc_nmhandle_ref(ccmsg->handle);
result = isc_nm_read(ccmsg->handle, recv_nonce, ccmsg);
if (result != ISC_R_SUCCESS) {
ccmsg->task = NULL;
isc_nmhandle_unref(ccmsg->handle);
}
return (result);
@@ -192,7 +210,7 @@ void
isccc_ccmsg_cancelread(isccc_ccmsg_t *ccmsg) {
REQUIRE(VALID_CCMSG(ccmsg));
isc_socket_cancel(ccmsg->sock, NULL, ISC_SOCKCANCEL_RECV);
isc_nm_cancelread(ccmsg->handle);
}
void
@@ -201,10 +219,7 @@ isccc_ccmsg_invalidate(isccc_ccmsg_t *ccmsg) {
ccmsg->magic = 0;
if (ccmsg->buffer.base != NULL) {
isc_mem_put(ccmsg->mctx, ccmsg->buffer.base,
ccmsg->buffer.length);
ccmsg->buffer.base = NULL;
ccmsg->buffer.length = 0;
if (ccmsg->buffer != NULL) {
isc_buffer_free(&ccmsg->buffer);
}
}

View File

@@ -32,39 +32,37 @@
#include <isc/buffer.h>
#include <isc/lang.h>
#include <isc/socket.h>
#include <isc/netmgr.h>
#include <isc/sockaddr.h>
/*% ISCCC Message Structure */
typedef struct isccc_ccmsg {
/* private (don't touch!) */
unsigned int magic;
uint32_t size;
isc_buffer_t buffer;
unsigned int maxsize;
isc_mem_t * mctx;
isc_socket_t * sock;
isc_task_t * task;
isc_taskaction_t action;
void * arg;
isc_event_t event;
unsigned int magic;
uint32_t size;
isc_buffer_t * buffer;
unsigned int maxsize;
isc_mem_t * mctx;
isc_nmhandle_t *handle;
isc_nm_cb_t cb;
void * cbarg;
/* public (read-only) */
isc_result_t result;
isc_sockaddr_t address;
isc_result_t result;
} isccc_ccmsg_t;
ISC_LANG_BEGINDECLS
void
isccc_ccmsg_init(isc_mem_t *mctx, isc_socket_t *sock, isccc_ccmsg_t *ccmsg);
isccc_ccmsg_init(isc_mem_t *mctx, isc_nmhandle_t *handle, isccc_ccmsg_t *ccmsg);
/*%
* Associate a cc message state with a given memory context and
* TCP socket.
* netmgr handle.
*
* Requires:
*
*\li "mctx" and "sock" be non-NULL and valid types.
*\li "mctx" be a valid memory context.
*
*\li "sock" be a read/write TCP socket.
*\li "handle" be a netmgr handle for a stream socket.
*
*\li "ccmsg" be non-NULL and an uninitialized or invalidated structure.
*
@@ -86,8 +84,7 @@ isccc_ccmsg_setmaxsize(isccc_ccmsg_t *ccmsg, unsigned int maxsize);
*/
isc_result_t
isccc_ccmsg_readmessage(isccc_ccmsg_t *ccmsg, isc_task_t *task,
isc_taskaction_t action, void *arg);
isccc_ccmsg_readmessage(isccc_ccmsg_t *ccmsg, isc_nm_cb_t cb, void *cbarg);
/*%
* Schedule an event to be delivered when a command channel message is
* readable, or when an error occurs on the socket.
@@ -96,12 +93,10 @@ isccc_ccmsg_readmessage(isccc_ccmsg_t *ccmsg, isc_task_t *task,
*
*\li "ccmsg" be valid.
*
*\li "task", "taskaction", and "arg" be valid.
*
* Returns:
*
*\li #ISC_R_SUCCESS -- no error
*\li Anything that the isc_socket_recv() call can return. XXXMLG
*\li Anything that the isc_nm_read() call can return.
*
* Notes:
*