From: Wouter Wijngaards Date: Wed, 31 Jan 2007 09:32:30 +0000 (+0000) Subject: udp work. X-Git-Tag: release-0.0~80 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=775158882e543f7a46db9df35bb5383f6d74e55e;p=thirdparty%2Funbound.git udp work. git-svn-id: file:///svn/unbound/trunk@45 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/daemon/worker.c b/daemon/worker.c index 38540dffc..2aff3bb63 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -45,17 +45,87 @@ #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(); diff --git a/daemon/worker.h b/daemon/worker.h index aa184992d..b8ae64012 100644 --- a/daemon/worker.h +++ b/daemon/worker.h @@ -44,7 +44,7 @@ #define DAEMON_WORKER_H #include "config.h" -struct comm_base; +#include "util/netevent.h" struct listen_dnsport; /** @@ -57,6 +57,12 @@ struct worker { /** 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; }; /** diff --git a/doc/Changelog b/doc/Changelog index 01273603e..c620816e4 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,5 +1,9 @@ 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. diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c index 448bd468a..ec5781189 100644 --- a/services/listen_dnsport.c +++ b/services/listen_dnsport.c @@ -55,18 +55,6 @@ /** 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. @@ -199,12 +187,15 @@ make_sock(int stype, const char* ifname, const char* port, * @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; @@ -215,7 +206,7 @@ listen_create_if(const char* ifname, struct listen_dnsport* front, 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); @@ -228,7 +219,7 @@ listen_create_if(const char* ifname, struct listen_dnsport* front, 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); @@ -254,18 +245,16 @@ listen_create_if(const char* ifname, struct listen_dnsport* front, 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; @@ -274,8 +263,6 @@ listen_create(struct comm_base* base, int num_ifs, const char* ifs[], 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); @@ -304,13 +291,13 @@ listen_create(struct comm_base* base, int num_ifs, const char* ifs[], 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; ifd, 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 @@ -358,3 +397,15 @@ comm_point_set_cb_arg(struct comm_point* c, void *arg) 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"); + } +} + diff --git a/util/netevent.h b/util/netevent.h index 3360b8702..754e5d0aa 100644 --- a/util/netevent.h +++ b/util/netevent.h @@ -55,13 +55,15 @@ #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. @@ -142,10 +144,15 @@ struct comm_point { 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. @@ -157,6 +164,18 @@ struct comm_point { 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. @@ -232,4 +251,10 @@ void comm_point_delete(struct comm_point* c); */ 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 */