Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
lwip_netdb.c
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 */
Generated on Tue Jul 12 2022 13:54:29 by
