~donmcc/ood

af17d3608a44c89c22d104e3789e3a184a660e5c — Don McCaughey 10 months ago 8bfc80c
Add function `sa_alloc_from_sockaddr()`.

Allow creation of an `sa_address` union from a generic socket address.
3 files changed, 125 insertions(+), 0 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 +12 -0
@@ 45,6 45,18 @@ sa_alloc_from_local_path(char const *path)


union sa_address *
sa_alloc_from_sockaddr(struct sockaddr const *generic_address)
{
    switch (generic_address->sa_family) {
        case AF_UNIX: return sa_alloc_from_sockaddr_un((struct sockaddr_un const *)generic_address);
        case AF_INET: return sa_alloc_from_sockaddr_in((struct sockaddr_in const *)generic_address);
        case AF_INET6: return sa_alloc_from_sockaddr_in6((struct sockaddr_in6 const *)generic_address);
        default: return NULL;
    }
}


union sa_address *
sa_alloc_from_sockaddr_in(struct sockaddr_in const *ipv4_address)
{
    union sa_address *address = calloc(1, sizeof(union sa_address));

M src/sa/sa.h => src/sa/sa.h +3 -0
@@ 62,6 62,9 @@ sa_alloc_from_local_path(char const *path);
// # Allocate socket address from a `sockaddr`-type struct.

union sa_address *
sa_alloc_from_sockaddr(struct sockaddr const *generic_address);

union sa_address *
sa_alloc_from_sockaddr_in(struct sockaddr_in const *ipv4_address);

union sa_address *

M src/sa/sa_tests.c => src/sa/sa_tests.c +110 -0
@@ 86,6 86,110 @@ test_sa_alloc_from_local_path_when_too_long(void)


static void
test_sa_alloc_from_sockaddr_for_unspecified(void)
{
    struct sockaddr generic = {
            .sa_family=AF_UNSPEC,
    };

    union sa_address *address = sa_alloc_from_sockaddr(&generic);

    assert(!address);
}


static void
test_sa_alloc_from_sockaddr_for_ipv4(void)
{
    struct sockaddr_in ipv4 = {
            .sin_family=AF_INET,
            .sin_addr=(struct in_addr){
                    .s_addr=htonl(INADDR_LOOPBACK)
            },
            .sin_port=htons(8080),
    };
    struct sockaddr *generic = (struct sockaddr *)&ipv4;

    union sa_address *address = sa_alloc_from_sockaddr(generic);

    assert(address);
    assert(AF_INET == address->generic.sa_family);
    assert(AF_INET == address->ipv4.sin_family);
    assert(AF_INET == address->ipv6.sin6_family);
    assert(AF_INET == address->local.sun_family);
    assert(AF_INET == address->storage.ss_family);
    assert(htonl(INADDR_LOOPBACK) == address->ipv4.sin_addr.s_addr);
    assert(htons(8080) == address->ipv4.sin_port);
    assert(STR_EQ("127.0.0.1:8080", sa_str(address)));

    free(address);
}


static void
test_sa_alloc_from_sockaddr_for_ipv6(void)
{
    struct sockaddr_in6 ipv6 = {
            .sin6_family=AF_INET6,
            .sin6_addr=in6addr_loopback,
            .sin6_port=htons(8080),
    };
    struct sockaddr *generic = (struct sockaddr *)&ipv6;

    union sa_address *address = sa_alloc_from_sockaddr(generic);

    assert(address);
    assert(AF_INET6 == address->generic.sa_family);
    assert(AF_INET6 == address->ipv4.sin_family);
    assert(AF_INET6 == address->ipv6.sin6_family);
    assert(AF_INET6 == address->local.sun_family);
    assert(AF_INET6 == address->storage.ss_family);
    assert(IN6_ADDR_EQ(&in6addr_loopback, &address->ipv6.sin6_addr));
    assert(htons(8080) == address->ipv6.sin6_port);
    assert(STR_EQ("::1:8080", sa_str(address)));

    free(address);
}


static void
test_sa_alloc_from_sockaddr_for_local(void)
{
    struct sockaddr_un local = {
            .sun_family = AF_UNIX,
            .sun_path = "/var/dood/http",
    };
    struct sockaddr *generic = (struct sockaddr *)&local;

    union sa_address *address = sa_alloc_from_sockaddr(generic);

    assert(address);
    assert(AF_UNIX == address->generic.sa_family);
    assert(AF_UNIX == address->ipv4.sin_family);
    assert(AF_UNIX == address->ipv6.sin6_family);
    assert(AF_UNIX == address->local.sun_family);
    assert(AF_UNIX == address->storage.ss_family);
    assert(STR_EQ("/var/dood/http", address->local.sun_path));
    assert(STR_EQ("/var/dood/http", sa_str(address)));

    free(address);
}


static void
test_sa_alloc_from_sockaddr_for_unsupported(void)
{
    struct sockaddr generic = {
            .sa_family=0xff,
    };

    union sa_address *address = sa_alloc_from_sockaddr(&generic);

    assert(!address);
}


static void
test_sa_alloc_from_sockaddr_in(void)
{
    struct sockaddr_in ipv4 = {


@@ 254,6 358,12 @@ main(int argc, char *argv[])
    test_sa_alloc_from_local_path_when_null();
    test_sa_alloc_from_local_path_when_too_long();

    test_sa_alloc_from_sockaddr_for_unspecified();
    test_sa_alloc_from_sockaddr_for_ipv4();
    test_sa_alloc_from_sockaddr_for_ipv6();
    test_sa_alloc_from_sockaddr_for_local();
    test_sa_alloc_from_sockaddr_for_unsupported();

    test_sa_alloc_from_sockaddr_in();
    test_sa_alloc_from_sockaddr_in6();
    test_sa_alloc_from_sockaddr_un();