mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
serialize, deserialize, raw commpoints.
case preserve note. git-svn-id: file:///svn/unbound/trunk@881 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
c7ad292438
commit
05f9d35f00
9 changed files with 574 additions and 42 deletions
|
|
@ -1,3 +1,6 @@
|
||||||
|
21 January 2008: Wouter
|
||||||
|
- libworker work, netevent raw commpoints, write_msg, serialize.
|
||||||
|
|
||||||
18 January 2008: Wouter
|
18 January 2008: Wouter
|
||||||
- touch up of manpage for libunbound.
|
- touch up of manpage for libunbound.
|
||||||
- support for IP_RECVDSTADDR (for *BSD ip4).
|
- support for IP_RECVDSTADDR (for *BSD ip4).
|
||||||
|
|
|
||||||
|
|
@ -200,3 +200,9 @@ o If a client makes a query without RD bit, in the case of a returned
|
||||||
ascertains that RRSIGs are OK (and not omitted), but does not
|
ascertains that RRSIGs are OK (and not omitted), but does not
|
||||||
check NSEC/NSEC3.
|
check NSEC/NSEC3.
|
||||||
|
|
||||||
|
o Case preservation
|
||||||
|
Unbound preserves the casing received from authority servers as best
|
||||||
|
as possible. It compresses without case, so case can get lost there.
|
||||||
|
The casing from the authority server is used in preference to the casing
|
||||||
|
of the query name. This is different from BIND. RFC4343 allows either
|
||||||
|
behaviour.
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
#include "libunbound/context.h"
|
#include "libunbound/context.h"
|
||||||
#include "util/module.h"
|
#include "util/module.h"
|
||||||
#include "util/config_file.h"
|
#include "util/config_file.h"
|
||||||
|
#include "util/net_help.h"
|
||||||
#include "services/modstack.h"
|
#include "services/modstack.h"
|
||||||
#include "services/localzone.h"
|
#include "services/localzone.h"
|
||||||
#include "services/cache/rrset.h"
|
#include "services/cache/rrset.h"
|
||||||
|
|
@ -183,3 +184,158 @@ context_release_alloc(struct ub_val_ctx* ctx, struct alloc_cache* alloc)
|
||||||
ctx->alloc_list = alloc;
|
ctx->alloc_list = alloc;
|
||||||
lock_basic_unlock(&ctx->cfglock);
|
lock_basic_unlock(&ctx->cfglock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t*
|
||||||
|
context_serialize_new_query(struct ctx_query* q, uint32_t* len)
|
||||||
|
{
|
||||||
|
/* format for new query is
|
||||||
|
* o uint32 cmd
|
||||||
|
* o uint32 id
|
||||||
|
* o uint32 type
|
||||||
|
* o uint32 class
|
||||||
|
* o rest queryname (string)
|
||||||
|
*/
|
||||||
|
uint8_t* p;
|
||||||
|
size_t slen = strlen(q->res->qname) + 1/*end of string*/;
|
||||||
|
*len = sizeof(uint32_t)*4 + slen;
|
||||||
|
p = (uint8_t*)malloc(*len);
|
||||||
|
if(!p) return NULL;
|
||||||
|
ldns_write_uint32(p, UB_LIBCMD_NEWQUERY);
|
||||||
|
ldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
|
||||||
|
ldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)q->res->qtype);
|
||||||
|
ldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->res->qclass);
|
||||||
|
memmove(p+4*sizeof(uint32_t), q->res->qname, slen);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ctx_query*
|
||||||
|
context_deserialize_new_query(struct ub_val_ctx* ctx, uint8_t* p, uint32_t len)
|
||||||
|
{
|
||||||
|
struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q));
|
||||||
|
if(!q) return NULL;
|
||||||
|
if(len < 4*sizeof(uint32_t)+1) {
|
||||||
|
free(q);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
log_assert( ldns_read_uint32(p) == UB_LIBCMD_NEWQUERY);
|
||||||
|
q->querynum = (int)ldns_read_uint32(p+sizeof(uint32_t));
|
||||||
|
q->node.key = &q->querynum;
|
||||||
|
q->async = 1;
|
||||||
|
q->res = (struct ub_val_result*)calloc(1, sizeof(*q->res));
|
||||||
|
if(!q->res) {
|
||||||
|
free(q);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
q->res->qtype = (int)ldns_read_uint32(p+2*sizeof(uint32_t));
|
||||||
|
q->res->qclass = (int)ldns_read_uint32(p+3*sizeof(uint32_t));
|
||||||
|
q->res->qname = strdup((char*)(p+4*sizeof(uint32_t)));
|
||||||
|
if(!q->res->qname) {
|
||||||
|
free(q->res);
|
||||||
|
free(q);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** add to query list */
|
||||||
|
ctx->num_async++;
|
||||||
|
(void)rbtree_insert(&ctx->queries, &q->node);
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t*
|
||||||
|
context_serialize_answer(struct ctx_query* q, int err, uint32_t* len)
|
||||||
|
{
|
||||||
|
/* answer format
|
||||||
|
* o uint32 cmd
|
||||||
|
* o uint32 id
|
||||||
|
* o uint32 error_code
|
||||||
|
* o uint32 msg_security
|
||||||
|
* o the remainder is the answer msg from resolver lookup.
|
||||||
|
* remainder can be length 0.
|
||||||
|
*/
|
||||||
|
uint8_t* p;
|
||||||
|
*len = sizeof(uint32_t)*4 + q->msg_len;
|
||||||
|
p = (uint8_t*)malloc(*len);
|
||||||
|
if(!p) return NULL;
|
||||||
|
ldns_write_uint32(p, UB_LIBCMD_ANSWER);
|
||||||
|
ldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
|
||||||
|
ldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)err);
|
||||||
|
ldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->msg_security);
|
||||||
|
memmove(p+4*sizeof(uint32_t), q->msg, q->msg_len);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ctx_query*
|
||||||
|
context_deserialize_answer(struct ub_val_ctx* ctx,
|
||||||
|
uint8_t* p, uint32_t len, int* err)
|
||||||
|
{
|
||||||
|
struct ctx_query* q = NULL ;
|
||||||
|
int id;
|
||||||
|
if(len < 4*sizeof(uint32_t)) return NULL;
|
||||||
|
log_assert( ldns_read_uint32(p) == UB_LIBCMD_ANSWER);
|
||||||
|
id = (int)ldns_read_uint32(p+sizeof(uint32_t));
|
||||||
|
q = (struct ctx_query*)rbtree_search(&ctx->queries, &id);
|
||||||
|
if(!q) return NULL;
|
||||||
|
*err = (int)ldns_read_uint32(p+2*sizeof(uint32_t));
|
||||||
|
q->msg_security = ldns_read_uint32(p+3*sizeof(uint32_t));
|
||||||
|
if(len > 4*sizeof(uint32_t)) {
|
||||||
|
q->msg_len = len - 4*sizeof(uint32_t);
|
||||||
|
q->msg = (uint8_t*)memdup(p+4*sizeof(uint32_t), q->msg_len);
|
||||||
|
if(!q->msg) {
|
||||||
|
/* pass malloc failure to the user callback */
|
||||||
|
q->msg_len = 0;
|
||||||
|
*err = UB_NOMEM;
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
q->msg_len = 0;
|
||||||
|
free(q->msg);
|
||||||
|
q->msg = NULL;
|
||||||
|
}
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t*
|
||||||
|
context_serialize_cancel(struct ctx_query* q, uint32_t* len)
|
||||||
|
{
|
||||||
|
/* format of cancel:
|
||||||
|
* o uint32 cmd
|
||||||
|
* o uint32 async-id */
|
||||||
|
uint8_t* p = (uint8_t*)malloc(2*sizeof(uint32_t));
|
||||||
|
if(!p) return NULL;
|
||||||
|
*len = 2*sizeof(uint32_t);
|
||||||
|
ldns_write_uint32(p, UB_LIBCMD_CANCEL);
|
||||||
|
ldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ctx_query* context_deserialize_cancel(struct ub_val_ctx* ctx,
|
||||||
|
uint8_t* p, uint32_t len)
|
||||||
|
{
|
||||||
|
struct ctx_query* q;
|
||||||
|
int id;
|
||||||
|
if(len != 2*sizeof(uint32_t)) return NULL;
|
||||||
|
log_assert( ldns_read_uint32(p) == UB_LIBCMD_CANCEL);
|
||||||
|
id = (int)ldns_read_uint32(p+sizeof(uint32_t));
|
||||||
|
q = (struct ctx_query*)rbtree_search(&ctx->queries, &id);
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t*
|
||||||
|
context_serialize_quit(uint32_t* len)
|
||||||
|
{
|
||||||
|
uint8_t* p = (uint8_t*)malloc(sizeof(uint32_t));
|
||||||
|
if(!p)
|
||||||
|
return NULL;
|
||||||
|
*len = sizeof(uint32_t);
|
||||||
|
ldns_write_uint32(p, UB_LIBCMD_QUIT);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len)
|
||||||
|
{
|
||||||
|
uint32_t v;
|
||||||
|
if((size_t)len < sizeof(v))
|
||||||
|
return UB_LIBCMD_QUIT;
|
||||||
|
v = ldns_read_uint32(p);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,8 @@ struct ctx_query {
|
||||||
int querynum;
|
int querynum;
|
||||||
/** was this an async query? */
|
/** was this an async query? */
|
||||||
int async;
|
int async;
|
||||||
|
/** has this query been cancelled? (for bg thread) */
|
||||||
|
int cancelled;
|
||||||
|
|
||||||
/** for async query, the callback function */
|
/** for async query, the callback function */
|
||||||
ub_val_callback_t cb;
|
ub_val_callback_t cb;
|
||||||
|
|
@ -171,6 +173,25 @@ enum ub_ctx_err {
|
||||||
UB_INITFAIL = -7
|
UB_INITFAIL = -7
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command codes for libunbound pipe.
|
||||||
|
*
|
||||||
|
* Serialization looks like this:
|
||||||
|
* o length (of remainder) uint32.
|
||||||
|
* o uint32 command code.
|
||||||
|
* o per command format.
|
||||||
|
*/
|
||||||
|
enum ub_ctx_cmd {
|
||||||
|
/** QUIT */
|
||||||
|
UB_LIBCMD_QUIT = 0,
|
||||||
|
/** New query, sent to bg worker */
|
||||||
|
UB_LIBCMD_NEWQUERY,
|
||||||
|
/** Cancel query, sent to bg worker */
|
||||||
|
UB_LIBCMD_CANCEL,
|
||||||
|
/** Query result, originates from bg worker */
|
||||||
|
UB_LIBCMD_ANSWER
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* finalize a context.
|
* finalize a context.
|
||||||
* @param ctx: context to finalize. creates shared data.
|
* @param ctx: context to finalize. creates shared data.
|
||||||
|
|
@ -208,4 +229,80 @@ struct alloc_cache* context_obtain_alloc(struct ub_val_ctx* ctx);
|
||||||
*/
|
*/
|
||||||
void context_release_alloc(struct ub_val_ctx* ctx, struct alloc_cache* alloc);
|
void context_release_alloc(struct ub_val_ctx* ctx, struct alloc_cache* alloc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize a context query that questions data.
|
||||||
|
* This serializes the query name, type, ...
|
||||||
|
* As well as command code 'new_query'.
|
||||||
|
* @param q: context query
|
||||||
|
* @param len: the length of the allocation is returned.
|
||||||
|
* @return: an alloc, or NULL on mem error.
|
||||||
|
*/
|
||||||
|
uint8_t* context_serialize_new_query(struct ctx_query* q, uint32_t* len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize a context_query result to hand back to user.
|
||||||
|
* This serializes the query name, type, ..., and result.
|
||||||
|
* As well as command code 'answer'.
|
||||||
|
* @param q: context query
|
||||||
|
* @param err: error code to pass to client.
|
||||||
|
* @param len: the length of the allocation is returned.
|
||||||
|
* @return: an alloc, or NULL on mem error.
|
||||||
|
*/
|
||||||
|
uint8_t* context_serialize_answer(struct ctx_query* q, int err, uint32_t* len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize a query cancellation. Serializes query async id
|
||||||
|
* as well as command code 'cancel'
|
||||||
|
* @param q: context query
|
||||||
|
* @param len: the length of the allocation is returned.
|
||||||
|
* @return: an alloc, or NULL on mem error.
|
||||||
|
*/
|
||||||
|
uint8_t* context_serialize_cancel(struct ctx_query* q, uint32_t* len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize a 'quit' command.
|
||||||
|
* @param len: the length of the allocation is returned.
|
||||||
|
* @return: an alloc, or NULL on mem error.
|
||||||
|
*/
|
||||||
|
uint8_t* context_serialize_quit(uint32_t* len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain command code from serialized buffer
|
||||||
|
* @param p: buffer serialized.
|
||||||
|
* @param len: length of buffer.
|
||||||
|
* @return command code or QUIT on error.
|
||||||
|
*/
|
||||||
|
enum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize a new_query buffer.
|
||||||
|
* @param ctx: context
|
||||||
|
* @param p: buffer serialized.
|
||||||
|
* @param len: length of buffer.
|
||||||
|
* @return new ctx_query or NULL for malloc failure.
|
||||||
|
*/
|
||||||
|
struct ctx_query* context_deserialize_new_query(struct ub_val_ctx* ctx,
|
||||||
|
uint8_t* p, uint32_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize an answer buffer.
|
||||||
|
* @param ctx: context
|
||||||
|
* @param p: buffer serialized.
|
||||||
|
* @param len: length of buffer.
|
||||||
|
* @param err: error code to be returned to client is passed.
|
||||||
|
* @return ctx_query with answer added or NULL for malloc failure.
|
||||||
|
*/
|
||||||
|
struct ctx_query* context_deserialize_answer(struct ub_val_ctx* ctx,
|
||||||
|
uint8_t* p, uint32_t len, int* err);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize a cancel buffer.
|
||||||
|
* @param ctx: context
|
||||||
|
* @param p: buffer serialized.
|
||||||
|
* @param len: length of buffer.
|
||||||
|
* @return ctx_query to cancel or NULL for failure.
|
||||||
|
*/
|
||||||
|
struct ctx_query* context_deserialize_cancel(struct ub_val_ctx* ctx,
|
||||||
|
uint8_t* p, uint32_t len);
|
||||||
|
|
||||||
#endif /* LIBUNBOUND_CONTEXT_H */
|
#endif /* LIBUNBOUND_CONTEXT_H */
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,9 @@
|
||||||
/** size of table used for random numbers. large to be more secure. */
|
/** size of table used for random numbers. large to be more secure. */
|
||||||
#define RND_STATE_SIZE 256
|
#define RND_STATE_SIZE 256
|
||||||
|
|
||||||
|
/** handle new query command for bg worker */
|
||||||
|
static void handle_newq(struct libworker* w, uint8_t* buf, uint32_t len);
|
||||||
|
|
||||||
/** delete libworker struct */
|
/** delete libworker struct */
|
||||||
static void
|
static void
|
||||||
libworker_delete(struct libworker* w)
|
libworker_delete(struct libworker* w)
|
||||||
|
|
@ -155,51 +158,89 @@ libworker_setup(struct ub_val_ctx* ctx)
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
/** handle cancel command for bg worker */
|
||||||
|
static void
|
||||||
|
handle_cancel(struct libworker* w, uint8_t* buf, uint32_t len)
|
||||||
|
{
|
||||||
|
struct ctx_query* q = context_deserialize_cancel(w->ctx, buf, len);
|
||||||
|
if(!q) {
|
||||||
|
log_err("deserialize cancel failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
q->cancelled = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** handle control command coming into server */
|
||||||
|
int
|
||||||
libworker_handle_control_cmd(struct comm_point* c, void* arg,
|
libworker_handle_control_cmd(struct comm_point* c, void* arg,
|
||||||
int err, struct comm_reply* ATTR_UNUSED(rep))
|
int ATTR_UNUSED(err), struct comm_reply* ATTR_UNUSED(rep))
|
||||||
{
|
{
|
||||||
/*struct ub_val_ctx* ctx = (struct ub_val_ctx*)arg;*/
|
struct libworker* w = (struct libworker*)arg;
|
||||||
if(err != NETEVENT_NOERROR) {
|
uint32_t len = 0;
|
||||||
if(err == NETEVENT_CLOSED) {
|
uint8_t* buf = NULL;
|
||||||
/* parent closed pipe, must have exited somehow */
|
int r = libworker_read_msg(c->fd, &buf, &len, 1);
|
||||||
/* it is of no use to go on, exit */
|
if(r==0) {
|
||||||
exit(0);
|
/* error has happened or */
|
||||||
}
|
/* parent closed pipe, must have exited somehow */
|
||||||
log_err("internal error: control cmd err %d", err);
|
/* it is of no use to go on, exit */
|
||||||
exit(0);
|
comm_base_exit(w->base);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(r==-1) /* nothing to read now, try later */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch(context_serial_getcmd(buf, len)) {
|
||||||
|
default:
|
||||||
|
case UB_LIBCMD_ANSWER:
|
||||||
|
log_err("unknown command for bg worker %d",
|
||||||
|
(int)context_serial_getcmd(buf, len));
|
||||||
|
/* and fall through to quit */
|
||||||
|
case UB_LIBCMD_QUIT:
|
||||||
|
comm_base_exit(w->base);
|
||||||
|
break;
|
||||||
|
case UB_LIBCMD_NEWQUERY:
|
||||||
|
handle_newq(w, buf, len);
|
||||||
|
break;
|
||||||
|
case UB_LIBCMD_CANCEL:
|
||||||
|
handle_cancel(w, buf, len);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
/** handle opportunity to write result back */
|
||||||
|
int
|
||||||
libworker_handle_result_write(struct comm_point* c, void* arg,
|
libworker_handle_result_write(struct comm_point* c, void* arg,
|
||||||
int err, struct comm_reply* ATTR_UNUSED(rep))
|
int ATTR_UNUSED(err), struct comm_reply* ATTR_UNUSED(rep))
|
||||||
{
|
{
|
||||||
/*struct ub_val_ctx* ctx = (struct ub_val_ctx*)arg;*/
|
struct libworker* w = (struct libworker*)arg;
|
||||||
if(err != NETEVENT_NOERROR) {
|
struct libworker_res_list* item = w->res_list;
|
||||||
if(err == NETEVENT_CLOSED) {
|
int r;
|
||||||
/* parent closed pipe, must have exited somehow */
|
if(!item) {
|
||||||
/* it is of no use to go on, exit */
|
comm_point_stop_listening(c);
|
||||||
exit(0);
|
return 0;
|
||||||
}
|
}
|
||||||
log_err("internal error: pipe comm err %d", err);
|
r = libworker_write_msg(c->fd, item->buf, item->len, 1);
|
||||||
exit(0);
|
if(r == -1)
|
||||||
|
return 0; /* try again later */
|
||||||
|
if(r == 0) {
|
||||||
|
/* error on pipe, must have exited somehow */
|
||||||
|
/* it is of no use to go on, exit */
|
||||||
|
comm_base_exit(w->base);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* done this result, remove it */
|
||||||
|
free(item->buf);
|
||||||
|
item->buf = NULL;
|
||||||
|
w->res_list = w->res_list->next;
|
||||||
|
free(item);
|
||||||
|
if(!w->res_list) {
|
||||||
|
w->res_last = NULL;
|
||||||
|
comm_point_stop_listening(c);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** get bufsize for cfg */
|
|
||||||
static size_t
|
|
||||||
getbufsz(struct ub_val_ctx* ctx)
|
|
||||||
{
|
|
||||||
size_t s = 65535;
|
|
||||||
lock_basic_lock(&ctx->cfglock);
|
|
||||||
s = ctx->env->cfg->msg_buffer_size;
|
|
||||||
lock_basic_unlock(&ctx->cfglock);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** the background thread func */
|
/** the background thread func */
|
||||||
static void*
|
static void*
|
||||||
libworker_dobg(void* arg)
|
libworker_dobg(void* arg)
|
||||||
|
|
@ -207,24 +248,22 @@ libworker_dobg(void* arg)
|
||||||
/* setup */
|
/* setup */
|
||||||
struct ub_val_ctx* ctx = (struct ub_val_ctx*)arg;
|
struct ub_val_ctx* ctx = (struct ub_val_ctx*)arg;
|
||||||
struct libworker* w = libworker_setup(ctx);
|
struct libworker* w = libworker_setup(ctx);
|
||||||
size_t bufsz = getbufsz(ctx);
|
|
||||||
log_thread_set(&w->thread_num);
|
log_thread_set(&w->thread_num);
|
||||||
if(!w) {
|
if(!w) {
|
||||||
log_err("libunbound bg worker init failed, nomem");
|
log_err("libunbound bg worker init failed, nomem");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
lock_basic_lock(&ctx->qqpipe_lock);
|
lock_basic_lock(&ctx->qqpipe_lock);
|
||||||
if(!(w->cmd_com=comm_point_create_local(w->base, ctx->qqpipe[0],
|
if(!(w->cmd_com=comm_point_create_raw(w->base, ctx->qqpipe[0], 0,
|
||||||
bufsz, libworker_handle_control_cmd, w))) {
|
libworker_handle_control_cmd, w))) {
|
||||||
lock_basic_unlock(&ctx->qqpipe_lock);
|
lock_basic_unlock(&ctx->qqpipe_lock);
|
||||||
log_err("libunbound bg worker init failed, no cmdcom");
|
log_err("libunbound bg worker init failed, no cmdcom");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
lock_basic_unlock(&ctx->qqpipe_lock);
|
lock_basic_unlock(&ctx->qqpipe_lock);
|
||||||
lock_basic_lock(&ctx->rrpipe_lock);
|
lock_basic_lock(&ctx->rrpipe_lock);
|
||||||
/* TODO create writing local commpoint */
|
if(!(w->res_com=comm_point_create_raw(w->base, ctx->rrpipe[1], 1,
|
||||||
if(!(w->res_com=comm_point_create_local(w->base, ctx->rrpipe[1],
|
libworker_handle_result_write, w))) {
|
||||||
bufsz, libworker_handle_result_write, w))) {
|
|
||||||
lock_basic_unlock(&ctx->qqpipe_lock);
|
lock_basic_unlock(&ctx->qqpipe_lock);
|
||||||
log_err("libunbound bg worker init failed, no cmdcom");
|
log_err("libunbound bg worker init failed, no cmdcom");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -441,6 +480,18 @@ int libworker_fg(struct ub_val_ctx* ctx, struct ctx_query* q)
|
||||||
return UB_NOERROR;
|
return UB_NOERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** handle new query command for bg worker */
|
||||||
|
static void
|
||||||
|
handle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
|
||||||
|
{
|
||||||
|
struct ctx_query* q = context_deserialize_new_query(w->ctx, buf, len);
|
||||||
|
if(!q) {
|
||||||
|
log_err("failed to deserialize newq");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* TODO start new query in bg mode */
|
||||||
|
}
|
||||||
|
|
||||||
void libworker_alloc_cleanup(void* arg)
|
void libworker_alloc_cleanup(void* arg)
|
||||||
{
|
{
|
||||||
struct libworker* w = (struct libworker*)arg;
|
struct libworker* w = (struct libworker*)arg;
|
||||||
|
|
@ -547,6 +598,83 @@ libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
libworker_write_msg(int fd, uint8_t* buf, uint32_t len, int nonblock)
|
||||||
|
{
|
||||||
|
ssize_t r;
|
||||||
|
/* test */
|
||||||
|
if(nonblock) {
|
||||||
|
r = write(fd, &len, sizeof(len));
|
||||||
|
if(r == -1) {
|
||||||
|
if(errno==EINTR || errno==EAGAIN)
|
||||||
|
return -1;
|
||||||
|
log_err("msg write failed: %s", strerror(errno));
|
||||||
|
return -1; /* can still continue, perhaps */
|
||||||
|
}
|
||||||
|
} else r = 0;
|
||||||
|
if(!fd_set_block(fd))
|
||||||
|
return 0;
|
||||||
|
/* write remainder */
|
||||||
|
if(r != (ssize_t)sizeof(len)) {
|
||||||
|
if(write(fd, (char*)(&len)+r, sizeof(len)-r) == -1) {
|
||||||
|
log_err("msg write failed: %s", strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(write(fd, buf, len) == -1) {
|
||||||
|
log_err("msg write failed: %s", strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(!fd_set_nonblock(fd))
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
libworker_read_msg(int fd, uint8_t** buf, uint32_t* len, int nonblock)
|
||||||
|
{
|
||||||
|
ssize_t r;
|
||||||
|
|
||||||
|
/* test */
|
||||||
|
*len = 0;
|
||||||
|
if(nonblock) {
|
||||||
|
r = read(fd, len, sizeof(*len));
|
||||||
|
if(r == -1) {
|
||||||
|
if(errno==EINTR || errno==EAGAIN)
|
||||||
|
return -1;
|
||||||
|
log_err("msg read failed: %s", strerror(errno));
|
||||||
|
return -1; /* we can still continue, perhaps */
|
||||||
|
}
|
||||||
|
if(r == 0) /* EOF */
|
||||||
|
return 0;
|
||||||
|
} else r = 0;
|
||||||
|
if(!fd_set_block(fd))
|
||||||
|
return 0;
|
||||||
|
/* read remainder */
|
||||||
|
if(r != (ssize_t)sizeof(*len)) {
|
||||||
|
if((r=read(fd, (char*)(len)+r, sizeof(*len)-r)) == -1) {
|
||||||
|
log_err("msg read failed: %s", strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(r == 0) /* EOF */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*buf = (uint8_t*)malloc(*len);
|
||||||
|
if(!*buf) {
|
||||||
|
log_err("out of memory");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if((r=read(fd, *buf, *len)) == -1) {
|
||||||
|
log_err("msg read failed: %s", strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(r == 0) /* EOF */
|
||||||
|
return 0;
|
||||||
|
if(!fd_set_nonblock(fd))
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* --- fake callbacks for fptr_wlist to work --- */
|
/* --- fake callbacks for fptr_wlist to work --- */
|
||||||
int worker_handle_control_cmd(struct comm_point* ATTR_UNUSED(c),
|
int worker_handle_control_cmd(struct comm_point* ATTR_UNUSED(c),
|
||||||
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ struct outbound_entry;
|
||||||
struct module_qstate;
|
struct module_qstate;
|
||||||
struct comm_point;
|
struct comm_point;
|
||||||
struct comm_reply;
|
struct comm_reply;
|
||||||
|
struct libworker_res_list;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The library-worker status structure
|
* The library-worker status structure
|
||||||
|
|
@ -78,8 +79,13 @@ struct libworker {
|
||||||
struct ub_randstate* rndstate;
|
struct ub_randstate* rndstate;
|
||||||
/** commpoint to listen to commands */
|
/** commpoint to listen to commands */
|
||||||
struct comm_point* cmd_com;
|
struct comm_point* cmd_com;
|
||||||
/** commpoint to write results back (nonblocking) */
|
/** commpoint to write results back */
|
||||||
struct comm_point* res_com;
|
struct comm_point* res_com;
|
||||||
|
|
||||||
|
/** list of outstanding results to be written back */
|
||||||
|
struct libworker_res_list* res_list;
|
||||||
|
/** last in list */
|
||||||
|
struct libworker_res_list* res_last;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -92,6 +98,18 @@ struct libworker_fg_data {
|
||||||
struct ctx_query* q;
|
struct ctx_query* q;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of results (arbitrary command serializations) to write back
|
||||||
|
*/
|
||||||
|
struct libworker_res_list {
|
||||||
|
/** next in list */
|
||||||
|
struct libworker_res_list* next;
|
||||||
|
/** serialized buffer to write */
|
||||||
|
uint8_t* buf;
|
||||||
|
/** length to write */
|
||||||
|
uint32_t len;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a background worker
|
* Create a background worker
|
||||||
* @param ctx: is updated with pid/tid of the background worker.
|
* @param ctx: is updated with pid/tid of the background worker.
|
||||||
|
|
@ -157,4 +175,46 @@ int libworker_handle_reply(struct comm_point* c, void* arg, int error,
|
||||||
int libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
|
int libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
|
||||||
struct comm_reply* reply_info);
|
struct comm_reply* reply_info);
|
||||||
|
|
||||||
|
/** handle control command coming into server */
|
||||||
|
int libworker_handle_control_cmd(struct comm_point* c, void* arg,
|
||||||
|
int err, struct comm_reply* rep);
|
||||||
|
|
||||||
|
/** handle opportunity to write result back */
|
||||||
|
int libworker_handle_result_write(struct comm_point* c, void* arg,
|
||||||
|
int err, struct comm_reply* rep);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write length bytes followed by message.
|
||||||
|
* @param fd: the socket to write on. Is nonblocking.
|
||||||
|
* Set to blocking by the function,
|
||||||
|
* and back to non-blocking at exit of function.
|
||||||
|
* @param buf: the message.
|
||||||
|
* @param len: length of message.
|
||||||
|
* @param nonblock: if set to true, the first write is nonblocking.
|
||||||
|
* If the first write fails the function returns -1.
|
||||||
|
* If set false, the first write is blocking.
|
||||||
|
* @return: all remainder writes are nonblocking.
|
||||||
|
* return 0 on error, in that case blocking/nonblocking of socket is
|
||||||
|
* unknown.
|
||||||
|
* return 1 if all OK.
|
||||||
|
*/
|
||||||
|
int libworker_write_msg(int fd, uint8_t* buf, uint32_t len, int nonblock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read length bytes followed by message.
|
||||||
|
* @param fd: the socket to write on. Is nonblocking.
|
||||||
|
* Set to blocking by the function,
|
||||||
|
* and back to non-blocking at exit of function.
|
||||||
|
* @param buf: the message, malloced.
|
||||||
|
* @param len: length of message, returned.
|
||||||
|
* @param nonblock: if set to true, the first read is nonblocking.
|
||||||
|
* If the first read fails the function returns -1.
|
||||||
|
* If set false, the first read is blocking.
|
||||||
|
* @return: all remainder reads are nonblocking.
|
||||||
|
* return 0 on error, in that case blocking/nonblocking of socket is
|
||||||
|
* unknown. On EOF 0 is returned.
|
||||||
|
* return 1 if all OK.
|
||||||
|
*/
|
||||||
|
int libworker_read_msg(int fd, uint8_t** buf, uint32_t* len, int nonblock);
|
||||||
|
|
||||||
#endif /* LIBUNBOUND_WORKER_H */
|
#endif /* LIBUNBOUND_WORKER_H */
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,7 @@ fptr_whitelist_event(void (*fptr)(int, short, void *))
|
||||||
else if(fptr == &comm_timer_callback) return 1;
|
else if(fptr == &comm_timer_callback) return 1;
|
||||||
else if(fptr == &comm_signal_callback) return 1;
|
else if(fptr == &comm_signal_callback) return 1;
|
||||||
else if(fptr == &comm_point_local_handle_callback) return 1;
|
else if(fptr == &comm_point_local_handle_callback) return 1;
|
||||||
|
else if(fptr == &comm_point_raw_handle_callback) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -743,6 +743,15 @@ void comm_point_local_handle_callback(int fd, short event, void* arg)
|
||||||
log_err("Ignored event %d for localhdl.", event);
|
log_err("Ignored event %d for localhdl.", event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void comm_point_raw_handle_callback(int ATTR_UNUSED(fd),
|
||||||
|
short ATTR_UNUSED(event), void* arg)
|
||||||
|
{
|
||||||
|
struct comm_point* c = (struct comm_point*)arg;
|
||||||
|
log_assert(c->type == comm_raw);
|
||||||
|
|
||||||
|
(void)(*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
struct comm_point*
|
struct comm_point*
|
||||||
comm_point_create_udp(struct comm_base *base, int fd, ldns_buffer* buffer,
|
comm_point_create_udp(struct comm_base *base, int fd, ldns_buffer* buffer,
|
||||||
comm_point_callback_t* callback, void* callback_arg)
|
comm_point_callback_t* callback, void* callback_arg)
|
||||||
|
|
@ -1048,7 +1057,55 @@ comm_point_create_local(struct comm_base *base, int fd, size_t bufsize,
|
||||||
if(event_base_set(base->eb->base, &c->ev->ev) != 0 ||
|
if(event_base_set(base->eb->base, &c->ev->ev) != 0 ||
|
||||||
event_add(&c->ev->ev, c->timeout) != 0 )
|
event_add(&c->ev->ev, c->timeout) != 0 )
|
||||||
{
|
{
|
||||||
log_err("could not add tcphdl event");
|
log_err("could not add localhdl event");
|
||||||
|
free(c->ev);
|
||||||
|
free(c);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct comm_point*
|
||||||
|
comm_point_create_raw(struct comm_base* base, int fd, int writing,
|
||||||
|
comm_point_callback_t* callback, void* callback_arg)
|
||||||
|
{
|
||||||
|
struct comm_point* c = (struct comm_point*)calloc(1,
|
||||||
|
sizeof(struct comm_point));
|
||||||
|
short evbits;
|
||||||
|
if(!c)
|
||||||
|
return NULL;
|
||||||
|
c->ev = (struct internal_event*)calloc(1,
|
||||||
|
sizeof(struct internal_event));
|
||||||
|
if(!c->ev) {
|
||||||
|
free(c);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
c->fd = fd;
|
||||||
|
c->buffer = NULL;
|
||||||
|
c->timeout = NULL;
|
||||||
|
c->tcp_is_reading = 0;
|
||||||
|
c->tcp_byte_count = 0;
|
||||||
|
c->tcp_parent = NULL;
|
||||||
|
c->max_tcp_count = 0;
|
||||||
|
c->tcp_handlers = NULL;
|
||||||
|
c->tcp_free = NULL;
|
||||||
|
c->type = comm_raw;
|
||||||
|
c->tcp_do_close = 0;
|
||||||
|
c->do_not_close = 1;
|
||||||
|
c->tcp_do_toggle_rw = 0;
|
||||||
|
c->tcp_check_nb_connect = 0;
|
||||||
|
c->callback = callback;
|
||||||
|
c->cb_arg = callback_arg;
|
||||||
|
/* libevent stuff */
|
||||||
|
if(writing)
|
||||||
|
evbits = EV_PERSIST | EV_WRITE;
|
||||||
|
else evbits = EV_PERSIST | EV_READ;
|
||||||
|
event_set(&c->ev->ev, c->fd, evbits, comm_point_raw_handle_callback,
|
||||||
|
c);
|
||||||
|
if(event_base_set(base->eb->base, &c->ev->ev) != 0 ||
|
||||||
|
event_add(&c->ev->ev, c->timeout) != 0 )
|
||||||
|
{
|
||||||
|
log_err("could not add rawhdl event");
|
||||||
free(c->ev);
|
free(c->ev);
|
||||||
free(c);
|
free(c);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,9 @@ struct comm_point {
|
||||||
/** TCP handler socket - handle byteperbyte readwrite. */
|
/** TCP handler socket - handle byteperbyte readwrite. */
|
||||||
comm_tcp,
|
comm_tcp,
|
||||||
/** AF_UNIX socket - for internal commands. */
|
/** AF_UNIX socket - for internal commands. */
|
||||||
comm_local
|
comm_local,
|
||||||
|
/** raw - not DNS format - for pipe readers and writers */
|
||||||
|
comm_raw
|
||||||
}
|
}
|
||||||
/** variable with type of socket, UDP,TCP-accept,TCP,pipe */
|
/** variable with type of socket, UDP,TCP-accept,TCP,pipe */
|
||||||
type;
|
type;
|
||||||
|
|
@ -350,6 +352,19 @@ struct comm_point* comm_point_create_local(struct comm_base* base,
|
||||||
int fd, size_t bufsize,
|
int fd, size_t bufsize,
|
||||||
comm_point_callback_t* callback, void* callback_arg);
|
comm_point_callback_t* callback, void* callback_arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create commpoint to listen to a local domain pipe descriptor.
|
||||||
|
* @param base: in which base to alloc the commpoint.
|
||||||
|
* @param fd: file descriptor.
|
||||||
|
* @param writing: true if you want to listen to writes, false for reads.
|
||||||
|
* @param callback: callback function pointer for the handler.
|
||||||
|
* @param callback_arg: will be passed to your callback function.
|
||||||
|
* @return: the commpoint or NULL on error.
|
||||||
|
*/
|
||||||
|
struct comm_point* comm_point_create_raw(struct comm_base* base,
|
||||||
|
int fd, int writing,
|
||||||
|
comm_point_callback_t* callback, void* callback_arg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close a comm point fd.
|
* Close a comm point fd.
|
||||||
* @param c: comm point to close.
|
* @param c: comm point to close.
|
||||||
|
|
@ -569,5 +584,14 @@ void comm_signal_callback(int fd, short event, void* arg);
|
||||||
*/
|
*/
|
||||||
void comm_point_local_handle_callback(int fd, short event, void* arg);
|
void comm_point_local_handle_callback(int fd, short event, void* arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This routine is published for checks and tests, and is only used internally.
|
||||||
|
* libevent callback for raw fd access.
|
||||||
|
* @param fd: file descriptor.
|
||||||
|
* @param event: event bits from libevent:
|
||||||
|
* EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT.
|
||||||
|
* @param arg: the comm_point structure.
|
||||||
|
*/
|
||||||
|
void comm_point_raw_handle_callback(int fd, short event, void* arg);
|
||||||
|
|
||||||
#endif /* NET_EVENT_H */
|
#endif /* NET_EVENT_H */
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue