avoid generating logging helper functions if !PTLS_HAVE_LOG
diff --git a/include/picotls.h b/include/picotls.h index 61b5198..2aaa7e3 100644 --- a/include/picotls.h +++ b/include/picotls.h
@@ -1963,11 +1963,13 @@ inline uint32_t ptls_log_point_maybe_active(struct st_ptls_log_point_t *point) { - if (!PTLS_HAVE_LOG) - return 0; +#if PTLS_HAVE_LOG if (PTLS_UNLIKELY(point->state.generation != ptls_log._generation)) ptls_log__recalc_point(0, point); return point->state.active_conns; +#else + return 0; +#endif } inline void ptls_log_recalc_conn_state(ptls_log_conn_state_t *state) @@ -1977,11 +1979,13 @@ inline uint32_t ptls_log_conn_maybe_active(ptls_log_conn_state_t *conn, const char *(*get_sni)(void *), void *get_sni_arg) { - if (!PTLS_HAVE_LOG) - return 0; +#if PTLS_HAVE_LOG if (PTLS_UNLIKELY(conn->state.generation != ptls_log._generation)) ptls_log__recalc_conn(0, conn, get_sni, get_sni_arg); return conn->state.active_conns; +#else + return 0; +#endif } inline ptls_t *ptls_new(ptls_context_t *ctx, int is_server)
diff --git a/lib/picotls.c b/lib/picotls.c index 7c1030a..23639be 100644 --- a/lib/picotls.c +++ b/lib/picotls.c
@@ -6775,6 +6775,58 @@ memcpy(&v6->s6_addr[12], &v4->s_addr, 4); } +struct st_ptls_log_t ptls_log = { + .dummy_conn_state = {.random_ = 1 /* never log */}, + ._generation = 1, /* starts from 1 so that recalc can be forced by setting to zero (i.e., the initial) */ +}; +PTLS_THREADLOCAL ptls_log_conn_state_t *ptls_log_conn_state_override = NULL; + +#if PTLS_HAVE_LOG + +static struct { + /** + * list of connections; the slot is connected if points != NULL + */ + struct { + /** + * file descriptor + */ + int fd; + /** + * see `ptls_log_add_fd` + */ + char *points; + /** + * + */ + char *snis; + /** + * list of addresses terminated by ip6addr_any + */ + struct in6_addr *addresses; + /** + * + */ + float sample_ratio; + /** + * + */ + unsigned appdata : 1; + } conns[sizeof(((struct st_ptls_log_state_t *)NULL)->active_conns) * 8]; + /** + * counts the number of writes that failed + */ + size_t num_lost; + /** + * anchor of the single-linked list of log points; the tail refers to itself (i.e., point->next == point) + */ + struct st_ptls_log_point_t *points; + /** + * + */ + pthread_mutex_t mutex; +} logctx = {.mutex = PTHREAD_MUTEX_INITIALIZER}; + static PTLS_THREADLOCAL struct { ptls_buffer_t buf; /* buf.base == NULL upon failre */ char smallbuf[128]; @@ -6784,6 +6836,117 @@ } tid; } ptlslogbuf; +static void close_log_fd(size_t slot) +{ + assert(logctx.conns[slot].fd >= 0 && logctx.conns[slot].points != NULL); + + close(logctx.conns[slot].fd); + + /* clear the connection information */ + logctx.conns[slot].fd = -1; + logctx.conns[slot].sample_ratio = 0; + free(logctx.conns[slot].points); + logctx.conns[slot].points = NULL; + free(logctx.conns[slot].snis); + logctx.conns[slot].snis = NULL; + free(logctx.conns[slot].addresses); + logctx.conns[slot].addresses = NULL; + logctx.conns[slot].appdata = 0; + ++ptls_log._generation; +} + +static char *duplicate_stringlist(const char *input) +{ + if (input == NULL) + return strdup(""); + + char *result; + const char *in_tail; + + for (in_tail = input; in_tail[0] != '\0'; in_tail += strlen(in_tail) + 1) + ; + ++in_tail; + if ((result = malloc(in_tail - input)) == NULL) + return NULL; + memcpy(result, input, in_tail - input); + return result; +} + +static int is_in_stringlist(const char *list, const char *search_for) +{ + if (list[0] == '\0') + return 1; + + if (search_for == NULL) + return 0; + + for (const char *element = list; element[0] != '\0'; element += strlen(element) + 1) + if (strcmp(element, search_for) == 0) + return 1; + return 0; +} + +static int is_in_addresslist(const struct in6_addr *list, const struct in6_addr *search_for) +{ +#define IS_EQUAL(x, y) (memcmp((x), (y), sizeof(struct in6_addr)) == 0) + + if (IS_EQUAL(&list[0], &in6addr_any)) + return 1; + + if (IS_EQUAL(search_for, &in6addr_any)) + return 0; + + for (const struct in6_addr *element = list; !IS_EQUAL(element, &in6addr_any); ++element) + if (IS_EQUAL(element, search_for)) + return 1; + return 0; + +#undef IS_EQUAL +} + +void ptls_log__recalc_point(int caller_locked, struct st_ptls_log_point_t *point) +{ + if (!caller_locked) + pthread_mutex_lock(&logctx.mutex); + + if (point->state.generation != ptls_log._generation) { + /* update active bitmap */ + uint32_t new_active = 0; + for (size_t slot = 0; slot < PTLS_ELEMENTSOF(logctx.conns); ++slot) + if (logctx.conns[slot].points != NULL && is_in_stringlist(logctx.conns[slot].points, point->name)) + new_active |= (uint32_t)1 << slot; + point->state.active_conns = new_active; + point->state.generation = ptls_log._generation; + } + + if (!caller_locked) + pthread_mutex_unlock(&logctx.mutex); +} + +void ptls_log__recalc_conn(int caller_locked, struct st_ptls_log_conn_state_t *conn, const char *(*get_sni)(void *), + void *get_sni_arg) +{ + if (!caller_locked) + pthread_mutex_lock(&logctx.mutex); + + if (conn->state.generation != ptls_log._generation) { + /* update active bitmap */ + uint32_t new_active = 0; + const char *sni = get_sni != NULL ? get_sni(get_sni_arg) : NULL; + for (size_t slot = 0; slot < PTLS_ELEMENTSOF(logctx.conns); ++slot) { + if (logctx.conns[slot].points != NULL && conn->random_ < logctx.conns[slot].sample_ratio && + is_in_stringlist(logctx.conns[slot].snis, sni) && is_in_addresslist(logctx.conns[slot].addresses, &conn->address)) { + new_active |= (uint32_t)1 << slot; + } + } + conn->state.active_conns = new_active; + conn->state.generation = ptls_log._generation; + } + + if (!caller_locked) + pthread_mutex_unlock(&logctx.mutex); +} + static int expand_logbuf_or_invalidate(const char *prefix, size_t prefix_len, size_t capacity) { if (ptlslogbuf.buf.base == NULL) @@ -6881,275 +7044,6 @@ } } -struct st_ptls_log_t ptls_log = { - .dummy_conn_state = {.random_ = 1 /* never log */}, - ._generation = 1, /* starts from 1 so that recalc can be forced by setting to zero (i.e., the initial) */ -}; -PTLS_THREADLOCAL ptls_log_conn_state_t *ptls_log_conn_state_override = NULL; - -#if PTLS_HAVE_LOG - -static struct { - /** - * list of connections; the slot is connected if points != NULL - */ - struct { - /** - * file descriptor - */ - int fd; - /** - * see `ptls_log_add_fd` - */ - char *points; - /** - * - */ - char *snis; - /** - * list of addresses terminated by ip6addr_any - */ - struct in6_addr *addresses; - /** - * - */ - float sample_ratio; - /** - * - */ - unsigned appdata : 1; - } conns[sizeof(((struct st_ptls_log_state_t *)NULL)->active_conns) * 8]; - /** - * counts the number of writes that failed - */ - size_t num_lost; - /** - * anchor of the single-linked list of log points; the tail refers to itself (i.e., point->next == point) - */ - struct st_ptls_log_point_t *points; - /** - * - */ - pthread_mutex_t mutex; -} logctx = {.mutex = PTHREAD_MUTEX_INITIALIZER}; - -static void close_log_fd(size_t slot) -{ - assert(logctx.conns[slot].fd >= 0 && logctx.conns[slot].points != NULL); - - close(logctx.conns[slot].fd); - - /* clear the connection information */ - logctx.conns[slot].fd = -1; - logctx.conns[slot].sample_ratio = 0; - free(logctx.conns[slot].points); - logctx.conns[slot].points = NULL; - free(logctx.conns[slot].snis); - logctx.conns[slot].snis = NULL; - free(logctx.conns[slot].addresses); - logctx.conns[slot].addresses = NULL; - logctx.conns[slot].appdata = 0; - ++ptls_log._generation; -} - -static char *duplicate_stringlist(const char *input) -{ - if (input == NULL) - return strdup(""); - - char *result; - const char *in_tail; - - for (in_tail = input; in_tail[0] != '\0'; in_tail += strlen(in_tail) + 1) - ; - ++in_tail; - if ((result = malloc(in_tail - input)) == NULL) - return NULL; - memcpy(result, input, in_tail - input); - return result; -} - -static int is_in_stringlist(const char *list, const char *search_for) -{ - if (list[0] == '\0') - return 1; - - if (search_for == NULL) - return 0; - - for (const char *element = list; element[0] != '\0'; element += strlen(element) + 1) - if (strcmp(element, search_for) == 0) - return 1; - return 0; -} - -static int is_in_addresslist(const struct in6_addr *list, const struct in6_addr *search_for) -{ -#define IS_EQUAL(x, y) (memcmp((x), (y), sizeof(struct in6_addr)) == 0) - - if (IS_EQUAL(&list[0], &in6addr_any)) - return 1; - - if (IS_EQUAL(search_for, &in6addr_any)) - return 0; - - for (const struct in6_addr *element = list; !IS_EQUAL(element, &in6addr_any); ++element) - if (IS_EQUAL(element, search_for)) - return 1; - return 0; - -#undef IS_EQUAL -} - -#endif - -void ptls_log_init_conn_state(ptls_log_conn_state_t *state, void (*random_bytes)(void *, size_t)) -{ - uint32_t r; - random_bytes(&r, sizeof(r)); - - *state = (ptls_log_conn_state_t){ - .random_ = (float)r / ((uint64_t)UINT32_MAX + 1), /* [0..1), so that any(r) < sample_ratio where sample_ratio is [0..1] */ - .address = in6addr_any, - }; -} - -size_t ptls_log_num_lost(void) -{ -#if PTLS_HAVE_LOG - return logctx.num_lost; -#else - return 0; -#endif -} - -void ptls_log__recalc_point(int caller_locked, struct st_ptls_log_point_t *point) -{ -#if PTLS_HAVE_LOG - if (!caller_locked) - pthread_mutex_lock(&logctx.mutex); - - if (point->state.generation != ptls_log._generation) { - /* update active bitmap */ - uint32_t new_active = 0; - for (size_t slot = 0; slot < PTLS_ELEMENTSOF(logctx.conns); ++slot) - if (logctx.conns[slot].points != NULL && is_in_stringlist(logctx.conns[slot].points, point->name)) - new_active |= (uint32_t)1 << slot; - point->state.active_conns = new_active; - point->state.generation = ptls_log._generation; - } - - if (!caller_locked) - pthread_mutex_unlock(&logctx.mutex); -#endif -} - -void ptls_log__recalc_conn(int caller_locked, struct st_ptls_log_conn_state_t *conn, const char *(*get_sni)(void *), - void *get_sni_arg) -{ -#if PTLS_HAVE_LOG - if (!caller_locked) - pthread_mutex_lock(&logctx.mutex); - - if (conn->state.generation != ptls_log._generation) { - /* update active bitmap */ - uint32_t new_active = 0; - const char *sni = get_sni != NULL ? get_sni(get_sni_arg) : NULL; - for (size_t slot = 0; slot < PTLS_ELEMENTSOF(logctx.conns); ++slot) { - if (logctx.conns[slot].points != NULL && conn->random_ < logctx.conns[slot].sample_ratio && - is_in_stringlist(logctx.conns[slot].snis, sni) && is_in_addresslist(logctx.conns[slot].addresses, &conn->address)) { - new_active |= (uint32_t)1 << slot; - } - } - conn->state.active_conns = new_active; - conn->state.generation = ptls_log._generation; - } - - if (!caller_locked) - pthread_mutex_unlock(&logctx.mutex); -#endif -} - -int ptls_log_add_fd(int fd, float sample_ratio, const char *_points, const char *_snis, const char *_addresses, int appdata) -{ -#if PTLS_HAVE_LOG - - char *points = NULL, *snis = NULL; - struct in6_addr *addresses = NULL; - int ret; - - pthread_mutex_lock(&logctx.mutex); - - if ((points = duplicate_stringlist(_points)) == NULL) { - ret = PTLS_ERROR_NO_MEMORY; - goto Exit; - } - if ((snis = duplicate_stringlist(_snis)) == NULL) { - ret = PTLS_ERROR_NO_MEMORY; - goto Exit; - } - { - size_t num_addresses = 0; - for (const char *input = _addresses; input != NULL && *input != '\0'; input += strlen(input) + 1) - ++num_addresses; - if ((addresses = malloc(sizeof(*addresses) * (num_addresses + 1))) == NULL) { - ret = PTLS_ERROR_NO_MEMORY; - goto Exit; - } - size_t index = 0; - for (const char *input = _addresses; input != NULL && *input != '\0'; input += strlen(input) + 1) { - /* note: for consistency to the handling of points, erroneous input is ignored. V4 addresses will use the mapped form - * (::ffff:192.0.2.1) */ - if (!inet_pton(AF_INET6, input, &addresses[index])) { - struct in_addr v4; - if (!inet_pton(AF_INET, input, &v4)) - continue; - ptls_build_v4_mapped_v6_address(&addresses[index], &v4); - } - if (memcmp(&addresses[index], &in6addr_any, sizeof(struct in6_addr)) == 0) - continue; - ++index; - } - addresses[index] = in6addr_any; - } - - /* find slot, or return if not available */ - size_t slot_index; - for (slot_index = 0; slot_index < PTLS_ELEMENTSOF(logctx.conns); ++slot_index) - if (logctx.conns[slot_index].points == NULL) - break; - if (slot_index == PTLS_ELEMENTSOF(logctx.conns)) { - ret = PTLS_ERROR_NO_MEMORY; - goto Exit; - } - - /* setup the slot */ - logctx.conns[slot_index].fd = fd; - logctx.conns[slot_index].points = points; - logctx.conns[slot_index].snis = snis; - logctx.conns[slot_index].addresses = addresses; - logctx.conns[slot_index].sample_ratio = sample_ratio; - logctx.conns[slot_index].appdata = appdata; - ++ptls_log._generation; - - ret = 0; /* success */ - -Exit: - pthread_mutex_unlock(&logctx.mutex); - if (ret != 0) { - free(points); - free(snis); - free(addresses); - } - return ret; - -#else - return PTLS_ERROR_NOT_AVAILABLE; -#endif -} - -#if PTLS_HAVE_LOG - void ptls_log__do_write_start(struct st_ptls_log_point_t *point, int add_time) { assert(ptlslogbuf.buf.base == NULL); @@ -7249,3 +7143,101 @@ } #endif + +void ptls_log_init_conn_state(ptls_log_conn_state_t *state, void (*random_bytes)(void *, size_t)) +{ + uint32_t r; + random_bytes(&r, sizeof(r)); + + *state = (ptls_log_conn_state_t){ + .random_ = (float)r / ((uint64_t)UINT32_MAX + 1), /* [0..1), so that any(r) < sample_ratio where sample_ratio is [0..1] */ + .address = in6addr_any, + }; +} + +size_t ptls_log_num_lost(void) +{ +#if PTLS_HAVE_LOG + return logctx.num_lost; +#else + return 0; +#endif +} + +int ptls_log_add_fd(int fd, float sample_ratio, const char *_points, const char *_snis, const char *_addresses, int appdata) +{ +#if PTLS_HAVE_LOG + + char *points = NULL, *snis = NULL; + struct in6_addr *addresses = NULL; + int ret; + + pthread_mutex_lock(&logctx.mutex); + + if ((points = duplicate_stringlist(_points)) == NULL) { + ret = PTLS_ERROR_NO_MEMORY; + goto Exit; + } + if ((snis = duplicate_stringlist(_snis)) == NULL) { + ret = PTLS_ERROR_NO_MEMORY; + goto Exit; + } + { + size_t num_addresses = 0; + for (const char *input = _addresses; input != NULL && *input != '\0'; input += strlen(input) + 1) + ++num_addresses; + if ((addresses = malloc(sizeof(*addresses) * (num_addresses + 1))) == NULL) { + ret = PTLS_ERROR_NO_MEMORY; + goto Exit; + } + size_t index = 0; + for (const char *input = _addresses; input != NULL && *input != '\0'; input += strlen(input) + 1) { + /* note: for consistency to the handling of points, erroneous input is ignored. V4 addresses will use the mapped form + * (::ffff:192.0.2.1) */ + if (!inet_pton(AF_INET6, input, &addresses[index])) { + struct in_addr v4; + if (!inet_pton(AF_INET, input, &v4)) + continue; + ptls_build_v4_mapped_v6_address(&addresses[index], &v4); + } + if (memcmp(&addresses[index], &in6addr_any, sizeof(struct in6_addr)) == 0) + continue; + ++index; + } + addresses[index] = in6addr_any; + } + + /* find slot, or return if not available */ + size_t slot_index; + for (slot_index = 0; slot_index < PTLS_ELEMENTSOF(logctx.conns); ++slot_index) + if (logctx.conns[slot_index].points == NULL) + break; + if (slot_index == PTLS_ELEMENTSOF(logctx.conns)) { + ret = PTLS_ERROR_NO_MEMORY; + goto Exit; + } + + /* setup the slot */ + logctx.conns[slot_index].fd = fd; + logctx.conns[slot_index].points = points; + logctx.conns[slot_index].snis = snis; + logctx.conns[slot_index].addresses = addresses; + logctx.conns[slot_index].sample_ratio = sample_ratio; + logctx.conns[slot_index].appdata = appdata; + ++ptls_log._generation; + + ret = 0; /* success */ + +Exit: + pthread_mutex_unlock(&logctx.mutex); + if (ret != 0) { + free(points); + free(snis); + free(addresses); + } + return ret; + +#else + return PTLS_ERROR_NOT_AVAILABLE; +#endif +}