1 /* 2 * answer.c -- manipulating query answers and encoding them. 3 * 4 * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. 5 * 6 * See LICENSE for the license. 7 * 8 */ 9 10 #include <config.h> 11 12 #include <string.h> 13 14 #include "answer.h" 15 #include "packet.h" 16 #include "query.h" 17 18 void 19 answer_init(answer_type *answer) 20 { 21 answer->rrset_count = 0; 22 } 23 24 int 25 answer_add_rrset(answer_type *answer, rr_section_type section, 26 domain_type *domain, rrset_type *rrset) 27 { 28 size_t i; 29 30 assert(section >= ANSWER_SECTION && section < RR_SECTION_COUNT); 31 assert(domain); 32 assert(rrset); 33 34 /* Don't add an RRset multiple times. */ 35 for (i = 0; i < answer->rrset_count; ++i) { 36 if (answer->rrsets[i] == rrset) { 37 if (section < answer->section[i]) { 38 answer->section[i] = section; 39 return 1; 40 } else { 41 return 0; 42 } 43 } 44 } 45 46 if (answer->rrset_count >= MAXRRSPP) { 47 /* XXX: Generate warning/error? */ 48 return 0; 49 } 50 51 answer->section[answer->rrset_count] = section; 52 answer->domains[answer->rrset_count] = domain; 53 answer->rrsets[answer->rrset_count] = rrset; 54 ++answer->rrset_count; 55 56 return 1; 57 } 58 59 void 60 encode_answer(query_type *q, const answer_type *answer) 61 { 62 uint16_t counts[RR_SECTION_COUNT]; 63 rr_section_type section; 64 size_t i; 65 int minimal_respsize = IPV4_MINIMAL_RESPONSE_SIZE; 66 int done = 0; 67 68 #if defined(INET6) && defined(MINIMAL_RESPONSES) 69 if (q->addr.ss_family == AF_INET6) 70 minimal_respsize = IPV6_MINIMAL_RESPONSE_SIZE; 71 #endif 72 73 for (section = ANSWER_SECTION; section < RR_SECTION_COUNT; ++section) { 74 counts[section] = 0; 75 } 76 77 for (section = ANSWER_SECTION; 78 !TC(q->packet) && section < RR_SECTION_COUNT; 79 ++section) { 80 81 for (i = 0; !TC(q->packet) && i < answer->rrset_count; ++i) { 82 if (answer->section[i] == section) { 83 counts[section] += packet_encode_rrset( 84 q, 85 answer->domains[i], 86 answer->rrsets[i], 87 section, minimal_respsize, &done); 88 } 89 } 90 #ifdef MINIMAL_RESPONSES 91 /** 92 * done is set prematurely, because the minimal response size 93 * has been reached. No need to try adding RRsets in following 94 * sections. 95 */ 96 if (done) { 97 break; 98 } 99 #endif 100 } 101 102 ANCOUNT_SET(q->packet, counts[ANSWER_SECTION]); 103 NSCOUNT_SET(q->packet, 104 counts[AUTHORITY_SECTION] 105 + counts[OPTIONAL_AUTHORITY_SECTION]); 106 ARCOUNT_SET(q->packet, 107 counts[ADDITIONAL_A_SECTION] 108 + counts[ADDITIONAL_AAAA_SECTION] 109 + counts[ADDITIONAL_OTHER_SECTION]); 110 } 111