"Fossies" - the Fresh Open Source Software Archive

Member "hydra-3.3.2/mpl/src/sock/mpl_sockaddr.c" (12 Nov 2019, 10430 Bytes) of package /linux/misc/hydra-3.3.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mpl_sockaddr.c" see the Fossies "Dox" file reference documentation.

    1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
    2 /*
    3 *  (C) 2018 by Argonne National Laboratory.
    4 *      See COPYRIGHT in top-level directory.
    5 */
    6 
    7 /** Rationale:
    8  *    MPL wrap for handling IPv4 and IPv6.
    9  *
   10  *    Applications: pm, pmi, ch3.
   11  *    ch4 supports tcp sockets indirectly through ucx and ofi.
   12  */
   13 
   14 /** Design considerations:
   15  *    Either IPv4 or IPv6, globally set as defalt or with command line option, to
   16  *    simplify logic.
   17  *    TCP only, no UDP or unix domain sockets.
   18  *
   19  *    Application use MPL_sockaddr_t exclusively.
   20  *            MPL_get_sockaddr for hostname
   21  *            MPL_get_sockaddr_iface for network interface
   22  *            MPL_get_sockaddr_direct for listening socket on ANY or LOOPBACK
   23  *
   24  *    Simplified MPL_connect and MPL_listen interface.
   25  *            Both have a port parameter.
   26  *            MPL_listen combines bind with listen.
   27  */
   28 
   29 /** Portability:
   30  *    MPL_sockaddr_t:
   31  *            In case this struct is not available (in sys/socket.h), it can be
   32  *        circumvented by declare following (in mpl_sockaddr.h):
   33  *                    MPL_sockaddr_t {
   34  *                            unsigend short ss_family;
   35  *                            char padding[126];
   36  *                    };
   37  *            Only the ss_family field is directly accessed. All the other fields are
   38  *        always accessed by casting to either struct sockaddr_in or struct
   39  *        sockaddr_in6.
   40  *
   41  *    The implementation uses getaddrinfo and getifaddrs. The former, as with
   42  *    sockaddr_storage and sockaddr_in6, are documented in RFC 2553, 1999, and are
   43  *    expected to be supported on most supported platforms. getifaddrs is not in
   44  *    POSIX.1, but it is present on Linux since glibc 2.3.3, and available on BSD
   45  *    systems even earlier.
   46  */
   47 
   48 #include "mplconfig.h"
   49 #include <assert.h>
   50 #include <sys/types.h>
   51 #include <sys/socket.h>
   52 #include <netdb.h>
   53 #include <netinet/in.h>
   54 #include <string.h>
   55 #include <ifaddrs.h>
   56 #include <errno.h>
   57 #include <stdio.h>
   58 
   59 #include "mpl_sockaddr.h"
   60 
   61 static int is_localhost(struct sockaddr *p_addr);
   62 
   63 static int af_type = AF_INET;
   64 static int _use_loopback = 0;
   65 static int _max_conn = SOMAXCONN;
   66 
   67 void MPL_sockaddr_set_aftype(int type)
   68 {
   69     af_type = type;
   70 }
   71 
   72 int MPL_get_sockaddr(const char *s_hostname, MPL_sockaddr_t * p_addr)
   73 {
   74     struct addrinfo ai_hint;
   75     struct addrinfo *ai_list;
   76     int ret;
   77 
   78     /* Macos adds .local to hostname when network is unavailable or limited.
   79      * This will result in long timeout in getaddrinfo below.
   80      * Bypass it by resetting the hostname to "localhost"
   81      */
   82     int n = strlen(s_hostname);
   83     if (n > 6 && strcmp(s_hostname + n - 6, ".local") == 0) {
   84         s_hostname = "localhost";
   85     }
   86 
   87     /* NOTE: there is report that getaddrinfo implementations will call kernel
   88      * even when s_hostname is entirely numerical string and it may cause
   89      * problems when host is configured with thousands of ip addresses.
   90      */
   91     /* TODO: detect the cases when s_hostname is entirely numerical string and
   92      * call inet_pton directly (-- do this on first bug report).
   93      */
   94     memset(p_addr, 0, sizeof(*p_addr));
   95     memset(&ai_hint, 0, sizeof(ai_hint));
   96     ai_hint.ai_family = af_type;
   97     ai_hint.ai_socktype = SOCK_STREAM;
   98     ai_hint.ai_protocol = IPPROTO_TCP;
   99     ai_hint.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED;
  100     ret = getaddrinfo(s_hostname, NULL, &ai_hint, &ai_list);
  101     if (ret) {
  102         return ret;
  103     }
  104     if (af_type == AF_INET) {
  105         memcpy(p_addr, ai_list->ai_addr, sizeof(struct sockaddr_in));
  106     } else if (af_type == AF_INET6) {
  107         memcpy(p_addr, ai_list->ai_addr, sizeof(struct sockaddr_in6));
  108     } else {
  109         assert(0);
  110     }
  111     freeaddrinfo(ai_list);
  112     return 0;
  113 }
  114 
  115 int MPL_get_sockaddr_direct(int type, MPL_sockaddr_t * p_addr)
  116 {
  117     memset(p_addr, 0, sizeof(*p_addr));
  118     assert(type == MPL_SOCKADDR_ANY || type == MPL_SOCKADDR_LOOPBACK);
  119     if (af_type == AF_INET) {
  120         struct sockaddr_in *p_addr4 = (struct sockaddr_in *) p_addr;
  121 
  122         p_addr4->sin_family = AF_INET;
  123         if (type == MPL_SOCKADDR_LOOPBACK) {
  124             p_addr4->sin_addr.s_addr = htonl(0x7f000001);
  125         } else {
  126             p_addr4->sin_addr.s_addr = htonl(INADDR_ANY);
  127         }
  128         return 0;
  129     } else if (af_type == AF_INET6) {
  130         struct sockaddr_in6 *p_addr6 = (struct sockaddr_in6 *) p_addr;
  131 
  132         p_addr6->sin6_family = AF_INET6;
  133         if (type == MPL_SOCKADDR_LOOPBACK) {
  134             p_addr6->sin6_addr = in6addr_loopback;
  135         } else {
  136             p_addr6->sin6_addr = in6addr_any;
  137         }
  138         return 0;
  139     } else {
  140         assert(0);
  141     }
  142 }
  143 
  144 int MPL_get_sockaddr_iface(const char *s_iface, MPL_sockaddr_t * p_addr)
  145 {
  146     struct ifaddrs *ifaddr;
  147     int ret;
  148     struct ifaddrs *ifa;
  149     int found = 0;
  150 
  151     memset(p_addr, 0, sizeof(*p_addr));
  152     ret = getifaddrs(&ifaddr);
  153     if (ret) {
  154         return ret;
  155     }
  156     ifa = ifaddr;
  157     while (ifa) {
  158         if (s_iface && ifa->ifa_name && strcmp(s_iface, ifa->ifa_name) != 0) {
  159             ifa = ifa->ifa_next;
  160             continue;
  161         }
  162         if (ifa->ifa_addr && ifa->ifa_addr->sa_family == af_type) {
  163             found++;
  164             if (af_type == AF_INET) {
  165                 memcpy(p_addr, ifa->ifa_addr, sizeof(struct sockaddr_in));
  166             } else if (af_type == AF_INET6) {
  167                 memcpy(p_addr, ifa->ifa_addr, sizeof(struct sockaddr_in6));
  168             }
  169             if (!is_localhost((struct sockaddr *) ifa->ifa_addr)) {
  170                 break;
  171             }
  172         }
  173         ifa = ifa->ifa_next;
  174     }
  175     freeifaddrs(ifaddr);
  176     if (!found) {
  177         return -1;
  178     } else {
  179         return 0;
  180     }
  181 }
  182 
  183 int MPL_socket()
  184 {
  185     return socket(af_type, SOCK_STREAM, IPPROTO_TCP);
  186 }
  187 
  188 int MPL_connect(int socket, MPL_sockaddr_t * p_addr, unsigned short port)
  189 {
  190     if (af_type == AF_INET) {
  191         ((struct sockaddr_in *) p_addr)->sin_port = htons(port);
  192         return connect(socket, (const struct sockaddr *) p_addr, sizeof(struct sockaddr_in));
  193     } else if (af_type == AF_INET6) {
  194         ((struct sockaddr_in6 *) p_addr)->sin6_port = htons(port);
  195         return connect(socket, (const struct sockaddr *) p_addr, sizeof(struct sockaddr_in6));
  196     } else {
  197         return -1;
  198     }
  199 }
  200 
  201 void MPL_set_listen_attr(int use_loopback, int max_conn)
  202 {
  203     _use_loopback = use_loopback;
  204     _max_conn = max_conn;
  205 }
  206 
  207 int MPL_listen(int socket, unsigned short port)
  208 {
  209     MPL_sockaddr_t addr;
  210     int ret;
  211 
  212     if (_use_loopback) {
  213         MPL_get_sockaddr_direct(MPL_SOCKADDR_LOOPBACK, &addr);
  214     } else {
  215         MPL_get_sockaddr_direct(MPL_SOCKADDR_ANY, &addr);
  216     }
  217     if (af_type == AF_INET) {
  218         ((struct sockaddr_in *) &addr)->sin_port = htons(port);
  219         ret = bind(socket, (const struct sockaddr *) &addr, sizeof(struct sockaddr_in));
  220     } else if (af_type == AF_INET6) {
  221         ((struct sockaddr_in6 *) &addr)->sin6_port = htons(port);
  222         ret = bind(socket, (const struct sockaddr *) &addr, sizeof(struct sockaddr_in6));
  223     } else {
  224         assert(0);
  225     }
  226     if (ret) {
  227         return ret;
  228     }
  229     return listen(socket, _max_conn);
  230 }
  231 
  232 int MPL_listen_anyport(int socket, unsigned short *p_port)
  233 {
  234     MPL_sockaddr_t addr;
  235     int ret;
  236     socklen_t n;
  237 
  238     if (_use_loopback) {
  239         MPL_get_sockaddr_direct(MPL_SOCKADDR_LOOPBACK, &addr);
  240     } else {
  241         MPL_get_sockaddr_direct(MPL_SOCKADDR_ANY, &addr);
  242     }
  243     if (af_type == AF_INET) {
  244         ((struct sockaddr_in *) &addr)->sin_port = 0;
  245         ret = bind(socket, (const struct sockaddr *) &addr, sizeof(struct sockaddr_in));
  246     } else if (af_type == AF_INET6) {
  247         ((struct sockaddr_in6 *) &addr)->sin6_port = 0;
  248         ret = bind(socket, (const struct sockaddr *) &addr, sizeof(struct sockaddr_in6));
  249     } else {
  250         assert(0);
  251     }
  252     if (ret) {
  253         return ret;
  254     }
  255     n = sizeof(addr);
  256     ret = getsockname(socket, (struct sockaddr *) &addr, &n);
  257     if (ret) {
  258         return ret;
  259     }
  260     if (af_type == AF_INET) {
  261         *p_port = ntohs(((struct sockaddr_in *) &addr)->sin_port);
  262     } else if (af_type == AF_INET6) {
  263         *p_port = ntohs(((struct sockaddr_in6 *) &addr)->sin6_port);
  264     }
  265     return listen(socket, _max_conn);
  266 }
  267 
  268 int MPL_listen_portrange(int socket, unsigned short *p_port, int low_port, int high_port)
  269 {
  270     MPL_sockaddr_t addr;
  271     int i;
  272     int ret;
  273 
  274     if (_use_loopback) {
  275         MPL_get_sockaddr_direct(MPL_SOCKADDR_LOOPBACK, &addr);
  276     } else {
  277         MPL_get_sockaddr_direct(MPL_SOCKADDR_ANY, &addr);
  278     }
  279     for (i = low_port; i <= high_port; i++) {
  280         ret = MPL_listen(socket, i);
  281         if (ret == 0) {
  282             *p_port = i;
  283             break;
  284         } else if (errno == EADDRINUSE) {
  285             continue;
  286         } else {
  287             return -1;
  288         }
  289     }
  290     if (i > high_port) {
  291         return -2;
  292     }
  293     return listen(socket, _max_conn);
  294 }
  295 
  296 int MPL_sockaddr_to_str(MPL_sockaddr_t * p_addr, char *str, int maxlen)
  297 {
  298     unsigned char *p;
  299 
  300     /* TODO: consider inet_ntop */
  301     if (p_addr->ss_family == AF_INET) {
  302         p = (void *) &((struct sockaddr_in *) p_addr)->sin_addr;
  303         snprintf(str, maxlen, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
  304     } else if (p_addr->ss_family == AF_INET6) {
  305         p = (void *) &((struct sockaddr_in6 *) p_addr)->sin6_addr;
  306         snprintf(str, maxlen,
  307                  "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
  308                  p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
  309                  p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
  310     }
  311     return 0;
  312 }
  313 
  314 int MPL_sockaddr_port(MPL_sockaddr_t * p_addr)
  315 {
  316     if (p_addr->ss_family == AF_INET) {
  317         return ntohs(((struct sockaddr_in *) p_addr)->sin_port);
  318     } else if (p_addr->ss_family == AF_INET6) {
  319         return ntohs(((struct sockaddr_in6 *) p_addr)->sin6_port);
  320     }
  321     return 0;
  322 }
  323 
  324 int is_localhost(struct sockaddr *p_addr)
  325 {
  326     char *p;
  327 
  328     if (p_addr->sa_family == AF_INET) {
  329         p = (void *) &((struct sockaddr_in *) p_addr)->sin_addr;
  330         return strncmp(p, "\x7f\x00\x00\x01", 4) == 0;
  331     } else if (p_addr->sa_family == AF_INET6) {
  332         p = (void *) &((struct sockaddr_in6 *) p_addr)->sin6_addr;
  333         return strncmp(p, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01", 16) == 0 ||
  334             strncmp(p, "\xfe\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\x01", 16) == 0;
  335     } else {
  336         return 0;
  337     }
  338 }