Fri Aug 17 00:17:17 2018

Asterisk developer's documentation


netsock2.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2010, Digium, Inc.
00005  *
00006  * Viagénie <asteriskv6@viagenie.ca>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Network socket handling
00022  *
00023  * \author Viagénie <asteriskv6@viagenie.ca>
00024  */
00025 
00026 /*** MODULEINFO
00027    <support_level>core</support_level>
00028  ***/
00029 
00030 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369108 $")
00033 
00034 #include "asterisk/config.h"
00035 #include "asterisk/netsock2.h"
00036 #include "asterisk/utils.h"
00037 #include "asterisk/threadstorage.h"
00038 
00039 int ast_sockaddr_ipv4_mapped(const struct ast_sockaddr *addr, struct ast_sockaddr *ast_mapped)
00040 {
00041    const struct sockaddr_in6 *sin6;
00042    struct sockaddr_in sin4;
00043 
00044    if (!ast_sockaddr_is_ipv6(addr)) {
00045       return 0;
00046    }
00047 
00048    if (!ast_sockaddr_is_ipv4_mapped(addr)) {
00049       return 0;
00050    }
00051 
00052    sin6 = (const struct sockaddr_in6*)&addr->ss;
00053 
00054    memset(&sin4, 0, sizeof(sin4));
00055    sin4.sin_family = AF_INET;
00056    sin4.sin_port = sin6->sin6_port;
00057    sin4.sin_addr.s_addr = ((uint32_t *)&sin6->sin6_addr)[3];
00058 
00059    ast_sockaddr_from_sin(ast_mapped, &sin4);
00060 
00061    return 1;
00062 }
00063 
00064 
00065 AST_THREADSTORAGE(ast_sockaddr_stringify_buf);
00066 
00067 char *ast_sockaddr_stringify_fmt(const struct ast_sockaddr *sa, int format)
00068 {
00069    struct ast_sockaddr sa_ipv4;
00070    const struct ast_sockaddr *sa_tmp;
00071    char host[NI_MAXHOST];
00072    char port[NI_MAXSERV];
00073    struct ast_str *str;
00074    int e;
00075    static const size_t size = sizeof(host) - 1 + sizeof(port) - 1 + 4;
00076 
00077 
00078    if (ast_sockaddr_isnull(sa)) {
00079       return "(null)";
00080    }
00081 
00082    if (!(str = ast_str_thread_get(&ast_sockaddr_stringify_buf, size))) {
00083       return "";
00084    }
00085 
00086    if (ast_sockaddr_ipv4_mapped(sa, &sa_ipv4)) {
00087       sa_tmp = &sa_ipv4;
00088    } else {
00089       sa_tmp = sa;
00090    }
00091 
00092    if ((e = getnameinfo((struct sockaddr *)&sa_tmp->ss, sa_tmp->len,
00093               format & AST_SOCKADDR_STR_ADDR ? host : NULL,
00094               format & AST_SOCKADDR_STR_ADDR ? sizeof(host) : 0,
00095               format & AST_SOCKADDR_STR_PORT ? port : 0,
00096               format & AST_SOCKADDR_STR_PORT ? sizeof(port): 0,
00097               NI_NUMERICHOST | NI_NUMERICSERV))) {
00098       ast_log(LOG_ERROR, "getnameinfo(): %s\n", gai_strerror(e));
00099       return "";
00100    }
00101 
00102    if ((format & AST_SOCKADDR_STR_REMOTE) == AST_SOCKADDR_STR_REMOTE) {
00103       char *p;
00104       if (ast_sockaddr_is_ipv6_link_local(sa) && (p = strchr(host, '%'))) {
00105          *p = '\0';
00106       }
00107    }
00108 
00109    switch ((format & AST_SOCKADDR_STR_FORMAT_MASK))  {
00110    case AST_SOCKADDR_STR_DEFAULT:
00111       ast_str_set(&str, 0, sa_tmp->ss.ss_family == AF_INET6 ?
00112             "[%s]:%s" : "%s:%s", host, port);
00113       break;
00114    case AST_SOCKADDR_STR_ADDR:
00115       ast_str_set(&str, 0, "%s", host);
00116       break;
00117    case AST_SOCKADDR_STR_HOST:
00118       ast_str_set(&str, 0,
00119              sa_tmp->ss.ss_family == AF_INET6 ? "[%s]" : "%s", host);
00120       break;
00121    case AST_SOCKADDR_STR_PORT:
00122       ast_str_set(&str, 0, "%s", port);
00123       break;
00124    default:
00125       ast_log(LOG_ERROR, "Invalid format\n");
00126       return "";
00127    }
00128 
00129    return ast_str_buffer(str);
00130 }
00131 
00132 int ast_sockaddr_split_hostport(char *str, char **host, char **port, int flags)
00133 {
00134    char *s = str;
00135    char *orig_str = str;/* Original string in case the port presence is incorrect. */
00136    char *host_end = NULL;/* Delay terminating the host in case the port presence is incorrect. */
00137 
00138    ast_debug(5, "Splitting '%s' into...\n", str);
00139    *host = NULL;
00140    *port = NULL;
00141    if (*s == '[') {
00142       *host = ++s;
00143       for (; *s && *s != ']'; ++s) {
00144       }
00145       if (*s == ']') {
00146          host_end = s;
00147          ++s;
00148       }
00149       if (*s == ':') {
00150          *port = s + 1;
00151       }
00152    } else {
00153       *host = s;
00154       for (; *s; ++s) {
00155          if (*s == ':') {
00156             if (*port) {
00157                *port = NULL;
00158                break;
00159             } else {
00160                *port = s;
00161             }
00162          }
00163       }
00164       if (*port) {
00165          host_end = *port;
00166          ++*port;
00167       }
00168    }
00169 
00170    switch (flags & PARSE_PORT_MASK) {
00171    case PARSE_PORT_IGNORE:
00172       *port = NULL;
00173       break;
00174    case PARSE_PORT_REQUIRE:
00175       if (*port == NULL) {
00176          ast_log(LOG_WARNING, "Port missing in %s\n", orig_str);
00177          return 0;
00178       }
00179       break;
00180    case PARSE_PORT_FORBID:
00181       if (*port != NULL) {
00182          ast_log(LOG_WARNING, "Port disallowed in %s\n", orig_str);
00183          return 0;
00184       }
00185       break;
00186    }
00187 
00188    /* Can terminate the host string now if needed. */
00189    if (host_end) {
00190       *host_end = '\0';
00191    }
00192    ast_debug(5, "...host '%s' and port '%s'.\n", *host, *port ? *port : "");
00193    return 1;
00194 }
00195 
00196 
00197 
00198 int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
00199 {
00200    struct addrinfo hints;
00201    struct addrinfo   *res;
00202    char *s;
00203    char *host;
00204    char *port;
00205    int   e;
00206 
00207    s = ast_strdupa(str);
00208    if (!ast_sockaddr_split_hostport(s, &host, &port, flags)) {
00209       return 0;
00210    }
00211 
00212    memset(&hints, 0, sizeof(hints));
00213    /* Hint to get only one entry from getaddrinfo */
00214    hints.ai_socktype = SOCK_DGRAM;
00215 
00216 #ifdef AI_NUMERICSERV
00217    hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
00218 #else
00219    hints.ai_flags = AI_NUMERICHOST;
00220 #endif
00221    if ((e = getaddrinfo(host, port, &hints, &res))) {
00222       if (e != EAI_NONAME) { /* if this was just a host name rather than a ip address, don't print error */
00223          ast_log(LOG_ERROR, "getaddrinfo(\"%s\", \"%s\", ...): %s\n",
00224             host, S_OR(port, "(null)"), gai_strerror(e));
00225       }
00226       return 0;
00227    }
00228 
00229    /*
00230     * I don't see how this could be possible since we're not resolving host
00231     * names. But let's be careful...
00232     */
00233    if (res->ai_next != NULL) {
00234       ast_log(LOG_WARNING, "getaddrinfo() returned multiple "
00235          "addresses. Ignoring all but the first.\n");
00236    }
00237 
00238    if (addr) {
00239       addr->len = res->ai_addrlen;
00240       memcpy(&addr->ss, res->ai_addr, addr->len);
00241    }
00242 
00243    freeaddrinfo(res);
00244 
00245    return 1;
00246 }
00247 
00248 int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str,
00249           int flags, int family)
00250 {
00251    struct addrinfo hints, *res, *ai;
00252    char *s, *host, *port;
00253    int   e, i, res_cnt;
00254 
00255    if (!str) {
00256       return 0;
00257    }
00258 
00259    s = ast_strdupa(str);
00260    if (!ast_sockaddr_split_hostport(s, &host, &port, flags)) {
00261       return 0;
00262    }
00263 
00264    memset(&hints, 0, sizeof(hints));
00265    hints.ai_family = family;
00266    hints.ai_socktype = SOCK_DGRAM;
00267 
00268    if ((e = getaddrinfo(host, port, &hints, &res))) {
00269       ast_log(LOG_ERROR, "getaddrinfo(\"%s\", \"%s\", ...): %s\n",
00270          host, S_OR(port, "(null)"), gai_strerror(e));
00271       return 0;
00272    }
00273 
00274    res_cnt = 0;
00275    for (ai = res; ai; ai = ai->ai_next) {
00276       res_cnt++;
00277    }
00278 
00279    if (res_cnt == 0) {
00280       goto cleanup;
00281    }
00282 
00283    if ((*addrs = ast_malloc(res_cnt * sizeof(struct ast_sockaddr))) == NULL) {
00284       res_cnt = 0;
00285       goto cleanup;
00286    }
00287 
00288    i = 0;
00289    for (ai = res; ai; ai = ai->ai_next) {
00290       (*addrs)[i].len = ai->ai_addrlen;
00291       memcpy(&(*addrs)[i].ss, ai->ai_addr, ai->ai_addrlen);
00292       ++i;
00293    }
00294 
00295 cleanup:
00296    freeaddrinfo(res);
00297    return res_cnt;
00298 }
00299 
00300 int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
00301 {
00302    const struct ast_sockaddr *a_tmp, *b_tmp;
00303    struct ast_sockaddr ipv4_mapped;
00304 
00305    a_tmp = a;
00306    b_tmp = b;
00307 
00308    if (a_tmp->len != b_tmp->len) {
00309       if (ast_sockaddr_ipv4_mapped(a, &ipv4_mapped)) {
00310          a_tmp = &ipv4_mapped;
00311       } else if (ast_sockaddr_ipv4_mapped(b, &ipv4_mapped)) {
00312          b_tmp = &ipv4_mapped;
00313       }
00314    }
00315 
00316    if (a_tmp->len < b_tmp->len) {
00317       return -1;
00318    } else if (a_tmp->len > b_tmp->len) {
00319       return 1;
00320    }
00321 
00322    return memcmp(&a_tmp->ss, &b_tmp->ss, a_tmp->len);
00323 }
00324 
00325 int ast_sockaddr_cmp_addr(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
00326 {
00327    const struct ast_sockaddr *a_tmp, *b_tmp;
00328    struct ast_sockaddr ipv4_mapped;
00329    const struct in_addr *ip4a, *ip4b;
00330    const struct in6_addr *ip6a, *ip6b;
00331    int ret = -1;
00332 
00333    a_tmp = a;
00334    b_tmp = b;
00335 
00336    if (a_tmp->len != b_tmp->len) {
00337       if (ast_sockaddr_ipv4_mapped(a, &ipv4_mapped)) {
00338          a_tmp = &ipv4_mapped;
00339       } else if (ast_sockaddr_ipv4_mapped(b, &ipv4_mapped)) {
00340          b_tmp = &ipv4_mapped;
00341       }
00342    }
00343 
00344    if (a->len < b->len) {
00345       ret = -1;
00346    } else if (a->len > b->len) {
00347       ret = 1;
00348    }
00349 
00350    switch (a_tmp->ss.ss_family) {
00351    case AF_INET:
00352       ip4a = &((const struct sockaddr_in*)&a_tmp->ss)->sin_addr;
00353       ip4b = &((const struct sockaddr_in*)&b_tmp->ss)->sin_addr;
00354       ret = memcmp(ip4a, ip4b, sizeof(*ip4a));
00355       break;
00356    case AF_INET6:
00357       ip6a = &((const struct sockaddr_in6*)&a_tmp->ss)->sin6_addr;
00358       ip6b = &((const struct sockaddr_in6*)&b_tmp->ss)->sin6_addr;
00359       ret = memcmp(ip6a, ip6b, sizeof(*ip6a));
00360       break;
00361    }
00362    return ret;
00363 }
00364 
00365 uint16_t _ast_sockaddr_port(const struct ast_sockaddr *addr, const char *file, int line, const char *func)
00366 {
00367    if (addr->ss.ss_family == AF_INET &&
00368        addr->len == sizeof(struct sockaddr_in)) {
00369       return ntohs(((struct sockaddr_in *)&addr->ss)->sin_port);
00370    } else if (addr->ss.ss_family == AF_INET6 &&
00371        addr->len == sizeof(struct sockaddr_in6)) {
00372       return ntohs(((struct sockaddr_in6 *)&addr->ss)->sin6_port);
00373    }
00374    if (option_debug >= 1) {
00375       ast_log(__LOG_DEBUG, file, line, func, "Not an IPv4 nor IPv6 address, cannot get port.\n");
00376    }
00377    return 0;
00378 }
00379 
00380 void _ast_sockaddr_set_port(struct ast_sockaddr *addr, uint16_t port, const char *file, int line, const char *func)
00381 {
00382    if (addr->ss.ss_family == AF_INET &&
00383        addr->len == sizeof(struct sockaddr_in)) {
00384       ((struct sockaddr_in *)&addr->ss)->sin_port = htons(port);
00385    } else if (addr->ss.ss_family == AF_INET6 &&
00386        addr->len == sizeof(struct sockaddr_in6)) {
00387       ((struct sockaddr_in6 *)&addr->ss)->sin6_port = htons(port);
00388    } else if (option_debug >= 1) {
00389       ast_log(__LOG_DEBUG, file, line, func,
00390          "Not an IPv4 nor IPv6 address, cannot set port.\n");
00391    }
00392 }
00393 
00394 uint32_t ast_sockaddr_ipv4(const struct ast_sockaddr *addr)
00395 {
00396    const struct sockaddr_in *sin = (struct sockaddr_in *)&addr->ss;
00397    return ntohl(sin->sin_addr.s_addr);
00398 }
00399 
00400 int ast_sockaddr_is_ipv4(const struct ast_sockaddr *addr)
00401 {
00402    return addr->ss.ss_family == AF_INET &&
00403        addr->len == sizeof(struct sockaddr_in);
00404 }
00405 
00406 int ast_sockaddr_is_ipv4_mapped(const struct ast_sockaddr *addr)
00407 {
00408    const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr->ss;
00409    return addr->len && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr);
00410 }
00411 
00412 int ast_sockaddr_is_ipv6_link_local(const struct ast_sockaddr *addr)
00413 {
00414    const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr->ss;
00415    return ast_sockaddr_is_ipv6(addr) && IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr);
00416 }
00417 
00418 int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
00419 {
00420    return addr->ss.ss_family == AF_INET6 &&
00421        addr->len == sizeof(struct sockaddr_in6);
00422 }
00423 
00424 int ast_sockaddr_is_any(const struct ast_sockaddr *addr)
00425 {
00426    union {
00427       struct sockaddr_storage ss;
00428       struct sockaddr_in sin;
00429       struct sockaddr_in6 sin6;
00430    } tmp_addr = {
00431       .ss = addr->ss,
00432    };
00433 
00434    return (ast_sockaddr_is_ipv4(addr) && (tmp_addr.sin.sin_addr.s_addr == INADDR_ANY)) ||
00435        (ast_sockaddr_is_ipv6(addr) && IN6_IS_ADDR_UNSPECIFIED(&tmp_addr.sin6.sin6_addr));
00436 }
00437 
00438 int ast_sockaddr_hash(const struct ast_sockaddr *addr)
00439 {
00440    /*
00441     * For IPv4, return the IP address as-is. For IPv6, return the last 32
00442     * bits.
00443     */
00444    switch (addr->ss.ss_family) {
00445    case AF_INET:
00446       return ((const struct sockaddr_in *)&addr->ss)->sin_addr.s_addr;
00447    case AF_INET6:
00448       return ((uint32_t *)&((const struct sockaddr_in6 *)&addr->ss)->sin6_addr)[3];
00449    default:
00450       ast_log(LOG_ERROR, "Unknown address family '%d'.\n",
00451          addr->ss.ss_family);
00452       return 0;
00453    }
00454 }
00455 
00456 int ast_accept(int sockfd, struct ast_sockaddr *addr)
00457 {
00458    addr->len = sizeof(addr->ss);
00459    return accept(sockfd, (struct sockaddr *)&addr->ss, &addr->len);
00460 }
00461 
00462 int ast_bind(int sockfd, const struct ast_sockaddr *addr)
00463 {
00464    return bind(sockfd, (const struct sockaddr *)&addr->ss, addr->len);
00465 }
00466 
00467 int ast_connect(int sockfd, const struct ast_sockaddr *addr)
00468 {
00469    return connect(sockfd, (const struct sockaddr *)&addr->ss, addr->len);
00470 }
00471 
00472 int ast_getsockname(int sockfd, struct ast_sockaddr *addr)
00473 {
00474    addr->len = sizeof(addr->ss);
00475    return getsockname(sockfd, (struct sockaddr *)&addr->ss, &addr->len);
00476 }
00477 
00478 ssize_t ast_recvfrom(int sockfd, void *buf, size_t len, int flags,
00479            struct ast_sockaddr *src_addr)
00480 {
00481    src_addr->len = sizeof(src_addr->ss);
00482    return recvfrom(sockfd, buf, len, flags,
00483          (struct sockaddr *)&src_addr->ss, &src_addr->len);
00484 }
00485 
00486 ssize_t ast_sendto(int sockfd, const void *buf, size_t len, int flags,
00487          const struct ast_sockaddr *dest_addr)
00488 {
00489    return sendto(sockfd, buf, len, flags,
00490             (const struct sockaddr *)&dest_addr->ss, dest_addr->len);
00491 }
00492 
00493 int ast_set_qos(int sockfd, int tos, int cos, const char *desc)
00494 {
00495    int res = 0;
00496    int set_tos;
00497    int set_tclass;
00498    struct ast_sockaddr addr;
00499 
00500    /* If the sock address is IPv6, the TCLASS field must be set. */
00501    set_tclass = !ast_getsockname(sockfd, &addr) && ast_sockaddr_is_ipv6(&addr) ? 1 : 0;
00502 
00503    /* If the the sock address is IPv4 or (IPv6 set to any address [::]) set TOS bits */
00504    set_tos = (!set_tclass || (set_tclass && ast_sockaddr_is_any(&addr))) ? 1 : 0;
00505 
00506    if (set_tos) {
00507       if ((res = setsockopt(sockfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)))) {
00508          ast_log(LOG_WARNING, "Unable to set %s DSCP TOS value to %d (may be you have no "
00509             "root privileges): %s\n", desc, tos, strerror(errno));
00510       } else if (tos) {
00511          ast_verb(2, "Using %s TOS bits %d\n", desc, tos);
00512       }
00513    }
00514 
00515 #if defined(IPV6_TCLASS) && defined(IPPROTO_IPV6)
00516    if (set_tclass) {
00517       if (!ast_getsockname(sockfd, &addr) && ast_sockaddr_is_ipv6(&addr)) {
00518          if ((res = setsockopt(sockfd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)))) {
00519             ast_log(LOG_WARNING, "Unable to set %s DSCP TCLASS field to %d (may be you have no "
00520                "root privileges): %s\n", desc, tos, strerror(errno));
00521          } else if (tos) {
00522             ast_verb(2, "Using %s TOS bits %d in TCLASS field.\n", desc, tos);
00523          }
00524       }
00525    }
00526 #endif
00527 
00528 #ifdef linux
00529    if (setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, &cos, sizeof(cos))) {
00530       ast_log(LOG_WARNING, "Unable to set %s CoS to %d: %s\n", desc, cos,
00531          strerror(errno));
00532    } else if (cos) {
00533       ast_verb(2, "Using %s CoS mark %d\n", desc, cos);
00534    }
00535 #endif
00536 
00537    return res;
00538 }
00539 
00540 int _ast_sockaddr_to_sin(const struct ast_sockaddr *addr,
00541          struct sockaddr_in *sin, const char *file, int line, const char *func)
00542 {
00543    if (ast_sockaddr_isnull(addr)) {
00544       memset(sin, 0, sizeof(*sin));
00545       return 1;
00546    }
00547 
00548    if (addr->len != sizeof(*sin)) {
00549       ast_log(__LOG_ERROR, file, line, func, "Bad address cast to IPv4\n");
00550       return 0;
00551    }
00552 
00553    if (addr->ss.ss_family != AF_INET && option_debug >= 1) {
00554       ast_log(__LOG_DEBUG, file, line, func, "Address family is not AF_INET\n");
00555    }
00556 
00557    *sin = *(struct sockaddr_in *)&addr->ss;
00558    return 1;
00559 }
00560 
00561 void _ast_sockaddr_from_sin(struct ast_sockaddr *addr, const struct sockaddr_in *sin,
00562       const char *file, int line, const char *func)
00563 {
00564    memcpy(&addr->ss, sin, sizeof(*sin));
00565 
00566    if (addr->ss.ss_family != AF_INET && option_debug >= 1) {
00567       ast_log(__LOG_DEBUG, file, line, func, "Address family is not AF_INET\n");
00568    }
00569 
00570    addr->len = sizeof(*sin);
00571 }

Generated on 17 Aug 2018 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1