~donmcc/ood

129d2e05738bfa24ed1164dcaa2926e7ed1c0e4e — Don McCaughey 10 months ago ffe8c6c
Add `sa_len()` function.

Socket functions like `bind()` and `connect()` take a `sockaddr` pointer
and the corresponding length of the given struct.  The `sa_len()`
function returns the correct length of the active union field in an
`sa_address` struct.

Some renames in test for consistency.
3 files changed, 99 insertions(+), 17 deletions(-)

M src/sa/sa.c
M src/sa/sa.h
M src/sa/sa_tests.c
M src/sa/sa.c => src/sa/sa.c +15 -1
@@ 104,13 104,27 @@ sa_alloc_from_sockaddr_un(struct sockaddr_un const *local_address)
}


socklen_t
sa_len(struct sa_address const *address)
{
    switch (address->generic.sa_family) {
        case AF_UNSPEC: return sizeof(struct sockaddr_storage);
        case AF_UNIX: return sizeof(struct sockaddr_un);
        case AF_INET: return sizeof(struct sockaddr_in);
        case AF_INET6: return sizeof(struct sockaddr_in6);
        default: return sizeof(struct sockaddr_storage);
    }
    return 0;
}


char const *
sa_str(struct sa_address const *address)
{
    switch (address->generic.sa_family) {
        case AF_UNSPEC: return "(unspecified)";
        case AF_INET: return address->ipv4_string;
        case AF_UNIX: return address->local.sun_path;
        case AF_INET: return address->ipv4_string;
        case AF_INET6: return address->ipv6_string;
        default: return "(unsupported)";
    }

M src/sa/sa.h => src/sa/sa.h +3 -0
@@ 60,6 60,9 @@ sa_alloc_from_path(char const *path);
struct sa_address *
sa_alloc_from_sockaddr_un(struct sockaddr_un const *local_address);

socklen_t
sa_len(struct sa_address const *address);

char const *
sa_str(struct sa_address const *address);


M src/sa/sa_tests.c => src/sa/sa_tests.c +81 -16
@@ 9,7 9,7 @@


static void
test_sa_alloc_from_address_and_port(void)
test_sa_alloc_from_ipv4_address_and_port(void)
{
    struct sa_address *address = sa_alloc_from_ipv4_address_and_port(INADDR_LOOPBACK, 8080);



@@ 30,7 30,7 @@ test_sa_alloc_from_address_and_port(void)
static void
test_sa_alloc_from_sockaddr_in(void)
{
    struct sockaddr_in inet = {
    struct sockaddr_in ipv4 = {
            .sin_family=AF_INET,
            .sin_addr=(struct in_addr){
                    .s_addr=htonl(INADDR_LOOPBACK)


@@ 38,7 38,7 @@ test_sa_alloc_from_sockaddr_in(void)
            .sin_port=htons(8080),
    };

    struct sa_address *address = sa_alloc_from_sockaddr_in(&inet);
    struct sa_address *address = sa_alloc_from_sockaddr_in(&ipv4);

    assert(address);
    assert(AF_INET == address->generic.sa_family);


@@ 76,13 76,13 @@ test_sa_alloc_from_ipv6_address_and_port(void)
static void
test_sa_alloc_from_sockaddr_in6(void)
{
    struct sockaddr_in6 inet6 = {
    struct sockaddr_in6 ipv6 = {
            .sin6_family=AF_INET6,
            .sin6_addr=in6addr_loopback,
            .sin6_port=htons(8080),
    };

    struct sa_address *address = sa_alloc_from_sockaddr_in6(&inet6);
    struct sa_address *address = sa_alloc_from_sockaddr_in6(&ipv6);

    assert(address);
    assert(AF_INET6 == address->generic.sa_family);


@@ 140,12 140,12 @@ test_sa_alloc_from_path_when_too_long(void)
static void
test_sa_alloc_from_sockaddr_un(void)
{
    struct sockaddr_un local_address = {
    struct sockaddr_un local = {
            .sun_family = AF_UNIX,
            .sun_path = "/var/dood/http",
    };

    struct sa_address *address = sa_alloc_from_sockaddr_un(&local_address);
    struct sa_address *address = sa_alloc_from_sockaddr_un(&local);

    assert(address);
    assert(AF_UNIX == address->generic.sa_family);


@@ 161,35 161,94 @@ test_sa_alloc_from_sockaddr_un(void)


static void
test_sa_str_for_unspecified_family(void)
test_sa_len_for_unspecified(void)
{
    struct sa_address generic_address = {
    struct sa_address address = {
            .generic = {
                    .sa_family = AF_UNSPEC,
            }
    };

    assert(STR_EQ("(unspecified)", sa_str(&generic_address)));
    assert(sizeof(struct sockaddr_storage) == sa_len(&address));
}


static void
test_sa_str_for_unsupported_family(void)
test_sa_len_for_ipv4(void)
{
    struct sa_address generic_address = {
    struct sa_address *address = sa_alloc_from_ipv4_address_and_port(INADDR_LOOPBACK, 8080);

    assert(sizeof(struct sockaddr_in) == sa_len(address));

    free(address);
}


static void
test_sa_len_for_ipv6(void)
{
    struct sa_address *address = sa_alloc_from_ipv6_address_and_port(in6addr_loopback, 8080);

    assert(sizeof(struct sockaddr_in6) == sa_len(address));

    free(address);
}


static void
test_sa_len_for_unix(void)
{
    struct sa_address *address = sa_alloc_from_path("/var/dood/http");

    assert(sizeof(struct sockaddr_un) == sa_len(address));

    free(address);
}


static void
test_sa_len_for_unsupported(void)
{
    struct sa_address address = {
            .generic = {
                    .sa_family = 0xff,
            }
    };

    assert(sizeof(struct sockaddr_storage) == sa_len(&address));
}


static void
test_sa_str_for_unspecified(void)
{
    struct sa_address address = {
            .generic = {
                    .sa_family = AF_UNSPEC,
            }
    };

    assert(STR_EQ("(unspecified)", sa_str(&address)));
}


static void
test_sa_str_for_unsupported(void)
{
    struct sa_address address = {
            .generic = {
                    .sa_family = 0xff,
            }
    };

    assert(STR_EQ("(unsupported)", sa_str(&generic_address)));
    assert(STR_EQ("(unsupported)", sa_str(&address)));
}


int
main(int argc, char *argv[])
{
    test_sa_alloc_from_address_and_port();
    test_sa_alloc_from_ipv4_address_and_port();
    test_sa_alloc_from_sockaddr_in();

    test_sa_alloc_from_ipv6_address_and_port();


@@ 200,6 259,12 @@ main(int argc, char *argv[])
    test_sa_alloc_from_path_when_too_long();
    test_sa_alloc_from_sockaddr_un();

    test_sa_str_for_unspecified_family();
    test_sa_str_for_unsupported_family();
    test_sa_len_for_unspecified();
    test_sa_len_for_ipv4();
    test_sa_len_for_ipv6();
    test_sa_len_for_unix();
    test_sa_len_for_unsupported();

    test_sa_str_for_unspecified();
    test_sa_str_for_unsupported();
}