// // Copyright 2020 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this // file was obtained (LICENSE.txt). A copy of the license may also be // found online at https://opensource.org/licenses/MIT. // #include "core/nng_impl.h" #ifdef NNG_PLATFORM_POSIX #include #include #include #include #include #include #include #include #include size_t nni_posix_nn2sockaddr(void *sa, const nni_sockaddr *na) { struct sockaddr_in * sin; struct sockaddr_in6 * sin6; struct sockaddr_un * spath; const nng_sockaddr_in * nsin; const nng_sockaddr_in6 * nsin6; const nng_sockaddr_path * nspath; const nng_sockaddr_abstract *nsabs; size_t sz; if ((sa == NULL) || (na == NULL)) { return (0); } switch (na->s_family) { case NNG_AF_INET: sin = (void *) sa; nsin = &na->s_in; memset(sin, 0, sizeof(*sin)); sin->sin_family = PF_INET; sin->sin_port = nsin->sa_port; sin->sin_addr.s_addr = nsin->sa_addr; return (sizeof(*sin)); case NNG_AF_INET6: sin6 = (void *) sa; nsin6 = &na->s_in6; memset(sin6, 0, sizeof(*sin6)); #ifdef SIN6_LEN sin6->sin6_len = sizeof(*sin6); #endif sin6->sin6_family = PF_INET6; sin6->sin6_port = nsin6->sa_port; sin6->sin6_scope_id = nsin6->sa_scope; memcpy(sin6->sin6_addr.s6_addr, nsin6->sa_addr, 16); return (sizeof(*sin6)); case NNG_AF_IPC: spath = (void *) sa; nspath = &na->s_ipc; memset(spath, 0, sizeof(*spath)); // Make sure that the path fits! sz = sizeof(spath->sun_path); if (nni_strlcpy(spath->sun_path, nspath->sa_path, sz) >= sz) { return (0); } spath->sun_family = PF_UNIX; return (sizeof(*spath)); case NNG_AF_ABSTRACT: spath = (void *) sa; nsabs = &na->s_abstract; if (nsabs->sa_len >= sizeof (spath->sun_path)) { return (0); } memset(spath, 0, sizeof(*spath)); spath->sun_family = PF_UNIX; spath->sun_path[0] = '\0'; // abstract starts with nul // We support auto-bind with an empty string. There is // a subtle caveat here, which is that we cannot bind to // the *empty* name. if (nsabs->sa_len == 0) { return (sizeof (sa_family_t)); // auto bind } else { memcpy(&spath->sun_path[1], nsabs->sa_name, nsabs->sa_len); return (sizeof(sa_family_t) + 1 + nsabs->sa_len); } } return (0); } int nni_posix_sockaddr2nn(nni_sockaddr *na, const void *sa, size_t sz) { const struct sockaddr_in * sin; const struct sockaddr_in6 *sin6; const struct sockaddr_un * spath; nng_sockaddr_in * nsin; nng_sockaddr_in6 * nsin6; nng_sockaddr_path * nspath; nng_sockaddr_abstract * nsabs; if ((na == NULL) || (sa == NULL)) { return (-1); } switch (((struct sockaddr *) sa)->sa_family) { case AF_INET: if (sz < sizeof(*sin)) { return (-1); } sin = (void *) sa; nsin = &na->s_in; nsin->sa_family = NNG_AF_INET; nsin->sa_port = sin->sin_port; nsin->sa_addr = sin->sin_addr.s_addr; break; case AF_INET6: if (sz < sizeof(*sin6)) { return (-1); } sin6 = (void *) sa; nsin6 = &na->s_in6; nsin6->sa_family = NNG_AF_INET6; nsin6->sa_port = sin6->sin6_port; nsin6->sa_scope = sin6->sin6_scope_id; memcpy(nsin6->sa_addr, sin6->sin6_addr.s6_addr, 16); break; case AF_UNIX: // AF_UNIX can be NNG_AF_IPC, or NNG_AF_ABSTRACT. spath = (void *) sa; if ((sz < sizeof(sa_family_t)) || (sz > sizeof(*spath))) { return (-1); } // Now we need to look more closely. sz -= sizeof(sa_family_t); if (sz == 0) { // Unnamed socket. These will be treated using // auto-bind if we actually listen to them, and // it is impossible to connect them. nsabs = &na->s_abstract; nsabs->sa_family = NNG_AF_ABSTRACT; nsabs->sa_len = 0; } else if (spath->sun_path[0] == 0) { nsabs = &na->s_abstract; nsabs->sa_family = NNG_AF_ABSTRACT; nsabs->sa_len = sz - 1; memcpy(nsabs->sa_name, &spath->sun_path[1], sz - 1); } else { nspath = &na->s_ipc; nspath->sa_family = NNG_AF_IPC; nni_strlcpy(nspath->sa_path, spath->sun_path, sizeof(nspath->sa_path)); } break; default: // We should never see this - the OS should always be // specific about giving us either AF_INET or AF_INET6. // Other address families are not handled here. return (-1); } return (0); } #endif // NNG_PLATFORM_POSIX