From f8344baf6451c7cef2b9b8d19ea9495b84ecafd3 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 4 Jan 2017 13:16:47 +1030 Subject: [PATCH] ccan: update, new modules. ccan/autodata, ccan/breakpoint, ccan/crypto/hmac_sha256, ccan/crypto/hkdf_sha256, ccan/fdpass and ccan/io/fdpass. Signed-off-by: Rusty Russell --- Makefile | 27 +- ccan/README | 2 +- ccan/ccan/autodata/LICENSE | 1 + ccan/ccan/autodata/_info | 111 ++++++ ccan/ccan/autodata/autodata.c | 80 ++++ ccan/ccan/autodata/autodata.h | 109 ++++++ ccan/ccan/autodata/test/helper.c | 6 + ccan/ccan/autodata/test/run-fools.c | 71 ++++ ccan/ccan/autodata/test/run.c | 41 +++ ccan/ccan/breakpoint/LICENSE | 1 + ccan/ccan/breakpoint/_info | 34 ++ ccan/ccan/breakpoint/breakpoint.c | 32 ++ ccan/ccan/breakpoint/breakpoint.h | 24 ++ ccan/ccan/breakpoint/test/run.c | 17 + ccan/ccan/cppmagic/test/run.c | 2 +- ccan/ccan/crypto/hkdf_sha256/LICENSE | 1 + ccan/ccan/crypto/hkdf_sha256/_info | 30 ++ ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.c | 97 +++++ ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.h | 22 ++ .../crypto/hkdf_sha256/test/api-rfc5869.c | 101 +++++ ccan/ccan/crypto/hmac_sha256/LICENSE | 1 + ccan/ccan/crypto/hmac_sha256/_info | 52 +++ ccan/ccan/crypto/hmac_sha256/hmac_sha256.c | 160 ++++++++ ccan/ccan/crypto/hmac_sha256/hmac_sha256.h | 86 +++++ .../crypto/hmac_sha256/test/api-rfc4231.c | 159 ++++++++ ccan/ccan/crypto/shachain/shachain.c | 9 +- ccan/ccan/crypto/shachain/shachain.h | 6 +- ccan/ccan/crypto/shachain/tools/Makefile | 39 ++ ccan/ccan/crypto/shachain/tools/shachain48.c | 58 +++ ccan/ccan/fdpass/LICENSE | 1 + ccan/ccan/fdpass/_info | 65 ++++ ccan/ccan/fdpass/fdpass.c | 83 +++++ ccan/ccan/fdpass/fdpass.h | 23 ++ ccan/ccan/fdpass/test/run.c | 88 +++++ ccan/ccan/io/backend.h | 12 +- ccan/ccan/io/fdpass/LICENSE | 1 + ccan/ccan/io/fdpass/_info | 95 +++++ ccan/ccan/io/fdpass/fdpass.c | 54 +++ ccan/ccan/io/fdpass/fdpass.h | 68 ++++ ccan/ccan/io/fdpass/test/run.c | 51 +++ ccan/ccan/io/io.c | 119 ++---- ccan/ccan/io/io.h | 40 +- ccan/ccan/io/poll.c | 60 +-- ccan/ccan/io/test/run-01-start-finish-debug.c | 2 - ccan/ccan/io/test/run-01-start-finish.c | 7 - ccan/ccan/io/test/run-02-read-debug.c | 2 - ccan/ccan/io/test/run-02-read.c | 7 - ccan/ccan/io/test/run-03-readpartial-debug.c | 2 - ccan/ccan/io/test/run-03-readpartial.c | 7 - ccan/ccan/io/test/run-04-writepartial-debug.c | 2 - ccan/ccan/io/test/run-04-writepartial.c | 7 - ccan/ccan/io/test/run-05-write-debug.c | 2 - ccan/ccan/io/test/run-05-write.c | 7 - ccan/ccan/io/test/run-06-idle.c | 4 - ccan/ccan/io/test/run-07-break-debug.c | 2 - ccan/ccan/io/test/run-07-break.c | 7 - ccan/ccan/io/test/run-09-connect-debug.c | 2 - ccan/ccan/io/test/run-09-connect.c | 7 - ccan/ccan/io/test/run-12-bidir-debug.c | 2 - ccan/ccan/io/test/run-12-bidir.c | 7 - .../io/test/run-14-duplex-both-read-debug.c | 2 - ccan/ccan/io/test/run-14-duplex-both-read.c | 7 - ccan/ccan/io/test/run-15-timeout.c | 7 - ccan/ccan/io/test/run-16-duplex-test-debug.c | 2 - ccan/ccan/io/test/run-16-duplex-test.c | 7 - ccan/ccan/io/test/run-17-homemade-io-debug.c | 2 - ccan/ccan/io/test/run-17-homemade-io.c | 7 - ccan/ccan/io/test/run-18-errno-debug.c | 2 - ccan/ccan/io/test/run-18-errno.c | 9 +- ccan/ccan/io/test/run-19-always-debug.c | 2 - ccan/ccan/io/test/run-19-always.c | 7 - ccan/ccan/ptr_valid/LICENSE | 1 + ccan/ccan/ptr_valid/_info | 29 ++ ccan/ccan/ptr_valid/ptr_valid.c | 344 ++++++++++++++++++ ccan/ccan/ptr_valid/ptr_valid.h | 229 ++++++++++++ ccan/ccan/ptr_valid/test/run-string.c | 56 +++ ccan/ccan/ptr_valid/test/run.c | 90 +++++ ccan/ccan/tal/tal.c | 111 ++++-- ccan/ccan/tal/tal.h | 61 +++- ccan/ccan/tal/test/run-destructor2.c | 38 ++ ccan/ccan/tal/test/run-free.c | 5 +- ccan/ccan/time/time.c | 2 +- ccan/ccan/time/time.h | 2 + 83 files changed, 2883 insertions(+), 354 deletions(-) create mode 120000 ccan/ccan/autodata/LICENSE create mode 100644 ccan/ccan/autodata/_info create mode 100644 ccan/ccan/autodata/autodata.c create mode 100644 ccan/ccan/autodata/autodata.h create mode 100644 ccan/ccan/autodata/test/helper.c create mode 100644 ccan/ccan/autodata/test/run-fools.c create mode 100644 ccan/ccan/autodata/test/run.c create mode 120000 ccan/ccan/breakpoint/LICENSE create mode 100644 ccan/ccan/breakpoint/_info create mode 100644 ccan/ccan/breakpoint/breakpoint.c create mode 100644 ccan/ccan/breakpoint/breakpoint.h create mode 100644 ccan/ccan/breakpoint/test/run.c create mode 120000 ccan/ccan/crypto/hkdf_sha256/LICENSE create mode 100644 ccan/ccan/crypto/hkdf_sha256/_info create mode 100644 ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.c create mode 100644 ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.h create mode 100644 ccan/ccan/crypto/hkdf_sha256/test/api-rfc5869.c create mode 120000 ccan/ccan/crypto/hmac_sha256/LICENSE create mode 100644 ccan/ccan/crypto/hmac_sha256/_info create mode 100644 ccan/ccan/crypto/hmac_sha256/hmac_sha256.c create mode 100644 ccan/ccan/crypto/hmac_sha256/hmac_sha256.h create mode 100644 ccan/ccan/crypto/hmac_sha256/test/api-rfc4231.c create mode 100644 ccan/ccan/crypto/shachain/tools/Makefile create mode 100644 ccan/ccan/crypto/shachain/tools/shachain48.c create mode 120000 ccan/ccan/fdpass/LICENSE create mode 100644 ccan/ccan/fdpass/_info create mode 100644 ccan/ccan/fdpass/fdpass.c create mode 100644 ccan/ccan/fdpass/fdpass.h create mode 100644 ccan/ccan/fdpass/test/run.c create mode 120000 ccan/ccan/io/fdpass/LICENSE create mode 100644 ccan/ccan/io/fdpass/_info create mode 100644 ccan/ccan/io/fdpass/fdpass.c create mode 100644 ccan/ccan/io/fdpass/fdpass.h create mode 100644 ccan/ccan/io/fdpass/test/run.c delete mode 100644 ccan/ccan/io/test/run-01-start-finish-debug.c delete mode 100644 ccan/ccan/io/test/run-02-read-debug.c delete mode 100644 ccan/ccan/io/test/run-03-readpartial-debug.c delete mode 100644 ccan/ccan/io/test/run-04-writepartial-debug.c delete mode 100644 ccan/ccan/io/test/run-05-write-debug.c delete mode 100644 ccan/ccan/io/test/run-07-break-debug.c delete mode 100644 ccan/ccan/io/test/run-09-connect-debug.c delete mode 100644 ccan/ccan/io/test/run-12-bidir-debug.c delete mode 100644 ccan/ccan/io/test/run-14-duplex-both-read-debug.c delete mode 100644 ccan/ccan/io/test/run-16-duplex-test-debug.c delete mode 100644 ccan/ccan/io/test/run-17-homemade-io-debug.c delete mode 100644 ccan/ccan/io/test/run-18-errno-debug.c delete mode 100644 ccan/ccan/io/test/run-19-always-debug.c create mode 120000 ccan/ccan/ptr_valid/LICENSE create mode 100644 ccan/ccan/ptr_valid/_info create mode 100644 ccan/ccan/ptr_valid/ptr_valid.c create mode 100644 ccan/ccan/ptr_valid/ptr_valid.h create mode 100644 ccan/ccan/ptr_valid/test/run-string.c create mode 100644 ccan/ccan/ptr_valid/test/run.c create mode 100644 ccan/ccan/tal/test/run-destructor2.c diff --git a/Makefile b/Makefile index 79c152307..75e6819ea 100644 --- a/Makefile +++ b/Makefile @@ -53,16 +53,22 @@ CORE_SRC := \ CORE_OBJS := $(CORE_SRC:.c=.o) CCAN_OBJS := \ + ccan-asort.o \ + ccan-autodata.o \ + ccan-breakpoint.o \ + ccan-crypto-hmac.o \ + ccan-crypto-hkdf.o \ ccan-crypto-ripemd160.o \ ccan-crypto-sha256.o \ ccan-crypto-shachain.o \ - ccan-asort.o \ ccan-crypto-siphash24.o \ ccan-err.o \ + ccan-fdpass.o \ ccan-htable.o \ ccan-ilog.o \ ccan-io-io.o \ ccan-io-poll.o \ + ccan-io-fdpass.o \ ccan-isaac.o \ ccan-isaac64.o \ ccan-list.o \ @@ -89,6 +95,8 @@ CCAN_HEADERS := \ $(CCANDIR)/ccan/alignof/alignof.h \ $(CCANDIR)/ccan/array_size/array_size.h \ $(CCANDIR)/ccan/asort/asort.h \ + $(CCANDIR)/ccan/autodata/autodata.h \ + $(CCANDIR)/ccan/breakpoint/breakpoint.h \ $(CCANDIR)/ccan/build_assert/build_assert.h \ $(CCANDIR)/ccan/cast/cast.h \ $(CCANDIR)/ccan/cdump/cdump.h \ @@ -96,16 +104,20 @@ CCAN_HEADERS := \ $(CCANDIR)/ccan/compiler/compiler.h \ $(CCANDIR)/ccan/container_of/container_of.h \ $(CCANDIR)/ccan/cppmagic/cppmagic.h \ + $(CCANDIR)/ccan/crypto/hkdf_sha256/hkdf_sha256.h \ + $(CCANDIR)/ccan/crypto/hmac_sha256/hmac_sha256.h \ $(CCANDIR)/ccan/crypto/ripemd160/ripemd160.h \ $(CCANDIR)/ccan/crypto/sha256/sha256.h \ $(CCANDIR)/ccan/crypto/shachain/shachain.h \ $(CCANDIR)/ccan/crypto/siphash24/siphash24.h \ $(CCANDIR)/ccan/endian/endian.h \ $(CCANDIR)/ccan/err/err.h \ + $(CCANDIR)/ccan/fdpass/fdpass.h \ $(CCANDIR)/ccan/htable/htable.h \ $(CCANDIR)/ccan/htable/htable_type.h \ $(CCANDIR)/ccan/ilog/ilog.h \ $(CCANDIR)/ccan/io/backend.h \ + $(CCANDIR)/ccan/io/fdpass/fdpass.h \ $(CCANDIR)/ccan/io/io.h \ $(CCANDIR)/ccan/io/io_plan.h \ $(CCANDIR)/ccan/isaac/isaac.h \ @@ -118,6 +130,7 @@ CCAN_HEADERS := \ $(CCANDIR)/ccan/opt/private.h \ $(CCANDIR)/ccan/order/order.h \ $(CCANDIR)/ccan/pipecmd/pipecmd.h \ + $(CCANDIR)/ccan/ptr_valid/ptr_valid.h \ $(CCANDIR)/ccan/ptrint/ptrint.h \ $(CCANDIR)/ccan/read_write_all/read_write_all.h \ $(CCANDIR)/ccan/short_types/short_types.h \ @@ -337,6 +350,8 @@ include daemon/Makefile unittest/%: % $(VALGRIND) $(VALGRIND_TEST_ARGS) $* +ccan-breakpoint.o: $(CCANDIR)/ccan/breakpoint/breakpoint.c + $(CC) $(CFLAGS) -c -o $@ $< ccan-tal.o: $(CCANDIR)/ccan/tal/tal.c $(CC) $(CFLAGS) -c -o $@ $< ccan-tal-str.o: $(CCANDIR)/ccan/tal/str/str.c @@ -351,6 +366,8 @@ ccan-list.o: $(CCANDIR)/ccan/list/list.c $(CC) $(CFLAGS) -c -o $@ $< ccan-asort.o: $(CCANDIR)/ccan/asort/asort.c $(CC) $(CFLAGS) -c -o $@ $< +ccan-autodata.o: $(CCANDIR)/ccan/autodata/autodata.c + $(CC) $(CFLAGS) -c -o $@ $< ccan-read_write_all.o: $(CCANDIR)/ccan/read_write_all/read_write_all.c $(CC) $(CFLAGS) -c -o $@ $< ccan-str.o: $(CCANDIR)/ccan/str/str.c @@ -369,6 +386,10 @@ ccan-noerr.o: $(CCANDIR)/ccan/noerr/noerr.c $(CC) $(CFLAGS) -c -o $@ $< ccan-str-hex.o: $(CCANDIR)/ccan/str/hex/hex.c $(CC) $(CFLAGS) -c -o $@ $< +ccan-crypto-hmac.o: $(CCANDIR)/ccan/crypto/hmac_sha256/hmac_sha256.c + $(CC) $(CFLAGS) -c -o $@ $< +ccan-crypto-hkdf.o: $(CCANDIR)/ccan/crypto/hkdf_sha256/hkdf_sha256.c + $(CC) $(CFLAGS) -c -o $@ $< ccan-crypto-shachain.o: $(CCANDIR)/ccan/crypto/shachain/shachain.c $(CC) $(CFLAGS) -c -o $@ $< ccan-crypto-sha256.o: $(CCANDIR)/ccan/crypto/sha256/sha256.c @@ -397,7 +418,11 @@ ccan-io-io.o: $(CCANDIR)/ccan/io/io.c $(CC) $(CFLAGS) -c -o $@ $< ccan-io-poll.o: $(CCANDIR)/ccan/io/poll.c $(CC) $(CFLAGS) -c -o $@ $< +ccan-io-fdpass.o: $(CCANDIR)/ccan/io/fdpass/fdpass.c + $(CC) $(CFLAGS) -c -o $@ $< ccan-pipecmd.o: $(CCANDIR)/ccan/pipecmd/pipecmd.c $(CC) $(CFLAGS) -c -o $@ $< ccan-mem.o: $(CCANDIR)/ccan/mem/mem.c $(CC) $(CFLAGS) -c -o $@ $< +ccan-fdpass.o: $(CCANDIR)/ccan/fdpass/fdpass.c + $(CC) $(CFLAGS) -c -o $@ $< diff --git a/ccan/README b/ccan/README index 21b0a5c0d..0698a0be7 100644 --- a/ccan/README +++ b/ccan/README @@ -1,3 +1,3 @@ CCAN imported from http://ccodearchive.net. -CCAN version: init-2302-g6b74669 +CCAN version: init-2338-g97ac583 diff --git a/ccan/ccan/autodata/LICENSE b/ccan/ccan/autodata/LICENSE new file mode 120000 index 000000000..2354d1294 --- /dev/null +++ b/ccan/ccan/autodata/LICENSE @@ -0,0 +1 @@ +../../licenses/BSD-MIT \ No newline at end of file diff --git a/ccan/ccan/autodata/_info b/ccan/ccan/autodata/_info new file mode 100644 index 000000000..507de1a1e --- /dev/null +++ b/ccan/ccan/autodata/_info @@ -0,0 +1,111 @@ +#include "config.h" +#include +#include + +/** + * autodata - stash pointers in your binary for automatic registration + * + * This code allows declarations in your source which you can gather + * together at runtime to form tables. This is often used in place of + * having a central registration function or table. + * + * Note that this technique does not work in general for shared libaries, + * only for code compiled into a binary. + * + * License: BSD-MIT + * + * Example: + * // Distributed commandline option registration (note: ccan/opt is better!) + * #include + * #include + * #include + * #include + * #include + * + * static bool verbose = false; + * + * // This would normally be in a header, so any C file can use it. + * struct option { + * char c; + * bool takes_arg; + * bool (*cb)(char *optarg); + * }; + * AUTODATA_TYPE(options, struct option); + * #define REGISTER_OPTION(optstruct) \ + * AUTODATA(options, (optstruct)) + * + * // Now a few examples (could be anywhere in source) + * static bool verbose_cb(char *unused) + * { + * verbose = true; + * return true; + * } + * static struct option dash_v = { 'v', false, verbose_cb }; + * REGISTER_OPTION(&dash_v); + * + * static bool chdir_cb(char *dir) + * { + * if (verbose) + * printf("chdir to %s. ", dir); + * if (chdir(dir) != 0) + * return false; + * return true; + * } + * static struct option dash_C = { 'C', true, chdir_cb }; + * REGISTER_OPTION(&dash_C); + * + * int main(int argc, char *argv[]) + * { + * struct option **opts; + * size_t i, num; + * int o; + * char *optstring, *p; + * + * // Gather together all the registered options. + * opts = autodata_get(options, &num); + * + * // Make pretty string for getopt(). + * p = optstring = malloc(num * 2 + 1); + * for (i = 0; i < num; i++) { + * *(p++) = opts[i]->c; + * if (opts[i]->takes_arg) + * *(p++) = ':'; + * } + * *p = '\0'; + * + * while ((o = getopt(argc, argv, optstring)) != -1) { + * if (o == '?') + * exit(1); + * // Call callback in matching option. + * for (i = 0; i < num; i++) { + * if (opts[i]->c == o) { + * if (!opts[i]->cb(optarg)) + * err(1, "parsing -%c", o); + * break; + * } + * } + * } + * // free up gathered option table. + * autodata_free(opts); + * + * if (verbose) + * printf("verbose mode on\n"); + * return 0; + * } + * // Given "-v" outputs "verbose mode on\n" + * // Given "-v -C /" outputs "chdir to /. verbose mode on\n" + */ +int main(int argc, char *argv[]) +{ + /* Expect exactly one argument */ + if (argc != 2) + return 1; + + if (strcmp(argv[1], "depends") == 0) { + printf("ccan/compiler\n"); + printf("ccan/ptr_valid\n"); + return 0; + } + + return 1; +} diff --git a/ccan/ccan/autodata/autodata.c b/ccan/ccan/autodata/autodata.c new file mode 100644 index 000000000..e8086e3ab --- /dev/null +++ b/ccan/ccan/autodata/autodata.c @@ -0,0 +1,80 @@ +// Licensed under BSD-MIT: See LICENSE. +#include "autodata.h" +#include +#include +#include + +#if HAVE_SECTION_START_STOP +void *autodata_get_section(void *start, void *stop, size_t *nump) +{ + *nump = (void **)(stop) - (void **)(start); + return start; +} + +void autodata_free(void *table UNNEEDED) +{ +} +#else +#include + +void *autodata_make_table(const void *example, const char *name, size_t *nump) +{ + const char *start, *end, *tag; + struct ptr_valid_batch batch; + const void *const magic = (void *)AUTODATA_MAGIC; + void **table = NULL; + char first_magic; + + if (!ptr_valid_batch_start(&batch)) + return NULL; + + /* Get range to search. */ + for (start = (char *)((intptr_t)example & ~(getpagesize() - 1)); + ptr_valid_batch(&batch, start-getpagesize(), 1, sizeof(void *), + false); + start -= getpagesize()); + + for (end = (char *)((intptr_t)example & ~(getpagesize() - 1)); + ptr_valid_batch(&batch, end, 1, sizeof(void *), false); + end += getpagesize()); + + *nump = 0; + first_magic = *(char *)&magic; + for (tag = memchr(start, first_magic, end - start); + tag; + tag = memchr(tag+1, first_magic, end - (tag + 1))) { + void *adata[4]; + + /* We can read 4 void *'s here? */ + if (tag + sizeof(adata) > end) + continue; + + memcpy(adata, tag, sizeof(adata)); + + /* False match? */ + if (adata[0] != (void *)AUTODATA_MAGIC || adata[1] != tag) + continue; + + /* OK, check name. */ + if (!ptr_valid_batch_string(&batch, adata[3]) + || strcmp(name, adata[3]) != 0) + continue; + + if (!ptr_valid_batch_read(&batch, (char *)adata[2])) + continue; + + table = realloc(table, sizeof(void *) * (*nump + 1)); + if (!table) + break; + table[*nump] = adata[2]; + (*nump)++; + } + ptr_valid_batch_end(&batch); + return table; +} + +void autodata_free(void *table) +{ + free(table); +} +#endif diff --git a/ccan/ccan/autodata/autodata.h b/ccan/ccan/autodata/autodata.h new file mode 100644 index 000000000..3f0a71a3f --- /dev/null +++ b/ccan/ccan/autodata/autodata.h @@ -0,0 +1,109 @@ +// Licensed under BSD-MIT: See LICENSE. +#ifndef CCAN_AUTODATA_H +#define CCAN_AUTODATA_H +#include "config.h" +#include +#include + +#if HAVE_SECTION_START_STOP + +/** + * AUTODATA_TYPE - declare the type for a given autodata name. + * @name: the name for this set of autodata + * @type: the type this autodata points to + * + * This macro is usually placed in a header: it must preceed any + * autodata functions in the file. + * + * Example: + * #include + * + * // My set of char pointers. + * AUTODATA_TYPE(names, char); + */ +#define AUTODATA_TYPE(name, type) \ + typedef type autodata_##name##_; \ + extern type *__start_xautodata_##name[], *__stop_xautodata_##name[] + +/** + * AUTODATA - add a pointer to this autodata set + * @name: the name of the set of autodata + * @ptr: the compile-time-known pointer + * + * This embeds @ptr into the binary, with the tag corresponding to + * @name (which must look like a valid identifier, no punctuation!). + * The type of @ptr must match that given by AUTODATA_TYPE. It is + * usually a file-level declaration. + * + * Example: + * // Put two char pointers into the names AUTODATA set. + * AUTODATA(names, "Arabella"); + * AUTODATA(names, "Alex"); + */ +#define AUTODATA(name, ptr) \ + static const autodata_##name##_ *NEEDED \ + __attribute__((section("xautodata_" #name))) \ + AUTODATA_VAR_(name, __LINE__) = (ptr); + +/** + * autodata_get - get an autodata set + * @name: the name of the set of autodata + * @nump: the number of items in the set. + * + * This extract the embedded pointers matching @name. It may fail + * if malloc() fails, or if there is no AUTODATA at all. + * + * The return will be a pointer to an array of @type pointers (from + * AUTODATA_TYPE). + * + * Example: + * static void print_embedded_names(void) + * { + * unsigned int i; + * size_t num; + * char **n = autodata_get(names, &num); + * + * for (i = 0; i < num; i++) + * printf("%s\n", n[i]); + * } + */ +#define autodata_get(name, nump) \ + ((autodata_##name##_ **) \ + autodata_get_section(__start_xautodata_##name, \ + __stop_xautodata_##name, (nump))) +#endif /* HAVE_SECTION_START_STOP */ + +/** + * autodata_free - free the table returned by autodata_get() + * @p: the table. + */ +void autodata_free(void *p); + +/* Internal functions. */ +#define AUTODATA_VAR__(name, line) autodata_##name##_##line +#define AUTODATA_VAR_(name, line) AUTODATA_VAR__(name, line) + +#if HAVE_SECTION_START_STOP +void *autodata_get_section(void *start, void *stop, size_t *nump); +#else +#define AUTODATA_TYPE(name, type) \ + typedef type autodata_##name##_; \ + static const void *autodata_##name##_ex = &autodata_##name##_ex + +#define AUTODATA_MAGIC ((long)0xFEEDA10DA7AF00D5ULL) +#define AUTODATA(name, ptr) \ + static const autodata_##name##_ *NEEDED \ + AUTODATA_VAR_(name, __LINE__)[4] = \ + { (void *)AUTODATA_MAGIC, \ + (void *)&AUTODATA_VAR_(name, __LINE__), \ + (ptr), \ + (void *)#name } + +#define autodata_get(name, nump) \ + ((autodata_##name##_ **) \ + autodata_make_table(&autodata_##name##_ex, #name, (nump))) + +void *autodata_make_table(const void *example, const char *name, size_t *nump); +#endif + +#endif /* CCAN_AUTODATA_H */ diff --git a/ccan/ccan/autodata/test/helper.c b/ccan/ccan/autodata/test/helper.c new file mode 100644 index 000000000..5655914d7 --- /dev/null +++ b/ccan/ccan/autodata/test/helper.c @@ -0,0 +1,6 @@ +/* Check that linking together works. */ +#include + +AUTODATA_TYPE(autostrings, char); + +AUTODATA(autostrings, "helper"); diff --git a/ccan/ccan/autodata/test/run-fools.c b/ccan/ccan/autodata/test/run-fools.c new file mode 100644 index 000000000..47a3b0679 --- /dev/null +++ b/ccan/ccan/autodata/test/run-fools.c @@ -0,0 +1,71 @@ +#include +/* Include the C files directly. */ +#include +#include + +AUTODATA_TYPE(autostrings, char); + +AUTODATA(autostrings, "genuine"); + +#if !HAVE_SECTION_START_STOP +/* These are all fake, to test the various failure paths. */ +/* Hopefully fake_alpha or fake_omega will test run-past-end. */ +static const void *NEEDED fake_alpha[] = { (void *)AUTODATA_MAGIC }; + +/* Wrong magic in the middle. */ +static const void *NEEDED fake1[] = { (void *)(AUTODATA_MAGIC ^ 0x10000), + (void *)&fake1, + "fake1", + (void *)"autostrings" }; + +/* Wrong self pointer. */ +static const void *NEEDED fake2[] = { (void *)AUTODATA_MAGIC, + (void *)&fake1, + "fake2", + (void *)"autostrings" }; + +/* Wrong name. */ +static const void *NEEDED fake3[] = { (void *)AUTODATA_MAGIC, + (void *)&fake3, + "fake3", + (void *)"autostrings2" }; + +/* Invalid self-pointer. */ +static const void *NEEDED fake4[] = { (void *)AUTODATA_MAGIC, + (void *)1UL, + "fake4", + (void *)"autostrings" }; + +/* Invalid name pointer */ +static const void *NEEDED fake5[] = { (void *)AUTODATA_MAGIC, + (void *)&fake5, + "fake5", + (void *)1UL }; + +/* Invalid contents pointer */ +static const void *NEEDED fake6[] = { (void *)AUTODATA_MAGIC, + (void *)&fake6, + (char *)1UL, + (void *)"autostrings" }; + +static const void *NEEDED fake_omega[] = { (void *)AUTODATA_MAGIC }; +#endif + +int main(void) +{ + char **table; + size_t num; + + /* This is how many tests you plan to run */ + plan_tests(2); + + table = autodata_get(autostrings, &num); + ok1(num == 2); + ok1((!strcmp(table[0], "genuine") && !strcmp(table[1], "helper")) + || (!strcmp(table[1], "genuine") && !strcmp(table[0], "helper"))); + + autodata_free(table); + + /* This exits depending on whether all tests passed */ + return exit_status(); +} diff --git a/ccan/ccan/autodata/test/run.c b/ccan/ccan/autodata/test/run.c new file mode 100644 index 000000000..d70faaa2b --- /dev/null +++ b/ccan/ccan/autodata/test/run.c @@ -0,0 +1,41 @@ +#include +/* Include the C files directly. */ +#include +#include + +AUTODATA_TYPE(autostrings, char); + +AUTODATA(autostrings, "hello"); +AUTODATA(autostrings, "world"); + +int main(void) +{ + char **table; + size_t num; + int i, hello = -1, world = -1, helper = -1; + + /* This is how many tests you plan to run */ + plan_tests(4); + + table = autodata_get(autostrings, &num); + ok1(num == 3); + + for (i = 0; i < num; i++) { + if (strcmp(table[i], "hello") == 0) + hello = i; + else if (strcmp(table[i], "world") == 0) + world = i; + else if (strcmp(table[i], "helper") == 0) + helper = i; + else + fail("Unknown entry %s", table[i]); + } + ok1(hello != -1); + ok1(world != -1); + ok1(helper != -1); + + autodata_free(table); + + /* This exits depending on whether all tests passed */ + return exit_status(); +} diff --git a/ccan/ccan/breakpoint/LICENSE b/ccan/ccan/breakpoint/LICENSE new file mode 120000 index 000000000..b7951dabd --- /dev/null +++ b/ccan/ccan/breakpoint/LICENSE @@ -0,0 +1 @@ +../../licenses/CC0 \ No newline at end of file diff --git a/ccan/ccan/breakpoint/_info b/ccan/ccan/breakpoint/_info new file mode 100644 index 000000000..272ee25d3 --- /dev/null +++ b/ccan/ccan/breakpoint/_info @@ -0,0 +1,34 @@ +#include "config.h" +#include +#include + +/** + * breakpoint - break if the program is run under gdb. + * + * This code allows you to insert breakpoints within a program. These will + * do nothing unless your program is run under GDB. + * + * License: CC0 (Public domain) + * + * Example: + * #include + * + * int main(void) + * { + * breakpoint(); + * return 0; + * } + */ +int main(int argc, char *argv[]) +{ + /* Expect exactly one argument */ + if (argc != 2) + return 1; + + if (strcmp(argv[1], "depends") == 0) { + printf("ccan/compiler\n"); + return 0; + } + + return 1; +} diff --git a/ccan/ccan/breakpoint/breakpoint.c b/ccan/ccan/breakpoint/breakpoint.c new file mode 100644 index 000000000..279e29a1d --- /dev/null +++ b/ccan/ccan/breakpoint/breakpoint.c @@ -0,0 +1,32 @@ +/* CC0 (Public domain) - see LICENSE file for details + * + * Idea for implementation thanks to stackoverflow.com: + * http://stackoverflow.com/questions/3596781/detect-if-gdb-is-running + */ +#include + +bool breakpoint_initialized; +bool breakpoint_under_debug; + +/* This doesn't get called if we're under GDB. */ +static void trap(int signum) +{ + breakpoint_initialized = true; +} + +void breakpoint_init(void) +{ + struct sigaction old, new; + + new.sa_handler = trap; + new.sa_flags = 0; + sigemptyset(&new.sa_mask); + sigaction(SIGTRAP, &new, &old); + kill(getpid(), SIGTRAP); + sigaction(SIGTRAP, &old, NULL); + + if (!breakpoint_initialized) { + breakpoint_initialized = true; + breakpoint_under_debug = true; + } +} diff --git a/ccan/ccan/breakpoint/breakpoint.h b/ccan/ccan/breakpoint/breakpoint.h new file mode 100644 index 000000000..6283a0105 --- /dev/null +++ b/ccan/ccan/breakpoint/breakpoint.h @@ -0,0 +1,24 @@ +/* CC0 (Public domain) - see LICENSE file for details */ +#ifndef CCAN_BREAKPOINT_H +#define CCAN_BREAKPOINT_H +#include +#include +#include +#include +#include + +void breakpoint_init(void) COLD; +extern bool breakpoint_initialized; +extern bool breakpoint_under_debug; + +/** + * breakpoint - stop if running under the debugger. + */ +static inline void breakpoint(void) +{ + if (!breakpoint_initialized) + breakpoint_init(); + if (breakpoint_under_debug) + kill(getpid(), SIGTRAP); +} +#endif /* CCAN_BREAKPOINT_H */ diff --git a/ccan/ccan/breakpoint/test/run.c b/ccan/ccan/breakpoint/test/run.c new file mode 100644 index 000000000..b36e9c228 --- /dev/null +++ b/ccan/ccan/breakpoint/test/run.c @@ -0,0 +1,17 @@ +#include +#include +#include + +int main(void) +{ + /* This is how many tests you plan to run */ + plan_tests(2); + + breakpoint(); + + ok1(breakpoint_initialized); + ok1(!breakpoint_under_debug); + + /* This exits depending on whether all tests passed */ + return exit_status(); +} diff --git a/ccan/ccan/cppmagic/test/run.c b/ccan/ccan/cppmagic/test/run.c index ee02c6c8d..7c0aa7f6a 100644 --- a/ccan/ccan/cppmagic/test/run.c +++ b/ccan/ccan/cppmagic/test/run.c @@ -15,7 +15,7 @@ static inline void check1(const char *orig, const char *expand, #define CHECK1(orig, match) \ check1(#orig, CPPMAGIC_STRINGIFY(orig), match) -#define TESTRECURSE() R CPPMAGIC_DEFER1(_TESTRECURSE)()() +#define TESTRECURSE() R CPPMAGIC_DEFER1(_TESTRECURSE) ()() #define _TESTRECURSE() TESTRECURSE #define TESTMAP1(x) <> diff --git a/ccan/ccan/crypto/hkdf_sha256/LICENSE b/ccan/ccan/crypto/hkdf_sha256/LICENSE new file mode 120000 index 000000000..2b1feca54 --- /dev/null +++ b/ccan/ccan/crypto/hkdf_sha256/LICENSE @@ -0,0 +1 @@ +../../../licenses/BSD-MIT \ No newline at end of file diff --git a/ccan/ccan/crypto/hkdf_sha256/_info b/ccan/ccan/crypto/hkdf_sha256/_info new file mode 100644 index 000000000..b8b3cb67b --- /dev/null +++ b/ccan/ccan/crypto/hkdf_sha256/_info @@ -0,0 +1,30 @@ +#include "config.h" +#include +#include + +/** + * crypto/hkdf_sha256 - RFC5869 Hardened Key Derivation Functions using SHA256 + * + * This code implements the hkdf described in RFC5869. + * + * License: BSD-MIT + * Maintainer: Rusty Russell + */ +int main(int argc, char *argv[]) +{ + /* Expect exactly one argument */ + if (argc != 2) + return 1; + + if (strcmp(argv[1], "depends") == 0) { + printf("ccan/crypto/hmac_sha256\n"); + return 0; + } + + if (strcmp(argv[1], "testdepends") == 0) { + printf("ccan/str/hex\n"); + return 0; + } + + return 1; +} diff --git a/ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.c b/ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.c new file mode 100644 index 000000000..f36bf67ad --- /dev/null +++ b/ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.c @@ -0,0 +1,97 @@ +/* MIT (BSD) license - see LICENSE file for details */ +#include +#include +#include +#include + +void hkdf_sha256(void *okm, size_t okm_size, + const void *s, size_t ssize, + const void *k, size_t ksize, + const void *info, size_t isize) +{ + struct hmac_sha256 prk, t; + struct hmac_sha256_ctx ctx; + unsigned char c; + + assert(okm_size < 255 * sizeof(t)); + + /* RFC 5869: + * + * 2.2. Step 1: Extract + * + * HKDF-Extract(salt, IKM) -> PRK + * + * Options: + * Hash a hash function; HashLen denotes the length of the + * hash function output in octets + * + * Inputs: + * salt optional salt value (a non-secret random value); + * if not provided, it is set to a string of HashLen zeros. + * IKM input keying material + * + * Output: + * PRK a pseudorandom key (of HashLen octets) + * + * The output PRK is calculated as follows: + * + * PRK = HMAC-Hash(salt, IKM) + */ + hmac_sha256(&prk, s, ssize, k, ksize); + + /* + * 2.3. Step 2: Expand + * + * HKDF-Expand(PRK, info, L) -> OKM + * + * Options: + * Hash a hash function; HashLen denotes the length of the + * hash function output in octets + * + * Inputs: + * PRK a pseudorandom key of at least HashLen octets + * (usually, the output from the extract step) + * info optional context and application specific information + * (can be a zero-length string) + * L length of output keying material in octets + * (<= 255*HashLen) + * + * Output: + * OKM output keying material (of L octets) + * + * The output OKM is calculated as follows: + * + * N = ceil(L/HashLen) + * T = T(1) | T(2) | T(3) | ... | T(N) + * OKM = first L octets of T + * + * where: + * T(0) = empty string (zero length) + * T(1) = HMAC-Hash(PRK, T(0) | info | 0x01) + * T(2) = HMAC-Hash(PRK, T(1) | info | 0x02) + * T(3) = HMAC-Hash(PRK, T(2) | info | 0x03) + * ... + * + * (where the constant concatenated to the end of each T(n) is a + * single octet.) + */ + c = 1; + hmac_sha256_init(&ctx, &prk, sizeof(prk)); + hmac_sha256_update(&ctx, info, isize); + hmac_sha256_update(&ctx, &c, 1); + hmac_sha256_done(&ctx, &t); + + while (okm_size > sizeof(t)) { + memcpy(okm, &t, sizeof(t)); + okm = (char *)okm + sizeof(t); + okm_size -= sizeof(t); + + c++; + hmac_sha256_init(&ctx, &prk, sizeof(prk)); + hmac_sha256_update(&ctx, &t, sizeof(t)); + hmac_sha256_update(&ctx, info, isize); + hmac_sha256_update(&ctx, &c, 1); + hmac_sha256_done(&ctx, &t); + } + memcpy(okm, &t, okm_size); +} diff --git a/ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.h b/ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.h new file mode 100644 index 000000000..cf95c5afd --- /dev/null +++ b/ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.h @@ -0,0 +1,22 @@ +#ifndef CCAN_CRYPTO_HKDF_SHA256_H +#define CCAN_CRYPTO_HKDF_SHA256_H +/* BSD-MIT - see LICENSE file for details */ +#include "config.h" +#include + +/** + * hkdf_sha256 - generate a derived key + * @okm: where to output the key + * @okm_size: the number of bytes pointed to by @okm (must be less than 255*32) + * @s: salt + * @ssize: the number of bytes pointed to by @s + * @k: pointer to input key + * @ksize: the number of bytes pointed to by @k + * @info: pointer to info + * @isize: the number of bytes pointed to by @info + */ +void hkdf_sha256(void *okm, size_t okm_size, + const void *s, size_t ssize, + const void *k, size_t ksize, + const void *info, size_t isize); +#endif /* CCAN_CRYPTO_HKDF_SHA256_H */ diff --git a/ccan/ccan/crypto/hkdf_sha256/test/api-rfc5869.c b/ccan/ccan/crypto/hkdf_sha256/test/api-rfc5869.c new file mode 100644 index 000000000..3e3bdbfdf --- /dev/null +++ b/ccan/ccan/crypto/hkdf_sha256/test/api-rfc5869.c @@ -0,0 +1,101 @@ +/* From RFC5869 Appendix A + * + * https://tools.ietf.org/html/rfc5869 + */ +#include +#include +#include +#include +#include + +struct test { + const char *ikm, *salt, *info, *okm; +}; + +static struct test tests[] = { { + /* Test Case 1 + Basic test case with SHA-256 + */ + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", /* (22 octets) */ + "000102030405060708090a0b0c", /* (13 octets) */ + "f0f1f2f3f4f5f6f7f8f9", /* (10 octets) */ + "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865", /* (42 octets) */ + }, + { + /* Test Case 2 + * + * Test with SHA-256 and longer inputs/outputs */ + "000102030405060708090a0b0c0d0e0f" + "101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f" + "303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f", /* (80 octets) */ + "606162636465666768696a6b6c6d6e6f" + "707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", /* (80 octets )*/ + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", /* (80 octets) */ + "b11e398dc80327a1c8e7f78c596a4934" + "4f012eda2d4efad8a050cc4c19afa97c" + "59045a99cac7827271cb41c65e590e09" + "da3275600c2f09b8367793a9aca3db71" + "cc30c58179ec3e87c14c01d5c1f3434f" + "1d87" /* (82 octets) */ + }, + { + /* Test Case 3 + * + * Test with SHA-256 and zero-length salt/info + */ + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", /* (22 octets) */ + "", /* (0 octets) */ + "", /* (0 octets) */ + "8da4e775a563c18f715f802a063c5a31" + "b8a11f5c5ee1879ec3454e5f3c738d2d" + "9d201395faa4b61a96c8" /* (42 octets) */ + } +}; + +static void *fromhex(const char *str, size_t *len) +{ + void *p; + + *len = hex_data_size(strlen(str)); + p = malloc(*len); + if (!hex_decode(str, strlen(str), p, *len)) + abort(); + return p; +} + +int main(void) +{ + size_t i; + + plan_tests(sizeof(tests) / sizeof(tests[0])); + + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { + size_t ksize, ssize, isize, okmsize; + void *k, *s, *info, *expect, *okm; + + k = fromhex(tests[i].ikm, &ksize); + s = fromhex(tests[i].salt, &ssize); + info = fromhex(tests[i].info, &isize); + expect = fromhex(tests[i].okm, &okmsize); + okm = malloc(okmsize); + hkdf_sha256(okm, okmsize, s, ssize, k, ksize, info, isize); + ok1(memcmp(okm, expect, okmsize) == 0); + + free(k); + free(s); + free(info); + free(expect); + free(okm); + } + + return exit_status(); +} diff --git a/ccan/ccan/crypto/hmac_sha256/LICENSE b/ccan/ccan/crypto/hmac_sha256/LICENSE new file mode 120000 index 000000000..2b1feca54 --- /dev/null +++ b/ccan/ccan/crypto/hmac_sha256/LICENSE @@ -0,0 +1 @@ +../../../licenses/BSD-MIT \ No newline at end of file diff --git a/ccan/ccan/crypto/hmac_sha256/_info b/ccan/ccan/crypto/hmac_sha256/_info new file mode 100644 index 000000000..386123872 --- /dev/null +++ b/ccan/ccan/crypto/hmac_sha256/_info @@ -0,0 +1,52 @@ +#include "config.h" +#include +#include + +/** + * crypto/hmac_sha256 - RFC2104 HMAC using SHA256. + * + * This code implements RFC2104, which is a fairly standard HMAC. + * + * License: BSD-MIT + * Maintainer: Rusty Russell + * + * Example: + * #include + * #include + * #include + * #include + * + * // Simple demonstration: idential strings will have the same hash, but + * // two different strings will not. + * int main(int argc, char *argv[]) + * { + * struct hmac_sha256 hash1, hash2; + * + * if (argc != 3) + * errx(1, "Usage: %s ", argv[0]); + * + * hmac_sha256(&hash1, "key", 3, argv[1], strlen(argv[1])); + * hmac_sha256(&hash2, "key", 3, argv[2], strlen(argv[2])); + * printf("Hash is %s\n", memcmp(&hash1, &hash2, sizeof(hash1)) + * ? "different" : "same"); + * return 0; + * } + */ +int main(int argc, char *argv[]) +{ + /* Expect exactly one argument */ + if (argc != 2) + return 1; + + if (strcmp(argv[1], "depends") == 0) { + printf("ccan/crypto/sha256\n"); + return 0; + } + + if (strcmp(argv[1], "testdepends") == 0) { + printf("ccan/str/hex\n"); + return 0; + } + + return 1; +} diff --git a/ccan/ccan/crypto/hmac_sha256/hmac_sha256.c b/ccan/ccan/crypto/hmac_sha256/hmac_sha256.c new file mode 100644 index 000000000..0392afe5c --- /dev/null +++ b/ccan/ccan/crypto/hmac_sha256/hmac_sha256.c @@ -0,0 +1,160 @@ +/* MIT (BSD) license - see LICENSE file for details */ +#include +#include + +#define IPAD 0x3636363636363636ULL +#define OPAD 0x5C5C5C5C5C5C5C5CULL + +#define BLOCK_U64S (HMAC_SHA256_BLOCKSIZE / sizeof(uint64_t)) + +static inline void xor_block(uint64_t block[BLOCK_U64S], uint64_t pad) +{ + size_t i; + + for (i = 0; i < BLOCK_U64S; i++) + block[i] ^= pad; +} + +void hmac_sha256_init(struct hmac_sha256_ctx *ctx, + const void *k, size_t ksize) +{ + struct sha256 hashed_key; + /* We use k_opad as k_ipad temporarily. */ + uint64_t *k_ipad = ctx->k_opad; + + /* (keys longer than B bytes are first hashed using H) */ + if (ksize > HMAC_SHA256_BLOCKSIZE) { + sha256(&hashed_key, k, ksize); + k = &hashed_key; + ksize = sizeof(hashed_key); + } + + /* From RFC2104: + * + * (1) append zeros to the end of K to create a B byte string + * (e.g., if K is of length 20 bytes and B=64, then K will be + * appended with 44 zero bytes 0x00) + */ + memcpy(k_ipad, k, ksize); + memset((char *)k_ipad + ksize, 0, HMAC_SHA256_BLOCKSIZE - ksize); + + /* + * (2) XOR (bitwise exclusive-OR) the B byte string computed + * in step (1) with ipad + */ + xor_block(k_ipad, IPAD); + + /* + * We start (4) here, appending text later: + * + * (3) append the stream of data 'text' to the B byte string resulting + * from step (2) + * (4) apply H to the stream generated in step (3) + */ + sha256_init(&ctx->sha); + sha256_update(&ctx->sha, k_ipad, HMAC_SHA256_BLOCKSIZE); + + /* + * (5) XOR (bitwise exclusive-OR) the B byte string computed in + * step (1) with opad + */ + xor_block(ctx->k_opad, IPAD^OPAD); +} + +void hmac_sha256_update(struct hmac_sha256_ctx *ctx, const void *p, size_t size) +{ + /* This is the appending-text part of this: + * + * (3) append the stream of data 'text' to the B byte string resulting + * from step (2) + * (4) apply H to the stream generated in step (3) + */ + sha256_update(&ctx->sha, p, size); +} + +void hmac_sha256_done(struct hmac_sha256_ctx *ctx, + struct hmac_sha256 *hmac) +{ + /* (4) apply H to the stream generated in step (3) */ + sha256_done(&ctx->sha, &hmac->sha); + + /* + * (6) append the H result from step (4) to the B byte string + * resulting from step (5) + * (7) apply H to the stream generated in step (6) and output + * the result + */ + sha256_init(&ctx->sha); + sha256_update(&ctx->sha, ctx->k_opad, sizeof(ctx->k_opad)); + sha256_update(&ctx->sha, &hmac->sha, sizeof(hmac->sha)); + sha256_done(&ctx->sha, &hmac->sha); +} + +#if 1 +void hmac_sha256(struct hmac_sha256 *hmac, + const void *k, size_t ksize, + const void *d, size_t dsize) +{ + struct hmac_sha256_ctx ctx; + + hmac_sha256_init(&ctx, k, ksize); + hmac_sha256_update(&ctx, d, dsize); + hmac_sha256_done(&ctx, hmac); +} +#else +/* Direct mapping from MD5 example in RFC2104 */ +void hmac_sha256(struct hmac_sha256 *hmac, + const void *key, size_t key_len, + const void *text, size_t text_len) +{ + struct sha256_ctx context; + unsigned char k_ipad[65]; /* inner padding - + * key XORd with ipad + */ + unsigned char k_opad[65]; /* outer padding - + * key XORd with opad + *//* start out by storing key in pads */ + unsigned char tk[32]; + int i; + + /* if key is longer than 64 bytes reset it to key=MD5(key) */ + if (key_len > 64) { + + struct sha256_ctx tctx; + + sha256_init(&tctx); + sha256_update(&tctx, key, key_len); + sha256_done(&tctx, tk); + + key = tk; + key_len = 32; + } + bzero( k_ipad, sizeof k_ipad); + bzero( k_opad, sizeof k_opad); + bcopy( key, k_ipad, key_len); + bcopy( key, k_opad, key_len); + + /* XOR key with ipad and opad values */ + for (i=0; i<64; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + /* + * perform inner MD5 + */ + sha256_init(&context); /* init context for 1st + * pass */ + sha256_update(&context, k_ipad, 64); /* start with inner pad */ + sha256_update(&context, text, text_len); /* then text of datagram */ + sha256_done(&context, &hmac->sha); /* finish up 1st pass */ + /* + * perform outer MD5 + */ + sha256_init(&context); /* init context for 2nd + * pass */ + sha256_update(&context, k_opad, 64); /* start with outer pad */ + sha256_update(&context, &hmac->sha, 32); /* then results of 1st + * hash */ + sha256_done(&context, &hmac->sha); /* finish up 2nd pass */ +} +#endif diff --git a/ccan/ccan/crypto/hmac_sha256/hmac_sha256.h b/ccan/ccan/crypto/hmac_sha256/hmac_sha256.h new file mode 100644 index 000000000..79f1660cd --- /dev/null +++ b/ccan/ccan/crypto/hmac_sha256/hmac_sha256.h @@ -0,0 +1,86 @@ +#ifndef CCAN_CRYPTO_HMAC_SHA256_H +#define CCAN_CRYPTO_HMAC_SHA256_H +/* BSD-MIT - see LICENSE file for details */ +#include "config.h" +#include +#include +#include + +/* Number of bytes per block. */ +#define HMAC_SHA256_BLOCKSIZE 64 + +/** + * struct hmac_sha256 - structure representing a completed HMAC. + */ +struct hmac_sha256 { + struct sha256 sha; +}; + +/** + * hmac_sha256 - return hmac of an object with a key. + * @hmac: the hmac to fill in + * @k: pointer to the key, + * @ksize: the number of bytes pointed to by @k + * @d: pointer to memory, + * @dsize: the number of bytes pointed to by @d + */ +void hmac_sha256(struct hmac_sha256 *hmac, + const void *k, size_t ksize, + const void *d, size_t dsize); + +/** + * struct hmac_sha256_ctx - structure to store running context for hmac_sha256 + */ +struct hmac_sha256_ctx { + struct sha256_ctx sha; + uint64_t k_opad[HMAC_SHA256_BLOCKSIZE / sizeof(uint64_t)]; +}; + +/** + * hmac_sha256_init - initialize an HMAC_SHA256 context. + * @ctx: the hmac_sha256_ctx to initialize + * @k: pointer to the key, + * @ksize: the number of bytes pointed to by @k + * + * This must be called before hmac_sha256_update or hmac_sha256_done. + * + * If it was already initialized, this forgets anything which was + * hashed before. + * + * Example: + * static void hmac_all(const char *key, + * const char **arr, struct hmac_sha256 *hash) + * { + * size_t i; + * struct hmac_sha256_ctx ctx; + * + * hmac_sha256_init(&ctx, key, strlen(key)); + * for (i = 0; arr[i]; i++) + * hmac_sha256_update(&ctx, arr[i], strlen(arr[i])); + * hmac_sha256_done(&ctx, hash); + * } + */ +void hmac_sha256_init(struct hmac_sha256_ctx *ctx, + const void *k, size_t ksize); + +/** + * hmac_sha256_update - include some memory in the hash. + * @ctx: the hmac_sha256_ctx to use + * @p: pointer to memory, + * @size: the number of bytes pointed to by @p + * + * You can call this multiple times to hash more data, before calling + * hmac_sha256_done(). + */ +void hmac_sha256_update(struct hmac_sha256_ctx *ctx, const void *p, size_t size); + +/** + * hmac_sha256_done - finish HMAC_SHA256 and return the hash + * @ctx: the hmac_sha256_ctx to complete + * @res: the hash to return. + * + * Note that @ctx is *destroyed* by this, and must be reinitialized. + * To avoid that, pass a copy instead. + */ +void hmac_sha256_done(struct hmac_sha256_ctx *hmac_sha256, struct hmac_sha256 *res); +#endif /* CCAN_CRYPTO_HMAC_SHA256_H */ diff --git a/ccan/ccan/crypto/hmac_sha256/test/api-rfc4231.c b/ccan/ccan/crypto/hmac_sha256/test/api-rfc4231.c new file mode 100644 index 000000000..ed99b0eb8 --- /dev/null +++ b/ccan/ccan/crypto/hmac_sha256/test/api-rfc4231.c @@ -0,0 +1,159 @@ +/* From RFC4231 "Identifiers and Test Vectors for HMAC-SHA-224, HMAC-SHA-256, + * HMAC-SHA-384, and HMAC-SHA-512" + * + * https://tools.ietf.org/html/rfc4231 + */ +#include +#include +#include +#include +#include + +struct test { + const char *key, *data, *hmac; +}; + +static struct test tests[] = { { + /* Test Case 1 */ + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", /* (20 bytes) */ + "4869205468657265", /* ("Hi There") */ + "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7" + }, + /* Test Case 2: + Test with a key shorter than the length of the HMAC output. */ + { + "4a656665", /* ("Jefe") */ + /* ("what do ya want for nothing?") */ + "7768617420646f2079612077616e7420666f72206e6f7468696e673f", + "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843" + }, + { + /* Test Case 3 + + Test with a combined length of key and data that is larger than 64 + bytes (= block-size of SHA-224 and SHA-256). + */ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", /* (20 bytes) */ + "dddddddddddddddddddddddddddddddd" + "dddddddddddddddddddddddddddddddd" + "dddddddddddddddddddddddddddddddd" + "dddd", /* (50 bytes) */ + "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe" + }, + { + /* Test Case 4 + + Test with a combined length of key and data that is larger than 64 + bytes (= block-size of SHA-224 and SHA-256). + */ + "0102030405060708090a0b0c0d0e0f10111213141516171819", /* (25 bytes) */ + "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" + "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" + "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" + "cdcd", /* (50 bytes) */ + "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b" + }, +#if 0 + { + /* Test Case 5 + + Test with a truncation of output to 128 bits. + */ + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", /* (20 bytes) */ + "546573742057697468205472756e636174696f6e", /* ("Test With Truncation") */ + "a3b6167473100ee06e0c796c2955552b" + }, +#endif + { + /* Test Case 6 + + Test with a key larger than 128 bytes (= block-size of SHA-384 and + SHA-512). + */ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaa", /* (131 bytes) */ + "54657374205573696e67204c61726765" /* ("Test Using Large") */ + "72205468616e20426c6f636b2d53697a" /* ("r Than Block-Siz") */ + "65204b6579202d2048617368204b6579" /* ("e Key - Hash Key") */ + "204669727374", /* (" First") */ + "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54" + }, + { + /* Test Case 7 + + Test with a key and data that is larger than 128 bytes (= block-size + of SHA-384 and SHA-512). */ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaa", /* (131 bytes) */ + "54686973206973206120746573742075" /* ("This is a test u") */ + "73696e672061206c6172676572207468" /* ("sing a larger th") */ + "616e20626c6f636b2d73697a65206b65" /* ("an block-size ke") */ + "7920616e642061206c61726765722074" /* ("y and a larger t") */ + "68616e20626c6f636b2d73697a652064" /* ("han block-size d") */ + "6174612e20546865206b6579206e6565" /* ("ata. The key nee") */ + "647320746f2062652068617368656420" /* ("ds to be hashed ") */ + "6265666f7265206265696e6720757365" /* ("before being use") */ + "642062792074686520484d414320616c" /* ("d by the HMAC al") */ + "676f726974686d2e", /* ("gorithm.") */ + "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2" + } +}; + +static void *fromhex(const char *str, size_t *len) +{ + void *p; + + *len = hex_data_size(strlen(str)); + p = malloc(*len); + if (!hex_decode(str, strlen(str), p, *len)) + abort(); + return p; +} + +int main(void) +{ + size_t i; + struct hmac_sha256 hmac; + + plan_tests(sizeof(tests) / sizeof(tests[0]) * 2); + + for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { + size_t ksize, dsize, hmacsize; + void *k, *d, *expect; + struct hmac_sha256_ctx ctx; + + k = fromhex(tests[i].key, &ksize); + d = fromhex(tests[i].data, &dsize); + expect = fromhex(tests[i].hmac, &hmacsize); + assert(hmacsize == sizeof(hmac)); + hmac_sha256(&hmac, k, ksize, d, dsize); + ok1(memcmp(&hmac, expect, hmacsize) == 0); + + /* Now test partial API. */ + hmac_sha256_init(&ctx, k, ksize); + hmac_sha256_update(&ctx, d, dsize / 2); + hmac_sha256_update(&ctx, (char *)d + dsize/2, dsize - dsize/2); + hmac_sha256_done(&ctx, &hmac); + ok1(memcmp(&hmac, expect, hmacsize) == 0); + + free(k); + free(d); + free(expect); + } + + return exit_status(); +} diff --git a/ccan/ccan/crypto/shachain/shachain.c b/ccan/ccan/crypto/shachain/shachain.c index c6bd37e8f..2c9cb3d54 100644 --- a/ccan/ccan/crypto/shachain/shachain.c +++ b/ccan/ccan/crypto/shachain/shachain.c @@ -5,8 +5,6 @@ #include #include -#define INDEX_BITS ((sizeof(shachain_index_t)) * CHAR_BIT) - static void change_bit(unsigned char *arr, size_t index) { arr[index / CHAR_BIT] ^= (1 << (index % CHAR_BIT)); @@ -15,11 +13,11 @@ static void change_bit(unsigned char *arr, size_t index) static unsigned int count_trailing_zeroes(shachain_index_t index) { #if HAVE_BUILTIN_CTZLL - return index ? (unsigned int)__builtin_ctzll(index) : INDEX_BITS; + return index ? (unsigned int)__builtin_ctzll(index) : SHACHAIN_BITS; #else unsigned int i; - for (i = 0; i < INDEX_BITS; i++) { + for (i = 0; i < SHACHAIN_BITS; i++) { if (index & (1ULL << i)) break; } @@ -81,7 +79,8 @@ bool shachain_add_hash(struct shachain *chain, /* You have to insert them in order! */ assert(index == chain->min_index - 1 || - (index == (shachain_index_t)(-1ULL) && chain->num_valid == 0)); + (index == (shachain_index_t)(UINT64_MAX >> (64 - SHACHAIN_BITS)) + && chain->num_valid == 0)); pos = count_trailing_zeroes(index); diff --git a/ccan/ccan/crypto/shachain/shachain.h b/ccan/ccan/crypto/shachain/shachain.h index ba4ba11cd..90f2380ed 100644 --- a/ccan/ccan/crypto/shachain/shachain.h +++ b/ccan/ccan/crypto/shachain/shachain.h @@ -11,6 +11,10 @@ #define shachain_index_t uint64_t #endif +#ifndef SHACHAIN_BITS +#define SHACHAIN_BITS (sizeof(shachain_index_t) * 8) +#endif + /** * shachain_from_seed - Generate an unpredictable SHA from a seed value. * @seed: (secret) seed value to use @@ -56,7 +60,7 @@ struct shachain { struct { shachain_index_t index; struct sha256 hash; - } known[sizeof(shachain_index_t) * 8 + 1]; + } known[SHACHAIN_BITS + 1]; }; /** diff --git a/ccan/ccan/crypto/shachain/tools/Makefile b/ccan/ccan/crypto/shachain/tools/Makefile new file mode 100644 index 000000000..a1b0177c7 --- /dev/null +++ b/ccan/ccan/crypto/shachain/tools/Makefile @@ -0,0 +1,39 @@ +#! /usr/bin/make + +CCANDIR=../../../.. +CFLAGS=-Wall -Werror -O3 -I$(CCANDIR) -DSHACHAIN_BITS=48 +#CFLAGS=-Wall -Werror -g3 -I$(CCANDIR) -DSHACHAIN_BITS=48 + +# 48 bit index for shachain. This is what lightning uses. +CCAN_OBJS:=ccan-str.o ccan-err.o ccan-hex.o ccan-shachain.o ccan-sha256.o ccan-rbuf.o + +all: shachain48 + +shachain48: shachain48.o $(CCAN_OBJS) + +shachain48.o: $(CCANDIR)/ccan/crypto/shachain/shachain.h \ + $(CCANDIR)/ccan/str/hex/hex.h \ + $(CCANDIR)/ccan/str/str.h \ + $(CCANDIR)/ccan/err/err.h \ + $(CCANDIR)/ccan/rbuf/rbuf.h + +shachain48.o $(CCAN_OBJS): $(CCANDIR)/config.h + +$(CCANDIR)/config.h: + $(MAKE) -C $(CCANDIR) config.h + +clean: + rm -f shachain *.o + +ccan-err.o: $(CCANDIR)/ccan/err/err.c + $(CC) $(CFLAGS) -c -o $@ $< +ccan-hex.o: $(CCANDIR)/ccan/str/hex/hex.c + $(CC) $(CFLAGS) -c -o $@ $< +ccan-str.o: $(CCANDIR)/ccan/str/str.c + $(CC) $(CFLAGS) -c -o $@ $< +ccan-shachain.o: $(CCANDIR)/ccan/crypto/shachain/shachain.c + $(CC) $(CFLAGS) -c -o $@ $< +ccan-sha256.o: $(CCANDIR)/ccan/crypto/sha256/sha256.c + $(CC) $(CFLAGS) -c -o $@ $< +ccan-rbuf.o: $(CCANDIR)/ccan/rbuf/rbuf.c + $(CC) $(CFLAGS) -c -o $@ $< diff --git a/ccan/ccan/crypto/shachain/tools/shachain48.c b/ccan/ccan/crypto/shachain/tools/shachain48.c new file mode 100644 index 000000000..5cc910909 --- /dev/null +++ b/ccan/ccan/crypto/shachain/tools/shachain48.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + if (argc == 2 && streq(argv[1], "--store")) { + struct shachain s; + struct rbuf rbuf; + size_t size = rbuf_good_size(STDIN_FILENO); + char *p; + + shachain_init(&s); + rbuf_init(&rbuf, STDIN_FILENO, malloc(size), size); + + while ((p = rbuf_read_str(&rbuf, '\n', realloc)) != NULL) { + struct sha256 hash; + unsigned long long idx; + + if (strstarts(p, "0x")) + p += 2; + if (!hex_decode(p, 64, &hash, sizeof(hash))) + errx(2, "%.*s is not 64 chars of hex", 64, p); + p += 64; + p += strspn(p, " \t"); + idx = strtoull(p, NULL, 0); + if (shachain_add_hash(&s, idx, &hash)) + printf("OK\n"); + else + printf("ERROR\n"); + } + } else if (argc == 3) { + struct sha256 seed, hash; + const char *p; + unsigned long long idx; + char hex[65]; + + if (strstarts(argv[1], "0x")) + p = argv[1] + 2; + else + p = argv[1]; + idx = strtoull(argv[2], NULL, 0); + + if (!hex_decode(p, 64, &seed, sizeof(seed))) + errx(2, "%s is not 64 chars of hex", p); + + shachain_from_seed(&seed, idx, &hash); + hex_encode(&hash, sizeof(hash), hex, sizeof(hex)); + printf("0x%s\n", hex); + } else + errx(1, "Usage: shachain --store OR shachain "); + return 0; +} diff --git a/ccan/ccan/fdpass/LICENSE b/ccan/ccan/fdpass/LICENSE new file mode 120000 index 000000000..b7951dabd --- /dev/null +++ b/ccan/ccan/fdpass/LICENSE @@ -0,0 +1 @@ +../../licenses/CC0 \ No newline at end of file diff --git a/ccan/ccan/fdpass/_info b/ccan/ccan/fdpass/_info new file mode 100644 index 000000000..dfc873288 --- /dev/null +++ b/ccan/ccan/fdpass/_info @@ -0,0 +1,65 @@ +#include "config.h" +#include +#include + +/** + * fdpass - routines to pass a file descriptor over a socket. + * + * This code handles all the hairy details of fd passing. + * + * License: CC0 (Public domain) + * Maintainer: Rusty Russell + * + * Example: + * // Outputs hello! + * #include + * #include + * #include + * #include + * #include + * #include + * + * static void child(int sockfd) + * { + * char buffer[6]; + * int newfd = fdpass_recv(sockfd); + * read(newfd, buffer, sizeof(buffer)); + * printf("%.*s\n", (int)sizeof(buffer), buffer); + * exit(0); + * } + * + * static void parent(int sockfd) + * { + * int pfds[2]; + * + * pipe(pfds); + * fdpass_send(sockfd, pfds[0]); + * close(pfds[0]); + * write(pfds[1], "hello!", 6); + * exit(0); + * } + * + * int main(void) + * { + * int sv[2]; + * + * socketpair(AF_UNIX, SOCK_STREAM, 0, sv); + * if (fork() == 0) + * child(sv[0]); + * else + * parent(sv[1]); + * } + */ +int main(int argc, char *argv[]) +{ + /* Expect exactly one argument */ + if (argc != 2) + return 1; + + if (strcmp(argv[1], "depends") == 0) + return 0; + + return 1; +} + + diff --git a/ccan/ccan/fdpass/fdpass.c b/ccan/ccan/fdpass/fdpass.c new file mode 100644 index 000000000..7331468f9 --- /dev/null +++ b/ccan/ccan/fdpass/fdpass.c @@ -0,0 +1,83 @@ +/* CC0 license (public domain) - see LICENSE file for details */ +#include +#include +#include +#include + +bool fdpass_send(int sockout, int fd) +{ + /* From the cmsg(3) manpage: */ + struct msghdr msg = { 0 }; + struct cmsghdr *cmsg; + struct iovec iov; + char c = 0; + union { /* Ancillary data buffer, wrapped in a union + in order to ensure it is suitably aligned */ + char buf[CMSG_SPACE(sizeof(fd))]; + struct cmsghdr align; + } u; + + msg.msg_control = u.buf; + msg.msg_controllen = sizeof(u.buf); + memset(&u, 0, sizeof(u)); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + + /* Keith Packard reports that 0-length sends don't work, so we + * always send 1 byte. */ + iov.iov_base = &c; + iov.iov_len = 1; + + return sendmsg(sockout, &msg, 0) == 1; +} + +int fdpass_recv(int sockin) +{ + /* From the cmsg(3) manpage: */ + struct msghdr msg = { 0 }; + struct cmsghdr *cmsg; + struct iovec iov; + int fd; + char c; + union { /* Ancillary data buffer, wrapped in a union + in order to ensure it is suitably aligned */ + char buf[CMSG_SPACE(sizeof(fd))]; + struct cmsghdr align; + } u; + + msg.msg_control = u.buf; + msg.msg_controllen = sizeof(u.buf); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + + iov.iov_base = &c; + iov.iov_len = 1; + + if (recvmsg(sockin, &msg, 0) < 0) + return -1; + + cmsg = CMSG_FIRSTHDR(&msg); + if (!cmsg + || cmsg->cmsg_len != CMSG_LEN(sizeof(fd)) + || cmsg->cmsg_level != SOL_SOCKET + || cmsg->cmsg_type != SCM_RIGHTS) { + errno = -EINVAL; + return -1; + } + + memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd)); + return fd; +} diff --git a/ccan/ccan/fdpass/fdpass.h b/ccan/ccan/fdpass/fdpass.h new file mode 100644 index 000000000..127b66e5b --- /dev/null +++ b/ccan/ccan/fdpass/fdpass.h @@ -0,0 +1,23 @@ +/* CC0 license (public domain) - see LICENSE file for details */ +#ifndef CCAN_FDPASS_H +#define CCAN_FDPASS_H + +#include + +/** + * fdpass_send - send a file descriptor across a socket + * @sockout: socket to write to + * @fd: file descriptor to pass + * + * On failure, sets errno and returns false. + */ +bool fdpass_send(int sockout, int fd); + +/** + * fdpass_recv - receive a file descriptor from a socket + * @sockin: socket to read from + * + * On failure, returns -1 and sets errno. Otherwise returns fd. + */ +int fdpass_recv(int sockin); +#endif /* CCAN_FDPASS_H */ diff --git a/ccan/ccan/fdpass/test/run.c b/ccan/ccan/fdpass/test/run.c new file mode 100644 index 000000000..09d280e88 --- /dev/null +++ b/ccan/ccan/fdpass/test/run.c @@ -0,0 +1,88 @@ +#include +/* Include the C files directly. */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static void child(int sockfd) +{ + char c; + int newfd = fdpass_recv(sockfd); + assert(newfd >= 0); + assert(read(newfd, &c, 1) == 1); + assert(c == 0x77); + exit(0); +} + +static void child_nofd(int sockfd) +{ + assert(fdpass_recv(sockfd) == -1); + exit(0); +} + +static void parent(int sockfd) +{ + int pfds[2]; + + ok1(pipe(pfds) == 0); + ok1(fdpass_send(sockfd, pfds[0])); + ok1(close(pfds[0]) == 0); + ok1(write(pfds[1], "\x77", 1) == 1); + ok1(close(pfds[1]) == 0); +} + +int main(void) +{ + int sv[2]; + int pid, wstatus; + + plan_tests(17); + ok1(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); + + pid = fork(); + if (pid == 0) { + close(sv[1]); + child(sv[0]); + } + + parent(sv[1]); + ok1(waitpid(pid, &wstatus, 0) == pid); + ok1(WIFEXITED(wstatus)); + ok1(WEXITSTATUS(wstatus) == 0); + + pid = fork(); + if (pid == 0) { + close(sv[1]); + child_nofd(sv[0]); + } + /* Don't write an fd. */ + ok1(write(sv[1], "1", 1) == 1); + ok1(waitpid(pid, &wstatus, 0) == pid); + ok1(WIFEXITED(wstatus)); + ok1(WEXITSTATUS(wstatus) == 0); + + pid = fork(); + if (pid == 0) { + close(sv[1]); + child_nofd(sv[0]); + } + /* Don't write anything. */ + close(sv[1]); + ok1(waitpid(pid, &wstatus, 0) == pid); + ok1(WIFEXITED(wstatus)); + ok1(WEXITSTATUS(wstatus) == 0); + + close(sv[0]); + /* Test fdpass_recv from invalid fd. */ + ok1(fdpass_recv(sv[0]) == -1 && errno == EBADF); + + /* This exits depending on whether all tests passed */ + return exit_status(); +} diff --git a/ccan/ccan/io/backend.h b/ccan/ccan/io/backend.h index 3a1f12e7e..f57d24950 100644 --- a/ccan/ccan/io/backend.h +++ b/ccan/ccan/io/backend.h @@ -31,9 +31,7 @@ enum io_plan_status { /* Waiting for io_wake */ IO_WAITING, /* Always do this. */ - IO_ALWAYS, - /* Closing (both plans will be the same). */ - IO_CLOSING + IO_ALWAYS }; /** @@ -59,12 +57,9 @@ struct io_plan { /* One connection per client. */ struct io_conn { struct fd fd; - bool debug; - /* For duplex to save. */ - bool debug_saved; - /* always and closing lists. */ - struct list_node always, closing; + /* always list. */ + struct list_node always; void (*finish)(struct io_conn *, void *arg); void *finish_arg; @@ -78,7 +73,6 @@ bool add_listener(struct io_listener *l); bool add_conn(struct io_conn *c); bool add_duplex(struct io_conn *c); void del_listener(struct io_listener *l); -void backend_new_closing(struct io_conn *conn); void backend_new_always(struct io_conn *conn); void backend_new_plan(struct io_conn *conn); void remove_from_always(struct io_conn *conn); diff --git a/ccan/ccan/io/fdpass/LICENSE b/ccan/ccan/io/fdpass/LICENSE new file mode 120000 index 000000000..4d0b239e7 --- /dev/null +++ b/ccan/ccan/io/fdpass/LICENSE @@ -0,0 +1 @@ +../../../licenses/LGPL-2.1 \ No newline at end of file diff --git a/ccan/ccan/io/fdpass/_info b/ccan/ccan/io/fdpass/_info new file mode 100644 index 000000000..406b2f5c2 --- /dev/null +++ b/ccan/ccan/io/fdpass/_info @@ -0,0 +1,95 @@ +#include "config.h" +#include +#include + +/** + * io/fdpass - IO helper for passing file descriptors across local sockets + * + * This code adds the ability to pass file descriptors to ccan/io. + * + * License: LGPL (v2.1 or any later version) + * Author: Rusty Russell + * + * Example: + * // Given "hello" outputs hello + * #include + * #include + * #include + * #include + * #include + * #include + * #include + * + * // Child reads stdin into the buffer, prints it out. + * struct buf { + * size_t used; + * char c[100]; + * }; + * static struct io_plan *read_more(struct io_conn *conn, struct buf *buf) + * { + * printf("%.*s", (int)buf->used, buf->c); + * return io_read_partial(conn, buf->c, sizeof(buf->c), &buf->used, + * read_more, buf); + * } + * + * // Child has received fd, start reading loop. + * static struct io_plan *got_infd(struct io_conn *conn, int *infd) + * { + * struct buf *buf = calloc(1, sizeof(*buf)); + * + * io_new_conn(NULL, *infd, read_more, buf); + * return io_close(conn); + * } + * // Child is receiving the fd to read into. + * static struct io_plan *recv_infd(struct io_conn *conn, int *infd) + * { + * return io_recv_fd(conn, infd, got_infd, infd); + * } + * + * // Gets passed fd (stdin), which it reads from. + * static void child(int sockfd) + * { + * int infd; + * + * io_new_conn(NULL, sockfd, recv_infd, &infd); + * io_loop(NULL, NULL); + * exit(0); + * } + * + * static struct io_plan *send_stdin(struct io_conn *conn, void *unused) + * { + * return io_send_fd(conn, STDIN_FILENO, io_close_cb, NULL); + * } + * + * static void parent(int sockfd) + * { + * io_new_conn(NULL, sockfd, send_stdin, NULL); + * io_loop(NULL, NULL); + * exit(0); + * } + * + * int main(void) + * { + * int sv[2]; + * + * socketpair(AF_UNIX, SOCK_STREAM, 0, sv); + * if (fork() == 0) + * child(sv[0]); + * else + * parent(sv[1]); + * } + */ +int main(int argc, char *argv[]) +{ + /* Expect exactly one argument */ + if (argc != 2) + return 1; + + if (strcmp(argv[1], "depends") == 0) { + printf("ccan/fdpass\n"); + printf("ccan/io\n"); + return 0; + } + + return 1; +} diff --git a/ccan/ccan/io/fdpass/fdpass.c b/ccan/ccan/io/fdpass/fdpass.c new file mode 100644 index 000000000..11208a9b6 --- /dev/null +++ b/ccan/ccan/io/fdpass/fdpass.c @@ -0,0 +1,54 @@ +/* GNU LGPL version 2 (or later) - see LICENSE file for details */ +#include +#include +#include +#include + +static int do_fd_send(int fd, struct io_plan_arg *arg) +{ + if (!fdpass_send(fd, arg->u1.s)) { + /* In case ccan/io ever gets smart with non-blocking. */ + if (errno == EAGAIN || errno == EWOULDBLOCK) + return 0; + return -1; + } + return 1; +} + +struct io_plan *io_send_fd_(struct io_conn *conn, + int fd, + struct io_plan *(*next)(struct io_conn *, void *), + void *next_arg) +{ + struct io_plan_arg *arg = io_plan_arg(conn, IO_OUT); + + arg->u1.s = fd; + + return io_set_plan(conn, IO_OUT, do_fd_send, next, next_arg); +} + +static int do_fd_recv(int fd, struct io_plan_arg *arg) +{ + int fdin = fdpass_recv(fd); + + if (fdin < 0) { + /* In case ccan/io ever gets smart with non-blocking. */ + if (errno == EAGAIN || errno == EWOULDBLOCK) + return 0; + return -1; + } + *(int *)arg->u1.vp = fdin; + return 1; +} + +struct io_plan *io_recv_fd_(struct io_conn *conn, + int *fd, + struct io_plan *(*next)(struct io_conn *, void *), + void *next_arg) +{ + struct io_plan_arg *arg = io_plan_arg(conn, IO_IN); + + arg->u1.vp = fd; + + return io_set_plan(conn, IO_IN, do_fd_recv, next, next_arg); +} diff --git a/ccan/ccan/io/fdpass/fdpass.h b/ccan/ccan/io/fdpass/fdpass.h new file mode 100644 index 000000000..366ff3521 --- /dev/null +++ b/ccan/ccan/io/fdpass/fdpass.h @@ -0,0 +1,68 @@ +/* GNU LGPL version 2 (or later) - see LICENSE file for details */ +#ifndef CCAN_IO_FDPASS_H +#define CCAN_IO_FDPASS_H +#include + +/** + * io_send_fd - output plan to send a file descriptor + * @conn: the connection that plan is for. + * @fd: the file descriptor to pass. + * @next: function to call output is done. + * @arg: @next argument + * + * This updates the output plan, to write out a file descriptor. This + * usually only works over an AF_LOCAL (ie. Unix domain) socket. Once + * that's sent, the @next function will be called: on an error, the + * finish function is called instead. + * + * Note that the I/O may actually be done immediately, and the other end + * of the socket must use io_recv_fd: if it does a normal read, the file + * descriptor will be lost. + * + * Example: + * static struct io_plan *fd_to_conn(struct io_conn *conn, int fd) + * { + * // Write fd, then close. + * return io_send_fd(conn, fd, io_close_cb, NULL); + * } + */ +#define io_send_fd(conn, fd, next, arg) \ + io_send_fd_((conn), (fd), \ + typesafe_cb_preargs(struct io_plan *, void *, \ + (next), (arg), struct io_conn *), \ + (arg)) +struct io_plan *io_send_fd_(struct io_conn *conn, + int fd, + struct io_plan *(*next)(struct io_conn *, void *), + void *arg); + +/** + * io_recv_fd - input plan to receive a file descriptor + * @conn: the connection that plan is for. + * @fd: a pointer to where to place to file descriptor + * @next: function to call once input is done. + * @arg: @next argument + * + * This creates a plan to receive a file descriptor, as sent by + * io_send_fd. Once it's all read, the @next function will be called: + * on an error, the finish function is called instead. + * + * Note that the I/O may actually be done immediately. + * + * Example: + * static struct io_plan *read_from_conn(struct io_conn *conn, int *fdp) + * { + * // Read message, then close. + * return io_recv_fd(conn, fdp, io_close_cb, NULL); + * } + */ +#define io_recv_fd(conn, fd, next, arg) \ + io_recv_fd_((conn), (fd), \ + typesafe_cb_preargs(struct io_plan *, void *, \ + (next), (arg), struct io_conn *), \ + (arg)) +struct io_plan *io_recv_fd_(struct io_conn *conn, + int *fd, + struct io_plan *(*next)(struct io_conn *, void *), + void *arg); +#endif /* CCAN_IO_FDPASS_H */ diff --git a/ccan/ccan/io/fdpass/test/run.c b/ccan/ccan/io/fdpass/test/run.c new file mode 100644 index 000000000..d2021e827 --- /dev/null +++ b/ccan/ccan/io/fdpass/test/run.c @@ -0,0 +1,51 @@ +#include +/* Include the C files directly. */ +#include +#include +#include +#include + +static struct io_plan *try_reading(struct io_conn *conn, int *fd) +{ + char buf[6]; + ok1(read(*fd, buf, sizeof(buf)) == sizeof(buf)); + ok1(memcmp(buf, "hello!", sizeof(buf)) == 0); + return io_close(conn); +} + +static struct io_plan *get_fd(struct io_conn *conn, void *unused) +{ + int *fd = tal(conn, int); + return io_recv_fd(conn, fd, try_reading, fd); +} + +static struct io_plan *try_writing(struct io_conn *conn, int *pfd) +{ + close(pfd[0]); + ok1(write(pfd[1], "hello!", 6) == 6); + return io_close(conn); +} + +static struct io_plan *send_fd(struct io_conn *conn, int *pfd) +{ + return io_send_fd(conn, pfd[0], try_writing, pfd); +} + +int main(void) +{ + int sv[2]; + int pfd[2]; + + plan_tests(5); + ok1(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0); + ok1(pipe(pfd) == 0); + + /* Pass read end of pipe to ourselves, test. */ + io_new_conn(NULL, sv[0], get_fd, NULL); + io_new_conn(NULL, sv[1], send_fd, pfd); + + io_loop(NULL, NULL); + + /* This exits depending on whether all tests passed */ + return exit_status(); +} diff --git a/ccan/ccan/io/io.c b/ccan/ccan/io/io.c index cd5557d16..4c41c93a6 100644 --- a/ccan/ccan/io/io.c +++ b/ccan/ccan/io/io.c @@ -14,6 +14,8 @@ void *io_loop_return; +struct io_plan io_conn_freed; + struct io_listener *io_new_listener_(const tal_t *ctx, int fd, struct io_plan *(*init)(struct io_conn *, void *), @@ -35,8 +37,6 @@ struct io_listener *io_new_listener_(const tal_t *ctx, int fd, void io_close_listener(struct io_listener *l) { - close(l->fd.fd); - del_listener(l); tal_free(l); } @@ -45,7 +45,8 @@ static struct io_plan *io_never_called(struct io_conn *conn, void *arg) abort(); } -static void next_plan(struct io_conn *conn, struct io_plan *plan) +/* Returns false if conn was freed. */ +static bool next_plan(struct io_conn *conn, struct io_plan *plan) { struct io_plan *(*next)(struct io_conn *, void *arg); @@ -57,6 +58,9 @@ static void next_plan(struct io_conn *conn, struct io_plan *plan) plan = next(conn, plan->next_arg); + if (plan == &io_conn_freed) + return false; + /* It should have set a plan inside this conn (or duplex) */ assert(plan == &conn->plan[IO_IN] || plan == &conn->plan[IO_OUT] @@ -65,6 +69,7 @@ static void next_plan(struct io_conn *conn, struct io_plan *plan) || conn->plan[IO_OUT].status != IO_UNSET); backend_new_plan(conn); + return true; } static void set_blocking(int fd, bool block) @@ -93,8 +98,6 @@ struct io_conn *io_new_conn_(const tal_t *ctx, int fd, conn->finish = NULL; conn->finish_arg = NULL; list_node_init(&conn->always); - list_node_init(&conn->closing); - conn->debug = false; if (!add_conn(conn)) return tal_free(conn); @@ -107,7 +110,8 @@ struct io_conn *io_new_conn_(const tal_t *ctx, int fd, conn->plan[IO_IN].next = init; conn->plan[IO_IN].next_arg = arg; - next_plan(conn, &conn->plan[IO_IN]); + if (!next_plan(conn, &conn->plan[IO_IN])) + return NULL; return conn; } @@ -356,24 +360,20 @@ void io_wake(const void *wait) backend_wake(wait); } -static int do_plan(struct io_conn *conn, struct io_plan *plan) +/* Returns false if this has been freed. */ +static bool do_plan(struct io_conn *conn, struct io_plan *plan) { - /* Someone else might have called io_close() on us. */ - if (plan->status == IO_CLOSING) - return -1; - /* We shouldn't have polled for this event if this wasn't true! */ assert(plan->status == IO_POLLING); switch (plan->io(conn->fd.fd, &plan->arg)) { case -1: io_close(conn); - return -1; + return false; case 0: - return 0; + return true; case 1: - next_plan(conn, plan); - return 1; + return next_plan(conn, plan); default: /* IO should only return -1, 0 or 1 */ abort(); @@ -383,7 +383,8 @@ static int do_plan(struct io_conn *conn, struct io_plan *plan) void io_ready(struct io_conn *conn, int pollflags) { if (pollflags & POLLIN) - do_plan(conn, &conn->plan[IO_IN]); + if (!do_plan(conn, &conn->plan[IO_IN])) + return; if (pollflags & POLLOUT) do_plan(conn, &conn->plan[IO_OUT]); @@ -392,7 +393,8 @@ void io_ready(struct io_conn *conn, int pollflags) void io_do_always(struct io_conn *conn) { if (conn->plan[IO_IN].status == IO_ALWAYS) - next_plan(conn, &conn->plan[IO_IN]); + if (!next_plan(conn, &conn->plan[IO_IN])) + return; if (conn->plan[IO_OUT].status == IO_ALWAYS) next_plan(conn, &conn->plan[IO_OUT]); @@ -410,15 +412,8 @@ void io_do_wakeup(struct io_conn *conn, enum io_direction dir) /* Close the connection, we're done. */ struct io_plan *io_close(struct io_conn *conn) { - /* Already closing? Don't close twice. */ - if (conn->plan[IO_IN].status == IO_CLOSING) - return &conn->plan[IO_IN]; - - conn->plan[IO_IN].status = conn->plan[IO_OUT].status = IO_CLOSING; - conn->plan[IO_IN].arg.u1.s = errno; - backend_new_closing(conn); - - return io_set_plan(conn, IO_IN, NULL, NULL, NULL); + tal_free(conn); + return &io_conn_freed; } struct io_plan *io_close_cb(struct io_conn *conn, void *next_arg) @@ -443,43 +438,17 @@ int io_conn_fd(const struct io_conn *conn) return conn->fd.fd; } -void io_duplex_prepare(struct io_conn *conn) -{ - assert(conn->plan[IO_IN].status == IO_UNSET); - assert(conn->plan[IO_OUT].status == IO_UNSET); - - /* We can't sync debug until we've set both: io_wait() and io_always - * can't handle it. */ - conn->debug_saved = conn->debug; - io_set_debug(conn, false); -} - -struct io_plan *io_duplex_(struct io_plan *in_plan, struct io_plan *out_plan) +struct io_plan *io_duplex(struct io_conn *conn, + struct io_plan *in_plan, struct io_plan *out_plan) { - struct io_conn *conn; - + assert(conn == container_of(in_plan, struct io_conn, plan[IO_IN])); /* in_plan must be conn->plan[IO_IN], out_plan must be [IO_OUT] */ assert(out_plan == in_plan + 1); - - /* Restore debug. */ - conn = container_of(in_plan, struct io_conn, plan[IO_IN]); - io_set_debug(conn, conn->debug_saved); - - /* Now set the plans again, to invoke sync debug. */ - io_set_plan(conn, IO_OUT, - out_plan->io, out_plan->next, out_plan->next_arg); - io_set_plan(conn, IO_IN, - in_plan->io, in_plan->next, in_plan->next_arg); - return out_plan + 1; } struct io_plan *io_halfclose(struct io_conn *conn) { - /* Already closing? Don't close twice. */ - if (conn->plan[IO_IN].status == IO_CLOSING) - return &conn->plan[IO_IN]; - /* Both unset? OK. */ if (conn->plan[IO_IN].status == IO_UNSET && conn->plan[IO_OUT].status == IO_UNSET) @@ -502,45 +471,7 @@ struct io_plan *io_set_plan(struct io_conn *conn, enum io_direction dir, plan->io = io; plan->next = next; plan->next_arg = next_arg; - assert(plan->status == IO_CLOSING || next != NULL); - - if (!conn->debug) - return plan; - - if (io_loop_return) { - io_debug_complete(conn); - return plan; - } - - switch (plan->status) { - case IO_POLLING: - while (do_plan(conn, plan) == 0); - break; - /* Shouldn't happen, since you said you did plan! */ - case IO_UNSET: - abort(); - case IO_ALWAYS: - /* If other one is ALWAYS, leave in list! */ - if (conn->plan[!dir].status != IO_ALWAYS) - remove_from_always(conn); - next_plan(conn, plan); - break; - case IO_WAITING: - case IO_CLOSING: - io_debug_complete(conn); - } + assert(next != NULL); return plan; } - -void io_set_debug(struct io_conn *conn, bool debug) -{ - conn->debug = debug; - - /* Debugging means fds must block. */ - set_blocking(io_conn_fd(conn), debug); -} - -void io_debug_complete(struct io_conn *conn) -{ -} diff --git a/ccan/ccan/io/io.h b/ccan/ccan/io/io.h index e24beec46..fe040bce2 100644 --- a/ccan/ccan/io/io.h +++ b/ccan/ccan/io/io.h @@ -454,11 +454,8 @@ struct io_plan *io_connect_(struct io_conn *conn, const struct addrinfo *addr, * io_write(conn, b->out, sizeof(b->out), io_close_cb,b)); * } */ -#define io_duplex(conn, in_plan, out_plan) \ - (io_duplex_prepare(conn), io_duplex_(in_plan, out_plan)) - -struct io_plan *io_duplex_(struct io_plan *in_plan, struct io_plan *out_plan); -void io_duplex_prepare(struct io_conn *conn); +struct io_plan *io_duplex(struct io_conn *conn, + struct io_plan *in_plan, struct io_plan *out_plan); /** * io_halfclose - close half of an io_duplex connection. @@ -660,37 +657,4 @@ int io_conn_fd(const struct io_conn *conn); */ struct timemono (*io_time_override(struct timemono (*now)(void)))(void); -/** - * io_set_debug - set synchronous mode on a connection. - * @conn: the connection. - * @debug: whether to enable or disable debug. - * - * Once @debug is true on a connection, all I/O is done synchronously - * as soon as it is set, until it is unset or @conn is closed. This - * makes it easy to debug what's happening with a connection, but note - * that other connections are starved while this is being done. - * - * See also: io_debug_complete() - * - * Example: - * // Dumb init function to set debug and tell conn to close. - * static struct io_plan *conn_init(struct io_conn *conn, const char *msg) - * { - * io_set_debug(conn, true); - * return io_close(conn); - * } - */ -void io_set_debug(struct io_conn *conn, bool debug); - -/** - * io_debug_complete - empty function called when conn is closing/waiting. - * @conn: the connection. - * - * This is for putting a breakpoint onto, when debugging. It is called - * when a conn with io_set_debug() true can no longer be synchronous: - * 1) It is io_close()'d - * 2) It enters io_wait() (sychronous debug will resume after io_wake()) - * 3) io_break() is called (sychronous debug will resume after io_loop()) - */ -void io_debug_complete(struct io_conn *conn); #endif /* CCAN_IO_H */ diff --git a/ccan/ccan/io/poll.c b/ccan/ccan/io/poll.c index 36af33ef0..6738f720e 100644 --- a/ccan/ccan/io/poll.c +++ b/ccan/ccan/io/poll.c @@ -95,10 +95,17 @@ static void del_fd(struct fd *fd) close(fd->fd); } +static void destroy_listener(struct io_listener *l) +{ + close(l->fd.fd); + del_fd(&l->fd); +} + bool add_listener(struct io_listener *l) { if (!add_fd(&l->fd, POLLIN)) return false; + tal_add_destructor(l, destroy_listener); return true; } @@ -107,13 +114,6 @@ void remove_from_always(struct io_conn *conn) list_del_init(&conn->always); } -void backend_new_closing(struct io_conn *conn) -{ - /* In case it's on always list, remove it. */ - list_del_init(&conn->always); - list_add_tail(&closing, &conn->closing); -} - void backend_new_always(struct io_conn *conn) { /* In case it's already in always list. */ @@ -164,25 +164,28 @@ void backend_wake(const void *wait) } } -bool add_conn(struct io_conn *c) +static void destroy_conn(struct io_conn *conn) { - return add_fd(&c->fd, 0); -} + int saved_errno = errno; -static void del_conn(struct io_conn *conn) -{ + close(conn->fd.fd); del_fd(&conn->fd); + /* In case it's on always list, remove it. */ + list_del_init(&conn->always); + + /* errno saved/restored by tal_free itself. */ if (conn->finish) { - /* Saved by io_close */ - errno = conn->plan[IO_IN].arg.u1.s; + errno = saved_errno; conn->finish(conn, conn->finish_arg); } - tal_free(conn); } -void del_listener(struct io_listener *l) +bool add_conn(struct io_conn *c) { - del_fd(&l->fd); + if (!add_fd(&c->fd, 0)) + return false; + tal_add_destructor(c, destroy_conn); + return true; } static void accept_conn(struct io_listener *l) @@ -196,22 +199,6 @@ static void accept_conn(struct io_listener *l) io_new_conn(l->ctx, fd, l->init, l->arg); } -/* It's OK to miss some, as long as we make progress. */ -static bool close_conns(void) -{ - bool ret = false; - struct io_conn *conn; - - while ((conn = list_pop(&closing, struct io_conn, closing)) != NULL) { - assert(conn->plan[IO_IN].status == IO_CLOSING); - assert(conn->plan[IO_OUT].status == IO_CLOSING); - - del_conn(conn); - ret = true; - } - return ret; -} - static bool handle_always(void) { bool ret = false; @@ -244,11 +231,6 @@ void *io_loop(struct timers *timers, struct timer **expired) while (!io_loop_return) { int i, r, ms_timeout = -1; - if (close_conns()) { - /* Could have started/finished more. */ - continue; - } - if (handle_always()) { /* Could have started/finished more. */ continue; @@ -309,8 +291,6 @@ void *io_loop(struct timers *timers, struct timer **expired) } } - close_conns(); - ret = io_loop_return; io_loop_return = NULL; diff --git a/ccan/ccan/io/test/run-01-start-finish-debug.c b/ccan/ccan/io/test/run-01-start-finish-debug.c deleted file mode 100644 index bc43299fa..000000000 --- a/ccan/ccan/io/test/run-01-start-finish-debug.c +++ /dev/null @@ -1,2 +0,0 @@ -#define DEBUG_CONN -#include "run-01-start-finish.c" diff --git a/ccan/ccan/io/test/run-01-start-finish.c b/ccan/ccan/io/test/run-01-start-finish.c index 04952db88..5356244e8 100644 --- a/ccan/ccan/io/test/run-01-start-finish.c +++ b/ccan/ccan/io/test/run-01-start-finish.c @@ -6,11 +6,7 @@ #include #include -#ifdef DEBUG_CONN -#define PORT "64001" -#else #define PORT "65001" -#endif static int expected_fd; static void finish_ok(struct io_conn *conn, int *state) @@ -23,9 +19,6 @@ static void finish_ok(struct io_conn *conn, int *state) static struct io_plan *init_conn(struct io_conn *conn, int *state) { -#ifdef DEBUG_CONN - io_set_debug(conn, true); -#endif ok1(*state == 0); (*state)++; expected_fd = io_conn_fd(conn); diff --git a/ccan/ccan/io/test/run-02-read-debug.c b/ccan/ccan/io/test/run-02-read-debug.c deleted file mode 100644 index eba1363da..000000000 --- a/ccan/ccan/io/test/run-02-read-debug.c +++ /dev/null @@ -1,2 +0,0 @@ -#define DEBUG_CONN -#include "run-02-read.c" diff --git a/ccan/ccan/io/test/run-02-read.c b/ccan/ccan/io/test/run-02-read.c index 74cb2f021..95000b48e 100644 --- a/ccan/ccan/io/test/run-02-read.c +++ b/ccan/ccan/io/test/run-02-read.c @@ -6,11 +6,7 @@ #include #include -#ifdef DEBUG_CONN -#define PORT "64002" -#else #define PORT "65002" -#endif struct data { int state; @@ -26,9 +22,6 @@ static void finish_ok(struct io_conn *conn, struct data *d) static struct io_plan *init_conn(struct io_conn *conn, struct data *d) { -#ifdef DEBUG_CONN - io_set_debug(conn, true); -#endif ok1(d->state == 0); d->state++; diff --git a/ccan/ccan/io/test/run-03-readpartial-debug.c b/ccan/ccan/io/test/run-03-readpartial-debug.c deleted file mode 100644 index 7c9f8c4e9..000000000 --- a/ccan/ccan/io/test/run-03-readpartial-debug.c +++ /dev/null @@ -1,2 +0,0 @@ -#define DEBUG_CONN -#include "run-03-readpartial.c" diff --git a/ccan/ccan/io/test/run-03-readpartial.c b/ccan/ccan/io/test/run-03-readpartial.c index 7c24d16e9..2e2e8e16e 100644 --- a/ccan/ccan/io/test/run-03-readpartial.c +++ b/ccan/ccan/io/test/run-03-readpartial.c @@ -6,11 +6,7 @@ #include #include -#ifdef DEBUG_CONN -#define PORT "64003" -#else #define PORT "65003" -#endif struct data { int state; @@ -27,9 +23,6 @@ static void finish_ok(struct io_conn *conn, struct data *d) static struct io_plan *init_conn(struct io_conn *conn, struct data *d) { -#ifdef DEBUG_CONN - io_set_debug(conn, true); -#endif ok1(d->state == 0); d->state++; diff --git a/ccan/ccan/io/test/run-04-writepartial-debug.c b/ccan/ccan/io/test/run-04-writepartial-debug.c deleted file mode 100644 index dd40c0c9d..000000000 --- a/ccan/ccan/io/test/run-04-writepartial-debug.c +++ /dev/null @@ -1,2 +0,0 @@ -#define DEBUG_CONN -#include "run-04-writepartial.c" diff --git a/ccan/ccan/io/test/run-04-writepartial.c b/ccan/ccan/io/test/run-04-writepartial.c index d3f7043f7..947f01e57 100644 --- a/ccan/ccan/io/test/run-04-writepartial.c +++ b/ccan/ccan/io/test/run-04-writepartial.c @@ -6,11 +6,7 @@ #include #include -#ifdef DEBUG_CONN -#define PORT "64004" -#else #define PORT "65004" -#endif struct data { int state; @@ -27,9 +23,6 @@ static void finish_ok(struct io_conn *conn, struct data *d) static struct io_plan *init_conn(struct io_conn *conn, struct data *d) { -#ifdef DEBUG_CONN - io_set_debug(conn, true); -#endif ok1(d->state == 0); d->state++; io_set_finish(conn, finish_ok, d); diff --git a/ccan/ccan/io/test/run-05-write-debug.c b/ccan/ccan/io/test/run-05-write-debug.c deleted file mode 100644 index 5c991283a..000000000 --- a/ccan/ccan/io/test/run-05-write-debug.c +++ /dev/null @@ -1,2 +0,0 @@ -#define DEBUG_CONN -#include "run-05-write.c" diff --git a/ccan/ccan/io/test/run-05-write.c b/ccan/ccan/io/test/run-05-write.c index 41fe29494..3b0cc7243 100644 --- a/ccan/ccan/io/test/run-05-write.c +++ b/ccan/ccan/io/test/run-05-write.c @@ -6,11 +6,7 @@ #include #include -#ifdef DEBUG_CONN -#define PORT "64005" -#else #define PORT "65005" -#endif struct data { int state; @@ -27,9 +23,6 @@ static void finish_ok(struct io_conn *conn, struct data *d) static struct io_plan *init_conn(struct io_conn *conn, struct data *d) { -#ifdef DEBUG_CONN - io_set_debug(conn, true); -#endif ok1(d->state == 0); d->state++; io_set_finish(conn, finish_ok, d); diff --git a/ccan/ccan/io/test/run-06-idle.c b/ccan/ccan/io/test/run-06-idle.c index 57d5e20c1..3d7c3cc33 100644 --- a/ccan/ccan/io/test/run-06-idle.c +++ b/ccan/ccan/io/test/run-06-idle.c @@ -9,11 +9,7 @@ #include #include -#ifdef DEBUG_CONN -#define PORT "64006" -#else #define PORT "65006" -#endif static struct io_conn *idler; diff --git a/ccan/ccan/io/test/run-07-break-debug.c b/ccan/ccan/io/test/run-07-break-debug.c deleted file mode 100644 index 94291c688..000000000 --- a/ccan/ccan/io/test/run-07-break-debug.c +++ /dev/null @@ -1,2 +0,0 @@ -#define DEBUG_CONN -#include "run-07-break.c" diff --git a/ccan/ccan/io/test/run-07-break.c b/ccan/ccan/io/test/run-07-break.c index d13b0f183..135dcbb8f 100644 --- a/ccan/ccan/io/test/run-07-break.c +++ b/ccan/ccan/io/test/run-07-break.c @@ -6,11 +6,7 @@ #include #include -#ifdef DEBUG_CONN -#define PORT "64007" -#else #define PORT "65007" -#endif struct data { int state; @@ -32,9 +28,6 @@ static void finish_ok(struct io_conn *conn, struct data *d) static struct io_plan *init_conn(struct io_conn *conn, struct data *d) { -#ifdef DEBUG_CONN - io_set_debug(conn, true); -#endif ok1(d->state == 0); d->state++; diff --git a/ccan/ccan/io/test/run-09-connect-debug.c b/ccan/ccan/io/test/run-09-connect-debug.c deleted file mode 100644 index e7f9ddebf..000000000 --- a/ccan/ccan/io/test/run-09-connect-debug.c +++ /dev/null @@ -1,2 +0,0 @@ -#define DEBUG_CONN -#include "run-09-connect.c" diff --git a/ccan/ccan/io/test/run-09-connect.c b/ccan/ccan/io/test/run-09-connect.c index 124b6a1f7..e5f0d1f85 100644 --- a/ccan/ccan/io/test/run-09-connect.c +++ b/ccan/ccan/io/test/run-09-connect.c @@ -6,11 +6,7 @@ #include #include -#ifdef DEBUG_CONN -#define PORT "64009" -#else #define PORT "65009" -#endif static struct io_listener *l; static struct data *d2; @@ -35,9 +31,6 @@ static struct io_plan *connected(struct io_conn *conn, struct data *d2) static struct io_plan *init_conn(struct io_conn *conn, struct data *d) { -#ifdef DEBUG_CONN - io_set_debug(conn, true); -#endif ok1(d->state == 0); d->state++; io_close_listener(l); diff --git a/ccan/ccan/io/test/run-12-bidir-debug.c b/ccan/ccan/io/test/run-12-bidir-debug.c deleted file mode 100644 index af5fd89c4..000000000 --- a/ccan/ccan/io/test/run-12-bidir-debug.c +++ /dev/null @@ -1,2 +0,0 @@ -#define DEBUG_CONN -#include "run-12-bidir.c" diff --git a/ccan/ccan/io/test/run-12-bidir.c b/ccan/ccan/io/test/run-12-bidir.c index e79acb56d..77843ae7b 100644 --- a/ccan/ccan/io/test/run-12-bidir.c +++ b/ccan/ccan/io/test/run-12-bidir.c @@ -6,11 +6,7 @@ #include #include -#ifdef DEBUG_CONN -#define PORT "64012" -#else #define PORT "65012" -#endif struct data { struct io_listener *l; @@ -42,9 +38,6 @@ static struct io_plan *w_done(struct io_conn *conn, struct data *d) static struct io_plan *init_conn(struct io_conn *conn, struct data *d) { -#ifdef DEBUG_CONN - io_set_debug(conn, true); -#endif ok1(d->state == 0); d->state++; diff --git a/ccan/ccan/io/test/run-14-duplex-both-read-debug.c b/ccan/ccan/io/test/run-14-duplex-both-read-debug.c deleted file mode 100644 index 92bbb6708..000000000 --- a/ccan/ccan/io/test/run-14-duplex-both-read-debug.c +++ /dev/null @@ -1,2 +0,0 @@ -#define DEBUG_CONN -#include "run-14-duplex-both-read.c" diff --git a/ccan/ccan/io/test/run-14-duplex-both-read.c b/ccan/ccan/io/test/run-14-duplex-both-read.c index 30c46cd5d..ed77cab8a 100644 --- a/ccan/ccan/io/test/run-14-duplex-both-read.c +++ b/ccan/ccan/io/test/run-14-duplex-both-read.c @@ -8,11 +8,7 @@ #include #include -#ifdef DEBUG_CONN -#define PORT "64014" -#else #define PORT "65014" -#endif struct data { struct io_listener *l; @@ -47,9 +43,6 @@ static struct io_plan *make_duplex(struct io_conn *conn, struct data *d) static struct io_plan *init_conn(struct io_conn *conn, struct data *d) { -#ifdef DEBUG_CONN - io_set_debug(conn, true); -#endif ok1(d->state == 0); d->state++; diff --git a/ccan/ccan/io/test/run-15-timeout.c b/ccan/ccan/io/test/run-15-timeout.c index a4ab23add..64741c4f0 100644 --- a/ccan/ccan/io/test/run-15-timeout.c +++ b/ccan/ccan/io/test/run-15-timeout.c @@ -8,11 +8,7 @@ #include #include -#ifdef DEBUG_CONN -#define PORT "64015" -#else #define PORT "65015" -#endif struct data { struct timers timers; @@ -38,9 +34,6 @@ static struct io_plan *no_timeout(struct io_conn *conn, struct data *d) static struct io_plan *init_conn(struct io_conn *conn, struct data *d) { -#ifdef DEBUG_CONN - io_set_debug(conn, true); -#endif ok1(d->state == 0); d->state++; diff --git a/ccan/ccan/io/test/run-16-duplex-test-debug.c b/ccan/ccan/io/test/run-16-duplex-test-debug.c deleted file mode 100644 index 70ef3db94..000000000 --- a/ccan/ccan/io/test/run-16-duplex-test-debug.c +++ /dev/null @@ -1,2 +0,0 @@ -#define DEBUG_CONN -#include "run-16-duplex-test.c" diff --git a/ccan/ccan/io/test/run-16-duplex-test.c b/ccan/ccan/io/test/run-16-duplex-test.c index 8631be451..007f41119 100644 --- a/ccan/ccan/io/test/run-16-duplex-test.c +++ b/ccan/ccan/io/test/run-16-duplex-test.c @@ -8,11 +8,7 @@ #include #include -#ifdef DEBUG_CONN -#define PORT "64016" -#else #define PORT "65016" -#endif struct data { struct io_listener *l; @@ -34,9 +30,6 @@ static struct io_plan *io_done(struct io_conn *conn, struct data *d) static struct io_plan *init_conn(struct io_conn *conn, struct data *d) { -#ifdef DEBUG_CONN - io_set_debug(conn, true); -#endif ok1(d->state == 0); d->state++; diff --git a/ccan/ccan/io/test/run-17-homemade-io-debug.c b/ccan/ccan/io/test/run-17-homemade-io-debug.c deleted file mode 100644 index e26de11c1..000000000 --- a/ccan/ccan/io/test/run-17-homemade-io-debug.c +++ /dev/null @@ -1,2 +0,0 @@ -#define DEBUG_CONN -#include "run-17-homemade-io.c" diff --git a/ccan/ccan/io/test/run-17-homemade-io.c b/ccan/ccan/io/test/run-17-homemade-io.c index d104f3e9a..150bcbdc4 100644 --- a/ccan/ccan/io/test/run-17-homemade-io.c +++ b/ccan/ccan/io/test/run-17-homemade-io.c @@ -6,11 +6,7 @@ #include #include -#ifdef DEBUG_CONN -#define PORT "64017" -#else #define PORT "65017" -#endif struct packet { int state; @@ -85,9 +81,6 @@ static struct io_plan *io_read_packet(struct io_conn *conn, static struct io_plan *init_conn(struct io_conn *conn, struct packet *pkt) { -#ifdef DEBUG_CONN - io_set_debug(conn, true); -#endif ok1(pkt->state == 0); pkt->state++; diff --git a/ccan/ccan/io/test/run-18-errno-debug.c b/ccan/ccan/io/test/run-18-errno-debug.c deleted file mode 100644 index f7ffc3d44..000000000 --- a/ccan/ccan/io/test/run-18-errno-debug.c +++ /dev/null @@ -1,2 +0,0 @@ -#define DEBUG_CONN -#include "run-18-errno.c" diff --git a/ccan/ccan/io/test/run-18-errno.c b/ccan/ccan/io/test/run-18-errno.c index 1bee7682b..904a20caf 100644 --- a/ccan/ccan/io/test/run-18-errno.c +++ b/ccan/ccan/io/test/run-18-errno.c @@ -6,11 +6,7 @@ #include #include -#ifdef DEBUG_CONN -#define PORT "64018" -#else #define PORT "65018" -#endif static void finish_100(struct io_conn *conn, int *state) { @@ -29,13 +25,10 @@ static void finish_EBADF(struct io_conn *conn, int *state) static struct io_plan *init_conn(struct io_conn *conn, int *state) { -#ifdef DEBUG_CONN - io_set_debug(conn, true); -#endif if (*state == 0) { (*state)++; - errno = 100; io_set_finish(conn, finish_100, state); + errno = 100; return io_close(conn); } else { ok1(*state == 2); diff --git a/ccan/ccan/io/test/run-19-always-debug.c b/ccan/ccan/io/test/run-19-always-debug.c deleted file mode 100644 index f36d58ed2..000000000 --- a/ccan/ccan/io/test/run-19-always-debug.c +++ /dev/null @@ -1,2 +0,0 @@ -#define DEBUG_CONN -#include "run-19-always.c" diff --git a/ccan/ccan/io/test/run-19-always.c b/ccan/ccan/io/test/run-19-always.c index 7a015f28b..af190a4d0 100644 --- a/ccan/ccan/io/test/run-19-always.c +++ b/ccan/ccan/io/test/run-19-always.c @@ -6,11 +6,7 @@ #include #include -#ifdef DEBUG_CONN -#define PORT "64019" -#else #define PORT "65019" -#endif struct data { int state; @@ -32,9 +28,6 @@ static struct io_plan *write_buf(struct io_conn *conn, struct data *d) static struct io_plan *init_conn(struct io_conn *conn, struct data *d) { -#ifdef DEBUG_CONN - io_set_debug(conn, true); -#endif ok1(d->state == 0); d->state++; io_set_finish(conn, finish_ok, d); diff --git a/ccan/ccan/ptr_valid/LICENSE b/ccan/ccan/ptr_valid/LICENSE new file mode 120000 index 000000000..2354d1294 --- /dev/null +++ b/ccan/ccan/ptr_valid/LICENSE @@ -0,0 +1 @@ +../../licenses/BSD-MIT \ No newline at end of file diff --git a/ccan/ccan/ptr_valid/_info b/ccan/ccan/ptr_valid/_info new file mode 100644 index 000000000..91c9abd37 --- /dev/null +++ b/ccan/ccan/ptr_valid/_info @@ -0,0 +1,29 @@ +#include "config.h" +#include +#include + +/** + * ptr_valid - test whether a pointer is safe to dereference. + * + * This little helper tells you if an address is mapped; it doesn't tell you + * if it's read-only (or execute only). + * + * License: BSD-MIT + * + * Ccanlint: + * // Our child actually crashes, but that's OK! + * tests_pass_valgrind test/run.c:--child-silent-after-fork=yes + */ +int main(int argc, char *argv[]) +{ + /* Expect exactly one argument */ + if (argc != 2) + return 1; + + if (strcmp(argv[1], "depends") == 0) { + printf("ccan/noerr\n"); + return 0; + } + + return 1; +} diff --git a/ccan/ccan/ptr_valid/ptr_valid.c b/ccan/ccan/ptr_valid/ptr_valid.c new file mode 100644 index 000000000..dc61dd27c --- /dev/null +++ b/ccan/ccan/ptr_valid/ptr_valid.c @@ -0,0 +1,344 @@ +// Licensed under BSD-MIT: See LICENSE. +#include "ptr_valid.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_PROC_SELF_MAPS +static char *grab(const char *filename) +{ + int ret, fd; + size_t max = 16384, s = 0; + char *buffer; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return NULL; + + buffer = malloc(max+1); + if (!buffer) + goto close; + + while ((ret = read(fd, buffer + s, max - s)) > 0) { + s += ret; + if (s == max) { + buffer = realloc(buffer, max*2+1); + if (!buffer) + goto close; + max *= 2; + } + } + if (ret < 0) + goto free; + + close(fd); + buffer[s] = '\0'; + return buffer; + +free: + free(buffer); +close: + close_noerr(fd); + return NULL; +} + +static char *skip_line(char *p) +{ + char *nl = strchr(p, '\n'); + if (!nl) + return NULL; + return nl + 1; +} + +static struct ptr_valid_map *add_map(struct ptr_valid_map *map, + unsigned int *num, + unsigned int *max, + unsigned long start, unsigned long end, bool is_write) +{ + if (*num == *max) { + *max *= 2; + map = realloc(map, sizeof(*map) * *max); + if (!map) + return NULL; + } + map[*num].start = (void *)start; + map[*num].end = (void *)end; + map[*num].is_write = is_write; + (*num)++; + return map; +} + +static struct ptr_valid_map *get_proc_maps(unsigned int *num) +{ + char *buf, *p; + struct ptr_valid_map *map; + unsigned int max = 16; + + buf = grab("/proc/self/maps"); + if (!buf) { + *num = 0; + return NULL; + } + + map = malloc(sizeof(*map) * max); + if (!map) + goto free_buf; + + *num = 0; + for (p = buf; p && *p; p = skip_line(p)) { + unsigned long start, end; + char *endp; + + /* Expect '- rw... */ + start = strtoul(p, &endp, 16); + if (*endp != '-') + goto malformed; + end = strtoul(endp+1, &endp, 16); + if (*endp != ' ') + goto malformed; + + endp++; + if (endp[0] != 'r' && endp[0] != '-') + goto malformed; + if (endp[1] != 'w' && endp[1] != '-') + goto malformed; + + /* We only add readable mappings. */ + if (endp[0] == 'r') { + map = add_map(map, num, &max, start, end, + endp[1] == 'w'); + if (!map) + goto free_buf; + } + } + + free(buf); + return map; + + +malformed: + free(map); +free_buf: + free(buf); + *num = 0; + return NULL; +} +#else +static struct ptr_valid_map *get_proc_maps(unsigned int *num) +{ + *num = 0; + return NULL; +} +#endif + +static bool check_with_maps(struct ptr_valid_batch *batch, + const char *p, size_t size, bool is_write) +{ + unsigned int i; + + for (i = 0; i < batch->num_maps; i++) { + if (p >= batch->maps[i].start && p < batch->maps[i].end) { + /* Overlap into other maps? Recurse with remainder. */ + if (p + size > batch->maps[i].end) { + size_t len = p + size - batch->maps[i].end; + if (!check_with_maps(batch, batch->maps[i].end, + len, is_write)) + return false; + } + return !is_write || batch->maps[i].is_write; + } + } + return false; +} + +static void finish_child(struct ptr_valid_batch *batch) +{ + close(batch->to_child); + close(batch->from_child); + waitpid(batch->child_pid, NULL, 0); + batch->child_pid = 0; +} + +static bool child_alive(struct ptr_valid_batch *batch) +{ + return batch->child_pid != 0; +} + +static void run_child(int infd, int outfd) +{ + volatile char *p; + + /* This is how we expect to exit. */ + while (read(infd, &p, sizeof(p)) == sizeof(p)) { + size_t i, size; + bool is_write; + char ret = 0; + + /* This is weird. */ + if (read(infd, &size, sizeof(size)) != sizeof(size)) + exit(1); + if (read(infd, &is_write, sizeof(is_write)) != sizeof(is_write)) + exit(2); + + for (i = 0; i < size; i++) { + ret = p[i]; + if (is_write) + p[i] = ret; + } + + /* If we're still here, the answer is "yes". */ + if (write(outfd, &ret, 1) != 1) + exit(3); + } + exit(0); +} + +static bool create_child(struct ptr_valid_batch *batch) +{ + int outpipe[2], inpipe[2]; + + if (pipe(outpipe) != 0) + return false; + if (pipe(inpipe) != 0) + goto close_outpipe; + + fflush(stdout); + batch->child_pid = fork(); + if (batch->child_pid == 0) { + close(outpipe[1]); + close(inpipe[0]); + run_child(outpipe[0], inpipe[1]); + } + + if (batch->child_pid == -1) + goto cleanup_pid; + + close(outpipe[0]); + close(inpipe[1]); + + batch->to_child = outpipe[1]; + batch->from_child = inpipe[0]; + return true; + +cleanup_pid: + batch->child_pid = 0; + close_noerr(inpipe[0]); + close_noerr(inpipe[1]); +close_outpipe: + close_noerr(outpipe[0]); + close_noerr(outpipe[1]); + return false; +} + +static bool check_with_child(struct ptr_valid_batch *batch, + const void *p, size_t size, bool is_write) +{ + char ret; + + if (!child_alive(batch)) { + if (!create_child(batch)) + return false; + } + + if (write(batch->to_child, &p, sizeof(p)) + + write(batch->to_child, &size, sizeof(size)) + + write(batch->to_child, &is_write, sizeof(is_write)) + != sizeof(p) + sizeof(size) + sizeof(is_write)) { + finish_child(batch); + errno = EFAULT; + return false; + } + + if (read(batch->from_child, &ret, sizeof(ret)) != sizeof(ret)) { + finish_child(batch); + errno = EFAULT; + return false; + } + return true; +} + +/* msync seems most well-defined test, but page could be mapped with + * no permissions, and can't distiguish readonly from writable. */ +bool ptr_valid_batch(struct ptr_valid_batch *batch, + const void *p, size_t alignment, size_t size, bool write) +{ + char *start, *end; + bool ret; + + if ((intptr_t)p & (alignment - 1)) + return false; + + start = (void *)((intptr_t)p & ~(getpagesize() - 1)); + end = (void *)(((intptr_t)p + size - 1) & ~(getpagesize() - 1)); + + /* We cache single page hits. */ + if (start == end) { + if (batch->last && batch->last == start) + return batch->last_ok; + } + + if (batch->num_maps) + ret = check_with_maps(batch, p, size, write); + else + ret = check_with_child(batch, p, size, write); + + if (start == end) { + batch->last = start; + batch->last_ok = ret; + } + + return ret; +} + +bool ptr_valid_batch_string(struct ptr_valid_batch *batch, const char *p) +{ + while (ptr_valid_batch(batch, p, 1, 1, false)) { + if (*p == '\0') + return true; + p++; + } + return false; +} + +bool ptr_valid(const void *p, size_t alignment, size_t size, bool write) +{ + bool ret; + struct ptr_valid_batch batch; + if (!ptr_valid_batch_start(&batch)) + return false; + ret = ptr_valid_batch(&batch, p, alignment, size, write); + ptr_valid_batch_end(&batch); + return ret; +} + +bool ptr_valid_string(const char *p) +{ + bool ret; + struct ptr_valid_batch batch; + if (!ptr_valid_batch_start(&batch)) + return false; + ret = ptr_valid_batch_string(&batch, p); + ptr_valid_batch_end(&batch); + return ret; +} + +bool ptr_valid_batch_start(struct ptr_valid_batch *batch) +{ + batch->child_pid = 0; + batch->maps = get_proc_maps(&batch->num_maps); + batch->last = NULL; + return true; +} + +void ptr_valid_batch_end(struct ptr_valid_batch *batch) +{ + if (child_alive(batch)) + finish_child(batch); + free(batch->maps); +} diff --git a/ccan/ccan/ptr_valid/ptr_valid.h b/ccan/ccan/ptr_valid/ptr_valid.h new file mode 100644 index 000000000..3871cad8e --- /dev/null +++ b/ccan/ccan/ptr_valid/ptr_valid.h @@ -0,0 +1,229 @@ +// Licensed under BSD-MIT: See LICENSE. +#ifndef CCAN_PTR_VALID_H +#define CCAN_PTR_VALID_H +#include "config.h" +#include +#include + +/** + * ptr_valid_read - can I safely read from a pointer? + * @p: the proposed pointer. + * + * This function verifies that the pointer @p is safe to dereference for + * reading. It is very slow, particularly if the answer is "no". + * + * Sets errno to EFAULT on failure. + * + * See Also: + * ptr_valid_batch_read() + */ +#define ptr_valid_read(p) \ + ptr_valid_r((p), PTR_VALID_ALIGNOF(*(p)), sizeof(*(p))) + +/** + * ptr_valid_write - can I safely write to a pointer? + * @p: the proposed pointer. + * + * This function verifies that the pointer @p is safe to dereference + * for writing (and reading). It is very slow, particularly if the + * answer is "no". + * + * Sets errno to EFAULT on failure. + * + * See Also: + * ptr_valid_batch_write() + */ +#define ptr_valid_write(p) \ + ptr_valid_w((p), PTR_VALID_ALIGNOF(*(p)), sizeof(*(p))) + +/** + * ptr_valid_string - can I safely read a string? + * @p: the proposed string. + * + * This function verifies that the pointer @p is safe to dereference + * up to a nul character. It is very slow, particularly if the answer + * is "no". + * + * Sets errno to EFAULT on failure. + * + * See Also: + * ptr_valid_batch_string() + */ +bool ptr_valid_string(const char *p); + +/** + * ptr_valid - generic pointer check function + * @p: the proposed pointer. + * @align: the alignment requirements of the pointer. + * @size: the size of the region @p should point to + * @write: true if @p should be writable as well as readable. + * + * This function verifies that the pointer @p is safe to dereference. + * It is very slow, particularly if the answer is "no". + * + * Sets errno to EFAULT on failure. + * + * See Also: + * ptr_valid_batch() + */ +bool ptr_valid(const void *p, size_t align, size_t size, bool write); + +/** + * struct ptr_valid_batch - pointer to store state for batch ptr ops + * + * Treat as private. + */ +struct ptr_valid_batch { + unsigned int num_maps; + struct ptr_valid_map *maps; + int child_pid; + int to_child, from_child; + void *last; + bool last_ok; +}; + +/** + * ptr_valid_batch_start - prepare for a batch of ptr_valid checks. + * @batch: an uninitialized ptr_valid_batch structure. + * + * This initializes @batch; this same @batch pointer can be reused + * until the memory map changes (eg. via mmap(), munmap() or even + * malloc() and free()). + * + * This is useful to check many pointers, because otherwise it can be + * extremely slow. + * + * Example: + * struct linked { + * struct linked *next; + * const char *str; + * }; + * + * static bool check_linked_carefully(struct linked *head) + * { + * struct ptr_valid_batch batch; + * struct linked *old = head; + * bool half = true; + * + * // If this fails, we can't check. Assume OK. + * if (!ptr_valid_batch_start(&batch)) + * return true; + * + * while (head) { + * if (!ptr_valid_batch_read(&batch, head)) + * goto fail; + * if (!ptr_valid_batch_string(&batch, head->str)) + * goto fail; + * // Loop detection; move old at half speed of head. + * if (half) + * old = old->next; + * half = !half; + * if (head == old) { + * errno = ELOOP; + * goto fail; + * } + * } + * ptr_valid_batch_end(&batch); + * return true; + * + * fail: + * ptr_valid_batch_end(&batch); + * return false; + * } + * + * See Also: + * ptr_valid_batch_stop() + */ +bool ptr_valid_batch_start(struct ptr_valid_batch *batch); + +/** + * ptr_valid_batch_read - can I safely read from a pointer? + * @batch: the batch initialized by ptr_valid_batch_start(). + * @p: the proposed pointer. + * + * Batched version of ptr_valid_read(). + */ +#define ptr_valid_batch_read(batch, p) \ + ptr_valid_batch_r((batch), \ + (p), PTR_VALID_ALIGNOF(*(p)), sizeof(*(p))) + +/** + * ptr_valid_batch_write - can I safely write to a pointer? + * @batch: the batch initialized by ptr_valid_batch_start(). + * @p: the proposed pointer. + * + * Batched version of ptr_valid_write(). + */ +#define ptr_valid_batch_write(batch, p) \ + ptr_valid_batch_w((batch), \ + (p), PTR_VALID_ALIGNOF(*(p)), sizeof(*(p))) + +/** + * ptr_valid_batch_string - can I safely read a string? + * @batch: the batch initialized by ptr_valid_batch_start(). + * @p: the proposed string. + * + * Batched version of ptr_valid_string(). + */ +bool ptr_valid_batch_string(struct ptr_valid_batch *batch, const char *p); + +/** + * ptr_valid_batch - generic batched pointer check function + * @batch: the batch initialized by ptr_valid_batch_start(). + * @p: the proposed pointer. + * @align: the alignment requirements of the pointer. + * @size: the size of the region @p should point to + * @write: true if @p should be writable as well as readable. + * + * Batched version of ptr_valid(). + */ +bool ptr_valid_batch(struct ptr_valid_batch *batch, + const void *p, size_t alignment, size_t size, bool write); + +/** + * ptr_valid_batch_end - end a batch of ptr_valid checks. + * @batch: a ptr_valid_batch structure. + * + * This is used after all checks are complete. + * + * See Also: + * ptr_valid_batch_start() + */ +void ptr_valid_batch_end(struct ptr_valid_batch *batch); + + +/* These wrappers get constness correct. */ +static inline bool ptr_valid_r(const void *p, size_t align, size_t size) +{ + return ptr_valid(p, align, size, false); +} + +static inline bool ptr_valid_w(void *p, size_t align, size_t size) +{ + return ptr_valid(p, align, size, true); +} + +static inline bool ptr_valid_batch_r(struct ptr_valid_batch *batch, + const void *p, size_t align, size_t size) +{ + return ptr_valid_batch(batch, p, align, size, false); +} + +static inline bool ptr_valid_batch_w(struct ptr_valid_batch *batch, + void *p, size_t align, size_t size) +{ + return ptr_valid_batch(batch, p, align, size, true); +} + +struct ptr_valid_map { + const char *start, *end; + bool is_write; +}; + +#if HAVE_ALIGNOF +#define PTR_VALID_ALIGNOF(var) __alignof__(var) +#else +/* Can't check this... */ +#define PTR_VALID_ALIGNOF(var) 1 +#endif +#endif /* CCAN_PTR_VALID_H */ diff --git a/ccan/ccan/ptr_valid/test/run-string.c b/ccan/ccan/ptr_valid/test/run-string.c new file mode 100644 index 000000000..59d36a44f --- /dev/null +++ b/ccan/ccan/ptr_valid/test/run-string.c @@ -0,0 +1,56 @@ +#include +/* Include the C files directly. */ +#include +#include +#include + +int main(void) +{ + char *page; + struct ptr_valid_batch *batch = malloc(sizeof *batch); + + /* This is how many tests you plan to run */ + plan_tests(14); + + page = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + strcpy(page, "hello"); + ok1(ptr_valid_read(page)); + ok1(ptr_valid_write(page)); + ok1(ptr_valid_string(page)); + + ok1(ptr_valid_batch_start(batch)); + ok1(ptr_valid_batch_string(batch, page)); + ptr_valid_batch_end(batch); + + /* Check invalid case. */ + munmap(page, getpagesize()); + ok1(!ptr_valid_string(page)); + + ok1(ptr_valid_batch_start(batch)); + ok1(!ptr_valid_batch_string(batch, page)); + ptr_valid_batch_end(batch); + + /* Check for overrun. */ + page = mmap(NULL, getpagesize()*2, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + munmap(page + getpagesize(), getpagesize()); + + memset(page, 'a', getpagesize()); + ok1(!ptr_valid_string(page)); + ok1(ptr_valid_batch_start(batch)); + ok1(!ptr_valid_batch_string(batch, page)); + ptr_valid_batch_end(batch); + + page[getpagesize()-1] = '\0'; + ok1(ptr_valid_string(page)); + + ok1(ptr_valid_batch_start(batch)); + ok1(ptr_valid_batch_string(batch, page)); + ptr_valid_batch_end(batch); + munmap(page, getpagesize()); + + free(batch); + /* This exits depending on whether all tests passed */ + return exit_status(); +} diff --git a/ccan/ccan/ptr_valid/test/run.c b/ccan/ccan/ptr_valid/test/run.c new file mode 100644 index 000000000..c624aff5b --- /dev/null +++ b/ccan/ccan/ptr_valid/test/run.c @@ -0,0 +1,90 @@ +#include +/* Include the C files directly. */ +#include +#include +#include + +static bool check_batch(char *p, unsigned int num, bool expect) +{ + struct ptr_valid_batch batch; + unsigned int i; + + if (!ptr_valid_batch_start(&batch)) + return false; + for (i = 0; i < num; i++) { + if (ptr_valid_batch(&batch, p + i, 1, 1, false) != expect) + return false; + if (ptr_valid_batch(&batch, p + i, 1, 1, true) != expect) + return false; + } + ptr_valid_batch_end(&batch); + return true; +} + +int main(void) +{ + char *page; + + /* This is how many tests you plan to run */ + plan_tests(30); + + page = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + ok1(ptr_valid_read(page)); + ok1(ptr_valid_write(page)); + ok1(ptr_valid(page, 1, getpagesize(), false)); + ok1(ptr_valid(page, 1, getpagesize(), true)); + + /* Test alignment constraints. */ + ok1(ptr_valid(page, getpagesize(), getpagesize(), false)); + ok1(ptr_valid(page, getpagesize(), getpagesize(), true)); + ok1(!ptr_valid(page+1, getpagesize(), 1, false)); + ok1(!ptr_valid(page+1, getpagesize(), 1, true)); + + /* Test batch. */ + ok1(check_batch(page, getpagesize(), true)); + + /* Unmap, all should fail. */ + munmap(page, getpagesize()); + ok1(!ptr_valid_read(page)); + ok1(!ptr_valid_write(page)); + ok1(!ptr_valid(page, 1, getpagesize(), false)); + ok1(!ptr_valid(page, 1, getpagesize(), true)); + + /* Test alignment constraints. */ + ok1(!ptr_valid(page, getpagesize(), getpagesize(), false)); + ok1(!ptr_valid(page, getpagesize(), getpagesize(), true)); + ok1(!ptr_valid(page+1, getpagesize(), 1, false)); + ok1(!ptr_valid(page, getpagesize(), 1, true)); + + /* Test batch (slow, since each fails, so reduce count). */ + ok1(check_batch(page, 4, false)); + + /* Check read-only */ + page = mmap(NULL, getpagesize(), PROT_READ, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + ok1(ptr_valid_read(page)); + ok1(!ptr_valid_write(page)); + ok1(ptr_valid(page, 1, getpagesize(), false)); + ok1(!ptr_valid(page, 1, getpagesize(), true)); + + /* Test alignment constraints. */ + ok1(ptr_valid(page, getpagesize(), getpagesize(), false)); + ok1(!ptr_valid(page, getpagesize(), getpagesize(), true)); + ok1(!ptr_valid(page+1, getpagesize(), 1, false)); + ok1(!ptr_valid(page+1, getpagesize(), 1, true)); + munmap(page, getpagesize()); + + /* Check for overrun. */ + page = mmap(NULL, getpagesize()*2, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + munmap(page + getpagesize(), getpagesize()); + + ok1(ptr_valid(page, 1, getpagesize(), false)); + ok1(ptr_valid(page, 1, getpagesize(), true)); + ok1(!ptr_valid(page, 1, getpagesize()+1, false)); + ok1(!ptr_valid(page, 1, getpagesize()+1, true)); + + /* This exits depending on whether all tests passed */ + return exit_status(); +} diff --git a/ccan/ccan/tal/tal.c b/ccan/ccan/tal/tal.c index 842059d03..2a2eca77c 100644 --- a/ccan/ccan/tal/tal.c +++ b/ccan/ccan/tal/tal.c @@ -14,6 +14,7 @@ //#define TAL_DEBUG 1 #define NOTIFY_IS_DESTRUCTOR 512 +#define NOTIFY_EXTRA_ARG 1024 /* 32-bit type field, first byte 0 in either endianness. */ enum prop_type { @@ -56,9 +57,18 @@ struct notifier { union { void (*notifyfn)(tal_t *, enum tal_notify_type, void *); void (*destroy)(tal_t *); /* If NOTIFY_IS_DESTRUCTOR set */ + void (*destroy2)(tal_t *, void *); /* If NOTIFY_EXTRA_ARG */ } u; }; +/* Extra arg */ +struct notifier_extra_arg { + struct notifier n; + void *arg; +}; + +#define EXTRA_ARG(n) (((struct notifier_extra_arg *)(n))->arg) + static struct { struct tal_hdr hdr; struct children c; @@ -203,7 +213,8 @@ static struct tal_hdr *debug_tal(struct tal_hdr *tal) #endif static void notify(const struct tal_hdr *ctx, - enum tal_notify_type type, const void *info) + enum tal_notify_type type, const void *info, + int saved_errno) { const struct prop_hdr *p; @@ -216,9 +227,14 @@ static void notify(const struct tal_hdr *ctx, continue; n = (struct notifier *)p; if (n->types & type) { - if (n->types & NOTIFY_IS_DESTRUCTOR) - n->u.destroy(from_tal_hdr(ctx)); - else + errno = saved_errno; + if (n->types & NOTIFY_IS_DESTRUCTOR) { + if (n->types & NOTIFY_EXTRA_ARG) + n->u.destroy2(from_tal_hdr(ctx), + EXTRA_ARG(n)); + else + n->u.destroy(from_tal_hdr(ctx)); + } else n->u.notifyfn(from_tal_hdr(ctx), type, (void *)info); } @@ -274,13 +290,22 @@ static struct notifier *add_notifier_property(struct tal_hdr *t, enum tal_notify_type types, void (*fn)(void *, enum tal_notify_type, - void *)) + void *), + void *extra_arg) { - struct notifier *prop = allocate(sizeof(*prop)); + struct notifier *prop; + + if (types & NOTIFY_EXTRA_ARG) + prop = allocate(sizeof(struct notifier_extra_arg)); + else + prop = allocate(sizeof(struct notifier)); + if (prop) { init_property(&prop->hdr, t, NOTIFIER); prop->types = types; prop->u.notifyfn = fn; + if (types & NOTIFY_EXTRA_ARG) + EXTRA_ARG(prop) = extra_arg; } return prop; } @@ -288,24 +313,33 @@ static struct notifier *add_notifier_property(struct tal_hdr *t, static enum tal_notify_type del_notifier_property(struct tal_hdr *t, void (*fn)(tal_t *, enum tal_notify_type, - void *)) + void *), + bool match_extra_arg, + void *extra_arg) { struct prop_hdr **p; for (p = (struct prop_hdr **)&t->prop; *p; p = &(*p)->next) { struct notifier *n; + enum tal_notify_type types; if (is_literal(*p)) break; if ((*p)->type != NOTIFIER) continue; n = (struct notifier *)*p; - if (n->u.notifyfn == fn) { - enum tal_notify_type types = n->types; - *p = (*p)->next; - freefn(n); - return types & ~NOTIFY_IS_DESTRUCTOR; - } + if (n->u.notifyfn != fn) + continue; + + types = n->types; + if ((types & NOTIFY_EXTRA_ARG) + && match_extra_arg + && extra_arg != EXTRA_ARG(n)) + continue; + + *p = (*p)->next; + freefn(n); + return types & ~(NOTIFY_IS_DESTRUCTOR|NOTIFY_EXTRA_ARG); } return 0; } @@ -348,7 +382,7 @@ static bool add_child(struct tal_hdr *parent, struct tal_hdr *child) return true; } -static void del_tree(struct tal_hdr *t, const tal_t *orig) +static void del_tree(struct tal_hdr *t, const tal_t *orig, int saved_errno) { struct prop_hdr **prop, *p, *next; @@ -359,7 +393,7 @@ static void del_tree(struct tal_hdr *t, const tal_t *orig) set_destroying_bit(&t->parent_child); /* Call free notifiers. */ - notify(t, TAL_NOTIFY_FREE, (tal_t *)orig); + notify(t, TAL_NOTIFY_FREE, (tal_t *)orig, saved_errno); /* Now free children and groups. */ prop = find_property_ptr(t, CHILDREN); @@ -369,7 +403,7 @@ static void del_tree(struct tal_hdr *t, const tal_t *orig) while ((i = list_top(&c->children, struct tal_hdr, list))) { list_del(&i->list); - del_tree(i, orig); + del_tree(i, orig, saved_errno); } } @@ -426,7 +460,7 @@ void *tal_alloc_(const tal_t *ctx, size_t size, } debug_tal(parent); if (notifiers) - notify(parent, TAL_NOTIFY_ADD_CHILD, from_tal_hdr(child)); + notify(parent, TAL_NOTIFY_ADD_CHILD, from_tal_hdr(child), 0); return from_tal_hdr(debug_tal(child)); } @@ -466,9 +500,9 @@ void *tal_free(const tal_t *ctx) t = debug_tal(to_tal_hdr(ctx)); if (notifiers) notify(ignore_destroying_bit(t->parent_child)->parent, - TAL_NOTIFY_DEL_CHILD, ctx); + TAL_NOTIFY_DEL_CHILD, ctx, saved_errno); list_del(&t->list); - del_tree(t, ctx); + del_tree(t, ctx, saved_errno); errno = saved_errno; } return NULL; @@ -495,7 +529,7 @@ void *tal_steal_(const tal_t *new_parent, const tal_t *ctx) } debug_tal(newpar); if (notifiers) - notify(t, TAL_NOTIFY_STEAL, new_parent); + notify(t, TAL_NOTIFY_STEAL, new_parent, 0); } return (void *)ctx; } @@ -504,9 +538,19 @@ bool tal_add_destructor_(const tal_t *ctx, void (*destroy)(void *me)) { tal_t *t = debug_tal(to_tal_hdr(ctx)); return add_notifier_property(t, TAL_NOTIFY_FREE|NOTIFY_IS_DESTRUCTOR, - (void *)destroy); + (void *)destroy, NULL); +} + +bool tal_add_destructor2_(const tal_t *ctx, void (*destroy)(void *me, void *arg), + void *arg) +{ + tal_t *t = debug_tal(to_tal_hdr(ctx)); + return add_notifier_property(t, TAL_NOTIFY_FREE|NOTIFY_IS_DESTRUCTOR + |NOTIFY_EXTRA_ARG, + (void *)destroy, arg); } +/* We could support notifiers with an extra arg, but we didn't add to API */ bool tal_add_notifier_(const tal_t *ctx, enum tal_notify_type types, void (*callback)(tal_t *, enum tal_notify_type, void *)) { @@ -521,12 +565,12 @@ bool tal_add_notifier_(const tal_t *ctx, enum tal_notify_type types, | TAL_NOTIFY_DEL_NOTIFIER)) == 0); /* Don't call notifier about itself: set types after! */ - n = add_notifier_property(t, 0, callback); + n = add_notifier_property(t, 0, callback, NULL); if (unlikely(!n)) return false; if (notifiers) - notify(t, TAL_NOTIFY_ADD_NOTIFIER, callback); + notify(t, TAL_NOTIFY_ADD_NOTIFIER, callback, 0); n->types = types; if (types != TAL_NOTIFY_FREE) @@ -535,14 +579,15 @@ bool tal_add_notifier_(const tal_t *ctx, enum tal_notify_type types, } bool tal_del_notifier_(const tal_t *ctx, - void (*callback)(tal_t *, enum tal_notify_type, void *)) + void (*callback)(tal_t *, enum tal_notify_type, void *), + bool match_extra_arg, void *extra_arg) { struct tal_hdr *t = debug_tal(to_tal_hdr(ctx)); enum tal_notify_type types; - types = del_notifier_property(t, callback); + types = del_notifier_property(t, callback, match_extra_arg, extra_arg); if (types) { - notify(t, TAL_NOTIFY_DEL_NOTIFIER, callback); + notify(t, TAL_NOTIFY_DEL_NOTIFIER, callback, 0); if (types != TAL_NOTIFY_FREE) notifiers--; return true; @@ -552,7 +597,13 @@ bool tal_del_notifier_(const tal_t *ctx, bool tal_del_destructor_(const tal_t *ctx, void (*destroy)(void *me)) { - return tal_del_notifier_(ctx, (void *)destroy); + return tal_del_notifier_(ctx, (void *)destroy, false, NULL); +} + +bool tal_del_destructor2_(const tal_t *ctx, void (*destroy)(void *me, void *arg), + void *arg) +{ + return tal_del_notifier_(ctx, (void *)destroy, true, arg); } bool tal_set_name_(tal_t *ctx, const char *name, bool literal) @@ -582,7 +633,7 @@ bool tal_set_name_(tal_t *ctx, const char *name, bool literal) debug_tal(t); if (notifiers) - notify(t, TAL_NOTIFY_RENAME, name); + notify(t, TAL_NOTIFY_RENAME, name, 0); return true; } @@ -720,10 +771,10 @@ bool tal_resize_(tal_t **ctxp, size_t size, size_t count, bool clear) } *ctxp = from_tal_hdr(debug_tal(t)); if (notifiers) - notify(t, TAL_NOTIFY_MOVE, from_tal_hdr(old_t)); + notify(t, TAL_NOTIFY_MOVE, from_tal_hdr(old_t), 0); } if (notifiers) - notify(t, TAL_NOTIFY_RESIZE, (void *)size); + notify(t, TAL_NOTIFY_RESIZE, (void *)size, 0); return true; } diff --git a/ccan/ccan/tal/tal.h b/ccan/ccan/tal/tal.h index 713db1188..200c2b161 100644 --- a/ccan/ccan/tal/tal.h +++ b/ccan/ccan/tal/tal.h @@ -56,7 +56,8 @@ typedef void tal_t; * children (recursively) before finally freeing the memory. It returns * NULL, for convenience. * - * Note: errno is preserved by this call. + * Note: errno is preserved by this call, and also saved and restored + * for any destructors or notifiers. * * Example: * p = tal_free(p); @@ -168,6 +169,53 @@ void *tal_free(const tal_t *p); #define tal_del_destructor(ptr, function) \ tal_del_destructor_((ptr), typesafe_cb(void, void *, (function), (ptr))) +/** + * tal_add_destructor2 - add a 2-arg callback function when context is destroyed. + * @ptr: The tal allocated object. + * @function: the function to call before it's freed. + * @arg: the extra argument to the function. + * + * Sometimes an extra argument is required for a destructor; this + * saves the extra argument internally to avoid the caller having to + * do an extra allocation. + * + * Note that this can only fail if your allocfn fails and your errorfn returns. + */ +#define tal_add_destructor2(ptr, function, arg) \ + tal_add_destructor2_((ptr), \ + typesafe_cb_cast(void (*)(tal_t *, void *), \ + void (*)(__typeof__(ptr), \ + __typeof__(arg)), \ + (function)), \ + (arg)) + +/** + * tal_del_destructor - remove a destructor callback function. + * @ptr: The tal allocated object. + * @function: the function to call before it's freed. + * + * If @function has not been successfully added as a destructor, this returns + * false. + */ +#define tal_del_destructor(ptr, function) \ + tal_del_destructor_((ptr), typesafe_cb(void, void *, (function), (ptr))) + +/** + * tal_del_destructor2 - remove 2-arg callback function. + * @ptr: The tal allocated object. + * @function: the function to call before it's freed. + * @arg: the extra argument to the function. + * + * If @function has not been successfully added as a destructor with + * @arg, this returns false. + */ +#define tal_del_destructor2(ptr, function, arg) \ + tal_del_destructor2_((ptr), \ + typesafe_cb_cast(void (*)(tal_t *, void *), \ + void (*)(__typeof__(ptr), \ + __typeof__(arg)), \ + (function)), \ + (arg)) enum tal_notify_type { TAL_NOTIFY_FREE = 1, TAL_NOTIFY_STEAL = 2, @@ -194,6 +242,7 @@ enum tal_notify_type { * TAL_NOTIFY_FREE is called when @ptr is freed, either directly or * because an ancestor is freed: @info is the argument to tal_free(). * It is exactly equivalent to a destructor, with more information. + * errno is set to the value it was at the call of tal_free(). * * TAL_NOTIFY_STEAL is called when @ptr's parent changes: @info is the * new parent. @@ -232,7 +281,8 @@ enum tal_notify_type { tal_del_notifier_((ptr), \ typesafe_cb_postargs(void, void *, (callback), \ (ptr), \ - enum tal_notify_type, void *)) + enum tal_notify_type, void *), \ + false, NULL) /** * tal_set_name - attach a name to a tal pointer. @@ -447,12 +497,17 @@ bool tal_resize_(tal_t **ctxp, size_t size, size_t count, bool clear); bool tal_expand_(tal_t **ctxp, const void *src, size_t size, size_t count); bool tal_add_destructor_(const tal_t *ctx, void (*destroy)(void *me)); +bool tal_add_destructor2_(const tal_t *ctx, void (*destroy)(void *me, void *arg), + void *arg); bool tal_del_destructor_(const tal_t *ctx, void (*destroy)(void *me)); +bool tal_del_destructor2_(const tal_t *ctx, void (*destroy)(void *me, void *arg), + void *arg); bool tal_add_notifier_(const tal_t *ctx, enum tal_notify_type types, void (*notify)(tal_t *ctx, enum tal_notify_type, void *info)); bool tal_del_notifier_(const tal_t *ctx, void (*notify)(tal_t *ctx, enum tal_notify_type, - void *info)); + void *info), + bool match_extra_arg, void *arg); #endif /* CCAN_TAL_H */ diff --git a/ccan/ccan/tal/test/run-destructor2.c b/ccan/ccan/tal/test/run-destructor2.c new file mode 100644 index 000000000..a92f07f49 --- /dev/null +++ b/ccan/ccan/tal/test/run-destructor2.c @@ -0,0 +1,38 @@ +#include +#include +#include + +static void destroy_inc(char *p UNNEEDED, int *destroy_count) +{ + (*destroy_count)++; +} + +static void destroy_dec(char *p UNNEEDED, int *destroy_count) +{ + (*destroy_count)--; +} + +int main(void) +{ + char *p; + int destroy_count1 = 0, destroy_count2 = 0; + + plan_tests(10); + + p = tal(NULL, char); + /* Del must match both fn and arg. */ + ok1(tal_add_destructor2(p, destroy_inc, &destroy_count1)); + ok1(!tal_del_destructor2(p, destroy_inc, &destroy_count2)); + ok1(!tal_del_destructor2(p, destroy_dec, &destroy_count1)); + ok1(tal_del_destructor2(p, destroy_inc, &destroy_count1)); + ok1(!tal_del_destructor2(p, destroy_inc, &destroy_count1)); + + ok1(tal_add_destructor2(p, destroy_inc, &destroy_count1)); + ok1(tal_add_destructor2(p, destroy_dec, &destroy_count2)); + ok1(tal_free(p) == NULL); + ok1(destroy_count1 == 1); + ok1(destroy_count2 == -1); + + tal_cleanup(); + return exit_status(); +} diff --git a/ccan/ccan/tal/test/run-free.c b/ccan/ccan/tal/test/run-free.c index f21264748..37d03cd6f 100644 --- a/ccan/ccan/tal/test/run-free.c +++ b/ccan/ccan/tal/test/run-free.c @@ -4,6 +4,8 @@ static void destroy_errno(char *p UNNEEDED) { + /* Errno restored for all the destructors. */ + ok1(errno == EINVAL); errno = ENOENT; } @@ -11,10 +13,11 @@ int main(void) { char *p; - plan_tests(2); + plan_tests(5); p = tal(NULL, char); ok1(tal_add_destructor(p, destroy_errno)); + ok1(tal_add_destructor(p, destroy_errno)); /* Errno save/restored across free. */ errno = EINVAL; diff --git a/ccan/ccan/time/time.c b/ccan/ccan/time/time.c index 27f0d52a3..981079228 100644 --- a/ccan/ccan/time/time.c +++ b/ccan/ccan/time/time.c @@ -28,7 +28,7 @@ struct timeabs time_now(void) struct timemono time_mono(void) { struct timemono ret; -#ifdef TIME_HAVE_MONOTONIC +#if TIME_HAVE_MONOTONIC clock_gettime(CLOCK_MONOTONIC, &ret.ts); #else /* Best we can do */ ret.ts = time_now().ts; diff --git a/ccan/ccan/time/time.h b/ccan/ccan/time/time.h index 70ebdc9a7..6ab61a99c 100644 --- a/ccan/ccan/time/time.h +++ b/ccan/ccan/time/time.h @@ -71,6 +71,8 @@ struct timemono { */ #if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC) #define TIME_HAVE_MONOTONIC 1 +#else +#define TIME_HAVE_MONOTONIC 0 #endif struct timespec time_check_(struct timespec in, const char *abortstr);