diff --git a/Knot.files b/Knot.files index 8def07c81375a278fb1053476c0a0d15f6a039f9..552f82c4b59d30831b4ceef92837d62ffc056901 100644 --- a/Knot.files +++ b/Knot.files @@ -40,6 +40,8 @@ src/common/sockaddr.h src/common/sockaddr.c src/common/crc.c src/common/crc.h +src/common/ref.c +src/common/ref.h src/dnslib/dnslib-common.h src/dnslib/dname.h src/dnslib/dname.c diff --git a/src/Makefile.am b/src/Makefile.am index daa5632842c01007ae339010643556a204363fea..3b101663451fab612a736c781909fb5f224e241a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -153,6 +153,8 @@ libknot_la_SOURCES = \ common/sockaddr.c \ common/crc.h \ common/crc.c \ + common/ref.h \ + common/ref.c \ knot/stat/gatherer.c \ knot/stat/stat.c \ knot/stat/gatherer.h \ diff --git a/src/common/ref.c b/src/common/ref.c new file mode 100644 index 0000000000000000000000000000000000000000..88add37b60d14b5b6a23ebd5877bac0e92ac9dca --- /dev/null +++ b/src/common/ref.c @@ -0,0 +1,28 @@ +#include <stdio.h> + +#include "ref.h" + +void ref_init(ref_t *p, ref_destructor_t dtor) +{ + if (p) { + p->count = 0; + p->dtor = dtor; + } +} + +void ref_retain(ref_t *p) +{ + if (p) { + __sync_add_and_fetch(&p->count, 1); + } +} + +void ref_release(ref_t *p) +{ + if (p) { + int rc = __sync_sub_and_fetch(&p->count, 1); + if (rc == 0) { + p->dtor(p); + } + } +} diff --git a/src/common/ref.h b/src/common/ref.h new file mode 100644 index 0000000000000000000000000000000000000000..03bda19505992a39e86427c9d8e318d073fe4a04 --- /dev/null +++ b/src/common/ref.h @@ -0,0 +1,75 @@ +/*! + * \file ref.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Atomic reference counting structures. + * + * Reference counting allows implicit sharing of objects + * between threads with custom destructor functions. + * + * \addtogroup common_lib + * @{ + */ + +#ifndef _KNOT_REF_H_ +#define _KNOT_REF_H_ + +#include <stddef.h> + +struct ref_t; + +/*! \brief Prototype for object destructor callback. */ +typedef void (*ref_destructor_t)(struct ref_t * p); + +/*! + * \brief Structure for reference counting. + * + * Size equals to two sizes of pointer size. + * Structure may be embedded to the structures which + * we want to use for reference counting. + * + * \code + * struct mystruct { + * ref_t ref; + * int mydata; + * char *mystr; + * } + * \endcode + */ +typedef struct ref_t { + size_t count; /*! \brief Reference counter. */ + ref_destructor_t dtor; /*! \brief Object destructor function. */ +} ref_t; + +/*! + * \brief Initialize reference counter. + * + * Set reference counter to 0 and initialize destructor callback. + * + * \param p Reference-counted object. + * \param dtor Destructor function. + */ +void ref_init(ref_t *p, ref_destructor_t dtor); + +/*! + * \brief Mark object as used by the caller. + * + * Reference counter will be incremented. + * + * \param p Reference-counted object. + */ +void ref_retain(ref_t *p); + +/*! + * \brief Marks object as unused by the caller. + * + * Reference counter will be decremented. + * + * \param p Reference-counted object. + */ +void ref_release(ref_t *p); + +#endif /* _KNOT_REF_H_ */ + +/*! @} */ diff --git a/src/dnslib/dname-table.c b/src/dnslib/dname-table.c index 6ae8c1b58eeeb158b17d40c6a1f9592175a87e90..72258d2f019019605f0c29357425ef5c12fbd36f 100644 --- a/src/dnslib/dname-table.c +++ b/src/dnslib/dname-table.c @@ -49,7 +49,7 @@ static int compare_dname_table_nodes(struct dname_table_node *n1, static void delete_dname_table_node(struct dname_table_node *node, void *data) { if (data) { - dnslib_dname_free(&node->dname); + dnslib_dname_release(node->dname); } /*!< \todo it would be nice to set pointers to NULL. */ @@ -81,6 +81,7 @@ static int dnslib_dname_table_copy_node(const struct dname_table_node *from, } (*to)->dname = from->dname; + dnslib_dname_retain((*to)->dname); (*to)->avl.avl_height = from->avl.avl_height; int ret = dnslib_dname_table_copy_node(from->avl.avl_left, @@ -135,6 +136,9 @@ dnslib_dname_t *dnslib_dname_table_find_dname(const dnslib_dname_table_t *table, if (node == NULL) { return NULL; } else { + /* Increase reference counter. */ + dnslib_dname_retain(node->dname); + return node->dname; } } @@ -160,6 +164,9 @@ int dnslib_dname_table_add_dname(dnslib_dname_table_t *table, // printf("Inserted dname got id %d\n", node->dname->id); assert(node->dname->id != 0); + /* Increase reference counter. */ + dnslib_dname_retain(dname); + TREE_INSERT(table->tree, dname_table_node, avl, node); return DNSLIB_EOK; } @@ -168,7 +175,6 @@ int dnslib_dname_table_add_dname2(dnslib_dname_table_t *table, dnslib_dname_t **dname) { dnslib_dname_t *found_dname = NULL; - int ret; if (table == NULL || dname == NULL || *dname == NULL) { return DNSLIB_EBADARG; @@ -178,20 +184,31 @@ int dnslib_dname_table_add_dname2(dnslib_dname_table_t *table, // printf("Inserting name %s to dname table.\n", name); // free(name); - if ((!(found_dname = - dnslib_dname_table_find_dname(table ,*dname))) && - (ret = dnslib_dname_table_add_dname(table, *dname)) - != DNSLIB_EOK) { -// printf("Error!\n"); - return ret; - } else if (found_dname != NULL && found_dname != *dname) { + /* Fetch dname, need to release it later. */ + found_dname = dnslib_dname_table_find_dname(table ,*dname); + + if (!found_dname) { + /* Store reference in table. */ + return dnslib_dname_table_add_dname(table, *dname); + } else { /*! \todo Remove the check for equality. */ -// name = dnslib_dname_to_str(found_dname); -// printf("Already there: %s (%p)\n", name, found_dname); -// free(name); - dnslib_dname_free(dname); - *dname = found_dname; - return 1; + if (found_dname != *dname) { + //name = dnslib_dname_to_str(found_dname); + //printf("Already there: %s (%p)\n", name, found_dname); + //free(name); + + /* Replace dname with found. */ + dnslib_dname_release(*dname); + *dname = found_dname; + return 1; /*! \todo Error code? */ + + } else { + + /* If the dname is already in the table, there is already + * a reference to it. + */ + dnslib_dname_release(found_dname); + } } // printf("Done.\n"); @@ -199,8 +216,8 @@ int dnslib_dname_table_add_dname2(dnslib_dname_table_t *table, return DNSLIB_EOK; } -int dnslib_dname_table_copy(dnslib_dname_table_t *from, - dnslib_dname_table_t *to) +int dnslib_dname_table_shallow_copy(dnslib_dname_table_t *from, + dnslib_dname_table_t *to) { to->id_counter = from->id_counter; diff --git a/src/dnslib/dname-table.h b/src/dnslib/dname-table.h index d056317a1feb2cc0353ce3887763be15b4a5cfe1..ea2893371e607bd107a65802049cabc043351a52 100644 --- a/src/dnslib/dname-table.h +++ b/src/dnslib/dname-table.h @@ -55,6 +55,9 @@ dnslib_dname_table_t *dnslib_dname_table_new(); /*! * \brief Finds name in the domain name table. * + * \note Reference count to dname will be incremented, caller is responsible + * for releasing it. + * * \param table Domain name table to be searched. * \param dname Dname to be searched. * @@ -105,8 +108,8 @@ int dnslib_dname_table_add_dname2(dnslib_dname_table_t *table, * \param from Original domain name table. * \param to Copy of the domain name table. */ -int dnslib_dname_table_copy(dnslib_dname_table_t *from, - dnslib_dname_table_t *to); +int dnslib_dname_table_shallow_copy(dnslib_dname_table_t *from, + dnslib_dname_table_t *to); /*! * \brief Frees dname table without its nodes. Sets pointer to NULL. diff --git a/src/dnslib/dname.c b/src/dnslib/dname.c index 736bc13f6ce60d691d20bcc797f503436960ef34..dbf405b4503addc06e96ce63ca62ef1066faa204 100644 --- a/src/dnslib/dname.c +++ b/src/dnslib/dname.c @@ -14,6 +14,10 @@ #include "dnslib/utils.h" #include "dnslib/wire.h" +/*! \todo dnames allocated from TLS cache will be discarded after thread + * termination. This shouldn't happpen. + */ +#if 0 /* * Memory cache. */ @@ -46,6 +50,7 @@ static void dnslib_dname_cache_init() (void) pthread_key_create(&dname_ckey, dnslib_dname_cache_free); atexit(dnslib_dname_cache_main_free); // Main thread cleanup } +#endif /*! * \brief Allocate item from thread cache. @@ -56,6 +61,10 @@ static dnslib_dname_t* dnslib_dname_alloc() { return malloc(sizeof(dnslib_dname_t)); + /*! \todo dnames allocated from TLS cache will be discarded after thread + * termination. This shouldn't happpen. + */ +#if 0 /* Initialize dname cache TLS key. */ (void)pthread_once(&dname_once, dnslib_dname_cache_init); @@ -73,6 +82,7 @@ static dnslib_dname_t* dnslib_dname_alloc() } return slab_cache_alloc(cache); +#endif } /*----------------------------------------------------------------------------*/ @@ -326,6 +336,13 @@ DEBUG_DNSLIB_DNAME( return 0; } +/*! \brief Destructor for reference counter. */ +static void dnslib_dname_dtor(struct ref_t *p) +{ + dnslib_dname_t *dname = (dnslib_dname_t *)p; + dnslib_dname_free(&dname); +} + /*----------------------------------------------------------------------------*/ /* API functions */ /*----------------------------------------------------------------------------*/ @@ -340,6 +357,12 @@ dnslib_dname_t *dnslib_dname_new() dname->label_count = -1; dname->id = 0; + /* Initialize reference counting. */ + ref_init(&dname->ref, dnslib_dname_dtor); + + /* Set reference counter to 1, caller should release it after use. */ + dnslib_dname_retain(dname); + return dname; } @@ -411,7 +434,7 @@ dnslib_dname_t *dnslib_dname_new_from_wire(const uint8_t *name, uint size, return NULL; } - dnslib_dname_t *dname = dnslib_dname_alloc(); + dnslib_dname_t *dname = dnslib_dname_new(); if (dname == NULL) { ERR_ALLOC_FAILED; @@ -490,7 +513,7 @@ dnslib_dname_t *dnslib_dname_parse_from_wire(const uint8_t *wire, *pos += 1; } - dnslib_dname_t *dname = dnslib_dname_alloc(); + dnslib_dname_t *dname = dnslib_dname_new(); if (dname == NULL) { ERR_ALLOC_FAILED; @@ -541,7 +564,7 @@ int dnslib_dname_from_wire(const uint8_t *name, uint size, /*----------------------------------------------------------------------------*/ -dnslib_dname_t *dnslib_dname_copy(const dnslib_dname_t *dname) +dnslib_dname_t *dnslib_dname_deep_copy(const dnslib_dname_t *dname) { return dnslib_dname_new_from_wire(dname->name, dname->size, dname->node); diff --git a/src/dnslib/dname.h b/src/dnslib/dname.h index f711c6152e988a1996c1184e8aad9ae78a42b58d..df2d6feece3f49466cade28b64c38acbf811e6ac 100644 --- a/src/dnslib/dname.h +++ b/src/dnslib/dname.h @@ -14,6 +14,7 @@ #include <stdint.h> #include <string.h> +#include "common/ref.h" struct dnslib_node; @@ -36,6 +37,7 @@ struct dnslib_dname { unsigned short label_count; struct dnslib_node *node; /*!< Zone node the domain name belongs to. */ unsigned int id; /*!< ID of domain name used in zone dumping. */ + ref_t ref; /*!< Reference counting. */ }; typedef struct dnslib_dname dnslib_dname_t; @@ -45,6 +47,9 @@ typedef struct dnslib_dname dnslib_dname_t; /*! * \brief Creates empty dname structure (no name, no owner node). * + * \note Newly created dname is referenced, caller is responsible for releasing + * it after use. + * * \return Newly allocated and initialized dname structure. * * \todo Possibly useless. @@ -58,6 +63,9 @@ dnslib_dname_t *dnslib_dname_new(); * The resulting domain name is stored in wire format, but it may not end with * root label (0). * + * \note Newly created dname is referenced, caller is responsible for releasing + * it after use. + * * \param name Domain name in presentation format (labels separated by dots). * \param size Size of the domain name (count of characters with all dots). * \param node Zone node the domain name belongs to. Set to NULL if not @@ -74,6 +82,8 @@ dnslib_dname_t *dnslib_dname_new_from_str(const char *name, unsigned int size, * * \note The name is copied into the structure. * \note If the given name is not a FQDN, the result will be neither. + * \note Newly created dname is referenced, caller is responsible for releasing + * it after use. * * \param name Domain name in wire format. * \param size Size of the domain name in octets. @@ -124,13 +134,16 @@ int dnslib_dname_from_wire(const uint8_t *name, unsigned int size, struct dnslib_node *node, dnslib_dname_t *target); /*! - * \brief Copies the given domain name. + * \brief Duplicates the given domain name. + * + * \note Copied dname referense count is reset to 1, caller is responsible + * for releasing it after use. * * \param dname Domain name to be copied. * * \return New domain name which is an exact copy of \a dname. */ -dnslib_dname_t *dnslib_dname_copy(const dnslib_dname_t *dname); +dnslib_dname_t *dnslib_dname_deep_copy(const dnslib_dname_t *dname); /*! * \brief Converts the given domain name to string representation. @@ -204,6 +217,9 @@ int dnslib_dname_is_fqdn(const dnslib_dname_t *dname); /*! * \brief Creates new domain name by removing leftmost label from \a dname. * + * \note Newly created dname reference count is set to 1, caller is responsible + * for releasing it after use. + * * \param dname Domain name to remove the first label from. * * \return New domain name with the same labels as \a dname, except for the @@ -342,6 +358,45 @@ void dnslib_dname_set_id(dnslib_dname_t *dname, unsigned int id); unsigned int dnslib_dname_get_id(const dnslib_dname_t *dname); +/*! + * \brief Increment reference counter for dname. + * + * Function makes shallow copy (reference). + * + * \param dname Referenced dname. + */ +static inline void dnslib_dname_retain(dnslib_dname_t *dname) { + if (dname) { + ref_retain(&dname->ref); + } +} + +/* +#define dnslib_dname_retain(d) \ + dnslib_dname_retain_((d));\ + if ((d))\ + fprintf(stderr, "dname_retain: %s() at %s:%d, %p refcount=%zu\n",\ + __func__, __FILE__, __LINE__, d, (d)->ref.count) +*/ + +/*! + * \brief Decrement reference counter for dname. + * + * \param dname Referenced dname. + */ +static inline void dnslib_dname_release(dnslib_dname_t *dname) { + if (dname) { + ref_release(&dname->ref); + } +} +/* +#define dnslib_dname_release(d) \ + if ((d))\ + fprintf(stderr, "dname_release: %s() at %s:%d, %p refcount=%zu\n",\ + __func__, __FILE__, __LINE__, d, (d)->ref.count-1);\ + dnslib_dname_release_((d)) +*/ + #endif /* _KNOT_DNSLIB_DNAME_H_ */ /*! @} */ diff --git a/src/dnslib/node.c b/src/dnslib/node.c index 3e35ee50773b1f87004ee68ca1dfd3bb97f42ccc..54e9d6db9e94b28fac20619745cc4bbde1fb300f 100644 --- a/src/dnslib/node.c +++ b/src/dnslib/node.c @@ -170,6 +170,8 @@ dnslib_node_t *dnslib_node_new(dnslib_dname_t *owner, dnslib_node_t *parent, return NULL; } + /* Store reference to owner. */ + dnslib_dname_retain(owner); ret->owner = owner; dnslib_node_set_parent(ret, parent); ret->rrsets = skip_create_list(compare_rrset_types); @@ -434,6 +436,18 @@ dnslib_dname_t *dnslib_node_get_owner(const dnslib_node_t *node) /*----------------------------------------------------------------------------*/ +void dnslib_node_set_owner(dnslib_node_t *node, dnslib_dname_t* owner) +{ + if (node) { + /* Retain new owner and release old owner. */ + dnslib_dname_retain(owner); + dnslib_dname_release(node->owner); + node->owner = owner; + } +} + +/*----------------------------------------------------------------------------*/ + const dnslib_node_t *dnslib_node_wildcard_child(const dnslib_node_t *node, int check_version) { @@ -697,10 +711,12 @@ void dnslib_node_free(dnslib_node_t **node, int free_owner, int fix_refs) debug_dnslib_node("Freeing RRSets.\n"); skip_destroy_list(&(*node)->rrsets, NULL, NULL); } - if (free_owner) { - debug_dnslib_node("Freeing owner.\n"); - dnslib_dname_free(&(*node)->owner); - } + + /*! \todo Always release owner? */ + //if (free_owner) { + debug_dnslib_node("Releasing owner.\n"); + dnslib_dname_release((*node)->owner); + //} // check nodes referencing this node and fix the references @@ -757,7 +773,7 @@ int dnslib_node_compare(dnslib_node_t *node1, dnslib_node_t *node2) /*----------------------------------------------------------------------------*/ -int dnslib_node_deep_copy(const dnslib_node_t *from, dnslib_node_t **to) +int dnslib_node_shallow_copy(const dnslib_node_t *from, dnslib_node_t **to) { // create new node *to = dnslib_node_new(from->owner, from->parent, from->flags); @@ -765,17 +781,10 @@ int dnslib_node_deep_copy(const dnslib_node_t *from, dnslib_node_t **to) return DNSLIB_ENOMEM; } - // copy references - + // copy references // do not use the API function to set parent, so that children count // is not changed - (*to)->parent = from->parent; - (*to)->nsec3_node = from->nsec3_node; - (*to)->nsec3_referer = from->nsec3_referer; - (*to)->wildcard_child = from->wildcard_child; - (*to)->prev = from->prev; - (*to)->next = from->next; - (*to)->children = from->children; + memcpy(*to, from, sizeof(dnslib_node_t)); // copy RRSets // copy the skip list with the old references @@ -786,7 +795,5 @@ int dnslib_node_deep_copy(const dnslib_node_t *from, dnslib_node_t **to) return DNSLIB_ENOMEM; } - (*to)->rrset_count = from->rrset_count; - return DNSLIB_EOK; } diff --git a/src/dnslib/node.h b/src/dnslib/node.h index a0c1003fa2e4c509a184487a76febe980c30d3e1..95a8f741a97b09de81ec0d5e6d1c3dab4695c0e2 100644 --- a/src/dnslib/node.h +++ b/src/dnslib/node.h @@ -106,6 +106,8 @@ typedef enum { /*! * \brief Creates and initializes new node structure. * + * \todo Owner reference counter will be increased. + * * \param owner Owner of the created node. * \param parent Parent of the created node. * \param flags Document me. @@ -272,8 +274,21 @@ void dnslib_node_set_nsec3_node(dnslib_node_t *node, dnslib_node_t *nsec3_node); */ const dnslib_dname_t *dnslib_node_owner(const dnslib_node_t *node); +/*! + * \todo Document me. + */ dnslib_dname_t *dnslib_node_get_owner(const dnslib_node_t *node); +/*! + * \brief Set node owner to specified dname. + * + * Previous owner will be replaced if exist. + * + * \param node Specified node. + * \param owner New owner dname. + */ +void dnslib_node_set_owner(dnslib_node_t *node, dnslib_dname_t* owner); + /*! * \brief Returns the wildcard child of the node. * @@ -396,7 +411,7 @@ void dnslib_node_free(dnslib_node_t **node, int free_owner, int fix_refs); */ int dnslib_node_compare(dnslib_node_t *node1, dnslib_node_t *node2); -int dnslib_node_deep_copy(const dnslib_node_t *from, dnslib_node_t **to); +int dnslib_node_shallow_copy(const dnslib_node_t *from, dnslib_node_t **to); #endif /* _KNOT_DNSLIB_NODE_H_ */ diff --git a/src/dnslib/packet.c b/src/dnslib/packet.c index 4fd10ffc96ac09cde7db1bed66f4a2656a48a93a..d7b5aa45bb7863d4cf8d15a6b6c2c9397260fc21 100644 --- a/src/dnslib/packet.c +++ b/src/dnslib/packet.c @@ -388,7 +388,7 @@ DEBUG_DNSLIB_PACKET( if (size - *pos < 10) { debug_dnslib_packet("Malformed RR: Not enough data to parse RR" " header.\n"); - dnslib_dname_free(&owner); + dnslib_dname_release(owner); return NULL; } @@ -399,8 +399,12 @@ DEBUG_DNSLIB_PACKET( uint32_t ttl = dnslib_wire_read_u32(wire + *pos + 4); dnslib_rrset_t *rrset = dnslib_rrset_new(owner, type, rclass, ttl); + + /* Owner is either referenced in rrset or rrset creation failed. */ + dnslib_dname_release(owner); + + /* Check rrset allocation. */ if (rrset == NULL) { - dnslib_dname_free(&owner); return NULL; } @@ -415,7 +419,6 @@ DEBUG_DNSLIB_PACKET( if (size - *pos < rdlength) { debug_dnslib_packet("Malformed RR: Not enough data to parse RR" " RDATA.\n"); - //dnslib_dname_free(&rrset->owner); dnslib_rrset_deep_free(&rrset, 1, 1, 0); // free(rrset); return NULL; @@ -433,7 +436,6 @@ DEBUG_DNSLIB_PACKET( dnslib_rrtype_descriptor_by_type(rrset->type)); if (rdata == NULL) { debug_dnslib_packet("Malformed RR: Could not parse RDATA.\n"); - //dnslib_dname_free(&rrset->owner); dnslib_rrset_deep_free(&rrset, 1, 1, 0); // free(rrset); return NULL; @@ -442,7 +444,6 @@ DEBUG_DNSLIB_PACKET( if (dnslib_rrset_add_rdata(rrset, rdata) != DNSLIB_EOK) { debug_dnslib_packet("Malformed RR: Could not add RDATA to RRSet" ".\n"); - //dnslib_dname_free(&rrset->owner); dnslib_rdata_free(&rdata); dnslib_rrset_deep_free(&rrset, 1, 1, 0); // free(rrset); @@ -596,7 +597,7 @@ static void dnslib_packet_free_allocated_space(dnslib_packet_t *pkt) debug_dnslib_packet("Freeing additional space in packet.\n"); if (pkt->prealloc_type == DNSLIB_PACKET_PREALLOC_NONE) { debug_dnslib_packet("Freeing QNAME.\n"); - dnslib_dname_free(&pkt->question.qname); + dnslib_dname_release(pkt->question.qname); } if (pkt->max_an_rrsets > DEFAULT_RRSET_COUNT(ANCOUNT, pkt)) { diff --git a/src/dnslib/rdata.c b/src/dnslib/rdata.c index 3e7c678752e35d33a00058363c0965d2aa97760a..04d6dc1c7a060809cac2d27b8eae007be27c4946 100644 --- a/src/dnslib/rdata.c +++ b/src/dnslib/rdata.c @@ -201,6 +201,7 @@ int dnslib_rdata_from_wire(dnslib_rdata_t *rdata, const uint8_t *wire, //*pos += dname->size; parsed += pos2 - *pos; *pos = pos2; + dname = 0; break; case DNSLIB_RDATA_WF_BYTE: // printf("Next item - byte.\n"); @@ -266,6 +267,7 @@ int dnslib_rdata_from_wire(dnslib_rdata_t *rdata, const uint8_t *wire, //*pos += dname->size; parsed += pos2 - *pos; *pos = pos2; + dname = 0; break; default: assert(0); @@ -317,6 +319,11 @@ int dnslib_rdata_set_item(dnslib_rdata_t *rdata, uint pos, if (pos >= rdata->count) { return DNSLIB_EBADARG; } + + /*! \todo As in set_items() we should increment refcounter for dnames, + * but we don't know the item type. + */ + rdata->items[pos] = item; // this should copy the union; or use memcpy? return DNSLIB_EOK; } @@ -348,6 +355,10 @@ int dnslib_rdata_set_items(dnslib_rdata_t *rdata, memcpy(rdata->items, items, count * sizeof(dnslib_rdata_item_t)); rdata->count = count; + /*! \todo Cannot determine items type, so the dname + * refcounters should be increased in caller. + */ + return DNSLIB_EOK; } @@ -384,6 +395,9 @@ int dnslib_rdata_item_set_dname(dnslib_rdata_t *rdata, uint pos, return DNSLIB_EBADARG; } + /* Retain dname. */ + dnslib_dname_retain(dname); + rdata->items[pos].dname = dname; return DNSLIB_EOK; @@ -440,9 +454,17 @@ void dnslib_rdata_deep_free(dnslib_rdata_t **rdata, uint type, if (desc->wireformat[i] == DNSLIB_RDATA_WF_COMPRESSED_DNAME || desc->wireformat[i] == DNSLIB_RDATA_WF_UNCOMPRESSED_DNAME || desc->wireformat[i] == DNSLIB_RDATA_WF_LITERAL_DNAME ) { - if (((*rdata)->items[i].dname != NULL) && - free_all_dnames) { - dnslib_dname_free(&(*rdata)->items[i].dname); + if (((*rdata)->items[i].dname != NULL)) { + /*! \todo This is hack to prevent memory errors, + * as the rdata_set_items() cannot determine + * items type and so cannot increment + * reference count in case of dname type. + * Free would then release dnames that + * aren't referenced by the rdata. + */ + if (free_all_dnames) { + dnslib_dname_release((*rdata)->items[i].dname); + } } } else { free((*rdata)->items[i].raw_data); @@ -578,7 +600,8 @@ void dnslib_rdata_deep_free(dnslib_rdata_t **rdata, uint type, /*----------------------------------------------------------------------------*/ -dnslib_rdata_t *dnslib_rdata_copy(const dnslib_rdata_t *rdata, uint16_t type) +dnslib_rdata_t *dnslib_rdata_deep_copy(const dnslib_rdata_t *rdata, + uint16_t type) { dnslib_rdata_t *copy = dnslib_rdata_new(); CHECK_ALLOC_LOG(copy, NULL); @@ -603,7 +626,7 @@ dnslib_rdata_t *dnslib_rdata_copy(const dnslib_rdata_t *rdata, uint16_t type) || d->wireformat[i] == DNSLIB_RDATA_WF_UNCOMPRESSED_DNAME || d->wireformat[i] == DNSLIB_RDATA_WF_LITERAL_DNAME) { copy->items[i].dname = - dnslib_dname_copy(rdata->items[i].dname); + dnslib_dname_deep_copy(rdata->items[i].dname); } else { copy->items[i].raw_data = (uint16_t *)malloc( rdata->items[i].raw_data[0] + 2); diff --git a/src/dnslib/rdata.h b/src/dnslib/rdata.h index 0b3051302aa839b70e14077c26f1ea5cb0eed8c2..a679dbc7a4ede18dfa40b5dfa790e1558fcabe5d 100644 --- a/src/dnslib/rdata.h +++ b/src/dnslib/rdata.h @@ -213,7 +213,8 @@ int dnslib_rdata_item_set_raw_data(dnslib_rdata_t *rdata, unsigned int pos, * * \return Copy of \a rdata. */ -dnslib_rdata_t *dnslib_rdata_copy(const dnslib_rdata_t *rdata, uint16_t type); +dnslib_rdata_t *dnslib_rdata_deep_copy(const dnslib_rdata_t *rdata, + uint16_t type); /*! * \brief Destroys the RDATA structure without deleting RDATA items. diff --git a/src/dnslib/rrset.c b/src/dnslib/rrset.c index 6ba6dfc33509367fa8566b36f1801c524f5bced6..0387b834ed1438dfe4ff3e93036bcf53de2a5cf2 100644 --- a/src/dnslib/rrset.c +++ b/src/dnslib/rrset.c @@ -54,6 +54,9 @@ dnslib_rrset_t *dnslib_rrset_new(dnslib_dname_t *owner, uint16_t type, ret->rdata = NULL; + /* Retain reference to owner. */ + dnslib_dname_retain(owner); + ret->owner = owner; ret->type = type; ret->rclass = rclass; @@ -179,6 +182,18 @@ dnslib_dname_t *dnslib_rrset_get_owner(const dnslib_rrset_t *rrset) /*----------------------------------------------------------------------------*/ +void dnslib_rrset_set_owner(dnslib_rrset_t *rrset, dnslib_dname_t* owner) +{ + if (rrset) { + /* Retain new owner and release old owner. */ + dnslib_dname_retain(owner); + dnslib_dname_release(rrset->owner); + rrset->owner = owner; + } +} + +/*----------------------------------------------------------------------------*/ + uint16_t dnslib_rrset_type(const dnslib_rrset_t *rrset) { return rrset->type; @@ -294,10 +309,14 @@ int dnslib_rrset_compare(const dnslib_rrset_t *r1, /*----------------------------------------------------------------------------*/ -int dnslib_rrset_copy(const dnslib_rrset_t *from, dnslib_rrset_t **to) +int dnslib_rrset_shallow_copy(const dnslib_rrset_t *from, dnslib_rrset_t **to) { - /*! \todo Implement (shallow copy). */ - return DNSLIB_ERROR; + *to = (dnslib_rrset_t *)malloc(sizeof(dnslib_rrset_t)); + CHECK_ALLOC_LOG(*to, DNSLIB_ENOMEM); + + memcpy(*to, from, sizeof(dnslib_rrset_t)); + + return DNSLIB_EOK; } /*----------------------------------------------------------------------------*/ @@ -308,6 +327,9 @@ void dnslib_rrset_free(dnslib_rrset_t **rrset) return; } + /*! \todo Shouldn't we always release owner reference? */ + dnslib_dname_release((*rrset)->owner); + free(*rrset); *rrset = NULL; } @@ -345,9 +367,10 @@ void dnslib_rrset_deep_free(dnslib_rrset_t **rrset, int free_owner, free_rdata_dnames); } - if (free_owner) { - dnslib_dname_free(&(*rrset)->owner); - } + /*! \todo Release owner every time? */ + //if (free_owner) { + dnslib_dname_release((*rrset)->owner); + //} free(*rrset); *rrset = NULL; diff --git a/src/dnslib/rrset.h b/src/dnslib/rrset.h index dc93455f81bf8d850dfce7f1a886ae4060df1bec..ec456d82ecb07869fbe09a8941295cd605108b55 100644 --- a/src/dnslib/rrset.h +++ b/src/dnslib/rrset.h @@ -116,8 +116,21 @@ int dnslib_rrset_add_rrsigs(dnslib_rrset_t *rrset, dnslib_rrset_t *rrsigs, */ const dnslib_dname_t *dnslib_rrset_owner(const dnslib_rrset_t *rrset); +/*! + * \todo Document me. + */ dnslib_dname_t *dnslib_rrset_get_owner(const dnslib_rrset_t *rrset); +/*! + * \brief Set rrset owner to specified dname. + * + * Previous owner will be replaced if exist. + * + * \param rrset Specified RRSet. + * \param owner New owner dname. + */ +void dnslib_rrset_set_owner(dnslib_rrset_t *rrset, dnslib_dname_t* owner); + /*! * \brief Returns the TYPE of the RRSet. * @@ -198,7 +211,7 @@ int dnslib_rrset_compare(const dnslib_rrset_t *r1, const dnslib_rrset_t *r2, dnslib_rrset_compare_type_t cmp); -int dnslib_rrset_copy(const dnslib_rrset_t *from, dnslib_rrset_t **to); +int dnslib_rrset_shallow_copy(const dnslib_rrset_t *from, dnslib_rrset_t **to); /*! * \brief Destroys the RRSet structure. diff --git a/src/dnslib/tests/realdata/dnslib/response_tests_realdata.c b/src/dnslib/tests/realdata/dnslib/response_tests_realdata.c index 5ba6c46361c4fd6a3c425793a451090f48b295f3..dfc982db1c8d339f68b9239c1d231c2a2f469f9f 100644 --- a/src/dnslib/tests/realdata/dnslib/response_tests_realdata.c +++ b/src/dnslib/tests/realdata/dnslib/response_tests_realdata.c @@ -919,8 +919,6 @@ int dnslib_response_tests_count(int argc, char *argv[]) int dnslib_response_tests_run(int argc, char *argv[]) { - int ret; - test_data_t *data = data_for_dnslib_tests; ok(test_response_add_rrset_answer(data->rrset_list), diff --git a/src/dnslib/zone-contents.c b/src/dnslib/zone-contents.c index c51296ccb56f6ad8b940ea0a8bba3835a9846730..d72700173455b38365e77d95e83c9219fbdbcbec 100644 --- a/src/dnslib/zone-contents.c +++ b/src/dnslib/zone-contents.c @@ -562,6 +562,7 @@ DEBUG_DNSLIB_ZONE( debug_dnslib_zone("Base32-encoded hash: %s\n", name_b32); + /* Will be returned to caller, make sure it is released after use. */ *nsec3_name = dnslib_dname_new_from_str(name_b32, size, NULL); free(name_b32); @@ -578,7 +579,7 @@ DEBUG_DNSLIB_ZONE( if (ret == NULL) { debug_dnslib_zone("Error while creating NSEC3 domain name for " "hashed name.\n"); - dnslib_dname_free(nsec3_name); + dnslib_dname_release(*nsec3_name); return DNSLIB_ERROR; } @@ -722,8 +723,7 @@ static int dnslib_zone_contents_dnames_from_rrset_to_table( if (replace_owner) { // discard the old owner and replace it with the new - //dnslib_dname_free(&rrset->owner); - rrset->owner = owner; + dnslib_rrset_set_owner(rrset, owner); } debug_dnslib_zone("RRSet owner: %p\n", rrset->owner); @@ -994,6 +994,7 @@ DEBUG_DNSLIB_ZONE( debug_dnslib_zone("Creating new node.\n"); next_node = dnslib_node_new(chopped, NULL, flags); if (next_node == NULL) { + /* Directly discard. */ dnslib_dname_free(&chopped); return DNSLIB_ENOMEM; } @@ -1002,6 +1003,8 @@ DEBUG_DNSLIB_ZONE( dnslib_zone_contents_dnames_from_node_to_table( zone->dname_table, next_node); if (ret != DNSLIB_EOK) { + /*! \todo Will next_node leak? */ + dnslib_dname_release(chopped); return ret; } } @@ -1024,7 +1027,8 @@ DEBUG_DNSLIB_ZONE( debug_dnslib_zone("Failed to insert new node " "to zone tree.\n"); /*! \todo Delete the node?? */ - dnslib_dname_free(&chopped); + /* Directly discard. */ + dnslib_dname_release(chopped); return ret; } @@ -1046,7 +1050,8 @@ DEBUG_DNSLIB_ZONE( debug_dnslib_zone("Error inserting node into " "hash table!\n"); /*! \todo Delete the node?? */ - dnslib_dname_free(&chopped); + /* Directly discard. */ + dnslib_dname_release(chopped); return DNSLIB_EHASH; } @@ -1064,7 +1069,14 @@ DEBUG_DNSLIB_ZONE( #endif debug_dnslib_zone("Next parent.\n"); node = next_node; + dnslib_dname_t *chopped_last = chopped; chopped = dnslib_dname_left_chop(chopped); + + /* Release last chop, reference is already stored + * in next_node. + */ + dnslib_dname_release(chopped_last); + } // set the found parent (in the zone) as the parent of the last // inserted node @@ -1073,7 +1085,10 @@ DEBUG_DNSLIB_ZONE( debug_dnslib_zone("Created all parents.\n"); } - dnslib_dname_free(&chopped); + + /* Directly discard. */ + /*! \todo This may be double-release. */ + dnslib_dname_release(chopped); return DNSLIB_EOK; } @@ -1139,8 +1154,7 @@ int dnslib_zone_contents_add_rrset(dnslib_zone_contents_t *zone, // table) /*! \todo Do even if domain table is not used?? */ if (ret == DNSLIB_EOK && rrset->owner != (*node)->owner) { - dnslib_dname_free(&rrset->owner); - rrset->owner = (*node)->owner; + dnslib_rrset_set_owner(rrset, (*node)->owner); } debug_dnslib_zone("RRSet OK.\n"); @@ -1246,8 +1260,7 @@ int dnslib_zone_contents_add_rrsigs(dnslib_zone_contents_t *zone, // replace RRSet's owner with the node's owner (that is already in the // table) if ((*rrset)->owner != (*rrset)->rrsigs->owner) { - dnslib_dname_free(&rrsigs->owner); - (*rrset)->rrsigs->owner = (*rrset)->owner; + dnslib_rrset_set_owner((*rrset)->rrsigs, (*rrset)->owner); } debug_dnslib_zone("RRSIGs OK\n"); @@ -1359,8 +1372,7 @@ int dnslib_zone_contents_add_nsec3_rrset(dnslib_zone_contents_t *zone, // table) /*! \todo Do even if domain table is not used? */ if (rrset->owner != (*node)->owner) { - dnslib_dname_free(&rrset->owner); - rrset->owner = (*node)->owner; + dnslib_rrset_set_owner(rrset, (*node)->owner); } debug_dnslib_zone("NSEC3 OK\n"); @@ -1725,7 +1737,8 @@ DEBUG_DNSLIB_ZONE( // chop leftmost labels until some node is found // copy the name for chopping - dnslib_dname_t *name_copy = dnslib_dname_copy(name); + /* Local allocation, will be discarded. */ + dnslib_dname_t *name_copy = dnslib_dname_deep_copy(name); DEBUG_DNSLIB_ZONE( char *n = dnslib_dname_to_str(name_copy); debug_dnslib_zone("Finding closest encloser..\nStarting with: %s\n", n); @@ -1749,6 +1762,7 @@ DEBUG_DNSLIB_ZONE( name_copy->size); } + /* Directly discard. */ dnslib_dname_free(&name_copy); assert(item != NULL); @@ -1797,7 +1811,7 @@ DEBUG_DNSLIB_ZONE( zone->nsec3_nodes, nsec3_name, &found, &prev); assert(exact_match >= 0); - dnslib_dname_free(&nsec3_name); + dnslib_dname_release(nsec3_name); DEBUG_DNSLIB_ZONE( if (found) { @@ -2142,7 +2156,7 @@ int dnslib_zone_contents_shallow_copy(const dnslib_zone_contents_t *from, ret = DNSLIB_ENOMEM; goto cleanup; } - if ((ret = dnslib_dname_table_copy(from->dname_table, + if ((ret = dnslib_dname_table_shallow_copy(from->dname_table, contents->dname_table)) != DNSLIB_EOK) { goto cleanup; } @@ -2157,9 +2171,9 @@ int dnslib_zone_contents_shallow_copy(const dnslib_zone_contents_t *from, memcpy(&contents->nsec3_params, &from->nsec3_params, sizeof(dnslib_nsec3_params_t)); - if ((ret = dnslib_zone_tree_copy(from->nodes, + if ((ret = dnslib_zone_tree_shallow_copy(from->nodes, contents->nodes)) != DNSLIB_EOK - || (ret = dnslib_zone_tree_copy(from->nsec3_nodes, + || (ret = dnslib_zone_tree_shallow_copy(from->nsec3_nodes, contents->nsec3_nodes)) != DNSLIB_EOK) { goto cleanup; } @@ -2230,7 +2244,8 @@ void dnslib_zone_contents_deep_free(dnslib_zone_contents_t **contents) dnslib_zone_tree_reverse_apply_postorder( (*contents)->nsec3_nodes, - dnslib_zone_contents_destroy_node_rrsets_from_tree, 0); + dnslib_zone_contents_destroy_node_rrsets_from_tree, + (void*)1); dnslib_zone_tree_reverse_apply_postorder( (*contents)->nsec3_nodes, @@ -2238,7 +2253,8 @@ void dnslib_zone_contents_deep_free(dnslib_zone_contents_t **contents) dnslib_zone_tree_reverse_apply_postorder( (*contents)->nodes, - dnslib_zone_contents_destroy_node_rrsets_from_tree, 0); + dnslib_zone_contents_destroy_node_rrsets_from_tree, + (void*)1); dnslib_zone_tree_reverse_apply_postorder( (*contents)->nodes, diff --git a/src/dnslib/zone-dump.c b/src/dnslib/zone-dump.c index 8b83ea8d3ad2171dc33f368847e3af35355326f5..6cc4fbc8ebc988bbb193a705aa103265a381fb61 100644 --- a/src/dnslib/zone-dump.c +++ b/src/dnslib/zone-dump.c @@ -909,6 +909,7 @@ static int check_nsec3_node_in_zone(dnslib_zone_contents_t *zone, dnslib_node_t memmove(next_dname_decoded + 1, next_dname_decoded, real_size); next_dname_decoded[0] = real_size; + /* Local allocation, will be discarded. */ dnslib_dname_t *next_dname = dnslib_dname_new_from_wire(next_dname_decoded, real_size + 1, NULL); @@ -927,6 +928,8 @@ static int check_nsec3_node_in_zone(dnslib_zone_contents_t *zone, dnslib_node_t err_handler_handle_error(handler, node, ZC_ERR_NSEC3_RDATA_CHAIN); } + + /* Directly discard. */ dnslib_dname_free(&next_dname); /* This is probably not sufficient, but again, it is covered in @@ -1713,6 +1716,7 @@ static void log_cyclic_errors_in_zone(err_handler_t *handler, memmove(next_dname_decoded + 1, next_dname_decoded, real_size); next_dname_decoded[0] = real_size; + /* Local allocation, will be discarded. */ dnslib_dname_t *next_dname = dnslib_dname_new_from_wire(next_dname_decoded, real_size + 1, NULL); @@ -1725,6 +1729,7 @@ static void log_cyclic_errors_in_zone(err_handler_t *handler, free(next_dname_decoded); + /*! \todo Free result and dname! */ if (dnslib_dname_cat(next_dname, dnslib_node_owner(dnslib_zone_contents_apex(zone))) == NULL) { @@ -1747,6 +1752,7 @@ static void log_cyclic_errors_in_zone(err_handler_t *handler, ZC_ERR_NSEC3_RDATA_CHAIN); } + /* Directly discard. */ dnslib_dname_free(&next_dname); } else if (do_checks == 2 ) { diff --git a/src/dnslib/zone-load.c b/src/dnslib/zone-load.c index 01393f008973b50cbb674455fa42b1165fdb64ed..faed45ba6e6149a75f6f20ee3c34c206439ee28f 100644 --- a/src/dnslib/zone-load.c +++ b/src/dnslib/zone-load.c @@ -117,8 +117,25 @@ static void load_rdata_purge(dnslib_rdata_t *rdata, int count, uint16_t type) { + /* Increase refcount manually, as the set_items() doesn't see the dname + * type and thus is unable to increment refcounter. + */ + unsigned i = 0; + switch(type) { + case DNSLIB_RDATA_WF_COMPRESSED_DNAME: + case DNSLIB_RDATA_WF_UNCOMPRESSED_DNAME: + case DNSLIB_RDATA_WF_LITERAL_DNAME: + for (i = 0; i < count; ++i) { + dnslib_dname_retain(items[i].dname); + } + break; + default: + break; + } + + /* Copy items to rdata and free the temporary rdata. */ dnslib_rdata_set_items(rdata, items, count); - dnslib_rdata_deep_free(&rdata, type, 0); + dnslib_rdata_deep_free(&rdata, type, 1); free(items); } @@ -130,7 +147,7 @@ static dnslib_dname_t *read_dname_with_id(FILE *f) /* Read ID. */ uint32_t dname_id = 0; if (!fread_wrapper(&dname_id, sizeof(dname_id), 1, f)) { - dnslib_dname_free(&ret); + dnslib_dname_release(ret); return NULL; } @@ -139,7 +156,7 @@ static dnslib_dname_t *read_dname_with_id(FILE *f) /* Read size of dname. */ uint32_t dname_size = 0; if (!fread_wrapper(&dname_size, sizeof(dname_size), 1, f)) { - dnslib_dname_free(&ret); + dnslib_dname_release(ret); return NULL; } ret->size = dname_size; @@ -150,19 +167,19 @@ static dnslib_dname_t *read_dname_with_id(FILE *f) ret->name = malloc(sizeof(uint8_t) * ret->size); if (ret->name == NULL) { ERR_ALLOC_FAILED; - dnslib_dname_free(&ret); + dnslib_dname_release(ret); return NULL; } if (!fread_wrapper(ret->name, sizeof(uint8_t), ret->size, f)) { - dnslib_dname_free(&ret); + dnslib_dname_release(ret); return NULL; } /* Read labels. */ uint16_t label_count = 0; if (!fread_wrapper(&label_count, sizeof(label_count), 1, f)) { - dnslib_dname_free(&ret); + dnslib_dname_release(ret); return NULL; } @@ -171,7 +188,7 @@ static dnslib_dname_t *read_dname_with_id(FILE *f) ret->labels = malloc(sizeof(uint8_t) * ret->label_count); if (ret->labels == NULL) { ERR_ALLOC_FAILED; - dnslib_dname_free(&ret); + dnslib_dname_release(ret); return NULL; } @@ -230,6 +247,9 @@ static dnslib_rdata_t *dnslib_load_rdata(uint16_t type, FILE *f, load_rdata_purge(rdata, items, i, type); return NULL; } + + /* Store reference do dname. */ + dnslib_dname_retain(id_array[dname_id]); items[i].dname = id_array[dname_id]; } else { items[i].dname = read_dname_with_id(f); @@ -284,6 +304,7 @@ static dnslib_rdata_t *dnslib_load_rdata(uint16_t type, FILE *f, } } + /* Each item has refcount already incremented for saving in rdata. */ if (dnslib_rdata_set_items(rdata, items, desc->length) != 0) { fprintf(stderr, "zoneload: Could not set items " "when loading rdata.\n"); @@ -398,6 +419,12 @@ static dnslib_rrset_t *dnslib_load_rrset(FILE *f, dnslib_dname_t **id_array, rrset = dnslib_rrset_new(owner, rrset_type, rrset_class, rrset_ttl); + if (!use_ids) { + /* Directly release if allocated locally. */ + dnslib_dname_release(owner); + owner = 0; + } + debug_dnslib_zload("RRSet type: %d\n", rrset->type); dnslib_rdata_t *tmp_rdata; @@ -418,11 +445,11 @@ static dnslib_rrset_t *dnslib_load_rrset(FILE *f, dnslib_dname_t **id_array, if (rrsig_count) { tmp_rrsig = dnslib_load_rrsig(f, id_array, use_ids); if (!use_ids) { - tmp_rrsig->owner = rrset->owner; + dnslib_rrset_set_owner(tmp_rrsig, rrset->owner); } } - rrset->rrsigs = tmp_rrsig; + dnslib_rrset_set_rrsigs(rrset, tmp_rrsig); return rrset; } @@ -483,7 +510,9 @@ static dnslib_node_t *dnslib_load_node(FILE *f, dnslib_dname_t **id_array) dnslib_node_set_nsec3_node(node, NULL); // node->nsec3_node = NULL; } - node->owner = owner; + + /* Retain new owner while releasing replaced owner. */ + dnslib_node_set_owner(node, owner); node->flags = flags; //XXX will have to be set already...canonical order should do it @@ -504,9 +533,10 @@ static dnslib_node_t *dnslib_load_node(FILE *f, dnslib_dname_t **id_array) fprintf(stderr, "zone: Could not load rrset.\n"); return NULL; } - tmp_rrset->owner = node->owner; + /* Retain new owner while releasing replaced owner. */ + dnslib_rrset_set_owner(tmp_rrset, node->owner); if (tmp_rrset->rrsigs != NULL) { - tmp_rrset->rrsigs->owner = node->owner; + dnslib_rrset_set_owner(tmp_rrset->rrsigs, node->owner); } if (dnslib_node_add_rrset(node, tmp_rrset, 0) < 0) { fprintf(stderr, "zone: Could not add rrset.\n"); @@ -538,6 +568,7 @@ static void find_and_set_wildcard_child(dnslib_zone_contents_t *zone, dnslib_zone_contents_get_nsec3_node(zone, chopped); } + /* Directly discard. */ dnslib_dname_free(&chopped); assert(wildcard_parent); /* it *has* to be there */ @@ -744,7 +775,7 @@ static void cleanup_id_array(dnslib_dname_t **id_array, const uint from, const uint to) { for (uint i = from; i < to; i++) { - dnslib_dname_free(&(id_array[i])); + dnslib_dname_release(id_array[i]); } free(id_array); @@ -831,19 +862,30 @@ static dnslib_dname_t **create_dname_array(FILE *f, uint max_id) cleanup_id_array(array, 0, i); return NULL; } + if (read_dname->id < max_id) { + + /* Create new node from dname. */ read_dname->node = dnslib_node_new(read_dname, NULL, 0); + if (read_dname->node == NULL) { ERR_ALLOC_FAILED; + + /* Release read dname. */ + dnslib_dname_release(read_dname); cleanup_id_array(array, 0, i); - dnslib_dname_free(&read_dname); return NULL; } + + /* Store reference to dname in array. */ array[read_dname->id] = read_dname; } else { + /* Release read dname. */ + dnslib_dname_release(read_dname); cleanup_id_array(array, 0, i); return NULL; } + // assert(array[i]->id == i); } @@ -1027,6 +1069,10 @@ dnslib_zone_t *dnslib_zload_load(zloader_t *loader) } /* ID array is now useless */ + for (uint i = 1; i < total_dnames; i++) { + /* Added to table, may discard now. */ + dnslib_dname_release(id_array[i]); + } free(id_array); diff --git a/src/dnslib/zone-tree.c b/src/dnslib/zone-tree.c index 28d80b6f47884bc4f886c80c247c37dfd4f013b1..2718634635cf2e29f1b85e4aa6d89e4d0acc748c 100644 --- a/src/dnslib/zone-tree.c +++ b/src/dnslib/zone-tree.c @@ -398,7 +398,8 @@ int dnslib_zone_tree_reverse_apply_postorder(dnslib_zone_tree_t *tree, /*----------------------------------------------------------------------------*/ -int dnslib_zone_tree_copy(dnslib_zone_tree_t *from, dnslib_zone_tree_t *to) +int dnslib_zone_tree_shallow_copy(dnslib_zone_tree_t *from, + dnslib_zone_tree_t *to) { /* * This function will copy the tree by hand, so that the nodes diff --git a/src/dnslib/zone-tree.h b/src/dnslib/zone-tree.h index aaa8c93064484d397260f747a72b42fe8c4795b3..1dade6acc5b5b07c9a2919cc8628eb95b329d1f9 100644 --- a/src/dnslib/zone-tree.h +++ b/src/dnslib/zone-tree.h @@ -256,7 +256,8 @@ int dnslib_zone_tree_reverse_apply_postorder(dnslib_zone_tree_t *tree, * \retval DNSLIB_EOK * \retval DNSLIB_ENOMEM */ -int dnslib_zone_tree_copy(dnslib_zone_tree_t *from, dnslib_zone_tree_t *to); +int dnslib_zone_tree_shallow_copy(dnslib_zone_tree_t *from, + dnslib_zone_tree_t *to); /*! * \brief Destroys the zone tree, not touching the saved data. diff --git a/src/dnslib/zone.c b/src/dnslib/zone.c index eb37ae71a96748225080a6827fbf6f29422e9a18..c6ab358d26eaa250520d80fe3c275f721dd3d9ed 100644 --- a/src/dnslib/zone.c +++ b/src/dnslib/zone.c @@ -40,7 +40,7 @@ dnslib_zone_t *dnslib_zone_new(dnslib_node_t *apex, uint node_count, // save the zone name debug_dnslib_zone("Copying zone name.\n"); - zone->name = dnslib_dname_copy(dnslib_node_owner(apex)); + zone->name = dnslib_dname_deep_copy(dnslib_node_owner(apex)); if (zone->name == NULL) { ERR_ALLOC_FAILED; free(zone); @@ -51,7 +51,7 @@ dnslib_zone_t *dnslib_zone_new(dnslib_node_t *apex, uint node_count, zone->contents = dnslib_zone_contents_new(apex, node_count, use_domain_table, zone); if (zone->contents == NULL) { - dnslib_dname_free(&zone->name); + dnslib_dname_release(zone->name); free(zone); return NULL; } @@ -331,7 +331,7 @@ void dnslib_zone_free(dnslib_zone_t **zone) "update.\n"); } - dnslib_dname_free(&(*zone)->name); + dnslib_dname_release((*zone)->name); /* Call zone data destructor if exists. */ if ((*zone)->dtor) { @@ -365,7 +365,7 @@ DEBUG_DNSLIB_ZONE( free(name); ); - dnslib_dname_free(&(*zone)->name); + dnslib_dname_release((*zone)->name); /* Call zone data destructor if exists. */ if ((*zone)->dtor) { diff --git a/src/dnslib/zonedb.c b/src/dnslib/zonedb.c index c20a1e166cbe5868fd00fdb2be1833adcea296ec..501ca07f15281ccea42e1b7525cac38412ac7603 100644 --- a/src/dnslib/zonedb.c +++ b/src/dnslib/zonedb.c @@ -210,23 +210,6 @@ DEBUG_DNSLIB_ZONEDB( /*----------------------------------------------------------------------------*/ -dnslib_zonedb_t *dnslib_zonedb_copy(const dnslib_zonedb_t *db) -{ - dnslib_zonedb_t *db_new = - (dnslib_zonedb_t *)malloc(sizeof(dnslib_zonedb_t)); - CHECK_ALLOC_LOG(db_new, NULL); - - db_new->zones = skip_copy_list(db->zones); - if (db_new->zones == NULL) { - free(db_new); - return NULL; - } - - return db_new; -} - -/*----------------------------------------------------------------------------*/ - void dnslib_zonedb_free(dnslib_zonedb_t **db) { skip_destroy_list(&(*db)->zones, NULL, NULL); diff --git a/src/dnslib/zonedb.h b/src/dnslib/zonedb.h index fe374e55e496f554a8a4dfdb68ae3c6e48036671..45e811f45ba2d4c0f5147f4fee17ed82694ec476 100644 --- a/src/dnslib/zonedb.h +++ b/src/dnslib/zonedb.h @@ -97,16 +97,6 @@ dnslib_zone_t *dnslib_zonedb_find_zone(const dnslib_zonedb_t *db, const dnslib_zone_t *dnslib_zonedb_find_zone_for_name(dnslib_zonedb_t *db, const dnslib_dname_t *dname); -/*! - * \brief Copies the zone database structure (but not the zones within). - * - * \param db Zone database to copy. - * - * \return A new zone database structure containing the same zones as \a db or - * NULL if an error occured. - */ -dnslib_zonedb_t *dnslib_zonedb_copy(const dnslib_zonedb_t *db); - /*! * \brief Destroys and deallocates the zone database structure (but not the * zones within). diff --git a/src/knot/conf/cf-parse.y b/src/knot/conf/cf-parse.y index f8a63fd3d7172d2d7018f09fa774744134a8fde7..adb8f551b743ebbc7d3fe9a5269be67654a706e2 100644 --- a/src/knot/conf/cf-parse.y +++ b/src/knot/conf/cf-parse.y @@ -267,7 +267,7 @@ zone_start: TEXT { strcat(this_zone->name, "."); } - // Check domain name + /* Check domain name. */ dnslib_dname_t *dn = dnslib_dname_new_from_str(this_zone->name, nlen + 1, 0); @@ -276,6 +276,7 @@ zone_start: TEXT { free(this_zone); cf_error("invalid zone origin", scanner); } else { + /* Directly discard dname, won't be needed. */ dnslib_dname_free(&dn); add_tail(&new_config->zones, &this_zone->n); ++new_config->zones_count; diff --git a/src/knot/server/name-server.c b/src/knot/server/name-server.c index edfd753e62649d08b6c80131948ea6e17a8509cf..2e4ab3a8b7f316831c320269bd3f226310524289 100644 --- a/src/knot/server/name-server.c +++ b/src/knot/server/name-server.c @@ -82,12 +82,10 @@ static const dnslib_zone_t *ns_get_zone_for_qname(dnslib_zonedb_t *zdb, * records are only present in a parent zone. */ if (qtype == DNSLIB_RRTYPE_DS) { - /* - * TODO: optimize!!! - * 1) do not copy the name! - */ + /*! \todo Optimize, do not deep copy dname. */ dnslib_dname_t *name = dnslib_dname_left_chop(qname); zone = dnslib_zonedb_find_zone_for_name(zdb, name); + /* Directly discard. */ dnslib_dname_free(&name); } else { zone = dnslib_zonedb_find_zone_for_name(zdb, qname); @@ -114,7 +112,7 @@ static dnslib_rrset_t *ns_synth_from_wildcard( { debug_ns("Synthetizing RRSet from wildcard...\n"); - dnslib_dname_t *owner = dnslib_dname_copy(qname); + dnslib_dname_t *owner = dnslib_dname_deep_copy(qname); // printf("Copied owner ptr: %p\n", owner); dnslib_rrset_t *synth_rrset = dnslib_rrset_new( @@ -122,8 +120,10 @@ static dnslib_rrset_t *ns_synth_from_wildcard( dnslib_rrset_class(wildcard_rrset), dnslib_rrset_ttl(wildcard_rrset)); + /* Release owner, as it's retained in rrset. */ + dnslib_dname_release(owner); + if (synth_rrset == NULL) { - dnslib_dname_free(&owner); return NULL; } @@ -136,7 +136,7 @@ static dnslib_rrset_t *ns_synth_from_wildcard( // we could use the RDATA from the wildcard rrset // but there is no way to distinguish it when deleting // temporary RRSets - dnslib_rdata_t *rdata_copy = dnslib_rdata_copy(rdata, + dnslib_rdata_t *rdata_copy = dnslib_rdata_deep_copy(rdata, dnslib_rrset_type(synth_rrset)); if (rdata_copy == NULL) { dnslib_rrset_deep_free(&synth_rrset, 1, 1, 0); @@ -634,7 +634,7 @@ static dnslib_dname_t *ns_next_closer(const dnslib_dname_t *closest_encloser, == ce_labels); // chop some labels from the qname - dnslib_dname_t *next_closer = dnslib_dname_copy(name); + dnslib_dname_t *next_closer = dnslib_dname_deep_copy(name); if (next_closer == NULL) { return NULL; } @@ -812,7 +812,7 @@ DEBUG_NS( ret = ns_put_covering_nsec3(zone, next_closer, resp); // the cast is ugly, but no better way around it - dnslib_dname_free((dnslib_dname_t **)&next_closer); + dnslib_dname_release((dnslib_dname_t *)next_closer); } else { ret = ns_put_covering_nsec3(zone, next_closer, resp); } @@ -838,6 +838,7 @@ static dnslib_dname_t *ns_wildcard_child_name(const dnslib_dname_t *name) } if (dnslib_dname_cat(wildcard, name) == NULL) { + /* Directly discard dname. */ dnslib_dname_free(&wildcard); return NULL; } @@ -879,6 +880,8 @@ static int ns_put_nsec3_no_wildcard_child(const dnslib_zone_contents_t *zone, ret = NS_ERR_SERVFAIL; } else { ret = ns_put_covering_nsec3(zone, wildcard, resp); + + /* Directly discard wildcard. */ dnslib_dname_free(&wildcard); } @@ -991,6 +994,7 @@ static int ns_put_nsec_nxdomain(const dnslib_dname_t *qname, debug_ns("Previous node: %s\n", dnslib_dname_to_str(dnslib_node_owner(prev_new))); + /* Directly discard dname. */ dnslib_dname_free(&wildcard); if (prev_new != previous) { @@ -1123,8 +1127,9 @@ DEBUG_NS( ); int ret = ns_put_covering_nsec3(zone, next_closer, resp); - // the cast is ugly, but no better way around it - dnslib_dname_free(&next_closer); + + /* Duplicate from ns_next_close(), safe to discard. */ + dnslib_dname_release(next_closer); return ret; } @@ -1414,7 +1419,7 @@ static dnslib_rrset_t *ns_cname_from_dname(const dnslib_rrset_t *dname_rrset, // create new CNAME RRSet - dnslib_dname_t *owner = dnslib_dname_copy(qname); + dnslib_dname_t *owner = dnslib_dname_deep_copy(qname); if (owner == NULL) { return NULL; } @@ -1422,8 +1427,10 @@ static dnslib_rrset_t *ns_cname_from_dname(const dnslib_rrset_t *dname_rrset, dnslib_rrset_t *cname_rrset = dnslib_rrset_new( owner, DNSLIB_RRTYPE_CNAME, DNSLIB_CLASS_IN, SYNTH_CNAME_TTL); + /* Release owner, as it's retained in rrset. */ + dnslib_dname_release(owner); + if (cname_rrset == NULL) { - dnslib_dname_free(&owner); return NULL; } @@ -3059,7 +3066,8 @@ int ns_process_response(ns_nameserver_t *nameserver, sockaddr_t *from, evsched_cancel(sched, refresh_ev); } - // get zone contents + /* Get zone contents. */ + rcu_read_lock(); const dnslib_zone_contents_t *contents = dnslib_zone_contents(zone); @@ -3083,20 +3091,23 @@ int ns_process_response(ns_nameserver_t *nameserver, sockaddr_t *from, ref_tmr); evsched_schedule(sched, refresh_ev, ref_tmr); + rcu_read_unlock(); return KNOT_EOK; } - /* Prepare XFR client transfer. */ ns_xfr_t xfr_req; memset(&xfr_req, 0, sizeof(ns_xfr_t)); memcpy(&xfr_req.addr, from, sizeof(sockaddr_t)); - xfr_req.data = (void *)contents; + xfr_req.data = (void *)zone; xfr_req.send = ns_send_cb; /* Select transfer method. */ xfr_req.type = ns_transfer_to_use(nameserver, contents); + /* Unlock zone contents. */ + rcu_read_unlock(); + /* Enqueue XFR request. */ return xfr_request(nameserver->server->xfr_h, &xfr_req); } @@ -3181,6 +3192,8 @@ static int ns_find_zone_for_xfr(ns_xfr_t *xfr, const char **zonefile, int r = dnslib_dname_compare(zone_name, dnslib_node_owner( dnslib_zone_contents_apex(xfr->zone))); + + /* Directly discard dname, won't be needed. */ dnslib_dname_free(&zone_name); if (r == 0) { @@ -3340,7 +3353,7 @@ int ns_process_axfrin(ns_nameserver_t *nameserver, ns_xfr_t *xfr) debug_ns("ns_process_axfrin: incoming packet\n"); int ret = xfrin_process_axfr_packet(xfr->wire, xfr->wire_size, - (dnslib_zone_contents_t **)(&xfr->data)); + (dnslib_zone_contents_t **)(&xfr->data)); if (ret > 0) { // transfer finished debug_ns("ns_process_axfrin: AXFR finished, zone created.\n"); diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c index b227063410cb9ba7761c67939ac92617a0c107c6..9edd8889e87cc374980bdc67f52b0ad70fb22a3e 100644 --- a/src/knot/server/xfr-handler.c +++ b/src/knot/server/xfr-handler.c @@ -10,6 +10,8 @@ #include <stdlib.h> #include <errno.h> +#include <urcu.h> + #include "knot/common.h" #include "knot/server/xfr-handler.h" #include "knot/server/name-server.h" @@ -133,12 +135,10 @@ static inline void xfr_bridge_ev(struct ev_loop *loop, ev_io *w, int revents) } /* Fetch associated zone. */ - dnslib_zone_contents_t *zone = (dnslib_zone_contents_t *)req->data; + dnslib_zone_t *zone = (dnslib_zone_t *)req->data; if (!zone) { return; } - const dnslib_node_t *apex = dnslib_zone_contents_apex(zone); - const dnslib_dname_t *dname = dnslib_node_owner(apex); /* Connect to remote. */ if (req->session <= 0) { @@ -158,21 +158,28 @@ static inline void xfr_bridge_ev(struct ev_loop *loop, ev_io *w, int revents) req->session = dup(req->session); } + /* Fetch zone contents. */ + rcu_read_lock(); + const dnslib_zone_contents_t *contents = dnslib_zone_contents(zone); + /* Create XFR query. */ ret = KNOT_ERROR; size_t bufsize = req->wire_size; switch(req->type) { case NS_XFR_TYPE_AIN: - ret = xfrin_create_axfr_query(dname, req->wire, &bufsize); + ret = xfrin_create_axfr_query(contents, req->wire, &bufsize); break; case NS_XFR_TYPE_IIN: - ret = xfrin_create_ixfr_query(dname, req->wire, &bufsize); + ret = xfrin_create_ixfr_query(contents, req->wire, &bufsize); break; default: ret = KNOT_EINVAL; break; } + /* Unlock zone contents. */ + rcu_read_unlock(); + /* Handle errors. */ if (ret != KNOT_EOK) { debug_xfr("xfr_in: failed to create XFR query type %d\n", @@ -403,7 +410,7 @@ int xfr_master(dthread_t *thread) } - // Stop whole unit + /* Stop whole unit. */ debug_xfr("xfr_master: finished.\n"); return KNOT_EOK; } diff --git a/src/knot/server/xfr-in.c b/src/knot/server/xfr-in.c index eaf732c7ffb25f1fe3fbf0b6708ed369b16bdc1a..13e09904d13387b61ade9e4380166bd3b1d3da9e 100644 --- a/src/knot/server/xfr-in.c +++ b/src/knot/server/xfr-in.c @@ -28,7 +28,7 @@ static const size_t XFRIN_CHANGESET_BINARY_STEP = 100; /* Non-API functions */ /*----------------------------------------------------------------------------*/ -static int xfrin_create_query(const dnslib_dname_t *qname, uint16_t qtype, +static int xfrin_create_query(const dnslib_zone_contents_t *zone, uint16_t qtype, uint16_t qclass, uint8_t *buffer, size_t *size) { dnslib_packet_t *pkt = dnslib_packet_new(DNSLIB_PACKET_PREALLOC_QUERY); @@ -49,6 +49,12 @@ static int xfrin_create_query(const dnslib_dname_t *qname, uint16_t qtype, dnslib_question_t question; + const dnslib_node_t *apex = dnslib_zone_contents_apex(zone); + dnslib_dname_t *qname = dnslib_node_get_owner(apex); + + /* Retain qname until the question is freed. */ + dnslib_dname_retain(qname); + // this is ugly!! question.qname = (dnslib_dname_t *)qname; question.qtype = qtype; @@ -56,6 +62,7 @@ static int xfrin_create_query(const dnslib_dname_t *qname, uint16_t qtype, rc = dnslib_query_set_question(pkt, &question); if (rc != DNSLIB_EOK) { + dnslib_dname_release(question.qname); dnslib_packet_free(&pkt); return KNOT_ERROR; } @@ -68,6 +75,7 @@ static int xfrin_create_query(const dnslib_dname_t *qname, uint16_t qtype, size_t wire_size = 0; rc = dnslib_packet_to_wire(pkt, &wire, &wire_size); if (rc != DNSLIB_EOK) { + dnslib_dname_release(question.qname); dnslib_packet_free(&pkt); return KNOT_ERROR; } @@ -87,6 +95,9 @@ static int xfrin_create_query(const dnslib_dname_t *qname, uint16_t qtype, dnslib_packet_free(&pkt); + /* Release qname. */ + dnslib_dname_release(question.qname); + return KNOT_EOK; } @@ -160,10 +171,10 @@ static inline uint64_t ixfrdb_key_make(uint32_t from, uint32_t to) /* API functions */ /*----------------------------------------------------------------------------*/ -int xfrin_create_soa_query(const dnslib_dname_t *zone_name, uint8_t *buffer, +int xfrin_create_soa_query(const dnslib_zone_contents_t *zone, uint8_t *buffer, size_t *size) { - return xfrin_create_query(zone_name, DNSLIB_RRTYPE_SOA, + return xfrin_create_query(zone, DNSLIB_RRTYPE_SOA, DNSLIB_CLASS_IN, buffer, size); } @@ -230,19 +241,19 @@ int xfrin_transfer_needed(const dnslib_zone_contents_t *zone, /*----------------------------------------------------------------------------*/ -int xfrin_create_axfr_query(const dnslib_dname_t *zone_name, uint8_t *buffer, +int xfrin_create_axfr_query(const dnslib_zone_contents_t *zone, uint8_t *buffer, size_t *size) { - return xfrin_create_query(zone_name, DNSLIB_RRTYPE_AXFR, + return xfrin_create_query(zone, DNSLIB_RRTYPE_AXFR, DNSLIB_CLASS_IN, buffer, size); } /*----------------------------------------------------------------------------*/ -int xfrin_create_ixfr_query(const dnslib_dname_t *zone_name, uint8_t *buffer, +int xfrin_create_ixfr_query(const dnslib_zone_contents_t *zone, uint8_t *buffer, size_t *size) { - return xfrin_create_query(zone_name, DNSLIB_RRTYPE_IXFR, + return xfrin_create_query(zone, DNSLIB_RRTYPE_IXFR, DNSLIB_CLASS_IN, buffer, size); } @@ -259,7 +270,7 @@ int xfrin_zone_transferred(ns_nameserver_t *nameserver, /*----------------------------------------------------------------------------*/ int xfrin_process_axfr_packet(const uint8_t *pkt, size_t size, - dnslib_zone_contents_t **zone) + dnslib_zone_contents_t **zone) { if (pkt == NULL || zone == NULL) { debug_xfr("Wrong parameters supported.\n"); @@ -1572,11 +1583,6 @@ static void xfrin_rollback_update(dnslib_zone_contents_t *contents, dnslib_rrset_deep_free(&changes->new_rrsets[i], 0, 1, 0); } -// // discard new dnames -// for (int i = 0; i < changes->new_dnames_count; ++i) { -// dnslib_dname_free(&changes->new_dnames[i]); -// } - // destroy the shallow copy of zone xfrin_zone_contents_free(&contents); } @@ -1611,7 +1617,7 @@ static int xfrin_get_node_copy(dnslib_node_t **node, xfrin_changes_t *changes) dnslib_node_get_new_node(*node); if (new_node == NULL) { debug_xfr("Creating copy of node.\n"); - int ret = dnslib_node_deep_copy(*node, &new_node); + int ret = dnslib_node_shallow_copy(*node, &new_node); if (ret != DNSLIB_EOK) { debug_xfr("Failed to create node copy.\n"); return KNOT_ENOMEM; @@ -1659,7 +1665,7 @@ static int xfrin_copy_old_rrset(dnslib_rrset_t *old, dnslib_rrset_t **copy, xfrin_changes_t *changes) { // create new RRSet by copying the old one - int ret = dnslib_rrset_copy(old, copy); + int ret = dnslib_rrset_shallow_copy(old, copy); if (ret != DNSLIB_EOK) { debug_xfr("Failed to create RRSet copy.\n"); return KNOT_ENOMEM; diff --git a/src/knot/server/xfr-in.h b/src/knot/server/xfr-in.h index 11ecd1486d728a24636aebab1fe8987cab59d7ca..f8ffb5c558749db99a32a18c6376822206e5e455 100644 --- a/src/knot/server/xfr-in.h +++ b/src/knot/server/xfr-in.h @@ -61,7 +61,7 @@ typedef struct { /*! * \brief Creates normal query for the given zone name and the SOA type. * - * \param zone_name Name of the zone to ask for - the SOA owner. + * \param zone Zone to ask for - the SOA owner. * \param buffer Buffer to fill the message in. * \param size In: available space in the buffer. Out: actual size of the * message in bytes. @@ -70,7 +70,7 @@ typedef struct { * \retval KNOT_ESPACE * \retval KNOT_ERROR */ -int xfrin_create_soa_query(const dnslib_dname_t *zone_name, uint8_t *buffer, +int xfrin_create_soa_query(const dnslib_zone_contents_t *zone, uint8_t *buffer, size_t *size); /*! @@ -90,7 +90,7 @@ int xfrin_transfer_needed(const dnslib_zone_contents_t *zone, /*! * \brief Creates normal query for the given zone name and the AXFR type. * - * \param zone_name Name of the zone to ask for - the SOA owner. + * \param zone Zone to ask for - the SOA owner. * \param buffer Buffer to fill the message in. * \param size In: available space in the buffer. Out: actual size of the * message in bytes. @@ -99,13 +99,13 @@ int xfrin_transfer_needed(const dnslib_zone_contents_t *zone, * \retval KNOT_ESPACE * \retval KNOT_ERROR */ -int xfrin_create_axfr_query(const dnslib_dname_t *zone_name, uint8_t *buffer, +int xfrin_create_axfr_query(const dnslib_zone_contents_t *zone, uint8_t *buffer, size_t *size); /*! * \brief Creates normal query for the given zone name and the IXFR type. * - * \param zone_name Name of the zone to ask for - the SOA owner. + * \param zone Zone to ask for - the SOA owner. * \param buffer Buffer to fill the message in. * \param size In: available space in the buffer. Out: actual size of the * message in bytes. @@ -114,7 +114,7 @@ int xfrin_create_axfr_query(const dnslib_dname_t *zone_name, uint8_t *buffer, * \retval KNOT_ESPACE * \retval KNOT_ERROR */ -int xfrin_create_ixfr_query(const dnslib_dname_t *zone_name, uint8_t *buffer, +int xfrin_create_ixfr_query(const dnslib_zone_contents_t *zone, uint8_t *buffer, size_t *size); /*! @@ -143,7 +143,7 @@ int xfrin_zone_transferred(ns_nameserver_t *nameserver, * \todo Refactor!!! */ int xfrin_process_axfr_packet(const uint8_t *pkt, size_t size, - dnslib_zone_contents_t **zone); + dnslib_zone_contents_t **zone); /*! * \brief Destroys the whole changesets structure. diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c index 9984195df3060ef73a18d7b07e5db87c078b4d6b..6da0539efd68e68a65b29a20b7f601ceb0161ddc 100644 --- a/src/knot/server/zones.c +++ b/src/knot/server/zones.c @@ -210,17 +210,12 @@ static int zones_axfrin_poll(event_t *e) /* Cancel pending timers. */ zonedata_t *zd = (zonedata_t *)dnslib_zone_data(zone); - /* Get zone dname. */ - const dnslib_node_t *apex = dnslib_zone_contents_apex( - dnslib_zone_contents(zone)); - const dnslib_dname_t *dname = dnslib_node_owner(apex); - /* Prepare buffer for query. */ uint8_t qbuf[SOCKET_MTU_SZ]; size_t buflen = SOCKET_MTU_SZ; /* Create query. */ - int ret = xfrin_create_soa_query(dname, qbuf, &buflen); + int ret = xfrin_create_soa_query(dnslib_zone_contents(zone), qbuf, &buflen); if (ret == KNOT_EOK && zd->xfr_in.ifaces) { int sock = -1; @@ -691,7 +686,9 @@ static int zones_insert_zones(ns_nameserver_t *ns, // for all zones in the configuration WALK_LIST(n, *zone_conf) { conf_zone_t *z = (conf_zone_t *)n; - // convert the zone name into a domain name + + /* Convert the zone name into a domain name. */ + /* Local allocation, will be discarded. */ dnslib_dname_t *zone_name = dnslib_dname_new_from_str(z->name, strlen(z->name), NULL); if (zone_name == NULL) { @@ -790,6 +787,7 @@ static int zones_insert_zones(ns_nameserver_t *ns, dnslib_zone_contents_dump(dnslib_zone_get_contents(zone), 1); + /* Directly discard zone. */ dnslib_dname_free(&zone_name); } return inserted; @@ -814,7 +812,9 @@ static int zones_remove_zones(const list *zone_conf, dnslib_zonedb_t *db_old) // for all zones in the configuration WALK_LIST(n, *zone_conf) { conf_zone_t *z = (conf_zone_t *)n; - // convert the zone name into a domain name + + /* Convert the zone name into a domain name. */ + /* Local allocation, will be discarded. */ dnslib_dname_t *zone_name = dnslib_dname_new_from_str(z->name, strlen(z->name), NULL); if (zone_name == NULL) { @@ -827,6 +827,7 @@ static int zones_remove_zones(const list *zone_conf, dnslib_zonedb_t *db_old) // remove the zone from the old zone db, but do not delete it dnslib_zonedb_remove_zone(db_old, zone_name, 0); + /* Directly discard. */ dnslib_dname_free(&zone_name); } return KNOT_EOK; diff --git a/src/zcompile/zcompile.c b/src/zcompile/zcompile.c index 0764f0e51cc531df1c4fceaa4e747e7ee4e9197f..11bb49d22febe8b83f4e6bcb5a0760183772b3b1 100644 --- a/src/zcompile/zcompile.c +++ b/src/zcompile/zcompile.c @@ -300,6 +300,9 @@ static ssize_t rdata_wireformat_to_rdata_atoms(const uint16_t *wireformat, dname = dnslib_dname_new_from_str((char *)wireformat, length, NULL); + /*! \todo implement refcounting correctly. */ + ref_init(&dname->ref, 0); /* disable dtor */ + ref_retain(&dname->ref); if (dname == NULL) { dbg_rdata("malformed dname!\n"); @@ -1824,6 +1827,9 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, dnslib_dname_t *dname = dnslib_dname_new_from_str(name, strlen(name), NULL); + /*! \todo implement refcounting correctly. */ + ref_init(&dname->ref, 0); /* disable dtor */ + ref_retain(&dname->ref); dnslib_node_t *origin_node = dnslib_node_new(dname, NULL, 0); diff --git a/src/zcompile/zlexer.l b/src/zcompile/zlexer.l index 43d8bff937b8000d20e5393f642694b12f89ecb7..84ab56d1f4bbdb0a433d10741c1914453cef19af 100644 --- a/src/zcompile/zlexer.l +++ b/src/zcompile/zlexer.l @@ -194,10 +194,13 @@ ANY [^\"\n\\]|\\. /*! \todo dnslib_dname_new_from_wire() (dname.h) * which dnslib_node to pass as node? */ - const dnslib_dname_t *dname; + dnslib_dname_t *dname; dname = dnslib_dname_new_from_wire((uint8_t*)tmp + 1, strlen(tmp + 1), NULL); + /*! \todo implement refcounting correctly. */ + ref_init(&dname->ref, 0); /* disable dtor */ + ref_retain(&dname->ref); if (!dname) { zc_error("incorrect include origin '%s'", tmp + 1); diff --git a/src/zcompile/zparser.y b/src/zcompile/zparser.y index abbf12e7af77b8b906c9b3b8145c0705510dddfe..17ef150d0d97dddb55c1809a3128105b470c5695 100644 --- a/src/zcompile/zparser.y +++ b/src/zcompile/zparser.y @@ -282,14 +282,14 @@ owner: dname sp // printf("Totally new dname: %p %s\n", $1, // dnslib_dname_to_str($1)); dnslib_dname_free(&parser->prev_dname); - parser->prev_dname = dnslib_dname_copy($1); + parser->prev_dname = dnslib_dname_deep_copy($1); $$ = $1; } | PREV { // printf("Name from prev_dname!: %p %s\n", parser->prev_dname, // dnslib_dname_to_str(parser->prev_dname)); - $$ = dnslib_dname_copy(parser->prev_dname); + $$ = dnslib_dname_deep_copy(parser->prev_dname); } ; @@ -344,7 +344,7 @@ abs_dname: '.' { /*! \todo Get root domain from db. */ //$$ = parser->db->domains->root; - $$ = dnslib_dname_copy(parser->root_domain); + $$ = dnslib_dname_deep_copy(parser->root_domain); } | '@' { @@ -370,6 +370,9 @@ label: STR $$ = error_dname; } else { $$ = dnslib_dname_new_from_str($1.str, $1.len, NULL); + /*! \todo implement refcounting correctly. */ + //ref_init(&$$->ref, 0); /* disable dtor */ + //ref_retain(&dname->ref); //printf("new: %p %s\n", $$, dnslib_dname_to_str($$)); } @@ -1213,6 +1216,9 @@ rdata_rrsig: STR sp STR sp STR sp STR sp STR sp STR $15.len));*/ dnslib_dname_t *dname = dnslib_dname_new_from_wire((uint8_t *)$15.str, $15.len, NULL); + /*! \todo implement refcounting correctly. */ + ref_init(&dname->ref, 0); /* disable dtor */ + ref_retain(&dname->ref); dnslib_dname_cat(dname, parser->root_domain); @@ -1240,6 +1246,10 @@ rdata_nsec: wire_dname nsec_seq dnslib_dname_t *dname = dnslib_dname_new_from_wire((uint8_t *)$1.str, $1.len, NULL); + /*! \todo implement refcounting correctly. */ + ref_init(&dname->ref, 0); /* disable dtor */ + ref_retain(&dname->ref); + free($1.str); dnslib_dname_cat(dname, parser->root_domain); @@ -1312,7 +1322,7 @@ rdata_dnskey: STR sp STR sp STR sp str_sp_seq trail rdata_ipsec_base: STR sp STR sp STR sp dotted_str { - const dnslib_dname_t* name = 0; + dnslib_dname_t* name = 0; zadd_rdata_wireformat(zparser_conv_byte($1.str)); /* precedence */ zadd_rdata_wireformat(zparser_conv_byte($3.str)); /* gateway type */ @@ -1335,6 +1345,9 @@ rdata_ipsec_base: STR sp STR sp STR sp dotted_str name = dnslib_dname_new_from_wire((uint8_t*)$7.str + 1, strlen($7.str + 1), NULL); + /*! \todo implement refcounting correctly. */ + ref_init(&name->ref, 0); /* disable dtor */ + ref_retain(&name->ref); if(!name) { zc_error_prev_line("IPSECKEY bad gateway" @@ -1345,8 +1358,14 @@ rdata_ipsec_base: STR sp STR sp STR sp dotted_str tmpd = dnslib_dname_new_from_wire(name->name, name->size, NULL); + /*! \todo implement refcounting correctly. */ + ref_init(&tmpd->ref, 0); /* disable dtor */ + ref_retain(&tmpd->ref); name = dnslib_dname_cat(tmpd, dnslib_node_parent(parser->origin, 0)->owner); + /*! \todo implement refcounting correctly. */ + ref_init(&name->ref, 0); /* disable dtor */ + ref_retain(&name->ref); } free($1.str); @@ -1444,7 +1463,7 @@ zparser_init(const char *filename, uint32_t ttl, uint16_t rclass, parser->default_class = rclass; parser->origin = origin; - parser->prev_dname = dnslib_dname_copy(parser->origin->owner); + parser->prev_dname = dnslib_dname_deep_copy(parser->origin->owner); parser->default_apex = origin; parser->error_occurred = 0; @@ -1455,6 +1474,9 @@ zparser_init(const char *filename, uint32_t ttl, uint16_t rclass, parser->last_node = origin; parser->root_domain = dnslib_dname_new_from_str(".", 1, NULL); + /*! \todo implement refcounting correctly. */ + ref_init(&parser->root_domain->ref, 0); /* disable dtor */ + ref_retain(&parser->root_domain->ref); /* Create zone */ parser->current_zone = dnslib_zone_new(origin, 0, 1);