Browse Source

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 <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 8 years ago
parent
commit
f8344baf64
  1. 27
      Makefile
  2. 2
      ccan/README
  3. 1
      ccan/ccan/autodata/LICENSE
  4. 111
      ccan/ccan/autodata/_info
  5. 80
      ccan/ccan/autodata/autodata.c
  6. 109
      ccan/ccan/autodata/autodata.h
  7. 6
      ccan/ccan/autodata/test/helper.c
  8. 71
      ccan/ccan/autodata/test/run-fools.c
  9. 41
      ccan/ccan/autodata/test/run.c
  10. 1
      ccan/ccan/breakpoint/LICENSE
  11. 34
      ccan/ccan/breakpoint/_info
  12. 32
      ccan/ccan/breakpoint/breakpoint.c
  13. 24
      ccan/ccan/breakpoint/breakpoint.h
  14. 17
      ccan/ccan/breakpoint/test/run.c
  15. 2
      ccan/ccan/cppmagic/test/run.c
  16. 1
      ccan/ccan/crypto/hkdf_sha256/LICENSE
  17. 30
      ccan/ccan/crypto/hkdf_sha256/_info
  18. 97
      ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.c
  19. 22
      ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.h
  20. 101
      ccan/ccan/crypto/hkdf_sha256/test/api-rfc5869.c
  21. 1
      ccan/ccan/crypto/hmac_sha256/LICENSE
  22. 52
      ccan/ccan/crypto/hmac_sha256/_info
  23. 160
      ccan/ccan/crypto/hmac_sha256/hmac_sha256.c
  24. 86
      ccan/ccan/crypto/hmac_sha256/hmac_sha256.h
  25. 159
      ccan/ccan/crypto/hmac_sha256/test/api-rfc4231.c
  26. 9
      ccan/ccan/crypto/shachain/shachain.c
  27. 6
      ccan/ccan/crypto/shachain/shachain.h
  28. 39
      ccan/ccan/crypto/shachain/tools/Makefile
  29. 58
      ccan/ccan/crypto/shachain/tools/shachain48.c
  30. 1
      ccan/ccan/fdpass/LICENSE
  31. 65
      ccan/ccan/fdpass/_info
  32. 83
      ccan/ccan/fdpass/fdpass.c
  33. 23
      ccan/ccan/fdpass/fdpass.h
  34. 88
      ccan/ccan/fdpass/test/run.c
  35. 12
      ccan/ccan/io/backend.h
  36. 1
      ccan/ccan/io/fdpass/LICENSE
  37. 95
      ccan/ccan/io/fdpass/_info
  38. 54
      ccan/ccan/io/fdpass/fdpass.c
  39. 68
      ccan/ccan/io/fdpass/fdpass.h
  40. 51
      ccan/ccan/io/fdpass/test/run.c
  41. 119
      ccan/ccan/io/io.c
  42. 40
      ccan/ccan/io/io.h
  43. 60
      ccan/ccan/io/poll.c
  44. 2
      ccan/ccan/io/test/run-01-start-finish-debug.c
  45. 7
      ccan/ccan/io/test/run-01-start-finish.c
  46. 2
      ccan/ccan/io/test/run-02-read-debug.c
  47. 7
      ccan/ccan/io/test/run-02-read.c
  48. 2
      ccan/ccan/io/test/run-03-readpartial-debug.c
  49. 7
      ccan/ccan/io/test/run-03-readpartial.c
  50. 2
      ccan/ccan/io/test/run-04-writepartial-debug.c
  51. 7
      ccan/ccan/io/test/run-04-writepartial.c
  52. 2
      ccan/ccan/io/test/run-05-write-debug.c
  53. 7
      ccan/ccan/io/test/run-05-write.c
  54. 4
      ccan/ccan/io/test/run-06-idle.c
  55. 2
      ccan/ccan/io/test/run-07-break-debug.c
  56. 7
      ccan/ccan/io/test/run-07-break.c
  57. 2
      ccan/ccan/io/test/run-09-connect-debug.c
  58. 7
      ccan/ccan/io/test/run-09-connect.c
  59. 2
      ccan/ccan/io/test/run-12-bidir-debug.c
  60. 7
      ccan/ccan/io/test/run-12-bidir.c
  61. 2
      ccan/ccan/io/test/run-14-duplex-both-read-debug.c
  62. 7
      ccan/ccan/io/test/run-14-duplex-both-read.c
  63. 7
      ccan/ccan/io/test/run-15-timeout.c
  64. 2
      ccan/ccan/io/test/run-16-duplex-test-debug.c
  65. 7
      ccan/ccan/io/test/run-16-duplex-test.c
  66. 2
      ccan/ccan/io/test/run-17-homemade-io-debug.c
  67. 7
      ccan/ccan/io/test/run-17-homemade-io.c
  68. 2
      ccan/ccan/io/test/run-18-errno-debug.c
  69. 9
      ccan/ccan/io/test/run-18-errno.c
  70. 2
      ccan/ccan/io/test/run-19-always-debug.c
  71. 7
      ccan/ccan/io/test/run-19-always.c
  72. 1
      ccan/ccan/ptr_valid/LICENSE
  73. 29
      ccan/ccan/ptr_valid/_info
  74. 344
      ccan/ccan/ptr_valid/ptr_valid.c
  75. 229
      ccan/ccan/ptr_valid/ptr_valid.h
  76. 56
      ccan/ccan/ptr_valid/test/run-string.c
  77. 90
      ccan/ccan/ptr_valid/test/run.c
  78. 111
      ccan/ccan/tal/tal.c
  79. 61
      ccan/ccan/tal/tal.h
  80. 38
      ccan/ccan/tal/test/run-destructor2.c
  81. 5
      ccan/ccan/tal/test/run-free.c
  82. 2
      ccan/ccan/time/time.c
  83. 2
      ccan/ccan/time/time.h

27
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 $@ $<

2
ccan/README

@ -1,3 +1,3 @@
CCAN imported from http://ccodearchive.net.
CCAN version: init-2302-g6b74669
CCAN version: init-2338-g97ac583

1
ccan/ccan/autodata/LICENSE

@ -0,0 +1 @@
../../licenses/BSD-MIT

111
ccan/ccan/autodata/_info

@ -0,0 +1,111 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
/**
* 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 <ccan/autodata/autodata.h>
* #include <stdio.h>
* #include <unistd.h>
* #include <stdbool.h>
* #include <err.h>
*
* 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;
}

80
ccan/ccan/autodata/autodata.c

@ -0,0 +1,80 @@
// Licensed under BSD-MIT: See LICENSE.
#include "autodata.h"
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#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 <ccan/ptr_valid/ptr_valid.h>
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

109
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 <ccan/compiler/compiler.h>
#include <stdlib.h>
#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 <ccan/autodata/autodata.h>
*
* // 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 */

6
ccan/ccan/autodata/test/helper.c

@ -0,0 +1,6 @@
/* Check that linking together works. */
#include <ccan/autodata/autodata.h>
AUTODATA_TYPE(autostrings, char);
AUTODATA(autostrings, "helper");

71
ccan/ccan/autodata/test/run-fools.c

@ -0,0 +1,71 @@
#include <ccan/autodata/autodata.h>
/* Include the C files directly. */
#include <ccan/autodata/autodata.c>
#include <ccan/tap/tap.h>
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();
}

41
ccan/ccan/autodata/test/run.c

@ -0,0 +1,41 @@
#include <ccan/autodata/autodata.h>
/* Include the C files directly. */
#include <ccan/autodata/autodata.c>
#include <ccan/tap/tap.h>
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();
}

1
ccan/ccan/breakpoint/LICENSE

@ -0,0 +1 @@
../../licenses/CC0

34
ccan/ccan/breakpoint/_info

@ -0,0 +1,34 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
/**
* 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 <ccan/breakpoint/breakpoint.h>
*
* 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;
}

32
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 <ccan/breakpoint/breakpoint.h>
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;
}
}

24
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 <ccan/compiler/compiler.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdbool.h>
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 */

17
ccan/ccan/breakpoint/test/run.c

@ -0,0 +1,17 @@
#include <ccan/breakpoint/breakpoint.h>
#include <ccan/breakpoint/breakpoint.c>
#include <ccan/tap/tap.h>
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();
}

2
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) <<x>>

1
ccan/ccan/crypto/hkdf_sha256/LICENSE

@ -0,0 +1 @@
../../../licenses/BSD-MIT

30
ccan/ccan/crypto/hkdf_sha256/_info

@ -0,0 +1,30 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
/**
* crypto/hkdf_sha256 - RFC5869 Hardened Key Derivation Functions using SHA256
*
* This code implements the hkdf described in RFC5869.
*
* License: BSD-MIT
* Maintainer: Rusty Russell <rusty@rustcorp.com.au>
*/
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;
}

97
ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.c

@ -0,0 +1,97 @@
/* MIT (BSD) license - see LICENSE file for details */
#include <ccan/crypto/hkdf_sha256/hkdf_sha256.h>
#include <ccan/crypto/hmac_sha256/hmac_sha256.h>
#include <assert.h>
#include <string.h>
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);
}

22
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 <stdlib.h>
/**
* 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 */

101
ccan/ccan/crypto/hkdf_sha256/test/api-rfc5869.c

@ -0,0 +1,101 @@
/* From RFC5869 Appendix A
*
* https://tools.ietf.org/html/rfc5869
*/
#include <ccan/crypto/hkdf_sha256/hkdf_sha256.h>
#include <ccan/tap/tap.h>
#include <ccan/str/hex/hex.h>
#include <string.h>
#include <assert.h>
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();
}

1
ccan/ccan/crypto/hmac_sha256/LICENSE

@ -0,0 +1 @@
../../../licenses/BSD-MIT

52
ccan/ccan/crypto/hmac_sha256/_info

@ -0,0 +1,52 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
/**
* crypto/hmac_sha256 - RFC2104 HMAC using SHA256.
*
* This code implements RFC2104, which is a fairly standard HMAC.
*
* License: BSD-MIT
* Maintainer: Rusty Russell <rusty@rustcorp.com.au>
*
* Example:
* #include <ccan/crypto/hmac_sha256/hmac_sha256.h>
* #include <err.h>
* #include <stdio.h>
* #include <string.h>
*
* // 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 <string1> <string2>", 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;
}

160
ccan/ccan/crypto/hmac_sha256/hmac_sha256.c

@ -0,0 +1,160 @@
/* MIT (BSD) license - see LICENSE file for details */
#include <ccan/crypto/hmac_sha256/hmac_sha256.h>
#include <string.h>
#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

86
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 <stdint.h>
#include <stdlib.h>
#include <ccan/crypto/sha256/sha256.h>
/* 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 */

159
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 <ccan/crypto/hmac_sha256/hmac_sha256.h>
#include <ccan/tap/tap.h>
#include <ccan/str/hex/hex.h>
#include <string.h>
#include <assert.h>
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();
}

9
ccan/ccan/crypto/shachain/shachain.c

@ -5,8 +5,6 @@
#include <string.h>
#include <assert.h>
#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);

6
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];
};
/**

39
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 $@ $<

58
ccan/ccan/crypto/shachain/tools/shachain48.c

@ -0,0 +1,58 @@
#include <ccan/crypto/shachain/shachain.h>
#include <ccan/str/hex/hex.h>
#include <ccan/str/str.h>
#include <ccan/err/err.h>
#include <ccan/rbuf/rbuf.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
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 <seed> <index>");
return 0;
}

1
ccan/ccan/fdpass/LICENSE

@ -0,0 +1 @@
../../licenses/CC0

65
ccan/ccan/fdpass/_info

@ -0,0 +1,65 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
/**
* 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 <rusty@rustcorp.com.au>
*
* Example:
* // Outputs hello!
* #include <ccan/fdpass/fdpass.h>
* #include <sys/socket.h>
* #include <sys/un.h>
* #include <stdio.h>
* #include <stdlib.h>
* #include <unistd.h>
*
* 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;
}

83
ccan/ccan/fdpass/fdpass.c

@ -0,0 +1,83 @@
/* CC0 license (public domain) - see LICENSE file for details */
#include <ccan/fdpass/fdpass.h>
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
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;
}

23
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 <stdbool.h>
/**
* 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 */

88
ccan/ccan/fdpass/test/run.c

@ -0,0 +1,88 @@
#include <ccan/fdpass/fdpass.h>
/* Include the C files directly. */
#include <ccan/fdpass/fdpass.c>
#include <ccan/tap/tap.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
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();
}

12
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);

1
ccan/ccan/io/fdpass/LICENSE

@ -0,0 +1 @@
../../../licenses/LGPL-2.1

95
ccan/ccan/io/fdpass/_info

@ -0,0 +1,95 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
/**
* 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 <rusty@rustcorp.com.au>
*
* Example:
* // Given "hello" outputs hello
* #include <ccan/io/fdpass/fdpass.h>
* #include <sys/types.h>
* #include <sys/socket.h>
* #include <sys/un.h>
* #include <stdio.h>
* #include <stdlib.h>
* #include <unistd.h>
*
* // 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;
}

54
ccan/ccan/io/fdpass/fdpass.c

@ -0,0 +1,54 @@
/* GNU LGPL version 2 (or later) - see LICENSE file for details */
#include <ccan/io/fdpass/fdpass.h>
#include <ccan/fdpass/fdpass.h>
#include <ccan/io/io_plan.h>
#include <errno.h>
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);
}

68
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 <ccan/io/io.h>
/**
* 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 */

51
ccan/ccan/io/fdpass/test/run.c

@ -0,0 +1,51 @@
#include <ccan/io/fdpass/fdpass.h>
/* Include the C files directly. */
#include <ccan/io/fdpass/fdpass.c>
#include <ccan/tap/tap.h>
#include <sys/types.h>
#include <sys/socket.h>
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();
}

119
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)
{
}

40
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 */

60
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;

2
ccan/ccan/io/test/run-01-start-finish-debug.c

@ -1,2 +0,0 @@
#define DEBUG_CONN
#include "run-01-start-finish.c"

7
ccan/ccan/io/test/run-01-start-finish.c

@ -6,11 +6,7 @@
#include <sys/wait.h>
#include <stdio.h>
#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);

2
ccan/ccan/io/test/run-02-read-debug.c

@ -1,2 +0,0 @@
#define DEBUG_CONN
#include "run-02-read.c"

7
ccan/ccan/io/test/run-02-read.c

@ -6,11 +6,7 @@
#include <sys/wait.h>
#include <stdio.h>
#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++;

2
ccan/ccan/io/test/run-03-readpartial-debug.c

@ -1,2 +0,0 @@
#define DEBUG_CONN
#include "run-03-readpartial.c"

7
ccan/ccan/io/test/run-03-readpartial.c

@ -6,11 +6,7 @@
#include <sys/wait.h>
#include <stdio.h>
#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++;

2
ccan/ccan/io/test/run-04-writepartial-debug.c

@ -1,2 +0,0 @@
#define DEBUG_CONN
#include "run-04-writepartial.c"

7
ccan/ccan/io/test/run-04-writepartial.c

@ -6,11 +6,7 @@
#include <sys/wait.h>
#include <stdio.h>
#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);

2
ccan/ccan/io/test/run-05-write-debug.c

@ -1,2 +0,0 @@
#define DEBUG_CONN
#include "run-05-write.c"

7
ccan/ccan/io/test/run-05-write.c

@ -6,11 +6,7 @@
#include <sys/wait.h>
#include <stdio.h>
#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);

4
ccan/ccan/io/test/run-06-idle.c

@ -9,11 +9,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#ifdef DEBUG_CONN
#define PORT "64006"
#else
#define PORT "65006"
#endif
static struct io_conn *idler;

2
ccan/ccan/io/test/run-07-break-debug.c

@ -1,2 +0,0 @@
#define DEBUG_CONN
#include "run-07-break.c"

7
ccan/ccan/io/test/run-07-break.c

@ -6,11 +6,7 @@
#include <sys/wait.h>
#include <stdio.h>
#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++;

2
ccan/ccan/io/test/run-09-connect-debug.c

@ -1,2 +0,0 @@
#define DEBUG_CONN
#include "run-09-connect.c"

7
ccan/ccan/io/test/run-09-connect.c

@ -6,11 +6,7 @@
#include <sys/wait.h>
#include <stdio.h>
#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);

2
ccan/ccan/io/test/run-12-bidir-debug.c

@ -1,2 +0,0 @@
#define DEBUG_CONN
#include "run-12-bidir.c"

7
ccan/ccan/io/test/run-12-bidir.c

@ -6,11 +6,7 @@
#include <sys/wait.h>
#include <stdio.h>
#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++;

2
ccan/ccan/io/test/run-14-duplex-both-read-debug.c

@ -1,2 +0,0 @@
#define DEBUG_CONN
#include "run-14-duplex-both-read.c"

7
ccan/ccan/io/test/run-14-duplex-both-read.c

@ -8,11 +8,7 @@
#include <sys/wait.h>
#include <stdio.h>
#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++;

7
ccan/ccan/io/test/run-15-timeout.c

@ -8,11 +8,7 @@
#include <stdio.h>
#include <unistd.h>
#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++;

2
ccan/ccan/io/test/run-16-duplex-test-debug.c

@ -1,2 +0,0 @@
#define DEBUG_CONN
#include "run-16-duplex-test.c"

7
ccan/ccan/io/test/run-16-duplex-test.c

@ -8,11 +8,7 @@
#include <sys/wait.h>
#include <stdio.h>
#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++;

2
ccan/ccan/io/test/run-17-homemade-io-debug.c

@ -1,2 +0,0 @@
#define DEBUG_CONN
#include "run-17-homemade-io.c"

7
ccan/ccan/io/test/run-17-homemade-io.c

@ -6,11 +6,7 @@
#include <sys/wait.h>
#include <stdio.h>
#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++;

2
ccan/ccan/io/test/run-18-errno-debug.c

@ -1,2 +0,0 @@
#define DEBUG_CONN
#include "run-18-errno.c"

9
ccan/ccan/io/test/run-18-errno.c

@ -6,11 +6,7 @@
#include <sys/wait.h>
#include <stdio.h>
#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);

2
ccan/ccan/io/test/run-19-always-debug.c

@ -1,2 +0,0 @@
#define DEBUG_CONN
#include "run-19-always.c"

7
ccan/ccan/io/test/run-19-always.c

@ -6,11 +6,7 @@
#include <sys/wait.h>
#include <stdio.h>
#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);

1
ccan/ccan/ptr_valid/LICENSE

@ -0,0 +1 @@
../../licenses/BSD-MIT

29
ccan/ccan/ptr_valid/_info

@ -0,0 +1,29 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
/**
* 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;
}

344
ccan/ccan/ptr_valid/ptr_valid.c

@ -0,0 +1,344 @@
// Licensed under BSD-MIT: See LICENSE.
#include "ptr_valid.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ccan/noerr/noerr.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#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 '<start-in-hex>-<end-in-hex> 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);
}

229
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 <stdbool.h>
#include <stdlib.h>
/**
* 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 */

56
ccan/ccan/ptr_valid/test/run-string.c

@ -0,0 +1,56 @@
#include <ccan/ptr_valid/ptr_valid.h>
/* Include the C files directly. */
#include <ccan/ptr_valid/ptr_valid.c>
#include <ccan/tap/tap.h>
#include <sys/mman.h>
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();
}

90
ccan/ccan/ptr_valid/test/run.c

@ -0,0 +1,90 @@
#include <ccan/ptr_valid/ptr_valid.h>
/* Include the C files directly. */
#include <ccan/ptr_valid/ptr_valid.c>
#include <ccan/tap/tap.h>
#include <sys/mman.h>
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();
}

111
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;
}

61
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 */

38
ccan/ccan/tal/test/run-destructor2.c

@ -0,0 +1,38 @@
#include <ccan/tal/tal.h>
#include <ccan/tal/tal.c>
#include <ccan/tap/tap.h>
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();
}

5
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;

2
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;

2
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);

Loading…
Cancel
Save