Sat Mar 10 01:54:21 2012

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

Generated on Sat Mar 10 01:54:21 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7