_public_ int knot_rdataset_sort_at(knot_rdataset_t *rrs, size_t pos, knot_mm_t *mm) { if (rrs == NULL || rrs->rr_count == 0) { return KNOT_EINVAL; } knot_rdata_t *rr = knot_rdataset_at(rrs, pos); assert(rr); knot_rdata_t *earlier_rr = NULL; for (uint16_t i = 0; i < rrs->rr_count; ++i) { if (i == pos) { // It already is at the position return KNOT_EOK; } earlier_rr = knot_rdataset_at(rrs, i); int cmp = knot_rdata_cmp(earlier_rr, rr); if (cmp == 0) { // Duplication - we need to remove this RR return remove_rr_at(rrs, pos, mm); } else if (cmp > 0) { // Found position to move break; } } // RDATA have to be rearanged. knot_rdata_t *last_rr = knot_rdataset_at(rrs, pos - 1); assert(last_rr); assert(earlier_rr); // Save the RR to be moved const uint16_t size = knot_rdata_rdlen(rr); const uint32_t ttl = knot_rdata_ttl(rr); const uint8_t *rdata = knot_rdata_data(rr); knot_rdata_t tmp_rr[knot_rdata_array_size(size)]; knot_rdata_init(tmp_rr, size, rdata, ttl); // Move the array or just part of it knot_rdata_t *earlier_rr_moved = earlier_rr + knot_rdata_array_size(size); size_t last_rr_size = knot_rdata_array_size(knot_rdata_rdlen(last_rr)); memmove(earlier_rr_moved, earlier_rr, (last_rr + last_rr_size) - earlier_rr); // Set new RR knot_rdata_init(earlier_rr, size, knot_rdata_data(tmp_rr), ttl); return KNOT_EOK; }
_public_ int knot_rdataset_reserve(knot_rdataset_t *rrs, size_t size, knot_mm_t *mm) { if (rrs == NULL || size > MAX_RDLENGTH) { return KNOT_EINVAL; } size_t total_size = knot_rdataset_size(rrs); size_t new_size = total_size + knot_rdata_array_size(size); uint8_t *tmp = mm_realloc(mm, rrs->data, new_size, total_size); if (tmp == NULL) { return KNOT_ENOMEM; } rrs->data = tmp; rrs->rr_count++; // We have to initialise the 'size' field in the reserved space. knot_rdata_t *rr = knot_rdataset_at(rrs, rrs->rr_count - 1); assert(rr); knot_rdata_set_rdlen(rr, size); return KNOT_EOK; }
static int add_rr_at(knot_rdataset_t *rrs, const knot_rdata_t *rr, size_t pos, knot_mm_t *mm) { if (rrs == NULL || pos > rrs->rr_count) { return KNOT_EINVAL; } const uint16_t size = knot_rdata_rdlen(rr); const uint32_t ttl = knot_rdata_ttl(rr); const uint8_t *rdata = knot_rdata_data(rr); size_t total_size = knot_rdataset_size(rrs); // Realloc data. void *tmp = mm_realloc(mm, rrs->data, total_size + knot_rdata_array_size(size), total_size); if (tmp) { rrs->data = tmp; } else { return KNOT_ENOMEM; } if (rrs->rr_count == 0 || pos == rrs->rr_count) { // No need to rearange RDATA rrs->rr_count++; knot_rdata_t *new_rr = knot_rdataset_at(rrs, pos); knot_rdata_init(new_rr, size, rdata, ttl); return KNOT_EOK; } // RDATA have to be rearanged. knot_rdata_t *last_rr = knot_rdataset_at(rrs, rrs->rr_count - 1); knot_rdata_t *old_rr = knot_rdataset_at(rrs, pos); assert(last_rr); assert(old_rr); // Make space for new data by moving the array memmove(old_rr + knot_rdata_array_size(size), old_rr, (last_rr + knot_rdata_array_size(knot_rdata_rdlen(last_rr))) - old_rr); // Set new RR knot_rdata_init(old_rr, size, rdata, ttl); rrs->rr_count++; return KNOT_EOK; }
int main(int argc, char *argv[]) { plan(9); // Test array size size_t array_size = knot_rdata_array_size(16); ok(array_size == sizeof(struct rr_offsets) + 16, "rdata: array size."); // Test init knot_rdata_t rdata[array_size]; uint8_t payload[16] = "abcdefghijklmnop"; knot_rdata_init(rdata, 16, payload, 3600); const bool set_ok = knot_rdata_rdlen(rdata) == 16 && knot_rdata_ttl(rdata) == 3600 && memcmp(knot_rdata_data(rdata), payload, 16) == 0; ok(set_ok, "rdata: init."); // Test setters knot_rdata_set_ttl(rdata, 1234); ok(knot_rdata_ttl(rdata) == 1234, "rdata: set TTL."); knot_rdata_set_rdlen(rdata, 1); ok(knot_rdata_rdlen(rdata) == 1, "rdata: set RDLEN."); // Test compare knot_rdata_set_rdlen(rdata, 16); ok(knot_rdata_cmp(rdata, rdata) == 0, "rdata: cmp eq."); knot_rdata_t *lower = rdata; knot_rdata_t greater[knot_rdata_array_size(16)]; knot_rdata_init(greater, 16, (uint8_t *)"qrstuvwxyz123456", 1234); ok(knot_rdata_cmp(lower, greater) < 0, "rdata: cmp lower."); ok(knot_rdata_cmp(greater, lower) > 0, "rdata: cmp greater."); // Payloads will be the same. memcpy(knot_rdata_data(greater), knot_rdata_data(lower), 16); assert(knot_rdata_cmp(lower, greater) == 0); knot_rdata_set_rdlen(lower, 15); ok(knot_rdata_cmp(lower, greater) < 0, "rdata: cmp lower size."); ok(knot_rdata_cmp(greater, lower) > 0, "rdata: cmp greater size."); return 0; }
static int remove_rr_at(knot_rdataset_t *rrs, size_t pos, knot_mm_t *mm) { if (rrs == NULL || pos >= rrs->rr_count) { return KNOT_EINVAL; } knot_rdata_t *old_rr = knot_rdataset_at(rrs, pos); knot_rdata_t *last_rr = knot_rdataset_at(rrs, rrs->rr_count - 1); assert(old_rr); assert(last_rr); size_t total_size = knot_rdataset_size(rrs); uint16_t old_size = knot_rdata_rdlen(old_rr); uint8_t *old_threshold = old_rr + knot_rdata_array_size(old_size); uint8_t *last_threshold = last_rr + knot_rdata_array_size(knot_rdata_rdlen(last_rr)); // Move RDATA memmove(old_rr, old_threshold, last_threshold - old_threshold); if (rrs->rr_count > 1) { // Realloc RDATA void *tmp = mm_realloc(mm, rrs->data, total_size - (knot_rdata_array_size(old_size)), total_size); if (tmp == NULL) { return KNOT_ENOMEM; } else { rrs->data = tmp; } } else { // Free RDATA mm_free(mm, rrs->data); rrs->data = NULL; } rrs->rr_count--; return KNOT_EOK; }
static knot_rdata_t *rr_seek(knot_rdata_t *d, size_t pos) { if (d == NULL) { return NULL; } size_t offset = 0; for (size_t i = 0; i < pos; i++) { knot_rdata_t *rr = d + offset; offset += knot_rdata_array_size(knot_rdata_rdlen(rr)); } return d + offset; }
_public_ size_t knot_rdataset_size(const knot_rdataset_t *rrs) { if (rrs == NULL) { return 0; } size_t total_size = 0; for (size_t i = 0; i < rrs->rr_count; ++i) { const knot_rdata_t *rr = knot_rdataset_at(rrs, i); assert(rr); total_size += knot_rdata_array_size(knot_rdata_rdlen(rr)); } return total_size; }
static int add_pair(struct kr_zonecut *hints, const char *name, const char *addr) { /* Build key */ knot_dname_t key[KNOT_DNAME_MAXLEN]; if (!knot_dname_from_str(key, name, sizeof(key))) { return kr_error(EINVAL); } /* Parse address string */ struct sockaddr_storage ss; if (parse_addr_str(&ss, addr) != 0) { return kr_error(EINVAL); } /* Build rdata */ size_t addr_len = 0; uint8_t *raw_addr = sockaddr_raw(&ss, &addr_len); knot_rdata_t rdata[knot_rdata_array_size(addr_len)]; knot_rdata_init(rdata, addr_len, raw_addr, 0); return kr_zonecut_add(hints, key, rdata); }
static int parse_rdata(struct entry *entry, const char *owner, const char *rrtype, const char *rdata, int ttl, knot_mm_t *mm) { knot_rdataset_init(&entry->data.rrs); int ret = knot_rrtype_from_string(rrtype, &entry->data.type); if (ret != KNOT_EOK) { return ret; } /* Synthetize RR line */ char *rr_line = sprintf_alloc("%s %u IN %s %s\n", owner, ttl, rrtype, rdata); if (zs_set_input_string(g_scanner, rr_line, strlen(rr_line)) != 0 || zs_parse_all(g_scanner) != 0) { free(rr_line); return KNOT_EPARSEFAIL; } free(rr_line); /* Write parsed RDATA. */ knot_rdata_t rr[knot_rdata_array_size(g_scanner->r_data_length)]; knot_rdata_init(rr, g_scanner->r_data_length, g_scanner->r_data, ttl); return knot_rdataset_add(&entry->data.rrs, rr, mm); }
static int parse_rdata(struct entry *entry, const char *owner, const char *rrtype, const char *rdata, int ttl, mm_ctx_t *mm) { knot_rdataset_init(&entry->data.rrs); int ret = knot_rrtype_from_string(rrtype, &entry->data.type); if (ret != KNOT_EOK) { return ret; } /* Synthetize RR line */ char *rr_line = sprintf_alloc("%s %u IN %s %s\n", owner, ttl, rrtype, rdata); ret = zs_scanner_parse(g_scanner, rr_line, rr_line + strlen(rr_line), true); free(rr_line); /* Write parsed RDATA. */ if (ret == KNOT_EOK) { knot_rdata_t rr[knot_rdata_array_size(g_scanner->r_data_length)]; knot_rdata_init(rr, g_scanner->r_data_length, g_scanner->r_data, ttl); ret = knot_rdataset_add(&entry->data.rrs, rr, mm); } return ret; }
int main(int argc, char *argv[]) { plan(34); // Test init knot_rdataset_t rdataset; knot_rdataset_init(&rdataset); ok(rdataset.data == NULL && rdataset.rr_count == 0, "rdataset: init."); // Test rdata addition knot_rdata_t rdata_gt[knot_rdata_array_size(4)]; knot_rdata_init(rdata_gt, 4, (uint8_t *)"wxyz", 3600); int ret = knot_rdataset_add(NULL, NULL, NULL); ok(ret == KNOT_EINVAL, "rdataset: add NULL."); ret = knot_rdataset_add(&rdataset, rdata_gt, NULL); bool add_ok = ret == KNOT_EOK && rdataset.rr_count == 1 && knot_rdata_cmp(rdata_gt, rdataset.data) == 0; ok(add_ok, "rdataset: add."); knot_rdata_t rdata_lo[knot_rdata_array_size(4)]; knot_rdata_init(rdata_lo, 4, (uint8_t *)"abcd", 3600); ret = knot_rdataset_add(&rdataset, rdata_lo, NULL); add_ok = ret == KNOT_EOK && rdataset.rr_count == 2 && knot_rdata_cmp(rdata_lo, rdataset.data) == 0; ok(add_ok, "rdataset: add lower."); // Test getters ok(knot_rdata_cmp(knot_rdataset_at(&rdataset, 0), rdata_lo) == 0 && knot_rdata_cmp(knot_rdataset_at(&rdataset, 1), rdata_gt) == 0, "rdataset: at."); ok(knot_rdataset_size(&rdataset) == knot_rdata_array_size(4) * 2, "rdataset: size."); // Test copy ok(knot_rdataset_copy(NULL, NULL, NULL) == KNOT_EINVAL, "rdataset: copy NULL."); knot_rdataset_t copy; ret = knot_rdataset_copy(©, &rdataset, NULL); const bool copy_ok = ret == KNOT_EOK && copy.rr_count == rdataset.rr_count && knot_rdataset_size(©) == knot_rdataset_size(&rdataset) && memcmp(rdataset.data, copy.data, knot_rdataset_size(&rdataset)) == 0; ok(copy_ok, "rdataset: copy"); // Test eq ok(knot_rdataset_eq(&rdataset, ©), "rdataset: equal"); // Test clear knot_rdataset_clear(©, NULL); ok(copy.rr_count == 0 && copy.data == NULL, "rdataset: clear."); // Test not equal (different count) ok(!knot_rdataset_eq(&rdataset, ©), "rdataset: not equal - count"); // Test member knot_rdata_t not_a_member[knot_rdata_array_size(1)]; knot_rdata_init(not_a_member, 1, (uint8_t *)"?", 3600); ok(knot_rdataset_member(&rdataset, rdata_gt, true), "rdataset: is member."); ok(!knot_rdataset_member(&rdataset, not_a_member, true), "rdataset: is not member."); knot_rdata_set_ttl(rdata_gt, 1234); ok(knot_rdataset_member(&rdataset, rdata_gt, false), "rdataset: is member TTL."); ok(!knot_rdataset_member(&rdataset, rdata_gt, true), "rdataset: is not member TTL."); // Test merge ok(knot_rdataset_merge(NULL, NULL, NULL) == KNOT_EINVAL, "rdataset: merge NULL."); knot_rdataset_t empty; knot_rdataset_init(&empty); ret = knot_rdataset_merge(&empty, &rdataset, NULL); bool merge_ok = ret == KNOT_EOK && knot_rdataset_eq(&empty, &rdataset); ok(merge_ok, "rdataset: merge empty."); knot_rdata_t *data_before = rdataset.data; ret = knot_rdataset_merge(&rdataset, &rdataset, NULL); merge_ok = ret == KNOT_EOK && rdataset.rr_count == 2 && data_before == rdataset.data; ok(merge_ok, "rdataset: merge self."); knot_rdataset_clear(&empty, NULL); // Init structs for merge sort testing knot_rdataset_t rdataset_lo; // "Lower" rdataset knot_rdataset_init(&rdataset_lo); RDATASET_INIT_WITH(rdataset_lo, rdata_lo); knot_rdataset_t rdataset_gt; // "Greater" rdataset knot_rdataset_init(&rdataset_gt); RDATASET_INIT_WITH(rdataset_gt, rdata_gt); // Test not equal - different data ok(!knot_rdataset_eq(&rdataset_gt, &rdataset_lo), "rdataset: data not equal."); // Test that merge keeps the sorted order ret = knot_rdataset_merge(&rdataset_lo, &rdataset_gt, NULL); merge_ok = ret == KNOT_EOK && knot_rdataset_eq(&rdataset_lo, &rdataset); ok(merge_ok, "rdataset: merge into lower."); RDATASET_INIT_WITH(rdataset_lo, rdata_lo); RDATASET_INIT_WITH(rdataset_gt, rdata_gt); ret = knot_rdataset_merge(&rdataset_gt, &rdataset_lo, NULL); merge_ok = ret == KNOT_EOK && knot_rdataset_eq(&rdataset_gt, &rdataset); ok(merge_ok, "rdataset: merge into greater."); // Test intersect ok(knot_rdataset_intersect(NULL, NULL, NULL, NULL) == KNOT_EINVAL, "rdataset: intersect NULL."); knot_rdataset_t intersection; ret = knot_rdataset_intersect(&rdataset, &rdataset, &intersection, NULL); bool intersect_ok = ret == KNOT_EOK && knot_rdataset_eq(&rdataset, &intersection); ok(intersect_ok, "rdataset: intersect self."); knot_rdataset_clear(&intersection, NULL); RDATASET_INIT_WITH(rdataset_lo, rdata_lo); RDATASET_INIT_WITH(rdataset_gt, rdata_gt); ret = knot_rdataset_intersect(&rdataset_lo, &rdataset_gt, &intersection, NULL); intersect_ok = ret == KNOT_EOK && intersection.rr_count == 0; ok(intersect_ok, "rdataset: intersect no common."); ret = knot_rdataset_intersect(&rdataset, &rdataset_lo, &intersection, NULL); intersect_ok = ret == KNOT_EOK && knot_rdataset_eq(&intersection, &rdataset_lo); ok(intersect_ok, "rdataset: intersect normal."); knot_rdataset_clear(&intersection, NULL); // Test subtract ok(knot_rdataset_subtract(NULL, NULL, NULL) == KNOT_EINVAL, "rdataset: subtract NULL."); ok(knot_rdataset_subtract(&rdataset, &rdataset, NULL) == KNOT_EINVAL, "rdataset: subtract self."); ret = knot_rdataset_copy(©, &rdataset, NULL); assert(ret == KNOT_EOK); ret = knot_rdataset_subtract(©, &rdataset, NULL); bool subtract_ok = ret == KNOT_EOK && copy.rr_count == 0; ok(subtract_ok, "rdataset: subtract identical."); RDATASET_INIT_WITH(rdataset_lo, rdata_lo); RDATASET_INIT_WITH(rdataset_gt, rdata_gt); data_before = rdataset_lo.data; ret = knot_rdataset_subtract(&rdataset_lo, &rdataset_gt, NULL); subtract_ok = ret == KNOT_EOK && rdataset_lo.rr_count == 1 && rdataset_lo.data == data_before; ok(subtract_ok, "rdataset: subtract no common."); ret = knot_rdataset_subtract(&rdataset, &rdataset_gt, NULL); subtract_ok = ret == KNOT_EOK && knot_rdataset_eq(&rdataset, &rdataset_lo); ok(subtract_ok, "rdataset: subtract normal."); ret = knot_rdataset_subtract(&rdataset, &rdataset_lo, NULL); subtract_ok = ret == KNOT_EOK && rdataset.rr_count == 0 && rdataset.data == NULL; ok(subtract_ok, "rdataset: subtract last."); ret = knot_rdataset_reserve(&rdataset, 65536, NULL); ok(ret == KNOT_EINVAL, "rdataset: reserve too much"); RDATASET_INIT_WITH(rdataset, rdata_gt); size_t old_rrs_size = knot_rdataset_size(&rdataset); size_t rr_size = knot_rdata_rdlen(rdata_lo); ret = knot_rdataset_reserve(&rdataset, rr_size, NULL); size_t new_rrs_size = knot_rdataset_size(&rdataset); bool reserve_ok = ret == KNOT_EOK && new_rrs_size == (old_rrs_size + knot_rdata_array_size(rr_size)); ok(reserve_ok, "rdataset: reserve normal"); RDATASET_INIT_WITH(copy, rdata_lo); knot_rdataset_add(©, rdata_gt, NULL); knot_rdata_init(knot_rdataset_at(&rdataset, 1), 4, (uint8_t *)"abcd", 3600); ret = knot_rdataset_sort_at(&rdataset, 1, NULL); bool sort_ok = ret == KNOT_EOK && knot_rdataset_eq(&rdataset, ©); ok(sort_ok, "rdataset: sort reserved space"); knot_rdataset_clear(©, NULL); knot_rdataset_clear(&rdataset, NULL); knot_rdataset_clear(&rdataset_lo, NULL); knot_rdataset_clear(&rdataset_gt, NULL); return EXIT_SUCCESS; }