return 0;
}
+int json_dispatch_in6_addr(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
+ struct in6_addr *address = ASSERT_PTR(userdata);
+ _cleanup_(iovec_done) struct iovec iov = {};
+ int r;
+
+ if (sd_json_variant_is_null(variant)) {
+ *address = (struct in6_addr) {};
+ return 0;
+ }
+
+ /* We support both a more human readable string based encoding and an array based encoding */
+ if (sd_json_variant_is_string(variant)) {
+ union in_addr_union a;
+ r = in_addr_from_string(AF_INET6, sd_json_variant_string(variant), &a);
+ if (r < 0)
+ return json_log(variant, flags, r,
+ "JSON field '%s' is not a valid IPv6 address string: %s", strna(name), sd_json_variant_string(variant));
+
+ *address = a.in6;
+ return 0;
+ }
+
+ r = json_dispatch_byte_array_iovec(name, variant, flags, &iov);
+ if (r < 0)
+ return r;
+
+ if (iov.iov_len != sizeof(struct in6_addr))
+ return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL),
+ "Expected JSON field '%s' to be an array of %zu bytes.", strna(name), sizeof(struct in6_addr));
+
+ memcpy(address, iov.iov_base, iov.iov_len);
+ return 0;
+}
+
int json_dispatch_const_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
const char **p = ASSERT_PTR(userdata), *path;
int json_dispatch_const_user_group_name(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
int json_dispatch_const_unit_name(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
int json_dispatch_in_addr(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
+int json_dispatch_in6_addr(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
int json_dispatch_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
int json_dispatch_const_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
int json_dispatch_strv_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
&dummy), EINVAL);
}
+TEST(json_dispatch_in6_addr) {
+ _cleanup_(sd_json_variant_unrefp) sd_json_variant *j = NULL;
+
+ /* ::1 */
+ ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
+ SD_JSON_BUILD_PAIR("addr", JSON_BUILD_IN6_ADDR(&(const struct in6_addr) { .s6_addr = { [15] = 1 } })),
+ SD_JSON_BUILD_PAIR("null_addr", SD_JSON_BUILD_NULL))));
+
+ struct {
+ struct in6_addr addr;
+ struct in6_addr null_addr;
+ } data = {};
+
+ ASSERT_OK(sd_json_dispatch(j,
+ (const sd_json_dispatch_field[]) {
+ { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in6_addr, offsetof(typeof(data), addr) },
+ { "null_addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in6_addr, offsetof(typeof(data), null_addr) },
+ {},
+ },
+ /* flags= */ 0,
+ &data));
+
+ ASSERT_EQ(data.addr.s6_addr[15], 1);
+ for (size_t i = 0; i < 15; i++)
+ ASSERT_EQ(data.addr.s6_addr[i], 0);
+ for (size_t i = 0; i < 16; i++)
+ ASSERT_EQ(data.null_addr.s6_addr[i], 0);
+
+ struct in6_addr dummy = {};
+
+ /* Too few bytes (15 instead of 16) */
+ j = sd_json_variant_unref(j);
+ ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
+ SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_ARRAY(
+ SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
+ SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
+ SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
+ SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(1))))));
+ ASSERT_ERROR(sd_json_dispatch(j,
+ (const sd_json_dispatch_field[]) {
+ { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in6_addr, 0 },
+ {},
+ },
+ /* flags= */ 0,
+ &dummy), EINVAL);
+
+ /* Too many bytes (17 instead of 16) */
+ j = sd_json_variant_unref(j);
+ ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
+ SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_ARRAY(
+ SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
+ SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
+ SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
+ SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(1),
+ SD_JSON_BUILD_UNSIGNED(0))))));
+ ASSERT_ERROR(sd_json_dispatch(j,
+ (const sd_json_dispatch_field[]) {
+ { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in6_addr, 0 },
+ {},
+ },
+ /* flags= */ 0,
+ &dummy), EINVAL);
+
+ /* Not an array */
+ j = sd_json_variant_unref(j);
+ ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
+ SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_BOOLEAN(true)))));
+ ASSERT_ERROR(sd_json_dispatch(j,
+ (const sd_json_dispatch_field[]) {
+ { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in6_addr, 0 },
+ {},
+ },
+ /* flags= */ 0,
+ &dummy), EINVAL);
+
+ /* A string */
+ j = sd_json_variant_unref(j);
+ ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
+ SD_JSON_BUILD_PAIR("addr", JSON_BUILD_CONST_STRING("::1")))));
+
+ zero(data);
+ ASSERT_OK(sd_json_dispatch(j,
+ (const sd_json_dispatch_field[]) {
+ { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in6_addr, 0 },
+ {},
+ },
+ /* flags= */ 0,
+ &data));
+
+ ASSERT_EQ(data.addr.s6_addr[15], 1);
+ for (size_t i = 0; i < 15; i++)
+ ASSERT_EQ(data.addr.s6_addr[i], 0);
+}
+
DEFINE_TEST_MAIN(LOG_DEBUG);