Wed Apr 6 11:29:46 2011

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

Generated on Wed Apr 6 11:29:46 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7