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