master.c revision d22b4de3f1c3151979e2a064cb271007c710c5a7
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley/*
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * Copyright (C) 1999, 2000 Internet Software Consortium.
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley *
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * Permission to use, copy, modify, and distribute this software for any
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * purpose with or without fee is hereby granted, provided that the above
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * copyright notice and this permission notice appear in all copies.
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley *
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley */
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
110d1702731f42dd620879c1d765ebe91f3920ceMichael Graff/* $Id: master.c,v 1.64 2000/09/05 03:35:17 marka Exp $ */
110d1702731f42dd620879c1d765ebe91f3920ceMichael Graff
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#include <config.h>
54f959d12b5a1f9315fbf6a776c6d349316e9686Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#include <isc/event.h>
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#include <isc/lex.h>
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#include <isc/magic.h>
54f959d12b5a1f9315fbf6a776c6d349316e9686Bob Halley#include <isc/mem.h>
0d0d9a9d9895605aba3a44fd03c051e15f88ecf5Bob Halley#include <isc/stdtime.h>
0d0d9a9d9895605aba3a44fd03c051e15f88ecf5Bob Halley#include <isc/string.h>
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#include <isc/task.h>
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews#include <isc/util.h>
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#include <dns/callbacks.h>
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#include <dns/events.h>
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#include <dns/fixedname.h>
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#include <dns/master.h>
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#include <dns/name.h>
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#include <dns/rdata.h>
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#include <dns/rdataclass.h>
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#include <dns/rdatalist.h>
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#include <dns/rdataset.h>
078d49b63324f01d98301ee21671abee0c41fcdeBob Halley#include <dns/rdatatype.h>
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#include <dns/result.h>
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#include <dns/time.h>
904a5734375869ffb504ed8cde6b68cafadb6d64Bob Halley#include <dns/ttl.h>
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley/*
ca67883a666bdf314d3da958d5195e7215b1f797Bob Halley * Grow the number of dns_rdatalist_t (RDLSZ) and dns_rdata_t (RDSZ) structures
b12f0228b32775ee688ed21ddbf3a116c1adfb43Michael Graff * by these sizes when we need to.
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley *
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * RDLSZ reflects the number of different types with the same name expected.
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * RDSZ reflects the number of rdata expected at a give name that can fit into
e496615043400500492fa7b891c515c8e7cb7d08Bob Halley * 64k.
e496615043400500492fa7b891c515c8e7cb7d08Bob Halley */
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#define RDLSZ 32
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#define RDSZ 512
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#define NBUFS 4
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#define MAXWIRESZ 255
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley/*
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * Target buffer size and minimum target size.
078d49b63324f01d98301ee21671abee0c41fcdeBob Halley * MINTSIZ must be big enough to hold the largest rdata record.
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley *
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * TSIZ >= MINTSIZ
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley */
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#define TSIZ (128*1024)
904a5734375869ffb504ed8cde6b68cafadb6d64Bob Halley/*
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * max message size - header - root - type - class - ttl - rdlen
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley */
ca67883a666bdf314d3da958d5195e7215b1f797Bob Halley#define MINTSIZ (65535 - 12 - 1 - 2 - 2 - 4 - 2)
b12f0228b32775ee688ed21ddbf3a116c1adfb43Michael Graff/*
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * Size for tokens in the presentation format,
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * The largest tokens are the base64 blocks in KEY and CERT records,
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley * Largest key allowed is about 1372 bytes but
e496615043400500492fa7b891c515c8e7cb7d08Bob Halley * there is no fixed upper bound on CERT records.
e496615043400500492fa7b891c515c8e7cb7d08Bob Halley * 2K is too small for some X.509s, 8K is overkill.
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley */
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#define TOKENSIZ (8*1024)
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleytypedef ISC_LIST(dns_rdatalist_t) rdatalist_head_t;
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley/*
2cd0c38115b1efb043ed3104c0d08e51ceade0d7Bob Halley * Master file loading state that persists across $INCLUDEs.
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley */
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
078d49b63324f01d98301ee21671abee0c41fcdeBob Halleystruct dns_loadctx {
0180ccf72c79b98eb8ee5abbb7331aec6951dd9fBob Halley isc_uint32_t magic;
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley isc_mem_t *mctx;
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley isc_lex_t *lex;
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley dns_loadctx_t *parent;
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley dns_rdatacallbacks_t *callbacks;
904a5734375869ffb504ed8cde6b68cafadb6d64Bob Halley isc_task_t *task;
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley dns_loaddonefunc_t done;
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley void *done_arg;
ca67883a666bdf314d3da958d5195e7215b1f797Bob Halley isc_boolean_t ttl_known;
b12f0228b32775ee688ed21ddbf3a116c1adfb43Michael Graff isc_boolean_t default_ttl_known;
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley isc_boolean_t warn_1035;
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley isc_boolean_t age_ttl;
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley isc_uint32_t ttl;
e496615043400500492fa7b891c515c8e7cb7d08Bob Halley isc_uint32_t default_ttl;
e496615043400500492fa7b891c515c8e7cb7d08Bob Halley dns_rdataclass_t zclass;
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley dns_fixedname_t fixed_top;
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley dns_fixedname_t fixed[NBUFS]; /* working buffers */
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley unsigned int in_use[NBUFS]; /* covert to bitmap? */
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley dns_name_t *top; /* top of zone */
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley dns_name_t *origin;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley dns_name_t *current;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley dns_name_t *glue;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley /* Which fixed buffers we are using? */
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley int glue_in_use;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley int current_in_use;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley int origin_in_use;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley unsigned int loop_cnt; /* records per quantum,
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley * 0 => all. */
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley isc_boolean_t canceled;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley /* Rate limit goo. */
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley isc_boolean_t rate_limited;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley ISC_LINK(dns_loadctx_t) link;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley char *master_file;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley dns_loadmgr_t *loadmgr;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley isc_event_t event;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley isc_mutex_t lock;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley /* locked by lock */
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley isc_uint32_t references;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley};
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley#define DNS_LCTX_MAGIC ISC_MAGIC('L','c','t','x')
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley#define DNS_LCTX_VALID(ctx) ISC_MAGIC_VALID(ctx, DNS_LCTX_MAGIC)
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halleystruct dns_loadmgr {
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley isc_uint32_t magic;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley isc_mem_t *mctx;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley isc_uint32_t erefs;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley isc_uint32_t irefs;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley isc_mutex_t lock;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley isc_uint32_t active;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley isc_uint32_t limit;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley ISC_LIST(dns_loadctx_t) list;
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley};
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley#define DNS_LMGR_MAGIC ISC_MAGIC('L','m','g','r')
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley#define DNS_LMGR_VALID(ctx) ISC_MAGIC_VALID(ctx, DNS_LMGR_MAGIC)
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halleystatic isc_result_t
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halleypushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t **ctxp);
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halleystatic isc_result_t
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halleycommit(dns_rdatacallbacks_t *, isc_lex_t *, rdatalist_head_t *, dns_name_t *,
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley dns_name_t *);
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleystatic isc_boolean_t
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleyis_glue(rdatalist_head_t *, dns_name_t *);
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleystatic dns_rdatalist_t *
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleygrow_rdatalist(int, dns_rdatalist_t *, int, rdatalist_head_t *,
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley rdatalist_head_t *, isc_mem_t *mctx);
078d49b63324f01d98301ee21671abee0c41fcdeBob Halley
0180ccf72c79b98eb8ee5abbb7331aec6951dd9fBob Halleystatic dns_rdata_t *
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleygrow_rdata(int, dns_rdata_t *, int, rdatalist_head_t *, rdatalist_head_t *,
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley isc_mem_t *);
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleystatic isc_boolean_t
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleyon_list(dns_rdatalist_t *this, dns_rdata_t *rdata);
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleystatic void
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleyload_quantum(isc_task_t *task, isc_event_t *event);
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleystatic isc_result_t
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleytask_send(dns_loadctx_t *ctx);
078d49b63324f01d98301ee21671abee0c41fcdeBob Halley
0180ccf72c79b98eb8ee5abbb7331aec6951dd9fBob Halleystatic void
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleyloadctx_destroy(dns_loadctx_t *ctx);
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleystatic void
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleyloadmgr_start(isc_task_t *task, isc_event_t *event);
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleystatic void
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleyloadmgr_cancel(dns_loadmgr_t *mgr);
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleystatic void
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleyloadmgr_iattach(dns_loadmgr_t *source, dns_loadmgr_t **target);
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
078d49b63324f01d98301ee21671abee0c41fcdeBob Halleystatic void
0180ccf72c79b98eb8ee5abbb7331aec6951dd9fBob Halleyloadmgr_idetach(dns_loadmgr_t **mgrp);
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleystatic void
5619558151f1aa4249b3ead979e76876e29278b6Bob Halleyloadmgr_destroy(dns_loadmgr_t *mgr);
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#define GETTOKEN(lexer, options, token, eol) \
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley do { \
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley result = gettoken(lexer, options, token, eol, callbacks); \
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley switch (result) { \
ccbfddc70ef38263daca312d29bb8c5077e24785Bob Halley case ISC_R_SUCCESS: \
8d6024e7cffbd84fa8d06ce50c60307d7b3b49c2Michael Graff break; \
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley case ISC_R_UNEXPECTED: \
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff goto cleanup; \
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff default: \
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff goto error_cleanup; \
ccbfddc70ef38263daca312d29bb8c5077e24785Bob Halley } \
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews if ((token)->type == isc_tokentype_special) \
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews goto error_cleanup; \
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff } while (0)
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley#define COMMITALL \
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley do { \
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley result = commit(callbacks, ctx->lex, &current_list, \
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley ctx->current, ctx->top); \
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley if (result != ISC_R_SUCCESS) \
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley goto cleanup; \
54f959d12b5a1f9315fbf6a776c6d349316e9686Bob Halley result = commit(callbacks, ctx->lex, &glue_list, \
ccbfddc70ef38263daca312d29bb8c5077e24785Bob Halley ctx->glue, ctx->top); \
54f959d12b5a1f9315fbf6a776c6d349316e9686Bob Halley if (result != ISC_R_SUCCESS) \
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley goto cleanup; \
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley rdcount = 0; \
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley rdlcount = 0; \
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley isc_buffer_init(&target, target_mem, target_size); \
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley rdcount_save = rdcount; \
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley rdlcount_save = rdlcount; \
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley } while (0)
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley
ccbfddc70ef38263daca312d29bb8c5077e24785Bob Halley#define WARNUNEXPECTEDEOF(lexer) \
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff do { \
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff if (isc_lex_isfile(lexer)) \
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff (*callbacks->warn)(callbacks, \
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff "%s:%lu: file does not end with newline", \
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews isc_lex_getsourcename(lexer), \
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews isc_lex_getsourceline(lexer)); \
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews } while (0)
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews#define CTX_COPYVAR(ctx, new, var) (new)->var = (ctx)->var
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrewsstatic inline isc_result_t
c1e7aff941dbf40090fec49300e728ad017d4f0cMark Andrewsgettoken(isc_lex_t *lex, unsigned int options, isc_token_t *token,
c1e7aff941dbf40090fec49300e728ad017d4f0cMark Andrews isc_boolean_t eol, dns_rdatacallbacks_t *callbacks)
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews{
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff isc_result_t result;
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff options |= ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | ISC_LEXOPT_DNSMULTILINE |
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley ISC_LEXOPT_ESCAPE;
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff result = isc_lex_gettoken(lex, options, token);
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff if (result != ISC_R_SUCCESS) {
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff switch (result) {
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff case ISC_R_NOMEMORY:
c1e7aff941dbf40090fec49300e728ad017d4f0cMark Andrews return (ISC_R_NOMEMORY);
c1e7aff941dbf40090fec49300e728ad017d4f0cMark Andrews default:
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews UNEXPECTED_ERROR(__FILE__, __LINE__,
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff "isc_lex_gettoken() failed: %s",
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews isc_result_totext(result));
22f735acbce7ffe95af20bb58bb8929b6f1d674fMichael Graff return (ISC_R_UNEXPECTED);
904a5734375869ffb504ed8cde6b68cafadb6d64Bob Halley }
bf345589ce0b0b64533d4566e4992a0e63aac6f5Bob Halley /*NOTREACHED*/
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff }
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff if (eol != ISC_TRUE)
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff if (token->type == isc_tokentype_eol ||
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff token->type == isc_tokentype_eof) {
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff (*callbacks->error)(callbacks,
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff "dns_master_load: %s:%lu: unexpected end of %s",
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff isc_lex_getsourcename(lex),
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff isc_lex_getsourceline(lex),
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff (token->type ==
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff isc_tokentype_eol) ?
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff "line" : "file");
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff return (ISC_R_UNEXPECTEDEND);
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff }
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff return (ISC_R_SUCCESS);
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff}
c1e7aff941dbf40090fec49300e728ad017d4f0cMark Andrews
c1e7aff941dbf40090fec49300e728ad017d4f0cMark Andrews
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graffvoid
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graffdns_loadctx_attach(dns_loadctx_t *source, dns_loadctx_t **target) {
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff REQUIRE(target != NULL && *target == NULL);
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff REQUIRE(DNS_LCTX_VALID(source));
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff
c1e7aff941dbf40090fec49300e728ad017d4f0cMark Andrews LOCK(&source->lock);
c1e7aff941dbf40090fec49300e728ad017d4f0cMark Andrews INSIST(source->references > 0);
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff source->references++;
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff INSIST(source->references != 0); /* Overflow? */
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff UNLOCK(&source->lock);
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff
69be7837c920fac5c71a73e8fad586f9a2711e96Michael Graff *target = source;
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews}
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff
ccbfddc70ef38263daca312d29bb8c5077e24785Bob Halleyvoid
ccbfddc70ef38263daca312d29bb8c5077e24785Bob Halleydns_loadctx_detach(dns_loadctx_t **ctxp) {
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff dns_loadctx_t *ctx;
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff isc_boolean_t need_destroy = ISC_FALSE;
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff REQUIRE(ctxp != NULL);
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff ctx = *ctxp;
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff REQUIRE(DNS_LCTX_VALID(ctx));
ccbfddc70ef38263daca312d29bb8c5077e24785Bob Halley
ccbfddc70ef38263daca312d29bb8c5077e24785Bob Halley LOCK(&ctx->lock);
76883e8cee593f45c65b0936e5d6e8f778d6e3efMichael Graff INSIST(ctx->references > 0);
5619558151f1aa4249b3ead979e76876e29278b6Bob Halley ctx->references--;
if (ctx->references == 0)
need_destroy = ISC_TRUE;
UNLOCK(&ctx->lock);
if (need_destroy)
loadctx_destroy(ctx);
*ctxp = NULL;
}
static void
loadctx_destroy(dns_loadctx_t *ctx) {
isc_mem_t *mctx;
REQUIRE(DNS_LCTX_VALID(ctx));
ctx->magic = 0;
if (ctx->parent != NULL)
dns_loadctx_detach(&ctx->parent);
if (ctx->lex != NULL) {
isc_lex_close(ctx->lex);
isc_lex_destroy(&ctx->lex);
}
if (ctx->task != NULL)
isc_task_detach(&ctx->task);
if (ctx->master_file != NULL) {
isc_mem_free(ctx->mctx, ctx->master_file);
ctx->master_file = NULL;
}
if (ctx->loadmgr != NULL)
loadmgr_idetach(&ctx->loadmgr);
DESTROYLOCK(&ctx->lock);
mctx = NULL;
isc_mem_attach(ctx->mctx, &mctx);
isc_mem_detach(&ctx->mctx);
isc_mem_put(mctx, ctx, sizeof(*ctx));
isc_mem_detach(&mctx);
}
static isc_result_t
loadctx_create(isc_mem_t *mctx, isc_boolean_t age_ttl, dns_name_t *top,
dns_rdataclass_t zclass, dns_name_t *origin,
dns_rdatacallbacks_t *callbacks, isc_task_t *task,
dns_loaddonefunc_t done, void *done_arg,
dns_loadctx_t **ctxp)
{
dns_loadctx_t *ctx;
isc_result_t result;
isc_region_t r;
int i;
isc_lexspecials_t specials;
REQUIRE(ctxp != NULL && *ctxp == NULL);
REQUIRE(callbacks != NULL);
REQUIRE(callbacks->add != NULL);
REQUIRE(callbacks->error != NULL);
REQUIRE(callbacks->warn != NULL);
REQUIRE(mctx != NULL);
REQUIRE(dns_name_isabsolute(top));
REQUIRE(dns_name_isabsolute(origin));
REQUIRE((task == NULL && done == NULL) ||
(task != NULL && done != NULL));
ctx = isc_mem_get(mctx, sizeof(*ctx));
if (ctx == NULL)
return (ISC_R_NOMEMORY);
result = isc_mutex_init(&ctx->lock);
if (result != ISC_R_SUCCESS) {
isc_mem_put(mctx, ctx, sizeof *ctx);
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_mutex_init() failed: %s",
isc_result_totext(result));
return (ISC_R_UNEXPECTED);
}
ctx->lex = NULL;
result = isc_lex_create(mctx, TOKENSIZ, &ctx->lex);
if (result != ISC_R_SUCCESS)
goto cleanup_ctx;
memset(specials, 0, sizeof specials);
specials['('] = 1;
specials[')'] = 1;
specials['"'] = 1;
isc_lex_setspecials(ctx->lex, specials);
isc_lex_setcomments(ctx->lex, ISC_LEXCOMMENT_DNSMASTERFILE);
ctx->ttl_known = ISC_FALSE;
ctx->ttl = 0;
ctx->default_ttl_known = ISC_FALSE;
ctx->default_ttl = 0;
ctx->warn_1035 = ISC_TRUE; /* XXX Argument? */
ctx->age_ttl = age_ttl;
ctx->zclass = zclass;
dns_fixedname_init(&ctx->fixed_top);
ctx->top = dns_fixedname_name(&ctx->fixed_top);
dns_name_toregion(top, &r);
dns_name_fromregion(ctx->top, &r);
for (i = 0; i < NBUFS; i++) {
dns_fixedname_init(&ctx->fixed[i]);
ctx->in_use[i] = ISC_FALSE;
}
ctx->origin_in_use = 0;
ctx->origin = dns_fixedname_name(&ctx->fixed[ctx->origin_in_use]);
ctx->in_use[ctx->origin_in_use] = ISC_TRUE;
dns_name_toregion(origin, &r);
dns_name_fromregion(ctx->origin, &r);
ctx->glue = NULL;
ctx->current = NULL;
ctx->glue_in_use = -1;
ctx->current_in_use = -1;
ctx->loop_cnt = (done != NULL) ? 100 : 0;
ctx->callbacks = callbacks;
ctx->parent = NULL;
ctx->task = NULL;
if (task != NULL)
isc_task_attach(task, &ctx->task);
ctx->done = done;
ctx->done_arg = done_arg;
ctx->rate_limited = ISC_FALSE;
ctx->master_file = NULL;
ctx->loadmgr = NULL;
ISC_LINK_INIT(ctx, link);
ISC_EVENT_INIT(&ctx->event, sizeof(ctx->event), 0, NULL,
DNS_EVENT_MASTERNEXTZONE, loadmgr_start,
ctx, ctx, NULL, NULL);
ctx->canceled = ISC_FALSE;
ctx->mctx = NULL;
isc_mem_attach(mctx, &ctx->mctx);
ctx->references = 1; /* Implicit attach. */
ctx->magic = DNS_LCTX_MAGIC;
*ctxp = ctx;
return (ISC_R_SUCCESS);
cleanup_ctx:
isc_mem_put(mctx, ctx, sizeof(*ctx));
return (result);
}
static isc_result_t
load(dns_loadctx_t **ctxp) {
dns_rdataclass_t rdclass;
dns_rdatatype_t type, covers;
isc_uint32_t ttl_offset = 0;
dns_name_t *new_name;
isc_boolean_t current_has_delegation = ISC_FALSE;
isc_boolean_t done = ISC_FALSE;
isc_boolean_t finish_origin = ISC_FALSE;
isc_boolean_t finish_include = ISC_FALSE;
isc_boolean_t read_till_eol = ISC_FALSE;
isc_boolean_t initialws;
char *include_file = NULL;
isc_token_t token;
isc_result_t result = ISC_R_UNEXPECTED;
rdatalist_head_t glue_list;
rdatalist_head_t current_list;
dns_rdatalist_t *this;
dns_rdatalist_t *rdatalist = NULL;
dns_rdatalist_t *new_rdatalist;
int rdlcount = 0;
int rdlcount_save = 0;
int rdatalist_size = 0;
isc_buffer_t buffer;
isc_buffer_t target;
isc_buffer_t target_save;
dns_rdata_t *rdata = NULL;
dns_rdata_t *new_rdata;
int rdcount = 0;
int rdcount_save = 0;
int rdata_size = 0;
unsigned char *target_mem = NULL;
int target_size = TSIZ;
int new_in_use;
unsigned int loop_cnt = 0;
isc_mem_t *mctx;
dns_rdatacallbacks_t *callbacks;
dns_loadctx_t *ctx;
ctx = *ctxp;
REQUIRE(DNS_LCTX_VALID(ctx));
callbacks = ctx->callbacks;
mctx = ctx->mctx;
ISC_LIST_INIT(glue_list);
ISC_LIST_INIT(current_list);
/*
* Allocate target_size of buffer space. This is greater than twice
* the maximum individual RR data size.
*/
target_mem = isc_mem_get(mctx, target_size);
if (target_mem == NULL) {
result = ISC_R_NOMEMORY;
goto error_cleanup;
}
isc_buffer_init(&target, target_mem, target_size);
target_save = target;
do {
initialws = ISC_FALSE;
GETTOKEN(ctx->lex, ISC_LEXOPT_INITIALWS, &token, ISC_TRUE);
if (token.type == isc_tokentype_eof) {
if (read_till_eol)
WARNUNEXPECTEDEOF(ctx->lex);
/* Pop the include stack? */
if (ctx->parent != NULL) {
COMMITALL;
*ctxp = ctx->parent;
ctx->parent = NULL;
CTX_COPYVAR(ctx, *ctxp, ttl_known);
CTX_COPYVAR(ctx, *ctxp, default_ttl_known);
CTX_COPYVAR(ctx, *ctxp, ttl);
CTX_COPYVAR(ctx, *ctxp, default_ttl);
CTX_COPYVAR(ctx, *ctxp, warn_1035);
dns_loadctx_detach(&ctx);
ctx = *ctxp;
continue;
}
done = ISC_TRUE;
continue;
}
if (token.type == isc_tokentype_eol) {
read_till_eol = ISC_FALSE;
continue; /* blank line */
}
if (read_till_eol)
continue;
if (token.type == isc_tokentype_initialws) {
/*
* Still working on the same name.
*/
initialws = ISC_TRUE;
} else if (token.type == isc_tokentype_string) {
/*
* "$" Support.
*
* "$ORIGIN" and "$INCLUDE" can both take domain names.
* The processing of "$ORIGIN" and "$INCLUDE" extends
* across the normal domain name processing.
*/
if (strcasecmp(token.value.as_pointer,
"$ORIGIN") == 0) {
GETTOKEN(ctx->lex, 0, &token, ISC_FALSE);
read_till_eol = ISC_TRUE;
finish_origin = ISC_TRUE;
} else if (strcasecmp(token.value.as_pointer,
"$TTL") == 0) {
GETTOKEN(ctx->lex, 0, &token, ISC_FALSE);
result =
dns_ttl_fromtext(&token.value.as_textregion,
&ctx->ttl);
if (result != ISC_R_SUCCESS)
goto cleanup;
if (ctx->ttl > 0x7fffffffUL) {
(callbacks->warn)(callbacks,
"%s: %s:%lu: "
"$TTL %lu > MAXTTL, "
"setting $TTL to 0",
"dns_master_load",
isc_lex_getsourcename(ctx->lex),
isc_lex_getsourceline(ctx->lex),
ctx->ttl);
ctx->ttl = 0;
}
ctx->default_ttl = ctx->ttl;
ctx->default_ttl_known = ISC_TRUE;
read_till_eol = ISC_TRUE;
continue;
} else if (strcasecmp(token.value.as_pointer,
"$INCLUDE") == 0) {
COMMITALL;
if (ttl_offset != 0) {
(callbacks->error)(callbacks,
"%s: %s:%lu: $INCLUDE "
"may not be used with $DATE",
"dns_master_load",
isc_lex_getsourcename(ctx->lex),
isc_lex_getsourceline(ctx->lex));
goto cleanup;
}
GETTOKEN(ctx->lex, ISC_LEXOPT_QSTRING, &token,
ISC_FALSE);
if (include_file != NULL)
isc_mem_free(mctx, include_file);
include_file = isc_mem_strdup(mctx,
token.value.as_pointer);
if (include_file == NULL) {
result = ISC_R_NOMEMORY;
goto error_cleanup;
}
GETTOKEN(ctx->lex, 0, &token, ISC_TRUE);
if (token.type == isc_tokentype_eol ||
token.type == isc_tokentype_eof) {
if (token.type == isc_tokentype_eof)
WARNUNEXPECTEDEOF(ctx->lex);
isc_lex_ungettoken(ctx->lex, &token);
/*
* No origin field.
*/
result = pushfile(include_file,
ctx->origin,
ctxp);
if (result != ISC_R_SUCCESS)
goto cleanup;
ctx = *ctxp;
continue;
}
/*
* There is an origin field. Fall through
* to domain name processing code and do
* the actual inclusion later.
*/
read_till_eol = ISC_TRUE;
finish_include = ISC_TRUE;
} else if (strcasecmp(token.value.as_pointer,
"$DATE") == 0) {
isc_int64_t dump_time64;
isc_stdtime_t dump_time, current_time;
GETTOKEN(ctx->lex, 0, &token, ISC_FALSE);
isc_stdtime_get(&current_time);
result = dns_time64_fromtext(token.value.
as_pointer, &dump_time64);
if (result != ISC_R_SUCCESS)
goto error_cleanup;
dump_time = (isc_stdtime_t)dump_time64;
if (dump_time != dump_time64) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"%s: %s:%lu: "
"$DATE outside epoch",
"dns_master_load",
isc_lex_getsourcename(ctx->lex),
isc_lex_getsourceline(ctx->lex));
goto cleanup;
}
if (dump_time > current_time) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"%s: %s:%lu: "
"$DATE in future, using current date",
"dns_master_load",
isc_lex_getsourcename(ctx->lex),
isc_lex_getsourceline(ctx->lex));
dump_time = current_time;
}
ttl_offset = current_time - dump_time;
read_till_eol = ISC_TRUE;
continue;
} else if (strncasecmp(token.value.as_pointer,
"$", 1) == 0) {
(callbacks->error)(callbacks,
"%s: %s:%lu: "
"unknown $ directive '%s'",
"dns_master_load",
isc_lex_getsourcename(ctx->lex),
isc_lex_getsourceline(ctx->lex),
token.value.as_pointer);
goto cleanup;
}
/*
* Normal processing resumes.
*
* Find a free name buffer.
*/
for (new_in_use = 0; new_in_use < NBUFS ; new_in_use++)
if (!ctx->in_use[new_in_use])
break;
INSIST(new_in_use < NBUFS);
dns_fixedname_init(&ctx->fixed[new_in_use]);
new_name = dns_fixedname_name(&ctx->fixed[new_in_use]);
isc_buffer_init(&buffer, token.value.as_region.base,
token.value.as_region.length);
isc_buffer_add(&buffer, token.value.as_region.length);
isc_buffer_setactive(&buffer,
token.value.as_region.length);
result = dns_name_fromtext(new_name, &buffer,
ctx->origin, ISC_FALSE, NULL);
if (result != ISC_R_SUCCESS)
goto error_cleanup;
/*
* Finish $ORIGIN / $INCLUDE processing if required.
*/
if (finish_origin) {
if (ctx->origin_in_use != -1)
ctx->in_use[ctx->origin_in_use] = ISC_FALSE;
ctx->origin_in_use = new_in_use;
ctx->in_use[ctx->origin_in_use] = ISC_TRUE;
ctx->origin = new_name;
finish_origin = ISC_FALSE;
continue;
}
if (finish_include) {
finish_include = ISC_FALSE;
result = pushfile(include_file, new_name, ctxp);
if (result != ISC_R_SUCCESS)
goto cleanup;
ctx = *ctxp;
continue;
}
/*
* "$" Processing Finished
*/
/*
* If we are processing glue and the new name does
* not match the current glue name, commit the glue
* and pop stacks leaving us in 'normal' processing
* state. Linked lists are undone by commit().
*/
if (ctx->glue != NULL &&
dns_name_compare(ctx->glue, new_name) != 0) {
result = commit(callbacks, ctx->lex, &glue_list,
ctx->glue, ctx->top);
if (result != ISC_R_SUCCESS)
goto cleanup;
if (ctx->glue_in_use != -1)
ctx->in_use[ctx->glue_in_use] = ISC_FALSE;
ctx->glue_in_use = -1;
ctx->glue = NULL;
rdcount = rdcount_save;
rdlcount = rdlcount_save;
target = target_save;
}
/*
* If we are in 'normal' processing state and the new
* name does not match the current name, see if the
* new name is for glue and treat it as such,
* otherwise we have a new name so commit what we
* have.
*/
if ((ctx->glue == NULL) && (ctx->current == NULL ||
dns_name_compare(ctx->current, new_name) != 0)) {
if (current_has_delegation &&
is_glue(&current_list, new_name)) {
rdcount_save = rdcount;
rdlcount_save = rdlcount;
target_save = target;
ctx->glue = new_name;
ctx->glue_in_use = new_in_use;
ctx->in_use[ctx->glue_in_use] = ISC_TRUE;
} else {
result = commit(callbacks, ctx->lex,
&current_list,
ctx->current,
ctx->top);
if (result != ISC_R_SUCCESS)
goto cleanup;
rdcount = 0;
rdlcount = 0;
if (ctx->current_in_use != -1)
ctx->in_use[ctx->current_in_use]
= ISC_FALSE;
ctx->current_in_use = new_in_use;
ctx->in_use[ctx->current_in_use] = ISC_TRUE;
ctx->current = new_name;
current_has_delegation = ISC_FALSE;
isc_buffer_init(&target, target_mem,
target_size);
}
}
} else {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"%s:%lu: isc_lex_gettoken() returned "
"unexpeced token type (%d)",
isc_lex_getsourcename(ctx->lex),
isc_lex_getsourceline(ctx->lex),
token.type);
result = ISC_R_UNEXPECTED;
goto cleanup;
}
/*
* Find TTL, class and type. Both TTL and class are optional
* and may occur in any order if they exist. TTL and class
* come before type which must exist.
*
* [<TTL>] [<class>] <type> <RDATA>
* [<class>] [<TTL>] <type> <RDATA>
*/
type = 0;
rdclass = 0;
GETTOKEN(ctx->lex, 0, &token, initialws);
if (initialws) {
if (token.type == isc_tokentype_eol) {
read_till_eol = ISC_FALSE;
continue; /* blank line */
}
if (token.type == isc_tokentype_eof) {
WARNUNEXPECTEDEOF(ctx->lex);
read_till_eol = ISC_FALSE;
isc_lex_ungettoken(ctx->lex, &token);
continue;
}
if (ctx->current == NULL) {
(*callbacks->error)(callbacks,
"%s: %s:%lu: No current owner name",
"dns_master_load",
isc_lex_getsourcename(ctx->lex),
isc_lex_getsourceline(ctx->lex));
result = DNS_R_NOOWNER;
goto cleanup;
}
}
if (dns_rdataclass_fromtext(&rdclass,
&token.value.as_textregion)
== ISC_R_SUCCESS)
GETTOKEN(ctx->lex, 0, &token, ISC_FALSE);
if (dns_ttl_fromtext(&token.value.as_textregion, &ctx->ttl)
== ISC_R_SUCCESS) {
if (ctx->ttl > 0x7fffffffUL) {
(callbacks->warn)(callbacks,
"%s: %s:%lu: "
"TTL %lu > MAXTTL, "
"setting TTL to 0",
"dns_master_load",
isc_lex_getsourcename(ctx->lex),
isc_lex_getsourceline(ctx->lex),
ctx->ttl);
ctx->ttl = 0;
}
ctx->ttl_known = ISC_TRUE;
GETTOKEN(ctx->lex, 0, &token, ISC_FALSE);
} else if (!ctx->ttl_known && !ctx->default_ttl_known) {
/*
* BIND 4 / 8 'USE_SOA_MINIMUM' could be set here.
*/
(*callbacks->error)(callbacks,
"%s: %s:%lu: no TTL specified",
"dns_master_load",
isc_lex_getsourcename(ctx->lex),
isc_lex_getsourceline(ctx->lex));
result = DNS_R_NOTTL;
goto cleanup;
} else if (ctx->default_ttl_known) {
ctx->ttl = ctx->default_ttl;
} else if (ctx->warn_1035) {
(*callbacks->warn)(callbacks,
"%s: %s:%lu: "
"using RFC 1035 TTL semantics",
"dns_master_load",
isc_lex_getsourcename(ctx->lex),
isc_lex_getsourceline(ctx->lex));
ctx->warn_1035 = ISC_FALSE;
}
if (token.type != isc_tokentype_string) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_lex_gettoken() returned unexpected token type");
result = ISC_R_UNEXPECTED;
goto cleanup;
}
if (rdclass == 0 &&
dns_rdataclass_fromtext(&rdclass,
&token.value.as_textregion)
== ISC_R_SUCCESS)
GETTOKEN(ctx->lex, 0, &token, ISC_FALSE);
if (token.type != isc_tokentype_string) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_lex_gettoken() returned unexpected token type");
result = ISC_R_UNEXPECTED;
goto cleanup;
}
result = dns_rdatatype_fromtext(&type,
&token.value.as_textregion);
if (result != ISC_R_SUCCESS)
goto cleanup;
/*
* If the class specified does not match the zone's class
* print out a error message and exit.
*/
if (rdclass != 0 && rdclass != ctx->zclass) {
char buf1[32];
char buf2[32];
unsigned int len1, len2;
isc_buffer_t buffer;
isc_region_t region;
isc_buffer_init(&buffer, buf1, sizeof(buf1));
result = dns_rdataclass_totext(rdclass, &buffer);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"dns_rdataclass_totext() failed: %s",
dns_result_totext(result));
result = ISC_R_UNEXPECTED;
goto cleanup;
}
isc_buffer_usedregion(&buffer, &region);
len1 = region.length;
isc_buffer_init(&buffer, buf2, sizeof(buf2));
result = dns_rdataclass_totext(ctx->zclass, &buffer);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"dns_rdataclass_totext() failed: %s",
dns_result_totext(result));
result = ISC_R_UNEXPECTED;
goto cleanup;
}
isc_buffer_usedregion(&buffer, &region);
len2 = region.length;
(*callbacks->error)(callbacks,
"%s: %s:%lu: class (%.*s) != "
"zone class (%.*s)",
"dns_master_load",
isc_lex_getsourcename(ctx->lex),
isc_lex_getsourceline(ctx->lex),
len1, buf1, len2, buf2);
result = DNS_R_BADCLASS;
goto cleanup;
}
if (type == dns_rdatatype_ns && ctx->glue == NULL)
current_has_delegation = ISC_TRUE;
if (ctx->age_ttl) {
/*
* Adjust the TTL for $DATE. If the RR has already
* expired, ignore it without even parsing the rdata
* part (good for performance, bad for catching
* syntax errors).
*/
if (ctx->ttl < ttl_offset) {
read_till_eol = ISC_TRUE;
continue;
}
ctx->ttl -= ttl_offset;
}
/*
* Find a rdata structure.
*/
if (rdcount == rdata_size) {
new_rdata = grow_rdata(rdata_size + RDSZ, rdata,
rdata_size, &current_list,
&glue_list, mctx);
if (new_rdata == NULL) {
result = ISC_R_NOMEMORY;
goto error_cleanup;
}
rdata_size += RDSZ;
rdata = new_rdata;
}
/*
* Read rdata contents.
*/
result = dns_rdata_fromtext(&rdata[rdcount], ctx->zclass, type,
ctx->lex, ctx->origin, ISC_FALSE, &target,
callbacks);
if (result != ISC_R_SUCCESS)
goto cleanup;
if (type == dns_rdatatype_sig)
covers = dns_rdata_covers(&rdata[rdcount]);
else
covers = 0;
/*
* Find type in rdatalist.
* If it does not exist create new one and prepend to list
* as this will mimimise list traversal.
*/
if (ctx->glue != NULL)
this = ISC_LIST_HEAD(glue_list);
else
this = ISC_LIST_HEAD(current_list);
while (this != NULL) {
if (this->type == type && this->covers == covers)
break;
this = ISC_LIST_NEXT(this, link);
}
if (this == NULL) {
if (rdlcount == rdatalist_size) {
new_rdatalist =
grow_rdatalist(rdatalist_size + RDLSZ,
rdatalist,
rdatalist_size,
&current_list,
&glue_list,
mctx);
if (new_rdatalist == NULL) {
result = ISC_R_NOMEMORY;
goto error_cleanup;
}
rdatalist = new_rdatalist;
rdatalist_size += RDLSZ;
}
this = &rdatalist[rdlcount++];
this->type = type;
this->covers = covers;
this->rdclass = ctx->zclass;
this->ttl = ctx->ttl;
ISC_LIST_INIT(this->rdata);
ISC_LINK_INIT(this, link);
if (ctx->glue != NULL)
ISC_LIST_PREPEND(glue_list, this, link);
else
ISC_LIST_PREPEND(current_list, this, link);
} else if (this->ttl != ctx->ttl) {
(*callbacks->warn)(callbacks,
"%s: %s:%lu: "
"TTL set to prior TTL (%lu)",
"dns_master_load",
isc_lex_getsourcename(ctx->lex),
isc_lex_getsourceline(ctx->lex),
this->ttl);
ctx->ttl = this->ttl;
}
/*
* If the new rdata is not on the list add it.
*
* If the new rdata is on the list do not worry about
* recovering the space it is using in target as it will be
* recovered when we next call commit. The worst that can
* happen is that we make a few extra calls to commit.
*/
if (!on_list(this, &rdata[rdcount])) {
ISC_LIST_APPEND(this->rdata, &rdata[rdcount], link);
rdcount++;
}
/*
* We must have at least 64k as rdlen is 16 bits.
* If we don't commit everything we have so far.
*/
if ((target.length - target.used) < MINTSIZ)
COMMITALL;
} while (!done && (ctx->loop_cnt == 0 || ctx->loop_cnt < loop_cnt++));
/*
* Commit what has not yet been committed.
*/
result = commit(callbacks, ctx->lex, &current_list, ctx->current, ctx->top);
if (result != ISC_R_SUCCESS)
goto cleanup;
result = commit(callbacks, ctx->lex, &glue_list, ctx->glue, ctx->top);
if (result != ISC_R_SUCCESS)
goto cleanup;
else
result = ISC_R_SUCCESS;
if (!done) {
INSIST(ctx->done != NULL && ctx->task != NULL);
result = DNS_R_CONTINUE;
}
goto cleanup;
error_cleanup:
(*callbacks->error)(callbacks, "dns_master_load: %s",
dns_result_totext(result));
cleanup:
while ((this = ISC_LIST_HEAD(current_list)) != NULL)
ISC_LIST_UNLINK(current_list, this, link);
while ((this = ISC_LIST_HEAD(glue_list)) != NULL)
ISC_LIST_UNLINK(glue_list, this, link);
if (rdatalist != NULL)
isc_mem_put(mctx, rdatalist,
rdatalist_size * sizeof *rdatalist);
if (rdata != NULL)
isc_mem_put(mctx, rdata, rdata_size * sizeof *rdata);
if (target_mem != NULL)
isc_mem_put(mctx, target_mem, target_size);
if (include_file != NULL)
isc_mem_free(mctx, include_file);
return (result);
}
static isc_result_t
pushfile(const char *master_file, dns_name_t *origin, dns_loadctx_t **ctxp) {
isc_result_t result;
dns_loadctx_t *ctx;
dns_loadctx_t *new = NULL;
isc_region_t r;
int new_in_use;
REQUIRE(master_file != NULL);
REQUIRE(ctxp != NULL);
ctx = *ctxp;
REQUIRE(DNS_LCTX_VALID(ctx));
result = loadctx_create(ctx->mctx, ctx->age_ttl, ctx->top,
ctx->zclass, origin, ctx->callbacks,
ctx->task, ctx->done, ctx->done_arg,
&new);
if (result != ISC_R_SUCCESS)
return (result);
/* Set current domain. */
if (ctx->glue != NULL || ctx->current != NULL) {
for (new_in_use = 0; new_in_use < NBUFS ; new_in_use++)
if (!ctx->in_use[new_in_use])
break;
INSIST(new_in_use < NBUFS);
new->current_in_use = new_in_use;
new->current =
dns_fixedname_name(&new->fixed[new->current_in_use]);
new->in_use[ctx->current_in_use] = ISC_TRUE;
dns_name_toregion((ctx->glue != NULL) ?
ctx->glue : ctx->current, &r);
dns_name_fromregion(new->current, &r);
}
CTX_COPYVAR(ctx, new, ttl_known);
CTX_COPYVAR(ctx, new, default_ttl_known);
CTX_COPYVAR(ctx, new, ttl);
CTX_COPYVAR(ctx, new, default_ttl);
CTX_COPYVAR(ctx, new, warn_1035);
result = isc_lex_openfile(new->lex, master_file);
if (result != ISC_R_SUCCESS)
goto cleanup;
new->parent = ctx;
*ctxp = new;
return (ISC_R_SUCCESS);
cleanup:
if (new != NULL)
dns_loadctx_detach(&new);
return (result);
}
isc_result_t
dns_master_loadfile(const char *master_file, dns_name_t *top,
dns_name_t *origin,
dns_rdataclass_t zclass, isc_boolean_t age_ttl,
dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
{
dns_loadctx_t *ctx = NULL;
isc_result_t result;
result = loadctx_create(mctx, age_ttl, top, zclass, origin,
callbacks, NULL, NULL, NULL, &ctx);
if (result != ISC_R_SUCCESS)
return (result);
result = isc_lex_openfile(ctx->lex, master_file);
if (result != ISC_R_SUCCESS)
goto cleanup;
result = load(&ctx);
INSIST(result != DNS_R_CONTINUE);
cleanup:
if (ctx != NULL)
dns_loadctx_detach(&ctx);
return (result);
}
isc_result_t
dns_master_loadfilequota(const char *master_file, dns_name_t *top,
dns_name_t *origin, dns_rdataclass_t zclass,
isc_boolean_t age_ttl, dns_rdatacallbacks_t *callbacks, isc_task_t *task, dns_loaddonefunc_t done,
void *done_arg, dns_loadmgr_t *lmgr,
dns_loadctx_t **ctxp, isc_mem_t *mctx)
{
isc_boolean_t queue;
dns_loadctx_t *ctx = NULL;
isc_result_t result;
isc_event_t *event;
REQUIRE(DNS_LMGR_VALID(lmgr));
REQUIRE(ctxp != NULL && *ctxp == NULL);
result = loadctx_create(mctx, age_ttl, top, zclass, origin,
callbacks, task, done, done_arg, &ctx);
if (result != ISC_R_SUCCESS)
goto cleanup;
ctx->rate_limited = ISC_TRUE;
ctx->master_file = isc_mem_strdup(mctx, master_file);
if (ctx->master_file == NULL) {
result = ISC_R_NOMEMORY;
goto cleanup;
}
loadmgr_iattach(lmgr, &ctx->loadmgr);
LOCK(&lmgr->lock);
lmgr->active++;
queue = ISC_TF((lmgr->limit != 0 && lmgr->active > lmgr->limit));
if (queue)
ISC_LIST_APPEND(lmgr->list, ctx, link);
INSIST(queue || ISC_LIST_EMPTY(lmgr->list));
UNLOCK(&lmgr->lock);
dns_loadctx_attach(ctx, ctxp);
result = DNS_R_CONTINUE;
if (!queue) {
event = &ctx->event;
isc_task_send(ctx->task, &event);
}
return (result);
cleanup:
if (ctx != NULL)
dns_loadctx_detach(&ctx);
return (result);
}
static void
loadmgr_done(dns_loadctx_t *ctx, isc_result_t result) {
dns_loadctx_t *next;
isc_event_t *event;
if (ctx->done != NULL)
(ctx->done)(ctx->done_arg, result);
LOCK(&ctx->loadmgr->lock);
INSIST(ctx->loadmgr->active > 0);
ctx->loadmgr->active--;
/* dequeue */
next = ISC_LIST_HEAD(ctx->loadmgr->list);
if (next != NULL)
ISC_LIST_UNLINK(ctx->loadmgr->list, next, link);
UNLOCK(&ctx->loadmgr->lock);
if (next != NULL) {
event = &next->event;
isc_task_send(next->task, &event);
}
}
static void
loadmgr_start(isc_task_t *task, isc_event_t *event) {
dns_loadctx_t *ctx = event->ev_arg;
isc_result_t result;
INSIST(task == ctx->task);
if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0) {
result = ISC_R_CANCELED;
goto done;
}
result = isc_lex_openfile(ctx->lex, ctx->master_file);
if (result == ISC_R_SUCCESS)
result = load(&ctx);
if (result == DNS_R_CONTINUE) {
result = task_send(ctx);
if (result == ISC_R_SUCCESS)
isc_event_free(&event);
return;
}
done:
loadmgr_done(ctx, result);
isc_event_free(&event);
dns_loadctx_detach(&ctx);
return;
}
isc_result_t
dns_master_loadfileinc(const char *master_file, dns_name_t *top,
dns_name_t *origin, dns_rdataclass_t zclass,
isc_boolean_t age_ttl, dns_rdatacallbacks_t *callbacks,
isc_task_t *task, dns_loaddonefunc_t done,
void *done_arg, isc_mem_t *mctx)
{
dns_loadctx_t *ctx = NULL;
isc_result_t tresult;
isc_result_t result;
result = loadctx_create(mctx, age_ttl, top, zclass, origin,
callbacks, task, done, done_arg, &ctx);
if (result != ISC_R_SUCCESS)
return (result);
result = isc_lex_openfile(ctx->lex, master_file);
if (result != ISC_R_SUCCESS)
goto cleanup;
result = load(&ctx);
if (result == DNS_R_CONTINUE) {
tresult = task_send(ctx);
if (tresult == ISC_R_SUCCESS)
return (result);
result = tresult;
}
if (ctx->done != NULL)
(ctx->done)(ctx->done_arg, result);
cleanup:
if (ctx != NULL)
dns_loadctx_detach(&ctx);
return (result);
}
isc_result_t
dns_master_loadstream(FILE *stream, dns_name_t *top, dns_name_t *origin,
dns_rdataclass_t zclass, isc_boolean_t age_ttl,
dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
{
isc_result_t result;
dns_loadctx_t *ctx = NULL;
REQUIRE(stream != NULL);
result = loadctx_create(mctx, age_ttl, top, zclass, origin,
callbacks, NULL, NULL, NULL, &ctx);
if (result != ISC_R_SUCCESS)
goto cleanup;
result = isc_lex_openstream(ctx->lex, stream);
if (result != ISC_R_SUCCESS)
goto cleanup;
result = load(&ctx);
INSIST(result != DNS_R_CONTINUE);
cleanup:
if (ctx != NULL)
dns_loadctx_detach(&ctx);
return (result);
}
isc_result_t
dns_master_loadstreaminc(FILE *stream, dns_name_t *top, dns_name_t *origin,
dns_rdataclass_t zclass, isc_boolean_t age_ttl,
dns_rdatacallbacks_t *callbacks, isc_task_t *task,
dns_loaddonefunc_t done, void *done_arg,
isc_mem_t *mctx)
{
isc_result_t result;
isc_result_t tresult;
dns_loadctx_t *ctx = NULL;
REQUIRE(stream != NULL);
result = loadctx_create(mctx, age_ttl, top, zclass, origin,
callbacks, task, done, done_arg, &ctx);
if (result != ISC_R_SUCCESS)
goto cleanup;
result = isc_lex_openstream(ctx->lex, stream);
if (result != ISC_R_SUCCESS)
goto cleanup;
result = load(&ctx);
if (result == DNS_R_CONTINUE) {
tresult = task_send(ctx);
if (tresult == ISC_R_SUCCESS)
return (result);
result = tresult;
}
if (ctx->done != NULL)
(ctx->done)(ctx->done_arg, result);
cleanup:
if (ctx != NULL)
dns_loadctx_detach(&ctx);
return (result);
}
isc_result_t
dns_master_loadbuffer(isc_buffer_t *buffer, dns_name_t *top,
dns_name_t *origin, dns_rdataclass_t zclass,
isc_boolean_t age_ttl,
dns_rdatacallbacks_t *callbacks, isc_mem_t *mctx)
{
isc_result_t result;
dns_loadctx_t *ctx = NULL;
REQUIRE(buffer != NULL);
result = loadctx_create(mctx, age_ttl, top, zclass, origin,
callbacks, NULL, NULL, NULL, &ctx);
if (result != ISC_R_SUCCESS)
return (result);
result = isc_lex_openbuffer(ctx->lex, buffer);
if (result != ISC_R_SUCCESS)
goto cleanup;
result = load(&ctx);
INSIST(result != DNS_R_CONTINUE);
cleanup:
if (ctx != NULL)
dns_loadctx_detach(&ctx);
return (result);
}
isc_result_t
dns_master_loadbufferinc(isc_buffer_t *buffer, dns_name_t *top,
dns_name_t *origin, dns_rdataclass_t zclass,
isc_boolean_t age_ttl,
dns_rdatacallbacks_t *callbacks, isc_task_t *task,
dns_loaddonefunc_t done, void *done_arg,
isc_mem_t *mctx)
{
isc_result_t result;
isc_result_t tresult;
dns_loadctx_t *ctx = NULL;
REQUIRE(buffer != NULL);
result = loadctx_create(mctx, age_ttl, top, zclass, origin,
callbacks, task, done, done_arg, &ctx);
if (result != ISC_R_SUCCESS)
return (result);
result = isc_lex_openbuffer(ctx->lex, buffer);
if (result != ISC_R_SUCCESS)
goto cleanup;
result = load(&ctx);
if (result == DNS_R_CONTINUE) {
tresult = task_send(ctx);
if (tresult == ISC_R_SUCCESS)
return (result);
result = tresult;
}
if (ctx->done != NULL)
(ctx->done)(ctx->done_arg, result);
cleanup:
if (ctx != NULL)
dns_loadctx_detach(&ctx);
return (result);
}
/*
* Grow the slab of dns_rdatalist_t structures.
* Re-link glue and current list.
*/
static dns_rdatalist_t *
grow_rdatalist(int new_len, dns_rdatalist_t *old, int old_len,
rdatalist_head_t *current, rdatalist_head_t *glue,
isc_mem_t *mctx)
{
dns_rdatalist_t *new;
int rdlcount = 0;
ISC_LIST(dns_rdatalist_t) save;
dns_rdatalist_t *this;
new = isc_mem_get(mctx, new_len * sizeof *new);
if (new == NULL)
return (NULL);
ISC_LIST_INIT(save);
this = ISC_LIST_HEAD(*current);
while ((this = ISC_LIST_HEAD(*current)) != NULL) {
ISC_LIST_UNLINK(*current, this, link);
ISC_LIST_APPEND(save, this, link);
}
while ((this = ISC_LIST_HEAD(save)) != NULL) {
ISC_LIST_UNLINK(save, this, link);
new[rdlcount] = *this;
ISC_LIST_APPEND(*current, &new[rdlcount], link);
rdlcount++;
}
ISC_LIST_INIT(save);
this = ISC_LIST_HEAD(*glue);
while ((this = ISC_LIST_HEAD(*glue)) != NULL) {
ISC_LIST_UNLINK(*glue, this, link);
ISC_LIST_APPEND(save, this, link);
}
while ((this = ISC_LIST_HEAD(save)) != NULL) {
ISC_LIST_UNLINK(save, this, link);
new[rdlcount] = *this;
ISC_LIST_APPEND(*glue, &new[rdlcount], link);
rdlcount++;
}
INSIST(rdlcount == old_len);
if (old != NULL)
isc_mem_put(mctx, old, old_len * sizeof *old);
return (new);
}
/*
* Grow the slab of rdata structs.
* Re-link the current and glue chains.
*/
static dns_rdata_t *
grow_rdata(int new_len, dns_rdata_t *old, int old_len,
rdatalist_head_t *current, rdatalist_head_t *glue,
isc_mem_t *mctx)
{
dns_rdata_t *new;
int rdcount = 0;
ISC_LIST(dns_rdata_t) save;
dns_rdatalist_t *this;
dns_rdata_t *rdata;
new = isc_mem_get(mctx, new_len * sizeof *new);
if (new == NULL)
return (NULL);
memset(new, 0, new_len * sizeof *new);
/*
* Copy current relinking.
*/
this = ISC_LIST_HEAD(*current);
while (this != NULL) {
ISC_LIST_INIT(save);
while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
ISC_LIST_UNLINK(this->rdata, rdata, link);
ISC_LIST_APPEND(save, rdata, link);
}
while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
ISC_LIST_UNLINK(save, rdata, link);
new[rdcount] = *rdata;
ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
rdcount++;
}
this = ISC_LIST_NEXT(this, link);
}
/*
* Copy glue relinking.
*/
this = ISC_LIST_HEAD(*glue);
while (this != NULL) {
ISC_LIST_INIT(save);
while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
ISC_LIST_UNLINK(this->rdata, rdata, link);
ISC_LIST_APPEND(save, rdata, link);
}
while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
ISC_LIST_UNLINK(save, rdata, link);
new[rdcount] = *rdata;
ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
rdcount++;
}
this = ISC_LIST_NEXT(this, link);
}
INSIST(rdcount == old_len);
if (old != NULL)
isc_mem_put(mctx, old, old_len * sizeof *old);
return (new);
}
/*
* Convert each element from a rdatalist_t to rdataset then call commit.
* Unlink each element as we go.
*/
static isc_result_t
commit(dns_rdatacallbacks_t *callbacks, isc_lex_t *lex,
rdatalist_head_t *head, dns_name_t *owner, dns_name_t *top)
{
dns_rdatalist_t *this;
dns_rdataset_t dataset;
isc_result_t result;
isc_boolean_t ignore = ISC_FALSE;
this = ISC_LIST_HEAD(*head);
if (this == NULL)
return (ISC_R_SUCCESS);
if (!dns_name_issubdomain(owner, top)) {
/*
* Ignore out-of-zone data.
*/
(callbacks->warn)(callbacks,
"%s: %s:%lu: "
"ignoring out-of-zone data",
"dns_master_load",
isc_lex_getsourcename(lex),
isc_lex_getsourceline(lex));
ignore = ISC_TRUE;
}
do {
if (!ignore) {
dns_rdataset_init(&dataset);
dns_rdatalist_tordataset(this, &dataset);
dataset.trust = dns_trust_ultimate;
result = ((*callbacks->add)(callbacks->add_private,
owner,
&dataset));
if (result != ISC_R_SUCCESS)
return (result);
}
ISC_LIST_UNLINK(*head, this, link);
this = ISC_LIST_HEAD(*head);
} while (this != NULL);
return (ISC_R_SUCCESS);
}
/*
* Returns ISC_TRUE if one of the NS rdata's contains 'owner'.
*/
static isc_boolean_t
is_glue(rdatalist_head_t *head, dns_name_t *owner) {
dns_rdatalist_t *this;
dns_rdata_t *rdata;
isc_region_t region;
dns_name_t name;
/*
* Find NS rrset.
*/
this = ISC_LIST_HEAD(*head);
while (this != NULL) {
if (this->type == dns_rdatatype_ns)
break;
this = ISC_LIST_NEXT(this, link);
}
if (this == NULL)
return (ISC_FALSE);
rdata = ISC_LIST_HEAD(this->rdata);
while (rdata != NULL) {
dns_name_init(&name, NULL);
dns_rdata_toregion(rdata, &region);
dns_name_fromregion(&name, &region);
if (dns_name_compare(&name, owner) == 0)
return (ISC_TRUE);
rdata = ISC_LIST_NEXT(rdata, link);
}
return (ISC_FALSE);
}
/*
* Returns ISC_TRUE if the 'rdata' is already on 'rdatalist'.
*/
static isc_boolean_t
on_list(dns_rdatalist_t *rdatalist, dns_rdata_t *rdata) {
dns_rdata_t *rdata2;
rdata2 = ISC_LIST_HEAD(rdatalist->rdata);
while (rdata2 != NULL) {
if (dns_rdata_compare(rdata, rdata2) == 0)
return (ISC_TRUE);
rdata2 = ISC_LIST_NEXT(rdata2, link);
}
return (ISC_FALSE);
}
static void
load_quantum(isc_task_t *task, isc_event_t *event) {
isc_result_t result;
dns_loadctx_t *ctx;
REQUIRE(event != NULL);
ctx = event->ev_arg;
REQUIRE(DNS_LCTX_VALID(ctx));
if (ctx->canceled)
result = ISC_R_CANCELED;
else
result = load(&ctx);
if (result == DNS_R_CONTINUE) {
isc_task_send(task, &event);
} else if (result == ISC_R_SUCCESS && ctx->parent) {
/* Pop ctx and continue. */
event->ev_arg = ctx->parent;
ctx->parent = NULL;
dns_loadctx_detach(&ctx);
isc_task_send(task, &event);
} else {
if (ctx->rate_limited)
loadmgr_done(ctx, result);
else
(ctx->done)(ctx->done_arg, result);
isc_event_free(&event);
dns_loadctx_detach(&ctx);
}
}
static isc_result_t
task_send(dns_loadctx_t *ctx) {
isc_event_t *event;
event = isc_event_allocate(ctx->mctx, NULL,
DNS_EVENT_MASTERQUANTUM,
load_quantum, ctx, sizeof(*event));
if (event == NULL)
return (ISC_R_NOMEMORY);
isc_task_send(ctx->task, &event);
return (ISC_R_SUCCESS);
}
/*
* DNS load manager.
*/
isc_result_t
dns_loadmgr_create(isc_mem_t *mctx, dns_loadmgr_t **mgrp) {
dns_loadmgr_t *mgr;
isc_result_t result;
REQUIRE(mgrp != NULL && *mgrp == NULL);
mgr = isc_mem_get(mctx, sizeof(*mgr));
if (mgr == NULL)
return (ISC_R_NOMEMORY);
result = isc_mutex_init(&mgr->lock);
if (result != ISC_R_SUCCESS) {
isc_mem_put(mctx, mgr, sizeof(*mgr));
return (result);
}
mgr->erefs = 1;
mgr->irefs = 0;
mgr->limit = 0;
mgr->active = 0;
mgr->mctx = NULL;
isc_mem_attach(mctx, &mgr->mctx);
ISC_LIST_INIT(mgr->list);
mgr->magic = DNS_LMGR_MAGIC;
*mgrp = mgr;
return (ISC_R_SUCCESS);
}
void
dns_loadmgr_setlimit(dns_loadmgr_t *mgr, isc_uint32_t limit) {
REQUIRE(DNS_LMGR_VALID(mgr));
mgr->limit = limit;
}
isc_uint32_t
dns_loadmgr_getlimit(dns_loadmgr_t *mgr) {
REQUIRE(DNS_LMGR_VALID(mgr));
return(mgr->limit);
}
void
dns_loadmgr_cancel(dns_loadmgr_t *mgr) {
REQUIRE(DNS_LMGR_VALID(mgr));
LOCK(&mgr->lock);
loadmgr_cancel(mgr);
UNLOCK(&mgr->lock);
}
static void
loadmgr_cancel(dns_loadmgr_t *mgr) {
dns_loadctx_t *ctx;
isc_event_t *event;
for (ctx = ISC_LIST_HEAD(mgr->list); ctx != NULL; ) {
ISC_LIST_UNLINK(mgr->list, ctx, link);
event = &ctx->event;
event->ev_attributes |= ISC_EVENTATTR_CANCELED;
isc_task_send(ctx->task, &event);
}
}
void
dns_loadctx_cancel(dns_loadctx_t *ctx) {
isc_event_t *event;
REQUIRE(DNS_LCTX_VALID(ctx));
LOCK(&ctx->lock);
ctx->canceled = ISC_TRUE;
/*
* If we are queued to be run dequeue.
*/
if (ctx->loadmgr != NULL && ISC_LINK_LINKED(ctx, link)) {
LOCK(&ctx->loadmgr->lock);
ISC_LIST_UNLINK(ctx->loadmgr->list, ctx, link);
UNLOCK(&ctx->loadmgr->lock);
event = &ctx->event;
event->ev_attributes |= ISC_EVENTATTR_CANCELED;
isc_task_send(ctx->task, &event);
}
UNLOCK(&ctx->lock);
}
void
dns_loadmgr_attach(dns_loadmgr_t *source, dns_loadmgr_t **target) {
REQUIRE(DNS_LMGR_VALID(source));
REQUIRE(target != NULL && *target == NULL);
LOCK(&source->lock);
INSIST(source->erefs != 0);
source->erefs++;
INSIST(source->erefs != 0); /* Overflow? */
UNLOCK(&source->lock);
*target = source;
}
void
dns_loadmgr_detach(dns_loadmgr_t **mgrp) {
dns_loadmgr_t *mgr;
isc_boolean_t destroy = ISC_FALSE;
REQUIRE(mgrp != NULL);
mgr = *mgrp;
REQUIRE(DNS_LMGR_VALID(mgr));
mgrp = NULL;
LOCK(&mgr->lock);
INSIST(mgr->erefs != 0);
mgr->erefs--;
if (mgr->erefs == 0) {
if (mgr->irefs == 0)
destroy = ISC_TRUE;
else
loadmgr_cancel(mgr);
}
UNLOCK(&mgr->lock);
if (destroy)
loadmgr_destroy(mgr);
}
static void
loadmgr_iattach(dns_loadmgr_t *source, dns_loadmgr_t **target) {
REQUIRE(DNS_LMGR_VALID(source));
REQUIRE(target != NULL && *target == NULL);
LOCK(&source->lock);
source->irefs++;
INSIST(source->irefs != 0); /* Overflow? */
UNLOCK(&source->lock);
*target = source;
}
static void
loadmgr_idetach(dns_loadmgr_t **mgrp) {
dns_loadmgr_t *mgr;
isc_boolean_t destroy = ISC_FALSE;
REQUIRE(mgrp != NULL);
mgr = *mgrp;
REQUIRE(DNS_LMGR_VALID(mgr));
mgrp = NULL;
LOCK(&mgr->lock);
INSIST(mgr->irefs != 0);
mgr->irefs--;
if (mgr->erefs == 0 && mgr->irefs == 0)
destroy = ISC_TRUE;
UNLOCK(&mgr->lock);
if (destroy)
loadmgr_destroy(mgr);
}
static void
loadmgr_destroy(dns_loadmgr_t *mgr) {
INSIST(ISC_LIST_EMPTY(mgr->list));
mgr->magic = 0;
DESTROYLOCK(&mgr->lock);
isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
}