]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
writev and sendmsg support in netevent.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Wed, 28 Mar 2007 15:40:12 +0000 (15:40 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Wed, 28 Mar 2007 15:40:12 +0000 (15:40 +0000)
git-svn-id: file:///svn/unbound/trunk@204 be551aaa-1e26-0410-a405-d3ace91eadb9

doc/TODO
testcode/fake_event.c
util/data/msgreply.c
util/data/msgreply.h
util/netevent.c
util/netevent.h

index 69fbad760f857bc640e7b6eef5cb4215374250dd..094f8e6a565ede0dfb93a77327b6308419cff4c8 100644 (file)
--- 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.
index d4e4aef087e19796c123a08a417c4e17af4da006..f5f9863b532bb8753cb4ad1c7493a3899beb3ba8 100644 (file)
@@ -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; i<iovlen; i++)
+               ldns_buffer_write(repinfo->c->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)
 {
index 72bcf550b312387653143089646132e0ae6b3f35..51554e9238c57bb481ff553ebe70b4eae6065e3c 100644 (file)
@@ -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)
 {
index 9d458ba7da511ce37010ad30e52b92ee364df481..a976d7b0f250da9db169437c432fad6a4a78aa09 100644 (file)
@@ -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.
index 566b4367ffd032ba389dca401b109577443d3fe4..d8b4d88f2de52c9b753b445ab470e3789dd590b4 100644 (file)
@@ -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; i<iovlen; i++)
+                       len += iov[i].iov_len;
+               len = htons(len);
+               iov[0].iov_base = &len;
+               iov[0].iov_len = sizeof(uint16_t);
+               if((done=writev(repinfo->c->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; i<iovlen; i++)
+                               ldns_buffer_write(repinfo->c->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)
 {
index c6495549f594e0efa863827ae8e185729a2785c3..2f8295743fdd9c60452c9d7aa5d3d0219f80ef43 100644 (file)
@@ -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.