⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 su_localinfo.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@ingroup su_socket * @CFILE su_localinfo.c * * Obtain list of local addresses. * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * @author Martti Mela <Martti.Mela@nokia.com> *  * @date Created: Wed Oct  4 14:09:29 EET 2000 ppessi */#include "config.h"#if HAVE_SYS_SOCKIO_H#include <sys/sockio.h>#endif#include <sofia-sip/su.h>#include <sofia-sip/su_localinfo.h>#include "su_module_debug.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <stddef.h>#include <sys/types.h>#if HAVE_SYS_SOCKET_H#include <sys/socket.h>#endif#if HAVE_NETINET_IN_H#include <netinet/in.h>#endif#if HAVE_SYS_IOCTL_H#include <sys/ioctl.h>#endif#if HAVE_NET_IF_H#include <net/if.h>#endif#if HAVE_NET_IF_TYPES_H#include <net/if_types.h>#endif#if HAVE_GETIFADDRS#define USE_LOCALINFO0 1#define localinfo0 bsd_localinfostatic int bsd_localinfo(su_localinfo_t const *, su_localinfo_t **);#elif HAVE_IPHLPAPI_H#include <iphlpapi.h>#define USE_LOCALINFO0 1#define localinfo0 win_localinfostatic int win_localinfo(su_localinfo_t const *, su_localinfo_t **);#else#undef USE_LOCALINFO0static int localinfo4(su_localinfo_t const *, su_localinfo_t **);#  if SU_HAVE_IN6static int localinfo6(su_localinfo_t const *, su_localinfo_t **);#  endif#endifstatic int li_name(su_localinfo_t const*, int, su_sockaddr_t const*, char **);static void li_sort(su_localinfo_t *i, su_localinfo_t **rresult);static int li_scope4(uint32_t ip4);/** @brief Request local address information. * * Gather the network interfaces and the addresses corresponding to them, * check if they match to the search criteria specifed by @a hints and * return a list of matching local address information in the @a * return_localinfo. The local address information may include IPv4/IPv6 * addresses, interface name, interface index, address scope, and domain * names corresponding to the local addresses. * * @param[in] hints specifies selection criteria * @param[out] return_localinfo   return list of local addresses * * @par Selection criteria - hints * * The selection criteria @a hints is used to select which addresses are * returned and what kind of information is included in the @a res list. * * @par Selection by flags - hints->li_flags * * The @a hints->li_flags contain flags, which can be combined with bit-wise * or.  The currently defined flags are as follows: * * - #LI_V4MAPPED: when returning IPv4 addresses, map them as IPv6 *   addresses.  If this flag is specified, IPv4 addresses are returned even *   if @a hints->li_family is set to @c AF_INET6. * - #LI_CANONNAME: return the domain name (DNS PTR) corresponding to the  *   local address in @a li_canonname. * - #LI_NAMEREQD: Do not return addresses not in DNS.  * - #LI_NUMERIC: instead of domain name, return the text presentation of *   the addresss in @a li_canonname. * - #LI_DOWN: include interfaces and their addresses even if the interfaces *   are down. New in @VERSION_1_12_2. * - #LI_IFNAME: return the interface name in @a li_ifname. * * @par Selection by address family - hints->li_family * * The address family can have three values: 0, AF_INET and AF_INET6.  If * address family @a hints->li_family, both IPv4 and IPv6 addresses are * returned. * * @par Selection by interface index - hints->li_index * * If the field @a hints->li_index is non-zero, only the addresses assigned * to the interface with given index are returned.  The list of interface * indices and names can be obtained by the function @c su_if_names(). * * @par Selection by interface name - hints->li_ifname * * If the field @a hints->li_ifname is not NULL, only the addresses assigned * to the named interface are returned.  The list of interface names can be * obtained by the function @c su_if_names(). * * @par Selection by address scope - hints->li_scope * * If the field @a hints->li_scope is nonzero, only the addresses with * matching scope are returned. The different address scopes can be combined * with bitwise or. They are defined as follows * - #LI_SCOPE_HOST: host-local address, valid within host (::1, 127.0.0.1/8) * - #LI_SCOPE_LINK: link-local address, valid within link  *   (IP6 addresses with prefix fe80::/10,  *    IP4 addresses in net 169.254.0.0/16). * - #LI_SCOPE_SITE: site-local address, addresses valid within organization *   (IPv6 addresses with prefix  fec::/10, *    private IPv4 addresses in nets 10.0.0.0/8, 172.16.0.0/12,  *    and 192.168.0.0/16 as defined in @RFC1918) * - #LI_SCOPE_GLOBAL: global address. * * For instance, setting @a hints->li_scope to @c LI_SCOPE_GLOBAL | @c * LI_SCOPE_SITE, both the @e global and @e site-local addresses are * returned. * * @sa @RFC1918, @RFC4291, su_sockaddr_scope() * * @par Selection by domain name - hints->li_canonname * * If this field is non-null, the domain name (DNS PTR) corresponding to * local IP addresses should match to the name given in this field. * * @return Zero (#ELI_NOERROR) when successful, or negative error code when * failed. *  * @par Diagnostics * Use su_gli_strerror() in order to obtain a string describing the error * code returned by su_getlocalinfo(). * */int su_getlocalinfo(su_localinfo_t const *hints, 		    su_localinfo_t **return_localinfo){  int error = 0, ip4 = 0, ip6 = 0;  su_localinfo_t *result = NULL, **rr = &result;  su_localinfo_t hh[1] = {{ 0 }};  assert(return_localinfo);  *return_localinfo = NULL;  if (hints) {    /* Copy hints so that it can be modified */    *hh = *hints;    if (hh->li_canonname)      hh->li_flags |= LI_CANONNAME;    if ((hh->li_flags & LI_IFNAME) && hh->li_ifname == NULL)      return ELI_BADHINTS;  }  switch (hh->li_family) {#if SU_HAVE_IN6  case AF_INET6:    if (hh->li_flags & LI_V4MAPPED)      ip6 = ip4 = 1, hh->li_family = 0;    else      ip6 = 1;    break;#endif  case AF_INET:    ip4 = 1;    break;  case 0:    ip6 = ip4 = 1;        break;  default:    return -1;  }#if USE_LOCALINFO0   error = localinfo0(hh, rr);#else#  if SU_HAVE_IN6  if (ip6) {    error = localinfo6(hh, rr);    if (error == ELI_NOADDRESS && ip4)      error = 0;        if (!error)       /* Search end of list */      for (; *rr; rr = &(*rr)->li_next)	;  }#  endif  if (ip4 && !error) {    /* Append IPv4 addresses */    error = localinfo4(hh, rr);  }#endif  if (!result)    error = ELI_NOADDRESS;  if (!error)    li_sort(result, return_localinfo);  else    su_freelocalinfo(result);  return error;}/** Free local address information.  * * Free a list of su_localinfo_t structures obtained with su_getlocalinfo() * or su_copylocalinfo() along with socket addresses and strings associated * with them. * * @sa su_getlocalinfo(), su_copylocalinfo(), #su_localinfo_t */void su_freelocalinfo(su_localinfo_t *tbf){  su_localinfo_t *li;  for (li = tbf; li; li = tbf) {    tbf = li->li_next;    if (li->li_canonname)      free(li->li_canonname);    free(li);  }}/** Describe su_localinfo errors.  * * The function su_gli_strerror() returns a string describing the error * condition indicated by the code that was returned by the function * su_getlocalinfo(). * * @param error error code returned by su_getlocalinfo() * * @return * A pointer to string describing the error condition. */char const *su_gli_strerror(int error){  switch (error) {  case ELI_NOERROR:   return "No error";  case ELI_NOADDRESS: return "No matching address";  case ELI_MEMORY:    return "Memory allocation error";  case ELI_FAMILY:    return "Unknown address family";  case ELI_RESOLVER:  return "Error when resolving address";  case ELI_SYSTEM:    return "System error";  case ELI_BADHINTS:  return "Invalid value for hints";  default:            return "Unknown error";  }}/** Duplicate su_localinfo structure. */su_localinfo_t *su_copylocalinfo(su_localinfo_t const *li0){  size_t n;  su_localinfo_t *li, *retval = NULL, **lli = &retval;# define SLEN(s) ((s) ? strlen(s) + 1 : 0)  for (; li0 ; li0 = li0->li_next) {    n = sizeof(*li0) + li0->li_addrlen + SLEN(li0->li_ifname);    if (!(li = calloc(1, n))) {      su_freelocalinfo(retval);      return NULL;    }    *lli = li;    lli = &li->li_next;    li->li_flags = li0->li_flags;    li->li_family = li0->li_family;    li->li_index = li0->li_index;    li->li_scope = li0->li_scope;    li->li_addrlen = li0->li_addrlen;    li->li_addr = memcpy(li + 1, li0->li_addr, li0->li_addrlen);    if (li0->li_canonname) {      if (!(li->li_canonname = malloc(SLEN(li0->li_canonname)))) {	su_freelocalinfo(retval);	return NULL;      }      strcpy(li->li_canonname, li0->li_canonname);    }    if (li0->li_ifname)      li->li_ifname = strcpy(li->li_addrlen + (char *)li->li_addr, 			     li0->li_ifname);  }  return retval;}/** Return IPv4 address scope */static int li_scope4(uint32_t ip4){  ip4 = ntohl(ip4);  if (0x7f000000 == (ip4 & 0xff000000))    return LI_SCOPE_HOST;  /* draft-ietf-zeroconf-ipv4-linklocal-02.txt - 169.254/16. */  else if (0xa9fe0000 == (ip4 & 0xffff0000))    return LI_SCOPE_LINK;  /* RFC1918 - 10/8, 172.16/12, 192.168/16. */  else if (0x0a000000 == (ip4 & 0xff000000) ||	   0xac100000 == (ip4 & 0xfff00000) ||	   0xc0a80000 == (ip4 & 0xffff0000))    return LI_SCOPE_SITE;  else    return LI_SCOPE_GLOBAL;}#if SU_HAVE_IN6#if HAVE_WINSOCK2_H#define IN6_IS_ADDR_LOOPBACK SU_IN6_IS_ADDR_LOOPBACKsu_inline intIN6_IS_ADDR_LOOPBACK(void const *ip6){  uint8_t const *u = ip6;  return     u[0] == 0 && u[1] == 0 && u[2] == 0 && u[3] == 0 &&     u[4] == 0 && u[5] == 0 && u[6] == 0 && u[7] == 0 &&     u[8] == 0 && u[9] == 0 && u[10] == 0 && u[11] == 0 &&     u[12] == 0 && u[13] == 0 && u[14] == 0 && u[15] == 1;}#endif/** Return IPv6 address scope */static int li_scope6(struct in6_addr const *ip6){  if (IN6_IS_ADDR_V4MAPPED(ip6) || IN6_IS_ADDR_V4COMPAT(ip6)) {    uint32_t ip4 = *(uint32_t *)(ip6->s6_addr + 12);    return li_scope4(ip4);  }  else if (IN6_IS_ADDR_LOOPBACK(ip6))    return LI_SCOPE_HOST;  else if (IN6_IS_ADDR_LINKLOCAL(ip6))    return LI_SCOPE_LINK;  else if (IN6_IS_ADDR_SITELOCAL(ip6))    return LI_SCOPE_SITE;  else    return LI_SCOPE_GLOBAL;}#endif/** Return the scope of address in the sockaddr structure */int su_sockaddr_scope(su_sockaddr_t const *su, socklen_t sulen){  if (sulen >= (sizeof su->su_sin) && su->su_family == AF_INET)    return li_scope4(su->su_sin.sin_addr.s_addr);#if SU_HAVE_IN6  if (sulen >= (sizeof su->su_sin6) && su->su_family == AF_INET6)    return li_scope6(&su->su_sin6.sin6_addr);#endif  return 0;}#if HAVE_OPEN_Cextern int su_get_local_ip_addr(su_sockaddr_t *su);#endif#if USE_LOCALINFO0#elif HAVE_IFCONF#if __APPLE_CC__/** Build a list of local IPv4 addresses and append it to *rresult. */staticint localinfo4(su_localinfo_t const *hints, su_localinfo_t **rresult){  su_localinfo_t *tbf = NULL, **lli = &tbf;  su_localinfo_t *li = NULL, *li_first = NULL;  su_sockaddr_t *su;  int error = ELI_NOADDRESS;  char *canonname = NULL;  su_socket_t s;#if SU_HAVE_IN6  int su_xtra = (hints->li_flags & LI_V4MAPPED) ? sizeof(*su) : 0;#else  int const su_xtra = 0;#endif  struct ifconf ifc;  int numifs;  char *buffer;  struct ifreq *ifr, *ifr_next;  su_sockaddr_t *sa;  socklen_t salen = sizeof(*sa);  int scope = 0, gni_flags = 0;  s = su_socket(AF_INET, SOCK_DGRAM, 0);  if (s == -1) {    SU_DEBUG_1(("su_localinfo: su_socket failed: %s\n", 		su_strerror(su_errno())));    return ELI_SYSTEM;  }  li = calloc(1, sizeof(su_localinfo_t));  sa = calloc(1, sizeof(su_sockaddr_t));  error = getsockname(s, (struct sockaddr *) sa, &salen);  if (error < 0 && errno == SOCKET_ERROR) {    SU_DEBUG_1(("%s: getsockname() failed: %s\n", __func__,                su_strerror(su_errno())));  }  error = bind(s, (struct sockaddr *) sa, salen);  if (error < 0) {    SU_DEBUG_1(("%s: bind() failed: %s\n", __func__,                su_strerror(su_errno())));    goto err;  }  su_close(s);  scope = li_scope4(sa->su_sin.sin_addr.s_addr);  if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)    gni_flags = NI_NUMERICHOST;      if (su_xtra) {    /* Map IPv4 address to IPv6 address */    memset(sa, 0, sizeof(*sa));    sa->su_family = AF_INET6;    ((int32_t*)&sa->su_sin6.sin6_addr)[3] = sa->su_sin.sin_addr.s_addr;      ((int32_t*)&sa->su_sin6.sin6_addr)[2] = htonl(0xffff);  }  li->li_family = sa->su_family;  li->li_scope = scope;  li->li_index = 0;  li->li_addrlen = su_sockaddr_size(sa);  li->li_addr = sa;  if ((error = li_name(hints, gni_flags, sa, &canonname)) < 0)    goto err;  if (canonname) {    if (strchr(canonname, ':') ||       strspn(canonname, "0123456789.") == strlen(canonname))	  li->li_flags |= LI_NUMERIC;  }  else    li->li_flags = 0;    li->li_canonname = canonname;  canonname = NULL;  *rresult = li;  return 0;err:  if (canonname) free(canonname);  if (li_first) free(li_first);  su_freelocalinfo(tbf);  su_close(s);  return error;}#else /* !__APPLE_CC__ *//** Build a list of local IPv4 addresses and append it to *rresult. */staticint localinfo4(su_localinfo_t const *hints, su_localinfo_t **rresult){  su_localinfo_t *tbf = NULL, **lli = &tbf;  su_localinfo_t *li = NULL, *li_first = NULL;  su_sockaddr_t *su;  int error = ELI_NOADDRESS;  char *canonname = NULL;  su_socket_t s;#if SU_HAVE_IN6  int su_xtra = (hints->li_flags & LI_V4MAPPED) ? sizeof(*su) : 0;#else  int const su_xtra = 0;#endif  struct ifconf ifc;  int numifs;  char *buffer;  struct ifreq *ifr, *ifr_next;#if HAVE_OPEN_C    su_sockaddr_t *sa;    socklen_t salen = sizeof(*sa);#endif  s = su_socket(AF_INET, SOCK_DGRAM, 0);  if (s == -1) {    SU_DEBUG_1(("su_localinfo: su_socket failed: %s\n", 		su_strerror(su_errno())));    return ELI_SYSTEM;  }# if HAVE_IFNUM

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -