diff options
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) |