Official mbed lwIP library (version 1.4.0)

Dependents:   LwIPNetworking NetServicesMin EthernetInterface EthernetInterface_RSF ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers netdb.c Source File

netdb.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * API functions for name resolving
00004  *
00005  */
00006 
00007 /*
00008  * Redistribution and use in source and binary forms, with or without modification, 
00009  * are permitted provided that the following conditions are met:
00010  *
00011  * 1. Redistributions of source code must retain the above copyright notice,
00012  *    this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright notice,
00014  *    this list of conditions and the following disclaimer in the documentation
00015  *    and/or other materials provided with the distribution.
00016  * 3. The name of the author may not be used to endorse or promote products
00017  *    derived from this software without specific prior written permission. 
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
00020  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
00021  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
00022  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00023  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
00024  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
00025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
00026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
00027  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
00028  * OF SUCH DAMAGE.
00029  *
00030  * This file is part of the lwIP TCP/IP stack.
00031  * 
00032  * Author: Simon Goldschmidt
00033  *
00034  */
00035 
00036 #include "lwip/netdb.h"
00037 
00038 #if LWIP_DNS && LWIP_SOCKET
00039 
00040 #include "lwip/err.h"
00041 #include "lwip/mem.h"
00042 #include "lwip/memp.h"
00043 #include "lwip/ip_addr.h"
00044 #include "lwip/api.h"
00045 #include "lwip/dns.h"
00046 
00047 #include <string.h>
00048 #include <stdlib.h>
00049 
00050 /** helper struct for gethostbyname_r to access the char* buffer */
00051 struct gethostbyname_r_helper {
00052   ip_addr_t *addrs;
00053   ip_addr_t addr;
00054   char *aliases;
00055 };
00056 
00057 /** h_errno is exported in netdb.h for access by applications. */
00058 #if LWIP_DNS_API_DECLARE_H_ERRNO
00059 int h_errno;
00060 #endif /* LWIP_DNS_API_DECLARE_H_ERRNO */
00061 
00062 /** define "hostent" variables storage: 0 if we use a static (but unprotected)
00063  * set of variables for lwip_gethostbyname, 1 if we use a local storage */
00064 #ifndef LWIP_DNS_API_HOSTENT_STORAGE
00065 #define LWIP_DNS_API_HOSTENT_STORAGE 0
00066 #endif
00067 
00068 /** define "hostent" variables storage */
00069 #if LWIP_DNS_API_HOSTENT_STORAGE
00070 #define HOSTENT_STORAGE
00071 #else
00072 #define HOSTENT_STORAGE static
00073 #endif /* LWIP_DNS_API_STATIC_HOSTENT */
00074 
00075 /**
00076  * Returns an entry containing addresses of address family AF_INET
00077  * for the host with name name.
00078  * Due to dns_gethostbyname limitations, only one address is returned.
00079  *
00080  * @param name the hostname to resolve
00081  * @return an entry containing addresses of address family AF_INET
00082  *         for the host with name name
00083  */
00084 struct hostent*
00085 lwip_gethostbyname(const char *name)
00086 {
00087   err_t err;
00088   ip_addr_t addr;
00089 
00090   /* buffer variables for lwip_gethostbyname() */
00091   HOSTENT_STORAGE struct hostent s_hostent;
00092   HOSTENT_STORAGE char *s_aliases;
00093   HOSTENT_STORAGE ip_addr_t s_hostent_addr;
00094   HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2];
00095 
00096   /* query host IP address */
00097   err = netconn_gethostbyname(name, &addr);
00098   if (err != ERR_OK) {
00099     LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
00100     h_errno = HOST_NOT_FOUND;
00101     return NULL;
00102   }
00103 
00104   /* fill hostent */
00105   s_hostent_addr = addr;
00106   s_phostent_addr[0] = &s_hostent_addr;
00107   s_phostent_addr[1] = NULL;
00108   s_hostent.h_name = (char*)name;
00109   s_hostent.h_aliases = &s_aliases;
00110   s_hostent.h_addrtype = AF_INET;
00111   s_hostent.h_length = sizeof(ip_addr_t);
00112   s_hostent.h_addr_list = (char**)&s_phostent_addr;
00113 
00114 #if DNS_DEBUG
00115   /* dump hostent */
00116   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name           == %s\n", s_hostent.h_name));
00117   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases        == %p\n", s_hostent.h_aliases));
00118   if (s_hostent.h_aliases != NULL) {
00119     u8_t idx;
00120     for ( idx=0; s_hostent.h_aliases[idx]; idx++) {
00121       LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == %p\n", idx, s_hostent.h_aliases[idx]));
00122       LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == %s\n", idx, s_hostent.h_aliases[idx]));
00123     }
00124   }
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", 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, ip_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 == 0)) {
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 = ENSRNOTFOUND;
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->addrs = &(h->addr);
00213   h->aliases = NULL;
00214   ret->h_name = (char*)hostname;
00215   ret->h_aliases = &(h->aliases);
00216   ret->h_addrtype = AF_INET;
00217   ret->h_length = sizeof(ip_addr_t);
00218   ret->h_addr_list = (char**)&(h->addrs);
00219 
00220   /* set result != NULL */
00221   *result = ret;
00222 
00223   /* return success */
00224   return 0;
00225 }
00226 
00227 /**
00228  * Frees one or more addrinfo structures returned by getaddrinfo(), along with
00229  * any additional storage associated with those structures. If the ai_next field
00230  * of the structure is not null, the entire list of structures is freed.
00231  *
00232  * @param ai struct addrinfo to free
00233  */
00234 void
00235 lwip_freeaddrinfo(struct addrinfo *ai)
00236 {
00237   struct addrinfo *next;
00238 
00239   while (ai != NULL) {
00240     next = ai->ai_next;
00241     memp_free(MEMP_NETDB, ai);
00242     ai = next;
00243   }
00244 }
00245 
00246 /**
00247  * Translates the name of a service location (for example, a host name) and/or
00248  * a service name and returns a set of socket addresses and associated
00249  * information to be used in creating a socket with which to address the
00250  * specified service.
00251  * Memory for the result is allocated internally and must be freed by calling
00252  * lwip_freeaddrinfo()!
00253  *
00254  * Due to a limitation in dns_gethostbyname, only the first address of a
00255  * host is returned.
00256  * Also, service names are not supported (only port numbers)!
00257  *
00258  * @param nodename descriptive name or address string of the host
00259  *                 (may be NULL -> local address)
00260  * @param servname port number as string of NULL 
00261  * @param hints structure containing input values that set socktype and protocol
00262  * @param res pointer to a pointer where to store the result (set to NULL on failure)
00263  * @return 0 on success, non-zero on failure
00264  */
00265 int
00266 lwip_getaddrinfo(const char *nodename, const char *servname,
00267        const struct addrinfo *hints, struct addrinfo **res)
00268 {
00269   err_t err;
00270   ip_addr_t addr;
00271   struct addrinfo *ai;
00272   struct sockaddr_in *sa = NULL;
00273   int port_nr = 0;
00274   size_t total_size;
00275   size_t namelen = 0;
00276 
00277   if (res == NULL) {
00278     return EAI_FAIL;
00279   }
00280   *res = NULL;
00281   if ((nodename == NULL) && (servname == NULL)) {
00282     return EAI_NONAME;
00283   }
00284 
00285   if (servname != NULL) {
00286     /* service name specified: convert to port number
00287      * @todo?: currently, only ASCII integers (port numbers) are supported! */
00288     port_nr = atoi(servname);
00289     if ((port_nr <= 0) || (port_nr > 0xffff)) {
00290       return EAI_SERVICE;
00291     }
00292   }
00293 
00294   if (nodename != NULL) {
00295     /* service location specified, try to resolve */
00296     err = netconn_gethostbyname(nodename, &addr);
00297     if (err != ERR_OK) {
00298       return EAI_FAIL;
00299     }
00300   } else {
00301     /* service location specified, use loopback address */
00302     ip_addr_set_loopback(&addr);
00303   }
00304 
00305   total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
00306   if (nodename != NULL) {
00307     namelen = strlen(nodename);
00308     LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1);
00309     total_size += namelen + 1;
00310   }
00311   /* If this fails, please report to lwip-devel! :-) */
00312   LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!",
00313     total_size <= NETDB_ELEM_SIZE);
00314   ai = (struct addrinfo *)memp_malloc(MEMP_NETDB);
00315   if (ai == NULL) {
00316     goto memerr;
00317   }
00318   memset(ai, 0, total_size);
00319   sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo));
00320   /* set up sockaddr */
00321   inet_addr_from_ipaddr(&sa->sin_addr, &addr);
00322   sa->sin_family = AF_INET;
00323   sa->sin_len = sizeof(struct sockaddr_in);
00324   sa->sin_port = htons((u16_t)port_nr);
00325 
00326   /* set up addrinfo */
00327   ai->ai_family = AF_INET;
00328   if (hints != NULL) {
00329     /* copy socktype & protocol from hints if specified */
00330     ai->ai_socktype = hints->ai_socktype;
00331     ai->ai_protocol = hints->ai_protocol;
00332   }
00333   if (nodename != NULL) {
00334     /* copy nodename to canonname if specified */
00335     ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
00336     MEMCPY(ai->ai_canonname, nodename, namelen);
00337     ai->ai_canonname[namelen] = 0;
00338   }
00339   ai->ai_addrlen = sizeof(struct sockaddr_in);
00340   ai->ai_addr = (struct sockaddr*)sa;
00341 
00342   *res = ai;
00343 
00344   return 0;
00345 memerr:
00346   if (ai != NULL) {
00347     memp_free(MEMP_NETDB, ai);
00348   }
00349   return EAI_MEMORY;
00350 }
00351 
00352 #endif /* LWIP_DNS && LWIP_SOCKET */