Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_netdb.c Source File

lwip_netdb.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * API functions for name resolving
00004  *
00005  * @defgroup netdbapi NETDB API
00006  * @ingroup socket
00007  */
00008 
00009 /*
00010  * Redistribution and use in source and binary forms, with or without modification,
00011  * are permitted provided that the following conditions are met:
00012  *
00013  * 1. Redistributions of source code must retain the above copyright notice,
00014  *    this list of conditions and the following disclaimer.
00015  * 2. Redistributions in binary form must reproduce the above copyright notice,
00016  *    this list of conditions and the following disclaimer in the documentation
00017  *    and/or other materials provided with the distribution.
00018  * 3. The name of the author may not be used to endorse or promote products
00019  *    derived from this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00022  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00023  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00024  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00025  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00026  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00027  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00028  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00029  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00030  * OF SUCH DAMAGE.
00031  *
00032  * This file is part of the lwIP TCP/IP stack.
00033  *
00034  * Author: Simon Goldschmidt
00035  *
00036  */
00037 
00038 #include "lwip/netdb.h"
00039 
00040 #if LWIP_DNS && LWIP_SOCKET
00041 
00042 #include "lwip/err.h"
00043 #include "lwip/mem.h"
00044 #include "lwip/memp.h"
00045 #include "lwip/ip_addr.h"
00046 #include "lwip/api.h"
00047 #include "lwip/dns.h"
00048 
00049 #include <string.h> /* memset */
00050 #include <stdlib.h> /* atoi */
00051 
00052 /** helper struct for gethostbyname_r to access the char* buffer */
00053 struct gethostbyname_r_helper {
00054   ip_addr_t *addr_list[2];
00055   ip_addr_t addr;
00056   char *aliases;
00057 };
00058 
00059 /** h_errno is exported in netdb.h for access by applications. */
00060 #if LWIP_DNS_API_DECLARE_H_ERRNO
00061 int h_errno;
00062 #endif /* LWIP_DNS_API_DECLARE_H_ERRNO */
00063 
00064 /** define "hostent" variables storage: 0 if we use a static (but unprotected)
00065  * set of variables for lwip_gethostbyname, 1 if we use a local storage */
00066 #ifndef LWIP_DNS_API_HOSTENT_STORAGE
00067 #define LWIP_DNS_API_HOSTENT_STORAGE 0
00068 #endif
00069 
00070 /** define "hostent" variables storage */
00071 #if LWIP_DNS_API_HOSTENT_STORAGE
00072 #define HOSTENT_STORAGE
00073 #else
00074 #define HOSTENT_STORAGE static
00075 #endif /* LWIP_DNS_API_STATIC_HOSTENT */
00076 
00077 /**
00078  * Returns an entry containing addresses of address family AF_INET
00079  * for the host with name name.
00080  * Due to dns_gethostbyname limitations, only one address is returned.
00081  *
00082  * @param name the hostname to resolve
00083  * @return an entry containing addresses of address family AF_INET
00084  *         for the host with name name
00085  */
00086 struct hostent *
00087 lwip_gethostbyname(const char *name)
00088 {
00089   err_t err;
00090   ip_addr_t addr;
00091 
00092   /* buffer variables for lwip_gethostbyname() */
00093   HOSTENT_STORAGE struct hostent s_hostent;
00094   HOSTENT_STORAGE char *s_aliases;
00095   HOSTENT_STORAGE ip_addr_t s_hostent_addr;
00096   HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2];
00097   HOSTENT_STORAGE char s_hostname[DNS_MAX_NAME_LENGTH + 1];
00098 
00099   /* query host IP address */
00100   err = netconn_gethostbyname(name, &addr);
00101   if (err != ERR_OK) {
00102     LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
00103     h_errno = HOST_NOT_FOUND;
00104     return NULL;
00105   }
00106 
00107   /* fill hostent */
00108   s_hostent_addr = addr;
00109   s_phostent_addr[0] = &s_hostent_addr;
00110   s_phostent_addr[1] = NULL;
00111   strncpy(s_hostname, name, DNS_MAX_NAME_LENGTH);
00112   s_hostname[DNS_MAX_NAME_LENGTH] = 0;
00113   s_hostent.h_name = s_hostname;
00114   s_aliases = NULL;
00115   s_hostent.h_aliases = &s_aliases;
00116   s_hostent.h_addrtype = AF_INET;
00117   s_hostent.h_length = sizeof(ip_addr_t);
00118   s_hostent.h_addr_list = (char **)&s_phostent_addr;
00119 
00120 #if DNS_DEBUG
00121   /* dump hostent */
00122   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name           == %s\n", s_hostent.h_name));
00123   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases        == %p\n", (void *)s_hostent.h_aliases));
00124   /* h_aliases are always empty */
00125   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype       == %d\n", s_hostent.h_addrtype));
00126   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length         == %d\n", s_hostent.h_length));
00127   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list      == %p\n", (void *)s_hostent.h_addr_list));
00128   if (s_hostent.h_addr_list != NULL) {
00129     u8_t idx;
00130     for (idx = 0; s_hostent.h_addr_list[idx]; idx++) {
00131       LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]   == %p\n", idx, s_hostent.h_addr_list[idx]));
00132       LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ipaddr_ntoa((ip_addr_t *)s_hostent.h_addr_list[idx])));
00133     }
00134   }
00135 #endif /* DNS_DEBUG */
00136 
00137 #if LWIP_DNS_API_HOSTENT_STORAGE
00138   /* this function should return the "per-thread" hostent after copy from s_hostent */
00139   return sys_thread_hostent(&s_hostent);
00140 #else
00141   return &s_hostent;
00142 #endif /* LWIP_DNS_API_HOSTENT_STORAGE */
00143 }
00144 
00145 /**
00146  * Thread-safe variant of lwip_gethostbyname: instead of using a static
00147  * buffer, this function takes buffer and errno pointers as arguments
00148  * and uses these for the result.
00149  *
00150  * @param name the hostname to resolve
00151  * @param ret pre-allocated struct where to store the result
00152  * @param buf pre-allocated buffer where to store additional data
00153  * @param buflen the size of buf
00154  * @param result pointer to a hostent pointer that is set to ret on success
00155  *               and set to zero on error
00156  * @param h_errnop pointer to an int where to store errors (instead of modifying
00157  *                 the global h_errno)
00158  * @return 0 on success, non-zero on error, additional error information
00159  *         is stored in *h_errnop instead of h_errno to be thread-safe
00160  */
00161 int
00162 lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
00163                      size_t buflen, struct hostent **result, int *h_errnop)
00164 {
00165   err_t err;
00166   struct gethostbyname_r_helper *h;
00167   char *hostname;
00168   size_t namelen;
00169   int lh_errno;
00170 
00171   if (h_errnop == NULL) {
00172     /* ensure h_errnop is never NULL */
00173     h_errnop = &lh_errno;
00174   }
00175 
00176   if (result == NULL) {
00177     /* not all arguments given */
00178     *h_errnop = EINVAL;
00179     return -1;
00180   }
00181   /* first thing to do: set *result to nothing */
00182   *result = NULL;
00183   if ((name == NULL) || (ret == NULL) || (buf == NULL)) {
00184     /* not all arguments given */
00185     *h_errnop = EINVAL;
00186     return -1;
00187   }
00188 
00189   namelen = strlen(name);
00190   if (buflen < (sizeof(struct gethostbyname_r_helper) + LWIP_MEM_ALIGN_BUFFER(namelen + 1))) {
00191     /* buf can't hold the data needed + a copy of name */
00192     *h_errnop = ERANGE;
00193     return -1;
00194   }
00195 
00196   h = (struct gethostbyname_r_helper *)LWIP_MEM_ALIGN(buf);
00197   hostname = ((char *)h) + sizeof(struct gethostbyname_r_helper);
00198 
00199   /* query host IP address */
00200   err = netconn_gethostbyname(name, &h->addr);
00201   if (err != ERR_OK) {
00202     LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
00203     *h_errnop = HOST_NOT_FOUND;
00204     return -1;
00205   }
00206 
00207   /* copy the hostname into buf */
00208   MEMCPY(hostname, name, namelen);
00209   hostname[namelen] = 0;
00210 
00211   /* fill hostent */
00212   h->addr_list[0] = &h->addr;
00213   h->addr_list[1] = NULL;
00214   h->aliases = NULL;
00215   ret->h_name = hostname;
00216   ret->h_aliases = &h->aliases;
00217   ret->h_addrtype = AF_INET;
00218   ret->h_length = sizeof(ip_addr_t);
00219   ret->h_addr_list = (char **)&h->addr_list;
00220 
00221   /* set result != NULL */
00222   *result = ret;
00223 
00224   /* return success */
00225   return 0;
00226 }
00227 
00228 /**
00229  * Frees one or more addrinfo structures returned by getaddrinfo(), along with
00230  * any additional storage associated with those structures. If the ai_next field
00231  * of the structure is not null, the entire list of structures is freed.
00232  *
00233  * @param ai struct addrinfo to free
00234  */
00235 void
00236 lwip_freeaddrinfo(struct addrinfo *ai)
00237 {
00238   struct addrinfo *next;
00239 
00240   while (ai != NULL) {
00241     next = ai->ai_next;
00242     memp_free(MEMP_NETDB, ai);
00243     ai = next;
00244   }
00245 }
00246 
00247 /**
00248  * Translates the name of a service location (for example, a host name) and/or
00249  * a service name and returns a set of socket addresses and associated
00250  * information to be used in creating a socket with which to address the
00251  * specified service.
00252  * Memory for the result is allocated internally and must be freed by calling
00253  * lwip_freeaddrinfo()!
00254  *
00255  * Due to a limitation in dns_gethostbyname, only the first address of a
00256  * host is returned.
00257  * Also, service names are not supported (only port numbers)!
00258  *
00259  * @param nodename descriptive name or address string of the host
00260  *                 (may be NULL -> local address)
00261  * @param servname port number as string of NULL
00262  * @param hints structure containing input values that set socktype and protocol
00263  * @param res pointer to a pointer where to store the result (set to NULL on failure)
00264  * @return 0 on success, non-zero on failure
00265  *
00266  * @todo: implement AI_V4MAPPED, AI_ADDRCONFIG
00267  */
00268 int
00269 lwip_getaddrinfo(const char *nodename, const char *servname,
00270                  const struct addrinfo *hints, struct addrinfo **res)
00271 {
00272   err_t err;
00273   ip_addr_t addr;
00274   struct addrinfo *ai;
00275   struct sockaddr_storage *sa = NULL;
00276   int port_nr = 0;
00277   size_t total_size;
00278   size_t namelen = 0;
00279   int ai_family;
00280 
00281   if (res == NULL) {
00282     return EAI_FAIL;
00283   }
00284   *res = NULL;
00285   if ((nodename == NULL) && (servname == NULL)) {
00286     return EAI_NONAME;
00287   }
00288 
00289   if (hints != NULL) {
00290     ai_family = hints->ai_family;
00291     if ((ai_family != AF_UNSPEC)
00292 #if LWIP_IPV4
00293         && (ai_family != AF_INET)
00294 #endif /* LWIP_IPV4 */
00295 #if LWIP_IPV6
00296         && (ai_family != AF_INET6)
00297 #endif /* LWIP_IPV6 */
00298        ) {
00299       return EAI_FAMILY;
00300     }
00301   } else {
00302     ai_family = AF_UNSPEC;
00303   }
00304 
00305   if (servname != NULL) {
00306     /* service name specified: convert to port number
00307      * @todo?: currently, only ASCII integers (port numbers) are supported (AI_NUMERICSERV)! */
00308     port_nr = atoi(servname);
00309     if ((port_nr <= 0) || (port_nr > 0xffff)) {
00310       return EAI_SERVICE;
00311     }
00312   }
00313 
00314   if (nodename != NULL) {
00315     /* service location specified, try to resolve */
00316     if ((hints != NULL) && (hints->ai_flags & AI_NUMERICHOST)) {
00317       /* no DNS lookup, just parse for an address string */
00318       if (!ipaddr_aton(nodename, &addr)) {
00319         return EAI_NONAME;
00320       }
00321 #if LWIP_IPV4 && LWIP_IPV6
00322       if ((IP_IS_V6_VAL(addr) && ai_family == AF_INET) ||
00323           (IP_IS_V4_VAL(addr) && ai_family == AF_INET6)) {
00324         return EAI_NONAME;
00325       }
00326 #endif /* LWIP_IPV4 && LWIP_IPV6 */
00327     } else {
00328 #if LWIP_IPV4 && LWIP_IPV6
00329       /* AF_UNSPEC: prefer IPv4 */
00330       u8_t type = NETCONN_DNS_IPV4_IPV6;
00331       if (ai_family == AF_INET) {
00332         type = NETCONN_DNS_IPV4;
00333       } else if (ai_family == AF_INET6) {
00334         type = NETCONN_DNS_IPV6;
00335       }
00336 #endif /* LWIP_IPV4 && LWIP_IPV6 */
00337       err = netconn_gethostbyname_addrtype(nodename, &addr, type);
00338       if (err != ERR_OK) {
00339         return EAI_FAIL;
00340       }
00341     }
00342   } else {
00343     /* service location specified, use loopback address */
00344     if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) {
00345       ip_addr_set_any_val(ai_family == AF_INET6, addr);
00346     } else {
00347       ip_addr_set_loopback_val(ai_family == AF_INET6, addr);
00348     }
00349   }
00350 
00351   total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage);
00352   if (nodename != NULL) {
00353     namelen = strlen(nodename);
00354     if (namelen > DNS_MAX_NAME_LENGTH) {
00355       /* invalid name length */
00356       return EAI_FAIL;
00357     }
00358     LWIP_ASSERT("namelen is too long", total_size + namelen + 1 > total_size);
00359     total_size += namelen + 1;
00360   }
00361   /* If this fails, please report to lwip-devel! :-) */
00362   LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!",
00363               total_size <= NETDB_ELEM_SIZE);
00364   ai = (struct addrinfo *)memp_malloc(MEMP_NETDB);
00365   if (ai == NULL) {
00366     return EAI_MEMORY;
00367   }
00368   memset(ai, 0, total_size);
00369   /* cast through void* to get rid of alignment warnings */
00370   sa = (struct sockaddr_storage *)(void *)((u8_t *)ai + sizeof(struct addrinfo));
00371   if (IP_IS_V6_VAL(addr)) {
00372 #if LWIP_IPV6
00373     struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
00374     /* set up sockaddr */
00375     inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr));
00376     sa6->sin6_family = AF_INET6;
00377     sa6->sin6_len = sizeof(struct sockaddr_in6);
00378     sa6->sin6_port = lwip_htons((u16_t)port_nr);
00379     sa6->sin6_scope_id = ip6_addr_zone(ip_2_ip6(&addr));
00380     ai->ai_family = AF_INET6;
00381 #endif /* LWIP_IPV6 */
00382   } else {
00383 #if LWIP_IPV4
00384     struct sockaddr_in *sa4 = (struct sockaddr_in *)sa;
00385     /* set up sockaddr */
00386     inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr));
00387     sa4->sin_family = AF_INET;
00388     sa4->sin_len = sizeof(struct sockaddr_in);
00389     sa4->sin_port = lwip_htons((u16_t)port_nr);
00390     ai->ai_family = AF_INET;
00391 #endif /* LWIP_IPV4 */
00392   }
00393 
00394   /* set up addrinfo */
00395   if (hints != NULL) {
00396     /* copy socktype & protocol from hints if specified */
00397     ai->ai_socktype = hints->ai_socktype;
00398     ai->ai_protocol = hints->ai_protocol;
00399   }
00400   if (nodename != NULL) {
00401     /* copy nodename to canonname if specified */
00402     ai->ai_canonname = ((char *)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage));
00403     MEMCPY(ai->ai_canonname, nodename, namelen);
00404     ai->ai_canonname[namelen] = 0;
00405   }
00406   ai->ai_addrlen = sizeof(struct sockaddr_storage);
00407   ai->ai_addr = (struct sockaddr *)sa;
00408 
00409   *res = ai;
00410 
00411   return 0;
00412 }
00413 
00414 #endif /* LWIP_DNS && LWIP_SOCKET */