diff --git a/doc/TODO b/doc/TODO index 69fbad760..094f8e6a5 100644 --- a/doc/TODO +++ b/doc/TODO @@ -3,4 +3,4 @@ o use real entropy to make random (ID, port) numbers more random. o in production mode, do not free memory on exit. In debug mode, test leaks. o profile memory allocation, and if performance issues, use special memory allocator. For example, with caches per thread. -o sendmsg, writev. +o do not do useless byteswap on query_id value. store qflags in uint16. diff --git a/testcode/fake_event.c b/testcode/fake_event.c index d4e4aef08..f5f9863b5 100644 --- a/testcode/fake_event.c +++ b/testcode/fake_event.c @@ -609,6 +609,19 @@ comm_point_send_reply(struct comm_reply* repinfo) log_pkt("reply pkt: ", ans->pkt); } +void +comm_point_send_reply_iov(struct comm_reply* repinfo, struct iovec* iov, + size_t iovlen) +{ + size_t i; + ldns_buffer_clear(repinfo->c->buffer); + for(i=1; ic->buffer, iov[i].iov_base, + iov[i].iov_len); + ldns_buffer_flip(repinfo->c->buffer); + comm_point_send_reply(repinfo); +} + void comm_point_drop_reply(struct comm_reply* repinfo) { diff --git a/util/data/msgreply.c b/util/data/msgreply.c index 72bcf550b..51554e923 100644 --- a/util/data/msgreply.c +++ b/util/data/msgreply.c @@ -43,6 +43,7 @@ #include "util/data/msgreply.h" #include "util/storage/lookup3.h" #include "util/log.h" +#include "util/netevent.h" /** determine length of a dname in buffer, no compression pointers allowed. */ size_t @@ -182,6 +183,28 @@ void reply_info_answer(struct reply_info* rep, uint16_t qflags, ldns_buffer_flip(buffer); } +void +reply_info_answer_iov(struct reply_info* rep, uint16_t qid, + uint16_t qflags, struct comm_reply* comrep) +{ + uint16_t flags; + /* [0]=tcp, [1]=id, [2]=flags, [3]=message */ + struct iovec iov[4]; + + qid = htons(qid); + iov[1].iov_base = &qid; + iov[1].iov_len = sizeof(uint16_t); + flags = ldns_read_uint16(rep->reply); + flags |= (qflags & 0x0100); /* copy RD bit */ + log_assert(flags & 0x8000); /* QR bit must be on in our replies */ + flags = htons(flags); + iov[2].iov_base = &flags; + iov[2].iov_len = sizeof(uint16_t); + iov[3].iov_base = rep->reply+2; + iov[3].iov_len = rep->replysize-2; + comm_point_send_reply_iov(comrep, iov, 4); +} + struct msgreply_entry* query_info_entrysetup(struct query_info* q, struct reply_info* r, hashvalue_t h) { diff --git a/util/data/msgreply.h b/util/data/msgreply.h index 9d458ba7d..a976d7b0f 100644 --- a/util/data/msgreply.h +++ b/util/data/msgreply.h @@ -42,6 +42,7 @@ #ifndef UTIL_DATA_MSGREPLY_H #define UTIL_DATA_MSGREPLY_H #include "util/storage/lruhash.h" +struct comm_reply; /** * Structure to store query information that makes answers to queries @@ -143,6 +144,16 @@ hashvalue_t query_info_hash(struct query_info *q); void reply_info_answer(struct reply_info* rep, uint16_t qflags, ldns_buffer* buf); +/** + * Generate and send out answer from reply_info. + * @param rep: reply to fill in. + * @param qid: query id. + * @param qflags: flags word from the query. + * @param comrep: communication reply point. + */ +void reply_info_answer_iov(struct reply_info* rep, uint16_t qid, + uint16_t qflags, struct comm_reply* comrep); + /** * Setup query info entry * @param q: query info to copy. Emptied as if clear is called. diff --git a/util/netevent.c b/util/netevent.c index 566b4367f..d8b4d88f2 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -780,6 +780,69 @@ comm_point_send_reply(struct comm_reply *repinfo) } } +void +comm_point_send_reply_iov(struct comm_reply* repinfo, struct iovec* iov, + size_t iovlen) +{ + log_assert(repinfo && repinfo->c); + if(repinfo->c->type == comm_udp) { + struct msghdr hdr; + hdr.msg_name = &repinfo->addr; + hdr.msg_namelen = repinfo->addrlen; + hdr.msg_iov = iov + 1; + hdr.msg_iovlen = iovlen - 1; + hdr.msg_control = NULL; + hdr.msg_controllen = 0; + hdr.msg_flags = 0; + /* note that number of characters sent is not checked. */ + if(sendmsg(repinfo->c->fd, &hdr, 0) == -1) + log_err("sendmsg: %s", strerror(errno)); + } else { + /* try if it can be sent in writev right now */ + size_t i; + uint16_t len = 0; + ssize_t done; + for(i=1; ic->fd, iov, (int)iovlen)) == -1) { +#ifdef S_SPLINT_S + /* don't complain about returning stack references */ + iov[0].iov_base = NULL; +#endif + if(errno != EINTR && errno != EAGAIN) { + log_err("writev: %s", strerror(errno)); + comm_point_drop_reply(repinfo); + return; + } + done = 0; + } +#ifdef S_SPLINT_S + /* don't complain about returning stack references */ + iov[0].iov_base = NULL; +#endif + if((size_t)done == ntohs(len) + sizeof(uint16_t)) { + /* done in one call */ + comm_point_drop_reply(repinfo); + } else { + /* sending remaining bytes */ + ldns_buffer_clear(repinfo->c->buffer); + repinfo->c->tcp_byte_count = (size_t)done; + for(i=1; ic->buffer, + iov[i].iov_base, iov[i].iov_len); + ldns_buffer_flip(repinfo->c->buffer); + if((size_t)done >= sizeof(uint16_t)) + ldns_buffer_set_position(repinfo->c->buffer, + (size_t)done - sizeof(uint16_t)); + comm_point_start_listening(repinfo->c, -1, + TCP_QUERY_TIMEOUT); + } + } +} + void comm_point_drop_reply(struct comm_reply* repinfo) { diff --git a/util/netevent.h b/util/netevent.h index c6495549f..2f8295743 100644 --- a/util/netevent.h +++ b/util/netevent.h @@ -327,6 +327,18 @@ void comm_point_set_cb_arg(struct comm_point* c, void* arg); */ void comm_point_send_reply(struct comm_reply* repinfo); +/** + * Send reply. Message is not put into commpoint buffer, but in iovec. + * If it cannot be sent immediately (TCP) the message is copied to the buffer. + * @param repinfo: reply info copied from commpoint callback call. + * @param iov: iovector, array of base, len parts to send out. + * caller must keep entry 0 free for use by tcp handler. Start at entry 1. + * @param iovlen: number of iov items to concatenate and send out. + * this includes the entry 0, which is not filled in by caller. + */ +void comm_point_send_reply_iov(struct comm_reply* repinfo, struct iovec* iov, + size_t iovlen); + /** * Drop reply. Cleans up. * @param repinfo: The reply info copied from a commpoint callback call.