SAMV71 Xplained Ultra Software Package 1.0

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/ip_addr.h"
00043 #include "lwip/api.h"
00044 
00045 #include <string.h>
00046 #include <stdlib.h>
00047 
00048 /** helper struct for gethostbyname_r to access the char* buffer */
00049 struct gethostbyname_r_helper {
00050   struct ip_addr *addrs;
00051   struct ip_addr addr;
00052   char *aliases;
00053 };
00054 
00055 /** h_errno is exported in netdb.h for access by applications. */
00056 #if LWIP_DNS_API_DECLARE_H_ERRNO
00057 int h_errno;
00058 #endif /* LWIP_DNS_API_DECLARE_H_ERRNO */
00059 
00060 /** define "hostent" variables storage: 0 if we use a static (but unprotected)
00061  * set of variables for lwip_gethostbyname, 1 if we use a local storage */
00062 #ifndef LWIP_DNS_API_HOSTENT_STORAGE
00063 #define LWIP_DNS_API_HOSTENT_STORAGE 0
00064 #endif
00065 
00066 /** define "hostent" variables storage */
00067 #if LWIP_DNS_API_HOSTENT_STORAGE
00068 #define HOSTENT_STORAGE
00069 #else
00070 #define HOSTENT_STORAGE static
00071 #endif /* LWIP_DNS_API_STATIC_HOSTENT */
00072 
00073 /**
00074  * Returns an entry containing addresses of address family AF_INET
00075  * for the host with name name.
00076  * Due to dns_gethostbyname limitations, only one address is returned.
00077  *
00078  * @param name the hostname to resolve
00079  * @return an entry containing addresses of address family AF_INET
00080  *         for the host with name name
00081  */
00082 struct hostent*
00083 lwip_gethostbyname(const char *name)
00084 {
00085   err_t err;
00086   struct ip_addr addr;
00087 
00088   /* buffer variables for lwip_gethostbyname() */
00089   HOSTENT_STORAGE struct hostent s_hostent;
00090   HOSTENT_STORAGE char *s_aliases;
00091   HOSTENT_STORAGE struct ip_addr s_hostent_addr;
00092   HOSTENT_STORAGE struct ip_addr *s_phostent_addr;
00093 
00094   /* query host IP address */
00095   err = netconn_gethostbyname(name, &addr);
00096   if (err != ERR_OK) {
00097     LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
00098     h_errno = HOST_NOT_FOUND;
00099     return NULL;
00100   }
00101 
00102   /* fill hostent */
00103   s_hostent_addr = addr;
00104   s_phostent_addr = &s_hostent_addr;
00105   s_hostent.h_name = (char*)name;
00106   s_hostent.h_aliases = &s_aliases;
00107   s_hostent.h_addrtype = AF_INET;
00108   s_hostent.h_length = sizeof(struct ip_addr);
00109   s_hostent.h_addr_list = (char**)&s_phostent_addr;
00110 
00111 #if DNS_DEBUG
00112   /* dump hostent */
00113   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name           == %s\n", s_hostent.h_name));
00114   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases        == %p\n", s_hostent.h_aliases));
00115   if (s_hostent.h_aliases != NULL) {
00116     u8_t idx;
00117     for ( idx=0; s_hostent.h_aliases[idx]; idx++) {
00118       LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == %p\n", idx, s_hostent.h_aliases[idx]));
00119       LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == %s\n", idx, s_hostent.h_aliases[idx]));
00120     }
00121   }
00122   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype       == %d\n", s_hostent.h_addrtype));
00123   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length         == %d\n", s_hostent.h_length));
00124   LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list      == %p\n", s_hostent.h_addr_list));
00125   if (s_hostent.h_addr_list != NULL) {
00126     u8_t idx;
00127     for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {
00128       LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]   == %p\n", idx, s_hostent.h_addr_list[idx]));
00129       LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ip_ntoa(s_hostent.h_addr_list[idx])));
00130     }
00131   }
00132 #endif /* DNS_DEBUG */
00133 
00134 #if LWIP_DNS_API_HOSTENT_STORAGE
00135   /* this function should return the "per-thread" hostent after copy from s_hostent */
00136   return sys_thread_hostent(&s_hostent);
00137 #else
00138   return &s_hostent;
00139 #endif /* LWIP_DNS_API_HOSTENT_STORAGE */
00140 }
00141 
00142 /**
00143  * Thread-safe variant of lwip_gethostbyname: instead of using a static
00144  * buffer, this function takes buffer and errno pointers as arguments
00145  * and uses these for the result.
00146  *
00147  * @param name the hostname to resolve
00148  * @param ret pre-allocated struct where to store the result
00149  * @param buf pre-allocated buffer where to store additional data
00150  * @param buflen the size of buf
00151  * @param result pointer to a hostent pointer that is set to ret on success
00152  *               and set to zero on error
00153  * @param h_errnop pointer to an int where to store errors (instead of modifying
00154  *                 the global h_errno)
00155  * @return 0 on success, non-zero on error, additional error information
00156  *         is stored in *h_errnop instead of h_errno to be thread-safe
00157  */
00158 int
00159 lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
00160                 size_t buflen, struct hostent **result, int *h_errnop)
00161 {
00162   err_t err;
00163   struct gethostbyname_r_helper *h;
00164   char *hostname;
00165   size_t namelen;
00166   int lh_errno;
00167 
00168   if (h_errnop == NULL) {
00169     /* ensure h_errnop is never NULL */
00170     h_errnop = &lh_errno;
00171   }
00172 
00173   if (result == NULL) {
00174     /* not all arguments given */
00175     *h_errnop = EINVAL;
00176     return -1;
00177   }
00178   /* first thing to do: set *result to nothing */
00179   *result = NULL;
00180   if ((name == NULL) || (ret == NULL) || (buf == 0)) {
00181     /* not all arguments given */
00182     *h_errnop = EINVAL;
00183     return -1;
00184   }
00185 
00186   namelen = strlen(name);
00187   if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) {
00188     /* buf can't hold the data needed + a copy of name */
00189     *h_errnop = ERANGE;
00190     return -1;
00191   }
00192 
00193   h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf);
00194   hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper);
00195 
00196   /* query host IP address */
00197   err = netconn_gethostbyname(name, &(h->addr));
00198   if (err != ERR_OK) {
00199     LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
00200     *h_errnop = ENSRNOTFOUND;
00201     return -1;
00202   }
00203 
00204   /* copy the hostname into buf */
00205   MEMCPY(hostname, name, namelen);
00206   hostname[namelen] = 0;
00207 
00208   /* fill hostent */
00209   h->addrs = &(h->addr);
00210   h->aliases = NULL;
00211   ret->h_name = (char*)hostname;
00212   ret->h_aliases = &(h->aliases);
00213   ret->h_addrtype = AF_INET;
00214   ret->h_length = sizeof(struct ip_addr);
00215   ret->h_addr_list = (char**)&(h->addrs);
00216 
00217   /* set result != NULL */
00218   *result = ret;
00219 
00220   /* return success */
00221   return 0;
00222 }
00223 
00224 /**
00225  * Frees one or more addrinfo structures returned by getaddrinfo(), along with
00226  * any additional storage associated with those structures. If the ai_next field
00227  * of the structure is not null, the entire list of structures is freed.
00228  *
00229  * @param ai struct addrinfo to free
00230  */
00231 void
00232 lwip_freeaddrinfo(struct addrinfo *ai)
00233 {
00234   struct addrinfo *next;
00235 
00236   while (ai != NULL) {
00237     next = ai->ai_next;
00238     mem_free(ai);
00239     ai = next;
00240   }
00241 }
00242 
00243 /**
00244  * Translates the name of a service location (for example, a host name) and/or
00245  * a service name and returns a set of socket addresses and associated
00246  * information to be used in creating a socket with which to address the
00247  * specified service.
00248  * Memory for the result is allocated internally and must be freed by calling
00249  * lwip_freeaddrinfo()!
00250  *
00251  * Due to a limitation in dns_gethostbyname, only the first address of a
00252  * host is returned.
00253  * Also, service names are not supported (only port numbers)!
00254  *
00255  * @param nodename descriptive name or address string of the host
00256  *                 (may be NULL -> local address)
00257  * @param servname port number as string of NULL 
00258  * @param hints structure containing input values that set socktype and protocol
00259  * @param res pointer to a pointer where to store the result (set to NULL on failure)
00260  * @return 0 on success, non-zero on failure
00261  */
00262 int
00263 lwip_getaddrinfo(const char *nodename, const char *servname,
00264        const struct addrinfo *hints, struct addrinfo **res)
00265 {
00266   err_t err;
00267   struct ip_addr addr;
00268   struct addrinfo *ai;
00269   struct sockaddr_in *sa = NULL;
00270   int port_nr = 0;
00271   size_t total_size;
00272   size_t namelen = 0;
00273 
00274   if (res == NULL) {
00275     return EAI_FAIL;
00276   }
00277   *res = NULL;
00278   if ((nodename == NULL) && (servname == NULL)) {
00279     return EAI_NONAME;
00280   }
00281 
00282   if (servname != NULL) {
00283     /* service name specified: convert to port number
00284      * @todo?: currently, only ASCII integers (port numbers) are supported! */
00285     port_nr = atoi(servname);
00286     if ((port_nr <= 0) || (port_nr > 0xffff)) {
00287       return EAI_SERVICE;
00288     }
00289   }
00290 
00291   if (nodename != NULL) {
00292     /* service location specified, try to resolve */
00293     err = netconn_gethostbyname(nodename, &addr);
00294     if (err != ERR_OK) {
00295       return EAI_FAIL;
00296     }
00297   } else {
00298     /* service location specified, use loopback address */
00299     addr.addr = htonl(INADDR_LOOPBACK);
00300   }
00301 
00302   total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
00303   if (nodename != NULL) {
00304     namelen = strlen(nodename);
00305     LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1);
00306     total_size += namelen + 1;
00307   }
00308   ai = mem_malloc(total_size);
00309   if (ai == NULL) {
00310     goto memerr;
00311   }
00312   memset(ai, 0, total_size);
00313   sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo));
00314   /* set up sockaddr */
00315   sa->sin_addr.s_addr = addr.addr;
00316   sa->sin_family = AF_INET;
00317   sa->sin_len = sizeof(struct sockaddr_in);
00318   sa->sin_port = htons(port_nr);
00319 
00320   /* set up addrinfo */
00321   ai->ai_family = AF_INET;
00322   if (hints != NULL) {
00323     /* copy socktype & protocol from hints if specified */
00324     ai->ai_socktype = hints->ai_socktype;
00325     ai->ai_protocol = hints->ai_protocol;
00326   }
00327   if (nodename != NULL) {
00328     /* copy nodename to canonname if specified */
00329     ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
00330     MEMCPY(ai->ai_canonname, nodename, namelen);
00331     ai->ai_canonname[namelen] = 0;
00332   }
00333   ai->ai_addrlen = sizeof(struct sockaddr_in);
00334   ai->ai_addr = (struct sockaddr*)sa;
00335 
00336   *res = ai;
00337 
00338   return 0;
00339 memerr:
00340   if (ai != NULL) {
00341     mem_free(ai);
00342   }
00343   return EAI_MEMORY;
00344 }
00345 
00346 #endif /* LWIP_DNS && LWIP_SOCKET */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines