writev and sendmsg support in netevent.

git-svn-id: file:///svn/unbound/trunk@204 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-03-28 15:40:12 +00:00
parent ae93dcac76
commit 806b4ddf67
6 changed files with 123 additions and 1 deletions

View File

@ -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.

View 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)
{

View 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)
{

View 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.

View 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)
{

View 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.