summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Včelák <jan.vcelak@nic.cz>2015-02-04 12:39:17 +0100
committerJan Včelák <jan.vcelak@nic.cz>2015-02-04 12:39:17 +0100
commita636c6de2130ab759a172dd49d6b71f74c556cde (patch)
tree6ef2fd6e2ac9b63708ec221cc8d674d34248e671
parentMerge branch 'docker' into 'master' (diff)
parentdocker: back to master branch, disabled building of the resolver-compat (diff)
downloadknot-a636c6de2130ab759a172dd49d6b71f74c556cde.tar.xz
knot-a636c6de2130ab759a172dd49d6b71f74c556cde.zip
Merge branch 'resolver_improvements' into 'master'
Summary: * requestor: fixed connected UDP sockets (not used in authoritative) * requestor: connects only if layers generate an answer (this saves connect() if a query can be satisfied from cache) * namedb: track full mapsize (ENOSPC) * namedb: memory reservation on insert (saves one alloc and memset) * packet: don't prealloc rrsets, allocate them from the packet mempool (not usable in resolver, as each request usually needs multiple queries)
-rw-r--r--src/knot/ctl/knotc_main.c2
-rw-r--r--src/knot/ctl/remote.c2
-rw-r--r--src/knot/nameserver/axfr.c6
-rw-r--r--src/knot/nameserver/internet.c5
-rw-r--r--src/knot/nameserver/ixfr.c13
-rw-r--r--src/knot/nameserver/notify.c2
-rw-r--r--src/knot/server/tcp-handler.c2
-rw-r--r--src/knot/server/udp-handler.c2
-rw-r--r--src/knot/updates/ddns.c9
-rw-r--r--src/knot/updates/zone-update.c2
-rw-r--r--src/knot/zone/zone.c10
-rw-r--r--src/libknot/errcode.c3
-rw-r--r--src/libknot/errcode.h5
-rw-r--r--src/libknot/internal/namedb/namedb_lmdb.c16
-rw-r--r--src/libknot/internal/namedb/namedb_trie.c5
-rw-r--r--src/libknot/internal/net.c38
-rw-r--r--src/libknot/internal/net.h13
-rw-r--r--src/libknot/internal/sockaddr.c4
-rw-r--r--src/libknot/packet/pkt.c101
-rw-r--r--src/libknot/packet/pkt.h19
-rw-r--r--src/libknot/processing/requestor.c83
-rw-r--r--src/utils/common/exec.c22
-rw-r--r--src/utils/kdig/kdig_exec.c4
-rw-r--r--tests/namedb.c2
-rw-r--r--tests/pkt.c2
-rw-r--r--tests/process_answer.c2
-rw-r--r--tests/process_query.c2
-rw-r--r--tests/requestor.c4
28 files changed, 236 insertions, 144 deletions
diff --git a/src/knot/ctl/knotc_main.c b/src/knot/ctl/knotc_main.c
index 37f95e540..cf8bc1b42 100644
--- a/src/knot/ctl/knotc_main.c
+++ b/src/knot/ctl/knotc_main.c
@@ -164,7 +164,7 @@ static int cmd_remote_reply(int c)
switch(ret) {
case KNOT_RCODE_NOERROR:
if (authority->count > 0) {
- ret = cmd_remote_print_reply(&authority->rr[0]);
+ ret = cmd_remote_print_reply(knot_pkt_rr(authority, 0));
}
break;
case KNOT_RCODE_REFUSED:
diff --git a/src/knot/ctl/remote.c b/src/knot/ctl/remote.c
index 2a8525de7..3c48bd1a1 100644
--- a/src/knot/ctl/remote.c
+++ b/src/knot/ctl/remote.c
@@ -701,7 +701,7 @@ int remote_answer(int sock, server_t *s, knot_pkt_t *pkt)
}
const knot_pktsection_t *authority = knot_pkt_section(pkt, KNOT_AUTHORITY);
- args.arg = authority->rr;
+ args.arg = knot_pkt_rr(authority, 0);
args.argc = authority->count;
args.rc = KNOT_RCODE_NOERROR;
diff --git a/src/knot/nameserver/axfr.c b/src/knot/nameserver/axfr.c
index 671d9acc2..d21f53458 100644
--- a/src/knot/nameserver/axfr.c
+++ b/src/knot/nameserver/axfr.c
@@ -355,13 +355,13 @@ static int axfr_answer_packet(knot_pkt_t *pkt, struct xfr_proc *proc)
zcreator_t zc = {.z = proc->contents, .master = false, .ret = KNOT_EOK };
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
+ const knot_rrset_t *answer_rr = knot_pkt_rr(answer, 0);
for (uint16_t i = 0; i < answer->count; ++i) {
- const knot_rrset_t *rr = &answer->rr[i];
- if (rr->type == KNOT_RRTYPE_SOA &&
+ if (answer_rr[i].type == KNOT_RRTYPE_SOA &&
node_rrtype_exists(zc.z->apex, KNOT_RRTYPE_SOA)) {
return KNOT_NS_PROC_DONE;
} else {
- int ret = zcreator_step(&zc, rr);
+ int ret = zcreator_step(&zc, &answer_rr[i]);
if (ret != KNOT_EOK) {
return KNOT_NS_PROC_FAIL;
}
diff --git a/src/knot/nameserver/internet.c b/src/knot/nameserver/internet.c
index 862053c5f..c099335ff 100644
--- a/src/knot/nameserver/internet.c
+++ b/src/knot/nameserver/internet.c
@@ -866,7 +866,8 @@ static int process_soa_answer(knot_pkt_t *pkt, struct answer_data *data)
/* Expect SOA in answer section. */
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
- if (answer->count < 1 || answer->rr[0].type != KNOT_RRTYPE_SOA) {
+ const knot_rrset_t *first_rr = knot_pkt_rr(answer, 0);
+ if (answer->count < 1 || first_rr->type != KNOT_RRTYPE_SOA) {
return KNOT_NS_PROC_FAIL;
}
@@ -879,7 +880,7 @@ static int process_soa_answer(knot_pkt_t *pkt, struct answer_data *data)
/* Check if master has newer zone and schedule transfer. */
knot_rdataset_t *soa = node_rdataset(zone->contents->apex, KNOT_RRTYPE_SOA);
uint32_t our_serial = knot_soa_serial(soa);
- uint32_t their_serial = knot_soa_serial(&answer->rr[0].rrs);
+ uint32_t their_serial = knot_soa_serial(&first_rr->rrs);
if (serial_compare(our_serial, their_serial) >= 0) {
ANSWER_LOG(LOG_INFO, data, "refresh, outgoing", "zone is up-to-date");
zone_events_cancel(zone, ZONE_EVENT_EXPIRE);
diff --git a/src/knot/nameserver/ixfr.c b/src/knot/nameserver/ixfr.c
index 052a27176..e11461b38 100644
--- a/src/knot/nameserver/ixfr.c
+++ b/src/knot/nameserver/ixfr.c
@@ -197,7 +197,7 @@ static int ixfr_query_check(struct query_data *qdata)
NS_NEED_QTYPE(qdata, KNOT_RRTYPE_IXFR, KNOT_RCODE_FORMERR);
/* Need SOA authority record. */
const knot_pktsection_t *authority = knot_pkt_section(qdata->query, KNOT_AUTHORITY);
- const knot_rrset_t *their_soa = &authority->rr[0];
+ const knot_rrset_t *their_soa = knot_pkt_rr(authority, 0);
if (authority->count < 1 || their_soa->type != KNOT_RRTYPE_SOA) {
qdata->rcode = KNOT_RCODE_FORMERR;
return KNOT_NS_PROC_FAIL;
@@ -241,7 +241,8 @@ static int ixfr_answer_init(struct query_data *qdata)
}
/* Compare serials. */
- const knot_rrset_t *their_soa = &knot_pkt_section(qdata->query, KNOT_AUTHORITY)->rr[0];
+ const knot_pktsection_t *authority = knot_pkt_section(qdata->query, KNOT_AUTHORITY);
+ const knot_rrset_t *their_soa = knot_pkt_rr(authority, 0);
list_t chgsets;
init_list(&chgsets);
int ret = ixfr_load_chsets(&chgsets, (zone_t *)qdata->zone, their_soa);
@@ -332,8 +333,8 @@ static bool ixfr_is_axfr(const knot_pkt_t *pkt)
{
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
return answer->count >= 2 &&
- answer->rr[0].type == KNOT_RRTYPE_SOA &&
- answer->rr[1].type != KNOT_RRTYPE_SOA;
+ knot_pkt_rr(answer, 0)->type == KNOT_RRTYPE_SOA &&
+ knot_pkt_rr(answer, 1)->type != KNOT_RRTYPE_SOA;
}
/*! \brief Cleans up data allocated by IXFR-in processing. */
@@ -584,7 +585,7 @@ static int process_ixfrin_packet(knot_pkt_t *pkt, struct answer_data *adata)
return KNOT_NS_PROC_FAIL;
}
- const knot_rrset_t *rr = &answer->rr[i];
+ const knot_rrset_t *rr = knot_pkt_rr(answer, i);
if (out_of_zone(rr, ixfr)) {
continue;
}
@@ -674,7 +675,7 @@ static int check_format(knot_pkt_t *pkt)
{
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
- if (answer->count >= 1 && answer->rr[0].type == KNOT_RRTYPE_SOA) {
+ if (answer->count >= 1 && knot_pkt_rr(answer, 0)->type == KNOT_RRTYPE_SOA) {
return KNOT_EOK;
} else {
return KNOT_EMALF;
diff --git a/src/knot/nameserver/notify.c b/src/knot/nameserver/notify.c
index 2fdab0923..01128ed81 100644
--- a/src/knot/nameserver/notify.c
+++ b/src/knot/nameserver/notify.c
@@ -85,7 +85,7 @@ int notify_process_query(knot_pkt_t *pkt, struct query_data *qdata)
/* SOA RR in answer may be included, recover serial. */
const knot_pktsection_t *answer = knot_pkt_section(qdata->query, KNOT_ANSWER);
if (answer->count > 0) {
- const knot_rrset_t *soa = &answer->rr[0];
+ const knot_rrset_t *soa = knot_pkt_rr(answer, 0);
if (soa->type == KNOT_RRTYPE_SOA) {
uint32_t serial = knot_soa_serial(&soa->rrs);
NOTIFY_QLOG(LOG_INFO, "received serial %u", serial);
diff --git a/src/knot/server/tcp-handler.c b/src/knot/server/tcp-handler.c
index 83f7de609..abe0be547 100644
--- a/src/knot/server/tcp-handler.c
+++ b/src/knot/server/tcp-handler.c
@@ -315,7 +315,7 @@ int tcp_master(dthread_t *thread)
/* Create big enough memory cushion. */
mm_ctx_t mm;
- mm_ctx_mempool(&mm, 4 * sizeof(knot_pkt_t));
+ mm_ctx_mempool(&mm, 16 * MM_DEFAULT_BLKSIZE);
/* Create TCP answering context. */
tcp.server = handler->server;
diff --git a/src/knot/server/udp-handler.c b/src/knot/server/udp-handler.c
index 7f9182f1e..fcb9c5f42 100644
--- a/src/knot/server/udp-handler.c
+++ b/src/knot/server/udp-handler.c
@@ -500,7 +500,7 @@ int udp_master(dthread_t *thread)
/* Create big enough memory cushion. */
mm_ctx_t mm;
- mm_ctx_mempool(&mm, 4 * sizeof(knot_pkt_t));
+ mm_ctx_mempool(&mm, 16 * MM_DEFAULT_BLKSIZE);
udp.overlay.mm = &mm;
/* Chose select as epoll/kqueue has larger overhead for a
diff --git a/src/knot/updates/ddns.c b/src/knot/updates/ddns.c
index 62f9ec873..b6ea928fa 100644
--- a/src/knot/updates/ddns.c
+++ b/src/knot/updates/ddns.c
@@ -892,9 +892,10 @@ int ddns_process_prereqs(const knot_pkt_t *query, zone_update_t *update,
init_list(&rrset_list);
const knot_pktsection_t *answer = knot_pkt_section(query, KNOT_ANSWER);
+ const knot_rrset_t *answer_rr = knot_pkt_rr(answer, 0);
for (int i = 0; i < answer->count; ++i) {
// Check what can be checked, store full RRs into list
- ret = process_prereq(&answer->rr[i], knot_pkt_qclass(query),
+ ret = process_prereq(&answer_rr[i], knot_pkt_qclass(query),
update, rcode, &rrset_list);
if (ret != KNOT_EOK) {
rrset_list_clear(&rrset_list);
@@ -934,10 +935,10 @@ int ddns_process_update(const zone_t *zone, const knot_pkt_t *query,
// Process all RRs in the authority section.
int apex_ns_rem = 0;
- const knot_pktsection_t *authority =
- knot_pkt_section(query, KNOT_AUTHORITY);
+ const knot_pktsection_t *authority = knot_pkt_section(query, KNOT_AUTHORITY);
+ const knot_rrset_t *authority_rr = knot_pkt_rr(authority, 0);
for (uint16_t i = 0; i < authority->count; ++i) {
- const knot_rrset_t *rr = &authority->rr[i];
+ const knot_rrset_t *rr = &authority_rr[i];
// Check if RR is correct.
int ret = check_update(rr, query, rcode);
if (ret != KNOT_EOK) {
diff --git a/src/knot/updates/zone-update.c b/src/knot/updates/zone-update.c
index 373cdc693..68907feb3 100644
--- a/src/knot/updates/zone-update.c
+++ b/src/knot/updates/zone-update.c
@@ -119,7 +119,7 @@ void zone_update_init(zone_update_t *update, const zone_contents_t *zone, change
{
update->zone = zone;
update->change = change;
- mm_ctx_mempool(&update->mm, 4096);
+ mm_ctx_mempool(&update->mm, MM_DEFAULT_BLKSIZE);
}
const zone_node_t *zone_update_get_node(zone_update_t *update, const knot_dname_t *dname)
diff --git a/src/knot/zone/zone.c b/src/knot/zone/zone.c
index 7584a0801..2017d6937 100644
--- a/src/knot/zone/zone.c
+++ b/src/knot/zone/zone.c
@@ -314,12 +314,16 @@ bool zone_transfer_needed(const zone_t *zone, const knot_pkt_t *pkt)
}
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
- const knot_rrset_t soa = answer->rr[0];
- if (soa.type != KNOT_RRTYPE_SOA) {
+ if (answer->count < 1) {
+ return false;
+ }
+
+ const knot_rrset_t *soa = knot_pkt_rr(answer, 0);
+ if (soa->type != KNOT_RRTYPE_SOA) {
return false;
}
return serial_compare(zone_contents_serial(zone->contents),
- knot_soa_serial(&soa.rrs)) < 0;
+ knot_soa_serial(&soa->rrs)) < 0;
}
diff --git a/src/libknot/errcode.c b/src/libknot/errcode.c
index 0f7aef2b3..a8a744569 100644
--- a/src/libknot/errcode.c
+++ b/src/libknot/errcode.c
@@ -124,6 +124,9 @@ const error_table_t error_messages[] = {
/* Dynamic backend errors. */
{ KNOT_DATABASE_ERROR, "unspecified database error" },
+ /* Processing errors. */
+ { KNOT_LAYER_ERROR, "processing layer error" },
+
{ KNOT_ERROR, NULL } /* Terminator */
};
diff --git a/src/libknot/errcode.h b/src/libknot/errcode.h
index b14f54c93..ff847c413 100644
--- a/src/libknot/errcode.h
+++ b/src/libknot/errcode.h
@@ -137,7 +137,10 @@ enum knot_error {
KNOT_NSEC3_ECOMPUTE_HASH,
/* Database backend. */
- KNOT_DATABASE_ERROR
+ KNOT_DATABASE_ERROR,
+
+ /* Processing error. */
+ KNOT_LAYER_ERROR
};
/*!
diff --git a/src/libknot/internal/namedb/namedb_lmdb.c b/src/libknot/internal/namedb/namedb_lmdb.c
index 828384c3f..c6a91e74f 100644
--- a/src/libknot/internal/namedb/namedb_lmdb.c
+++ b/src/libknot/internal/namedb/namedb_lmdb.c
@@ -61,6 +61,10 @@ static int lmdb_error_to_knot(int error)
return KNOT_EOK;
}
+ if (error == MDB_MAP_FULL || error == MDB_TXN_FULL || error == ENOSPC) {
+ return KNOT_ESPACE;
+ }
+
if (MDB_KEYEXIST <= error && error <= MDB_LAST_ERRCODE) {
return KNOT_DATABASE_ERROR;
}
@@ -402,11 +406,21 @@ static int insert(namedb_txn_t *txn, namedb_val_t *key, namedb_val_t *val, unsig
MDB_val db_key = { key->len, key->data };
MDB_val data = { val->len, val->data };
- int ret = mdb_put(txn->txn, env->dbi, &db_key, &data, 0);
+ /* Reserve if only size is declared. */
+ unsigned mdb_flags = 0;
+ if (val->len > 0 && val->data == NULL) {
+ mdb_flags |= MDB_RESERVE;
+ }
+
+ int ret = mdb_put(txn->txn, env->dbi, &db_key, &data, mdb_flags);
if (ret != MDB_SUCCESS) {
return lmdb_error_to_knot(ret);
}
+ /* Update the result. */
+ val->data = data.mv_data;
+ val->len = data.mv_size;
+
return KNOT_EOK;
}
diff --git a/src/libknot/internal/namedb/namedb_trie.c b/src/libknot/internal/namedb/namedb_trie.c
index de94324a1..2b2f614ab 100644
--- a/src/libknot/internal/namedb/namedb_trie.c
+++ b/src/libknot/internal/namedb/namedb_trie.c
@@ -92,6 +92,11 @@ static int find(namedb_txn_t *txn, namedb_val_t *key, namedb_val_t *val, unsigne
static int insert(namedb_txn_t *txn, namedb_val_t *key, namedb_val_t *val, unsigned flags)
{
+ /* No flags supported. */
+ if (flags != 0) {
+ return KNOT_ENOTSUP;
+ }
+
value_t *ret = hattrie_get((hattrie_t *)txn->db, key->data, key->len);
if (ret == NULL) {
return KNOT_ENOMEM;
diff --git a/src/libknot/internal/net.c b/src/libknot/internal/net.c
index 58d945676..80dafb4b5 100644
--- a/src/libknot/internal/net.c
+++ b/src/libknot/internal/net.c
@@ -15,6 +15,7 @@
*/
#include <stdlib.h>
+#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
@@ -169,7 +170,7 @@ int net_is_connected(int fd)
}
/*! \brief Wait for data and return true if data arrived. */
-static int tcp_wait_for_data(int fd, struct timeval *timeout)
+static int wait_for_data(int fd, struct timeval *timeout)
{
fd_set set;
FD_ZERO(&set);
@@ -178,11 +179,11 @@ static int tcp_wait_for_data(int fd, struct timeval *timeout)
}
/* \brief Receive a block of data from TCP socket with wait. */
-static int tcp_recv_data(int fd, uint8_t *buf, int len, struct timeval *timeout)
+static int recv_data(int fd, uint8_t *buf, int len, bool oneshot, struct timeval *timeout)
{
int ret = 0;
int rcvd = 0;
- int flags = 0;
+ int flags = MSG_DONTWAIT;
#ifdef MSG_NOSIGNAL
flags |= MSG_NOSIGNAL;
@@ -193,7 +194,12 @@ static int tcp_recv_data(int fd, uint8_t *buf, int len, struct timeval *timeout)
ret = recv(fd, buf + rcvd, len - rcvd, flags);
if (ret > 0) {
rcvd += ret;
- continue;
+ /* One-shot recv() */
+ if (oneshot) {
+ return ret;
+ } else {
+ continue;
+ }
}
/* Check for disconnected socket. */
if (ret == 0) {
@@ -203,7 +209,7 @@ static int tcp_recv_data(int fd, uint8_t *buf, int len, struct timeval *timeout)
/* Check for no data available. */
if (errno == EAGAIN || errno == EINTR) {
/* Continue only if timeout didn't expire. */
- ret = tcp_wait_for_data(fd, timeout);
+ ret = wait_for_data(fd, timeout);
if (ret) {
continue;
} else {
@@ -217,8 +223,7 @@ static int tcp_recv_data(int fd, uint8_t *buf, int len, struct timeval *timeout)
return rcvd;
}
-int udp_send_msg(int fd, const uint8_t *msg, size_t msglen,
- const struct sockaddr *addr)
+int udp_send_msg(int fd, const uint8_t *msg, size_t msglen, const struct sockaddr *addr)
{
socklen_t addr_len = sockaddr_len(addr);
int ret = sendto(fd, msg, msglen, 0, addr, addr_len);
@@ -229,15 +234,9 @@ int udp_send_msg(int fd, const uint8_t *msg, size_t msglen,
return ret;
}
-int udp_recv_msg(int fd, uint8_t *buf, size_t len, struct sockaddr *addr)
+int udp_recv_msg(int fd, uint8_t *buf, size_t len, struct timeval *timeout)
{
- socklen_t addr_len = sizeof(struct sockaddr_storage);
- int ret = recvfrom(fd, buf, len, 0, addr, &addr_len);
- if (ret < 0) {
- return KNOT_ECONN;
- }
-
- return ret;
+ return recv_data(fd, buf, len, true, timeout);
}
int tcp_send_msg(int fd, const uint8_t *msg, size_t msglen)
@@ -268,7 +267,7 @@ int tcp_recv_msg(int fd, uint8_t *buf, size_t len, struct timeval *timeout)
/* Receive size. */
unsigned short pktsize = 0;
- int ret = tcp_recv_data(fd, (uint8_t *)&pktsize, sizeof(pktsize), timeout);
+ int ret = recv_data(fd, (uint8_t *)&pktsize, sizeof(pktsize), false, timeout);
if (ret != sizeof(pktsize)) {
return ret;
}
@@ -281,10 +280,5 @@ int tcp_recv_msg(int fd, uint8_t *buf, size_t len, struct timeval *timeout)
}
/* Receive payload. */
- ret = tcp_recv_data(fd, buf, pktsize, timeout);
- if (ret != pktsize) {
- return ret;
- }
-
- return ret;
+ return recv_data(fd, buf, pktsize, false, timeout);
}
diff --git a/src/libknot/internal/net.h b/src/libknot/internal/net.h
index 5b44150c2..2ca95bd36 100644
--- a/src/libknot/internal/net.h
+++ b/src/libknot/internal/net.h
@@ -78,32 +78,31 @@ int net_connected_socket(int type, const struct sockaddr_storage *dst_addr,
int net_is_connected(int fd);
/*!
- * \brief Send a UDP message.
+ * \brief Send a UDP message over connected socket.
*
* \param fd Associated socket.
* \param msg Buffer for a query wireformat.
* \param msglen Buffer maximum size.
- * \param addr Destination address.
+ * \param addr Destination address (or NULL if connected).
*
* \retval Number of sent data on success.
* \retval KNOT_ERROR on error.
*/
-int udp_send_msg(int fd, const uint8_t *msg, size_t msglen,
- const struct sockaddr *addr);
+int udp_send_msg(int fd, const uint8_t *msg, size_t msglen, const struct sockaddr *addr);
/*!
- * \brief Receive a UDP message.
+ * \brief Receive a UDP message from connected socket.
*
* \param fd Associated socket.
* \param buf Buffer for incoming bytestream.
* \param len Buffer maximum size.
- * \param addr Source address.
+ * \param timeout Message receive timeout.
*
* \retval Number of read bytes on success.
* \retval KNOT_ERROR on error.
* \retval KNOT_ENOMEM on potential buffer overflow.
*/
-int udp_recv_msg(int fd, uint8_t *buf, size_t len, struct sockaddr *addr);
+int udp_recv_msg(int fd, uint8_t *buf, size_t len, struct timeval *timeout);
/*!
* \brief Send a TCP message.
diff --git a/src/libknot/internal/sockaddr.c b/src/libknot/internal/sockaddr.c
index cebee1888..a6c9099bb 100644
--- a/src/libknot/internal/sockaddr.c
+++ b/src/libknot/internal/sockaddr.c
@@ -25,6 +25,10 @@
int sockaddr_len(const struct sockaddr *ss)
{
+ if (ss == NULL) {
+ return 0;
+ }
+
const struct sockaddr_storage *sa = (const struct sockaddr_storage *)ss;
switch(sa->ss_family) {
case AF_INET:
diff --git a/src/libknot/packet/pkt.c b/src/libknot/packet/pkt.c
index 2cf93b43d..a176e5776 100644
--- a/src/libknot/packet/pkt.c
+++ b/src/libknot/packet/pkt.c
@@ -27,6 +27,10 @@
#include "libknot/packet/rrset-wire.h"
#include "libknot/internal/macros.h"
+/*! \brief Packet RR array growth step. */
+#define NEXT_RR_ALIGN 16
+#define NEXT_RR_COUNT(count) (((count) / NEXT_RR_ALIGN + 1) * NEXT_RR_ALIGN)
+
/*! \brief Scan packet for RRSet existence. */
static bool pkt_contains(const knot_pkt_t *packet,
const knot_rrset_t *rrset)
@@ -124,6 +128,41 @@ static void pkt_rr_wirecount_add(knot_pkt_t *pkt, knot_section_t section_id,
}
}
+/*! \brief Reserve enough space in the RR arrays. */
+static int pkt_rr_array_alloc(knot_pkt_t *pkt, uint16_t count)
+{
+ /* Enough space. */
+ if (pkt->rrset_allocd >= count) {
+ return KNOT_EOK;
+ }
+
+ /* Allocate rr_info and rr fields to next size. */
+ size_t next_size = NEXT_RR_COUNT(count);
+ knot_rrinfo_t *rr_info = mm_alloc(&pkt->mm, sizeof(knot_rrinfo_t) * next_size);
+ if (rr_info == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ knot_rrset_t *rr = mm_alloc(&pkt->mm, sizeof(knot_rrset_t) * next_size);
+ if (rr == NULL) {
+ mm_free(&pkt->mm, rr_info);
+ return KNOT_ENOMEM;
+ }
+
+ /* Copy the old data. */
+ memcpy(rr_info, pkt->rr_info, pkt->rrset_allocd * sizeof(knot_rrinfo_t));
+ memcpy(rr, pkt->rr, pkt->rrset_allocd * sizeof(knot_rrset_t));
+
+ /* Reassign and free old data. */
+ mm_free(&pkt->mm, pkt->rr);
+ mm_free(&pkt->mm, pkt->rr_info);
+ pkt->rr = rr;
+ pkt->rr_info = rr_info;
+ pkt->rrset_allocd = next_size;
+
+ return KNOT_EOK;
+}
+
/*! \brief Clear the packet and switch wireformat pointers (possibly allocate new). */
static int pkt_reset(knot_pkt_t *pkt, void *wire, uint16_t len)
{
@@ -131,14 +170,12 @@ static int pkt_reset(knot_pkt_t *pkt, void *wire, uint16_t len)
/* Free allocated data. */
pkt_free_data(pkt);
-
- /* NULL everything up to 'sections' (not the large data fields). */
- int ret = KNOT_EOK;
mm_ctx_t mm = pkt->mm;
- memset(pkt, 0, offsetof(knot_pkt_t, rr_info));
+ memset(pkt, 0, sizeof(knot_pkt_t));
pkt->mm = mm;
/* Initialize wire. */
+ int ret = KNOT_EOK;
if (wire == NULL) {
ret = pkt_wire_alloc(pkt, len);
} else {
@@ -185,9 +222,9 @@ static knot_pkt_t *pkt_new_mm(void *wire, uint16_t len, mm_ctx_t *mm)
if (pkt == NULL) {
return NULL;
}
+ memset(pkt, 0, sizeof(knot_pkt_t));
/* No data to free, set memory context. */
- pkt->rrset_count = 0;
memcpy(&pkt->mm, mm, sizeof(mm_ctx_t));
if (pkt_reset(pkt, wire, len) != KNOT_EOK) {
mm_free(mm, pkt);
@@ -233,6 +270,12 @@ int knot_pkt_copy(knot_pkt_t *dst, const knot_pkt_t *src)
}
}
+ /* Invalidate arrays . */
+ dst->rr = NULL;
+ dst->rr_info = NULL;
+ dst->rrset_count = 0;
+ dst->rrset_allocd = 0;
+
/* @note This could be done more effectively if needed. */
return knot_pkt_parse(dst, 0);
}
@@ -291,6 +334,10 @@ void knot_pkt_free(knot_pkt_t **pkt)
/* Free temporary RRSets. */
pkt_free_data(*pkt);
+ /* Free RR/RR info arrays. */
+ mm_free(&(*pkt)->mm, (*pkt)->rr);
+ mm_free(&(*pkt)->mm, (*pkt)->rr_info);
+
// free the space for wireformat
if ((*pkt)->flags & KNOT_PF_FREE) {
(*pkt)->mm.free((*pkt)->wire);
@@ -423,8 +470,9 @@ int knot_pkt_begin(knot_pkt_t *pkt, knot_section_t section_id)
pkt->current = section_id;
/* Remember watermark. */
- pkt->sections[section_id].rr = pkt->rr + pkt->rrset_count;
- pkt->sections[section_id].rrinfo = pkt->rr_info + pkt->rrset_count;
+ pkt->sections[section_id].pkt = pkt;
+ pkt->sections[section_id].pos = pkt->rrset_count;
+
return KNOT_EOK;
}
@@ -474,12 +522,18 @@ int knot_pkt_put(knot_pkt_t *pkt, uint16_t compr_hint, const knot_rrset_t *rr,
return KNOT_EINVAL;
}
+ /* Reserve memory for RR descriptors. */
+ int ret = pkt_rr_array_alloc(pkt, pkt->rrset_count + 1);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
knot_rrinfo_t *rrinfo = &pkt->rr_info[pkt->rrset_count];
memset(rrinfo, 0, sizeof(knot_rrinfo_t));
rrinfo->pos = pkt->size;
rrinfo->flags = flags;
rrinfo->compress_ptr[0] = compr_hint;
- pkt->rr[pkt->rrset_count] = *rr;
+ memcpy(pkt->rr + pkt->rrset_count, rr, sizeof(knot_rrset_t));
/* Check for double insertion. */
if ((flags & KNOT_PF_CHECKDUP) &&
@@ -499,7 +553,7 @@ int knot_pkt_put(knot_pkt_t *pkt, uint16_t compr_hint, const knot_rrset_t *rr,
compr.wire);
/* Write RRSet to wireformat. */
- int ret = knot_rrset_to_wire(rr, pos, maxlen, &compr);
+ ret = knot_rrset_to_wire(rr, pos, maxlen, &compr);
if (ret < 0) {
/* Truncate packet if required. */
if (ret == KNOT_ESPACE && !(flags & KNOT_PF_NOTRUNC)) {
@@ -538,6 +592,16 @@ const knot_pktsection_t *knot_pkt_section(const knot_pkt_t *pkt,
}
_public_
+const knot_rrset_t *knot_pkt_rr(const knot_pktsection_t *section, uint16_t i)
+{
+ if (section == NULL) {
+ return NULL;
+ }
+
+ return section->pkt->rr + section->pos + i;
+}
+
+_public_
int knot_pkt_parse(knot_pkt_t *pkt, unsigned flags)
{
if (pkt == NULL) {
@@ -656,8 +720,13 @@ int knot_pkt_parse_rr(knot_pkt_t *pkt, unsigned flags)
return KNOT_EFEWDATA;
}
+ /* Reserve memory for RR descriptors. */
+ int ret = pkt_rr_array_alloc(pkt, pkt->rrset_count + 1);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
/* Initialize RR info. */
- int ret = KNOT_EOK;
memset(&pkt->rr_info[pkt->rrset_count], 0, sizeof(knot_rrinfo_t));
pkt->rr_info[pkt->rrset_count].pos = pkt->parsed;
pkt->rr_info[pkt->rrset_count].flags = KNOT_PF_FREE;
@@ -714,7 +783,14 @@ int knot_pkt_parse_payload(knot_pkt_t *pkt, unsigned flags)
assert(pkt->wire != NULL);
assert(pkt->size > 0);
- int ret = KNOT_ERROR;
+ /* Reserve memory in advance to avoid resizing. */
+ size_t rr_count = knot_wire_get_ancount(pkt->wire) +
+ knot_wire_get_nscount(pkt->wire) +
+ knot_wire_get_arcount(pkt->wire);
+ int ret = pkt_rr_array_alloc(pkt, rr_count);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
for (knot_section_t i = KNOT_ANSWER; i <= KNOT_ADDITIONAL; ++i) {
ret = knot_pkt_begin(pkt, i);
@@ -730,7 +806,8 @@ int knot_pkt_parse_payload(knot_pkt_t *pkt, unsigned flags)
/* TSIG must be last record of AR if present. */
const knot_pktsection_t *ar = knot_pkt_section(pkt, KNOT_ADDITIONAL);
if (pkt->tsig_rr != NULL) {
- if (ar->count > 0 && pkt->tsig_rr->rrs.data != ar->rr[ar->count - 1].rrs.data) {
+ const knot_rrset_t *last_rr = knot_pkt_rr(ar, ar->count - 1);
+ if (ar->count > 0 && pkt->tsig_rr->rrs.data != last_rr->rrs.data) {
return KNOT_EMALF;
}
}
diff --git a/src/libknot/packet/pkt.h b/src/libknot/packet/pkt.h
index 6534ac9f8..b9641ff84 100644
--- a/src/libknot/packet/pkt.h
+++ b/src/libknot/packet/pkt.h
@@ -39,8 +39,8 @@
/* Number of packet sections (ANSWER, AUTHORITY, ADDITIONAL). */
#define KNOT_PKT_SECTIONS 3
-/* Number of maximum RRs in packet. */
-#define KNOT_PKT_MAX_RRS (KNOT_WIRE_MAX_PAYLOAD / KNOT_WIRE_RR_MIN_SIZE)
+/* Forward decls */
+struct knot_pkt;
/*!
* \brief DNS query types (internal use only).
@@ -80,9 +80,9 @@ enum {
* This structure is required for random access to packet sections.
*/
typedef struct {
- const knot_rrset_t *rr; /*!< Array of RRSets for this section. */
- knot_rrinfo_t *rrinfo; /*!< Compression info for each RRSet. */
- uint16_t count; /*!< Number of RRSets in this section. */
+ struct knot_pkt *pkt; /*!< Owner. */
+ uint16_t pos; /*!< Position in the rr/rrinfo fields in packet. */
+ uint16_t count; /*!< Number of RRSets in this section. */
} knot_pktsection_t;
/*!
@@ -106,11 +106,10 @@ typedef struct knot_pkt {
knot_section_t current;
knot_pktsection_t sections[KNOT_PKT_SECTIONS];
- /*! \note <== Memory below this point is not cleared on init for performance reasons. */
-
/* Packet RRSet (meta)data. */
- knot_rrinfo_t rr_info[KNOT_PKT_MAX_RRS];
- knot_rrset_t rr[KNOT_PKT_MAX_RRS];
+ size_t rrset_allocd;
+ knot_rrinfo_t *rr_info;
+ knot_rrset_t *rr;
mm_ctx_t mm; /*!< Memory allocation context. */
} knot_pkt_t;
@@ -244,6 +243,8 @@ int knot_pkt_put(knot_pkt_t *pkt, uint16_t compr_hint, const knot_rrset_t *rr,
const knot_pktsection_t *knot_pkt_section(const knot_pkt_t *pkt,
knot_section_t section_id);
+/*! \brief Get RRSet from the packet section. */
+const knot_rrset_t *knot_pkt_rr(const knot_pktsection_t *section, uint16_t i);
/*
* Packet parsing API.
*/
diff --git a/src/libknot/processing/requestor.c b/src/libknot/processing/requestor.c
index f1d93e433..a45b073f2 100644
--- a/src/libknot/processing/requestor.c
+++ b/src/libknot/processing/requestor.c
@@ -40,41 +40,28 @@ static struct knot_request *request_make(mm_ctx_t *mm)
return request;
}
-/*! \brief Wait for socket readiness. */
-static int request_wait(int fd, int state, struct timeval *timeout)
+/*! \brief Ensure a socket is connected. */
+static int request_ensure_connected(struct knot_request *request)
{
- fd_set set;
- FD_ZERO(&set);
- FD_SET(fd, &set);
-
- switch(state) {
- case KNOT_NS_PROC_FULL: /* Wait for writeability. */
- return select(fd + 1, NULL, &set, NULL, timeout);
- case KNOT_NS_PROC_MORE: /* Wait for data. */
- return select(fd + 1, &set, NULL, NULL, timeout);
- default:
- return -1;
+ /* Connect the socket if not already connected. */
+ if (request->fd < 0) {
+ int sock_type = use_tcp(request) ? SOCK_STREAM : SOCK_DGRAM;
+ request->fd = net_connected_socket(sock_type, &request->remote, &request->origin, 0);
+ if (request->fd < 0) {
+ return KNOT_ECONN;
+ }
}
+
+ return KNOT_EOK;
}
static int request_send(struct knot_request *request,
const struct timeval *timeout)
{
- /* Each request has unique timeout. */
- struct timeval tv = { timeout->tv_sec, timeout->tv_usec };
-
/* Wait for writeability or error. */
- int ret = request_wait(request->fd, KNOT_NS_PROC_FULL, &tv);
- if (ret == 0) {
- return KNOT_ETIMEOUT;
- }
-
- /* Check socket error. */
- int err = 0;
- socklen_t len = sizeof(int);
- getsockopt(request->fd, SOL_SOCKET, SO_ERROR, &err, &len);
- if (err != 0) {
- return KNOT_ECONNREFUSED;
+ int ret = request_ensure_connected(request);
+ if (ret != KNOT_EOK) {
+ return ret;
}
/* Send query, construct if not exists. */
@@ -86,8 +73,7 @@ static int request_send(struct knot_request *request,
if (use_tcp(request)) {
ret = tcp_send_msg(request->fd, wire, wire_len);
} else {
- ret = udp_send_msg(request->fd, wire, wire_len,
- (const struct sockaddr *)&request->remote);
+ ret = udp_send_msg(request->fd, wire, wire_len, NULL);
}
if (ret != wire_len) {
return KNOT_ECONN;
@@ -99,22 +85,29 @@ static int request_send(struct knot_request *request,
static int request_recv(struct knot_request *request,
const struct timeval *timeout)
{
- int ret = 0;
knot_pkt_t *resp = request->resp;
knot_pkt_clear(resp);
/* Each request has unique timeout. */
struct timeval tv = { timeout->tv_sec, timeout->tv_usec };
+ /* Wait for readability */
+ int ret = request_ensure_connected(request);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
/* Receive it */
if (use_tcp(request)) {
ret = tcp_recv_msg(request->fd, resp->wire, resp->max_size, &tv);
} else {
- ret = udp_recv_msg(request->fd, resp->wire, resp->max_size,
- (struct sockaddr *)&request->remote);
+ ret = udp_recv_msg(request->fd, resp->wire, resp->max_size, &tv);
}
- if (ret < 0) {
+ if (ret <= 0) {
resp->size = 0;
+ if (ret == 0) {
+ return KNOT_ECONN;
+ }
return ret;
}
@@ -204,18 +197,8 @@ int knot_requestor_enqueue(struct knot_requestor *requestor,
return KNOT_EINVAL;
}
- /* Determine comm protocol. */
- int sock_type = SOCK_DGRAM;
- if (use_tcp(request)) {
- sock_type = SOCK_STREAM;
- }
-
- /* Fetch a bound socket. */
- request->fd = net_connected_socket(sock_type, &request->remote,
- &request->origin, O_NONBLOCK);
- if (request->fd < 0) {
- return KNOT_ECONN;
- }
+ /* Set socket as uninitialized. */
+ request->fd = -1;
/* Prepare response buffers. */
request->resp = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, requestor->mm);
@@ -253,9 +236,11 @@ static int request_io(struct knot_requestor *req, struct knot_request *last,
/* Process query and send it out. */
knot_overlay_out(&req->overlay, query);
- ret = request_send(last, timeout);
- if (ret != KNOT_EOK) {
- return ret;
+ if (req->overlay.state == KNOT_NS_PROC_MORE) {
+ ret = request_send(last, timeout);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
}
}
@@ -289,7 +274,7 @@ static int exec_request(struct knot_requestor *req, struct knot_request *last,
/* Expect complete request. */
if (req->overlay.state == KNOT_NS_PROC_FAIL) {
- ret = KNOT_ERROR;
+ ret = KNOT_LAYER_ERROR;
}
/* Finish current query processing. */
diff --git a/src/utils/common/exec.c b/src/utils/common/exec.c
index d90f8b2bb..14318b3ae 100644
--- a/src/utils/common/exec.c
+++ b/src/utils/common/exec.c
@@ -516,13 +516,13 @@ void print_data_xfr(const knot_pkt_t *packet,
switch (style->format) {
case FORMAT_DIG:
- print_section_dig(answers->rr, answers->count, style);
+ print_section_dig(knot_pkt_rr(answers, 0), answers->count, style);
break;
case FORMAT_HOST:
- print_section_host(answers->rr, answers->count, style);
+ print_section_host(knot_pkt_rr(answers, 0), answers->count, style);
break;
case FORMAT_FULL:
- print_section_full(answers->rr, answers->count, style, true);
+ print_section_full(knot_pkt_rr(answers, 0), answers->count, style, true);
// Print TSIG record.
if (style->show_tsig && knot_pkt_has_tsig(packet)) {
@@ -603,12 +603,12 @@ void print_packet(const knot_pkt_t *packet,
switch (style->format) {
case FORMAT_DIG:
if (ancount > 0) {
- print_section_dig(answers->rr, ancount, style);
+ print_section_dig(knot_pkt_rr(answers, 0), ancount, style);
}
break;
case FORMAT_HOST:
if (ancount > 0) {
- print_section_host(answers->rr, ancount, style);
+ print_section_host(knot_pkt_rr(answers, 0), ancount, style);
} else {
print_error_host(rcode, packet, style);
}
@@ -624,17 +624,17 @@ void print_packet(const knot_pkt_t *packet,
if (style->show_answer && ancount > 0) {
printf("\n;; PREREQUISITE SECTION:\n");
- print_section_full(answers->rr, ancount, style, true);
+ print_section_full(knot_pkt_rr(answers, 0), ancount, style, true);
}
if (style->show_authority && nscount > 0) {
printf("\n;; UPDATE SECTION:\n");
- print_section_full(authority->rr, nscount, style, true);
+ print_section_full(knot_pkt_rr(authority, 0), nscount, style, true);
}
if (style->show_additional && arcount > 0) {
printf("\n;; ADDITIONAL DATA:\n");
- print_section_full(additional->rr, arcount, style, true);
+ print_section_full(knot_pkt_rr(additional, 0), arcount, style, true);
}
break;
case FORMAT_FULL:
@@ -648,17 +648,17 @@ void print_packet(const knot_pkt_t *packet,
if (style->show_answer && ancount > 0) {
printf("\n;; ANSWER SECTION:\n");
- print_section_full(answers->rr, ancount, style, true);
+ print_section_full(knot_pkt_rr(answers, 0), ancount, style, true);
}
if (style->show_authority && nscount > 0) {
printf("\n;; AUTHORITY SECTION:\n");
- print_section_full(authority->rr, nscount, style, true);
+ print_section_full(knot_pkt_rr(authority, 0), nscount, style, true);
}
if (style->show_additional && arcount > 0) {
printf("\n;; ADDITIONAL SECTION:\n");
- print_section_full(additional->rr, arcount, style, true);
+ print_section_full(knot_pkt_rr(additional, 0), arcount, style, true);
}
break;
default:
diff --git a/src/utils/kdig/kdig_exec.c b/src/utils/kdig/kdig_exec.c
index 5d53eb306..b91a95855 100644
--- a/src/utils/kdig/kdig_exec.c
+++ b/src/utils/kdig/kdig_exec.c
@@ -438,7 +438,7 @@ static int64_t first_serial_check(const knot_pkt_t *reply)
return -1;
}
- const knot_rrset_t *first = &answer->rr[0];
+ const knot_rrset_t *first = knot_pkt_rr(answer, 0);
if (first->type != KNOT_RRTYPE_SOA) {
return -1;
@@ -454,7 +454,7 @@ static bool last_serial_check(const uint32_t serial, const knot_pkt_t *reply)
return false;
}
- const knot_rrset_t *last = &answer->rr[answer->count - 1];
+ const knot_rrset_t *last = knot_pkt_rr(answer, answer->count - 1);
if (last->type != KNOT_RRTYPE_SOA) {
return false;
diff --git a/tests/namedb.c b/tests/namedb.c
index 71ed9c4a7..d46aacba9 100644
--- a/tests/namedb.c
+++ b/tests/namedb.c
@@ -213,7 +213,7 @@ int main(int argc, char *argv[])
plan_lazy();
mm_ctx_t pool;
- mm_ctx_mempool(&pool, 4096);
+ mm_ctx_mempool(&pool, MM_DEFAULT_BLKSIZE);
/* Temporary DB identifier. */
char dbid_buf[] = "/tmp/namedb.XXXXXX";
diff --git a/tests/pkt.c b/tests/pkt.c
index 42f9b7549..f3cf21bf8 100644
--- a/tests/pkt.c
+++ b/tests/pkt.c
@@ -70,7 +70,7 @@ int main(int argc, char *argv[])
/* Create memory pool context. */
int ret = 0;
mm_ctx_t mm;
- mm_ctx_mempool(&mm, sizeof(knot_pkt_t));
+ mm_ctx_mempool(&mm, MM_DEFAULT_BLKSIZE);
/* Create names and data. */
knot_dname_t* dnames[NAMECOUNT] = {0};
diff --git a/tests/process_answer.c b/tests/process_answer.c
index af2a3b231..88fcca37e 100644
--- a/tests/process_answer.c
+++ b/tests/process_answer.c
@@ -112,7 +112,7 @@ int main(int argc, char *argv[])
/* Create processing context. */
mm_ctx_t mm;
- mm_ctx_mempool(&mm, sizeof(knot_pkt_t));
+ mm_ctx_mempool(&mm, MM_DEFAULT_BLKSIZE);
knot_layer_t proc;
memset(&proc, 0, sizeof(knot_layer_t));
diff --git a/tests/process_query.c b/tests/process_query.c
index af3931a47..264e765da 100644
--- a/tests/process_query.c
+++ b/tests/process_query.c
@@ -79,7 +79,7 @@ int main(int argc, char *argv[])
plan(8*6 + 4); /* exec_query = 6 TAP tests */
mm_ctx_t mm;
- mm_ctx_mempool(&mm, sizeof(knot_pkt_t));
+ mm_ctx_mempool(&mm, MM_DEFAULT_BLKSIZE);
/* Create processing context. */
knot_layer_t proc;
diff --git a/tests/requestor.c b/tests/requestor.c
index 8097f89a1..b57a5cd28 100644
--- a/tests/requestor.c
+++ b/tests/requestor.c
@@ -79,12 +79,12 @@ static void test_disconnected(struct knot_requestor *requestor, conf_iface_t *re
{
/* Enqueue packet. */
int ret = knot_requestor_enqueue(requestor, make_query(requestor, remote));
- is_int(KNOT_ECONN, ret, "requestor: disconnected/enqueue");
+ is_int(KNOT_EOK, ret, "requestor: disconnected/enqueue");
/* Wait for completion. */
struct timeval tv = { 5, 0 };
ret = knot_requestor_exec(requestor, &tv);
- is_int(KNOT_ENOENT, ret, "requestor: disconnected/wait");
+ is_int(KNOT_ECONN, ret, "requestor: disconnected/wait");
}
static void test_connected(struct knot_requestor *requestor, conf_iface_t *remote)