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.
Fork of OmniWheels by
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) + namelen + 1 + (MEM_ALIGNMENT - 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(ai_family == AF_INET6, &addr); 00346 } else { 00347 ip_addr_set_loopback(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 ai->ai_family = AF_INET6; 00380 #endif /* LWIP_IPV6 */ 00381 } else { 00382 #if LWIP_IPV4 00383 struct sockaddr_in *sa4 = (struct sockaddr_in*)sa; 00384 /* set up sockaddr */ 00385 inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr)); 00386 sa4->sin_family = AF_INET; 00387 sa4->sin_len = sizeof(struct sockaddr_in); 00388 sa4->sin_port = lwip_htons((u16_t)port_nr); 00389 ai->ai_family = AF_INET; 00390 #endif /* LWIP_IPV4 */ 00391 } 00392 00393 /* set up addrinfo */ 00394 if (hints != NULL) { 00395 /* copy socktype & protocol from hints if specified */ 00396 ai->ai_socktype = hints->ai_socktype; 00397 ai->ai_protocol = hints->ai_protocol; 00398 } 00399 if (nodename != NULL) { 00400 /* copy nodename to canonname if specified */ 00401 ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage)); 00402 MEMCPY(ai->ai_canonname, nodename, namelen); 00403 ai->ai_canonname[namelen] = 0; 00404 } 00405 ai->ai_addrlen = sizeof(struct sockaddr_storage); 00406 ai->ai_addr = (struct sockaddr*)sa; 00407 00408 *res = ai; 00409 00410 return 0; 00411 } 00412 00413 #endif /* LWIP_DNS && LWIP_SOCKET */
Generated on Fri Jul 22 2022 04:53:52 by
1.7.2
