diff options
author | Ondřej Surý <ondrej@sury.org> | 2012-04-13 17:14:49 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2012-04-13 17:14:49 +0200 |
commit | c5e123fb66dfd412a0d89293f893871f9a2e7d12 (patch) | |
tree | e4351340a850ae861ce99a4e7824f2f1bd0660a6 /src | |
parent | b5c64fe14e2b779a715756d47d7d4c7e8e5729ea (diff) | |
download | knot-c5e123fb66dfd412a0d89293f893871f9a2e7d12.tar.gz |
Imported Upstream version 1.0.2upstream/1.0.2
Diffstat (limited to 'src')
60 files changed, 3072 insertions, 1543 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index e73b2bf..a1bb196 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -217,12 +217,12 @@ libknot_la_SOURCES = \ libknots_la_SOURCES = \ common/slab/slab.c \ - common/slab/malloc.c \ common/slab/slab.h \ - common/slab/malloc.h \ common/libtap/tap.c \ common/libtap/tap.h \ common/libtap/tap_unit.h \ + common/mempattern.h \ + common/mempattern.c \ common/lists.c \ common/base32.c \ common/lists.h \ @@ -265,7 +265,9 @@ libknots_la_SOURCES = \ common/fdset_kqueue.h \ common/fdset_kqueue.c \ common/fdset_epoll.h \ - common/fdset_epoll.c + common/fdset_epoll.c \ + common/log.c \ + common/log.h libknotd_la_SOURCES = \ knot/stat/gatherer.c \ @@ -273,8 +275,6 @@ libknotd_la_SOURCES = \ knot/stat/gatherer.h \ knot/stat/stat.h \ knot/common.h \ - knot/other/log.c \ - knot/other/log.h \ knot/other/debug.h \ knot/other/error.h \ knot/other/error.c \ diff --git a/src/Makefile.in b/src/Makefile.in index f2d122c..bc8db39 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -69,7 +69,7 @@ am_libknot_la_OBJECTS = libknot_error.lo utils.lo debug.lo conv.lo \ tsig-op.lo libknot_la_OBJECTS = $(am_libknot_la_OBJECTS) libknotd_la_DEPENDENCIES = libknot.la libknots.la @LIBOBJS@ -am_libknotd_la_OBJECTS = gatherer.lo stat.lo log.lo error.lo \ +am_libknotd_la_OBJECTS = gatherer.lo stat.lo error.lo \ libknotd_la-cf-parse.lo libknotd_la-cf-lex.lo conf.lo \ logconf.lo process.lo dthreads.lo journal.lo socket.lo \ server.lo udp-handler.lo tcp-handler.lo xfr-handler.lo \ @@ -77,11 +77,11 @@ am_libknotd_la_OBJECTS = gatherer.lo stat.lo log.lo error.lo \ zone-dump-text.lo libknotd_la_OBJECTS = $(am_libknotd_la_OBJECTS) libknots_la_DEPENDENCIES = @LIBOBJS@ -am_libknots_la_OBJECTS = slab.lo malloc.lo tap.lo lists.lo base32.lo \ - print.lo dynamic-array.lo skip-list.lo base32hex.lo \ +am_libknots_la_OBJECTS = slab.lo tap.lo mempattern.lo lists.lo \ + base32.lo print.lo dynamic-array.lo skip-list.lo base32hex.lo \ general-tree.lo evqueue.lo evsched.lo acl.lo sockaddr.lo \ crc.lo ref.lo errors.lo dSFMT.lo prng.lo fdset.lo \ - fdset_poll.lo fdset_kqueue.lo fdset_epoll.lo + fdset_poll.lo fdset_kqueue.lo fdset_epoll.lo log.lo libknots_la_OBJECTS = $(am_libknots_la_OBJECTS) am__installdirs = "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(man8dir)" @@ -220,7 +220,6 @@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -248,7 +247,6 @@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ @@ -277,7 +275,6 @@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ @@ -310,6 +307,7 @@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ @@ -540,12 +538,12 @@ libknot_la_SOURCES = \ libknots_la_SOURCES = \ common/slab/slab.c \ - common/slab/malloc.c \ common/slab/slab.h \ - common/slab/malloc.h \ common/libtap/tap.c \ common/libtap/tap.h \ common/libtap/tap_unit.h \ + common/mempattern.h \ + common/mempattern.c \ common/lists.c \ common/base32.c \ common/lists.h \ @@ -588,7 +586,9 @@ libknots_la_SOURCES = \ common/fdset_kqueue.h \ common/fdset_kqueue.c \ common/fdset_epoll.h \ - common/fdset_epoll.c + common/fdset_epoll.c \ + common/log.c \ + common/log.h libknotd_la_SOURCES = \ knot/stat/gatherer.c \ @@ -596,8 +596,6 @@ libknotd_la_SOURCES = \ knot/stat/gatherer.h \ knot/stat/stat.h \ knot/common.h \ - knot/other/log.c \ - knot/other/log.h \ knot/other/debug.h \ knot/other/error.h \ knot/other/error.c \ @@ -892,7 +890,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logconf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mempattern.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/name-server.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node_tests.Po@am__quote@ @@ -1203,13 +1201,6 @@ stat.lo: knot/stat/stat.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o stat.lo `test -f 'knot/stat/stat.c' || echo '$(srcdir)/'`knot/stat/stat.c -log.lo: knot/other/log.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT log.lo -MD -MP -MF $(DEPDIR)/log.Tpo -c -o log.lo `test -f 'knot/other/log.c' || echo '$(srcdir)/'`knot/other/log.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/log.Tpo $(DEPDIR)/log.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='knot/other/log.c' object='log.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o log.lo `test -f 'knot/other/log.c' || echo '$(srcdir)/'`knot/other/log.c - error.lo: knot/other/error.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT error.lo -MD -MP -MF $(DEPDIR)/error.Tpo -c -o error.lo `test -f 'knot/other/error.c' || echo '$(srcdir)/'`knot/other/error.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/error.Tpo $(DEPDIR)/error.Plo @@ -1336,13 +1327,6 @@ slab.lo: common/slab/slab.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o slab.lo `test -f 'common/slab/slab.c' || echo '$(srcdir)/'`common/slab/slab.c -malloc.lo: common/slab/malloc.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT malloc.lo -MD -MP -MF $(DEPDIR)/malloc.Tpo -c -o malloc.lo `test -f 'common/slab/malloc.c' || echo '$(srcdir)/'`common/slab/malloc.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/malloc.Tpo $(DEPDIR)/malloc.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/slab/malloc.c' object='malloc.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o malloc.lo `test -f 'common/slab/malloc.c' || echo '$(srcdir)/'`common/slab/malloc.c - tap.lo: common/libtap/tap.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tap.lo -MD -MP -MF $(DEPDIR)/tap.Tpo -c -o tap.lo `test -f 'common/libtap/tap.c' || echo '$(srcdir)/'`common/libtap/tap.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tap.Tpo $(DEPDIR)/tap.Plo @@ -1350,6 +1334,13 @@ tap.lo: common/libtap/tap.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tap.lo `test -f 'common/libtap/tap.c' || echo '$(srcdir)/'`common/libtap/tap.c +mempattern.lo: common/mempattern.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mempattern.lo -MD -MP -MF $(DEPDIR)/mempattern.Tpo -c -o mempattern.lo `test -f 'common/mempattern.c' || echo '$(srcdir)/'`common/mempattern.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mempattern.Tpo $(DEPDIR)/mempattern.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/mempattern.c' object='mempattern.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mempattern.lo `test -f 'common/mempattern.c' || echo '$(srcdir)/'`common/mempattern.c + lists.lo: common/lists.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lists.lo -MD -MP -MF $(DEPDIR)/lists.Tpo -c -o lists.lo `test -f 'common/lists.c' || echo '$(srcdir)/'`common/lists.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/lists.Tpo $(DEPDIR)/lists.Plo @@ -1490,6 +1481,13 @@ fdset_epoll.lo: common/fdset_epoll.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fdset_epoll.lo `test -f 'common/fdset_epoll.c' || echo '$(srcdir)/'`common/fdset_epoll.c +log.lo: common/log.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT log.lo -MD -MP -MF $(DEPDIR)/log.Tpo -c -o log.lo `test -f 'common/log.c' || echo '$(srcdir)/'`common/log.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/log.Tpo $(DEPDIR)/log.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='common/log.c' object='log.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o log.lo `test -f 'common/log.c' || echo '$(srcdir)/'`common/log.c + zcompile_main.o: zcompile/zcompile_main.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zcompile_main.o -MD -MP -MF $(DEPDIR)/zcompile_main.Tpo -c -o zcompile_main.o `test -f 'zcompile/zcompile_main.c' || echo '$(srcdir)/'`zcompile/zcompile_main.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/zcompile_main.Tpo $(DEPDIR)/zcompile_main.Po diff --git a/src/common/acl.c b/src/common/acl.c index d739319..a3cabd4 100644 --- a/src/common/acl.c +++ b/src/common/acl.c @@ -52,34 +52,29 @@ static int acl_compare(void *k1, void *k2) } /* Compare integers if IPv4. */ - if (a1->len == sizeof(struct sockaddr_in)) { + if (a1->family == AF_INET) { /* Compute mask .*/ uint32_t mask = acl_fill_mask32(a1->prefix); /* Compare address. */ - ldiff = (int)((acl_sa_ipv4(a1) & mask) - (acl_sa_ipv4(a2) & mask)); - if (ldiff < 0) { - return -1; - } else if (ldiff > 0) { - return 1; - } else { - return 0; - } - + int cmp1 = (acl_sa_ipv4(a1) & mask); + int cmp2 = (acl_sa_ipv4(a2) & mask); + if (cmp1 > cmp2) return 1; + if (cmp1 < cmp2) return -1; return 0; } /* IPv6 matching. */ #ifndef DISABLE_IPV6 - if (a1->len == sizeof(struct sockaddr_in6)) { + if (a1->family == AF_INET6) { /* Get mask .*/ short chunk = a1->prefix; /* Compare address by 32bit chunks. */ - uint32_t* a1p = (uint32_t*)&a1->addr6.sin6_addr; - uint32_t* a2p = (uint32_t*)&a2->addr6.sin6_addr; + uint32_t* a1p = (uint32_t *)(&a1->addr6.sin6_addr); + uint32_t* a2p = (uint32_t *)(&a2->addr6.sin6_addr); /* Mask 0 = 0 bits to compare from LO->HO (in big-endian). * Mask 128 = 128 bits to compare. @@ -93,12 +88,10 @@ static int acl_compare(void *k1, void *k2) chunk = 0; } - ldiff = (*(a1p++) & mask) ^ (*(a2p++) & mask); - if (ldiff < 0) { - return -1; - } else if (ldiff > 0) { - return 1; - } + int cmp1 = (*(a1p++) & mask); + int cmp2 = (*(a2p++) & mask); + if (cmp1 > cmp2) return 1; + if (cmp1 < cmp2) return -1; } return 0; @@ -157,9 +150,8 @@ void acl_delete(acl_t **acl) } /* Truncate rules. */ - if (acl_truncate(*acl) != ACL_ACCEPT) { - return; - } + skip_destroy_list(&(*acl)->rules, 0, free); + skip_destroy_list(&(*acl)->rules_pref, 0, free); /* Free ACL. */ free(*acl); @@ -227,6 +219,11 @@ int acl_truncate(acl_t *acl) /* Destroy all rules. */ skip_destroy_list(&acl->rules, 0, free); skip_destroy_list(&acl->rules_pref, 0, free); + acl->rules = skip_create_list(acl_compare); + acl->rules_pref = skip_create_list(acl_compare); + if (acl->rules == NULL || acl->rules_pref == NULL) { + return ACL_ERROR; + } return ACL_ACCEPT; } diff --git a/src/common/fdset.c b/src/common/fdset.c index d674d4a..c915e01 100644 --- a/src/common/fdset.c +++ b/src/common/fdset.c @@ -103,10 +103,10 @@ void __attribute__ ((constructor)) fdset_init() * \retval 0 if a == b * \retval 1 if a > b */ -static int fdset_compare(void *a, void *b) +static inline int fdset_compare(void *a, void *b) { - if ((size_t)a < (size_t)b) return -1; - if ((size_t)a > (size_t)b) return 1; + if (a > b) return 1; + if (a < b) return -1; return 0; } diff --git a/src/common/fdset.h b/src/common/fdset.h index ead4d5b..4fbd9bc 100644 --- a/src/common/fdset.h +++ b/src/common/fdset.h @@ -34,6 +34,7 @@ #include <stddef.h> #include "skip-list.h" +#include "mempattern.h" /*! \brief Waiting for completion constants. */ enum fdset_wait_t { diff --git a/src/common/fdset_epoll.c b/src/common/fdset_epoll.c index dbd803f..f6f42f0 100644 --- a/src/common/fdset_epoll.c +++ b/src/common/fdset_epoll.c @@ -27,7 +27,6 @@ #include "skip-list.h" #define OS_FDS_CHUNKSIZE 8 /*!< Number of pollfd structs in a chunk. */ -#define OS_FDS_KEEPCHUNKS 32 /*!< Will attempt to free memory when reached. */ struct fdset_t { fdset_base_t _base; @@ -41,22 +40,20 @@ struct fdset_t { fdset_t *fdset_epoll_new() { fdset_t *set = malloc(sizeof(fdset_t)); - if (!set) { - return NULL; + if (set) { + /* Blank memory. */ + memset(set, 0, sizeof(fdset_t)); + + /* Create epoll fd. */ + set->epfd = epoll_create(OS_FDS_CHUNKSIZE); } - - /* Blank memory. */ - memset(set, 0, sizeof(fdset_t)); - - /* Create epoll fd. */ - set->epfd = epoll_create(OS_FDS_CHUNKSIZE); - + return set; } int fdset_epoll_destroy(fdset_t * fdset) { - if(!fdset) { + if(fdset == NULL) { return -1; } @@ -71,27 +68,14 @@ int fdset_epoll_destroy(fdset_t * fdset) int fdset_epoll_add(fdset_t *fdset, int fd, int events) { - if (!fdset || fd < 0 || events <= 0) { + if (fdset == NULL || fd < 0 || events <= 0) { return -1; } /* Realloc needed. */ - if (fdset->nfds == fdset->reserved) { - const size_t chunk = OS_FDS_CHUNKSIZE; - const size_t nsize = (fdset->reserved + chunk) * - sizeof(struct epoll_event); - struct epoll_event *events_n = malloc(nsize); - if (!events_n) { - return -1; - } - - /* Clear and copy old fdset data. */ - memset(events_n, 0, nsize); - memcpy(events_n, fdset->events, - fdset->nfds * sizeof(struct epoll_event)); - free(fdset->events); - fdset->events = events_n; - fdset->reserved += chunk; + if (mreserve((char **)&fdset->events, sizeof(struct epoll_event), + fdset->nfds + 1, OS_FDS_CHUNKSIZE, &fdset->reserved) < 0) { + return -1; } /* Add to epoll set. */ @@ -109,7 +93,7 @@ int fdset_epoll_add(fdset_t *fdset, int fd, int events) int fdset_epoll_remove(fdset_t *fdset, int fd) { - if (!fdset || fd < 0) { + if (fdset == NULL || fd < 0) { return -1; } @@ -123,13 +107,16 @@ int fdset_epoll_remove(fdset_t *fdset, int fd) /* Overwrite current item. */ --fdset->nfds; - /*! \todo Return memory if unused (issue #1582). */ + /* Trim excessive memory if possible (retval is not interesting). */ + mreserve((char **)&fdset->events, sizeof(struct epoll_event), fdset->nfds, + OS_FDS_CHUNKSIZE, &fdset->reserved); + return 0; } int fdset_epoll_wait(fdset_t *fdset, int timeout) { - if (!fdset || fdset->nfds < 1 || !fdset->events) { + if (fdset == NULL || fdset->nfds < 1 || fdset->events == NULL) { return -1; } @@ -149,7 +136,7 @@ int fdset_epoll_wait(fdset_t *fdset, int timeout) int fdset_epoll_begin(fdset_t *fdset, fdset_it_t *it) { - if (!fdset || !it) { + if (fdset == NULL || it == NULL) { return -1; } @@ -160,7 +147,7 @@ int fdset_epoll_begin(fdset_t *fdset, fdset_it_t *it) int fdset_epoll_end(fdset_t *fdset, fdset_it_t *it) { - if (!fdset || !it || fdset->nfds < 1) { + if (fdset == NULL || it == NULL || fdset->nfds < 1) { return -1; } @@ -181,7 +168,7 @@ int fdset_epoll_end(fdset_t *fdset, fdset_it_t *it) int fdset_epoll_next(fdset_t *fdset, fdset_it_t *it) { - if (!fdset || !it || fdset->nfds < 1) { + if (fdset == NULL || it == NULL || fdset->nfds < 1) { return -1; } diff --git a/src/common/fdset_kqueue.c b/src/common/fdset_kqueue.c index b9f639d..2c7dd52 100644 --- a/src/common/fdset_kqueue.c +++ b/src/common/fdset_kqueue.c @@ -37,32 +37,31 @@ struct fdset_t { struct kevent *revents; size_t nfds; size_t reserved; + size_t rreserved; size_t polled; }; fdset_t *fdset_kqueue_new() { fdset_t *set = malloc(sizeof(fdset_t)); - if (!set) { - return 0; - } - - /* Blank memory. */ - memset(set, 0, sizeof(fdset_t)); - - /* Create kqueue fd. */ - set->kq = kqueue(); - if (set->kq < 0) { - free(set); - set = 0; + if (set) { + /* Blank memory. */ + memset(set, 0, sizeof(fdset_t)); + + /* Create kqueue fd. */ + set->kq = kqueue(); + if (set->kq < 0) { + free(set); + set = 0; + } } - + return set; } int fdset_kqueue_destroy(fdset_t * fdset) { - if(!fdset) { + if(fdset == NULL) { return -1; } @@ -76,45 +75,20 @@ int fdset_kqueue_destroy(fdset_t * fdset) return 0; } -int fdset_kqueue_realloc(struct kevent **old, size_t oldsize, size_t nsize) -{ - void *nmem = malloc(nsize); - if (!nmem) { - return -1; - } - - /* Clear and copy old fdset data. */ - memset(nmem, 0, nsize); - if (oldsize > 0) { - memcpy(nmem, *old, oldsize); - free(*old); - } - - *old = nmem; - return 0; -} - int fdset_kqueue_add(fdset_t *fdset, int fd, int events) { - if (!fdset || fd < 0 || events <= 0) { + if (fdset == NULL || fd < 0 || events <= 0) { return -1; } /* Realloc needed. */ - if (fdset->nfds == fdset->reserved) { - size_t chunk = OS_FDS_CHUNKSIZE; - size_t nsize = (fdset->reserved + chunk) * - sizeof(struct kevent); - size_t oldsize = fdset->nfds * sizeof(struct kevent); - - if (fdset_kqueue_realloc(&fdset->events, oldsize, nsize) < 0) { - return -1; - } - - if (fdset_kqueue_realloc(&fdset->revents, oldsize, nsize) < 0) { - return -1; - } - + int ret = 0; + ret += mreserve((char **)&fdset->events, sizeof(struct kevent), + fdset->nfds + 1, OS_FDS_CHUNKSIZE, &fdset->reserved); + ret += mreserve((char **)&fdset->revents, sizeof(struct kevent), + fdset->nfds + 1, OS_FDS_CHUNKSIZE, &fdset->rreserved); + if (ret != 0) { + return ret; } /* Add to kqueue set. */ @@ -128,7 +102,7 @@ int fdset_kqueue_add(fdset_t *fdset, int fd, int events) int fdset_kqueue_remove(fdset_t *fdset, int fd) { - if (!fdset || fd < 0) { + if (fdset == NULL || fd < 0) { return -1; } @@ -153,16 +127,35 @@ int fdset_kqueue_remove(fdset_t *fdset, int fd) size_t remaining = ((fdset->nfds - pos) - 1) * sizeof(struct kevent); memmove(fdset->events + pos, fdset->events + (pos + 1), remaining); + /* Attempt to remove from revents set. */ + pos = -1; + for (int i = 0; i < fdset->nfds; ++i) { + if (fdset->events[i].ident == fd) { + pos = i; + break; + } + } + if (pos >= 0) { + size_t remaining = ((fdset->nfds - pos) - 1) * sizeof(struct kevent); + memmove(fdset->revents + pos, fdset->revents + (pos + 1), remaining); + } + + /* Overwrite current item. */ --fdset->nfds; - /*! \todo Return memory if unused (issue #1582). */ + /* Trim excessive memory if possible (retval is not interesting). */ + mreserve((char **)&fdset->events, sizeof(struct kevent), + fdset->nfds, OS_FDS_CHUNKSIZE, &fdset->reserved); + mreserve((char **)&fdset->revents, sizeof(struct kevent), + fdset->nfds, OS_FDS_CHUNKSIZE, &fdset->rreserved); + return 0; } int fdset_kqueue_wait(fdset_t *fdset, int timeout) { - if (!fdset || fdset->nfds < 1 || !fdset->events) { + if (fdset == NULL || fdset->nfds < 1 || fdset->events == NULL) { return -1; } @@ -196,7 +189,7 @@ int fdset_kqueue_wait(fdset_t *fdset, int timeout) int fdset_kqueue_begin(fdset_t *fdset, fdset_it_t *it) { - if (!fdset || !it) { + if (fdset == NULL || it == NULL) { return -1; } @@ -207,7 +200,7 @@ int fdset_kqueue_begin(fdset_t *fdset, fdset_it_t *it) int fdset_kqueue_end(fdset_t *fdset, fdset_it_t *it) { - if (!fdset || !it || fdset->nfds < 1) { + if (fdset == NULL || it == NULL || fdset->nfds < 1) { return -1; } @@ -228,7 +221,7 @@ int fdset_kqueue_end(fdset_t *fdset, fdset_it_t *it) int fdset_kqueue_next(fdset_t *fdset, fdset_it_t *it) { - if (!fdset || !it || fdset->nfds < 1) { + if (fdset == NULL || it == NULL || fdset->nfds < 1) { return -1; } diff --git a/src/common/fdset_poll.c b/src/common/fdset_poll.c index 02ed8d4..19804f5 100644 --- a/src/common/fdset_poll.c +++ b/src/common/fdset_poll.c @@ -26,7 +26,6 @@ #include "common/fdset_poll.h" #define OS_FDS_CHUNKSIZE 8 /*!< Number of pollfd structs in a chunk. */ -#define OS_FDS_KEEPCHUNKS 32 /*!< Will attempt to free memory when reached. */ struct fdset_t { fdset_base_t _base; @@ -40,18 +39,16 @@ struct fdset_t { fdset_t *fdset_poll_new() { fdset_t *set = malloc(sizeof(fdset_t)); - if (!set) { - return 0; + if (set != NULL) { + memset(set, 0, sizeof(fdset_t)); } - /* Blank memory. */ - memset(set, 0, sizeof(fdset_t)); return set; } int fdset_poll_destroy(fdset_t * fdset) { - if(!fdset) { + if(fdset == NULL) { return -1; } @@ -63,29 +60,18 @@ int fdset_poll_destroy(fdset_t * fdset) int fdset_poll_add(fdset_t *fdset, int fd, int events) { - if (!fdset || fd < 0 || events <= 0) { + if (fdset == NULL || fd < 0 || events <= 0) { return -1; } /* Realloc needed. */ - if (fdset->nfds == fdset->reserved) { - const size_t chunk = OS_FDS_CHUNKSIZE; - const size_t nsize = sizeof(struct pollfd) * (fdset->reserved + chunk); - struct pollfd *fds_n = malloc(nsize); - if (!fds_n) { - return -1; - } - - /* Clear and copy old fdset data. */ - memset(fds_n, 0, nsize); - memcpy(fds_n, fdset->fds, fdset->nfds * sizeof(struct pollfd)); - free(fdset->fds); - fdset->fds = fds_n; - fdset->reserved += chunk; + if (mreserve((char **)&fdset->fds, sizeof(struct pollfd), + fdset->nfds + 1, OS_FDS_CHUNKSIZE, &fdset->reserved) < 0) { + return -1; } /* Append. */ - int nid = fdset->nfds++; + int nid = fdset->nfds++;; fdset->fds[nid].fd = fd; fdset->fds[nid].events = POLLIN; return 0; @@ -93,7 +79,7 @@ int fdset_poll_add(fdset_t *fdset, int fd, int events) int fdset_poll_remove(fdset_t *fdset, int fd) { - if (!fdset || fd < 0) { + if (fdset == NULL || fd < 0) { return -1; } @@ -118,13 +104,16 @@ int fdset_poll_remove(fdset_t *fdset, int fd) memmove(fdset->fds + pos, fdset->fds + (pos + 1), remaining); --fdset->nfds; - /*! \todo Return memory if unused (issue #1582). */ + /* Trim excessive memory if possible (retval is not interesting). */ + mreserve((char **)&fdset->fds, sizeof(struct pollfd), fdset->nfds, + OS_FDS_CHUNKSIZE, &fdset->reserved); + return 0; } int fdset_poll_wait(fdset_t *fdset, int timeout) { - if (!fdset || fdset->nfds < 1 || !fdset->fds) { + if (fdset == NULL || fdset->nfds < 1 || fdset->fds == NULL) { return -1; } @@ -146,7 +135,7 @@ int fdset_poll_wait(fdset_t *fdset, int timeout) int fdset_poll_begin(fdset_t *fdset, fdset_it_t *it) { - if (!fdset || !it) { + if (fdset == NULL || it == NULL) { return -1; } @@ -157,7 +146,7 @@ int fdset_poll_begin(fdset_t *fdset, fdset_it_t *it) int fdset_poll_end(fdset_t *fdset, fdset_it_t *it) { - if (!fdset || !it || fdset->nfds < 1) { + if (fdset == NULL || it == NULL || fdset->nfds < 1) { return -1; } @@ -186,7 +175,7 @@ int fdset_poll_end(fdset_t *fdset, fdset_it_t *it) int fdset_poll_next(fdset_t *fdset, fdset_it_t *it) { - if (!fdset || !it || fdset->nfds < 1) { + if (fdset == NULL || it == NULL || fdset->nfds < 1) { return -1; } diff --git a/src/knot/other/log.c b/src/common/log.c index 488763d..6d77ccb 100644 --- a/src/knot/other/log.c +++ b/src/common/log.c @@ -20,10 +20,10 @@ #include <string.h> #include <stdlib.h> +#include "common/log.h" +#include "common/lists.h" #include "knot/common.h" #include "knot/other/error.h" -#include "knot/other/log.h" -#include "common/lists.h" #include "knot/conf/conf.h" /*! Log source table. */ @@ -208,6 +208,20 @@ static int _log_msg(logsrc_t src, int level, const char *msg) // Convert level to mask level = LOG_MASK(level); + + /* Prefix date and time. */ + char tstr[128] = {0}; + int tlen = 0; + time_t t = time(NULL); + struct tm *lt = localtime(&t); + if (lt != NULL) { + tlen = strftime(tstr, sizeof(tstr) - 1, + "%d-%m-%Y %H:%M:%S", lt); + if (tlen > 0) { + tstr[tlen] = ' '; + tstr[tlen + 1] = '\0'; + } + } // Log streams for (int i = LOGT_STDERR; i < LOGT_FILE + LOG_FDS_OPEN; ++i) { @@ -224,7 +238,7 @@ static int _log_msg(logsrc_t src, int level, const char *msg) } // Print - ret = fprintf(stream, "%s", msg); + ret = fprintf(stream, "%s%s", tstr, msg); if (stream == stdout) { fflush(stream); } @@ -248,15 +262,15 @@ int log_msg(logsrc_t src, int level, const char *msg, ...) /* Prefix error level. */ const char *prefix = ""; switch (level) { - case LOG_DEBUG: break; - case LOG_INFO: break; - case LOG_NOTICE: prefix = "notice: "; break; - case LOG_WARNING: prefix = "warning: "; break; - case LOG_ERR: prefix = "error: "; break; - case LOG_FATAL: prefix = "fatal: "; break; + case LOG_DEBUG: prefix = "[debug] "; break; + case LOG_INFO: prefix = ""; break; + case LOG_NOTICE: prefix = "[notice] "; break; + case LOG_WARNING: prefix = "[warning] "; break; + case LOG_ERR: prefix = "[error] "; break; + case LOG_FATAL: prefix = "[fatal] "; break; default: break; } - + /* Prepend prefix. */ int plen = strlen(prefix); if (plen > buflen) { diff --git a/src/knot/other/log.h b/src/common/log.h index 305020c..305020c 100644 --- a/src/knot/other/log.h +++ b/src/common/log.h diff --git a/src/common/slab/malloc.c b/src/common/mempattern.c index ec5a68d..5982e18 100644 --- a/src/common/slab/malloc.c +++ b/src/common/mempattern.c @@ -14,17 +14,37 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <config.h> -/* - * Skip unit if not debugging memory. - */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/resource.h> +#include <config.h> #include "common/slab/alloc-common.h" + +int mreserve(char **p, size_t tlen, size_t min, size_t allow, size_t *reserved) +{ + /* Trim excessive memory if possible. */ + size_t maxlen = min + allow; + if (maxlen < min) { + return -2; /* size_t overflow */ + } + + /* Meet target size but trim excessive amounts. */ + if (*reserved < min || *reserved > maxlen) { + void *trimmed = realloc(*p, maxlen * tlen); + if (trimmed != NULL) { + *p = trimmed; + *reserved = maxlen; + } else { + return -1; + } + } + + return 0; +} + #ifdef MEM_DEBUG /* * ((destructor)) attribute executes this function after main(). diff --git a/src/common/slab/malloc.h b/src/common/mempattern.h index 8ca9f58..ae1fa78 100644 --- a/src/common/slab/malloc.h +++ b/src/common/mempattern.h @@ -14,7 +14,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ /*! - * \file malloc.h + * \file mempattern.h * * \author Marek Vavrusa <marek.vavrusa@nic.cz> * @@ -27,7 +27,32 @@ #ifndef _KNOTD_COMMON_MALLOC_H_ #define _KNOTD_COMMON_MALLOC_H_ -#include <stdlib.h> +/*! + * \brief Reserve new or trim excessive memory. + * + * \param p Double-pointer to memory region. + * \param tlen Memory unit (f.e. sizeof(int) for int* array) + * \param min Minimum number of items required. + * \param allow Maximum extra items to keep (for trimming). + * \param reserved Pointer to number of already reserved items. + * + * \note Example usage: + * char *buf = NULL; size_t len = 0; + * if (mreserve(&buf, sizeof(char), 6, 0, &len) == 0) { + * memcpy(buf, "hello", strlen("hello"); + * if (mreserve(&buf, sizeof(char), 20, 0, &len) == 0) { + * strncat(buf, "!", 1); + * mreserve(&buf, sizeof(char), strlen("hello!")+1, 0, &len); + * } + * } + * free(buf); + * + * \retval 0 on success. + * \retval -1 on error. + * + * \note Memory region will be left untouched if function fails. + */ +int mreserve(char **p, size_t tlen, size_t min, size_t allow, size_t *reserved); /*! \brief Print usage statistics. * diff --git a/src/common/sockaddr.c b/src/common/sockaddr.c index 48551bc..b4e75ee 100644 --- a/src/common/sockaddr.c +++ b/src/common/sockaddr.c @@ -49,6 +49,20 @@ int sockaddr_init(sockaddr_t *addr, int af) return sockaddr_update(addr); } +int sockaddr_isvalid(sockaddr_t *addr) +{ + return addr && addr->family > -1; +} + +int sockaddr_copy(sockaddr_t *dst, const sockaddr_t *src) +{ + if (memcpy(dst, src, sizeof(sockaddr_t)) != NULL) { + return sockaddr_update(dst); + } + + return -1; +} + int sockaddr_update(sockaddr_t *addr) { /* Update internal pointer. */ @@ -117,7 +131,7 @@ int sockaddr_setprefix(sockaddr_t *dst, int prefix) return dst->prefix = prefix; } -int sockaddr_tostr(sockaddr_t *addr, char *dst, size_t size) +int sockaddr_tostr(const sockaddr_t *addr, char *dst, size_t size) { if (!addr || !dst || size == 0) { return -1; @@ -159,7 +173,7 @@ int sockaddr_tostr(sockaddr_t *addr, char *dst, size_t size) return 0; } -int sockaddr_portnum(sockaddr_t *addr) +int sockaddr_portnum(const sockaddr_t *addr) { if (!addr) { return -1; diff --git a/src/common/sockaddr.h b/src/common/sockaddr.h index b2725c0..52e621c 100644 --- a/src/common/sockaddr.h +++ b/src/common/sockaddr.h @@ -74,6 +74,16 @@ typedef struct sockaddr_t { int sockaddr_init(sockaddr_t *addr, int af); /*! + * \brief Return true value if sockaddr is valid. + * + * \param addr Socket address structure. + * + * \retval true on succes. + * \retval false otherwise. + */ +int sockaddr_isvalid(sockaddr_t *addr); + +/*! * \brief Update internal pointers according to length. * * \param addr Socket address structure. @@ -84,6 +94,17 @@ int sockaddr_init(sockaddr_t *addr, int af); int sockaddr_update(sockaddr_t *addr); /*! + * \brief Copy socket address structure. + * + * \param dst Target address structure. + * \param src Source address structure. + * + * \retval 0 on success. + * \retval -1 on error. + */ +int sockaddr_copy(sockaddr_t *dst, const sockaddr_t *src); + +/*! * \brief Set address and port. * * \param dst Target address structure. @@ -119,7 +140,7 @@ int sockaddr_setprefix(sockaddr_t *dst, int prefix); * \retval 0 on success. * \retval -1 on invalid parameters. */ -int sockaddr_tostr(sockaddr_t *addr, char *dst, size_t size); +int sockaddr_tostr(const sockaddr_t *addr, char *dst, size_t size); /*! * \brief Return port number from address. @@ -129,7 +150,7 @@ int sockaddr_tostr(sockaddr_t *addr, char *dst, size_t size); * \retval Port number on success. * \retval -1 on errors. */ -int sockaddr_portnum(sockaddr_t *addr); +int sockaddr_portnum(const sockaddr_t *addr); #endif /* _KNOTD_SOCKADDR_H_ */ diff --git a/src/config.h.in b/src/config.h.in index dfcea86..905e327 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -63,6 +63,9 @@ /* Define to 1 if you have the <limits.h> header file. */ #undef HAVE_LIMITS_H +/* Define to 1 if you have the `madvise' function. */ +#undef HAVE_MADVISE + /* Define to 1 if you have the <malloc.h> header file. */ #undef HAVE_MALLOC_H diff --git a/src/knot/common.h b/src/knot/common.h index 027962a..c321b94 100644 --- a/src/knot/common.h +++ b/src/knot/common.h @@ -79,7 +79,7 @@ typedef unsigned int uint; /*!< \brief Unsigned. */ #include "common/latency.h" #include "common/print.h" -#include "knot/other/log.h" +#include "common/log.h" #include "knot/other/debug.h" /*! \brief Eliminate compiler warning with unused parameters. */ diff --git a/src/knot/conf/cf-lex.l b/src/knot/conf/cf-lex.l index 6683edc..dfd0ac7 100644 --- a/src/knot/conf/cf-lex.l +++ b/src/knot/conf/cf-lex.l @@ -15,7 +15,7 @@ #include "common/sockaddr.h" #include "knot/conf/conf.h" -#include "knot/other/log.h" +#include "common/log.h" #include "libknotd_la-cf-parse.h" /* Automake generated header. */ /* Imported symbols. */ @@ -65,7 +65,6 @@ BLANK [ \t\n] %% \#.*\n /* Ignore comments */; {BLANK}+ /* Ignore whitespace */; -: /* Optional : in assignments. */; [\!\$\%\^\&\*\(\)\/\+\-\@\{\}\;\,] { return yytext[0]; } system { lval.t = yytext; return SYSTEM; } identity { lval.t = yytext; return IDENTITY; } @@ -255,6 +254,7 @@ hmac-sha512 { lval.alg = KNOT_TSIG_ALG_HMAC_SHA512; return TSIG_ALGO_NAME; } return TEXT /* Last resort, alphanumeric word. */; } +: /* Optional : in assignments. */; <<EOF>> return END; %% diff --git a/src/knot/conf/cf-parse.y b/src/knot/conf/cf-parse.y index c7efa10..4981606 100644 --- a/src/knot/conf/cf-parse.y +++ b/src/knot/conf/cf-parse.y @@ -52,6 +52,7 @@ static void conf_start_remote(void *scanner, char *remote) memset(this_remote, 0, sizeof(conf_iface_t)); this_remote->name = remote; add_tail(&new_config->remotes, &this_remote->n); + sockaddr_init(&this_remote->via, -1); ++new_config->remotes_count; } @@ -71,7 +72,7 @@ static void conf_remote_set_via(void *scanner, char *item) { snprintf(buf, sizeof(buf), "remote '%s' is not defined", item); cf_error(scanner, buf); } else { - this_remote->via = found; + sockaddr_set(&this_remote->via, found->family, found->address, 0); } } @@ -541,13 +542,17 @@ remote: } free($3.t); } + | remote VIA IPA ';' { + sockaddr_set(&this_remote->via, AF_INET, $3.t, 0); + free($3.t); + } + | remote VIA IPA6 ';' { + sockaddr_set(&this_remote->via, AF_INET6, $3.t, 0); + free($3.t); + } | remote VIA TEXT ';' { - if (this_remote->key != 0) { - cf_error(scanner, "only one 'via' definition is allowed in remote section\n"); - } else { conf_remote_set_via(scanner, $3.t); - } - free($3.t); + free($3.t); } ; diff --git a/src/knot/conf/conf.h b/src/knot/conf/conf.h index 1e6644e..40cd1cc 100644 --- a/src/knot/conf/conf.h +++ b/src/knot/conf/conf.h @@ -37,7 +37,8 @@ #include "libknot/util/descriptor.h" #include "libknot/tsig.h" #include "common/lists.h" -#include "knot/other/log.h" +#include "common/log.h" +#include "common/sockaddr.h" /* Constants. */ #define CONFIG_DEFAULT_PORT 53 @@ -60,7 +61,7 @@ typedef struct conf_iface_t { int port; /*!< Port number for this interface */ int family; /*!< Address family. */ knot_key_t *key; /*!< TSIG key (only valid for remotes). */ - struct conf_iface_t *via; /*!< Used for remotes to specify qry endpoint.*/ + sockaddr_t via; /*!< Used for remotes to specify qry endpoint.*/ } conf_iface_t; /*! diff --git a/src/knot/conf/logconf.c b/src/knot/conf/logconf.c index a57afd9..4d7334f 100644 --- a/src/knot/conf/logconf.c +++ b/src/knot/conf/logconf.c @@ -23,7 +23,7 @@ #include "knot/other/debug.h" #include "knot/conf/logconf.h" #include "knot/conf/conf.h" -#include "knot/other/log.h" +#include "common/log.h" #include "knot/other/error.h" #include "common/lists.h" #include "knot/common.h" diff --git a/src/knot/ctl/knotc_main.c b/src/knot/ctl/knotc_main.c index 814fbc3..436cc5e 100644 --- a/src/knot/ctl/knotc_main.c +++ b/src/knot/ctl/knotc_main.c @@ -71,7 +71,8 @@ void help(int argc, char **argv) " stop Stop %s server (no-op if not running).\n" " restart Stops and then starts %s server.\n" " reload Reload %s configuration and compiled zones.\n" - " running check if server is running.\n" + " running Check if server is running.\n" + " checkconf Check server configuration.\n" "\n" " compile Compile zone file.\n", PACKAGE_NAME, PACKAGE_NAME, PACKAGE_NAME, PACKAGE_NAME); @@ -105,8 +106,7 @@ int check_zone(const char *db, const char* source) break; } - fprintf(stderr, "error: "); - fprintf(stderr, emsg, source); + log_zone_error(emsg, source); return KNOTD_ENOENT; } @@ -161,7 +161,7 @@ pid_t start_cmd(const char *argv[], int argc) execvp(args[0], args); /* Execute failed. */ - fprintf(stderr, "Failed to run executable '%s'\n", args[0]); + log_server_error("Failed to run executable '%s'\n", args[0]); for (int i = 0; i < argc; ++i) { free(args[i]); } @@ -222,23 +222,23 @@ int zctask_wait(knotc_zctask_t *tasks, int count) } if (z == 0) { - fprintf(stderr, "error: Failed to find zone for finished " - "zone compilation process.\n"); + log_server_error("Failed to find zone for finished " + "zone compilation process.\n"); return 1; } /* Evaluate. */ if (!WIFEXITED(rc)) { - fprintf(stderr, "error: Compilation of '%s' " - "failed, process was killed.\n", - z->name); + log_server_error("Compilation of '%s' " + "failed, process was killed.\n", + z->name); return 1; } else { if (rc < 0 || WEXITSTATUS(rc) != 0) { - fprintf(stderr, "error: Compilation of " - "'%s' failed, knot-zcompile " - "return code was '%d'\n", - z->name, WEXITSTATUS(rc)); + log_server_error("Compilation of " + "'%s' failed, knot-zcompile " + "return code was '%d'\n", + z->name, WEXITSTATUS(rc)); return 1; } } @@ -289,7 +289,8 @@ int execute(const char *action, char **argv, int argc, pid_t pid, // Check pidfile for w+ FILE* chkf = fopen(pidfile, "w+"); if (chkf == NULL) { - fprintf(stderr, "control: PID file '%s' is not writeable, refusing to start\n", pidfile); + log_server_error("PID file '%s' is not writeable, " + "refusing to start\n", pidfile); return 1; } else { fclose(chkf); @@ -305,15 +306,15 @@ int execute(const char *action, char **argv, int argc, pid_t pid, // } if (pid > 0 && pid_running(pid)) { - fprintf(stderr, "control: Server PID found, " - "already running.\n"); + log_server_error("Server PID found, " + "already running.\n"); if (!has_flag(flags, F_FORCE)) { return 1; } else { - fprintf(stderr, "control: forcing " - "server start, killing old pid=%ld.\n", - (long)pid); + log_server_info("Forcing server start, " + "killing old pid=%ld.\n", + (long)pid); kill(pid, SIGKILL); pid_remove(pidfile); } @@ -344,7 +345,7 @@ int execute(const char *action, char **argv, int argc, pid_t pid, // Execute command if (has_flag(flags, F_INTERACTIVE)) { - printf("control: Running in interactive mode.\n"); + log_server_info("Running in interactive mode.\n"); fflush(stderr); fflush(stdout); } @@ -358,8 +359,7 @@ int execute(const char *action, char **argv, int argc, pid_t pid, // Wait for finish if (has_flag(flags, F_WAIT) && !has_flag(flags, F_INTERACTIVE)) { if (has_flag(flags, F_VERBOSE)) { - fprintf(stdout, "control: waiting for server " - "to load.\n"); + log_server_info("Waiting for server to load.\n"); } /* Periodically read pidfile and wait for * valid result. */ @@ -379,14 +379,13 @@ int execute(const char *action, char **argv, int argc, pid_t pid, valid_cmd = 1; rc = 0; if (pid <= 0 || !pid_running(pid)) { - fprintf(stderr, "Server PID not found, " - "probably not running.\n"); + log_server_warning("Server PID not found, " + "probably not running.\n"); if (!has_flag(flags, F_FORCE)) { rc = 1; } else { - fprintf(stderr, "control: forcing " - "server stop.\n"); + log_server_info("Forcing server stop.\n"); } } @@ -401,8 +400,8 @@ int execute(const char *action, char **argv, int argc, pid_t pid, // Wait for finish if (rc == 0 && has_flag(flags, F_WAIT)) { if (has_flag(flags, F_VERBOSE)) { - fprintf(stdout, "control: waiting for server " - "to stop.\n"); + log_server_info("Waiting for server " + "to stop.\n"); } /* Periodically read pidfile and wait for * valid result. */ @@ -426,8 +425,8 @@ int execute(const char *action, char **argv, int argc, pid_t pid, break; } if (i == WAITPID_TIMEOUT) { - fprintf(stderr, "Timeout while " - "waiting for the server to finish.\n"); + log_server_error("Timeout while waiting for " + "the server to finish.\n"); //pid_remove(pidfile); break; } else { @@ -436,7 +435,7 @@ int execute(const char *action, char **argv, int argc, pid_t pid, } } - printf("Restarting server.\n"); + log_server_info("Restarting server.\n"); rc = execute("start", argv, argc, -1, flags, jobs, pidfile); } if (strcmp(action, "reload") == 0) { @@ -444,12 +443,11 @@ int execute(const char *action, char **argv, int argc, pid_t pid, // Check PID valid_cmd = 1; if (pid <= 0 || !pid_running(pid)) { - fprintf(stderr, "Server PID not found, " - "probably not running.\n"); + log_server_warning("Server PID not found, " + "probably not running.\n"); if (has_flag(flags, F_FORCE)) { - fprintf(stderr, "control: forcing " - "server stop.\n"); + log_server_info("Forcing server stop.\n"); } else { return 1; } @@ -472,29 +470,33 @@ int execute(const char *action, char **argv, int argc, pid_t pid, // Check PID valid_cmd = 1; if (pid <= 0) { - printf("Server PID not found, " - "probably not running.\n"); + log_server_info("Server PID not found, " + "probably not running.\n"); rc = 1; } else { if (!pid_running(pid)) { - printf("Server PID not found, " - "probably not running.\n"); - fprintf(stderr, - "warning: PID file is stale.\n"); + log_server_info("Server PID not found, " + "probably not running.\n"); + log_server_warning("PID file is stale.\n"); } else { - printf("Server running as PID %ld.\n", - (long)pid); + log_server_info("Server running as PID %ld.\n", + (long)pid); } rc = 0; } } + if (strcmp(action, "checkconf") == 0) { + log_server_info("OK, configuration is valid.\n"); + rc = 0; + valid_cmd = 1; + } if (strcmp(action, "compile") == 0) { // Print job count if (jobs > 1) { - printf("warning: Will attempt to compile %d zones " - "in parallel, this increases memory consumption " - "for large zones.\n", jobs); + log_server_warning("Will attempt to compile %d zones " + "in parallel, this increases memory " + "consumption for large zones.\n", jobs); } // Check zone @@ -515,12 +517,12 @@ int execute(const char *action, char **argv, int argc, pid_t pid, // Check source files and mtime int zone_status = check_zone(zone->db, zone->file); if (zone_status == KNOTD_EOK) { - printf("Zone '%s' is up-to-date.\n", - zone->name); + log_zone_info("Zone '%s' is up-to-date.\n", + zone->name); if (has_flag(flags, F_FORCE)) { - fprintf(stderr, "control: forcing " - "zone recompilation.\n"); + log_zone_info("Forcing zone " + "recompilation.\n"); } else { continue; } @@ -533,7 +535,7 @@ int execute(const char *action, char **argv, int argc, pid_t pid, /* Evaluate space for new task. */ if (running == jobs) { - zctask_wait(tasks, jobs); + rc |= zctask_wait(tasks, jobs); --running; } @@ -549,8 +551,8 @@ int execute(const char *action, char **argv, int argc, pid_t pid, // Execute command if (has_flag(flags, F_VERBOSE)) { - printf("Compiling '%s' as '%s'...\n", - zone->name, zone->db); + log_zone_info("Compiling '%s' as '%s'...\n", + zone->name, zone->db); } fflush(stdout); fflush(stderr); @@ -570,13 +572,13 @@ int execute(const char *action, char **argv, int argc, pid_t pid, conf_read_unlock(); } if (!valid_cmd) { - fprintf(stderr, "Invalid command: '%s'\n", action); + log_server_error("Invalid command: '%s'\n", action); return 1; } // Log if (has_flag(flags, F_VERBOSE)) { - printf("'%s' finished (return code %d)\n", action, rc); + log_server_info("'%s' finished (return code %d)\n", action, rc); } return rc; } @@ -640,11 +642,8 @@ int main(int argc, char **argv) return 1; } - // Initialize log (no output) + // Initialize log log_init(); - log_levels_set(LOGT_SYSLOG, LOG_ANY, 0); - log_levels_set(LOGT_STDOUT, LOG_ANY, 0); - closelog(); // Find implicit configuration file char *default_fn = 0; @@ -657,11 +656,11 @@ int main(int argc, char **argv) int conf_ret = conf_open(config_fn); if (conf_ret != KNOTD_EOK) { if (conf_ret == KNOTD_ENOENT) { - fprintf(stderr, "Couldn't open configuration file " - "'%s'.\n", config_fn); + log_server_error("Couldn't open configuration file " + "'%s'.\n", config_fn); } else { - fprintf(stderr, "Failed to parse configuration '%s'.\n", - config_fn); + log_server_error("Failed to parse configuration '%s'.\n", + config_fn); } free(default_fn); return 1; @@ -679,8 +678,8 @@ int main(int argc, char **argv) // Fetch PID char* pidfile = pid_filename(); if (!pidfile) { - fprintf(stderr, "No configuration found, " - "please specify with '-c' parameter.\n"); + log_server_error("No configuration found, " + "please specify with '-c' parameter.\n"); log_close(); return 1; } diff --git a/src/knot/other/debug.h b/src/knot/other/debug.h index 7768d22..1a8698e 100644 --- a/src/knot/other/debug.h +++ b/src/knot/other/debug.h @@ -47,9 +47,11 @@ #ifdef KNOT_COMPILER_DEBUG #define KNOTD_ZDUMP_DEBUG #define KNOTD_ZLOAD_DEBUG + #define KNOTD_SEMCHECK_DEBUG + #define KNOTD_COMPILE_DEBUG #endif -#include "knot/other/log.h" +#include "common/log.h" #include "common/print.h" /******************************************************************************/ @@ -434,6 +436,90 @@ #define dbg_zload_exec_detail(cmds) #endif +#ifdef KNOTD_COMPILER_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_zp(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_zp_hex(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_zp(msg...) +#define dbg_zp_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_zp_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_zp_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_zp_verb(msg...) +#define dbg_zp_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_zp_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_zp_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len)) +#define dbg_zp_exec_detail(cmds) do { cmds } while (0) +#else +#define dbg_zp_detail(msg...) +#define dbg_zp_hex_detail(data, len) +#define dbg_zp_exec_detail(cmds) +#endif + +/* No messages. */ +#else +#define dbg_zp(msg...) +#define dbg_zp_hex(data, len) +#define dbg_zp_verb(msg...) +#define dbg_zp_hex_verb(data, len) +#define dbg_zp_detail(msg...) +#define dbg_zp_hex_detail(data, len) +#define dbg_zp_exec_detail(cmds) +#endif + +#ifdef KNOTD_SEMCHECK_DEBUG + +/* Brief messages. */ +#ifdef DEBUG_ENABLE_BRIEF +#define dbg_semcheck(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_semcheck_hex(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_semcheck(msg...) +#define dbg_semcheck_hex(data, len) +#endif + +/* Verbose messages. */ +#ifdef DEBUG_ENABLE_VERBOSE +#define dbg_semcheck_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_semcheck_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len)) +#else +#define dbg_semcheck_verb(msg...) +#define dbg_semcheck_hex_verb(data, len) +#endif + +/* Detail messages. */ +#ifdef DEBUG_ENABLE_DETAILS +#define dbg_semcheck_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_semcheck_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len)) +#define dbg_semcheck_exec_detail(cmds) do { cmds } while (0) +#else +#define dbg_semcheck_detail(msg...) +#define dbg_semcheck_hex_detail(data, len) +#define dbg_semcheck_exec_detail(cmds) +#endif + +/* No messages. */ +#else +#define dbg_semcheck(msg...) +#define dbg_semcheck_hex(data, len) +#define dbg_semcheck_verb(msg...) +#define dbg_semcheck_hex_verb(data, len) +#define dbg_semcheck_detail(msg...) +#define dbg_semcheck_hex_detail(data, len) +#define dbg_semcheck_exec_detail(cmds) +#endif + /******************************************************************************/ #endif /* _KNOTD_DEBUG_H_ */ diff --git a/src/knot/other/error.c b/src/knot/other/error.c index 0ab7568..70c84a3 100644 --- a/src/knot/other/error.c +++ b/src/knot/other/error.c @@ -26,7 +26,7 @@ const error_table_t knotd_error_msgs[] = { {KNOTD_ENOTSUP, "Parameter not supported."}, {KNOTD_EBUSY, "Requested resource is busy."}, {KNOTD_EAGAIN, "The system lacked the necessary resource, try again."}, - {KNOTD_EACCES, "Permission to perform requested operation is denied."}, + {KNOTD_EACCES, "Operation not permitted."}, {KNOTD_ECONNREFUSED, "Connection refused."}, {KNOTD_EISCONN, "Already connected."}, {KNOTD_EADDRINUSE, "Address already in use."}, diff --git a/src/knot/server/dthreads.c b/src/knot/server/dthreads.c index be6fc24..4e2b490 100644 --- a/src/knot/server/dthreads.c +++ b/src/knot/server/dthreads.c @@ -27,7 +27,7 @@ #include "knot/common.h" #include "knot/server/dthreads.h" -#include "knot/other/log.h" +#include "common/log.h" #include "knot/other/error.h" /*! \brief Lock thread state for R/W. */ @@ -124,6 +124,7 @@ static void *thread_ep(void *data) sigaddset(&ignset, SIGTERM); sigaddset(&ignset, SIGHUP); sigaddset(&ignset, SIGPIPE); + sigaddset(&ignset, SIGUSR1); pthread_sigmask(SIG_BLOCK, &ignset, 0); /*! \todo Review under BSD (issue #1441). */ dbg_dt("dthreads: [%p] entered ep\n", thread); @@ -236,8 +237,9 @@ static dthread_t *dt_create_thread(dt_unit_t *unit) // Initialize attribute pthread_attr_t *attr = &thread->_attr; pthread_attr_init(attr); - pthread_attr_setinheritsched(attr, PTHREAD_INHERIT_SCHED); - pthread_attr_setschedpolicy(attr, SCHED_OTHER); + //pthread_attr_setinheritsched(attr, PTHREAD_INHERIT_SCHED); + //pthread_attr_setschedpolicy(attr, SCHED_OTHER); + pthread_attr_setstacksize(attr, 1024*1024); return thread; } @@ -814,43 +816,43 @@ int dt_stop(dt_unit_t *unit) return KNOTD_EOK; } -int dt_setprio(dthread_t *thread, int prio) -{ - // Check input - if (thread == 0) { - return KNOTD_EINVAL; - } - - // Clamp priority - int policy = SCHED_FIFO; - prio = MIN(MAX(sched_get_priority_min(policy), prio), - sched_get_priority_max(policy)); - - // Update scheduler policy - int ret = pthread_attr_setschedpolicy(&thread->_attr, policy); - - // Update priority - if (ret == 0) { - struct sched_param sp; - sp.sched_priority = prio; - ret = pthread_attr_setschedparam(&thread->_attr, &sp); - } - - /* Map error codes. */ - if (ret != 0) { - dbg_dt("dthreads: [%p] %s(%d): failed", - thread, __func__, prio); - - /* Map "not supported". */ - if (errno == ENOTSUP) { - return KNOTD_ENOTSUP; - } - - return KNOTD_EINVAL; - } - - return KNOTD_EOK; -} +//int dt_setprio(dthread_t *thread, int prio) +//{ +// // Check input +// if (thread == 0) { +// return KNOTD_EINVAL; +// } + +// // Clamp priority +// int policy = SCHED_FIFO; +// prio = MIN(MAX(sched_get_priority_min(policy), prio), +// sched_get_priority_max(policy)); + +// // Update scheduler policy +// int ret = pthread_attr_setschedpolicy(&thread->_attr, policy); + +// // Update priority +// if (ret == 0) { +// struct sched_param sp; +// sp.sched_priority = prio; +// ret = pthread_attr_setschedparam(&thread->_attr, &sp); +// } + +// /* Map error codes. */ +// if (ret != 0) { +// dbg_dt("dthreads: [%p] %s(%d): failed", +// thread, __func__, prio); + +// /* Map "not supported". */ +// if (errno == ENOTSUP) { +// return KNOTD_ENOTSUP; +// } + +// return KNOTD_EINVAL; +// } + +// return KNOTD_EOK; +//} int dt_repurpose(dthread_t *thread, runnable_t runnable, void *data) { diff --git a/src/knot/server/dthreads.h b/src/knot/server/dthreads.h index 8a5e2b4..2347e1d 100644 --- a/src/knot/server/dthreads.h +++ b/src/knot/server/dthreads.h @@ -45,6 +45,9 @@ struct dthread_t; struct dt_unit_t; +/* Constants. */ +#define DTHREADS_STACKSIZE (1024*1024) /* 1M lightweight stack size. */ + /*! * \brief Thread state enumeration. */ @@ -238,10 +241,14 @@ int dt_stop(dt_unit_t *unit); * \param thread Target thread instance. * \param prio Requested priority (positive integer, default is 0). * + * \warning Thread priority setting is disabled as the compatible scheduler + * has significant performance deficiencies (SCHED_OTHER). + * (issue #1809) + * * \retval KNOTD_EOK on success. * \retval KNOTD_EINVAL on invalid parameters. */ -int dt_setprio(dthread_t *thread, int prio); +//int dt_setprio(dthread_t *thread, int prio); /*! * \brief Set thread to execute another runnable. diff --git a/src/knot/server/journal.c b/src/knot/server/journal.c index 6b566f6..fc8ec5c 100644 --- a/src/knot/server/journal.c +++ b/src/knot/server/journal.c @@ -14,13 +14,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <config.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> -#include <sys/stat.h> #include <fcntl.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include "common/crc.h" #include "knot/other/error.h" #include "knot/other/debug.h" #include "knot/zone/zone-dump.h" @@ -51,15 +54,9 @@ static inline int sfwrite(const void *src, size_t len, int fd) /*! \brief Equality compare function. */ static inline int journal_cmp_eq(uint64_t k1, uint64_t k2) { - if (k1 == k2) { - return 0; - } - - if (k1 < k2) { - return -1; - } - - return 1; + if (k1 > k2) return 1; + if (k1 < k2) return -1; + return 0; } /*! \brief Recover metadata from journal. */ @@ -132,6 +129,183 @@ static int journal_recover(journal_t *j) return KNOTD_EOK; } +int journal_write_in(journal_t *j, journal_node_t **rn, uint64_t id, size_t len) +{ + const size_t node_len = sizeof(journal_node_t); + *rn = NULL; + + /* Find next free node. */ + uint16_t jnext = (j->qtail + 1) % j->max_nodes; + + dbg_journal("journal: will write id=%llu, node=%u, size=%zu, fsize=%zu\n", + (unsigned long long)id, j->qtail, len, j->fsize); + + /* Calculate remaining bytes to reach file size limit. */ + size_t fs_remaining = j->fslimit - j->fsize; + + /* Increase free segment if on the end of file. */ + journal_node_t *n = j->nodes + j->qtail; + if (j->free.pos + j->free.len == j->fsize) { + + dbg_journal_verb("journal: * is last node\n"); + + /* Grow journal file until the size limit. */ + if(j->free.len < len && len <= fs_remaining) { + size_t diff = len - j->free.len; + dbg_journal("journal: * growing by +%zu, pos=%u, " + "new fsize=%zu\n", + diff, j->free.pos, + j->fsize + diff); + j->fsize += diff; /* Appending increases file size. */ + j->free.len += diff; + + } + + /* Rewind if resize is needed, but the limit is reached. */ + if(j->free.len < len && len > fs_remaining) { + journal_node_t *head = j->nodes + j->qhead; + j->fsize = j->free.pos; + j->free.pos = head->pos; + j->free.len = 0; + dbg_journal_verb("journal: * fslimit reached, " + "rewinding to %u\n", + head->pos); + dbg_journal_verb("journal: * file size trimmed to %zu\n", + j->fsize); + } + } + + /* Evict occupied nodes if necessary. */ + while (j->free.len < len || + j->nodes[jnext].flags > JOURNAL_FREE) { + + /* Evict least recent node if not empty. */ + journal_node_t *head = j->nodes + j->qhead; + + /* Check if it has been synced to disk. */ + if (head->flags & JOURNAL_DIRTY) { + return KNOTD_EAGAIN; + } + + /* Write back evicted node. */ + head->flags = JOURNAL_FREE; + lseek(j->fd, JOURNAL_HSIZE + (j->qhead + 1) * node_len, SEEK_SET); + if (!sfwrite(head, node_len, j->fd)) { + return KNOTD_ERROR; + } + + dbg_journal("journal: * evicted node=%u, growing by +%u\n", + j->qhead, head->len); + + /* Write back query state. */ + j->qhead = (j->qhead + 1) % j->max_nodes; + uint16_t qstate[2] = {j->qhead, j->qtail}; + lseek(j->fd, JOURNAL_HSIZE - 2 * sizeof(uint16_t), SEEK_SET); + if (!sfwrite(qstate, 2 * sizeof(uint16_t), j->fd)) { + return KNOTD_ERROR; + } + + /* Increase free segment. */ + j->free.len += head->len; + } + + /* Invalidate node and write back. */ + n->id = id; + n->pos = j->free.pos; + n->len = len; + n->flags = JOURNAL_FREE; + n->next = jnext; + journal_update(j, n); + *rn = n; + return KNOTD_EOK; +} + +int journal_write_out(journal_t *journal, journal_node_t *n) +{ + /* Mark node as valid and write back. */ + uint16_t jnext = n->next; + size_t size = n->len; + const size_t node_len = sizeof(journal_node_t); + n->flags = JOURNAL_VALID | journal->bflags; + n->next = 0; + journal_update(journal, n); + + /* Handle free segment on node rotation. */ + if (journal->qtail > jnext && journal->fslimit == FSLIMIT_INF) { + /* Trim free space. */ + journal->fsize -= journal->free.len; + dbg_journal_verb("journal: * trimmed filesize to %zu\n", + journal->fsize); + + /* Rewind free segment. */ + journal_node_t *n = journal->nodes + jnext; + journal->free.pos = n->pos; + journal->free.len = 0; + + } else { + /* Mark used space. */ + journal->free.pos += size; + journal->free.len -= size; + } + + dbg_journal("journal: finishing node=%u id=%llu flags=0x%x, " + "data=<%u, %u> free=<%u, %u>\n", + journal->qtail, (unsigned long long)n->id, + n->flags, n->pos, n->pos + n->len, + journal->free.pos, + journal->free.pos + journal->free.len); + + /* Write back free segment state. */ + lseek(journal->fd, JOURNAL_HSIZE, SEEK_SET); + if (!sfwrite(&journal->free, node_len, journal->fd)) { + /* Node is marked valid and failed to shrink free space, + * node will be overwritten on the next write. Return error. + */ + dbg_journal("journal: failed to write back " + "free segment descriptor\n"); + return KNOTD_ERROR; + } + + /* Node write successful. */ + journal->qtail = jnext; + + /* Write back queue state, not essential as it may be recovered. + * qhead - lowest valid node identifier (least recent) + * qtail - highest valid node identifier (most recently used) + */ + uint16_t qstate[2] = {journal->qhead, journal->qtail}; + lseek(journal->fd, JOURNAL_HSIZE - 2 * sizeof(uint16_t), SEEK_SET); + if (!sfwrite(qstate, 2 * sizeof(uint16_t), journal->fd)) { + dbg_journal("journal: failed to write back queue state\n"); + return KNOTD_ERROR; + } + + return KNOTD_EOK; +} + +/* Recalculate CRC. */ +int journal_update_crc(int fd) +{ + if (fcntl(fd, F_GETFL) < 0) { + return KNOTD_EINVAL; + } + + char buf[4096]; + ssize_t rb = 0; + crc_t crc = crc_init(); + lseek(fd, MAGIC_LENGTH + sizeof(crc_t), SEEK_SET); + while((rb = read(fd, buf, sizeof(buf))) > 0) { + crc = crc_update(crc, (const unsigned char *)buf, rb); + } + lseek(fd, MAGIC_LENGTH, SEEK_SET); + if (!sfwrite(&crc, sizeof(crc_t), fd)) { + dbg_journal("journal: couldn't write CRC to fd=%d\n", fd); + return KNOTD_ERROR; + } + + return KNOTD_EOK; +} + int journal_create(const char *fn, uint16_t max_nodes) { if (fn == NULL) { @@ -151,7 +325,7 @@ int journal_create(const char *fn, uint16_t max_nodes) int fd = open(fn, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (fd < 0) { dbg_journal("journal: failed to create file '%s'\n", fn); - return KNOTD_EINVAL; + return knot_map_errno(errno); } /* Lock. */ @@ -160,13 +334,20 @@ int journal_create(const char *fn, uint16_t max_nodes) /* Create journal header. */ dbg_journal("journal: creating header\n"); - const char magic[MAGIC_LENGTH] = MAGIC_BYTES; + const char magic[MAGIC_LENGTH] = JOURNAL_MAGIC; if (!sfwrite(magic, MAGIC_LENGTH, fd)) { fcntl(fd, F_SETLK, &fl); close(fd); remove(fn); return KNOTD_ERROR; } + crc_t crc = crc_init(); + if (!sfwrite(&crc, sizeof(crc_t), fd)) { + fcntl(fd, F_SETLK, &fl); + close(fd); + remove(fn); + return KNOTD_ERROR; + } if (!sfwrite(&max_nodes, sizeof(uint16_t), fd)) { fcntl(fd, F_SETLK, &fl); close(fd); @@ -222,6 +403,14 @@ int journal_create(const char *fn, uint16_t max_nodes) } } + /* Recalculate CRC. */ + if (journal_update_crc(fd) != KNOTD_EOK) { + fcntl(fd, F_SETLK, &fl); + close(fd); + remove(fn); + return KNOTD_ERROR; + } + /* Unlock and close. */ fcntl(fd, F_SETLK, &fl); close(fd); @@ -241,7 +430,6 @@ journal_t* journal_open(const char *fn, size_t fslimit, int mode, uint16_t bflag /* Open journal file for r/w (returns error if not exists). */ int fd = open(fn, O_RDWR); if (fd < 0) { - dbg_journal("journal: failed to open file '%s'\n", fn); return NULL; } @@ -274,7 +462,7 @@ journal_t* journal_open(const char *fn, size_t fslimit, int mode, uint16_t bflag /* Read magic bytes. */ dbg_journal("journal: reading magic bytes\n"); - const char magic_req[MAGIC_LENGTH] = MAGIC_BYTES; + const char magic_req[MAGIC_LENGTH] = JOURNAL_MAGIC; char magic[MAGIC_LENGTH]; if (!sfread(magic, MAGIC_LENGTH, fd)) { dbg_journal_detail("journal: cannot read magic bytes\n"); @@ -289,6 +477,32 @@ journal_t* journal_open(const char *fn, size_t fslimit, int mode, uint16_t bflag close(fd); return NULL; } + crc_t crc = 0; + if (!sfread(&crc, sizeof(crc_t), fd)) { + dbg_journal_detail("journal: cannot read CRC\n"); + fcntl(fd, F_SETLK, &fl); + close(fd); + return NULL; + } + + /* Recalculate CRC. */ + char buf[4096]; + ssize_t rb = 0; + crc_t crc_calc = crc_init(); + while((rb = read(fd, buf, sizeof(buf))) > 0) { + crc_calc = crc_update(crc_calc, (const unsigned char *)buf, rb); + } + + /* Compare */ + if (crc == crc_calc) { + lseek(fd, MAGIC_LENGTH + sizeof(crc_t), SEEK_SET); /* Rewind. */ + } else { + log_server_warning("Journal file '%s' CRC error, " + "it will be flushed.\n", fn); + fcntl(fd, F_SETLK, &fl); + close(fd); + return NULL; + } /* Check for lazy mode. */ if (mode & JOURNAL_LAZY) { @@ -452,7 +666,9 @@ int journal_fetch(journal_t *journal, uint64_t id, size_t i = jnode_prev(journal, journal->qtail); size_t endp = jnode_prev(journal, journal->qhead); for(; i != endp; i = jnode_prev(journal, i)) { - if (cf(journal->nodes[i].id, id) == 0) { + /* Ignore nodes in uncommited transaction. */ + journal_node_t *n = journal->nodes + i; + if (!(n->flags & JOURNAL_TRANS) && cf(n->id, id) == 0) { *dst = journal->nodes + i; return KNOTD_EOK; } @@ -497,156 +713,111 @@ int journal_read(journal_t *journal, uint64_t id, journal_cmp_t cf, char *dst) int journal_write(journal_t *journal, uint64_t id, const char *src, size_t size) { - if (journal == 0 || src == 0) { + if (journal == NULL || src == NULL) { return KNOTD_EINVAL; } - const size_t node_len = sizeof(journal_node_t); - - /* Find next free node. */ - uint16_t jnext = (journal->qtail + 1) % journal->max_nodes; - - dbg_journal("journal: will write id=%llu, node=%u, size=%zu, fsize=%zu\n", - (unsigned long long)id, journal->qtail, size, journal->fsize); - - /* Calculate remaining bytes to reach file size limit. */ - size_t fs_remaining = journal->fslimit - journal->fsize; - - /* Increase free segment if on the end of file. */ - journal_node_t *n = journal->nodes + journal->qtail; - if (journal->free.pos + journal->free.len == journal->fsize) { - - dbg_journal_verb("journal: * is last node\n"); - - /* Grow journal file until the size limit. */ - if(journal->free.len < size && size <= fs_remaining) { - size_t diff = size - journal->free.len; - dbg_journal("journal: * growing by +%zu, pos=%u, " - "new fsize=%zu\n", - diff, journal->free.pos, - journal->fsize + diff); - journal->fsize += diff; /* Appending increases file size. */ - journal->free.len += diff; - - } + /* Prepare journal write. */ + journal_node_t *n = NULL; + int ret = journal_write_in(journal, &n, id, size); + if (ret != KNOTD_EOK) { + return ret; + } - /* Rewind if resize is needed, but the limit is reached. */ - if(journal->free.len < size && size > fs_remaining) { - journal_node_t *head = journal->nodes + journal->qhead; - journal->fsize = journal->free.pos; - journal->free.pos = head->pos; - journal->free.len = 0; - dbg_journal_verb("journal: * fslimit reached, " - "rewinding to %u\n", - head->pos); - dbg_journal_verb("journal: * file size trimmed to %zu\n", - journal->fsize); - } + /* Write data to permanent storage. */ + lseek(journal->fd, n->pos, SEEK_SET); + if (!sfwrite(src, size, journal->fd)) { + return KNOTD_ERROR; } - /* Evict occupied nodes if necessary. */ - while (journal->free.len < size || - journal->nodes[jnext].flags > JOURNAL_FREE) { - - /* Evict least recent node if not empty. */ - journal_node_t *head = journal->nodes + journal->qhead; + /* Finalize journal write. */ + return journal_write_out(journal, n); +} - /* Check if it has been synced to disk. */ - if (head->flags & JOURNAL_DIRTY) { - return KNOTD_EAGAIN; - } +int journal_map(journal_t *journal, uint64_t id, char **dst, size_t size) +{ + if (journal == NULL || dst == NULL) { + return KNOTD_EINVAL; + } + + /* Prepare journal write. */ + journal_node_t *n = NULL; + int ret = journal_write_in(journal, &n, id, size); + if (ret != KNOTD_EOK) { + return ret; + } - /* Write back evicted node. */ - head->flags = JOURNAL_FREE; - lseek(journal->fd, JOURNAL_HSIZE + (journal->qhead + 1) * node_len, SEEK_SET); - if (!sfwrite(head, node_len, journal->fd)) { - return KNOTD_ERROR; + /* Reserve data in permanent storage. */ + /*! \todo This is only needed when inflating journal file. */ + lseek(journal->fd, n->pos, SEEK_SET); + char nbuf[4096] = {0}; + size_t wb = sizeof(nbuf); + while (size > 0) { + if (size < sizeof(nbuf)) { + wb = size; } - - dbg_journal("journal: * evicted node=%u, growing by +%u\n", - journal->qhead, head->len); - - /* Write back query state. */ - journal->qhead = (journal->qhead + 1) % journal->max_nodes; - uint16_t qstate[2] = {journal->qhead, journal->qtail}; - lseek(journal->fd, JOURNAL_HSIZE - 2 * sizeof(uint16_t), SEEK_SET); - if (!sfwrite(qstate, 2 * sizeof(uint16_t), journal->fd)) { + if (!sfwrite(nbuf, wb, journal->fd)) { return KNOTD_ERROR; } - - /* Increase free segment. */ - journal->free.len += head->len; + size -= wb; } - - /* Invalidate node and write back. */ - n->id = id; - n->pos = journal->free.pos; - n->len = size; - n->flags = JOURNAL_FREE; - journal_update(journal, n); - - /* Write data to permanent storage. */ - lseek(journal->fd, n->pos, SEEK_SET); - if (!sfwrite(src, size, journal->fd)) { + + /* Align offset to page size (required). */ + const size_t ps = sysconf(_SC_PAGESIZE); + off_t ps_delta = (n->pos % ps); + off_t off = n->pos - ps_delta; + + /* Map file region. */ + *dst = mmap(NULL, n->len + ps_delta, PROT_READ | PROT_WRITE, MAP_SHARED, + journal->fd, off); + if (*dst == ((void*)-1)) { + dbg_journal("journal: couldn't mmap() fd=%d <%u,%u> %d\n", + journal->fd, n->pos, n->pos+n->len, errno); return KNOTD_ERROR; } + + /* Advise usage of memory. */ +#ifdef HAVE_MADVISE + madvise(*dst, n->len + ps_delta, MADV_SEQUENTIAL); +#endif + /* Correct dst pointer to alignment. */ + *dst += ps_delta; + + return KNOTD_EOK; +} - /* Mark node as valid and write back. */ - n->flags = JOURNAL_VALID | journal->bflags; - journal_update(journal, n); - - /* Handle free segment on node rotation. */ - if (journal->qtail > jnext && journal->fslimit == FSLIMIT_INF) { - /* Trim free space. */ - journal->fsize -= journal->free.len; - dbg_journal_verb("journal: * trimmed filesize to %zu\n", - journal->fsize); - - /* Rewind free segment. */ - journal_node_t *n = journal->nodes + jnext; - journal->free.pos = n->pos; - journal->free.len = 0; - - } else { - /* Mark used space. */ - journal->free.pos += size; - journal->free.len -= size; +int journal_unmap(journal_t *journal, uint64_t id, void *ptr, int finalize) +{ + if (journal == NULL || ptr == NULL) { + return KNOTD_EINVAL; } - dbg_journal("journal: finished node=%u, data=<%u, %u> free=<%u, %u>\n", - journal->qtail, n->pos, n->pos + n->len, - journal->free.pos, - journal->free.pos + journal->free.len); - - /* Write back free segment state. */ - lseek(journal->fd, JOURNAL_HSIZE, SEEK_SET); - if (!sfwrite(&journal->free, node_len, journal->fd)) { - /* Node is marked valid and failed to shrink free space, - * node will be overwritten on the next write. Return error. - */ - dbg_journal("journal: failed to write back " - "free segment descriptor\n"); - return KNOTD_ERROR; + + /* Mapped node is on tail. */ + journal_node_t *n = journal->nodes + journal->qtail; + if(n->id != id) { + dbg_journal("journal: failed to find mmap node with id=%llu\n", + (unsigned long long)id); + return KNOTD_ENOENT; } - /* Node write successful. */ - journal->qtail = jnext; - - /* Write back queue state, not essential as it may be recovered. - * qhead - lowest valid node identifier (least recent) - * qtail - highest valid node identifier (most recently used) - */ - uint16_t qstate[2] = {journal->qhead, journal->qtail}; - lseek(journal->fd, JOURNAL_HSIZE - 2 * sizeof(uint16_t), SEEK_SET); - if (!sfwrite(qstate, 2 * sizeof(uint16_t), journal->fd)) { - dbg_journal("journal: failed to write back queue state\n"); + /* Realign memory. */ + const size_t ps = sysconf(_SC_PAGESIZE); + off_t ps_delta = (n->pos % ps); + ptr = ((char*)ptr - ps_delta); + + /* Unmap memory. */ + if (munmap(ptr, n->len + ps_delta) != 0) { + dbg_journal("journal: couldn't munmap() fd=%d <%u,%u> %d\n", + journal->fd, n->pos, n->pos+n->len, errno); return KNOTD_ERROR; } - - /*! \todo Delayed write-back? (issue #964) */ - dbg_journal_verb("journal: write of finished, nqueue=<%u, %u>\n", - journal->qhead, journal->qtail); - - return KNOTD_EOK; + + /* Finalize. */ + int ret = KNOTD_EOK; + if (finalize) { + ret = journal_write_out(journal, n); + } + return ret; } int journal_walk(journal_t *journal, journal_apply_t apply) @@ -677,8 +848,8 @@ int journal_update(journal_t *journal, journal_node_t *n) /* Calculate node position in permanent storage. */ long jn_fpos = JOURNAL_HSIZE + (i + 1) * node_len; - dbg_journal("journal: syncing journal node=%zu at %ld\n", - i, jn_fpos); + dbg_journal("journal: syncing journal node=%zu id=%llu flags=0x%x\n", + i, (unsigned long long)n->id, n->flags); /* Write back. */ lseek(journal->fd, jn_fpos, SEEK_SET); @@ -691,6 +862,82 @@ int journal_update(journal_t *journal, journal_node_t *n) return KNOTD_EOK; } +int journal_trans_begin(journal_t *journal) +{ + if (journal == NULL) { + return KNOTD_EINVAL; + } + + /* Already pending transactions. */ + if (journal->bflags & JOURNAL_TRANS) { + return KNOTD_EBUSY; + } + + journal->bflags |= JOURNAL_TRANS; + journal->tmark = journal->qtail; + dbg_journal("journal: starting transaction at qtail=%hu\n", + journal->tmark); + + return KNOTD_EOK; +} + +int journal_trans_commit(journal_t *journal) +{ + if (journal == NULL) { + return KNOTD_EINVAL; + } + if ((journal->bflags & JOURNAL_TRANS) == 0) { + return KNOTD_ENOENT; + } + + /* Mark affected nodes as commited. */ + int ret = KNOTD_EOK; + size_t i = journal->tmark; + for(; i != journal->qtail; i = (i + 1) % journal->max_nodes) { + journal->nodes[i].flags &= (~JOURNAL_TRANS); + ret = journal_update(journal, journal->nodes + i); + if (ret != KNOTD_EOK) { + dbg_journal("journal: failed to clear TRANS flag from " + "node %zu\n", i); + return ret; + } + } + + /* Clear in-transaction flags. */ + journal->tmark = 0; + journal->bflags &= (~JOURNAL_TRANS); + return KNOTD_EOK; +} + +int journal_trans_rollback(journal_t *journal) +{ + if (journal == NULL) { + return KNOTD_EINVAL; + } + if ((journal->bflags & JOURNAL_TRANS) == 0) { + return KNOTD_ENOENT; + } + + /* Expand free space and rewind node queue tail. */ + /*! \note This shouldn't be relied upon and probably shouldn't + * be written back to file, as crashing anywhere between + * transaction begin and rollback would result in corrupted + * journal. Also write function should recognize TRANS nodes. + */ + //journal->free.pos = journal->nodes[journal->tmark].pos; + //journal->free.len = 0; + + dbg_journal("journal: rollback transaction id=<%hu,%hu>\n", + journal->tmark, journal->qtail); + //journal->qtail = journal->tmark; + + /* Clear in-transaction flags. */ + journal->tmark = 0; + journal->bflags &= (~JOURNAL_TRANS); + + return KNOTD_EOK; +} + int journal_close(journal_t *journal) { /* Check journal. */ @@ -699,9 +946,13 @@ int journal_close(journal_t *journal) } /* Check if lazy. */ + int ret = KNOTD_EOK; if (journal->fd < 0) { free(journal->path); } else { + /* Recalculate CRC. */ + ret = journal_update_crc(journal->fd); + /* Unlock journal file. */ journal->fl.l_type = F_UNLCK; fcntl(journal->fd, F_SETLK, &journal->fl); @@ -714,10 +965,9 @@ int journal_close(journal_t *journal) dbg_journal("journal: closed journal %p\n", journal); /* Free allocated resources. */ - free(journal); - return KNOTD_EOK; + return ret; } journal_t *journal_retain(journal_t *journal) diff --git a/src/knot/server/journal.h b/src/knot/server/journal.h index b12bfc9..d874996 100644 --- a/src/knot/server/journal.h +++ b/src/knot/server/journal.h @@ -43,7 +43,6 @@ #include <stdint.h> #include <fcntl.h> -#include "knot/zone/zone-dump.h" /*! * \brief Journal entry flags. @@ -52,7 +51,8 @@ typedef enum journal_flag_t { JOURNAL_NULL = 0 << 0, /*!< Invalid journal entry. */ JOURNAL_FREE = 1 << 0, /*!< Free journal entry. */ JOURNAL_VALID = 1 << 1, /*!< Valid journal entry. */ - JOURNAL_DIRTY = 1 << 2 /*!< Journal entry cannot be evicted. */ + JOURNAL_DIRTY = 1 << 2, /*!< Journal entry cannot be evicted. */ + JOURNAL_TRANS = 1 << 3 /*!< Entry is in transaction (uncommited). */ } journal_flag_t; /*! @@ -73,6 +73,7 @@ typedef struct journal_node_t { uint64_t id; /*!< Node ID. */ uint16_t flags; /*!< Node flags. */ + uint16_t next; /*!< Next node ptr. */ uint32_t pos; /*!< Position in journal file. */ uint32_t len; /*!< Entry data length. */ } journal_node_t; @@ -94,6 +95,7 @@ typedef struct journal_t struct flock fl; /*!< File lock. */ char *path; /*!< Path to journal file. */ int refs; /*!< Number of references. */ + uint16_t tmark; /*!< Transaction start mark. */ uint16_t max_nodes; /*!< Number of nodes. */ uint16_t qhead; /*!< Node queue head. */ uint16_t qtail; /*!< Node queue tail. */ @@ -125,7 +127,9 @@ typedef int (*journal_apply_t)(journal_t *j, journal_node_t *n); * Journal defaults and constants. */ #define JOURNAL_NCOUNT 1024 /*!< Default node count. */ -#define JOURNAL_HSIZE (MAGIC_LENGTH + sizeof(uint16_t) * 3) /*!< magic, max_entries, qhead, qtail */ +/* HEADER = magic, crc, max_entries, qhead, qtail */ +#define JOURNAL_HSIZE (MAGIC_LENGTH + sizeof(crc_t) + sizeof(uint16_t) * 3) +#define JOURNAL_MAGIC {'k', 'n', 'o', 't', '1', '0', '2'} /*! * \brief Create new journal. @@ -195,6 +199,36 @@ int journal_read(journal_t *journal, uint64_t id, journal_cmp_t cf, char *dst); int journal_write(journal_t *journal, uint64_t id, const char *src, size_t size); /*! + * \brief Map journal entry for read/write. + * + * \warning New nodes shouldn't be created until the entry is unmapped. + * + * \param journal Associated journal. + * \param id Entry identifier. + * \param dst Will contain mapped memory. + * + * \retval KNOTD_EOK if successful. + * \retval KNOTD_EAGAIN if no free node is available, need to remove dirty nodes. + * \retval KNOTD_ERROR on I/O error. + */ +int journal_map(journal_t *journal, uint64_t id, char **dst, size_t size); + +/*! + * \brief Finalize mapped journal entry. + * + * \param journal Associated journal. + * \param id Entry identifier. + * \param ptr Mapped memory. + * \param finalize Set to true to finalize node or False to discard it. + * + * \retval KNOTD_EOK if successful. + * \retval KNOTD_ENOENT if the entry cannot be found. + * \retval KNOTD_EAGAIN if no free node is available, need to remove dirty nodes. + * \retval KNOTD_ERROR on I/O error. + */ +int journal_unmap(journal_t *journal, uint64_t id, void *ptr, int finalize); + +/*! * \brief Return least recent node (journal head). * * \param journal Associated journal. @@ -243,6 +277,45 @@ int journal_walk(journal_t *journal, journal_apply_t apply); int journal_update(journal_t *journal, journal_node_t *n); /*! + * \brief Begin transaction of multiple entries. + * + * \note Only one transaction at a time is supported. + * + * \param journal Associated journal. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_EBUSY if transaction is already pending. + */ +int journal_trans_begin(journal_t *journal); + +/*! + * \brief Commit pending transaction. + * + * \note Only one transaction at a time is supported. + * + * \param journal Associated journal. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_ENOENT if no transaction is pending. + */ +int journal_trans_commit(journal_t *journal); + +/*! + * \brief Rollback pending transaction. + * + * \note Only one transaction at a time is supported. + * + * \param journal Associated journal. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_ENOENT if no transaction is pending. + */ +int journal_trans_rollback(journal_t *journal); + +/*! * \brief Close journal file. * * \param journal Associated journal. @@ -270,4 +343,19 @@ journal_t *journal_retain(journal_t *journal); */ void journal_release(journal_t *journal); +/*! + * \brief Recompute journal CRC. + * + * \warning Use only if you altered the journal file somehow + * and need it to pass CRC checks. CRC check normally + * checks file integrity, so you should not touch it unless + * you know what you're doing. + * + * \param fd Open journal file. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL if not valid fd. + */ +int journal_update_crc(int fd); + #endif /* _KNOTD_JOURNAL_H_ */ diff --git a/src/knot/server/notify.c b/src/knot/server/notify.c index 566d66f..d12247b 100644 --- a/src/knot/server/notify.c +++ b/src/knot/server/notify.c @@ -193,7 +193,7 @@ static int notify_check_and_schedule(knot_nameserver_t *nameserver, char straddr[SOCKADDR_STRLEN]; sockaddr_tostr(from, straddr, sizeof(straddr)); log_zone_notice("Unauthorized NOTIFY query " - "from %s:%d to zone '%s'.\n", + "from '%s@%d' to zone '%s'.\n", straddr, sockaddr_portnum(from), zd->conf->name); return KNOT_ERROR; diff --git a/src/knot/server/server.c b/src/knot/server/server.c index ceab716..ba7ccd7 100644 --- a/src/knot/server/server.c +++ b/src/knot/server/server.c @@ -759,7 +759,7 @@ int server_conf_hook(const struct conf_t *conf, void *data) h->state = ServerRunning; ret = dt_start(h->unit); if (ret < 0) { - log_server_error("Handler for %s:%d " + log_server_error("Handler for '%s@%d' " "has failed to start.\n", h->iface->addr, h->iface->port); diff --git a/src/knot/server/tcp-handler.c b/src/knot/server/tcp-handler.c index a59ba7c..e53e286 100644 --- a/src/knot/server/tcp-handler.c +++ b/src/knot/server/tcp-handler.c @@ -53,7 +53,7 @@ typedef struct tcp_worker_t { /* * Forward decls. */ -#define TCP_THROTTLE_LO 10 /*!< Minimum recovery time on errors. */ +#define TCP_THROTTLE_LO 5 /*!< Minimum recovery time on errors. */ #define TCP_THROTTLE_HI 50 /*!< Maximum recovery time on errors. */ /*! \brief Calculate TCP throttle time (random). */ @@ -119,7 +119,7 @@ static void tcp_sweep(fdset_t *set, int fd, void* data) #endif } - log_server_notice("Connection with %s:%d was terminated due to " + log_server_notice("Connection with '%s@%d' was terminated due to " "inactivity.\n", r_addr, r_port); fdset_remove(set, fd); close(fd); @@ -164,9 +164,9 @@ static int tcp_handle(tcp_worker_t *w, int fd, uint8_t *qbuf, size_t qbuf_maxlen char r_addr[SOCKADDR_STRLEN]; sockaddr_tostr(&addr, r_addr, sizeof(r_addr)); int r_port = sockaddr_portnum(&addr); - log_server_warning("Couldn't receive query from %s:%d " - "within the time limit %ds.\n", - r_addr, r_port, TCP_ACTIVITY_WD); + log_server_warning("Couldn't receive query from '%s@%d'" + " within the time limit of %ds.\n", + r_addr, r_port, TCP_ACTIVITY_WD); } return KNOTD_ECONNREFUSED; } @@ -290,7 +290,6 @@ static int tcp_accept(int fd) /* Evaluate connection. */ if (incoming < 0) { int en = errno; - /*! \todo Better solution so it doesn't block current connections (issue #1542). */ if (en != EINTR) { log_server_error("Cannot accept connection " "(%d).\n", errno); diff --git a/src/knot/server/udp-handler.c b/src/knot/server/udp-handler.c index 6e50926..73c557d 100644 --- a/src/knot/server/udp-handler.c +++ b/src/knot/server/udp-handler.c @@ -72,7 +72,7 @@ int udp_handle(int fd, uint8_t *qbuf, size_t qbuflen, size_t *resp_len, #ifdef DEBUG_ENABLE_BRIEF char strfrom[SOCKADDR_STRLEN]; sockaddr_tostr(addr, strfrom, sizeof(strfrom)); - dbg_net("udp: fd=%d received %zd bytes from %s:%d.\n", fd, qbuflen, + dbg_net("udp: fd=%d received %zd bytes from '%s@%d'.\n", fd, qbuflen, strfrom, sockaddr_portnum(addr)); #endif @@ -458,8 +458,8 @@ void __attribute__ ((constructor)) udp_master_init() } /* Check for sendmmsg() support. */ -#ifdef ENABLE_SENDMMSG _send_mmsg = udp_sendto; +#ifdef ENABLE_SENDMMSG sendmmsg(0, 0, 0, 0); /* Just check if syscall exists */ if (errno != ENOSYS) { _send_mmsg = udp_sendmmsg; diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c index 3a1b7da..8e6d6ca 100644 --- a/src/knot/server/xfr-handler.c +++ b/src/knot/server/xfr-handler.c @@ -46,6 +46,7 @@ #define XFR_SWEEP_INTERVAL 2 /*! [seconds] between sweeps. */ #define XFR_BUFFER_SIZE 65535 /*! Do not change this - maximum value for UDP packet length. */ +/*! \brief Send interrupt to all workers. */ void xfr_interrupt(xfrhandler_t *h) { for(unsigned i = 0; i < h->unit->size; ++i) { @@ -53,6 +54,7 @@ void xfr_interrupt(xfrhandler_t *h) } } +/*! \brief Deinitialize allocated values from xfer descriptor. */ static void xfr_request_deinit(knot_ns_xfr_t *r) { if (r) { @@ -61,7 +63,7 @@ static void xfr_request_deinit(knot_ns_xfr_t *r) } } -/*! \todo Document me (issue #1586) */ +/*! \brief Free allocated xfer descriptor (also deinitializes). */ static void xfr_free_task(knot_ns_xfr_t *task) { if (!task) { @@ -89,20 +91,29 @@ static void xfr_free_task(knot_ns_xfr_t *task) pthread_mutex_unlock(&zd->xfr_in.lock); } } - - /* Remove fd-related data. */ - xfrhandler_t *h = w->master; - pthread_mutex_lock(&h->tasks_mx); - skip_remove(h->tasks, (void*)((size_t)task->session), 0, 0); - pthread_mutex_unlock(&h->tasks_mx); /* Deinitialize */ xfr_request_deinit(task); - - close(task->session); + if (!task->session_closed) { + /* Remove fd-related data. */ + xfrhandler_t *h = w->master; + pthread_mutex_lock(&h->tasks_mx); + skip_remove(h->tasks, (void*)((size_t)task->session), 0, 0); + pthread_mutex_unlock(&h->tasks_mx); + close(task->session); + } free(task); } +/*! + * \brief Return xfer descriptor associated with given fd. + * + * \param w Current worker. + * \param fd Requested descriptor. + * + * \retval xfer descriptor if found. + * \retval NULL if no descriptor found. + */ static knot_ns_xfr_t *xfr_handler_task(xfrworker_t *w, int fd) { xfrhandler_t *h = w->master; @@ -157,8 +168,8 @@ static int xfr_process_udp_resp(xfrworker_t *w, int fd, knot_ns_xfr_t *data) udp_handle(fd, data->wire, n, &resp_len, &data->addr, w->ns); } - xfr_free_task(data); - return KNOTD_EOK; + /* Invalidate pending query. */ + return KNOTD_ECONNREFUSED; } /*! \brief Sweep non-replied connection. */ @@ -188,8 +199,18 @@ static void xfr_sweep(fdset_t *set, int fd, void *data) } } -/*! \todo Document me (issue #1586) */ -static knot_ns_xfr_t *xfr_register_task(xfrworker_t *w, knot_ns_xfr_t *req) +/*! + * \brief Register task in given worker. + * + * \warning Must be freed with xfr_free_task() when finished. + * + * \param w Given worker. + * \param req Pointer to template xfer descriptor. + * + * \retval Newly allocated xfer descriptor if success. + * \retval NULL on error. + */ +static knot_ns_xfr_t *xfr_register_task(xfrworker_t *w, const knot_ns_xfr_t *req) { knot_ns_xfr_t *t = malloc(sizeof(knot_ns_xfr_t)); if (!t) { @@ -279,19 +300,12 @@ static int xfr_xfrin_cleanup(xfrworker_t *w, knot_ns_xfr_t *data) */ static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data) { - /* CLEANUP */ -// // get the zone name from Question -// dbg_xfr_verb("Query: %p, response: %p\n", data->query, data->response); -// const knot_dname_t *qname = knot_packet_qname(data->query); -// char *zorigin = "(unknown)"; -// if (qname != NULL) { -// zorigin = knot_dname_to_str(qname); -// } - + int ret = KNOTD_EOK; int apply_ret = KNOT_EOK; int switch_ret = KNOT_EOK; knot_changesets_t *chs = NULL; + journal_t *transaction = NULL; switch(data->type) { case XFR_TYPE_AIN: @@ -319,15 +333,21 @@ static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data) case XFR_TYPE_IIN: chs = (knot_changesets_t *)data->data; - /* First, serialize changesets. */ - ret = zones_changesets_to_binary(chs); + /* Serialize and store changesets. */ + dbg_xfr("xfr: IXFR/IN serializing and saving changesets\n"); + transaction = zones_store_changesets_begin(data); + if (transaction != NULL) { + ret = zones_store_changesets(data); + } else { + ret = KNOTD_ERROR; + } if (ret != KNOTD_EOK) { - log_zone_error("%s Failed to serialize changesets - %s" - "\n", data->msgpref, + log_zone_error("%s Failed to serialize and store " + "changesets - %s\n", data->msgpref, knotd_strerror(ret)); /* Free changesets, but not the data. */ knot_free_changesets(&chs); - data->data = 0; + data->data = NULL; break; } @@ -336,40 +356,30 @@ static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data) &data->new_contents); if (apply_ret != KNOT_EOK) { + zones_store_changesets_rollback(transaction); log_zone_error("%s Failed to apply changesets - %s\n", data->msgpref, knot_strerror(apply_ret)); /* Free changesets, but not the data. */ knot_free_changesets(&chs); - data->data = 0; + data->data = NULL; ret = KNOTD_ERROR; break; } - /* Save changesets. */ - dbg_xfr("xfr: IXFR/IN saving changesets\n"); - - /*! \note Here, the changesets may already be modified. - * Only the 'data' field of each changeset contains the - * proper serialized changesets. Serials should be - * OK too. - */ - ret = zones_store_changesets(data); + /* Commit transaction. */ + ret = zones_store_changesets_commit(transaction); if (ret != KNOTD_EOK) { - log_zone_error("%s Failed to save " - "transferred changesets - %s\n", - data->msgpref, knotd_strerror(ret)); - - // Cleanup old and new contents - xfrin_rollback_update(data->zone->contents, - &data->new_contents, - &chs->changes); - /* Free changesets, but not the data. */ + log_zone_error("%s Failed to commit stored changesets " + "- %s\n", + data->msgpref, + knot_strerror(apply_ret)); knot_free_changesets(&chs); - data->data = 0; + data->data = NULL; break; } + /* Switch zone contents. */ switch_ret = xfrin_switch_zone(data->zone, data->new_contents, data->type); @@ -386,7 +396,7 @@ static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data) /* Free changesets, but not the data. */ knot_free_changesets(&chs); - data->data = 0; + data->data = NULL; ret = KNOTD_ERROR; break; } @@ -395,7 +405,7 @@ static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data) /* Free changesets, but not the data. */ knot_free_changesets(&chs); - data->data = 0; + data->data = NULL; assert(ret == KNOTD_EOK); log_zone_info("%s Finished.\n", data->msgpref); break; @@ -404,11 +414,6 @@ static int xfr_xfrin_finalize(xfrworker_t *w, knot_ns_xfr_t *data) break; } - /* CLEANUP */ -// if (qname != NULL) { -// free(zorigin); -// } - return ret; } @@ -661,11 +666,20 @@ int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data, uint8_t *buf, data->msgpref, knot_strerror(ret)); } - /* Check finished zone. */ int result = KNOTD_EOK; if (xfer_finished) { + /* Close early to free up fd for storing zone. */ + data->session_closed = 1; + close(data->session); + + /* Remove fd-related data. */ + xfrhandler_t *h = w->master; + pthread_mutex_lock(&h->tasks_mx); + skip_remove(h->tasks, (void*)((size_t)data->session), 0, 0); + pthread_mutex_unlock(&h->tasks_mx); + knot_zone_t *zone = (knot_zone_t *)data->zone; zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); @@ -714,7 +728,14 @@ int xfr_process_event(xfrworker_t *w, int fd, knot_ns_xfr_t *data, uint8_t *buf, return result; } -/*! \todo Document me (issue #1586) +/*! + * \brief Start incoming transfer (applicable to AXFR/IN or IXFR/IN). + * + * \warning xfer descriptor will be registered if successful. + * \warning data->fd will be duplicated if successful. + * + * \param w Given worker. + * \param data xfer descriptor. */ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) { @@ -759,32 +780,20 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) /* Presume port is already preset. */ ret = bind(fd, data->saddr.ptr, data->saddr.len); } + if (ret < 0) { + log_server_warning("%s Failed to create socket.\n", + data->msgpref); + } else { + ret = connect(fd, data->addr.ptr, data->addr.len); + } } else { - pthread_mutex_unlock(&zd->xfr_in.lock); - log_server_warning("%s Failed to create socket " - "(type=%s, family=%s).\n", - "SOCK_STREAM", - data->msgpref, - data->addr.family == AF_INET ? - "AF_INET" : "AF_INET6"); - return KNOTD_ERROR; + ret = -1; } - ret = connect(fd, data->addr.ptr, data->addr.len); if (ret < 0) { pthread_mutex_unlock(&zd->xfr_in.lock); - if (!knot_zone_contents(zone)) { - /* Reschedule request (120 - 240s random delay). */ - int tmr_s = AXFR_BOOTSTRAP_RETRY * 2; /* Malus x2 */ - tmr_s += (int)((120.0 * 1000) * tls_rand()); - event_t *ev = zd->xfr_in.timer; - if (ev) { - evsched_cancel(ev->parent, ev); - evsched_schedule(ev->parent, ev, tmr_s); - } - log_zone_notice("%s Bootstrap failed, next " - "attempt in %d seconds.\n", - data->msgpref, tmr_s / 1000); + if (fd >= 0) { + close(fd); } return KNOTD_ECONNREFUSED; } @@ -794,6 +803,12 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) } else { /* Duplicate existing socket descriptor. */ data->session = dup(data->session); + if (data->session < 0) { + pthread_mutex_unlock(&zd->xfr_in.lock); + log_server_warning("Not enough memory to duplicate \n" + "sockets.\n"); + return KNOTD_ENOMEM; + } } /* Fetch zone contents. */ @@ -804,6 +819,8 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) rcu_read_unlock(); log_server_warning("%s Refusing to start IXFR/IN on zone with no " "contents.\n", data->msgpref); + close(data->session); + data->session = -1; return KNOTD_EINVAL; } @@ -842,8 +859,10 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) /* Handle errors. */ if (ret != KNOT_EOK) { pthread_mutex_unlock(&zd->xfr_in.lock); - fprintf(stderr, "xfr: failed to create XFR query type %d: %s\n", + dbg_xfr("xfr: failed to create XFR query type %d: %s\n", data->type, knot_strerror(ret)); + close(data->session); + data->session = -1; return KNOTD_ERROR; } @@ -858,30 +877,39 @@ static int xfr_client_start(xfrworker_t *w, knot_ns_xfr_t *data) log_server_info("%s Failed to send query (%s).\n", data->msgpref, buf); pthread_mutex_unlock(&zd->xfr_in.lock); + close(data->session); + data->session = -1; return KNOTD_ECONNREFUSED; } /* Add to pending transfers. */ - knot_ns_xfr_t *task = xfr_register_task(w, data); + knot_ns_xfr_t *task = xfr_register_task(w, data); + if (task == NULL) { + log_server_warning("%s Couldn't start connection.\n", + data->msgpref); + close(data->session); + data->session = -1; + return KNOTD_ERROR; + } /* Send XFR query. */ - log_server_info("%s Started.\n", task->msgpref); + log_server_info("%s Started.\n", data->msgpref); return KNOTD_EOK; } +/*! + * \brief Compare file descriptors. + * + * \note Return values of {-1,0,1} are required by skip-list structure. + */ static int xfr_fd_compare(void *k1, void *k2) { - if (k1 < k2) { - return -1; - } - - if (k1 > k2) { - return 1; - } - + if (k1 > k2) return 1; + if (k1 < k2) return -1; return 0; } +/*! \brief Return I/A character depending on xfer type. */ static inline char xfr_strtype(knot_ns_xfr_t *xfr) { if (xfr->type == XFR_TYPE_IOUT) { return 'I'; @@ -890,6 +918,7 @@ static inline char xfr_strtype(knot_ns_xfr_t *xfr) { } } +/*! \brief Wrapper function for answering AXFR/OUT. */ static int xfr_answer_axfr(knot_nameserver_t *ns, knot_ns_xfr_t *xfr) { int ret = knot_ns_answer_axfr(ns, xfr); @@ -897,22 +926,21 @@ static int xfr_answer_axfr(knot_nameserver_t *ns, knot_ns_xfr_t *xfr) return ret; } +/*! \brief Wrapper function for answering IXFR/OUT. */ static int xfr_answer_ixfr(knot_nameserver_t *ns, knot_ns_xfr_t *xfr) { /* Check serial differeces. */ int ret = KNOT_EOK; uint32_t serial_from = 0; uint32_t serial_to = 0; - dbg_xfr_verb("Loading serials for IXFR.\n"); ret = ns_ixfr_load_serials(xfr, &serial_from, &serial_to); - dbg_xfr_detail("Loaded serials: from: %u, to: %u\n", - serial_from, serial_to); + dbg_xfr_verb("xfr: loading changesets for IXFR %u-%u\n", + serial_from, serial_to); if (ret != KNOT_EOK) { return ret; } /* Load changesets from journal. */ - dbg_xfr_verb("Loading changesets from journal.\n"); int chsload = zones_xfr_load_changesets(xfr, serial_from, serial_to); if (chsload != KNOTD_EOK) { /* History cannot be reconstructed, fallback to AXFR. */ @@ -943,6 +971,7 @@ static int xfr_answer_ixfr(knot_nameserver_t *ns, knot_ns_xfr_t *xfr) return ret; } +/*! \brief Build string for logging related to given xfer descriptor. */ static int xfr_update_msgpref(knot_ns_xfr_t *req, const char *keytag) { /* Check */ @@ -990,22 +1019,22 @@ static int xfr_update_msgpref(knot_ns_xfr_t *req, const char *keytag) const char *pformat = NULL; switch (req->type) { case XFR_TYPE_AIN: - pformat = "AXFR transfer of '%s/IN' with %s:%d%s:"; + pformat = "AXFR transfer of '%s/IN' with '%s@%d'%s:"; break; case XFR_TYPE_IIN: - pformat = "IXFR transfer of '%s/IN' with %s:%d%s:"; + pformat = "IXFR transfer of '%s/IN' with '%s@%d'%s:"; break; case XFR_TYPE_AOUT: - pformat = "AXFR transfer of '%s/OUT' to %s:%d%s:"; + pformat = "AXFR transfer of '%s/OUT' to '%s@%d'%s:"; break; case XFR_TYPE_IOUT: - pformat = "IXFR transfer of '%s/OUT' to %s:%d%s:"; + pformat = "IXFR transfer of '%s/OUT' to '%s@%d'%s:"; break; case XFR_TYPE_NOTIFY: - pformat = "NOTIFY query of '%s' to %s:%d%s:"; + pformat = "NOTIFY query of '%s' to '%s@%d'%s:"; break; case XFR_TYPE_SOA: - pformat = "SOA query of '%s' to %s:%d%s:"; + pformat = "SOA query of '%s' to '%s@%d'%s:"; break; default: pformat = ""; @@ -1032,10 +1061,7 @@ static int xfr_update_msgpref(knot_ns_xfr_t *req, const char *keytag) return KNOTD_EOK; } -/* - * Public APIs. - */ - +/*! \brief Create XFR worker. */ static xfrworker_t* xfr_worker_create(xfrhandler_t *h, knot_nameserver_t *ns) { xfrworker_t *w = malloc(sizeof(xfrworker_t)); @@ -1068,6 +1094,7 @@ static xfrworker_t* xfr_worker_create(xfrhandler_t *h, knot_nameserver_t *ns) return w; } +/*! \brief Free created XFR worker. */ static void xfr_worker_free(xfrworker_t *w) { if (w) { evqueue_free(&w->q); @@ -1076,6 +1103,10 @@ static void xfr_worker_free(xfrworker_t *w) { } } +/* + * Public APIs. + */ + xfrhandler_t *xfr_create(size_t thrcount, knot_nameserver_t *ns) { /* Create XFR handler data. */ @@ -1243,7 +1274,6 @@ int xfr_answer(knot_nameserver_t *ns, knot_ns_xfr_t *xfr) // use the QNAME as the zone name to get names also for // zones that are not in the server - /*! \todo Update msgpref with zname from query. */ const knot_dname_t *qname = knot_packet_qname(xfr->query); if (qname != NULL) { xfr->zname = knot_dname_to_str(qname); @@ -1348,7 +1378,13 @@ static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen) /* Update XFR message prefix. */ xfr_update_msgpref(&xfr, NULL); - + + /* Check if not already processing. */ + zonedata_t *zd = NULL; + if (xfr.zone != NULL) { + zd = (zonedata_t *)knot_zone_data(xfr.zone); + } + conf_read_lock(); /* Handle request. */ @@ -1362,8 +1398,22 @@ static int xfr_process_request(xfrworker_t *w, uint8_t *buf, size_t buflen) /* Report. */ if (ret != KNOTD_EOK && ret != KNOTD_EACCES) { - log_server_error("%s %s\n", - xfr.msgpref, knotd_strerror(ret)); + if (zd != NULL && !knot_zone_contents(xfr.zone)) { + /* Reschedule request (120 - 240s random delay). */ + int tmr_s = AXFR_BOOTSTRAP_RETRY * 2; /* Malus x2 */ + tmr_s += (int)((120.0 * 1000) * tls_rand()); + event_t *ev = zd->xfr_in.timer; + if (ev) { + evsched_cancel(ev->parent, ev); + evsched_schedule(ev->parent, ev, tmr_s); + } + log_zone_notice("%s Bootstrap failed, next " + "attempt in %d seconds.\n", + xfr.msgpref, tmr_s / 1000); + } else { + log_server_error("%s %s\n", + xfr.msgpref, knotd_strerror(ret)); + } } break; @@ -1445,16 +1495,12 @@ int xfr_worker(dthread_t *thread) int rfd = evqueue_pollfd(w->q); fdset_it_t it; fdset_begin(w->fdset, &it); + int rfd_event = 0; while(nfds > 0) { /* Check if it request. */ if (it.fd == rfd) { - dbg_xfr_verb("xfr: worker=%p processing request\n", - w); - ret = xfr_process_request(w, buf, buflen); - if (ret == KNOTD_ENOTRUNNING) { - break; - } + rfd_event = 1; /* Delay new tasks after processing. */ } else { /* Find data. */ data = xfr_handler_task(w, it.fd); @@ -1481,6 +1527,12 @@ int xfr_worker(dthread_t *thread) } } + /* Lazily process new tasks. */ + if (rfd_event) { + dbg_xfr_verb("xfr: worker=%p processing request\n", w); + ret = xfr_process_request(w, buf, buflen); + } + /* Sweep inactive. */ timev_t now; if (time_now(&now) == 0) { diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c index be072e8..ba6340d 100644 --- a/src/knot/server/zones.c +++ b/src/knot/server/zones.c @@ -28,7 +28,7 @@ #include "knot/conf/conf.h" #include "knot/other/debug.h" #include "knot/other/error.h" -#include "knot/other/log.h" +#include "common/log.h" #include "knot/server/notify.h" #include "knot/server/server.h" #include "libknot/updates/xfr-in.h" @@ -42,6 +42,7 @@ static const size_t XFRIN_CHANGESET_BINARY_SIZE = 100; static const size_t XFRIN_CHANGESET_BINARY_STEP = 100; +static const size_t XFRIN_BOOTSTRAP_DELAY = 60; /*!< AXFR bootstrap avg. delay */ /* Forward declarations. */ static int zones_dump_zone_text(knot_zone_contents_t *zone, const char *zf); @@ -157,7 +158,7 @@ static int zonedata_init(conf_zone_t *cfg, knot_zone_t *zone) zd->xfr_in.next_id = -1; zd->xfr_in.acl = 0; zd->xfr_in.wrkr = 0; - zd->xfr_in.bootstrap_retry = 0; + zd->xfr_in.bootstrap_retry = XFRIN_BOOTSTRAP_DELAY * 1000 * tls_rand(); pthread_mutex_init(&zd->xfr_in.lock, 0); /* Initialize NOTIFY. */ @@ -169,16 +170,19 @@ static int zonedata_init(conf_zone_t *cfg, knot_zone_t *zone) if (!zd->ixfr_db) { int ret = journal_create(cfg->ixfr_db, JOURNAL_NCOUNT); if (ret != KNOTD_EOK) { - log_server_error("Failed to create journal file " - "'%s'\n", cfg->ixfr_db); + log_server_warning("Failed to create journal file " + "'%s' (%s)\n", cfg->ixfr_db, + knotd_strerror(ret)); } zd->ixfr_db = journal_open(cfg->ixfr_db, cfg->ixfr_fslimit, JOURNAL_LAZY, JOURNAL_DIRTY); } - if (zd->ixfr_db == 0) { - log_server_error("Failed to open journal file " - "'%s'\n", cfg->ixfr_db); + if (zd->ixfr_db == NULL) { + char ebuf[128] = {0}; + strerror_r(errno, ebuf, sizeof(ebuf)); + log_server_warning("Couldn't open journal file for zone '%s', " + "disabling IXFR/IN. (%s)\n", cfg->name, ebuf); } /* Initialize IXFR database syncing event. */ @@ -299,14 +303,32 @@ static int zones_expire_ev(event_t *e) rcu_read_lock(); dbg_zones("zones: EXPIRE timer event\n"); knot_zone_t *zone = (knot_zone_t *)e->data; - if (!zone) { - return KNOTD_EINVAL; - } - if (!zone->data) { + if (zone == NULL || zone->data == NULL) { return KNOTD_EINVAL; } - + zonedata_t *zd = (zonedata_t *)zone->data; + rcu_read_lock(); + + /* Do not issue SOA query if transfer is pending. */ + int locked = pthread_mutex_trylock(&zd->xfr_in.lock); + if (locked != 0) { + dbg_zones("zones: zone '%s' is being transferred, " + "deferring EXPIRE\n", + zd->conf->name); + + /* Reschedule as EXPIRE timer. */ + uint32_t exp_tmr = zones_soa_expire(zone); + evsched_schedule(e->parent, e, exp_tmr); + dbg_zones("zones: EXPIRE of '%s' after %u seconds\n", + zd->conf->name, exp_tmr / 1000); + + /* Unlock RCU. */ + rcu_read_unlock(); + return KNOTD_EOK; + } + dbg_zones_verb("zones: zone %s locked, no xfers are running\n", + zd->conf->name); /* Won't accept any pending SOA responses. */ zd->xfr_in.next_id = -1; @@ -316,23 +338,18 @@ static int zones_expire_ev(event_t *e) zd->server->nameserver->zone_db, zone->name); if (contents == NULL) { + pthread_mutex_unlock(&zd->xfr_in.lock); log_server_warning("Non-existent zone expired. Ignoring.\n"); rcu_read_unlock(); return 0; } - + /* Publish expired zone. */ rcu_read_unlock(); - - dbg_zones_verb("zones: zone %s expired, waiting for xfers to finish\n", - zd->conf->name); - pthread_mutex_lock(&zd->xfr_in.lock); - dbg_zones_verb("zones: zone %s locked, no xfers are running\n", - zd->conf->name); - synchronize_rcu(); - pthread_mutex_unlock(&zd->xfr_in.lock); + rcu_read_lock(); + /* Log event. */ log_server_info("Zone '%s' expired.\n", zd->conf->name); /* Early finish this event to prevent lockup during cancellation. */ @@ -353,6 +370,8 @@ static int zones_expire_ev(event_t *e) } knot_zone_contents_deep_free(&contents, 0); + pthread_mutex_unlock(&zd->xfr_in.lock); + rcu_read_unlock(); return 0; } @@ -364,20 +383,15 @@ static int zones_refresh_ev(event_t *e) { dbg_zones("zones: REFRESH or RETRY timer event\n"); knot_zone_t *zone = (knot_zone_t *)e->data; - if (!zone) { + if (zone == NULL || zone->data == NULL) { return KNOTD_EINVAL; } /* Cancel pending timers. */ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); - if (!zd) { - return KNOTD_EINVAL; - } - - /* Lock RCU. */ - rcu_read_lock(); /* Check for contents. */ + rcu_read_lock(); if (!knot_zone_contents(zone)) { /* Bootstrap from XFR master. */ @@ -415,8 +429,8 @@ static int zones_refresh_ev(event_t *e) return KNOTD_EOK; } - log_zone_info("Attempting to bootstrap zone %s from master\n", - zd->conf->name); +// log_zone_info("Attempting to bootstrap zone %s from master\n", +// zd->conf->name); ++zd->xfr_in.scheduled; pthread_mutex_unlock(&zd->xfr_in.lock); @@ -483,6 +497,8 @@ static int zones_refresh_ev(event_t *e) /* Create query. */ int sock = -1; + char strbuf[512] = "Generic error."; + const char *errstr = strbuf; sockaddr_t *master = &zd->xfr_in.master; int ret = xfrin_create_soa_query(zone->name, &xfr_req, &buflen); if (ret == KNOT_EOK) { @@ -496,6 +512,10 @@ static int zones_refresh_ev(event_t *e) if (bind(sock, via->ptr, via->len) < 0) { socket_close(sock); sock = -1; + char r_addr[SOCKADDR_STRLEN]; + sockaddr_tostr(via, r_addr, sizeof(r_addr)); + snprintf(strbuf, sizeof(strbuf), + "Couldn't bind to \'%s\'", r_addr); } } @@ -509,6 +529,7 @@ static int zones_refresh_ev(event_t *e) if (sent == buflen) { ret = KNOTD_EOK; } else { + strerror_r(errno, strbuf, sizeof(strbuf)); socket_close(sock); sock = -1; } @@ -523,6 +544,7 @@ static int zones_refresh_ev(event_t *e) } } else { ret = KNOTD_ERROR; + errstr = "Couldn't create SOA query"; } @@ -544,8 +566,8 @@ static int zones_refresh_ev(event_t *e) ret = xfr_request(zd->server->xfr_h, &req); } if (ret != KNOTD_EOK) { - log_server_warning("Failed to issue SOA query for zone '%s'.\n", - zd->conf->name); + log_server_warning("Failed to issue SOA query for zone '%s' (%s).\n", + zd->conf->name, errstr); } free(qbuf); @@ -564,9 +586,13 @@ static int zones_notify_send(event_t *e) dbg_notify("notify: NOTIFY timer event\n"); notify_ev_t *ev = (notify_ev_t *)e->data; - knot_zone_t *zone = ev->zone; - if (!zone) { + if (ev == NULL) { log_zone_error("NOTIFY invalid event received\n"); + return KNOTD_EINVAL; + } + knot_zone_t *zone = ev->zone; + if (zone == NULL || zone->data == NULL) { + log_zone_error("NOTIFY invalid event data received\n"); evsched_event_free(e->parent, e); free(ev); return KNOTD_EINVAL; @@ -744,17 +770,18 @@ static int zones_set_acl(acl_t **acl, list* acl_list) /* Create new ACL. */ *acl = acl_new(ACL_DENY, 0); - if (!*acl) { + if (*acl == NULL) { return KNOTD_ENOMEM; } /* Load ACL rules. */ + sockaddr_t addr; conf_remote_t *r = 0; WALK_LIST(r, *acl_list) { /* Initialize address. */ /*! Port matching disabled, port = 0. */ - sockaddr_t addr; + sockaddr_init(&addr, -1); conf_iface_t *cfg_if = r->remote; int ret = sockaddr_set(&addr, cfg_if->family, cfg_if->address, 0); @@ -988,7 +1015,7 @@ static inline uint64_t ixfrdb_key_make(uint32_t from, uint32_t to) /*----------------------------------------------------------------------------*/ -static int zones_changesets_from_binary(knot_changesets_t *chgsets) +int zones_changesets_from_binary(knot_changesets_t *chgsets) { assert(chgsets != NULL); assert(chgsets->allocated >= chgsets->count); @@ -1015,14 +1042,14 @@ static int zones_changesets_from_binary(knot_changesets_t *chgsets) * from journal) the SOA serial should already * be set, check it. */ + dbg_xfr_verb("xfr: reading RRSets to REMOVE, first RR is %hu\n", + knot_rrset_type(rrset)); assert(knot_rrset_type(rrset) == KNOT_RRTYPE_SOA); assert(chs->serial_from == knot_rdata_soa_serial(knot_rrset_rdata(rrset))); knot_changeset_store_soa(&chs->soa_from, &chs->serial_from, rrset); - dbg_xfr_verb("xfr: reading RRSets to REMOVE\n"); - /* Read remaining RRSets */ int in_remove_section = 1; while (remaining > 0) { @@ -1105,8 +1132,6 @@ static int zones_load_changesets(const knot_zone_t *zone, return KNOTD_EINVAL; } - dbg_xfr("Loading changesets from serial %u to %u\n", from, to); - /* Fetch zone-specific data. */ zonedata_t *zd = (zonedata_t *)knot_zone_data(zone); if (!zd->ixfr_db) { @@ -1114,6 +1139,11 @@ static int zones_load_changesets(const knot_zone_t *zone, return KNOTD_EINVAL; } + conf_read_lock(); + dbg_xfr("xfr: loading changesets for zone '%s' from serial %u to %u\n", + zd->conf->name, from, to); + conf_read_unlock(); + /* Retain journal for changeset loading. */ journal_t *j = journal_retain(zd->ixfr_db); @@ -1181,7 +1211,7 @@ static int zones_load_changesets(const knot_zone_t *zone, /*! \todo Check consistency. */ } - dbg_xfr_detail("xfr: Journal entries read.\n"); + dbg_xfr_detail("xfr: finished reading journal entries\n"); journal_release(j); /* Unpack binary data. */ @@ -1194,12 +1224,12 @@ static int zones_load_changesets(const knot_zone_t *zone, /* Check for complete history. */ if (to != found_to) { - dbg_xfr_detail("Returning ERANGE\n"); + dbg_xfr_detail("xfr: load changesets finished, ERANGE\n"); return KNOTD_ERANGE; } /* History reconstructed. */ - dbg_xfr_detail("Returning EOK\n"); + dbg_xfr_detail("xfr: load changesets finished, EOK\n"); return KNOTD_EOK; } @@ -1475,11 +1505,9 @@ static int zones_insert_zones(knot_nameserver_t *ns, cfg_if->family, cfg_if->address, cfg_if->port); - if (cfg_if->via) { - sockaddr_set(&zd->xfr_in.via, - cfg_if->via->family, - cfg_if->via->address, - 0); + if (sockaddr_isvalid(&cfg_if->via)) { + sockaddr_copy(&zd->xfr_in.via, + &cfg_if->via); } if (cfg_if->key) { @@ -1488,7 +1516,7 @@ static int zones_insert_zones(knot_nameserver_t *ns, sizeof(knot_key_t)); } - dbg_zones("zones: using %s:%d as XFR master " + dbg_zones("zones: using '%s@%d' as XFR master " "for '%s'\n", cfg_if->address, cfg_if->port, @@ -1690,27 +1718,28 @@ static int zones_check_tsig_query(const knot_zone_t *zone, knot_packet_additional_rrset_count(query) - 1); if (knot_rrset_type(tsig) == KNOT_RRTYPE_TSIG) { dbg_zones_verb("found TSIG in normal query\n"); - } else { - tsig = NULL; /* Invalidate if not TSIG RRTYPE. */ - } + } else { + tsig = NULL; /* Invalidate if not TSIG RRTYPE. */ + } } if (tsig == NULL) { // no TSIG, this is completely valid + /*! \note This function is (should be) called only in case of + normal query, i.e. we do not have to check ACL. + */ *tsig_rcode = 0; return KNOT_EOK; } // if there is some TSIG in the query, find the TSIG associated with // the zone - //knot_key_t *tsig_key_zone = NULL; - dbg_zones_verb("Checking zone and ACL.\n"); int ret = zones_query_check_zone(zone, addr, tsig_key_zone, rcode); - /*! \todo What if there is TSIG, but no key is configured? */ - - if (ret == KNOTD_EOK) { + + /* Accept found OR unknown key results. */ + if (ret == KNOTD_EOK || ret == KNOTD_EACCES) { if (*tsig_key_zone != NULL) { // everything OK, so check TSIG dbg_zones_verb("Verifying TSIG.\n"); @@ -1903,8 +1932,6 @@ int zones_query_check_zone(const knot_zone_t *zone, const sockaddr_t *addr, /* Check xfr-out ACL */ acl_key_t *match = NULL; if (acl_match(zd->xfr_out, addr, &match) == ACL_DENY) { - log_answer_warning("Unauthorized query or request for XFR " - "'%s/OUT'.\n", zd->conf->name); *rcode = KNOT_RCODE_REFUSED; return KNOTD_EACCES; } else { @@ -2244,7 +2271,7 @@ int zones_process_response(knot_nameserver_t *nameserver, char r_addr[SOCKADDR_STRLEN]; int r_port = sockaddr_portnum(from); sockaddr_tostr(from, r_addr, sizeof(r_addr)); - log_zone_info("SOA query of '%s' to %s:%d: Answered, no " + log_zone_info("SOA query of '%s' to '%s@%d': Answered, no " "transfer needed.\n", zd->conf->name, r_addr, r_port); rcu_read_unlock(); @@ -2257,7 +2284,7 @@ int zones_process_response(knot_nameserver_t *nameserver, assert(ret > 0); /* Already transferring. */ - int xfrtype = zones_transfer_to_use(contents); + int xfrtype = zones_transfer_to_use(zd); if (pthread_mutex_trylock(&zd->xfr_in.lock) != 0) { /* Unlock zone contents. */ dbg_zones("zones: SOA response received, but zone is " @@ -2299,9 +2326,12 @@ int zones_process_response(knot_nameserver_t *nameserver, /*----------------------------------------------------------------------------*/ -knot_ns_xfr_type_t zones_transfer_to_use(const knot_zone_contents_t *zone) +knot_ns_xfr_type_t zones_transfer_to_use(zonedata_t *data) { - /*! \todo Implement. */ + if (data == NULL || data->ixfr_db == NULL) { + return XFR_TYPE_AIN; + } + return XFR_TYPE_IIN; } @@ -2565,235 +2595,343 @@ int zones_ns_conf_hook(const struct conf_t *conf, void *data) } /*----------------------------------------------------------------------------*/ +/* Counting size of changeset in serialized form. */ +/*----------------------------------------------------------------------------*/ -static int zones_check_binary_size(uint8_t **data, size_t *allocated, - size_t required) +static inline size_t zones_dname_binary_size(const knot_dname_t *dname) { - if (required <= *allocated) { - return KNOTD_EOK; + if (dname == NULL) { + return 0; } - /* Allocate new memory block. */ - size_t new_count = required; - uint8_t *new_data = malloc(new_count * sizeof(uint8_t)); - if (new_data == NULL) { - return KNOTD_ENOMEM; + size_t size = 10; // 4B ID, 4B size, 2B label count + + // dname size in wire format + size += knot_dname_size(dname); + // label array size + size += knot_dname_label_count(dname); + + return size; +} + +/*----------------------------------------------------------------------------*/ + +static size_t zones_rdata_binary_size(const knot_rdata_t *rdata, + knot_rrtype_descriptor_t *desc) +{ + if (rdata == NULL) { + return 0; } - /* Clear memory block and copy old data. */ - memset(new_data, 0, new_count * sizeof(uint8_t)); - memcpy(new_data, *data, *allocated); + assert(desc != NULL); - /* Switch pointers and free old pointer. */ - free(*data); - *data = new_data; - *allocated = new_count; + size_t size = sizeof(unsigned int); // RDATA item count - return KNOTD_EOK; + for (int i = 0; i < rdata->count; ++i) { + if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME + || desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME + || desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME) { + size += zones_dname_binary_size(rdata->items[i].dname); + size += 2; // flags + } else { + if (rdata->items[i].raw_data != NULL) { + size += rdata->items[i].raw_data[0] + 2; + } + } + } + + return size; } /*----------------------------------------------------------------------------*/ -static int zones_changeset_rrset_to_binary(uint8_t **data, size_t *size, - size_t *allocated, - knot_rrset_t *rrset) +static size_t zones_rrset_binary_size(const knot_rrset_t *rrset) { - assert(data != NULL); - assert(size != NULL); - assert(allocated != NULL); + assert(rrset != NULL); - /* - * In *data, there is the whole changeset in the binary format, - * the actual RRSet will be just appended to it - */ + size_t size = 0; + + size += 13; // 2B type, 2B class, 4B TTL, 4B RDATA count, 1B flags + size += zones_dname_binary_size(rrset->owner); + + knot_rrtype_descriptor_t *desc = knot_rrtype_descriptor_by_type( + knot_rrset_type(rrset)); + assert(desc != NULL); + + const knot_rdata_t *rdata = knot_rrset_rdata(rrset); + while (rdata != NULL) { + size += zones_rdata_binary_size(rdata, desc); + rdata = knot_rrset_rdata_next(rrset, rdata); + } + + return size; +} + +/*----------------------------------------------------------------------------*/ - uint8_t *binary = NULL; - size_t actual_size = 0; - int ret = knot_zdump_rrset_serialize(rrset, &binary, &actual_size); - if (ret != KNOT_EOK || binary == NULL) { +int zones_changeset_binary_size(const knot_changeset_t *chgset, size_t *size) +{ + if (chgset == NULL || size == NULL) { + return KNOTD_EINVAL; + } + + size_t soa_from_size = zones_rrset_binary_size(chgset->soa_from); + size_t soa_to_size = zones_rrset_binary_size(chgset->soa_to); + + size_t remove_size = 0; + for (int i = 0; i < chgset->remove_count; ++i) + { + remove_size += zones_rrset_binary_size(chgset->remove[i]); + } + + size_t add_size = 0; + for (int i = 0; i < chgset->add_count; ++i) + { + add_size += zones_rrset_binary_size(chgset->add[i]); + } + + /*! \todo How is the changeset serialized? Any other parts? */ + *size += soa_from_size + soa_to_size + remove_size + add_size; + + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ +/* Changeset serialization and storing (new) */ +/*----------------------------------------------------------------------------*/ + +static int zones_rrset_write_to_mem(const knot_rrset_t *rr, char **entry, + size_t *remaining) { + size_t written = 0; + int ret = knot_zdump_rrset_serialize(rr, *((uint8_t **)entry), + *remaining, &written); + if (ret == KNOT_EOK) { + assert(written <= *remaining); + *remaining -= written; + *entry += written; + } + + return ret; +} + +static int zones_serialize_and_store_chgset(const knot_changeset_t *chs, + char *entry, size_t max_size) +{ + /* Serialize SOA 'from'. */ + int ret = zones_rrset_write_to_mem(chs->soa_from, &entry, &max_size); + if (ret != KNOT_EOK) { dbg_zones("knot_zdump_rrset_serialize() returned %s\n", knot_strerror(ret)); return KNOTD_ERROR; /*! \todo Other code? */ } - ret = zones_check_binary_size(data, allocated, *size + actual_size); - if (ret != KNOTD_EOK) { - free(binary); - return ret; + /* Serialize RRSets from the 'remove' section. */ + for (int i = 0; i < chs->remove_count; ++i) { + ret = zones_rrset_write_to_mem(chs->remove[i], &entry, &max_size); + if (ret != KNOT_EOK) { + dbg_zones("knot_zdump_rrset_serialize() returned %s\n", + knot_strerror(ret)); + return KNOTD_ERROR; /*! \todo Other code? */ + } + } + + /* Serialize SOA 'to'. */ + ret = zones_rrset_write_to_mem(chs->soa_to, &entry, &max_size); + if (ret != KNOT_EOK) { + dbg_zones("knot_zdump_rrset_serialize() returned %s\n", + knot_strerror(ret)); + return KNOTD_ERROR; /*! \todo Other code? */ + } + + /* Serialize RRSets from the 'add' section. */ + for (int i = 0; i < chs->add_count; ++i) { + ret = zones_rrset_write_to_mem(chs->add[i], &entry, &max_size); + if (ret != KNOT_EOK) { + dbg_zones("knot_zdump_rrset_serialize() returned %s\n", + knot_strerror(ret)); + return KNOTD_ERROR; /*! \todo Other code? */ + } + } - memcpy(*data + *size, binary, actual_size); - *size += actual_size; - free(binary); return KNOTD_EOK; } /*----------------------------------------------------------------------------*/ -int zones_changesets_to_binary(knot_changesets_t *chgsets) +static int zones_store_changeset(const knot_changeset_t *chs, journal_t *j, + knot_zone_t *zone, zonedata_t *zd) { - assert(chgsets != NULL); - assert(chgsets->allocated >= chgsets->count); + assert(chs != NULL); + assert(j != NULL); - /* - * Converts changesets to the binary format stored in chgsets->data - * from the changeset_t structures. - */ - int ret; + dbg_xfr("Saving changeset from %u to %u.\n", + chs->serial_from, chs->serial_to); - for (int i = 0; i < chgsets->count; ++i) { - knot_changeset_t *ch = &chgsets->sets[i]; - assert(ch->data == NULL); - assert(ch->size == 0); + uint64_t k = ixfrdb_key_make(chs->serial_from, chs->serial_to); - /* 1) origin SOA */ - ret = zones_changeset_rrset_to_binary(&ch->data, &ch->size, - &ch->allocated, ch->soa_from); - if (ret != KNOTD_EOK) { - free(ch->data); - ch->data = NULL; - dbg_zones("zones_changeset_rrset_to_binary(): %s\n", - knot_strerror(ret)); - return ret; - } + /* Count the size of the entire changeset in serialized form. */ + size_t entry_size = 0; - int j; - - /* 2) remove RRsets */ - assert(ch->remove_allocated >= ch->remove_count); - for (j = 0; j < ch->remove_count; ++j) { - ret = zones_changeset_rrset_to_binary(&ch->data, - &ch->size, - &ch->allocated, - ch->remove[j]); - if (ret != KNOTD_EOK) { - free(ch->data); - ch->data = NULL; - dbg_zones("zones_changeset_rrset_to_binary(): %s\n", - knot_strerror(ret)); - return ret; - } + int ret = zones_changeset_binary_size(chs, &entry_size); + assert(ret == KNOTD_EOK); + + dbg_xfr_verb("Size in serialized form: %zu\n", entry_size); + + /* Reserve space for the journal entry. */ + char *journal_entry = NULL; + ret = journal_map(j, k, &journal_entry, entry_size); + + /* Sync to zonefile may be needed. */ + while (ret == KNOTD_EAGAIN) { + /* Cancel sync timer. */ + event_t *tmr = zd->ixfr_dbsync; + if (tmr) { + dbg_xfr_verb("xfr: cancelling zonefile " + "SYNC timer of '%s'\n", + zd->conf->name); + evsched_cancel(tmr->parent, tmr); } - /* 3) new SOA */ - ret = zones_changeset_rrset_to_binary(&ch->data, &ch->size, - &ch->allocated, ch->soa_to); - if (ret != KNOTD_EOK) { - free(ch->data); - ch->data = NULL; - dbg_zones("zones_changeset_rrset_to_binary(): %s\n", - knot_strerror(ret)); - return ret; + /* Synchronize. */ + dbg_xfr_verb("xfr: forcing zonefile SYNC " + "of '%s'\n", + zd->conf->name); + ret = zones_zonefile_sync(zone, j); + if (ret != KNOTD_EOK && ret != KNOTD_ERANGE) { + continue; } - /* 4) add RRsets */ - assert(ch->add_allocated >= ch->add_count); - for (j = 0; j < ch->add_count; ++j) { - ret = zones_changeset_rrset_to_binary(&ch->data, - &ch->size, - &ch->allocated, - ch->add[j]); - if (ret != KNOTD_EOK) { - free(ch->data); - ch->data = NULL; - dbg_zones("zones_changeset_rrset_to_binary(): %s\n", - knot_strerror(ret)); - return ret; - } + /* Reschedule sync timer. */ + if (tmr) { + /* Fetch sync timeout. */ + conf_read_lock(); + int timeout = zd->conf->dbsync_timeout; + timeout *= 1000; /* Convert to ms. */ + conf_read_unlock(); + + /* Reschedule. */ + dbg_xfr_verb("xfr: resuming SYNC " + "of '%s'\n", + zd->conf->name); + evsched_schedule(tmr->parent, tmr, + timeout); + } + + /* Attempt to map again. */ + ret = journal_map(j, k, &journal_entry, entry_size); } - return KNOTD_EOK; + if (ret != KNOTD_EOK) { + dbg_xfr("Failed to map space for journal entry: %s.\n", + knotd_strerror(ret)); + return ret; + } + + assert(journal_entry != NULL); + + /* Serialize changeset, saving it bit by bit. */ + ret = zones_serialize_and_store_chgset(chs, journal_entry, entry_size); + + if (ret != KNOTD_EOK) { + dbg_xfr("Failed to serialize and store changeset: %s\n", + knotd_strerror(ret)); + } + + /* Unmap the journal entry. + If successfuly written changeset to journal, validate the entry. */ + ret = journal_unmap(j, k, journal_entry, ret == KNOTD_EOK); + + return ret; } /*----------------------------------------------------------------------------*/ -int zones_store_changesets(knot_ns_xfr_t *xfr) +journal_t *zones_store_changesets_begin(knot_ns_xfr_t *xfr) { if (xfr == NULL || xfr->data == NULL || xfr->zone == NULL) { - return KNOTD_EINVAL; + return NULL; } - - knot_zone_t *zone = xfr->zone; - knot_changesets_t *src = (knot_changesets_t *)xfr->data; /* Fetch zone-specific data. */ + knot_zone_t *zone = xfr->zone; zonedata_t *zd = (zonedata_t *)zone->data; if (!zd->ixfr_db) { - return KNOTD_EINVAL; + return NULL; } - /* Retain journal for changeset loading. */ + /* Begin transaction, will be release on commit/rollback. */ journal_t *j = journal_retain(zd->ixfr_db); + if (journal_trans_begin(j) != KNOTD_EOK) { + journal_release(j); + j = NULL; + } - /* Begin writing to journal. */ - for (unsigned i = 0; i < src->count; ++i) { + return j; +} - /* Make key from serials. */ - knot_changeset_t* chs = src->sets + i; - uint64_t k = ixfrdb_key_make(chs->serial_from, chs->serial_to); +/*----------------------------------------------------------------------------*/ - /* Write entry. */ - int ret = journal_write(j, k, (const char*)chs->data, chs->size); +int zones_store_changesets_commit(journal_t *j) +{ + if (j == NULL) { + return KNOTD_EINVAL; + } + + int ret = journal_trans_commit(j); + journal_release(j); + return ret; +} - /* Check for errors. */ - while (ret != KNOTD_EOK) { +/*----------------------------------------------------------------------------*/ - /* Sync to zonefile may be needed. */ - if (ret == KNOTD_EAGAIN) { +int zones_store_changesets_rollback(journal_t *j) +{ + if (j == NULL) { + return KNOTD_EINVAL; + } + + int ret = journal_trans_rollback(j); + journal_release(j); + return ret; +} - /* Cancel sync timer. */ - event_t *tmr = zd->ixfr_dbsync; - if (tmr) { - dbg_xfr_verb("xfr: cancelling zonefile " - "SYNC timer of '%s'\n", - zd->conf->name); - evsched_cancel(tmr->parent, tmr); - } +/*----------------------------------------------------------------------------*/ - /* Synchronize. */ - dbg_xfr_verb("xfr: forcing zonefile SYNC " - "of '%s'\n", - zd->conf->name); - ret = zones_zonefile_sync(zone, j); - if (ret != KNOTD_EOK && ret != KNOTD_ERANGE) { - continue; - } +int zones_store_changesets(knot_ns_xfr_t *xfr) +{ + if (xfr == NULL || xfr->data == NULL || xfr->zone == NULL) { + return KNOTD_EINVAL; + } - /* Reschedule sync timer. */ - if (tmr) { - /* Fetch sync timeout. */ - conf_read_lock(); - int timeout = zd->conf->dbsync_timeout; - timeout *= 1000; /* Convert to ms. */ - conf_read_unlock(); - - /* Reschedule. */ - dbg_xfr_verb("xfr: resuming SYNC " - "of '%s'\n", - zd->conf->name); - evsched_schedule(tmr->parent, tmr, - timeout); + knot_zone_t *zone = xfr->zone; + knot_changesets_t *src = (knot_changesets_t *)xfr->data; - } + /* Fetch zone-specific data. */ + zonedata_t *zd = (zonedata_t *)zone->data; + if (!zd->ixfr_db) { + return KNOTD_EINVAL; + } - /* Attempt to write again. */ - ret = journal_write(j, k, (const char*)chs->data, - chs->size); - } else { - /* Other errors. */ - journal_release(j); - return KNOTD_ERROR; - } - } + /* Retain journal for changeset writing. */ + journal_t *j = journal_retain(zd->ixfr_db); + + int ret = 0; + + /* Begin writing to journal. */ + for (unsigned i = 0; i < src->count; ++i) { + /* Make key from serials. */ + knot_changeset_t* chs = src->sets + i; - /* Free converted binary data. */ - free(chs->data); - chs->data = 0; - chs->size = 0; + ret = zones_store_changeset(chs, j, zone, zd); + if (ret != KNOTD_EOK) { + journal_release(j); + return ret; + } } - + /* Release journal. */ journal_release(j); @@ -2825,13 +2963,12 @@ int zones_xfr_load_changesets(knot_ns_xfr_t *xfr, uint32_t serial_from, return KNOTD_EOK; } - dbg_zones("Loading changesets...\n"); - + dbg_xfr_verb("xfr: loading changesets\n"); ret = zones_load_changesets(xfr->zone, chgsets, serial_from, serial_to); if (ret != KNOTD_EOK) { - dbg_zones_verb("Loading changesets failed: %s\n", - knotd_strerror(ret)); + dbg_xfr("xfr: failed to load changesets: %s\n", + knotd_strerror(ret)); knot_free_changesets(&chgsets); return ret; } @@ -2934,15 +3071,17 @@ int zones_timers_update(knot_zone_t *zone, conf_zone_t *cfzone, evsched_t *sch) int ret = sockaddr_set(&ev->addr, cfg_if->family, cfg_if->address, cfg_if->port); - conf_iface_t *via = cfg_if->via; - if (ret > 0 && via != NULL) { - ret = sockaddr_set(&ev->saddr, via->family, - via->address, 0); - } - if (ret < 1) { + sockaddr_t *via = &cfg_if->via; + if (ret > 0) { + if (sockaddr_isvalid(via)) { + sockaddr_copy(&ev->saddr, via); + } + } else { free(ev); - dbg_zones("notify: NOTIFY slave %s has invalid " - "address\n", cfg_if->name); + log_server_warning("NOTIFY slave '%s' has invalid " + "address '%s@%d', couldn't create" + "query.\n", cfg_if->name, + cfg_if->address, cfg_if->port); continue; } @@ -2961,7 +3100,7 @@ int zones_timers_update(knot_zone_t *zone, conf_zone_t *cfzone, evsched_t *sch) pthread_mutex_unlock(&zd->lock); log_server_info("Scheduled '%s' NOTIFY query " - "after %d s to %s:%d\n", zd->conf->name, + "after %d s to '%s@%d'.\n", zd->conf->name, tmr_s, cfg_if->address, cfg_if->port); } diff --git a/src/knot/server/zones.h b/src/knot/server/zones.h index 8421f30..08f9df6 100644 --- a/src/knot/server/zones.h +++ b/src/knot/server/zones.h @@ -174,13 +174,12 @@ int zones_process_response(knot_nameserver_t *nameserver, /*! * \brief Decides what type of transfer should be used to update the given zone. - * - * \param nameserver Name server structure that uses the zone. - * \param zone Zone to be updated by the transfer. + *. + * \param data Zone data for associated zone. * * \retval */ -knot_ns_xfr_type_t zones_transfer_to_use(const knot_zone_contents_t *zone); +knot_ns_xfr_type_t zones_transfer_to_use(zonedata_t *data); int zones_save_zone(const knot_ns_xfr_t *xfr); @@ -212,9 +211,40 @@ int zones_ns_conf_hook(const struct conf_t *conf, void *data); * \retval KNOTD_EAGAIN if journal needs to be synced with zonefile first. * * \todo Expects the xfr structure to be initialized in some way. + * \todo Update documentation!!! */ int zones_store_changesets(knot_ns_xfr_t *xfr); +/*! + * \brief Begin changesets storing transaction. + * + * \retval pointer to journal if successful + * \retval NULL on failure. + */ +journal_t *zones_store_changesets_begin(knot_ns_xfr_t *xfr); + +/*! + * \brief Commit stored changesets. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_ENOENT when no transaction is pending. + */ +int zones_store_changesets_commit(journal_t *j); + +/*! + * \brief Rollback stored changesets. + * + * \retval KNOTD_EOK on success. + * \retval KNOTD_EINVAL on invalid parameters. + * \retval KNOTD_ENOENT when no transaction is pending. + */ +int zones_store_changesets_rollback(journal_t *j); + +/*! \todo Document me. */ +int zones_changesets_from_binary(knot_changesets_t *chgsets); + +/*! \todo Document me. */ int zones_changesets_to_binary(knot_changesets_t *chgsets); /*! diff --git a/src/knot/stat/gatherer.c b/src/knot/stat/gatherer.c index e8048a1..5b8eab6 100644 --- a/src/knot/stat/gatherer.c +++ b/src/knot/stat/gatherer.c @@ -16,9 +16,11 @@ #include <config.h> #include <pthread.h> +#include <stdlib.h> +#include <string.h> #include "knot/stat/stat-common.h" -#include "common/slab/malloc.h" +#include "common/mempattern.h" #include "knot/stat/gatherer.h" gatherer_t *new_gatherer() diff --git a/src/knot/zone/semantic-check.c b/src/knot/zone/semantic-check.c index f900951..fc20c29 100644 --- a/src/knot/zone/semantic-check.c +++ b/src/knot/zone/semantic-check.c @@ -5,6 +5,7 @@ #include "knot/common.h" #include "knot/zone/zone-dump.h" #include "knot/other/error.h" +#include "knot/other/debug.h" #include "libknot/libknot.h" #include "common/base32hex.h" #include "common/crc.h" @@ -15,6 +16,8 @@ static char *error_messages[(-ZC_ERR_ALLOC) + 1] = { [-ZC_ERR_ALLOC] = "Memory allocation error!\n", [-ZC_ERR_MISSING_SOA] = "SOA record missing in zone!\n", + [-ZC_ERR_MISSING_NS_DEL_POINT] = "NS record missing in zone apex or in " + "delegation point!\n", [-ZC_ERR_RRSIG_RDATA_TYPE_COVERED] = "RRSIG: Type covered rdata field is wrong!\n", @@ -63,6 +66,9 @@ static char *error_messages[(-ZC_ERR_ALLOC) + 1] = { "NSEC3: NSEC3 chain is not coherent!\n", [-ZC_ERR_NSEC3_RDATA_BITMAP] = "NSEC3: NSEC3 bitmap error!\n", + [-ZC_ERR_NSEC3_EXTRA_RECORD] = + "NSEC3: NSEC3 node contains extra record. This is valid, however Knot " + "will not serve this record properly.\n", [-ZC_ERR_CNAME_CYCLE] = "CNAME: CNAME cycle!\n", @@ -90,9 +96,9 @@ static char *error_messages[(-ZC_ERR_ALLOC) + 1] = { specified otherwise */ [-ZC_ERR_GLUE_NODE] = - "GLUE: Node with Glue record missing!\n", + "GLUE: Node with glue record missing!\n", [-ZC_ERR_GLUE_RECORD] = - "GLUE: Record with Glue address missing\n", + "GLUE: Record with glue address missing\n", }; static const uint MAX_CNAME_CYCLE_DEPTH = 15; @@ -140,7 +146,11 @@ static void log_error_from_node(err_handler_t *handler, char *name = knot_dname_to_str(knot_node_owner(node)); fprintf(stderr, "Semantic warning in node: %s: ", name); - fprintf(stderr, "%s", error_messages[-error]); + if (error_messages[-error] != NULL) { + fprintf(stderr, "%s", error_messages[-error]); + } else { + fprintf(stderr, "Unknown error (%d).\n", error); + } free(name); } else { fprintf(stderr, "Total number of warnings is: %d for error: %s", @@ -171,6 +181,7 @@ int err_handler_handle_error(err_handler_t *handler, (error < ZC_ERR_GENERIC_GENERAL_ERROR)) { /* The two errors before SOA were handled */ log_error_from_node(handler, node, error); + return KNOT_EOK; } else if ((error < ZC_ERR_RRSIG_GENERAL_ERROR) && ((handler->errors[-error] == 0) || @@ -310,12 +321,19 @@ static int check_cname_cycles_in_zone(knot_zone_contents_t *zone, knot_dname_t *tmp_chopped = knot_dname_left_chop(next_dname_copy); - knot_dname_free(&next_dname_copy); - if (!tmp_chopped) { + if (!tmp_chopped && + !(knot_dname_is_fqdn(next_dname_copy) && + knot_dname_label_count(next_dname_copy) == 0)) { knot_dname_free(&chopped_wc); knot_dname_free(&next_dname_copy); return KNOT_ERROR; + } else if ((knot_dname_is_fqdn(next_dname_copy) && + knot_dname_label_count(next_dname_copy) == 0)) { + knot_dname_free(&next_dname_copy); + /* Root domain, end of search. */ + break; } + knot_dname_free(&next_dname_copy); cut_offs++; @@ -973,7 +991,8 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone, knot_node_t *nod /* Directly discard. */ knot_dname_free(&next_dname); - + + /*!< \todo These comments are not accurate anymore. */ /* This is probably not sufficient, but again, it is covered in * zone load time */ @@ -999,14 +1018,21 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone, knot_node_t *nod type) == NULL) { err_handler_handle_error(handler, node, ZC_ERR_NSEC3_RDATA_BITMAP); -/* char *name = - knot_dname_to_str( - log_zone_error("Node %s does " - "not contain RRSet of type %s " - "but NSEC bitmap says " - "it does!\n", name, - knot_rrtype_to_string(type)); - free(name); */ + } + } + + /* Check that the node only contains NSEC3 and RRSIG. */ + const knot_rrset_t **rrsets = knot_node_rrsets(nsec3_node); + if (rrsets == NULL) { + return KNOT_ENOMEM; + } + + for (int i = 0; i < knot_node_rrset_count(nsec3_node); i++) { + uint16_t type = knot_rrset_type(rrsets[i]); + if (!(type == KNOT_RRTYPE_NSEC3 || + type == KNOT_RRTYPE_RRSIG)) { + err_handler_handle_error(handler, nsec3_node, + ZC_ERR_NSEC3_EXTRA_RECORD); } } @@ -1143,15 +1169,21 @@ static int semantic_checks_plain(knot_zone_contents_t *zone, return KNOT_EOK; } + /*!< \todo Good Lord, move this to ist own function. */ - /* check for glue records at zone cuts */ - if (knot_node_is_deleg_point(node)) { + /* check for glue records at zone cuts and in apex. */ + if (knot_node_is_deleg_point(node) || knot_zone_contents_apex(zone) == + node) { const knot_rrset_t *ns_rrset = knot_node_rrset(node, KNOT_RRTYPE_NS); - assert(ns_rrset); + if (ns_rrset == NULL) { + err_handler_handle_error(handler, node, + ZC_ERR_MISSING_NS_DEL_POINT); + return KNOT_EOK; + } //FIXME this should be an error as well ! (i guess) - const knot_dname_t *ns_dname = + knot_dname_t *ns_dname = knot_rdata_get_item(knot_rrset_rdata (ns_rrset), 0)->dname; @@ -1159,12 +1191,41 @@ static int semantic_checks_plain(knot_zone_contents_t *zone, const knot_node_t *glue_node = knot_zone_contents_find_node(zone, ns_dname); - + if (knot_dname_is_subdomain(ns_dname, knot_node_owner(knot_zone_contents_apex(zone)))) { if (glue_node == NULL) { - err_handler_handle_error(handler, node, + /* Try wildcard. */ + knot_dname_t *wildcard = + knot_dname_new_from_str("*", 1, NULL); + if (wildcard == NULL) { + return KNOT_ENOMEM; + } + + knot_dname_left_chop_no_copy(ns_dname); + + if (knot_dname_cat(wildcard, + ns_dname) == NULL) { + knot_dname_free(&wildcard); + return KNOT_ENOMEM; + } + + const knot_node_t *wildcard_node = + knot_zone_contents_find_node(zone, + wildcard); + if (wildcard_node == NULL) { + err_handler_handle_error(handler, node, ZC_ERR_GLUE_NODE); + } else { + /* Look for A or AAAA. */ + if ((knot_node_rrset(wildcard_node, + KNOT_RRTYPE_A) == NULL) && + (knot_node_rrset(wildcard_node, + KNOT_RRTYPE_AAAA) == NULL)) { + err_handler_handle_error(handler, node, + ZC_ERR_GLUE_RECORD); + } + } } else { if ((knot_node_rrset(glue_node, KNOT_RRTYPE_A) == NULL) && @@ -1276,15 +1337,6 @@ static int semantic_checks_dnssec(knot_zone_contents_t *zone, err_handler_handle_error(handler, node, ZC_ERR_NSEC_RDATA_MULTIPLE); - /* CLEANUP */ -/* char *name = - knot_dname_to_str( - knot_node_owner(node)); - log_zone_error("Node %s contains more " - "than one NSEC " - "record!\n", name); - knot_rrset_dump(nsec_rrset, 0); - free(name); */ } /* @@ -1308,9 +1360,6 @@ static int semantic_checks_dnssec(knot_zone_contents_t *zone, err_handler_handle_error(handler, node, ZC_ERR_NSEC_RDATA_CHAIN); - /* CLEANUP */ -/* log_zone_error("NSEC chain is not " - "coherent!\n"); */ } if (knot_dname_compare(next_domain, @@ -1344,6 +1393,8 @@ static int semantic_checks_dnssec(knot_zone_contents_t *zone, */ static void do_checks_in_tree(knot_node_t *node, void *data) { + dbg_semcheck_verb("semcheck: do_check_in_tree: Checking node: %s\n", + knot_dname_to_str(node->owner)); assert(data != NULL); arg_t *args = (arg_t *)data; diff --git a/src/knot/zone/semantic-check.h b/src/knot/zone/semantic-check.h index 08396c8..17b774f 100644 --- a/src/knot/zone/semantic-check.h +++ b/src/knot/zone/semantic-check.h @@ -36,6 +36,7 @@ enum zonechecks_errors { ZC_ERR_UNKNOWN, ZC_ERR_MISSING_SOA, + ZC_ERR_MISSING_NS_DEL_POINT, ZC_ERR_GENERIC_GENERAL_ERROR, /* isn't there a better name? */ @@ -67,6 +68,7 @@ enum zonechecks_errors { ZC_ERR_NSEC3_RDATA_TTL, ZC_ERR_NSEC3_RDATA_CHAIN, ZC_ERR_NSEC3_RDATA_BITMAP, + ZC_ERR_NSEC3_EXTRA_RECORD, ZC_ERR_NSEC3_GENERAL_ERROR, @@ -101,6 +103,7 @@ struct arg { void *arg5; /* last node */ void *arg6; /* error handler */ void *arg7; /* CRC */ + int error_code; /* Error code. */ }; typedef struct arg arg_t; diff --git a/src/knot/zone/zone-dump.c b/src/knot/zone/zone-dump.c index 6ca969f..64b743c 100644 --- a/src/knot/zone/zone-dump.c +++ b/src/knot/zone/zone-dump.c @@ -55,9 +55,12 @@ static inline int write_to_file_crc(const void *src, size_t size, size_t n, int fd, crc_t *crc) { + if (src == NULL || fd < 0) { + return KNOT_EBADARG; + } ssize_t rc = write(fd, src, size * n); if (rc != size * n) { - fprintf(stderr, "fwrite: invalid write %zu (expected %zu)\n", rc, + fprintf(stderr, "write: invalid write %zu (expected %zu)\n", rc, n); } @@ -67,48 +70,66 @@ static inline int write_to_file_crc(const void *src, size * n); } - /* - * It was meant differtely, caller function does not - * care how many bytes had been written, it just cares about - * success/fail (not that it is checked anyway) (#1684). - */ - return rc == n; - + return rc == size * n; } static inline int write_to_stream(const void *src, - size_t size, size_t n, - uint8_t **stream, - size_t *stream_size) + size_t size, size_t n, + uint8_t *stream, + size_t max_size, + size_t *written_bytes) { - /* Resize the stream */ - void *tmp = realloc(*stream, - (*stream_size + (size * n)) * sizeof(uint8_t)); - if (tmp != NULL) { - *stream = tmp; - memcpy(*stream + *stream_size, src, - size * n); - *stream_size += (size * n) * sizeof(uint8_t); - return KNOT_EOK; - } else { - free(*stream); - *stream = NULL; - return KNOT_ENOMEM; + if (src == NULL || stream == NULL || written_bytes == NULL) { + return KNOT_EBADARG; } - + + /* Check that the stream boundary will not be crossed. */ + if (*written_bytes + (size * n) > max_size) { + /* Buffer overflown. */ + dbg_zdump("zdump: write_to_stream: Cannot write to stream, no " + "space left.\n"); + return KNOT_ERANGE; + } + + /* Do the actual write. */ + memcpy(stream + *written_bytes, src, size * n); + /* Expand size. */ + *written_bytes += (size * n); + return KNOT_EOK; } static int write_wrapper(const void *src, - size_t size, size_t n, int fd, - uint8_t **stream, size_t *stream_size, crc_t *crc) + size_t size, size_t n, int fd, + uint8_t *stream, size_t max_size, + size_t *written_bytes, crc_t *crc) { + if (src == NULL) { + dbg_zdump("zdump: write_wrapper: NULL source.\n"); + return KNOT_EBADARG; + } + + dbg_zdump_detail("zdump: write_wrapper: Writing %d bytes to fd: %d.\n", + size * n, fd); + if (fd < 0) { - assert(stream && stream_size); + assert(stream && written_bytes); assert(crc == NULL); - return write_to_stream(src, size, n, stream, stream_size); + /*!< \todo To comply with calling convention of write_wrapper, + * we have to lose the error. */ + int ret = write_to_stream(src, size, n, stream, max_size, + written_bytes); + if (ret != KNOT_EOK) { + dbg_zdump("zdump: write_wrapper: Could not write to " + "stream. Reason: %s.\n", knot_strerror(ret)); + /* Intentional! */ + return 0; + } else { + /* Intentional! */ + return 1; + } } else { - assert(stream == NULL && stream_size == NULL); + assert(stream == NULL && written_bytes == NULL); return write_to_file_crc(src, size, n, fd, crc); } } @@ -119,18 +140,30 @@ static int write_wrapper(const void *src, * \param dname Dname whose labels are to be dumped. * \param f Output file. */ -static void knot_labels_dump_binary(const knot_dname_t *dname, int fd, - uint8_t **stream, size_t *stream_size, - crc_t *crc) +static int knot_labels_dump_binary(const knot_dname_t *dname, int fd, + uint8_t *stream, size_t max_size, + size_t *written_bytes, crc_t *crc) { - dbg_zdump("label count: %d\n", dname->label_count); + if (dname == NULL) { + dbg_zdump("zdump: dump_labels: NULL dname.\n"); + return KNOT_EBADARG; + } + uint16_t label_count = dname->label_count; - /*!< \todo #1684 check the return value */ - write_wrapper(&label_count, sizeof(label_count), 1, fd, stream, - stream_size, crc); - /*!< \todo #1684 check the return value */ - write_wrapper(dname->labels, sizeof(uint8_t), dname->label_count, fd, - stream, stream_size, crc); + if (!write_wrapper(&label_count, sizeof(label_count), 1, fd, stream, + max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_labels: Could not write label count.\n"); + return KNOT_ERROR; + } + + if (!write_wrapper(dname->labels, sizeof(uint8_t), dname->label_count, + fd, stream, max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_labels: Could not write labels.\n"); + return KNOT_ERROR; + } + + dbg_zdump_verb("zdump: dump_labels: Labels dumped successfully.\n"); + return KNOT_EOK; } /*! @@ -139,33 +172,53 @@ static void knot_labels_dump_binary(const knot_dname_t *dname, int fd, * \param dname Dname to be dumped. * \param f Output file. */ -static void knot_dname_dump_binary(const knot_dname_t *dname, int fd, - uint8_t **stream, size_t *stream_size, - crc_t *crc) +static int knot_dname_dump_binary(const knot_dname_t *dname, int fd, + uint8_t *stream, size_t max_size, + size_t *written_bytes, + crc_t *crc) { + if (dname == NULL) { + dbg_zdump("zdump: dump_dname: NULL dname.\n"); + return KNOT_EBADARG; + } + + /*! \todo too big */ uint32_t dname_size = dname->size; - /*!< \todo #1684 check the return value */ - write_wrapper(&dname_size, sizeof(dname_size), 1, fd, stream, - stream_size, crc); - /*!< \todo #1684 check the return value */ - write_wrapper(dname->name, sizeof(uint8_t), dname->size, fd, - stream, stream_size, crc); - dbg_zdump("dname size: %d\n", dname->size); - knot_labels_dump_binary(dname, fd, stream, stream_size, crc); + if (!write_wrapper(&dname_size, sizeof(dname_size), 1, fd, stream, + max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_dname: Cannot write dname size.\n"); + return KNOT_ERROR; + } + + if (!write_wrapper(dname->name, sizeof(uint8_t), dname->size, fd, + stream, max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_dname: Cannot write dname name.\n"); + return KNOT_ERROR; + } + + dbg_zdump_verb("zdump: dump_dname: Dname dumped successfully.\n"); + return knot_labels_dump_binary(dname, fd, stream, max_size, + written_bytes, crc); } /*!< \todo #1684 some global variable indicating error! */ -static void dump_dname_with_id(const knot_dname_t *dname, int fd, - uint8_t **stream, size_t *stream_size, - crc_t *crc) +static int dump_dname_with_id(const knot_dname_t *dname, int fd, + uint8_t *stream, size_t max_size, + size_t *written_bytes, crc_t *crc) { + if (dname == NULL) { + dbg_zdump("zdump: dump_dname: NULL dname.\n"); + return KNOT_EBADARG; + } + uint32_t id = dname->id; - /*!< \todo #1684 check the return value */ - write_wrapper(&id, sizeof(id), 1, fd, stream, stream_size, crc); - knot_dname_dump_binary(dname, fd, stream, stream_size, crc); -/* if (!write_wrapper_safe(&dname->id, sizeof(dname->id), 1, f)) { + if (!write_wrapper(&id, sizeof(id), 1, fd, stream, max_size, + written_bytes, crc)) { + dbg_zdump("zdump: dump_dname: Cannot write ID.\n"); return KNOT_ERROR; - } */ + } + return knot_dname_dump_binary(dname, fd, stream, max_size, + written_bytes, crc); } /*! @@ -175,32 +228,39 @@ static void dump_dname_with_id(const knot_dname_t *dname, int fd, * \param type Type of rdata. * \param data Arguments to be propagated. */ -static void knot_rdata_dump_binary(knot_rdata_t *rdata, - uint32_t type, int fd, int use_ids, - uint8_t **stream, size_t *stream_size, - crc_t *crc) +static int knot_rdata_dump_binary(knot_rdata_t *rdata, + uint32_t type, int fd, int use_ids, + uint8_t *stream, size_t max_size, + size_t *written_bytes, + crc_t *crc) { + if (rdata == NULL) { + dbg_zdump("zdump: dump_rdata: NULL rdata.\n"); + return KNOT_EBADARG; + } knot_rrtype_descriptor_t *desc = knot_rrtype_descriptor_by_type(type); assert(desc != NULL); - dbg_zdump("Dumping type: %d\n", type); - if (desc->fixed_items) { assert(desc->length == rdata->count); } - + /* Write rdata count. */ - /*!< \todo #1684 check the return value */ - write_wrapper(&(rdata->count), - sizeof(rdata->count), 1, fd, stream, stream_size, crc); + if (!write_wrapper(&(rdata->count), + sizeof(rdata->count), 1, fd, stream, max_size, + written_bytes, crc)) { + dbg_zdump("zdump: dump_rdata: Could not write RDATA count.\n"); + return KNOT_ERROR; + } for (int i = 0; i < rdata->count; i++) { if (&(rdata->items[i]) == NULL) { - dbg_zdump("Item n. %d is not set!\n", i); + dbg_zdump("zdump: dump_rdata: " + "Item n. %d is not set!\n", i); continue; } - dbg_zdump("Item n: %d\n", i); + dbg_zdump_detail("zdump: dump_rdata: Dumping item nr: %d\n", i); if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME || desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME || desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME ) { @@ -219,60 +279,105 @@ static void knot_rdata_dump_binary(knot_rdata_t *rdata, assert(rdata->items[i].dname->id != 0); uint32_t id = rdata->items[i].dname->id; - /*!< \todo #1684 check the return value */ - write_wrapper(&id, - sizeof(id), 1, fd, stream, stream_size, - crc); + if (!write_wrapper(&id, + sizeof(id), + 1, fd, stream, max_size, + written_bytes, crc)) { + dbg_zdump("zdump: dump_rdata: Cannot " + "write dname ID.\n"); + return KNOT_ERROR; + } } else { -// assert(rdata->items[i].dname->id != 0); - dump_dname_with_id(rdata->items[i].dname, - fd, stream, - stream_size, crc); + int ret = dump_dname_with_id( + rdata->items[i].dname, + fd, stream, + max_size, + written_bytes, + crc); + if (ret != KNOT_EOK) { + dbg_zdump("zdump: dump_rdata: Cannot " + "dump dname.\n"); + return ret; + } } /* Write in the zone bit */ + /*! \todo Does not have to be so complex. + * Create extra variable. */ if (rdata->items[i].dname->node != NULL && !wildcard) { - /*!< \todo #1684 check the return value */ - write_wrapper((uint8_t *)"\1", - sizeof(uint8_t), 1, fd, stream, - stream_size, crc); + if (!write_wrapper((uint8_t *)"\1", + sizeof(uint8_t), 1, fd, + stream, max_size, + written_bytes, crc)) { + dbg_zdump("zdump: dump_rdata: Cannot " + "write zone bit.\n"); + return KNOT_ERROR; + } } else { - /*!< \todo #1684 check the return value */ - write_wrapper((uint8_t *)"\0", sizeof(uint8_t), - 1, fd, stream, stream_size, crc); + if (!write_wrapper((uint8_t *)"\0", + sizeof(uint8_t), + 1, fd, + stream, max_size, + written_bytes, crc)) { + dbg_zdump("zdump: dump_rdata: Cannot " + "write zone bit.\n"); + return KNOT_ERROR; + } } if (use_ids && wildcard) { - /*!< \todo #1684 check the return value */ - write_wrapper((uint8_t *)"\1", - sizeof(uint8_t), 1, fd, stream, - stream_size, crc); + if (!write_wrapper((uint8_t *)"\1", + sizeof(uint8_t), 1, + fd, stream, max_size, + written_bytes, crc)) { + dbg_zdump("zdump: dump_rdata: Cannot " + "write wildcard bit.\n"); + return KNOT_ERROR; + } + uint32_t wildcard_id = wildcard->id; - /*!< \todo #1684 check the return value */ - write_wrapper(&wildcard_id, - sizeof(wildcard_id), 1, fd, stream, - stream_size, crc); + if (!write_wrapper(&wildcard_id, + sizeof(wildcard_id), 1, + fd, stream, max_size, + written_bytes, crc)) { + dbg_zdump("zdump: dump_rdata: Cannot " + "write wildcard ID.\n"); + return KNOT_ERROR; + } } else { - /*!< \todo #1684 check the return value */ - write_wrapper((uint8_t *)"\0", sizeof(uint8_t), - 1, fd, stream, - stream_size, crc); + if (!write_wrapper((uint8_t *)"\0", + sizeof(uint8_t), + 1, fd, stream, + max_size, written_bytes, + crc)) { + dbg_zdump("zdump: dump_rdata: Cannot " + "write wildcard bit.\n"); + return KNOT_ERROR; + } } - } else { - dbg_zdump("Writing raw data. Item nr.: %d\n", + dbg_zdump_detail("zdump: dump_rdata: " + "Writing raw data. Item nr.: %d\n", i); assert(rdata->items[i].raw_data != NULL); - /*!< \todo #1684 check the return value */ - write_wrapper(rdata->items[i].raw_data, - sizeof(uint8_t), - rdata->items[i].raw_data[0] + 2, fd, - stream, stream_size, crc); - - dbg_zdump("Written %d long raw data\n", - rdata->items[i].raw_data[0]); + if (!write_wrapper(rdata->items[i].raw_data, + sizeof(uint8_t), + rdata->items[i].raw_data[0] + 2, fd, + stream, max_size, + written_bytes, crc)) { + dbg_zdump("zdump: dump_rdata: Cannot write raw " + "data.\n"); + return KNOT_ERROR; + } + + dbg_zdump_detail("zdump: dump_rdata: " + "Written %d long raw data.\n", + rdata->items[i].raw_data[0]); } } + + dbg_zdump_verb("zdump: dump_rdata: RDATA dumped successfully.\n"); + return KNOT_EOK; } /*! @@ -280,28 +385,45 @@ static void knot_rdata_dump_binary(knot_rdata_t *rdata, * * \param rrsig RRSIG to be dumped. * \param data Arguments to be propagated. + * + * \todo This whole function is obsolete. Change after 1.0.2 release. */ -static void knot_rrsig_set_dump_binary(knot_rrset_t *rrsig, int fd, - int use_ids, - uint8_t **stream, size_t *stream_size, - crc_t *crc) +static int knot_rrsig_set_dump_binary(knot_rrset_t *rrsig, int fd, + int use_ids, + uint8_t *stream, size_t max_size, + size_t *written_bytes, crc_t *crc) { + if (rrsig == NULL) { + dbg_zdump("zdump: dump_rrsig: NULL RRSIG.\n"); + return KNOT_EBADARG; + } + dbg_zdump_exec_detail( char *name = knot_dname_to_str(knot_rrset_owner(rrsig)); - dbg_zdump("Dumping RRSIG \\w owner: %s\n", - name); + dbg_zdump_detail("zdump: dump_rrsig: Dumping RRSIG \\w owner: %s.\n", + name); free(name); ); assert(rrsig->type == KNOT_RRTYPE_RRSIG); assert(rrsig->rdata); - /*!< \todo #1684 check the return value */ - write_wrapper(&rrsig->type, sizeof(rrsig->type), 1, fd, - stream, stream_size, crc); - write_wrapper(&rrsig->rclass, sizeof(rrsig->rclass), 1, fd, - stream, stream_size, crc); - write_wrapper(&rrsig->ttl, sizeof(rrsig->ttl), 1, fd, - stream, stream_size, crc); - + if (!write_wrapper(&rrsig->type, sizeof(rrsig->type), 1, fd, + stream, max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_rrsig: Cannot write type.\n"); + return KNOT_ERROR; + } + + if (!write_wrapper(&rrsig->rclass, sizeof(rrsig->rclass), 1, fd, + stream, max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_rrsig: Cannot write class.\n"); + return KNOT_ERROR; + } + + if (!write_wrapper(&rrsig->ttl, sizeof(rrsig->ttl), 1, fd, + stream, max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_rrsig: Cannot write TTL.\n"); + return KNOT_ERROR; + } + uint32_t rdata_count = 1; /* Calculate rrset rdata count. */ knot_rdata_t *tmp_rdata = rrsig->rdata; @@ -309,18 +431,30 @@ dbg_zdump_exec_detail( tmp_rdata = tmp_rdata->next; rdata_count++; } + + if (!write_wrapper(&rdata_count, sizeof(rdata_count), 1, fd, + stream, max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_rrsig: Cannot write rdata count.\n"); + return KNOT_ERROR; + } - write_wrapper(&rdata_count, sizeof(rdata_count), 1, fd, - stream, stream_size, crc); + dbg_zdump_verb("zdump: dump_rrsig: Static data dumped.\n"); tmp_rdata = rrsig->rdata; while (tmp_rdata->next != rrsig->rdata) { - knot_rdata_dump_binary(tmp_rdata, KNOT_RRTYPE_RRSIG, fd, - use_ids, stream, stream_size, crc); + int ret = knot_rdata_dump_binary(tmp_rdata, KNOT_RRTYPE_RRSIG, + fd, + use_ids, stream, max_size, + written_bytes, crc); + if (ret != KNOT_EOK) { + dbg_zdump("zdump: rrsig_to_binary: Could not dump " + "rdata. Reason: %s.\n", knot_strerror(ret)); + return ret; + } tmp_rdata = tmp_rdata->next; } - knot_rdata_dump_binary(tmp_rdata, KNOT_RRTYPE_RRSIG, fd, use_ids, - stream, stream_size, crc); + return knot_rdata_dump_binary(tmp_rdata, KNOT_RRTYPE_RRSIG, fd, use_ids, + stream, max_size, written_bytes, crc); } /*! @@ -329,25 +463,52 @@ dbg_zdump_exec_detail( * \param rrset RRSSet to be dumped. * \param data Arguments to be propagated. */ -static void knot_rrset_dump_binary(const knot_rrset_t *rrset, int fd, - int use_ids, - uint8_t **stream, size_t *stream_size, - crc_t *crc) +static int knot_rrset_dump_binary(const knot_rrset_t *rrset, int fd, + int use_ids, + uint8_t *stream, size_t max_size, + size_t *written_bytes, + crc_t *crc) { - dbg_zdump_detail("zdump: rrset_dump_binary: Dumping rrset to fd=%d\n", - fd); - + if (rrset == NULL) { + dbg_zdump("zdump: dump_rrset: NULL RRSet.\n"); + return KNOT_EBADARG; + } + + dbg_zdump_exec_detail( + char *name = knot_dname_to_str(knot_rrset_owner(rrset)); + dbg_zdump_detail("zdump: dump_rrset: " + "Dumping RRSet \\w owner: %s.\n", + name); + free(name); + ); + if (!use_ids) { - dump_dname_with_id(rrset->owner, fd, stream, stream_size, crc); + /*!< \todo IDs in changeset do no good. Change loading too. */ + int ret = dump_dname_with_id(rrset->owner, + fd, stream, max_size, + written_bytes, crc); + if (ret != KNOT_EOK) { + dbg_zdump("zdump: rrset_dump_binary: Could not dump " + "RRSet's owner.\n"); + return ret; + } } - /*!< \todo #1684 check the return value */ - write_wrapper(&rrset->type, sizeof(rrset->type), 1, fd, - stream, stream_size, crc); - write_wrapper(&rrset->rclass, sizeof(rrset->rclass), 1, fd, - stream, stream_size, crc); - write_wrapper(&rrset->ttl, sizeof(rrset->ttl), 1, fd, - stream, stream_size, crc); + if (!write_wrapper(&rrset->type, sizeof(rrset->type), 1, fd, + stream, max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_rrset: Cannot write type.\n"); + return KNOT_ERROR; + } + if (!write_wrapper(&rrset->rclass, sizeof(rrset->rclass), 1, fd, + stream, max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_rrset: Cannot write class.\n"); + return KNOT_ERROR; + } + if (!write_wrapper(&rrset->ttl, sizeof(rrset->ttl), 1, fd, + stream, max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_rrset: Cannot write TTL.\n"); + return KNOT_ERROR; + } uint32_t rdata_count = 1; uint8_t has_rrsig = rrset->rrsigs != NULL; @@ -359,31 +520,54 @@ static void knot_rrset_dump_binary(const knot_rrset_t *rrset, int fd, rdata_count++; } - write_wrapper(&rdata_count, sizeof(rdata_count), 1, fd, - stream, stream_size, crc); - write_wrapper(&has_rrsig, sizeof(has_rrsig), 1, fd, - stream, stream_size, crc); + if (!write_wrapper(&rdata_count, sizeof(rdata_count), 1, fd, + stream, max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_rrset: Cannot write rdata count.\n"); + return KNOT_ERROR; + } - dbg_zdump_detail("zdump: rrset_dump_binary: Static data dumped.\n"); + if (!write_wrapper(&has_rrsig, sizeof(has_rrsig), 1, fd, + stream, max_size, written_bytes, crc)) { + return KNOT_ERROR; + } + + dbg_zdump_verb("zdump: rrset_dump_binary: Static data dumped.\n"); tmp_rdata = rrset->rdata; while (tmp_rdata->next != rrset->rdata) { - knot_rdata_dump_binary(tmp_rdata, rrset->type, fd, use_ids, - stream, stream_size, crc); + int ret = knot_rdata_dump_binary(tmp_rdata, rrset->type, + fd, use_ids, + stream, max_size, + written_bytes, crc); + if (ret != KNOT_EOK) { + dbg_zdump("zdump: rrset_to_binary: Could not dump " + "rdata. Reason: %s.\n", knot_strerror(ret)); + return ret; + } tmp_rdata = tmp_rdata->next; } - knot_rdata_dump_binary(tmp_rdata, rrset->type, fd, use_ids, - stream, stream_size, crc); - dbg_zdump_detail("zdump: rrset_dump_binary: Rdata dumped.\n"); + int ret = knot_rdata_dump_binary(tmp_rdata, rrset->type, fd, use_ids, + stream, + max_size, written_bytes, crc); + if (ret != KNOT_EOK) { + dbg_zdump("zdump: rrset_to_binary: Could not dump " + "rdata. Reason: %s.\n", knot_strerror(ret)); + return ret; + } + + dbg_zdump_verb("zdump: rrset_dump_binary: Rdata dumped.\n"); /* This is now obsolete, although I'd rather not use recursion - that * would probably not work */ if (rrset->rrsigs != NULL) { - knot_rrsig_set_dump_binary(rrset->rrsigs, fd, use_ids, - stream, stream_size, crc); + return knot_rrsig_set_dump_binary(rrset->rrsigs, fd, use_ids, + stream, + max_size, written_bytes, crc); + } else { + return KNOT_EOK; } } @@ -393,12 +577,15 @@ static void knot_rrset_dump_binary(const knot_rrset_t *rrset, int fd, * \param node Node to dumped. * \param data Arguments to be propagated. */ -static void knot_node_dump_binary(knot_node_t *node, int fd, - uint8_t **stream, size_t *stream_size, - crc_t *crc) +static int knot_node_dump_binary(knot_node_t *node, int fd, + uint8_t *stream, + size_t max_size, + size_t *written_bytes, + crc_t *crc) { if (node == NULL) { - return; + dbg_zdump("zdump: dump_node: NULL node.\n"); + return KNOT_EBADARG; } /* first write dname */ @@ -407,61 +594,93 @@ static void knot_node_dump_binary(knot_node_t *node, int fd, /* Write owner ID. */ dbg_zdump_exec_detail( char *name = knot_dname_to_str(knot_node_owner(node)); - dbg_zdump("Dumping node owned by %s\n", - name); + dbg_zdump_detail("zdump: dump_node: Dumping node owned by %s\n", + name); free(name); ); assert(node->owner->id != 0); uint32_t owner_id = node->owner->id; - /*!< \todo #1684 check the return value */ - write_wrapper(&owner_id, sizeof(owner_id), 1, fd, stream, stream_size, - crc); + if (!write_wrapper(&owner_id, sizeof(owner_id), 1, fd, stream, + max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_node: Cannot write ID.\n"); + return KNOT_ERROR; + } + /*!< \todo Fix after release. */ if (knot_node_parent(node) != NULL) { uint32_t parent_id = knot_dname_id( knot_node_owner(knot_node_parent(node))); - write_wrapper(&parent_id, sizeof(parent_id), 1, fd, - stream, stream_size, crc); + if (!write_wrapper(&parent_id, sizeof(parent_id), 1, fd, + stream, max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_node: Cannot write parent " + "ID.\n"); + return KNOT_ERROR; + } } else { uint32_t parent_id = 0; - write_wrapper(&parent_id, sizeof(parent_id), 1, fd, - stream, stream_size, crc); + if (!write_wrapper(&parent_id, sizeof(parent_id), 1, fd, + stream, max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_node: Cannot write parent " + "ID.\n"); + return KNOT_ERROR; + } } - write_wrapper(&(node->flags), sizeof(node->flags), 1, fd, - stream, stream_size, crc); - - dbg_zdump("Written flags: %u\n", node->flags); + if (!write_wrapper(&(node->flags), sizeof(node->flags), 1, fd, + stream, max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_node: Cannot write node flags.\n"); + return KNOT_ERROR; + } if (knot_node_nsec3_node(node) != NULL) { uint32_t nsec3_id = knot_node_owner(knot_node_nsec3_node(node))->id; - write_wrapper(&nsec3_id, sizeof(nsec3_id), 1, fd, - stream, stream_size, crc); - dbg_zdump("Written nsec3 node id: %u\n", - knot_node_owner(knot_node_nsec3_node(node))->id); + if (!write_wrapper(&nsec3_id, sizeof(nsec3_id), 1, fd, + stream, max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_node: Cannot write NSEC3 ID.\n"); + return KNOT_ERROR; + } + + dbg_zdump_detail("Written nsec3 node id: %u\n", + knot_node_owner( + knot_node_nsec3_node(node))->id); } else { uint32_t nsec3_id = 0; - write_wrapper(&nsec3_id, sizeof(nsec3_id), 1, fd, - stream, stream_size, crc); + if (!write_wrapper(&nsec3_id, sizeof(nsec3_id), 1, fd, + stream, max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_node: Cannot write NSEC3 ID.\n"); + return KNOT_ERROR; + } } /* Now we need (or do we?) count of rrsets to be read * but that number is yet unknown */ uint16_t rrset_count = node->rrset_count; - write_wrapper(&rrset_count, sizeof(rrset_count), 1, fd, - stream, stream_size, crc); + if (!write_wrapper(&rrset_count, sizeof(rrset_count), 1, fd, + stream, max_size, written_bytes, crc)) { + dbg_zdump("zdump: dump_node: Cannot write RRSet count.\n"); + return KNOT_ERROR; + } const knot_rrset_t **node_rrsets = knot_node_rrsets(node); for (int i = 0; i < rrset_count; i++) { - knot_rrset_dump_binary(node_rrsets[i], fd, 1, - stream, stream_size, crc); + int ret = knot_rrset_dump_binary(node_rrsets[i], fd, 1, + stream, max_size, + written_bytes, crc); + if (ret != KNOT_EOK) { + dbg_zdump("zdump: dump_node: Could not dump RRSet. " + "Reason: %s.\n", knot_strerror(ret)); + return ret; + } } free(node_rrsets); + + dbg_zdump_verb("zdump: dump_node: Node dumped successfully.\n"); + return KNOT_EOK; } int zone_is_secure(knot_zone_contents_t *zone) @@ -483,17 +702,24 @@ static void dump_dname_from_tree(knot_dname_t *dname, void *data) { arg_t *arg = (arg_t *)data; + if (arg->error_code != KNOT_EOK) { + dbg_zdump("zdump: dump_dname_from_tree: " + "Error occured previously.\n"); + return; + } + int *fd_pointer = (int *)arg->arg1; int fd = -1; if (fd_pointer != NULL) { fd = *fd_pointer; } else { dbg_zdump("zdump: dump_dname_from_tree: Bad fd.\n"); + arg->error_code = KNOT_EBADARG; return; } crc_t *crc = (crc_t*)arg->arg2; - dump_dname_with_id(dname, fd, NULL, NULL, crc); + arg->error_code = dump_dname_with_id(dname, fd, NULL, 0, NULL, crc); } static int knot_dump_dname_table(const knot_dname_table_t *dname_table, @@ -502,16 +728,21 @@ static int knot_dump_dname_table(const knot_dname_table_t *dname_table, arg_t arg; arg.arg1 = &fd; arg.arg2 = crc; + arg.error_code = KNOT_EOK; /* Go through the tree and dump each dname along with its ID. */ knot_dname_table_tree_inorder_apply(dname_table, dump_dname_from_tree, &arg); - return KNOT_EOK; + return arg.error_code; } static void save_node_from_tree(knot_node_t *node, void *data) { arg_t *arg = (arg_t *)data; + if (arg == NULL) { + return; + } + /* Increment node count */ (*((uint32_t *)(arg->arg1)))++; /* Save the first node only */ @@ -524,13 +755,25 @@ static void save_node_from_tree(knot_node_t *node, void *data) static void dump_node_to_file(knot_node_t *node, void *data) { arg_t *arg = (arg_t *)data; + if (arg == NULL) { + return; + } + + if (arg->error_code != KNOT_EOK) { + dbg_zdump("zdump: dump_node_to_file: " + "Error occured previously.\n"); + return; + } + int *fd_pointer = (int *)arg->arg1; int fd = -1; if (fd_pointer != NULL) { fd = *fd_pointer; } - knot_node_dump_binary(node, fd, NULL, NULL, (crc_t *)arg->arg7); + arg->error_code = + knot_node_dump_binary(node, + fd, NULL, 0, NULL, (crc_t *)arg->arg7); } char *knot_zdump_crc_file(const char* filename) @@ -553,6 +796,7 @@ int knot_zdump_binary(knot_zone_contents_t *zone, int fd, crc_t *crc) { if (fd < 0 || sfilename == NULL) { + dbg_zdump("zdump: Bad arguments.\n"); return KNOT_EBADARG; } @@ -562,8 +806,9 @@ int knot_zdump_binary(knot_zone_contents_t *zone, int fd, arguments.arg1 = &node_count; arguments.arg2 = NULL; - /* Count number of normal nodes. */ - knot_zone_contents_tree_apply_inorder(zone, save_node_from_tree, &arguments); + /* Count number of normal nodes. This cannot fail. */ + knot_zone_contents_tree_apply_inorder(zone, save_node_from_tree, + &arguments); /* arg1 is now count of normal nodes */ uint32_t normal_node_count = *((uint32_t *)arguments.arg1); @@ -571,8 +816,9 @@ int knot_zdump_binary(knot_zone_contents_t *zone, int fd, arguments.arg1 = &node_count; arguments.arg2 = NULL; - /* Count number of NSEC3 nodes. */ - knot_zone_contents_nsec3_apply_inorder(zone, save_node_from_tree, &arguments); + /* Count number of NSEC3 nodes. This cannot fail. */ + knot_zone_contents_nsec3_apply_inorder(zone, + save_node_from_tree, &arguments); uint32_t nsec3_node_count = *((uint32_t *)arguments.arg1); /* arg2 is the first NSEC3 node - used in sem checks. */ /* arg3 is the last NSEC3 node - used in sem checks. */ @@ -616,74 +862,112 @@ int knot_zdump_binary(knot_zone_contents_t *zone, int fd, /* Start writing header - magic bytes. */ static const uint8_t MAGIC[MAGIC_LENGTH] = MAGIC_BYTES; - write_wrapper(&MAGIC, sizeof(uint8_t), MAGIC_LENGTH, fd, NULL, NULL, - crc); + if (!write_wrapper(&MAGIC, sizeof(uint8_t), MAGIC_LENGTH, + fd, NULL, 0, NULL, crc)) { + dbg_zdump("zdump: Cannot write magic bytes.\n"); + return KNOT_ERROR; + } /* Write source file length. */ uint32_t sflen = strlen(sfilename) + 1; - write_wrapper(&sflen, sizeof(uint32_t), 1, fd, NULL, NULL, crc); + if (!write_wrapper(&sflen, sizeof(uint32_t), 1, fd, + NULL, 0, NULL, crc)) { + dbg_zdump("zdump: Cannot write source file length.\n"); + return KNOT_ERROR; + } /* Write source file. */ - write_wrapper(sfilename, sflen, 1, fd, NULL, NULL, crc); + if (!write_wrapper(sfilename, sflen, 1, fd, NULL, 0, NULL, crc)) { + dbg_zdump("zdump: Cannot write source file name.\n"); + return KNOT_ERROR; + } /* Notice: End of header, */ /* Start writing compiled data. */ - write_wrapper(&normal_node_count, sizeof(normal_node_count), 1, fd, - NULL, NULL, crc); - write_wrapper(&nsec3_node_count, sizeof(nsec3_node_count), 1, fd, - NULL, NULL, crc); + if (!write_wrapper(&normal_node_count, sizeof(normal_node_count), 1, fd, + NULL, 0, NULL, crc)) { + dbg_zdump("zdump: Cannot write node count.\n"); + return KNOT_ERROR; + } + + if (!write_wrapper(&nsec3_node_count, sizeof(nsec3_node_count), 1, fd, + NULL, 0, NULL, crc)) { + dbg_zdump("zdump: Cannot write NSEC3 node count.\n"); + return KNOT_ERROR; + } uint32_t auth_node_count = zone->node_count; - write_wrapper(&auth_node_count, - sizeof(auth_node_count), 1, fd, NULL, NULL, crc); + if (!write_wrapper(&auth_node_count, + sizeof(auth_node_count), + 1, fd, NULL, 0, NULL, crc)) { + dbg_zdump("zdump: Cannot write authoritative node count.\n"); + return KNOT_ERROR; + } /* Write total number of dnames */ assert(zone->dname_table); uint32_t total_dnames = zone->dname_table->id_counter; - write_wrapper(&total_dnames, - sizeof(total_dnames), 1, fd, NULL, NULL, crc); + if (!write_wrapper(&total_dnames, + sizeof(total_dnames), 1, fd, NULL, 0, NULL, crc)) { + dbg_zdump("zdump: Cannot write dname count.\n"); + return KNOT_ERROR; + } /* Write dname table. */ if (knot_dump_dname_table(zone->dname_table, fd, crc) != KNOT_EOK) { + dbg_zdump("zdump: Cannot write dname table.\n"); return KNOT_ERROR; } arguments.arg1 = &fd; arguments.arg3 = zone; arguments.arg7 = crc; + + arguments.error_code = KNOT_EOK; /*!< \todo #1685 Stop traversal upon error. */ knot_zone_contents_tree_apply_inorder(zone, dump_node_to_file, (void *)&arguments); - + + if (arguments.error_code != KNOT_EOK) { + dbg_zdump("zdump: Dump of normal tree failed. Reason: %s.\n", + knot_strerror(arguments.error_code)); + return arguments.error_code; + } + + arguments.error_code = KNOT_EOK; knot_zone_contents_nsec3_apply_inorder(zone, dump_node_to_file, (void *)&arguments); + + if (arguments.error_code != KNOT_EOK) { + dbg_zdump("zdump: Dump of NSEC3 tree failed. Reason: %s.\n", + knot_strerror(arguments.error_code)); + return arguments.error_code; + } + *crc = crc_finalize(*crc); return KNOT_EOK; } -int knot_zdump_rrset_serialize(const knot_rrset_t *rrset, uint8_t **stream, - size_t *size) +int knot_zdump_rrset_serialize(const knot_rrset_t *rrset, uint8_t *stream, + size_t max_size, size_t *written_bytes) { - if (stream == NULL || *stream != NULL || rrset == NULL || - size == NULL) { + if (stream == NULL || rrset == NULL || + written_bytes == NULL) { dbg_zdump("zdump: rrset_serialize: Bad arguments.\n"); return KNOT_EBADARG; } - - *size = 0; - arg_t arguments; - memset(&arguments, 0, sizeof(arg_t)); + *written_bytes = 0; + /* This fd will signal functions to use streams. */ int fd = -1; - knot_rrset_dump_binary(rrset, fd, 0, stream, size, NULL); - - return KNOT_EOK; + return knot_rrset_dump_binary(rrset, fd, 0, stream, max_size, + written_bytes, NULL); } int knot_zdump_dump(knot_zone_contents_t *zone, int fd, const char *sfilename, diff --git a/src/knot/zone/zone-dump.h b/src/knot/zone/zone-dump.h index 975b8e8..46e760e 100644 --- a/src/knot/zone/zone-dump.h +++ b/src/knot/zone/zone-dump.h @@ -62,29 +62,15 @@ int knot_zdump_binary(knot_zone_contents_t *zone, int fd, * * \param rrset RRSet to be serialized. * \param stream Stream containing serialized RRSet. - * \param size Length of created stream. + * \param max_size Maximum size of stream. + * \param bytes_written Actually written data. * * \retval KNOT_EOK on success. * \retval KNOT_EBADARG if wrong arguments are supplied. * \retval KNOT_ENOMEM on memory error. */ -int knot_zdump_rrset_serialize(const knot_rrset_t *rrset, uint8_t **stream, - size_t *size); - -/*! - * \brief Serializes RRSet into binary stream. Expects NULL pointer, memory - * is handled inside function. - * - * \param rrset RRSet to be serialized. - * \param stream Stream containing serialized RRSet. - * \param size Length of created stream. - * - * \retval KNOT_EOK on success. - * \retval KNOT_EBADARG if wrong arguments are supplied. - * \retval KNOT_ENOMEM on memory error. - */ -int knot_zdump_rrset_serialize(const knot_rrset_t *rrset, uint8_t **stream, - size_t *size); +int knot_zdump_rrset_serialize(const knot_rrset_t *rrset, uint8_t *stream, + size_t max_size, size_t *bytes_written); /*! * \brief Checks if zone uses DNSSEC and/or NSEC3 diff --git a/src/knot/zone/zone-load.c b/src/knot/zone/zone-load.c index 69ea58f..cee138f 100644 --- a/src/knot/zone/zone-load.c +++ b/src/knot/zone/zone-load.c @@ -40,26 +40,14 @@ * \param y Second time_t value to be compared. * * \retval 0 when times are the some. - * \retval 1 when y < x. - * \retval -1 when x > y. + * \retval 1 when x > y. + * \retval -1 when x < y. */ static int timet_cmp(time_t x, time_t y) { - /* Calculate difference in the scale of seconds. */ - long diff = x - y; - - /* X and Y are equal. */ - if (diff == 0) { - return 0; - } - - /* X is newer. */ - if (diff > 0) { - return 1; - } - - /* Y is newer. */ - return -1; + if (x > y) return 1; + if (x < y) return -1; + return 0; } /*! @@ -160,6 +148,9 @@ static void load_rdata_purge(knot_rdata_t *rdata, static knot_dname_t *read_dname_with_id(FILE *f) { + if (f == NULL) { + dbg_zload("zload: read_dname_id: NULL file.\n"); + } knot_dname_t *ret = knot_dname_new(); CHECK_ALLOC_LOG(ret, NULL); @@ -167,16 +158,18 @@ static knot_dname_t *read_dname_with_id(FILE *f) uint32_t dname_id = 0; if (!fread_wrapper(&dname_id, sizeof(dname_id), 1, f)) { knot_dname_release(ret); + dbg_zload("zload: read_dname_id: Cannot read dname ID.\n"); return NULL; } ret->id = dname_id; - dbg_zload("loaded: dname id: %u\n", dname_id); + dbg_zload_detail("zload: read_dname_id: dname id: %u\n", dname_id); /* Read size of dname. */ uint32_t dname_size = 0; if (!fread_wrapper(&dname_size, sizeof(dname_size), 1, f)) { knot_dname_release(ret); + dbg_zload("zload: read_dname_id: Cannot read dname size.\n"); return NULL; } ret->size = dname_size; @@ -194,6 +187,7 @@ static knot_dname_t *read_dname_with_id(FILE *f) if (!fread_wrapper(ret->name, sizeof(uint8_t), ret->size, f)) { knot_dname_release(ret); + dbg_zload("zload: read_dname_id: Cannot read dname name.\n"); return NULL; } @@ -201,6 +195,8 @@ static knot_dname_t *read_dname_with_id(FILE *f) uint16_t label_count = 0; if (!fread_wrapper(&label_count, sizeof(label_count), 1, f)) { knot_dname_release(ret); + dbg_zload("zload: read_dname_id: Cannot read " + "dname label count.\n"); return NULL; } @@ -216,11 +212,16 @@ static knot_dname_t *read_dname_with_id(FILE *f) if (!fread_wrapper(ret->labels, sizeof(uint8_t), ret->label_count, f)) { free(ret->name); free(ret); + dbg_zload("zload: read_dname_id: Cannot read dname labels.\n"); return NULL; } - dbg_zload("loaded: %s (id: %d)\n", knot_dname_to_str(ret), +dbg_zload_exec_detail( + char *name = knot_dname_to_str(ret); + dbg_zload_detail("zload: Loaded dname: %s (id: %d).\n", name, ret->id); + free(name); +); return ret; } @@ -239,6 +240,7 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, { knot_rdata_t *rdata = knot_rdata_new(); if (rdata == NULL) { + dbg_zload("zload: load_rdata: Cannot create new rdata.\n"); return NULL; } @@ -246,13 +248,13 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, knot_rrtype_descriptor_by_type(type); assert(desc != NULL); - - /* First, should read rdata count. */ + /* First we should read rdata count. */ uint32_t rdata_count = 0; if(!fread_wrapper(&rdata_count, sizeof(rdata_count), 1, f)) { knot_rdata_free(&rdata); + dbg_zload("zload: load_rdata: Cannot read rdata count.\n"); return NULL; } @@ -263,11 +265,11 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, assert(desc->length == rdata_count); } - uint16_t raw_data_length; + uint16_t raw_data_length = 0; - dbg_zload("Reading %d items\n", rdata_count); - - dbg_zload("current type: %s\n", knot_rrtype_to_string(type)); + dbg_zload_detail("zload: load_rdata: Reading %d items\n", rdata_count); + dbg_zload_detail("zload: load_rdata: Current type: %s\n", + knot_rrtype_to_string(type)); for (int i = 0; i < rdata_count; i++) { if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME || @@ -283,8 +285,12 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, uint8_t in_the_zone = 0; if (use_ids) { - if(!fread_wrapper(&dname_id, sizeof(dname_id), 1, f)) { - load_rdata_purge(rdata, items, i, desc, type); + if(!fread_wrapper(&dname_id, sizeof(dname_id), + 1, f)) { + load_rdata_purge(rdata, + items, i, desc, type); + dbg_zload("zload: load_rdata: " + "Cannot read dname ID.\n"); return NULL; } @@ -298,12 +304,16 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, if(!fread_wrapper(&in_the_zone, sizeof(in_the_zone), 1, f)) { load_rdata_purge(rdata, items, i, desc, type); + dbg_zload("zload: load_rdata: " + "Cannot read zone bit.\n"); return NULL; } if(!fread_wrapper(&has_wildcard, sizeof(uint8_t), 1, f)) { load_rdata_purge(rdata, items, i, desc, type); + dbg_zload("zload: load_rdata: " + "Cannot read wildcard bit.\n"); return NULL; } @@ -312,11 +322,14 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, 1, f)) { load_rdata_purge(rdata, items, i, desc, type); + dbg_zload("zload: load_rdata: " + "Cannot read wc ID.\n"); return NULL; } items[i].dname->node = - id_array[dname_id]->node; - } else if (use_ids && !in_the_zone) { /* destroy the node */ + id_array[dname_id]->node; + } else if (use_ids && !in_the_zone) { + /* destroy the node */ if (id_array[dname_id]->node != NULL) { knot_node_free(&id_array[dname_id]-> node, 0); @@ -328,37 +341,51 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, if (!fread_wrapper(&raw_data_length, sizeof(raw_data_length), 1, f)) { load_rdata_purge(rdata, items, i, desc, type); + dbg_zload("zload: load_rdata: Cannot read " + "raw data length.\n"); return NULL; } /*!< \todo this is not proper fix, see #1678 */ items[i].raw_data = (uint16_t *) malloc(sizeof(uint8_t) * (raw_data_length + 2)); + if (items[i].raw_data == NULL) { + ERR_ALLOC_FAILED; + load_rdata_purge(rdata, items, i + 1, desc, + type); + return NULL; + } items[i].raw_data[0] = raw_data_length; - if (!fread_wrapper(items[i].raw_data + 1, sizeof(uint8_t), + if (!fread_wrapper(items[i].raw_data + 1, + sizeof(uint8_t), raw_data_length, f)) { - load_rdata_purge(rdata, items, i + 1, desc, type); + load_rdata_purge(rdata, items, i + 1, desc, + type); + dbg_zload("zload: load_rdata: Cannot read " + "raw data.\n"); return NULL; } - dbg_zload("read raw_data len %d\n", raw_data_length); + dbg_zload_detail("zload: load_rdata: Read raw_data " + "length=%d.\n", + raw_data_length); } } /* Each item has refcount already incremented for saving in rdata. */ if (knot_rdata_set_items(rdata, items, rdata_count) != 0) { - fprintf(stderr, "zoneload: Could not set items " + fprintf(stderr, "zload: read_rdata: Could not set items " "when loading rdata.\n"); + knot_rdata_deep_free(&rdata, type, 0); + return NULL; } free(items); - - dbg_zload("knot_load_rdata: all %d items read\n", - desc->length); - assert(rdata->count == rdata_count); - - rdata->count = rdata_count; + + dbg_zload_detail("zload: read_rdata: All %d items read " + "successfully.\n", + desc->length); return rdata; } @@ -373,54 +400,77 @@ static knot_rdata_t *knot_load_rdata(uint16_t type, FILE *f, static knot_rrset_t *knot_load_rrsig(FILE *f, knot_dname_t **id_array, int use_ids) { - knot_rrset_t *rrsig; + if (f == NULL || id_array == NULL) { + dbg_zload("zload: load_rrsig: Bad arguments.\n"); + return NULL; + } + + knot_rrset_t *rrsig = NULL; - uint16_t rrset_type; - uint16_t rrset_class; - uint32_t rrset_ttl; + uint16_t rrset_type = 0; + uint16_t rrset_class = 0; + uint32_t rrset_ttl = 0; - uint32_t rdata_count; + uint32_t rdata_count = 0; if (!fread_wrapper(&rrset_type, sizeof(rrset_type), 1, f)) { + dbg_zload("zload: load_rrsig: Cannot read type.\n"); return NULL; } if (rrset_type != KNOT_RRTYPE_RRSIG) { - fprintf(stderr, "!! Error: rrsig has wrong type\n"); + dbg_zload("zload: load_rrsig: RRSIG has wrong type," + " probably data corruption.\n"); return NULL; } - dbg_zload("rrset type: %d\n", rrset_type); + dbg_zload_detail("zload: load_rrsig: RRSIG type: %d\n", rrset_type); if (!fread_wrapper(&rrset_class, sizeof(rrset_class), 1, f)) { + dbg_zload("zload: load_rrsig: Cannot read class.\n"); return NULL; } - dbg_zload("rrset class %d\n", rrset_class); + dbg_zload_detail("zload: load_rrsig: Class=%d\n", rrset_class); if (!fread_wrapper(&rrset_ttl, sizeof(rrset_ttl), 1, f)) { + dbg_zload("zload: load_rrsig: Cannot read TTL.\n"); return NULL; } - dbg_zload("rrset ttl %d\n", rrset_ttl); + dbg_zload_detail("zload: load_rrsig: TTL=%d\n", rrset_ttl); if (!fread_wrapper(&rdata_count, sizeof(rdata_count), 1, f)) { + dbg_zload("zload: load_rrsig: Cannot read rdata count.\n"); return NULL; } rrsig = knot_rrset_new(NULL, rrset_type, rrset_class, rrset_ttl); + if (rrsig == NULL) { + dbg_zload("zload: load_rrsig: Cannot create new RRSIG.\n"); + return NULL; + } - knot_rdata_t *tmp_rdata; + knot_rdata_t *tmp_rdata = NULL; - dbg_zload("loading %d rdata entries\n", rdata_count); + dbg_zload_detail("zload: load_rrsig: Loading %d rdata entries.\n", + rdata_count); for (int i = 0; i < rdata_count; i++) { tmp_rdata = knot_load_rdata(KNOT_RRTYPE_RRSIG, f, id_array, use_ids); if (tmp_rdata) { - knot_rrset_add_rdata(rrsig, tmp_rdata); + int ret = knot_rrset_add_rdata(rrsig, tmp_rdata); + if (ret != KNOT_EOK) { + dbg_zload("zload: load_rrsig: Cannot " + "add RDATA\n."); + knot_rrset_deep_free(&rrsig, 0, 1, 1); + return NULL; + } } else { + dbg_zload("zload: load_rrsig: Cannot load rdata.\n"); knot_rrset_deep_free(&rrsig, 0, 1, 1); return NULL; } } + dbg_zload_detail("zload: load_rrsig: RRSIG loaded successfully.\n"); return rrsig; } @@ -446,55 +496,63 @@ static knot_rrset_t *knot_load_rrset(FILE *f, knot_dname_t **id_array, knot_dname_t *owner = NULL; if (!use_ids) { - dbg_zload("Loading owner of new RRSet from wire.\n"); + dbg_zload_detail("zload: load_rrset: " + "Loading owner of new RRSet from wire.\n"); owner = read_dname_with_id(f); + if (owner == NULL) { + dbg_zload("zload: load_rrset: Cannot load owner.\n"); + return NULL; + } } if (!fread_wrapper(&rrset_type, sizeof(rrset_type), 1, f)) { + dbg_zload("zload: load_rrset: Cannot load RRSet type.\n"); if (!use_ids) { knot_dname_free(&owner); } return NULL; } - dbg_zload("Zone load: rrset load: type: %u\n", rrset_type); + + dbg_zload_detail("zload: load_rrset: Type=%u\n", rrset_type); if (!fread_wrapper(&rrset_class, sizeof(rrset_class), 1, f)) { + dbg_zload("zload: load_rrset: Cannot load RRSet class.\n"); if (!use_ids) { knot_dname_free(&owner); } return NULL; } - dbg_zload("Zone load: rrset class: type: %u\n", rrset_class); + dbg_zload_detail("zload: load_rrset: Class=%u\n", rrset_class); if (!fread_wrapper(&rrset_ttl, sizeof(rrset_ttl), 1, f)) { + dbg_zload("zload: load_rrset: Cannot load RRSet TTL.\n"); if (!use_ids) { knot_dname_free(&owner); } return NULL; } - dbg_zload("Zone load: rrset ttl: type: %u\n", rrset_ttl); + dbg_zload_detail("zload: load_rrset: TTL=%u\n", rrset_ttl); if (!fread_wrapper(&rdata_count, sizeof(rdata_count), 1, f)) { if (!use_ids) { knot_dname_free(&owner); } return NULL; } - dbg_zload("Zone load: rrset load: rdata count: %u\n", rdata_count); + dbg_zload_detail("zload: load_rrset: rdata count=%u\n", rdata_count); if (!fread_wrapper(&rrsig_count, sizeof(rrsig_count), 1, f)) { if (!use_ids) { knot_dname_free(&owner); } return NULL; } - dbg_zload("Zone load: rrset load: type: %u\n", rrset_type); + dbg_zload_detail("zload: load_rrset: RRSIG count=%u\n", rrsig_count); dbg_zload_exec_detail( char *name = knot_dname_to_str(owner); - dbg_zload("Loading RRSet owned by: %s\n", + dbg_zload_detail("zload: load_rrset: Loading RRSet owned by: %s.\n", name); free(name); ); rrset = knot_rrset_new(owner, rrset_type, rrset_class, rrset_ttl); - if (rrset == NULL) { dbg_zload("zload: load_rrset: Could not create rrset."); knot_dname_free(&owner); @@ -507,7 +565,7 @@ dbg_zload_exec_detail( owner = NULL; } - dbg_zload("RRSet type: %d\n", rrset->type); + dbg_zload_detail("zload: load_rrset: RRSet type=%d\n", rrset->type); knot_rdata_t *tmp_rdata = NULL; @@ -515,7 +573,13 @@ dbg_zload_exec_detail( tmp_rdata = knot_load_rdata(rrset->type, f, id_array, use_ids); if (tmp_rdata) { - knot_rrset_add_rdata(rrset, tmp_rdata); + int ret = knot_rrset_add_rdata(rrset, tmp_rdata); + if (ret != KNOT_EOK) { + dbg_zload("zload: load_rrset: Cannot add " + "RDATA.\n"); + knot_rrset_deep_free(&rrset, 0, 1, 1); + return NULL; + } } else { knot_rrset_deep_free(&rrset, 0, 1, 1); return NULL; @@ -524,9 +588,15 @@ dbg_zload_exec_detail( knot_rrset_t *tmp_rrsig = NULL; - dbg_zload("Reading: %d RRSIGs\n", rrsig_count); + dbg_zload_detail("zload: load_rrset: Reading: %d RRSIGs.\n", + rrsig_count); if (rrsig_count) { tmp_rrsig = knot_load_rrsig(f, id_array, use_ids); + if (tmp_rrsig == NULL) { + dbg_zload("zload: load_rrset: Cannot load RRSIG.\n"); + knot_rrset_deep_free(&rrset, 0, 1, 1); + return NULL; + } if (!use_ids) { knot_rrset_set_owner(tmp_rrsig, rrset->owner); } @@ -534,8 +604,8 @@ dbg_zload_exec_detail( knot_rrset_set_rrsigs(rrset, tmp_rrsig); - dbg_zload("Finished loading RRSet %p\n", rrset); - + dbg_zload_detail("zload: load_rrset: Finished loading RRSet %p.\n", + rrset); return rrset; } @@ -548,6 +618,10 @@ dbg_zload_exec_detail( */ static knot_node_t *knot_load_node(FILE *f, knot_dname_t **id_array) { + if (f == NULL || id_array == NULL) { + dbg_zload("zload: load_node: Wrong parameters.\n"); + return NULL; + } uint8_t flags = 0; knot_node_t *node = NULL; uint32_t parent_id = 0; @@ -557,45 +631,51 @@ static knot_node_t *knot_load_node(FILE *f, knot_dname_t **id_array) /* At the beginning of node - just dname_id !!!.*/ if (!fread_wrapper(&dname_id, sizeof(dname_id), 1, f)) { + dbg_zload("zload: load_node: Cannot read owner ID.\n"); return NULL; } if (!fread_wrapper(&parent_id, sizeof(parent_id), 1, f)) { + dbg_zload("zload: load_node: Cannot read owner ID.\n"); return NULL; } if (!fread_wrapper(&flags, sizeof(flags), 1, f)) { + dbg_zload("zload: load_node: Cannot read node flags.\n"); return NULL; } if (!fread_wrapper(&nsec3_node_id, sizeof(nsec3_node_id), 1, f)) { + dbg_zload("zload: load_node: Cannot read NSEC3 node.\n"); return NULL; } if (!fread_wrapper(&rrset_count, sizeof(rrset_count), 1, f)) { + dbg_zload("zload: load_node: Cannot read rrset count.\n"); return NULL; } knot_dname_t *owner = id_array[dname_id]; - dbg_zload("Node owner id: %d\n", dname_id); - dbg_zload("Node owned by: %s\n", knot_dname_to_str(owner)); - dbg_zload("Number of RRSets in a node: %d\n", rrset_count); + dbg_zload_detail("zload: load_node: Node owner id: %d.\n", dname_id); +dbg_zload_exec_detail( + char *name = knot_dname_to_str(owner); + dbg_zload_detail("zload: load_node: Node owned by: %s.\n"); + free(name); +); + dbg_zload_detail("zload: load_node: Number of RRSets in a node: %d.\n", + rrset_count); node = owner->node; if (node == NULL) { - fprintf(stderr, "zone: Could not create node.\n"); + dbg_zload("zload: load_node: NULL node, cannot proceed.\n"); return NULL; } /* XXX can it be 0, ever? I think not. */ if (nsec3_node_id != 0) { knot_node_set_nsec3_node(node, id_array[nsec3_node_id]->node); - /* CLEANUP */ -// node->nsec3_node = id_array[nsec3_node_id]->node; } else { knot_node_set_nsec3_node(node, NULL); - /* CLEANUP */ -// node->nsec3_node = NULL; } /* Retain new owner while releasing replaced owner. */ @@ -611,7 +691,7 @@ static knot_node_t *knot_load_node(FILE *f, knot_dname_t **id_array) knot_node_set_parent(node, NULL); } - knot_rrset_t *tmp_rrset; + knot_rrset_t *tmp_rrset = NULL; for (int i = 0; i < rrset_count; i++) { if ((tmp_rrset = knot_load_rrset(f, id_array, 1)) == NULL) { @@ -619,7 +699,7 @@ static knot_node_t *knot_load_node(FILE *f, knot_dname_t **id_array) /*!< \todo #1686 * Refactor freeing, might not be enough. */ - fprintf(stderr, "zone: Could not load rrset.\n"); + dbg_zload("zload: load_node: Cannot load RRSet.\n"); return NULL; } /* Retain new owner while releasing replaced owner. */ @@ -628,12 +708,13 @@ static knot_node_t *knot_load_node(FILE *f, knot_dname_t **id_array) knot_rrset_set_owner(tmp_rrset->rrsigs, node->owner); } if (knot_node_add_rrset(node, tmp_rrset, 0) < 0) { - fprintf(stderr, "zone: Could not add rrset.\n"); + dbg_zload("zload: load_node: Cannot add RRSet " + "to node.\n"); return NULL; } } assert(node != NULL); - dbg_zload("Node loaded: %p\n", node); + dbg_zload_detail("zload: load_node: Node loaded: %p\n", node); return node; } @@ -647,6 +728,10 @@ static knot_node_t *knot_load_node(FILE *f, knot_dname_t **id_array) static void find_and_set_wildcard_child(knot_zone_contents_t *zone, knot_node_t *node, int nsec3) { + if (zone == NULL || node == NULL) { + dbg_zload("zload: set_wc: Bad arguments.\n"); + return; + } knot_dname_t *chopped = knot_dname_left_chop(node->owner); knot_node_t *wildcard_parent; if (!nsec3) { @@ -708,7 +793,10 @@ static unsigned long calculate_crc(FILE *f) unsigned char *chunk = malloc(sizeof(unsigned char) * chunk_size); CHECK_ALLOC_LOG(chunk, 0); while ((file_size - read_bytes) > chunk_size) { - if (!fread_wrapper(chunk, sizeof(unsigned char), chunk_size, f)) { + if (!fread_wrapper(chunk, + sizeof(unsigned char), chunk_size, f)) { + dbg_zload("zload: calculate_crc: Failed to read " + "data chunk.\n"); free(chunk); return 0; } @@ -720,6 +808,8 @@ static unsigned long calculate_crc(FILE *f) /* Read the rest of the file */ if (!fread_wrapper(chunk, sizeof(unsigned char), file_size - read_bytes, f)) { + dbg_zload("zload: calculate_crc: Failed to read " + "data remainder.\n"); free(chunk); return 0; } @@ -737,6 +827,7 @@ int knot_zload_open(zloader_t **dst, const char *filename) char crc_buf[65]; if (!dst || !filename) { + dbg_zload("zload: open: Bad arguments.\n"); return KNOT_EBADARG; } @@ -749,7 +840,7 @@ int knot_zload_open(zloader_t **dst, const char *filename) if (unlikely(!f)) { int reason = errno; dbg_zload("knot_zload_open: failed to open '%s'\n", - filename); + filename); switch (reason) { case EACCES: return KNOT_EACCES; break; case ENOENT: return KNOT_ENOENT; break; @@ -765,9 +856,11 @@ int knot_zload_open(zloader_t **dst, const char *filename) /* Read CRC from filename.crc file */ char *crc_path = - malloc(sizeof(char) * (strlen(filename) + 4 /* strlen(".crc") */ + 1)); + malloc(sizeof(char) * + (strlen(filename) + 4 /* strlen(".crc") */ + 1)); if (unlikely(!crc_path)) { fclose(f); + ERR_ALLOC_FAILED; return KNOT_ENOMEM; } memcpy(crc_path, filename, strlen(filename)); @@ -891,43 +984,12 @@ static void cleanup_id_array(knot_dname_t **id_array, free(id_array); } -//static knot_dname_table_t *create_dname_table(FILE *f, uint max_id) -//{ -// if (f == NULL ) { -// return NULL; -// } - -// if (!fread_wrapper(&max_id, sizeof(max_id), 1, f)) { -// return NULL; -// } - -// knot_dname_table_t *dname_table = knot_dname_table_new(); -// if (dname_table == NULL) { -// return NULL; -// } - -// /* Create nodes containing dnames. */ -// for (uint i = 1; i < max_id; i++) { -// knot_dname_t *loaded_dname = read_dname_with_id(f); -// if (loaded_dname == NULL) { -// knot_dname_table_deep_free(&dname_table); -// return NULL; -// } -// if (knot_dname_table_add_dname(dname_table, -// loaded_dname) != KNOT_EOK) { - -// } -// } - -// return dname_table; -//} - static knot_dname_table_t *create_dname_table_from_array( knot_dname_t **array, uint max_id) { if (array == NULL) { /* should I set errno or what ... ? */ - dbg_zload("No array passed\n"); + dbg_zload("zload: create_dname_table: No array passed.\n"); return NULL; } @@ -941,19 +1003,28 @@ static knot_dname_table_t *create_dname_table_from_array( assert(array[i]); if (knot_dname_table_add_dname(ret, array[i]) != KNOT_EOK) { - dbg_zload("Could not add: %s\n", - knot_dname_to_str(array[i])); +dbg_zload_exec_detail( + char *name = knot_dname_to_str(array[i]); + dbg_zload_detail("zload: create_dname_table: " + "Could not add dname: %s.\n", + name); + free(name); +); + dbg_zload("zload: create_dname_table: " + "Could not add dname.\n"); knot_dname_table_deep_free(&ret); return NULL; } } + dbg_zload("zload: create_dname_table: Table loaded.\n"); return ret; } static knot_dname_t **create_dname_array(FILE *f, uint max_id) { if (f == NULL) { + dbg_zload("zload: create_dname_array: Wrong arguments.\n"); return NULL; } @@ -964,23 +1035,24 @@ static knot_dname_t **create_dname_array(FILE *f, uint max_id) return NULL; } - memset(array, 0, sizeof(knot_dname_t *) * (max_id + 1)); + memset(array, 0, sizeof(knot_dname_t *) * (max_id + 1)); for (uint i = 0; i < max_id - 1; i++) { knot_dname_t *read_dname = read_dname_with_id(f); if (read_dname == NULL) { + dbg_zload("zload: create_dname_array: " + "Cannot read dname.\n" ); cleanup_id_array(array, 0, i); return NULL; } if (read_dname->id < max_id) { - /* Create new node from dname. */ read_dname->node = knot_node_new(read_dname, NULL, 0); - if (read_dname->node == NULL) { - ERR_ALLOC_FAILED; - + dbg_zload("zload: create_dname_array: " + "Cannot create new node " + "from dname.\n"); /* Release read dname. */ knot_dname_release(read_dname); cleanup_id_array(array, 0, i); @@ -991,21 +1063,24 @@ static knot_dname_t **create_dname_array(FILE *f, uint max_id) array[read_dname->id] = read_dname; } else { /* Release read dname. */ + dbg_zload("zload: create_dname_array: " + "dname id is out of range.\n"); knot_dname_release(read_dname); cleanup_id_array(array, 0, i); return NULL; } } - + + dbg_zload("zload: create_dname_array: Array created.\n"); return array; } knot_zone_t *knot_zload_load(zloader_t *loader) { - dbg_zload("Loading zone, loader: %p\n", loader); + dbg_zload("zload: load: Loading zone, loader: %p.\n", loader); if (!loader) { - dbg_zload("NULL loader!\n"); + dbg_zload("zload: load: NULL loader!\n"); return NULL; } @@ -1020,22 +1095,24 @@ knot_zone_t *knot_zload_load(zloader_t *loader) uint32_t auth_node_count; if (!fread_wrapper(&node_count, sizeof(node_count), 1, f)) { - dbg_zload("wrong read!\n"); + dbg_zload("zload: load: Cannot read node count!\n"); return NULL; } if (!fread_wrapper(&nsec3_node_count, sizeof(nsec3_node_count), 1, f)) { - dbg_zload("wrong read!\n"); + dbg_zload("zload: load: Cannot read NSEC3 node count!\n"); return NULL; } if (!fread_wrapper(&auth_node_count, sizeof(auth_node_count), 1, f)) { - dbg_zload("wrong read!\n"); + dbg_zload("zload: load: Cannot read authoritative " + "node count!\n"); return NULL; } - dbg_zload("authoritative nodes: %u\n", auth_node_count); - - dbg_zload("loading %u nodes\n", node_count); + + dbg_zload_verb("zload: load: Authoritative nodes: %u.\n", + auth_node_count); + dbg_zload_verb("zload: load: :oading %u nodes.\n", node_count); uint32_t total_dnames = 0; /* First, read number of dnames in dname table. */ @@ -1043,18 +1120,19 @@ knot_zone_t *knot_zload_load(zloader_t *loader) return NULL; } - dbg_zload("total dname count: %d\n", total_dnames); + dbg_zload_verb("zload: load: Total dname count: %d.\n", total_dnames); /* Create id array. */ knot_dname_t **id_array = create_dname_array(f, total_dnames); if (id_array == NULL) { + dbg_zload("zload: load: Cannot create ID array.\n"); return NULL; } knot_dname_table_t *dname_table = create_dname_table_from_array(id_array, total_dnames); if (dname_table == NULL) { - ERR_ALLOC_FAILED; + dbg_zload("zload: load: Cannot create ID array.\n"); cleanup_id_array(id_array, 1, total_dnames); free(dname_table); return NULL; @@ -1071,13 +1149,14 @@ knot_zone_t *knot_zload_load(zloader_t *loader) return NULL; } - dbg_zload("Apex node loaded: %p\n", apex); + dbg_zload_verb("zload: load: Apex node loaded: %p.\n", apex); knot_zone_t *zone = knot_zone_new(apex, auth_node_count, 0); if (zone == NULL) { cleanup_id_array(id_array, 1, node_count + nsec3_node_count + 1); - dbg_zload("Failed to create new zone from apex!\n"); + dbg_zload("zload: load: Failed to create new " + "zone from apex!\n"); knot_node_free(&apex, 0); free(dname_table); return NULL; @@ -1090,19 +1169,21 @@ knot_zone_t *knot_zload_load(zloader_t *loader) contents->dname_table = dname_table; knot_node_set_previous(apex, NULL); - knot_node_t *last_node = 0; - last_node = apex; for (uint i = 1; i < node_count; i++) { tmp_node = knot_load_node(f, id_array); - if (tmp_node != NULL) { if (knot_zone_contents_add_node(contents, tmp_node, 0, 0, 0) != 0) { - fprintf(stderr, "!! cannot add node\n"); - continue; + cleanup_id_array(id_array, 1, + node_count + + nsec3_node_count + 1); + knot_zone_deep_free(&zone, 0); + dbg_zload("zload: load: Failed to add node " + "to zone.\n"); + return NULL; } if (knot_dname_is_wildcard(tmp_node->owner)) { find_and_set_wildcard_child(contents, @@ -1118,8 +1199,12 @@ knot_zone_t *knot_zload_load(zloader_t *loader) } } else { - fprintf(stderr, "zone: Node error (in %s).\n", + dbg_zload("zload: load: Node error (in %s).\n", loader->filename); + knot_zone_deep_free(&zone, 0); + cleanup_id_array(id_array, node_count + 1, + nsec3_node_count + 1); + return NULL; } } @@ -1128,7 +1213,8 @@ knot_zone_t *knot_zload_load(zloader_t *loader) knot_node_set_previous(knot_zone_contents_get_apex(contents), last_node); - dbg_zload("loading %u nsec3 nodes\n", nsec3_node_count); + dbg_zload_detail("zload: load: Loading %u nsec3 nodes\n", + nsec3_node_count); knot_node_t *nsec3_first = NULL; @@ -1137,10 +1223,12 @@ knot_zone_t *knot_zload_load(zloader_t *loader) assert(nsec3_first != NULL); - if (knot_zone_contents_add_nsec3_node(contents, nsec3_first, 0, 0, 0) + if (knot_zone_contents_add_nsec3_node(contents, nsec3_first, + 0, 0, 0) != 0) { - fprintf(stderr, "!! cannot add first nsec3 node, " - "exiting.\n"); + dbg_zload(stderr, "zload: load: " + "cannot add first nsec3 node, " + "exiting.\n"); knot_zone_deep_free(&zone, 0); cleanup_id_array(id_array, node_count + 1, nsec3_node_count + 1); @@ -1157,8 +1245,12 @@ knot_zone_t *knot_zload_load(zloader_t *loader) if (tmp_node != NULL) { if (knot_zone_contents_add_nsec3_node(contents, tmp_node, 0, 0, 0) != 0) { - fprintf(stderr, "!! cannot add nsec3 node\n"); - continue; + dbg_zload("zload: load: Cannot add " + "NSEC3 node.\n"); + knot_zone_deep_free(&zone, 0); + cleanup_id_array(id_array, node_count + 1, + nsec3_node_count + 1); + return NULL; } knot_node_set_previous(tmp_node, last_node); @@ -1182,8 +1274,7 @@ knot_zone_t *knot_zload_load(zloader_t *loader) } free(id_array); - dbg_zload("zone loaded, returning: %p\n", zone); - + dbg_zload("zload: load: Zone loaded, returning: %p,\n", zone); return zone; } @@ -1231,6 +1322,7 @@ int knot_zload_rrset_deserialize(knot_rrset_t **rrset, uint8_t *stream, size_t *size) { if (stream == NULL || size == 0) { + dbg_zload("zload: rrset_deserialize: Bad arguments.\n"); return KNOT_EBADARG; } @@ -1240,8 +1332,8 @@ int knot_zload_rrset_deserialize(knot_rrset_t **rrset, knot_zload_stream_remaining = knot_zload_stream_size = *size; knot_rrset_t *ret = knot_load_rrset(NULL, NULL, 0); - if (ret == NULL) { + dbg_zload("zload: rrset_deserialize: Cannot load RRSet.\n"); knot_zload_stream = NULL; knot_zload_stream_remaining = 0; knot_zload_stream_size = 0; @@ -1254,7 +1346,9 @@ int knot_zload_rrset_deserialize(knot_rrset_t **rrset, knot_zload_stream = NULL; knot_zload_stream_remaining = 0; knot_zload_stream_size = 0; - + + dbg_zload_detail("zload: rrset_deserialize: RRSet deserialized " + "successfully.\n"); return KNOT_EOK; } diff --git a/src/libknot/dname.c b/src/libknot/dname.c index 0ab3d11..7a6ea5a 100644 --- a/src/libknot/dname.c +++ b/src/libknot/dname.c @@ -163,8 +163,7 @@ static int knot_dname_str_to_wire(const char *name, uint size, return -1; } - dbg_dname("Allocated space for wire format of dname: %p\n", - wire); + dbg_dname("Allocated space for wire format of dname: %p\n", wire); if (root) { *wire = '\0'; @@ -399,13 +398,22 @@ knot_dname_t *knot_dname_new_from_str(const char *name, uint size, return NULL; } - knot_dname_str_to_wire(name, size, dname); - dbg_dname("Created dname with size: %d\n", dname->size); - dbg_dname("Label offsets: "); + /*! \todo The function should return error codes. */ + int ret = knot_dname_str_to_wire(name, size, dname); + if (ret != 0) { + dbg_dname("Failed to create domain name from string.\n"); + knot_dname_free(&dname); + return NULL; + } + +dbg_dname_exec_verb( + dbg_dname_verb("Created dname with size: %d\n", dname->size); + dbg_dname_verb("Label offsets: "); for (int i = 0; i < dname->label_count; ++i) { - dbg_dname("%d, ", dname->labels[i]); + dbg_dname_verb("%d, ", dname->labels[i]); } - dbg_dname("\n"); + dbg_dname_verb("\n"); +); if (dname->size <= 0) { dbg_dname("Could not parse domain name " @@ -467,6 +475,7 @@ knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, uint size, dname->size = size; if (knot_dname_find_labels(dname, 1) != 0) { + dbg_dname("Could not find labels in dname (new from wire).\n"); knot_dname_free(&dname); return NULL; } @@ -567,6 +576,7 @@ knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire, memcpy(dname->name, name, i + 1); dname->size = i + 1; + /*! \todo Why l + 1 ?? */ dname->labels = (uint8_t *)malloc((l + 1) * sizeof(uint8_t)); if (dname->labels == NULL) { ERR_ALLOC_FAILED; @@ -603,8 +613,35 @@ int knot_dname_from_wire(const uint8_t *name, uint size, knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname) { - return knot_dname_new_from_wire(dname->name, dname->size, - dname->node); + //return knot_dname_new_from_wire(dname->name, dname->size, dname->node); + /* dname_new_from_wire() does not accept non-FQDN dnames, so we + * do the copy by hand. It's faster anyway */ + + knot_dname_t *copy = knot_dname_new(); + CHECK_ALLOC(copy, NULL); + + copy->labels = (uint8_t *)(malloc(dname->label_count)); + + if (copy->labels == NULL) { + knot_dname_free(©); + return NULL; + } + + copy->name = (uint8_t *)(malloc(dname->size)); + if (copy->name == NULL) { + knot_dname_free(©); + return NULL; + } + + memcpy(copy->labels, dname->labels, dname->label_count); + copy->label_count = dname->label_count; + + memcpy(copy->name, dname->name, dname->size); + copy->size = dname->size; + + copy->node = dname->node; + + return copy; } /*----------------------------------------------------------------------------*/ diff --git a/src/libknot/dname.h b/src/libknot/dname.h index 5a182ae..473bca7 100644 --- a/src/libknot/dname.h +++ b/src/libknot/dname.h @@ -116,6 +116,9 @@ knot_dname_t *knot_dname_new_from_str(const char *name, unsigned int size, * e.g. to knot_dname_to_str() may result in crash. Decide whether it * is OK to retain this and check the data in other functions before * calling this one, or if it should verify the given data. + * + * \warning Actually, right now this function does not accept non-FQDN dnames. + * For some reason there is a check for this. */ knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, unsigned int size, diff --git a/src/libknot/hash/cuckoo-hash-table.c b/src/libknot/hash/cuckoo-hash-table.c index 831aef8..50a7a0f 100644 --- a/src/libknot/hash/cuckoo-hash-table.c +++ b/src/libknot/hash/cuckoo-hash-table.c @@ -821,17 +821,19 @@ void ck_destroy_table(ck_hash_table_t **table, void (*dtor_value)(void *value), while (item != NULL) { // disconnect the item (*table)->stash = item->next; - /*! \todo Investigate this. */ - assert(item->item != NULL); - if (dtor_value) { - dtor_value(item->item->value); - } - if (delete_key) { - free((void *)item->item->key); + /*! \todo Check item semantics. (#1688) */ + if (item->item != NULL) { + if (dtor_value) { + dtor_value(item->item->value); + } + if (delete_key) { + free((void *)item->item->key); + } + + free((void *)item->item); } - free((void *)item->item); free(item); item = (*table)->stash; } diff --git a/src/libknot/nameserver/name-server.c b/src/libknot/nameserver/name-server.c index dea16ec..e1ccdd4 100644 --- a/src/libknot/nameserver/name-server.c +++ b/src/libknot/nameserver/name-server.c @@ -646,6 +646,8 @@ static int ns_put_authority_soa(const knot_zone_contents_t *zone, knot_rrset_set_ttl(soa_copy, min); soa_rrset = soa_copy; + /* Need to add it as temporary, so it get's freed. */ + knot_packet_add_tmp_rrset(resp, soa_copy); } assert(soa_rrset != NULL); diff --git a/src/libknot/nameserver/name-server.h b/src/libknot/nameserver/name-server.h index 1ae309c..42fa0f2 100644 --- a/src/libknot/nameserver/name-server.h +++ b/src/libknot/nameserver/name-server.h @@ -87,6 +87,7 @@ typedef struct knot_ns_xfr { knot_rcode_t rcode; xfr_callback_t send; int session; + int session_closed; /*! * XFR-out: Output buffer. diff --git a/src/libknot/updates/xfr-in.c b/src/libknot/updates/xfr-in.c index 75d7fd7..4874ccd 100644 --- a/src/libknot/updates/xfr-in.c +++ b/src/libknot/updates/xfr-in.c @@ -1374,13 +1374,20 @@ static int xfrin_changes_check_rdata(knot_rdata_t ***rdatas, uint **types, static void xfrin_changes_add_rdata(knot_rdata_t **rdatas, uint *types, int *count, knot_rdata_t *rdata, uint type) { - dbg_xfrin_detail("Adding RDATA to new RDATA list: %p\n", rdata); + dbg_xfrin_detail("Adding RDATA to RDATA list: %p\n", rdata); + + if (rdata == NULL) { + return; + } dbg_xfrin_exec_detail( // try to find the first RDATA in the given list for (int i = 0; i < *count; ++i) { knot_rdata_t *r = rdatas[i]; - while (r->next != rdatas[i]) { + if (r == NULL) { + continue; + } + while (r != NULL && r->next != rdatas[i]) { if (r == rdata) { dbg_xfrin_detail("Found same RDATA: %p\n", rdata); knot_rdata_dump(rdata, type, 0); @@ -1454,6 +1461,7 @@ static knot_rdata_t *xfrin_remove_rdata(knot_rrset_t *from, static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, knot_changes_t *changes) { + dbg_xfrin("Copying old RRSet: %p\n", old); // create new RRSet by copying the old one // int ret = knot_rrset_shallow_copy(old, copy); int ret = knot_rrset_deep_copy(old, copy); @@ -1486,6 +1494,7 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, changes->new_rrsets[changes->new_rrsets_count++] = *copy; + dbg_xfrin_verb("Adding RDATA from the RRSet copy to new RDATA list.\n"); xfrin_changes_add_rdata(changes->new_rdata, changes->new_rdata_types, &changes->new_rdata_count, knot_rrset_get_rdata(*copy), @@ -1495,6 +1504,8 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, assert(old->rrsigs != NULL); changes->new_rrsets[changes->new_rrsets_count++] = (*copy)->rrsigs; + dbg_xfrin_verb("Adding RDATA from RRSIG of the RRSet copy to " + "new RDATA list.\n"); xfrin_changes_add_rdata(changes->new_rdata, changes->new_rdata_types, &changes->new_rdata_count, @@ -1523,6 +1534,7 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, changes->old_rrsets[changes->old_rrsets_count++] = old; + dbg_xfrin_verb("Adding RDATA from old RRSet to old RDATA list.\n"); xfrin_changes_add_rdata(changes->old_rdata, changes->old_rdata_types, &changes->old_rdata_count, old->rdata, knot_rrset_type(old)); @@ -1531,6 +1543,8 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, assert(old->rrsigs != NULL); changes->old_rrsets[changes->old_rrsets_count++] = old->rrsigs; + dbg_xfrin_verb("Adding RDATA from RRSIG of the old RRSet to " + "old RDATA list.\n"); xfrin_changes_add_rdata(changes->old_rdata, changes->old_rdata_types, &changes->old_rdata_count, @@ -1546,8 +1560,18 @@ static int xfrin_copy_old_rrset(knot_rrset_t *old, knot_rrset_t **copy, static int xfrin_copy_rrset(knot_node_t *node, knot_rr_type_t type, knot_rrset_t **rrset, knot_changes_t *changes) { +dbg_xfrin_exec_verb( + char *name = knot_dname_to_str(knot_node_owner(node)); + dbg_xfrin_verb("Removing RRSet of type %s from node %s (%p)\n", + knot_rrtype_to_string(type), name, node); + free(name); +); knot_rrset_t *old = knot_node_remove_rrset(node, type); + dbg_xfrin_verb("Removed RRSet: %p\n", old); + dbg_xfrin_detail("Other RRSet of the same type in the node: %p\n", + knot_node_rrset(node, type)); + if (old == NULL) { dbg_xfrin("RRSet not found for RR to be removed.\n"); return 1; @@ -1558,7 +1582,7 @@ static int xfrin_copy_rrset(knot_node_t *node, knot_rr_type_t type, return ret; } - dbg_xfrin_detail("Copied old rrset %p to new %p.\n", old, *rrset); + dbg_xfrin_verb("Copied old rrset %p to new %p.\n", old, *rrset); // replace the RRSet in the node copy by the new one ret = knot_node_add_rrset(node, *rrset, 0); @@ -1601,6 +1625,7 @@ static int xfrin_apply_remove_rrsigs(knot_changes_t *changes, knot_rrset_rdata(remove)); // copy the rrset + dbg_xfrin_verb("Copying RRSet that carries the RRSIGs.\n"); ret = xfrin_copy_rrset(node, type, rrset, changes); if (ret != KNOT_EOK) { dbg_xfrin("Failed to copy rrset from changeset.\n"); @@ -1615,10 +1640,12 @@ static int xfrin_apply_remove_rrsigs(knot_changes_t *changes, // this RRSet should be the already copied RRSet so we may // update it right away /*! \todo Does this case even occur? */ + dbg_xfrin_verb("Using RRSet from previous iteration.\n"); } // get the old rrsigs knot_rrset_t *old = knot_rrset_get_rrsigs(*rrset); + dbg_xfrin_verb("Old RRSIGs from RRSet: %p\n", old); if (old == NULL) { return 1; } @@ -1630,8 +1657,10 @@ static int xfrin_apply_remove_rrsigs(knot_changes_t *changes, if (ret != KNOT_EOK) { return ret; } + dbg_xfrin_verb("Copied RRSIGs: %p\n", rrsigs); } else { rrsigs = old; + dbg_xfrin_verb("Using old RRSIGs: %p\n", rrsigs); } // set the RRSIGs to the new RRSet copy @@ -1935,14 +1964,22 @@ static int xfrin_apply_add_normal(knot_changes_t *changes, dbg_xfrin("applying rrset:\n"); knot_rrset_dump(add, 0); - if (!*rrset - || knot_dname_compare(knot_rrset_owner(*rrset), - knot_node_owner(node)) != 0 - || knot_rrset_type(*rrset) - != knot_rrset_type(add)) { - dbg_xfrin("Removing rrset!\n"); - *rrset = knot_node_remove_rrset(node, knot_rrset_type(add)); - } + /*! \note Reusing RRSet from previous function caused it not to be + * removed from the node. + * Maybe modification of the code would allow reusing the RRSet + * as in apply_add_rrsigs() - the RRSet should not be copied + * in such case. + */ +// if (!*rrset +// || knot_dname_compare(knot_rrset_owner(*rrset), +// knot_node_owner(node)) != 0 +// || knot_rrset_type(*rrset) +// != knot_rrset_type(add)) { +// dbg_xfrin("Removing rrset!\n"); +// *rrset = knot_node_remove_rrset(node, knot_rrset_type(add)); +// } + + *rrset = knot_node_remove_rrset(node, knot_rrset_type(add)); dbg_xfrin("Removed RRSet: \n"); knot_rrset_dump(*rrset, 1); @@ -1992,6 +2029,8 @@ dbg_xfrin_exec( return ret; } + dbg_xfrin("Copied RRSet: %p\n", *rrset); + // dbg_xfrin("After copy: Found RRSet with owner %s, type %s\n", // knot_dname_to_str((*rrset)->owner), // knot_rrtype_to_string(knot_rrset_type(*rrset))); @@ -2007,11 +2046,13 @@ dbg_xfrin_exec( * * TODO: add the 'add' rrset to list of old RRSets? */ - dbg_xfrin("Merging RRSets with owners: %s %s types: %d %d\n", - (*rrset)->owner->name, add->owner->name, (*rrset)->type, - add->type); + dbg_xfrin("Merging RRSets with owners: %s, %s types: %s, %s\n", + (*rrset)->owner->name, add->owner->name, + knot_rrtype_to_string((*rrset)->type), + knot_rrtype_to_string(add->type)); dbg_xfrin_detail("RDATA in RRSet1: %p, RDATA in RRSet2: %p\n", (*rrset)->rdata, add->rdata); + ret = knot_rrset_merge((void **)rrset, (void **)&add); if (ret != KNOT_EOK) { dbg_xfrin("Failed to merge changeset RRSet to copy.\n"); @@ -2021,6 +2062,11 @@ dbg_xfrin_exec( knot_rrset_dump(*rrset, 1); ret = knot_node_add_rrset(node, *rrset, 0); + if (ret < 0) { + dbg_xfrin("Failed to add merged RRSet to the node.\n"); + return ret; + } + // return 2 so that the add RRSet is removed from // the changeset (and thus not deleted) // and put to list of new RRSets (is this ok?) @@ -2058,6 +2104,9 @@ dbg_xfrin_exec( int copied = 0; + /*! \note Here the check is OK, because if we aready have the RRSet, + * it's a copied one, so it is OK to modify it right away. + */ if (!*rrset || knot_dname_compare(knot_rrset_owner(*rrset), knot_node_owner(node)) != 0 @@ -2081,7 +2130,6 @@ dbg_xfrin_exec( if (*rrset == NULL) { dbg_xfrin("RRSet to be added not found in zone.\n"); - dbg_xfrin("Creating new RRSet for RRSIG.\n"); // create a new RRSet to add the RRSIGs into *rrset = knot_rrset_new(knot_node_get_owner(node), type, knot_rrset_class(add), @@ -2090,6 +2138,7 @@ dbg_xfrin_exec( dbg_xfrin("Failed to create new RRSet for RRSIGs.\n"); return KNOT_ENOMEM; } + dbg_xfrin("Created new RRSet for RRSIG: %p.\n", *rrset); // add the RRset to the list of new RRsets ret = xfrin_changes_check_rrsets( @@ -2448,6 +2497,17 @@ static int xfrin_apply_remove2(knot_zone_contents_t *contents, int is_nsec3 = 0; for (int i = 0; i < chset->remove_count; ++i) { +dbg_xfrin_exec_verb( + char *name = knot_dname_to_str( + knot_rrset_owner(chset->remove[i])); + dbg_xfrin_verb("Removing RRSet: %s, type %s\n", name, + knot_rrtype_to_string( + knot_rrset_type(chset->remove[i]))); + free(name); +); +dbg_xfrin_exec_detail( + knot_rrset_dump(chset->remove[i], 0); +); is_nsec3 = 0; @@ -2524,8 +2584,17 @@ static int xfrin_apply_add2(knot_zone_contents_t *contents, int is_nsec3 = 0; for (int i = 0; i < chset->add_count; ++i) { - dbg_xfrin_detail("Adding RRSet:\n"); +dbg_xfrin_exec_verb( + char *name = knot_dname_to_str( + knot_rrset_owner(chset->add[i])); + dbg_xfrin_verb("Adding RRSet: %s, type: %s\n", name, + knot_rrtype_to_string( + knot_rrset_type(chset->add[i]))); + free(name); +); +dbg_xfrin_exec_detail( knot_rrset_dump(chset->add[i], 0); +); is_nsec3 = 0; @@ -2647,6 +2716,7 @@ static int xfrin_apply_replace_soa2(knot_zone_contents_t *contents, knot_changes_t *changes, knot_changeset_t *chset) { + dbg_xfrin("Replacing SOA record.\n"); knot_node_t *node = knot_zone_contents_get_apex(contents); assert(node != NULL); @@ -2658,6 +2728,7 @@ static int xfrin_apply_replace_soa2(knot_zone_contents_t *contents, contents->apex = node; // remove the SOA RRSet from the apex + dbg_xfrin_verb("Removing SOA.\n"); knot_rrset_t *rrset = knot_node_remove_rrset(node, KNOT_RRTYPE_SOA); assert(rrset != NULL); @@ -2704,6 +2775,7 @@ static int xfrin_apply_replace_soa2(knot_zone_contents_t *contents, changes->old_rrsets[changes->old_rrsets_count++] = rrset; /*! \todo Maybe check if the SOA does not have more RDATA? */ + dbg_xfrin_verb("Adding RDATA from old SOA to the list of old RDATA.\n"); xfrin_changes_add_rdata(changes->old_rdata, changes->old_rdata_types, &changes->old_rdata_count, rrset->rdata, KNOT_RRTYPE_SOA); @@ -2725,6 +2797,7 @@ static int xfrin_apply_replace_soa2(knot_zone_contents_t *contents, changes->new_rrsets[changes->new_rrsets_count++] = chset->soa_to; + dbg_xfrin_verb("Adding RDATA from new SOA to the list of new RDATA.\n"); xfrin_changes_add_rdata(changes->new_rdata, changes->new_rdata_types, &changes->new_rdata_count, @@ -2750,6 +2823,9 @@ static int xfrin_apply_changeset2(knot_zone_contents_t *contents, * SOA in the zone apex. */ + dbg_xfrin("APPLYING CHANGESET: from serial %u to serial %u\n", + chset->serial_from, chset->serial_to); + // check if serial matches /*! \todo Only if SOA is present? */ const knot_rrset_t *soa = knot_node_rrset(contents->apex, diff --git a/src/libknot/util/debug.h b/src/libknot/util/debug.h index e02f988..b6aba6e 100644 --- a/src/libknot/util/debug.h +++ b/src/libknot/util/debug.h @@ -33,6 +33,7 @@ #include <stdio.h> #include "config.h" /* autoconf generated */ +#include "common/log.h" /* * Debug macros @@ -132,8 +133,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Brief messages. */ #ifdef DEBUG_ENABLE_BRIEF -#define dbg_ns(msg...) fprintf(stderr, msg) -#define dbg_ns_hex(data, len) hex_print((data), (len)) +#define dbg_ns(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_ns_hex(data, len) hex_log(LOG_SERVER, (data), (len)) #define dbg_ns_exec(cmds) do { cmds } while (0) #else #define dbg_ns(msg...) @@ -143,8 +144,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE -#define dbg_ns_verb(msg...) fprintf(stderr, msg) -#define dbg_ns_hex_verb(data, len) hex_print((data), (len)) +#define dbg_ns_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_ns_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len)) #define dbg_ns_exec_verb(cmds) do { cmds } while (0) #else #define dbg_ns_verb(msg...) @@ -154,8 +155,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS -#define dbg_ns_detail(msg...) fprintf(stderr, msg) -#define dbg_ns_hex_detail(data, len) hex_print((data), (len)) +#define dbg_ns_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_ns_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len)) #define dbg_ns_exec_detail(cmds) do { cmds } while (0) #else #define dbg_ns_detail(msg...) @@ -182,8 +183,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Brief messages. */ #ifdef DEBUG_ENABLE_BRIEF -#define dbg_dname(msg...) fprintf(stderr, msg) -#define dbg_dname_hex(data, len) hex_print((data), (len)) +#define dbg_dname(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_dname_hex(data, len) hex_log(LOG_ZONE, (data), (len)) #define dbg_dname_exec(cmds) do { cmds } while (0) #else #define dbg_dname(msg...) @@ -193,8 +194,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE -#define dbg_dname_verb(msg...) fprintf(stderr, msg) -#define dbg_dname_hex_verb(data, len) hex_print((data), (len)) +#define dbg_dname_verb(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_dname_hex_verb(data, len) hex_log(LOG_ZONE, (data), (len)) #define dbg_dname_exec_verb(cmds) do { cmds } while (0) #else #define dbg_dname_verb(msg...) @@ -204,8 +205,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS -#define dbg_dname_detail(msg...) fprintf(stderr, msg) -#define dbg_dname_hex_detail(data, len) hex_print((data), (len)) +#define dbg_dname_detail(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_dname_hex_detail(data, len) hex_log(LOG_ZONE, (data), (len)) #define dbg_dname_exec_detail(cmds) do { cmds } while (0) #else #define dbg_dname_detail(msg...) @@ -232,8 +233,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Brief messages. */ #ifdef DEBUG_ENABLE_BRIEF -#define dbg_node(msg...) fprintf(stderr, msg) -#define dbg_node_hex(data, len) hex_print((data), (len)) +#define dbg_node(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_node_hex(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_node(msg...) #define dbg_node_hex(data, len) @@ -241,8 +242,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE -#define dbg_node_verb(msg...) fprintf(stderr, msg) -#define dbg_node_hex_verb(data, len) hex_print((data), (len)) +#define dbg_node_verb(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_node_hex_verb(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_node_verb(msg...) #define dbg_node_hex_verb(data, len) @@ -250,8 +251,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS -#define dbg_node_detail(msg...) fprintf(stderr, msg) -#define dbg_node_hex_detail(data, len) hex_print((data), (len)) +#define dbg_node_detail(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_node_hex_detail(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_node_detail(msg...) #define dbg_node_hex_detail(data, len) @@ -273,8 +274,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Brief messages. */ #ifdef DEBUG_ENABLE_BRIEF -#define dbg_zone(msg...) fprintf(stderr, msg) -#define dbg_zone_hex(data, len) hex_print((data), (len)) +#define dbg_zone(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_zone_hex(data, len) hex_log(LOG_ZONE, (data), (len)) #define dbg_zone_exec(cmds) do { cmds } while (0) #else #define dbg_zone(msg...) @@ -284,8 +285,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE -#define dbg_zone_verb(msg...) fprintf(stderr, msg) -#define dbg_zone_hex_verb(data, len) hex_print((data), (len)) +#define dbg_zone_verb(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_zone_hex_verb(data, len) hex_log(LOG_ZONE, (data), (len)) #define dbg_zone_exec_verb(cmds) do { cmds } while (0) #else #define dbg_zone_verb(msg...) @@ -295,8 +296,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS -#define dbg_zone_detail(msg...) fprintf(stderr, msg) -#define dbg_zone_hex_detail(data, len) hex_print((data), (len)) +#define dbg_zone_detail(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_zone_hex_detail(data, len) hex_log(LOG_ZONE, (data), (len)) #define dbg_zone_exec_detail(cmds) do { cmds } while (0) #else #define dbg_zone_detail(msg...) @@ -323,8 +324,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Brief messages. */ #ifdef DEBUG_ENABLE_BRIEF -#define dbg_zonedb(msg...) fprintf(stderr, msg) -#define dbg_zonedb_hex(data, len) hex_print((data), (len)) +#define dbg_zonedb(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_zonedb_hex(data, len) hex_log(LOG_ZONE, (data), (len)) #define dbg_zonedb_exec(cmds) do { cmds } while (0) #else #define dbg_zonedb(msg...) @@ -334,8 +335,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE -#define dbg_zonedb_verb(msg...) fprintf(stderr, msg) -#define dbg_zonedb_hex_verb(data, len) hex_print((data), (len)) +#define dbg_zonedb_verb(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_zonedb_hex_verb(data, len) hex_log(LOG_ZONE, (data), (len)) #define dbg_zonedb_exec_verb(cmds) do { cmds } while (0) #else #define dbg_zonedb_verb(msg...) @@ -345,8 +346,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS -#define dbg_zonedb_detail(msg...) fprintf(stderr, msg) -#define dbg_zonedb_hex_detail(data, len) hex_print((data), (len)) +#define dbg_zonedb_detail(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_zonedb_hex_detail(data, len) hex_log(LOG_ZONE, (data), (len)) #define dbg_zonedb_exec_detail(cmds) do { cmds } while (0) #else #define dbg_zonedb_detail(msg...) @@ -373,8 +374,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Brief messages. */ #ifdef DEBUG_ENABLE_BRIEF -#define dbg_response(msg...) fprintf(stderr, msg) -#define dbg_response_hex(data, len) hex_print((data), (len)) +#define dbg_response(msg...) log_msg(LOG_ANSWER, LOG_DEBUG, msg) +#define dbg_response_hex(data, len) hex_log(LOG_ANSWER, (data), (len)) #define dbg_response_exec(cmds) do { cmds } while (0) #else #define dbg_response(msg...) @@ -384,8 +385,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE -#define dbg_response_verb(msg...) fprintf(stderr, msg) -#define dbg_response_hex_verb(data, len) hex_print((data), (len)) +#define dbg_response_verb(msg...) log_msg(LOG_ANSWER, LOG_DEBUG, msg) +#define dbg_response_hex_verb(data, len) hex_log(LOG_ANSWER, (data), (len)) #define dbg_response_exec_verb(cmds) do { cmds } while (0) #else #define dbg_response_verb(msg...) @@ -395,8 +396,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS -#define dbg_response_detail(msg...) fprintf(stderr, msg) -#define dbg_response_hex_detail(data, len) hex_print((data), (len)) +#define dbg_response_detail(msg...) log_msg(LOG_ANSWER, LOG_DEBUG, msg) +#define dbg_response_hex_detail(data, len) hex_log(LOG_ANSWER, (data), (len)) #define dbg_response_exec_detail(cmds) do { cmds } while (0) #else #define dbg_response_detail(msg...) @@ -423,8 +424,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Brief messages. */ #ifdef DEBUG_ENABLE_BRIEF -#define dbg_packet(msg...) fprintf(stderr, msg) -#define dbg_packet_hex(data, len) hex_print((data), (len)) +#define dbg_packet(msg...) log_msg(LOG_ANSWER, LOG_DEBUG, msg) +#define dbg_packet_hex(data, len) hex_log(LOG_ANSWER, (data), (len)) #define dbg_packet_exec(cmds) do { cmds } while (0) #else #define dbg_packet(msg...) @@ -434,8 +435,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE -#define dbg_packet_verb(msg...) fprintf(stderr, msg) -#define dbg_packet_hex_verb(data, len) hex_print((data), (len)) +#define dbg_packet_verb(msg...) log_msg(LOG_ANSWER, LOG_DEBUG, msg) +#define dbg_packet_hex_verb(data, len) hex_log(LOG_ANSWER, (data), (len)) #define dbg_packet_exec_verb(cmds) do { cmds } while (0) #else #define dbg_packet_verb(msg...) @@ -445,8 +446,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS -#define dbg_packet_detail(msg...) fprintf(stderr, msg) -#define dbg_packet_hex_detail(data, len) hex_print((data), (len)) +#define dbg_packet_detail(msg...) log_msg(LOG_ANSWER, LOG_DEBUG, msg) +#define dbg_packet_hex_detail(data, len) hex_log(LOG_ANSWER, (data), (len)) #define dbg_packet_exec_detail(cmds) do { cmds } while (0) #else #define dbg_packet_detail(msg...) @@ -473,8 +474,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Brief messages. */ #ifdef DEBUG_ENABLE_BRIEF -#define dbg_edns(msg...) fprintf(stderr, msg) -#define dbg_edns_hex(data, len) hex_print((data), (len)) +#define dbg_edns(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_edns_hex(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_edns(msg...) #define dbg_edns_hex(data, len) @@ -482,8 +483,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE -#define dbg_edns_verb(msg...) fprintf(stderr, msg) -#define dbg_edns_hex_verb(data, len) hex_print((data), (len)) +#define dbg_edns_verb(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_edns_hex_verb(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_edns_verb(msg...) #define dbg_edns_hex_verb(data, len) @@ -491,8 +492,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS -#define dbg_edns_detail(msg...) fprintf(stderr, msg) -#define dbg_edns_hex_detail(data, len) hex_print((data), (len)) +#define dbg_edns_detail(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_edns_hex_detail(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_edns_detail(msg...) #define dbg_edns_hex_detail(data, len) @@ -514,8 +515,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Brief messages. */ #ifdef DEBUG_ENABLE_BRIEF -#define dbg_nsec3(msg...) fprintf(stderr, msg) -#define dbg_nsec3_hex(data, len) hex_print((data), (len)) +#define dbg_nsec3(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_nsec3_hex(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_nsec3(msg...) #define dbg_nsec3_hex(data, len) @@ -523,8 +524,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE -#define dbg_nsec3_verb(msg...) fprintf(stderr, msg) -#define dbg_nsec3_hex_verb(data, len) hex_print((data), (len)) +#define dbg_nsec3_verb(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_nsec3_hex_verb(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_nsec3_verb(msg...) #define dbg_nsec3_hex_verb(data, len) @@ -532,8 +533,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS -#define dbg_nsec3_detail(msg...) fprintf(stderr, msg) -#define dbg_nsec3_hex_detail(data, len) hex_print((data), (len)) +#define dbg_nsec3_detail(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_nsec3_hex_detail(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_nsec3_detail(msg...) #define dbg_nsec3_hex_detail(data, len) @@ -555,8 +556,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Brief messages. */ #ifdef DEBUG_ENABLE_BRIEF -#define dbg_ck(msg...) fprintf(stderr, msg) -#define dbg_ck_hex(data, len) hex_print((data), (len)) +#define dbg_ck(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_ck_hex(data, len) hex_log(LOG_SERVER, (data), (len)) #define dbg_ck_exec(cmds) do { cmds } while (0) #else #define dbg_ck(msg...) @@ -566,8 +567,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE -#define dbg_ck_verb(msg...) fprintf(stderr, msg) -#define dbg_ck_hex_verb(data, len) hex_print((data), (len)) +#define dbg_ck_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_ck_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len)) #define dbg_ck_exec_verb(cmds) do { cmds } while (0) #else #define dbg_ck_verb(msg...) @@ -577,8 +578,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS -#define dbg_ck_detail(msg...) fprintf(stderr, msg) -#define dbg_ck_hex_detail(data, len) hex_print((data), (len)) +#define dbg_ck_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_ck_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len)) #define dbg_ck_exec_detail(cmds) do { cmds } while (0) #else #define dbg_ck_detail(msg...) @@ -605,9 +606,9 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Brief messages. */ #ifdef DEBUG_ENABLE_BRIEF -#define dbg_ck_hash(msg...) fprintf(stderr, msg) -#define dbg_ck_rehash(msg...) fprintf(stderr, msg) -#define dbg_ck_hash_hex(data, len) hex_print((data), (len)) +#define dbg_ck_hash(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_ck_rehash(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_ck_hash_hex(data, len) hex_log(LOG_SERVER, (data), (len)) #else #define dbg_ck_hash(msg...) #define dbg_ck_rehash(msg...) @@ -616,8 +617,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE -#define dbg_ck_hash_verb(msg...) fprintf(stderr, msg) -#define dbg_ck_hash_hex_verb(data, len) hex_print((data), (len)) +#define dbg_ck_hash_verb(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_ck_hash_hex_verb(data, len) hex_log(LOG_SERVER, (data), (len)) #else #define dbg_ck_hash_verb(msg...) #define dbg_ck_hash_hex_verb(data, len) @@ -625,8 +626,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS -#define dbg_ck_hash_detail(msg...) fprintf(stderr, msg) -#define dbg_ck_hash_hex_detail(data, len) hex_print((data), (len)) +#define dbg_ck_hash_detail(msg...) log_msg(LOG_SERVER, LOG_DEBUG, msg) +#define dbg_ck_hash_hex_detail(data, len) hex_log(LOG_SERVER, (data), (len)) #else #define dbg_ck_hash_detail(msg...) #define dbg_ck_hash_hex_detail(data, len) @@ -649,8 +650,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Brief messages. */ #ifdef DEBUG_ENABLE_BRIEF -#define dbg_xfrin(msg...) fprintf(stderr, msg) -#define dbg_xfrin_hex(data, len) hex_print((data), (len)) +#define dbg_xfrin(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_xfrin_hex(data, len) hex_log(LOG_ZONE, (data), (len)) #define dbg_xfrin_exec(cmds) do { cmds } while (0) #else #define dbg_xfrin(msg...) @@ -660,8 +661,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE -#define dbg_xfrin_verb(msg...) fprintf(stderr, msg) -#define dbg_xfrin_hex_verb(data, len) hex_print((data), (len)) +#define dbg_xfrin_verb(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_xfrin_hex_verb(data, len) hex_log(LOG_ZONE, (data), (len)) #define dbg_xfrin_exec_verb(cmds) do { cmds } while (0) #else #define dbg_xfrin_verb(msg...) @@ -671,8 +672,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS -#define dbg_xfrin_detail(msg...) fprintf(stderr, msg) -#define dbg_xfrin_hex_detail(data, len) hex_print((data), (len)) +#define dbg_xfrin_detail(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_xfrin_hex_detail(data, len) hex_log(LOG_ZONE, (data), (len)) #define dbg_xfrin_exec_detail(cmds) do { cmds } while (0) #else #define dbg_xfrin_detail(msg...) @@ -699,8 +700,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Brief messages. */ #ifdef DEBUG_ENABLE_BRIEF -#define dbg_ddns(msg...) fprintf(stderr, msg) -#define dbg_ddns_hex(data, len) hex_print((data), (len)) +#define dbg_ddns(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_ddns_hex(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_ddns(msg...) #define dbg_ddns_hex(data, len) @@ -708,8 +709,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE -#define dbg_ddns_verb(msg...) fprintf(stderr, msg) -#define dbg_ddns_hex_verb(data, len) hex_print((data), (len)) +#define dbg_ddns_verb(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_ddns_hex_verb(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_ddns_verb(msg...) #define dbg_ddns_hex_verb(data, len) @@ -717,8 +718,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS -#define dbg_ddns_detail(msg...) fprintf(stderr, msg) -#define dbg_ddns_hex_detail(data, len) hex_print((data), (len)) +#define dbg_ddns_detail(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_ddns_hex_detail(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_ddns_detail(msg...) #define dbg_ddns_hex_detail(data, len) @@ -738,8 +739,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Brief messages. */ #ifdef DEBUG_ENABLE_BRIEF -#define dbg_tsig(msg...) fprintf(stderr, msg) -#define dbg_tsig_hex(data, len) hex_print((const char*)(data), (len)) +#define dbg_tsig(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_tsig_hex(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_tsig(msg...) #define dbg_tsig_hex(data, len) @@ -747,8 +748,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE -#define dbg_tsig_verb(msg...) fprintf(stderr, msg) -#define dbg_tsig_hex_verb(data, len) hex_print((const char*)(data), (len)) +#define dbg_tsig_verb(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_tsig_hex_verb(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_tsig_verb(msg...) #define dbg_tsig_hex_verb(data, len) @@ -756,8 +757,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS -#define dbg_tsig_detail(msg...) fprintf(stderr, msg) -#define dbg_tsig_hex_detail(data, len) hex_print((const char*)(data), (len)) +#define dbg_tsig_detail(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_tsig_hex_detail(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_tsig_detail(msg...) #define dbg_tsig_hex_detail(data, len) @@ -777,8 +778,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Brief messages. */ #ifdef DEBUG_ENABLE_BRIEF -#define dbg_rrset(msg...) fprintf(stderr, msg) -#define dbg_rrset_hex(data, len) hex_print((data), (len)) +#define dbg_rrset(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_rrset_hex(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_rrset(msg...) #define dbg_rrset_hex(data, len) @@ -786,8 +787,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Verbose messages. */ #ifdef DEBUG_ENABLE_VERBOSE -#define dbg_rrset_verb(msg...) fprintf(stderr, msg) -#define dbg_rrset_hex_verb(data, len) hex_print((data), (len)) +#define dbg_rrset_verb(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_rrset_hex_verb(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_rrset_verb(msg...) #define dbg_rrset_hex_verb(data, len) @@ -795,8 +796,8 @@ void knot_zone_contents_dump(knot_zone_contents_t *zone, char loaded_zone); /* Detail messages. */ #ifdef DEBUG_ENABLE_DETAILS -#define dbg_rrset_detail(msg...) fprintf(stderr, msg) -#define dbg_rrset_hex_detail(data, len) hex_print((data), (len)) +#define dbg_rrset_detail(msg...) log_msg(LOG_ZONE, LOG_DEBUG, msg) +#define dbg_rrset_hex_detail(data, len) hex_log(LOG_ZONE, (data), (len)) #else #define dbg_rrset_detail(msg...) #define dbg_rrset_hex_detail(data, len) diff --git a/src/tests/common/acl_tests.c b/src/tests/common/acl_tests.c index ea7b653..c1884cd 100644 --- a/src/tests/common/acl_tests.c +++ b/src/tests/common/acl_tests.c @@ -34,7 +34,7 @@ unit_api acl_tests_api = { static int acl_tests_count(int argc, char *argv[]) { - return 18; + return 20; } static int acl_tests_run(int argc, char *argv[]) @@ -146,6 +146,17 @@ static int acl_tests_run(int argc, char *argv[]) ret = acl_match(acl, &test_pf4, &rval); ok(rval->val == sval, "acl: search for preferred node"); + // 19. Scenario after truncating + ok(acl_truncate(acl) == ACL_ACCEPT, "acl: truncate"); + sockaddr_set(&test_pf6, AF_INET6, "2001:a1b0:e11e:50d1::3:300", 0); + acl_create(acl, &test_pf6, ACL_ACCEPT, 0, 0); + sockaddr_set(&test_pf4, AF_INET, "231.17.67.223", 0); + acl_create(acl, &test_pf4, ACL_ACCEPT, 0, 0); + sockaddr_set(&test_pf4, AF_INET, "82.87.48.136", 0); + acl_create(acl, &test_pf4, ACL_ACCEPT, 0, 0); + sockaddr_set(&match_pf4, AF_INET, "82.87.48.136", 12345); + ret = acl_match(acl, &match_pf4, 0); + ok(ret == ACL_ACCEPT, "acl: scenario after truncating"); acl_delete(&acl); // Return diff --git a/src/tests/files/sample_conf b/src/tests/files/sample_conf index 6cd9e50..b15fce5 100644 --- a/src/tests/files/sample_conf +++ b/src/tests/files/sample_conf @@ -8,7 +8,7 @@ system { identity "I have no mouth and must scream"; version "Infinitesimal"; - storage "/var/run/knot/"; + storage "."; } keys { diff --git a/src/tests/knot/dthreads_tests.c b/src/tests/knot/dthreads_tests.c index d95fbed..982329b 100644 --- a/src/tests/knot/dthreads_tests.c +++ b/src/tests/knot/dthreads_tests.c @@ -372,7 +372,6 @@ static int dt_tests_run(int argc, char *argv[]) ret += dt_join(0); // -1 ret += dt_repurpose(0, 0, 0); // -1 ret += dt_resize(0, 0); // -1 - ret += dt_setprio(0, 0); // -1 ret += dt_signalize(0, SIGALRM); // -1 ret += dt_start(0); // -1 ret += dt_start_id(0); // -1 diff --git a/src/tests/knot/journal_tests.c b/src/tests/knot/journal_tests.c index 420300e..7c8125e 100644 --- a/src/tests/knot/journal_tests.c +++ b/src/tests/knot/journal_tests.c @@ -34,7 +34,7 @@ unit_api journal_tests_api = { /* * Unit implementation. */ -static const int JOURNAL_TEST_COUNT = 12; +static const int JOURNAL_TEST_COUNT = 20; /*! \brief Generate random string with given length. */ static int randstr(char* dst, size_t len) @@ -164,13 +164,13 @@ static int journal_tests_run(int argc, char *argv[]) memcpy(chk_buf, tmpbuf, sizeof(chk_buf)); } } - ok(ret == 0, "journal: sustained looped writes"); + ok(j && ret == 0, "journal: sustained looped writes"); /* Test 11: Check data integrity. */ memset(tmpbuf, 0, sizeof(tmpbuf)); journal_read(j, chk_key, 0, tmpbuf); ret = strncmp(chk_buf, tmpbuf, sizeof(chk_buf)); - ok(ret == 0, "journal: read data integrity check"); + ok(j && ret == 0, "journal: read data integrity check"); /* Test 12: Reopen log and re-read value. */ memset(tmpbuf, 0, sizeof(tmpbuf)); @@ -178,7 +178,89 @@ static int journal_tests_run(int argc, char *argv[]) j = journal_open(jfilename, fsize, 0, 0); journal_read(j, chk_key, 0, tmpbuf); ret = strncmp(chk_buf, tmpbuf, sizeof(chk_buf)); - ok(ret == 0, "journal: read data integrity check after close/open"); + ok(j && ret == 0, "journal: read data integrity check after close/open"); + + /* Test 13: Map journal entry. */ + char *mptr = NULL; + memset(chk_buf, 0xde, sizeof(chk_buf)); + ret = journal_map(j, 0x12345, &mptr, sizeof(chk_buf)); + ok(j && mptr && ret == 0, "journal: mapped journal entry"); + skip(ret != 0, 2); + + /* Test 14: Write to mmaped entry and unmap. */ + memcpy(mptr, chk_buf, sizeof(chk_buf)); + ret = journal_unmap(j, 0x12345, mptr, 1); + ok(j && mptr && ret == 0, "journal: written to mapped entry and finished"); + + /* Test 15: Compare mmaped entry. */ + memset(tmpbuf, 0, sizeof(tmpbuf)); + journal_read(j, 0x12345, NULL, tmpbuf); + ret = strncmp(chk_buf, tmpbuf, sizeof(chk_buf)); + ok(j && ret == 0, "journal: mapped entry data integrity check"); + endskip; + + /* Test 17: Make a transaction. */ + uint64_t tskey = 0x75750000; + ret = journal_trans_begin(j); + ok(j && ret == 0, "journal: TRANS begin"); + for (int i = 0; i < 16; ++i) { + memset(tmpbuf, i, sizeof(tmpbuf)); + journal_write(j, tskey + i, tmpbuf, sizeof(tmpbuf)); + } + + /* Test 18: Check if uncommited node exists. */ + ret = journal_read(j, tskey + rand() % 16, NULL, chk_buf); + ok(j && ret != 0, "journal: check for uncommited node"); + + /* Test 19: Commit transaction. */ + ret = journal_trans_commit(j); + int read_ret = journal_read(j, tskey + rand() % 16, NULL, chk_buf); + ok(j && ret == 0 && read_ret == 0, "journal: transaction commit"); + + /* Test 20: Rollback transaction. */ + tskey = 0x6B6B0000; + journal_trans_begin(j); + for (int i = 0; i < 16; ++i) { + memset(tmpbuf, i, sizeof(tmpbuf)); + journal_write(j, tskey + i, tmpbuf, sizeof(tmpbuf)); + } + ret = journal_trans_rollback(j); + read_ret = journal_read(j, tskey + rand() % 16, NULL, chk_buf); + ok(j && ret == 0 && read_ret != 0, "journal: transaction rollback"); + + /* Test 16: Write random data. */ + ret = 0; + for (int i = 0; i < 512; ++i) { + int key = i; + randstr(tmpbuf, sizeof(tmpbuf)); + ret = journal_map(j, key, &mptr, sizeof(tmpbuf)); + if (ret != KNOTD_EOK) { + diag("journal_map failed: %s", knotd_strerror(ret)); + break; + } + memcpy(mptr, tmpbuf, sizeof(tmpbuf)); + if ((ret = journal_unmap(j, key, mptr, 1)) != KNOTD_EOK) { + diag("journal_unmap failed: %s", knotd_strerror(ret)); + break; + } + + /* Store some key on the end. */ + memset(chk_buf, 0, sizeof(chk_buf)); + ret = journal_read(j, key, 0, chk_buf); + if (ret != 0) { + diag("journal_map integrity check failed %s", + knotd_strerror(ret)); + break; + } + ret = strncmp(chk_buf, tmpbuf, sizeof(chk_buf)); + if (ret != 0) { + diag("journal_map integrity check failed"); + break; + } + } + + /* Test 16: Check data integrity. */ + ok(j && ret == 0, "journal: sustained mmap r/w"); /* Close journal. */ journal_close(j); diff --git a/src/tests/libknot/libknot/dname_tests.c b/src/tests/libknot/libknot/dname_tests.c index 22f6fbc..35ac230 100644 --- a/src/tests/libknot/libknot/dname_tests.c +++ b/src/tests/libknot/libknot/dname_tests.c @@ -39,7 +39,7 @@ unit_api dname_tests_api = { // C will not accept const int in other const definition enum { TEST_DOMAINS_OK = 8 }; -enum { TEST_DOMAINS_BAD = 4 }; +enum { TEST_DOMAINS_BAD = 5 }; enum { TEST_DOMAINS_NON_FQDN = 6 }; @@ -92,7 +92,8 @@ static const struct test_domain { NULL, "\2ex\3com", 0, "", 0 }, { "ex.com.", NULL, 0, "", 0 }, { "ex.com.\5", "\3ex\3com\0\5", 10, "", 0 }, - { "example.com", "\3example\3com", 12, "\x0\x8", 2 } + { "example.com", "\3example\3com", 12, "\x0\x8", 2 }, + { "example..", "\7example\0\0", 12, "\x0\x8", 2 } }; static int test_dname_create() @@ -194,7 +195,9 @@ static int test_dname_create_from_str_non_fqdn() knot_dname_t *dname = NULL; for (int i = 0; i < TEST_DOMAINS_NON_FQDN; ++i) { - //note("testing domain: %s", test_domains_non_fqdn[i].str); +// note("testing domain: %s, size: %zu", +// test_domains_non_fqdn[i].str, +// strlen(test_domains_non_fqdn[i].str)); dname = knot_dname_new_from_str(test_domains_non_fqdn[i].str, strlen(test_domains_non_fqdn[i].str), NULL); errors += check_domain_name(dname, test_domains_non_fqdn, i, 0); @@ -490,7 +493,7 @@ static int test_dname_is_subdomain() for (int i = 0; i < TEST_DOMAINS_NON_FQDN; ++i) { dnames_non_fqdn[i] = knot_dname_new_from_str( test_domains_non_fqdn[i].str, - test_domains_non_fqdn[i].size, NULL); + strlen(test_domains_non_fqdn[i].str), NULL); assert(dnames_non_fqdn[i] != NULL); } @@ -606,6 +609,60 @@ static int test_dname_is_subdomain() return (errors == 0); } +static int test_dname_deep_copy() { + int errors = 0; + + knot_dname_t *dnames_fqdn[TEST_DOMAINS_OK]; + knot_dname_t *dnames_non_fqdn[TEST_DOMAINS_NON_FQDN]; + knot_dname_t *dnames_fqdn_copy[TEST_DOMAINS_OK]; + knot_dname_t *dnames_non_fqdn_copy[TEST_DOMAINS_NON_FQDN]; + + for (int i = 0; i < TEST_DOMAINS_OK; ++i) { + dnames_fqdn[i] = knot_dname_new_from_wire( + (const uint8_t *)test_domains_ok[i].wire, + test_domains_ok[i].size, NODE_ADDRESS); + assert(dnames_fqdn[i] != NULL); + } + + for (int i = 0; i < TEST_DOMAINS_NON_FQDN; ++i) { + dnames_non_fqdn[i] = knot_dname_new_from_str( + test_domains_non_fqdn[i].str, + strlen(test_domains_non_fqdn[i].str), + NODE_ADDRESS); +// note("Created name: %.*s\n", dnames_non_fqdn[i]->size, +// dnames_non_fqdn[i]->name); + assert(dnames_non_fqdn[i] != NULL); + } + + /* + * Create copies of the domain names. + */ + for (int i = 0; i < TEST_DOMAINS_OK; ++i) { +// note("Testing %d. FQDN domain.\n", i); + dnames_fqdn_copy[i] = knot_dname_deep_copy(dnames_fqdn[i]); + assert(dnames_fqdn_copy[i] != NULL); + errors += check_domain_name(dnames_fqdn_copy[i], + test_domains_ok, i, 1); + knot_dname_free(&dnames_fqdn_copy[i]); + knot_dname_free(&dnames_fqdn[i]); + } + + for (int i = 0; i < TEST_DOMAINS_NON_FQDN; ++i) { +// note("Testing %d. non-FQDN domain: ", i); +// note("%.*s\n", dnames_non_fqdn[i]->size, +// dnames_non_fqdn[i]->name); + dnames_non_fqdn_copy[i] = + knot_dname_deep_copy(dnames_non_fqdn[i]); + assert(dnames_non_fqdn_copy[i] != NULL); + errors += check_domain_name(dnames_non_fqdn_copy[i], + test_domains_non_fqdn, i, 1); + knot_dname_free(&dnames_non_fqdn_copy[i]); + knot_dname_free(&dnames_non_fqdn[i]); + } + + return (errors == 0); +} + static int check_wires(const uint8_t *wire1, uint size1, uint8_t *wire2, uint size2) { @@ -652,7 +709,7 @@ static int test_dname_name(knot_dname_t **dnames_fqdn, for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) { const uint8_t *tmp_name; tmp_name = knot_dname_name(dnames_non_fqdn[i]); - if (!check_wires(tmp_name, dnames_non_fqdn[i]->size - 1, + if (!check_wires(tmp_name, dnames_non_fqdn[i]->size, (uint8_t *)test_domains_non_fqdn[i].wire, test_domains_non_fqdn[i].size)) { diag("Got bad name value from structure: " @@ -757,10 +814,13 @@ static int test_dname_getters(uint type) } for (int i = 0; i < TEST_DOMAINS_NON_FQDN; i++) { - printf("Creating dname: %s size: %d\n", test_domains_non_fqdn[i].wire, test_domains_non_fqdn[i].size); +// note("Creating dname: %s size: %d\n", +// test_domains_non_fqdn[i].wire, +// test_domains_non_fqdn[i].size); dnames_non_fqdn[i] = knot_dname_new_from_str( test_domains_non_fqdn[i].str, - test_domains_non_fqdn[i].size, NODE_ADDRESS); + strlen(test_domains_non_fqdn[i].str), + NODE_ADDRESS); assert(dnames_non_fqdn[i] != NULL); } @@ -792,7 +852,7 @@ static int test_dname_getters(uint type) return (errors == 0); } -static const int KNOT_DNAME_TEST_COUNT = 15; +static const int KNOT_DNAME_TEST_COUNT = 16; /*! This helper routine should report number of * scheduled tests for given parameters. @@ -834,15 +894,11 @@ static int knot_dname_tests_run(int argc, char *argv[]) res_final *= res_wire; res_final *= res_str_non_fqdn; - todo(); res = test_dname_getters(0); ok(res, "dname: name"); - endtodo; - todo(); res = test_dname_getters(1); ok(res, "dname: size"); - endtodo; res = test_dname_getters(2); ok(res, "dname: node"); @@ -871,6 +927,9 @@ static int knot_dname_tests_run(int argc, char *argv[]) ok((res = test_dname_is_subdomain()), "dname: is subdomain"); res_final *= res; + ok((res = test_dname_deep_copy()), "dname: deep copy"); + res_final *= res; + endskip; /* create failed */ return res_final; diff --git a/src/tests/libknot/libknot/packet_tests.c b/src/tests/libknot/libknot/packet_tests.c index 185504f..916328d 100644 --- a/src/tests/libknot/libknot/packet_tests.c +++ b/src/tests/libknot/libknot/packet_tests.c @@ -168,10 +168,8 @@ static int test_packet_parse_rest() knot_packet_new(KNOT_PACKET_PREALLOC_NONE); assert(packet); - todo(); lives_ok({res = knot_packet_parse_rest(packet);}, - "packet: parser rest empty packet"); - endtodo; + "packet: parser rest empty packet"); knot_packet_free(&packet); diff --git a/src/tests/unittests_main.c b/src/tests/unittests_main.c index 2d57ed2..1ec336a 100644 --- a/src/tests/unittests_main.c +++ b/src/tests/unittests_main.c @@ -36,6 +36,8 @@ int main(int argc, char *argv[]) // Open log log_init(); log_levels_set(LOGT_SYSLOG, LOG_ANY, 0); + log_levels_set(LOGT_STDERR, LOG_ANY, 0); + log_levels_set(LOGT_STDOUT, LOG_ANY, LOG_MASK(LOG_DEBUG)); // Build test set unit_api *tests[] = { diff --git a/src/tests/xfr_tests.c b/src/tests/xfr_tests.c index 9ea19fe..5017109 100644 --- a/src/tests/xfr_tests.c +++ b/src/tests/xfr_tests.c @@ -16,11 +16,9 @@ /* * This test is basically a copy of the whole server, with following exceptions: - * - conf file path is hardcoded, because it is generated by script - * invoking this binary. * - signal handler now handles one more signal - * SIGCONT is used to signal this - * binary that an integrity check should be done + * SIGUSR1 is used to signal this + * binary that an integrity check should be done */ #include <time.h> @@ -69,7 +67,7 @@ void interrupt_handle(int s) } // Start zone integrity check - if (s == SIGCONT) { + if (s == SIGUSR1) { sig_integrity_check = 1; return; } @@ -85,7 +83,8 @@ void help(int argc, char **argv) " -d, --daemonize Run server as a daemon.\n" " -v, --verbose Verbose mode - additional runtime information.\n" " -V, --version Print version of the server.\n" - " -h, --help Print help and usage.\n"); + " -h, --help Print help and usage.\n" + "Send SIGUSR1 to trigger integrity check.\n"); } int main(int argc, char **argv) @@ -272,7 +271,7 @@ int main(int argc, char **argv) sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sigaction(SIGHUP, &sa, NULL); - sigaction(SIGCONT, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); sa.sa_flags = 0; pthread_sigmask(SIG_BLOCK, &sa.sa_mask, NULL); diff --git a/src/zcompile/parser-descriptor.c b/src/zcompile/parser-descriptor.c index 41e7f2d..152781c 100644 --- a/src/zcompile/parser-descriptor.c +++ b/src/zcompile/parser-descriptor.c @@ -61,7 +61,7 @@ /* FIXME: Generate .y and .l to zoneparser/ */ #include "zparser.h" -enum desclen { PARSER_RRTYPE_DESCRIPTORS_LENGTH = 32770 }; // used to be 101 +enum desclen { PARSER_RRTYPE_DESCRIPTORS_LENGTH = 65536 }; // used to be 101 /* Taken from RFC 1035, section 3.2.4. */ static knot_lookup_table_t dns_rrclasses[] = { @@ -364,12 +364,13 @@ static parser_rrtype_descriptor_t /* 32769 */ [32769] = { PARSER_RRTYPE_DLV, T_DLV, "DLV", 4, { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE, - PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BINARY } }, + PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BINARY }}, + [32770 ... 65535] = { PARSER_RRTYPE_TYPEXXX, T_UTYPE, NULL, 1, { PARSER_RDATA_WF_BINARY }} }; parser_rrtype_descriptor_t *parser_rrtype_descriptor_by_type(uint16_t type) { - if (type <= PARSER_RRTYPE_DLV) { + if (type <= 65535) { return &knot_rrtype_descriptors[type]; } return &knot_rrtype_descriptors[0]; diff --git a/src/zcompile/parser-util.c b/src/zcompile/parser-util.c index dde5411..c225872 100644 --- a/src/zcompile/parser-util.c +++ b/src/zcompile/parser-util.c @@ -62,7 +62,7 @@ #include "common/base32hex.h" #include "zcompile/parser-util.h" #include "zcompile/zcompile.h" -#include "libknot/util/descriptor.h" +#include "parser-descriptor.h" #include "libknot/util/utils.h" #include "zcompile/zcompile-error.h" @@ -812,6 +812,7 @@ uint32_t strtoserial(const char *nptr, const char **endptr) inline void write_uint32(void *dst, uint32_t data) { +/*!< \todo Check what this means and delete if obsolete. */ #ifdef ALLOW_UNALIGNED_ACCESSES *(uint32_t *) dst = htonl(data); #else @@ -925,7 +926,6 @@ time_t mktime_from_utc(const struct tm *tm) } /*!< Following functions are conversions from text to wire. */ - //#define DEBUG_UNKNOWN_RDATA #ifdef DEBUG_UNKNOWN_RDATA @@ -994,6 +994,8 @@ static inline int rdata_atom_is_domain(uint16_t type, size_t index) && (descriptor->wireformat[index] == KNOT_RDATA_WF_COMPRESSED_DNAME || descriptor->wireformat[index] == + KNOT_RDATA_WF_LITERAL_DNAME || + descriptor->wireformat[index] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME)); } @@ -1013,6 +1015,8 @@ static inline uint8_t rdata_atom_wireformat_type(uint16_t type, size_t index) return descriptor->wireformat[index]; } +typedef int (*printf_t)(const char *fmt, ...); + /*! * \brief Converts rdata wireformat to rdata items. * @@ -1028,10 +1032,12 @@ static ssize_t rdata_wireformat_to_rdata_atoms(const uint16_t *wireformat, const uint16_t data_size, knot_rdata_item_t **items) { - dbg_rdata("read length: %d\n", data_size); - uint16_t const *end = (uint16_t *)((uint8_t *)wireformat + (data_size)); + /*!< \todo This is so ugly, it makes me wanna puke. */ + uint16_t const *end = + (uint16_t *)((uint8_t *)wireformat + (data_size)); dbg_rdata("set end pointer: %p which means length: %d\n", end, (uint8_t *)end - (uint8_t *)wireformat); + dbg_rdata("Parsing following wf: "); size_t i; knot_rdata_item_t *temp_rdatas = malloc(sizeof(*temp_rdatas) * MAXRDATALEN); @@ -1050,69 +1056,78 @@ static ssize_t rdata_wireformat_to_rdata_atoms(const uint16_t *wireformat, descriptor->length, data_size); for (i = 0; i < descriptor->length; ++i) { + dbg_rdata("this particular item is type %d.\n", + rdata_atom_wireformat_type(rrtype, i)); int is_domain = 0; int is_wirestore = 0; size_t length = 0; length = 0; - int required = descriptor->length; + bool required = descriptor->fixed_items; switch (rdata_atom_wireformat_type(rrtype, i)) { case KNOT_RDATA_WF_COMPRESSED_DNAME: case KNOT_RDATA_WF_UNCOMPRESSED_DNAME: + dbg_rdata("Parsed item is a dname.\n"); is_domain = 1; break; case KNOT_RDATA_WF_LITERAL_DNAME: + dbg_rdata("Parsed item is a literal dname.\n"); is_domain = 1; is_wirestore = 1; break; case KNOT_RDATA_WF_BYTE: + dbg_rdata("Parsed item is a byte.\n"); length = sizeof(uint8_t); break; case KNOT_RDATA_WF_SHORT: + dbg_rdata("Parsed item is a short.\n"); length = sizeof(uint16_t); break; case KNOT_RDATA_WF_LONG: + dbg_rdata("Parsed item is a long.\n"); length = sizeof(uint32_t); break; + case KNOT_RDATA_WF_APL: + dbg_rdata("APL data.\n"); + case KNOT_RDATA_WF_TEXT_SINGLE: case KNOT_RDATA_WF_TEXT: + dbg_rdata("TEXT rdata.\n"); case KNOT_RDATA_WF_BINARYWITHLENGTH: + dbg_rdata("BINARYWITHLENGTH rdata.\n"); /* Length is stored in the first byte. */ - length = 1; - if ((uint8_t *)wireformat + length <= (uint8_t *)end) { - // length += wireformat[length - 1]; - length += *((uint8_t *)wireformat); - dbg_rdata("%d: set new length: %d\n", i, - length); - } - /*if (buffer_position(packet) + length <= end) { - length += buffer_current(packet)[length - 1]; - }*/ + length = data_size; break; case KNOT_RDATA_WF_A: + dbg_rdata("Parsed item is an IPv4 address.\n"); length = sizeof(in_addr_t); break; case KNOT_RDATA_WF_AAAA: + dbg_rdata("Parsed item is an IPv6 address.\n"); length = IP6ADDRLEN; break; case KNOT_RDATA_WF_BINARY: /* Remaining RDATA is binary. */ - dbg_rdata("%d: guessing length from pointers: %p %p\n", + dbg_rdata("BINARY: item %d: guessing length from pointers: %p %p. ", i, wireformat, end); length = (uint8_t *)end - (uint8_t *)wireformat; -// length = end - buffer_position(packet); - break; - case KNOT_RDATA_WF_APL: - length = (sizeof(uint16_t) /* address family */ - + sizeof(uint8_t) /* prefix */ - + sizeof(uint8_t)); /* length */ - if ((uint8_t *)wireformat + length <= (uint8_t *)end) { - /* Mask out negation bit. */ - length += (wireformat[length - 1] - & APL_LENGTH_MASK); - } + dbg_rdata("Result: %d.\n", + length); break; +// case KNOT_RDATA_WF_APL: +// length = (sizeof(uint16_t) /* address family */ +// + sizeof(uint8_t) /* prefix */ +// + sizeof(uint8_t)); /* length */ +// if ((uint8_t *)wireformat + length <= (uint8_t *)end) { +// /* Mask out negation bit. */ +// dbg_rdata("APL: length was %d. ", length); +// length += (wireformat[data_size - 1] +// & APL_LENGTH_MASK); +// dbg_rdata("APL: after masking: %d.\n", length); +// } +// break; case KNOT_RDATA_WF_IPSECGATEWAY: + dbg_rdata("Parsed item is an IPSECGATEWAY address.\n"); switch (rdata_atom_data(temp_rdatas[1])[0]) { /* gateway type */ default: @@ -1130,19 +1145,34 @@ static ssize_t rdata_wireformat_to_rdata_atoms(const uint16_t *wireformat, is_wirestore = 1; break; } + break; } if (is_domain) { - knot_dname_t *dname; + knot_dname_t *dname = NULL; + /* + * Since we don't know how many dnames there are + * in the whole wireformat we have to search for next + * '\0'. + */ + for (length = 0; + (length < ((uint8_t *)end - (uint8_t *)wireformat)) + && (((uint8_t *)wireformat)[length] != '\0'); + length++) { + ; + } + length++; + dbg_rdata("item %d: length derived from position of " + "0: %d\n", i, length); if (!required && (wireformat == end)) { break; } - dname = knot_dname_new_from_str((char *)wireformat, - length, - NULL); + dname = knot_dname_new_from_wire((uint8_t *)wireformat, + length, + NULL); if (dname == NULL) { dbg_rdata("malformed dname!\n"); @@ -1150,8 +1180,9 @@ static ssize_t rdata_wireformat_to_rdata_atoms(const uint16_t *wireformat, free(temp_rdatas); return KNOTDZCOMPILE_EBRDATA; } - dbg_rdata("%d: created dname: %s\n", i, - knot_dname_to_str(dname)); + + dbg_rdata("item %d: created dname: %s, length: %d\n", i, + knot_dname_to_str(dname), length); if (is_wirestore) { /*temp_rdatas[i].raw_data = @@ -1180,7 +1211,8 @@ static ssize_t rdata_wireformat_to_rdata_atoms(const uint16_t *wireformat, } } else { - dbg_rdata("%d :length: %d %d %p %p\n", i, length, + /*!< \todo This calculated length makes no sense! */ + dbg_rdata("item %d :length: %d calculated: %d (%p %p)\n", i, length, end - wireformat, wireformat, end); if ((uint8_t *)wireformat + length > (uint8_t *)end) { @@ -1188,7 +1220,8 @@ static ssize_t rdata_wireformat_to_rdata_atoms(const uint16_t *wireformat, /* Truncated RDATA. */ /*! \todo rdata purge */ free(temp_rdatas); - dbg_rdata("truncated rdata\n"); + dbg_rdata("truncated rdata, end pointer is exceeded by %d octets.\n", + (wireformat + length) - end); return KNOTDZCOMPILE_EBRDATA; } else { break; @@ -1224,15 +1257,13 @@ static ssize_t rdata_wireformat_to_rdata_atoms(const uint16_t *wireformat, dbg_rdata("wire: %p\n", wireformat); dbg_rdata("remaining now: %d\n", end - wireformat); - } dbg_rdata("%p %p\n", wireformat, (uint8_t *)wireformat); if (wireformat < end) { /* Trailing garbage. */ - dbg_rdata("w: %p e: %p %d\n", wireformat, end, end - wireformat); -// region_destroy(temp_region); + dbg_rdata("Garbage: w: %p e: %p %d\n", wireformat, end, end - wireformat); free(temp_rdatas); return KNOTDZCOMPILE_EBRDATA; } @@ -1240,6 +1271,8 @@ static ssize_t rdata_wireformat_to_rdata_atoms(const uint16_t *wireformat, *items = temp_rdatas; /* *rdatas = (rdata_atom_type *) region_alloc_init( region, temp_rdatas, i * sizeof(rdata_atom_type)); */ + dbg_rdata("wf_to_rdata_atoms: Succesfully converted %d items.\n", + i); return (ssize_t)i; } @@ -2062,8 +2095,9 @@ uint16_t * zparser_conv_loc(char *str) zc_error_prev_line("space expected after seconds"); return NULL; } - - if (sscanf(start, "%16lf", &d) != 1) { + + d = strtod(start, &start); + if (errno != 0) { zc_error_prev_line("error parsing seconds"); } @@ -2160,9 +2194,10 @@ uint16_t * zparser_conv_loc(char *str) if (!isspace((int)*str) && *str != '\0') { ++str; } - - if (sscanf(start, "%16lf", &d) != 1) { - zc_error_prev_line("error parsing altitude"); + + d = strtod(start, &start); + if (errno != 0) { + zc_error_prev_line("error parsing altitued"); } alt = (uint32_t)(10000000.0 + d * 100 + 0.5); @@ -2342,18 +2377,12 @@ void zadd_rdata_txt_wireformat(uint16_t *data, int first) return; } dbg_zp("Adding text!\n"); -// hex_print(data + 1, data[0]); knot_rdata_item_t *rd; /* First STR in str_seq, allocate 65K in first unused rdata * else find last used rdata */ if (first) { rd = &parser->temporary_items[parser->rdata_count]; -// if ((rd->data = (uint8_t *) region_alloc(parser->rr_region, -// sizeof(uint8_t) + 65535 * sizeof(uint8_t))) == NULL) { -// zc_error_prev_line("Could not allocate memory for TXT RR"); -// return; -// } rd->raw_data = alloc_rdata(65535 * sizeof(uint8_t)); if (rd->raw_data == NULL) { parser->error_occurred = KNOTDZCOMPILE_ENOMEM; @@ -2361,7 +2390,6 @@ void zadd_rdata_txt_wireformat(uint16_t *data, int first) parser->rdata_count++; rd->raw_data[0] = 0; } else { -// assert(0); rd = &parser->temporary_items[parser->rdata_count-1]; } @@ -2392,8 +2420,8 @@ void zadd_rdata_domain(knot_dname_t *dname) void parse_unknown_rdata(uint16_t type, uint16_t *wireformat) { - dbg_rdata("parsing unknown rdata for type: %d\n", type); -// buffer_type packet; + dbg_rdata("parsing unknown rdata for type: %s (%d)\n", + knot_rrtype_to_string(type), type); uint16_t size; ssize_t rdata_count; ssize_t i; @@ -2405,14 +2433,13 @@ void parse_unknown_rdata(uint16_t type, uint16_t *wireformat) return; } -// buffer_create_from(&packet, wireformat + 1, *wireformat); rdata_count = rdata_wireformat_to_rdata_atoms(wireformat + 1, type, size, &items); -// dbg_rdata("got %d items\n", rdata_count); - dbg_rdata("wf to items returned error: %s (%d)\n", - error_to_str(knot_zcompile_error_msgs, rdata_count), - rdata_count); + dbg_rdata("got %d items\n", rdata_count); if (rdata_count < 0) { + dbg_rdata("wf to items returned error: %s (%d)\n", + error_to_str(knot_zcompile_error_msgs, rdata_count), + rdata_count); zc_error_prev_line("bad unknown RDATA\n"); /*!< \todo leaks */ return; @@ -2429,6 +2456,8 @@ void parse_unknown_rdata(uint16_t type, uint16_t *wireformat) free(items); /* Free wireformat */ free(wireformat); + + dbg_rdata("parse_unknown_rdata: Successfuly parsed unknown rdata.\n"); } void set_bitnsec(uint8_t bits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE], diff --git a/src/zcompile/zcompile.c b/src/zcompile/zcompile.c index d84feb7..263d0d7 100644 --- a/src/zcompile/zcompile.c +++ b/src/zcompile/zcompile.c @@ -36,6 +36,8 @@ #include <sys/stat.h> #include "common/base32hex.h" +#include "common/log.h" +#include "knot/other/debug.h" #include "zcompile/zcompile.h" #include "zcompile/parser-util.h" #include "zcompile/zcompile-error.h" @@ -54,12 +56,6 @@ static long int totalrrs = 0; extern FILE *zp_get_in(void *scanner); -#ifdef KNOT_COMPILER_DEBUG -#define dbg_zp(msg...) fprintf(stderr, msg) -#else -#define dbg_zp(msg...) -#endif - /*! * \brief Adds RRSet to list. * @@ -86,6 +82,8 @@ static int rrset_list_add(rrset_list_t **head, knot_rrset_t *rrsig) tmp->data = rrsig; *head = tmp; } + + dbg_zp_verb("zp: rrset_add: Added RRSIG %p to list.\n", rrsig); return KNOTDZCOMPILE_EOK; } @@ -109,6 +107,8 @@ static void rrset_list_delete(rrset_list_t **head) } *head = NULL; + + dbg_zp("zp: list_delete: List deleleted.\n"); } static int find_rrset_for_rrsig_in_zone(knot_zone_contents_t *zone, @@ -127,10 +127,11 @@ static int find_rrset_for_rrsig_in_zone(knot_zone_contents_t *zone, rrsig->owner); } - dbg_zp("Found this node for RRSIG: %p\n", - tmp_node); + dbg_zp_verb("zp: find_rr_for_sig: Found this node for RRSIG: %p.\n", + tmp_node); if (tmp_node == NULL) { + dbg_zp("zp: find_rr_for_sig: There is no node for this RR.\n"); return KNOTDZCOMPILE_EINVAL; } @@ -139,23 +140,37 @@ static int find_rrset_for_rrsig_in_zone(knot_zone_contents_t *zone, knot_rdata_rrsig_type_covered( rrsig->rdata)); - dbg_zp("Found this rrset for RRSIG: %p\n", - tmp_rrset); + dbg_zp_verb("zp: find_rr_for_sig: Found this RRSet for RRSIG: %p.\n", + tmp_rrset); if (tmp_rrset == NULL) { + dbg_zp("zp: find_rr_for_sig: There is no RRSet " + "for this RRSIG.\n"); return KNOTDZCOMPILE_EINVAL; } if (tmp_rrset->rrsigs != NULL) { - knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &tmp_node, + int ret = knot_zone_contents_add_rrsigs(zone, rrsig, + &tmp_rrset, &tmp_node, KNOT_RRSET_DUPL_MERGE, 1); + if (ret != KNOT_EOK) { + dbg_zp("zp: find_rr_for_sig: Cannot add RRSIG.\n"); + return ret; + } knot_rrset_free(&rrsig); } else { - knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &tmp_node, + int ret = knot_zone_contents_add_rrsigs(zone, rrsig, + &tmp_rrset, &tmp_node, KNOT_RRSET_DUPL_SKIP, 1); + if (ret != KNOT_EOK) { + dbg_zp("zp: find_rr_for_sig: Cannot add RRSIG.\n"); + return ret; + } } - + + dbg_zp("zp: find_rr_for_sig: Found node: %p found rrset: %p.\n", + tmo_node, tmp_rrset); return KNOTDZCOMPILE_EOK; } @@ -173,18 +188,25 @@ static int find_rrset_for_rrsig_in_node(knot_zone_contents_t *zone, knot_node_get_rrset(node, rrsig_type_covered(rrsig)); if (tmp_rrset == NULL) { + dbg_zp("zp: find_rr_for_sig_in_node: Node does not contain " + "RRSet of type %s.\n", + knot_rrtype_to_string(rrsig_type_covered(rrsig))); return KNOTDZCOMPILE_EINVAL; } if (tmp_rrset->rrsigs != NULL) { - if (knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &node, + if (knot_zone_contents_add_rrsigs(zone, rrsig, + &tmp_rrset, &node, KNOT_RRSET_DUPL_MERGE, 1) < 0) { + dbg_zp("zp: find_rr_for_sig: Cannot add RRSIG.\n"); return KNOTDZCOMPILE_EINVAL; } knot_rrset_free(&rrsig); } else { - if (knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &node, + if (knot_zone_contents_add_rrsigs(zone, rrsig, + &tmp_rrset, &node, KNOT_RRSET_DUPL_SKIP, 1) < 0) { + dbg_zp("zp: find_rr_for_sig: Cannot add RRSIG.\n"); return KNOTDZCOMPILE_EINVAL; } } @@ -201,6 +223,8 @@ static knot_node_t *create_node(knot_zone_contents_t *zone, knot_node_t *(*node_get_func)(const knot_zone_contents_t *zone, const knot_dname_t *owner)) { + dbg_zp_verb("zp: create_node: Creating node using RRSet: %p.\n", + current_rrset); knot_node_t *node = knot_node_new(current_rrset->owner, NULL, 0); if (node_add_func(zone, node, 1, 0, 1) != 0) { @@ -215,6 +239,8 @@ static knot_node_t *create_node(knot_zone_contents_t *zone, static void process_rrsigs_in_node(knot_zone_contents_t *zone, knot_node_t *node) { + dbg_zp_verb("zp: process_rrsigs: Processing RRSIGS in node: %p.\n", + node); rrset_list_t *tmp = parser->node_rrsigs; while (tmp != NULL) { if (find_rrset_for_rrsig_in_node(zone, node, @@ -238,18 +264,22 @@ int process_rr(void) knot_rrtype_descriptor_t *descriptor = knot_rrtype_descriptor_by_type(current_rrset->type); - dbg_zp("%s\n", knot_dname_to_str(parser->current_rrset->owner)); - dbg_zp("type: %s\n", knot_rrtype_to_string(parser->current_rrset->type)); - dbg_zp("rdata count: %d\n", parser->current_rrset->rdata->count); -// hex_print(parser->current_rrset->rdata->items[0].raw_data, -// parser->current_rrset->rdata->items[0].raw_data[0]); +dbg_zp_exec_detail( + char *name = knot_dname_to_str(parser->current_rrset->owner); + dbg_zp_detail("zp: process_rr: Processing RR owned by: %s .\n", + name); + free(name); +); + dbg_zp_verb("zp: process_rr: Processing type: %s.\n", + knot_rrtype_to_string(parser->current_rrset->type)); + dbg_zp_verb("zp: process_rr: RDATA count: %d.\n",\ + parser->current_rrset->rdata->count); if (descriptor->fixed_items) { assert(current_rrset->rdata->count == descriptor->length); } assert(current_rrset->rdata->count > 0); - assert(knot_dname_is_fqdn(current_rrset->owner)); int (*node_add_func)(knot_zone_contents_t *, knot_node_t *, int, @@ -312,12 +342,15 @@ int process_rr(void) current_rrset->rclass, current_rrset->ttl); if (tmp_rrsig == NULL) { + dbg_zp("zp: process_rr: Cannot create tmp RRSIG.\n"); return KNOTDZCOMPILE_ENOMEM; } if (knot_rrset_add_rdata(tmp_rrsig, current_rrset->rdata) != KNOT_EOK) { knot_rrset_free(&tmp_rrsig); + dbg_zp("zp: process_rr: Cannot add data to tmp" + " RRSIG.\n"); return KNOTDZCOMPILE_EBRDATA; } @@ -353,18 +386,24 @@ int process_rr(void) current_rrset, node_add_func, node_get_func)) == NULL) { knot_rrset_free(&tmp_rrsig); + dbg_zp("zp: process_rr: Cannot " + "create new node.\n"); return KNOTDZCOMPILE_EBADNODE; } } } if (rrset_list_add(&parser->node_rrsigs, tmp_rrsig) != 0) { + dbg_zp("zp: process_rr: Cannot " + "create new node.\n"); return KNOTDZCOMPILE_ENOMEM; } - + + dbg_zp_verb("zp: process_rr: RRSIG proccesed successfully.\n"); return KNOTDZCOMPILE_EOK; } - + + /*! \todo Move RRSIG and RRSet handling to funtions. */ assert(current_rrset->type != KNOT_RRTYPE_RRSIG); knot_node_t *node = NULL; @@ -395,6 +434,8 @@ int process_rr(void) if ((node = create_node(contents, current_rrset, node_add_func, node_get_func)) == NULL) { + dbg_zp("zp: process_rr: Cannot " + "create new node.\n"); return KNOTDZCOMPILE_EBADNODE; } } @@ -406,11 +447,15 @@ int process_rr(void) current_rrset->rclass, current_rrset->ttl); if (rrset == NULL) { + dbg_zp("zp: process_rr: Cannot " + "create new RRSet.\n"); return KNOTDZCOMPILE_ENOMEM; } if (knot_rrset_add_rdata(rrset, current_rrset->rdata) != 0) { - free(rrset); + knot_rrset_free(&rrset); + dbg_zp("zp: process_rr: Cannot " + "add RDATA to RRSet.\n"); return KNOTDZCOMPILE_EBRDATA; } @@ -418,7 +463,9 @@ int process_rr(void) * any rrset to skip */ if (knot_zone_contents_add_rrset(contents, rrset, &node, KNOT_RRSET_DUPL_SKIP, 1) < 0) { - free(rrset); + knot_rrset_free(&rrset); + dbg_zp("zp: process_rr: Cannot " + "add RDATA to RRSet.\n"); return KNOTDZCOMPILE_EBRDATA; } } else { @@ -426,12 +473,14 @@ int process_rr(void) KNOT_RRTYPE_RRSIG && rrset->ttl != current_rrset->ttl) { zc_error_prev_line( - "TTL does not match the TTL of the RRset"); + "TTL does not match the TTL of the RRSet"); } if (knot_zone_contents_add_rrset(contents, current_rrset, &node, KNOT_RRSET_DUPL_MERGE, 1) < 0) { + dbg_zp("zp: process_rr: Cannot " + "merge RRSets.\n"); return KNOTDZCOMPILE_EBRDATA; } } @@ -441,9 +490,10 @@ int process_rr(void) } parser->last_node = node; - ++totalrrs; - + + dbg_zp_verb("zp: process_rr: RRSet %p processed successfully.\n", + parser->current_rrset); return KNOTDZCOMPILE_EOK; } @@ -454,12 +504,14 @@ static uint find_rrsets_orphans(knot_zone_contents_t *zone, rrset_list_t while (head != NULL) { if (find_rrset_for_rrsig_in_zone(zone, head->data) == 0) { found_rrsets += 1; - dbg_zp("RRSET succesfully found: owner %s type %s\n", + dbg_zp("zp: find_orphans: " + "RRSet succesfully found: owner %s type %s\n", knot_dname_to_str(head->data->owner), knot_rrtype_to_string(head->data->type)); } else { /* we can throw it away now */ - dbg_zp("RRSet not found for RRSIG: %s (%s)\n", + dbg_zp("zp: find_orphans: " + "RRSet not found for RRSIG: %s (%s)\n", knot_dname_to_str(head->data->owner), knot_rrtype_to_string( knot_rdata_rrsig_type_covered(head->data->rdata))); @@ -473,6 +525,10 @@ static uint find_rrsets_orphans(knot_zone_contents_t *zone, rrset_list_t static int zone_open(const char *filename, uint32_t ttl, uint16_t rclass, knot_node_t *origin, void *scanner, knot_dname_t *origin_from_config) { + /*!< \todo #1676 Implement proper locking. */ + zparser_init(filename, ttl, rclass, origin, origin_from_config); + + /* Open the zone file... */ if (strcmp(filename, "-") == 0) { zp_set_in(stdin, scanner); @@ -487,11 +543,7 @@ static int zone_open(const char *filename, uint32_t ttl, uint16_t rclass, return 0; } } - - /*!< \todo #1676 Implement proper locking. */ - - zparser_init(filename, ttl, rclass, origin, origin_from_config); - + return 1; } @@ -503,6 +555,8 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, zonefile); return KNOTDZCOMPILE_EINVAL; } + + dbg_zp("zp: zone_read: Reading zone: %s.\n", zonefile); /* Check that we can write to outfile. */ FILE *f = fopen(outfile, "wb"); @@ -526,9 +580,8 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, } knot_node_t *origin_node = knot_node_new(dname, NULL, 0); - + knot_dname_release(dname); /* Stored in node or should be freed. */ if (origin_node == NULL) { - knot_dname_release(dname); return KNOTDZCOMPILE_ENOMEM; } @@ -554,10 +607,9 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, origin_from_config)) { zc_error_prev_line("Cannot open '%s' (%s).", zonefile, strerror(errno)); - zparser_free(); zp_lex_destroy(scanner); knot_dname_release(origin_from_config); - knot_node_free(&origin_node, 0); +// knot_node_free(&origin_node, 0); return KNOTDZCOMPILE_EZONEINVAL; } @@ -566,7 +618,8 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, FILE *in_file = (FILE *)zp_get_in(scanner); fclose(in_file); zp_lex_destroy(scanner); - knot_node_free(&origin_node, 0); + knot_dname_release(origin_from_config); +// knot_node_free(&origin_node, 0); return KNOTDZCOMPILE_ESYNT; } @@ -579,7 +632,8 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, /*!< \todo #1676 Implement proper locking. */ - dbg_zp("zp complete %p\n", parser->current_zone); + dbg_zp("zp: zone_read: Parse complete for %s.\n", + zonefile); if (parser->last_node && parser->node_rrsigs != NULL) { /* assign rrsigs to last node in the zone*/ @@ -588,15 +642,15 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, rrset_list_delete(&parser->node_rrsigs); } - dbg_zp("zone parsed\n"); + dbg_zp("zp: zone_read: RRSIGs processed.\n"); if (!(parser->current_zone && knot_node_rrset(parser->current_zone->contents->apex, KNOT_RRTYPE_SOA))) { zc_error_prev_line("Zone file does not contain SOA record!\n"); - knot_zone_deep_free(&parser->current_zone, 1); - zparser_free(); - knot_node_free(&origin_node, 0); +// knot_zone_deep_free(&parser->current_zone, 1); + knot_dname_release(origin_from_config); +// knot_node_free(&origin_node, 0); return KNOTDZCOMPILE_EZONEINVAL; } @@ -604,7 +658,7 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, found_orphans = find_rrsets_orphans(contents, parser->rrsig_orphans); - dbg_zp("%u orphans found\n", found_orphans); + dbg_zp("zp: zone_read: %u RRSIG orphans found.\n", found_orphans); rrset_list_delete(&parser->rrsig_orphans); @@ -618,17 +672,17 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, /*! \todo Check return value. */ knot_zone_contents_adjust(contents); - dbg_zp("rdata adjusted\n"); + dbg_zp("zp: zone_read: Zone adjusted.\n"); if (parser->errors != 0) { - fprintf(stderr, - "Parser finished with error, not dumping the zone!\n"); + log_zone_error("Parser finished with %d error(s), " + "not dumping the zone!\n", + parser->errors); } else { int fd = open(outfile, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG); if (fd < 0) { - fprintf(stderr, - "Could not open destination file for db: %s.\n", - outfile); + log_zone_error("Could not open destination file for db: %s.\n", + outfile); totalerrors++; } else { crc_t crc; @@ -636,22 +690,22 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, semantic_checks, zonefile, &crc); if (ret != KNOT_EOK) { - fprintf(stderr, "Could not dump zone, reason: " - "%s.\n", knot_strerror(ret)); + log_zone_error("Could not dump zone, reason: " + "%s.\n", knot_strerror(ret)); remove(outfile); totalerrors++; } else { /* Write CRC file. */ char *crc_path = knot_zdump_crc_file(outfile); if (crc_path == NULL) { - fprintf(stderr, - "Could not get crc file path.\n"); + log_zone_error( + "Could not get crc file path.\n"); remove(outfile); totalerrors++; } else { FILE *f_crc = fopen(crc_path, "w"); if (f_crc == NULL) { - fprintf(stderr, + log_zone_error( "Could not open crc file \n"); remove(outfile); totalerrors++; @@ -667,12 +721,13 @@ int zone_read(const char *name, const char *zonefile, const char *outfile, } - dbg_zp("zone dumped.\n"); + dbg_zp("zp: zone_read: Zone %s dumped successfully.\n", + zonefile); } fflush(stdout); totalerrors += parser->errors; - zparser_free(); + knot_dname_release(origin_from_config); return totalerrors; } diff --git a/src/zcompile/zcompile_main.c b/src/zcompile/zcompile_main.c index c873af6..4b631ce 100644 --- a/src/zcompile/zcompile_main.c +++ b/src/zcompile/zcompile_main.c @@ -19,6 +19,7 @@ #include <stdlib.h> #include "zcompile/zcompile.h" +#include "common/log.h" #include <config.h> static void help(int argc, char **argv) @@ -81,21 +82,21 @@ int main(int argc, char **argv) origin = argv[optind]; zonefile = argv[optind + 1]; - // Initialize log (no output) - //log_init(0); - //log_levels_set(LOGT_STDOUT, LOG_ANY, LOG_MASK(LOG_DEBUG)); - - printf("Parsing file '%s', origin '%s' ...\n", - zonefile, origin); + // Initialize log (no syslog) + log_init(); + log_levels_set(LOGT_SYSLOG, LOG_ANY, 0); + log_zone_info("Parsing file '%s', origin '%s' ...\n", + zonefile, origin); parser = zparser_create(); if (!parser) { - fprintf(stderr, "Failed to create parser.\n"); + log_server_error("Failed to create parser.\n"); //log_close(); return 1; } int error = zone_read(origin, zonefile, outfile, semantic_checks); + zparser_free(); if (error != 0) { /* FIXME! */ @@ -107,7 +108,7 @@ int main(int argc, char **argv) // } return 1; } else { - printf("Compilation successful.\n"); + log_zone_info("Compilation of '%s' successful.\n", origin); } //log_close(); diff --git a/src/zcompile/zparser.y b/src/zcompile/zparser.y index 59f037d..b353fbe 100644 --- a/src/zcompile/zparser.y +++ b/src/zcompile/zparser.y @@ -54,6 +54,7 @@ #include <assert.h> #include "zcompile/parser-util.h" +#include "common/log.h" #include "libknot/libknot.h" #include "zcompile/zcompile.h" @@ -198,7 +199,7 @@ line: NL assert(parser->current_rrset->rdata == NULL); if (knot_rrset_add_rdata(parser->current_rrset, tmp_rdata) != 0) { - fprintf(stderr, "Could not add rdata!\n"); + log_zone_error("Could not add rdata!\n"); } // tmp_rdata->next = tmp_rdata; // parser->current_rrset->rdata = tmp_rdata; @@ -223,7 +224,7 @@ line: NL if ((ret = process_rr()) != 0) { char *name = knot_dname_to_str(parser->current_rrset->owner); - fprintf(stderr, "Error: could not process RRSet\n" + log_zone_error("Error: could not process RRSet\n" "owner: %s reason: %s\n", name, error_to_str(knot_zcompile_error_msgs, ret)); @@ -258,7 +259,7 @@ line: NL * of the converting function was not able to convert. */ if (parser->error_occurred == KNOTDZCOMPILE_ENOMEM) { /* Ran out of memory in converting functions. */ - fprintf(stderr, "Parser ran out " + log_zone_error("Parser ran out " "of memory, aborting!\n"); knot_rrset_deep_free(&(parser->current_rrset), 0, 0, 0); @@ -691,7 +692,7 @@ str_sp_seq: STR char *result = malloc($1.len + $3.len + 1); if (result == NULL) { ERR_ALLOC_FAILED; - fprintf(stderr, "Parser ran out of memory, aborting!\n"); + log_zone_error("Parser ran out of memory, aborting!\n"); knot_rrset_deep_free(&(parser->current_rrset), 0, 0, 0); knot_zone_deep_free(&(parser->current_zone), @@ -719,7 +720,7 @@ str_dot_seq: STR char *result = malloc($1.len + $3.len + 1); if (result == NULL) { ERR_ALLOC_FAILED; - fprintf(stderr, "Parser ran out of memory, aborting!\n"); + log_zone_error("Parser ran out of memory, aborting!\n"); knot_rrset_deep_free(&(parser->current_rrset), 0, 0, 0); knot_zone_deep_free(&(parser->current_zone), @@ -751,7 +752,7 @@ dotted_str: STR char *result = malloc($1.len + 2); if (result == NULL) { ERR_ALLOC_FAILED; - fprintf(stderr, "Parser ran out of memory, aborting!\n"); + log_zone_error("Parser ran out of memory, aborting!\n"); knot_rrset_deep_free(&(parser->current_rrset), 0, 0, 0); knot_zone_deep_free(&(parser->current_zone), @@ -771,7 +772,7 @@ dotted_str: STR char *result = malloc($1.len + $3.len + 2); if (result == NULL) { ERR_ALLOC_FAILED; - fprintf(stderr, "Parser ran out of memory, aborting!\n"); + log_zone_error("Parser ran out of memory, aborting!\n"); knot_rrset_deep_free(&(parser->current_rrset), 0, 0, 0); knot_zone_deep_free(&(parser->current_zone), @@ -1563,23 +1564,19 @@ zparser_type *zparser_create() result->current_rrset = knot_rrset_new(NULL, 0, 0, 0); if (result->current_rrset == NULL) { - ERR_ALLOC_FAILED; free(result->temporary_items); free(result); return NULL; } result->root_domain = knot_dname_new_from_str(".", 1, NULL); -// printf("THE NEW ROOT: %p\n", result->root_domain); if (result->root_domain == NULL) { - ERR_ALLOC_FAILED; free(result->temporary_items); free(result->current_rrset); free(result); return NULL; } - knot_dname_retain(result->root_domain); return result; } @@ -1610,6 +1607,7 @@ zparser_init(const char *filename, uint32_t ttl, uint16_t rclass, parser->filename = filename; parser->rdata_count = 0; parser->origin_from_config = origin_from_config; + knot_dname_retain(origin_from_config); parser->last_node = origin; // parser->root_domain = NULL; @@ -1630,9 +1628,10 @@ zparser_init(const char *filename, uint32_t ttl, uint16_t rclass, void zparser_free() { -// knot_dname_release(parser->root_domain); + knot_dname_release(parser->root_domain); // knot_dname_release(parser->prev_dname); - knot_dname_free(&parser->origin_from_config); + knot_zone_deep_free(&parser->current_zone, 1); + knot_dname_release(parser->origin_from_config); free(parser->temporary_items); if (parser->current_rrset != NULL) { free(parser->current_rrset); @@ -1649,13 +1648,29 @@ yyerror(void *scanner, const char *message) static void error_va_list(unsigned line, const char *fmt, va_list args) { + char sbuf[4096] = {0}; + size_t buflen = sizeof(sbuf) - 1; + char *buf = sbuf; + int wb = 0; if (parser->filename) { - fprintf(stderr, "%s:%u: ", parser->filename, line); + wb = snprintf(buf, buflen, "%s:%u: ", + parser->filename, line); + if (wb > 0) { + buf += wb; + buflen -= wb; + } } - fprintf(stderr, "error: "); - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); - + + wb = vsnprintf(buf, buflen, fmt, args); + if (wb > 0) { + buf += wb; + buflen -= wb; + *buf = '\n'; + *(buf + 1) = '\0'; + } + + log_zone_error("%s", sbuf); + ++parser->errors; parser->error_occurred = 1; } @@ -1685,12 +1700,28 @@ zc_error(const char *fmt, ...) static void warning_va_list(unsigned line, const char *fmt, va_list args) { + char sbuf[4096] = {0}; + size_t buflen = sizeof(sbuf) - 1; + char *buf = sbuf; + int wb = 0; if (parser->filename) { - fprintf(stderr, "%s:%u: ", parser->filename, line); + wb = snprintf(buf, buflen, "%s:%u: ", + parser->filename, line); + if (wb > 0) { + buf += wb; + buflen -= wb; + } } - fprintf(stderr, "warning: "); - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); + + wb = vsnprintf(buf, buflen, fmt, args); + if (wb > 0) { + buf += wb; + buflen -= wb; + *buf = '\n'; + *(buf + 1) = '\0'; + } + + log_zone_warning("%s", sbuf); } void |