#include "util/netevent.h"
#include "services/listen_dnsport.h"
+/** process incoming request */
+static void worker_process_query(struct worker* worker)
+{
+ /* query the forwarding address */
+
+}
+
+/** check request sanity. Returns error code, 0 OK, or -1 discard. */
+static int worker_check_request(ldns_buffer* pkt)
+{
+ if(ldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) {
+ verbose(VERB_DETAIL, "request too short, discarded");
+ return -1;
+ }
+ if(LDNS_QR_WIRE(ldns_buffer_begin(pkt))) {
+ verbose(VERB_DETAIL, "request has QR bit on, discarded");
+ return -1;
+ }
+ if(LDNS_OPCODE_WIRE(ldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY) {
+ verbose(VERB_DETAIL, "request unknown opcode %d",
+ LDNS_OPCODE_WIRE(ldns_buffer_begin(pkt)));
+ return LDNS_RCODE_NOTIMPL;
+ }
+ if(LDNS_QDCOUNT(ldns_buffer_begin(pkt)) != 1) {
+ verbose(VERB_DETAIL, "request wrong nr qd=%d",
+ LDNS_QDCOUNT(ldns_buffer_begin(pkt)));
+ return LDNS_RCODE_FORMERR;
+ }
+ if(LDNS_ANCOUNT(ldns_buffer_begin(pkt)) != 0) {
+ verbose(VERB_DETAIL, "request wrong nr an=%d",
+ LDNS_ANCOUNT(ldns_buffer_begin(pkt)));
+ return LDNS_RCODE_FORMERR;
+ }
+ if(LDNS_NSCOUNT(ldns_buffer_begin(pkt)) != 0) {
+ verbose(VERB_DETAIL, "request wrong nr ns=%d",
+ LDNS_NSCOUNT(ldns_buffer_begin(pkt)));
+ return LDNS_RCODE_FORMERR;
+ }
+ if(LDNS_ARCOUNT(ldns_buffer_begin(pkt)) != 0) {
+ verbose(VERB_DETAIL, "request wrong nr ar=%d",
+ LDNS_ARCOUNT(ldns_buffer_begin(pkt)));
+ return LDNS_RCODE_FORMERR;
+ }
+ return 0;
+}
+
/** handles callbacks from listening event interface */
-static int worker_handle_request(ldns_buffer* packet, void* arg)
+static int worker_handle_request(struct comm_point* c, void* arg, int error,
+ struct comm_reply* repinfo)
{
+ struct worker* worker = (struct worker*)arg;
+ int ret;
log_info("worker handle request");
+ if(error != 0) {
+ log_err("called with err=%d", error);
+ return 0;
+ }
+ if((ret=worker_check_request(c->buffer)) != 0) {
+ if(ret != -1) {
+ LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), ret);
+ return 1;
+ }
+ return 0;
+ }
+ if(worker->num_requests > 0) {
+ verbose(VERB_DETAIL, "worker: too many requests active. "
+ "dropping incoming query.");
+ return 0;
+ }
+ /* answer it */
+ worker->num_requests ++;
+ memcpy(&worker->query_reply, repinfo, sizeof(struct comm_reply));
+ worker_process_query(worker);
return 0;
}
struct worker* worker_init(const char* port, int do_ip4, int do_ip6,
int do_udp, int do_tcp, size_t buffer_size)
{
- struct worker* worker = (struct worker*)malloc(sizeof(struct worker));
+ struct worker* worker = (struct worker*)calloc(1,
+ sizeof(struct worker));
if(!worker)
return NULL;
worker->base = comm_base_create();
#define DAEMON_WORKER_H
#include "config.h"
-struct comm_base;
+#include "util/netevent.h"
struct listen_dnsport;
/**
/** the frontside listening interface where request events come in */
struct listen_dnsport* front;
+
+ /** our one and only query, packet buffer and where to send. */
+ struct comm_reply query_reply;
+
+ /** number of requests currently active */
+ int num_requests;
};
/**
31 January 2007: Wouter
- Added makedist.sh script to make release tarball.
+ - Removed listen callback layer, did not add anything.
+ - Added UDP recv to netevent, worker callback for udp.
+ - netevent communication reply storage structure.
+ - minimal query header sanity checking for worker.
30 January 2007: Wouter
- links in example/ldns-testpkts.c and .h for premade packet support.
/** number of simultaneous open TCP connections */
#define TCP_COUNT 10
-/** callback of comm_point_callback_t for events. */
-static int listen_udp_callback(struct comm_point* cp, void* arg, int error)
-{
- return 0;
-}
-
-/** callback of comm_point_callback_t for events. */
-static int listen_tcp_callback(struct comm_point* cp, void* arg, int error)
-{
- return 0;
-}
-
/**
* Debug print of the getaddrinfo returned address.
* @param addr: the address returned.
* @param do_tcp: if udp should be used.
* @param hints: for getaddrinfo. family and flags have to be set by caller.
* @param bufsize: TCP buffer size.
+ * @param cb: callback function
+ * @param cb_arg: user parameter for callback function.
* @return: returns false on error.
*/
static int
listen_create_if(const char* ifname, struct listen_dnsport* front,
struct comm_base* base, const char* port, int do_udp, int do_tcp,
- struct addrinfo *hints, size_t bufsize)
+ struct addrinfo *hints, size_t bufsize, comm_point_callback_t* cb,
+ void *cb_arg)
{
struct comm_point *cp_udp = NULL, *cp_tcp = NULL;
struct listen_list *el_udp, *el_tcp;
if((s = make_sock(SOCK_DGRAM, ifname, port, hints)) == -1)
return 0;
cp_udp = comm_point_create_udp(base, s, front->udp_buff,
- listen_udp_callback, front);
+ cb, cb_arg);
if(!cp_udp) {
log_err("can't create commpoint");
close(s);
return 0;
}
cp_tcp = comm_point_create_tcp(base, s, TCP_COUNT, bufsize,
- listen_tcp_callback, front);
+ cb, cb_arg);
if(!cp_tcp) {
log_err("can't create commpoint");
comm_point_delete(cp_udp);
el_udp->com = cp_udp;
el_udp->next = front->cps;
front->cps = el_udp;
- comm_point_set_cb_arg(el_udp->com, el_udp);
el_tcp->com = cp_tcp;
el_tcp->next = front->cps;
front->cps = el_tcp;
- comm_point_set_cb_arg(el_tcp->com, el_tcp);
return 1;
}
struct listen_dnsport*
listen_create(struct comm_base* base, int num_ifs, const char* ifs[],
const char* port, int do_ip4, int do_ip6, int do_udp, int do_tcp,
- size_t bufsize, listen_dnsport_cb_t* cb, void *cb_arg)
+ size_t bufsize, comm_point_callback_t* cb, void *cb_arg)
{
struct addrinfo hints;
int i;
if(!front)
return NULL;
front->cps = NULL;
- front->cb = cb;
- front->cb_arg = cb_arg;
front->udp_buff = ldns_buffer_new(bufsize);
if(!front->udp_buff) {
free(front);
if(num_ifs == 0) {
if(!listen_create_if(NULL, front, base, port,
- do_udp, do_tcp, &hints, bufsize)) {
+ do_udp, do_tcp, &hints, bufsize, cb, cb_arg)) {
listen_delete(front);
return NULL;
}
} else for(i = 0; i<num_ifs; i++) {
if(!listen_create_if(ifs[i], front, base, port,
- do_udp, do_tcp, &hints, bufsize)) {
+ do_udp, do_tcp, &hints, bufsize, cb, cb_arg)) {
listen_delete(front);
return NULL;
}
#define LISTEN_DNSPORT_H
#include "config.h"
-struct comm_base;
+#include "util/netevent.h"
struct listen_list;
-/** The callback type for a incoming request packet */
-typedef int listen_dnsport_cb_t(ldns_buffer* packet, void* arg);
-
/**
* Listening for queries structure.
* Contains list of query-listen sockets.
/** list of comm points used to get incoming events */
struct listen_list *cps;
-
- /** callback function that accepts incoming message. */
- listen_dnsport_cb_t* cb;
-
- /** callback argument */
- void *cb_arg;
};
/**
* @param do_udp: listen to udp queries.
* @param do_tcp: listen to tcp queries.
* @param bufsize: size of datagram buffer.
- * @param cb: callback function when a request arrives.
+ * @param cb: callback function when a request arrives. It is passed
+ * the packet and user argument. Return true to send a reply.
* @param cb_arg: user data argument for callback function.
* @return: the malloced listening structure, ready for use. NULL on error.
*/
struct listen_dnsport* listen_create(struct comm_base* base,
int num_ifs, const char* ifs[], const char* port,
int do_ip4, int do_ip6, int do_udp, int do_tcp,
- size_t bufsize, listen_dnsport_cb_t* cb, void *cb_arg);
+ size_t bufsize, comm_point_callback_t* cb, void *cb_arg);
/**
* delete the listening structure
}
}
+/** send a UDP reply */
+static void
+comm_point_send_udp_msg(struct comm_point *c, struct sockaddr* addr,
+ socklen_t addrlen) {
+ ssize_t sent;
+ sent = sendto(c->fd, ldns_buffer_begin(c->buffer),
+ ldns_buffer_remaining(c->buffer), 0,
+ addr, addrlen);
+ if(sent == -1) {
+ log_err("sendto failed: %s", strerror(errno));
+ } else if((size_t)sent != ldns_buffer_remaining(c->buffer)) {
+ log_err("sent %d in place of %d bytes",
+ sent, (int)ldns_buffer_remaining(c->buffer));
+ }
+}
+
static void
-comm_point_udp_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(event),
- void* arg)
+comm_point_udp_callback(int fd, short event, void* arg)
{
- struct comm_point* c = (struct comm_point*)arg;
- log_info("callback udp for %x", (int)c);
+ struct comm_reply rep;
+ ssize_t recv;
+
+ rep.c = (struct comm_point*)arg;
+
+ verbose(VERB_ALGO, "callback udp");
+ if(!(event&EV_READ))
+ return;
+ log_assert(rep.c && rep.c->buffer && rep.c->fd == fd);
+ ldns_buffer_clear(rep.c->buffer);
+ recv = recvfrom(fd, ldns_buffer_begin(rep.c->buffer),
+ ldns_buffer_remaining(rep.c->buffer), 0,
+ (struct sockaddr*)&rep.addr, &rep.addrlen);
+ if(recv == -1) {
+ if(errno != EAGAIN && errno != EINTR) {
+ log_err("recvfrom failed: %s", strerror(errno));
+ }
+ return;
+ }
+ ldns_buffer_skip(rep.c->buffer, recv);
+ ldns_buffer_flip(rep.c->buffer);
+ if((*rep.c->callback)(rep.c, rep.c->cb_arg, 0, &rep)) {
+ /* send back immediate reply */
+ comm_point_send_udp_msg(rep.c, (struct sockaddr*)&rep.addr,
+ rep.addrlen);
+ }
}
static void
log_assert(c);
c->cb_arg = arg;
}
+
+void comm_point_send_reply(struct comm_reply *repinfo)
+{
+ log_assert(repinfo && repinfo->c);
+ if(repinfo->c->type == comm_udp) {
+ comm_point_send_udp_msg(repinfo->c,
+ (struct sockaddr*)&repinfo->addr, repinfo->addrlen);
+ } else {
+ log_info("tcp reply");
+ }
+}
+
#include "config.h"
struct comm_point;
+struct comm_reply;
/* internal event notification data storage structure. */
struct internal_event;
struct internal_base;
/** callback from communication point function type */
-typedef int comm_point_callback_t(struct comm_point*, void*, int);
+typedef int comm_point_callback_t(struct comm_point*, void*, int,
+ struct comm_reply*);
/**
* A communication point dispatcher. Thread specific.
nonzero. If nonzero, it is an errno value.
If the connection is closed (by remote end) then the
callback is called with error set to -1.
+ If a timeout happens on the connection, the error is set to -2.
+ The reply_info can be copied if the reply needs to happen at a
+ later time. It consists of a struct with commpoint and address.
+ It can be passed to a msg send routine some time later.
+ Note the reply information is temporary and must be copied.
declare as:
- int my_callback(struct comm_point* c, void* my_arg,
- int timeout, int error);
+ int my_callback(struct comm_point* c, void* my_arg, int error,
+ struct comm_reply *reply_info);
if the routine returns 0, nothing is done.
Notzero, the buffer will be sent back to client.
void *cb_arg;
};
+/**
+ * Reply information for a communication point.
+ */
+struct comm_reply {
+ /** the comm_point with fd to send reply on to. */
+ struct comm_point *c;
+ /** the address (for UDP based communication) */
+ struct sockaddr_storage addr;
+ /** length of address */
+ socklen_t addrlen;
+};
+
/**
* Create a new comm base.
* @return: the new comm base. NULL on error.
*/
void comm_point_set_cb_arg(struct comm_point* c, void *arg);
+/**
+ * Send reply. Put message into commpoint buffer.
+ * @param repinfo: The reply info copied from a commpoint callback call.
+ */
+void comm_point_send_reply(struct comm_reply *repinfo);
+
#endif /* NET_EVENT_H */