Example #1
0
static void
ping_send(int s, const ip_addr_t *addr)
{
  struct icmp_echo_hdr *iecho;
  struct sockaddr_storage to;

  if (!(iecho = (struct icmp_echo_hdr *)malloc(sizeof(struct icmp_echo_hdr))))
    return;

  ICMPH_TYPE_SET(iecho,ICMP_ECHO);
  iecho->chksum = 0;
  iecho->seqno  = htons(seq_num);
  iecho->chksum = inet_chksum(iecho, sizeof(*iecho));

#if LWIP_IPV4
  if(!IP_IS_V6(addr)) {
    struct sockaddr_in *to4 = (struct sockaddr_in*)&to;
    to4->sin_len    = sizeof(to);
    to4->sin_family = AF_INET;
    inet_addr_from_ipaddr(&to4->sin_addr, ip_2_ip4(addr));
  }
#endif /* LWIP_IPV4 */

#if LWIP_IPV6
  if(IP_IS_V6(addr)) {
    struct sockaddr_in6 *to6 = (struct sockaddr_in6*)&to;
    to6->sin6_len    = sizeof(to);
    to6->sin6_family = AF_INET6;
    inet6_addr_from_ip6addr(&to6->sin6_addr, ip_2_ip6(addr));
  }
#endif /* LWIP_IPV6 */

  lwip_sendto(s, iecho, sizeof(*iecho), 0, (struct sockaddr*)&to, sizeof(to));

  free(iecho);
  seq_num++;
}
Example #2
0
/**
 * Translates the name of a service location (for example, a host name) and/or
 * a service name and returns a set of socket addresses and associated
 * information to be used in creating a socket with which to address the
 * specified service.
 * Memory for the result is allocated internally and must be freed by calling
 * lwip_freeaddrinfo()!
 *
 * Due to a limitation in dns_gethostbyname, only the first address of a
 * host is returned.
 * Also, service names are not supported (only port numbers)!
 *
 * @param nodename descriptive name or address string of the host
 *                 (may be NULL -> local address)
 * @param servname port number as string of NULL
 * @param hints structure containing input values that set socktype and protocol
 * @param res pointer to a pointer where to store the result (set to NULL on failure)
 * @return 0 on success, non-zero on failure
 *
 * @todo: implement AI_V4MAPPED, AI_ADDRCONFIG
 */
int
lwip_getaddrinfo(const char *nodename, const char *servname,
       const struct addrinfo *hints, struct addrinfo **res)
{
  err_t err;
  ip_addr_t addr;
  struct addrinfo *ai;
  struct sockaddr_storage *sa = NULL;
  int port_nr = 0;
  size_t total_size;
  size_t namelen = 0;
  int ai_family;

  if (res == NULL) {
    return EAI_FAIL;
  }
  *res = NULL;
  if ((nodename == NULL) && (servname == NULL)) {
    return EAI_NONAME;
  }

  if (hints != NULL) {
    ai_family = hints->ai_family;
    if ((ai_family != AF_UNSPEC)
#if LWIP_IPV4
      && (ai_family != AF_INET)
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
      && (ai_family != AF_INET6)
#endif /* LWIP_IPV6 */
      ) {
      return EAI_FAMILY;
    }
  } else {
    ai_family = AF_UNSPEC;
  }

  if (servname != NULL) {
    /* service name specified: convert to port number
     * @todo?: currently, only ASCII integers (port numbers) are supported (AI_NUMERICSERV)! */
    port_nr = atoi(servname);
    if ((port_nr <= 0) || (port_nr > 0xffff)) {
      return EAI_SERVICE;
    }
  }

  if (nodename != NULL) {
    /* service location specified, try to resolve */
    if ((hints != NULL) && (hints->ai_flags & AI_NUMERICHOST)) {
      /* no DNS lookup, just parse for an address string */
      if (!ipaddr_aton(nodename, &addr)) {
        return EAI_NONAME;
      }
#if LWIP_IPV4 && LWIP_IPV6
      if ((IP_IS_V6_VAL(addr) && ai_family == AF_INET) ||
          (IP_IS_V4_VAL(addr) && ai_family == AF_INET6)) {
        return EAI_NONAME;
      }
#endif /* LWIP_IPV4 && LWIP_IPV6 */
    } else {
#if LWIP_IPV4 && LWIP_IPV6
      /* AF_UNSPEC: prefer IPv4 */
      u8_t type = NETCONN_DNS_IPV4_IPV6;
      if (ai_family == AF_INET) {
        type = NETCONN_DNS_IPV4;
      } else if (ai_family == AF_INET6) {
        type = NETCONN_DNS_IPV6;
      }
#endif /* LWIP_IPV4 && LWIP_IPV6 */
      err = netconn_gethostbyname_addrtype(nodename, &addr, type);
      if (err != ERR_OK) {
        return EAI_FAIL;
      }
    }
  } else {
    /* service location specified, use loopback address */
    if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) {
      ip_addr_set_any(ai_family == AF_INET6, &addr);
    } else {
      ip_addr_set_loopback(ai_family == AF_INET6, &addr);
    }
  }

  total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage);
  if (nodename != NULL) {
    namelen = strlen(nodename);
    if (namelen > DNS_MAX_NAME_LENGTH) {
      /* invalid name length */
      return EAI_FAIL;
    }
    LWIP_ASSERT("namelen is too long", total_size + namelen + 1 > total_size);
    total_size += namelen + 1;
  }
  /* If this fails, please report to lwip-devel! :-) */
  LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!",
    total_size <= NETDB_ELEM_SIZE);
  ai = (struct addrinfo *)memp_malloc(MEMP_NETDB);
  if (ai == NULL) {
    return EAI_MEMORY;
  }
  memset(ai, 0, total_size);
  /* cast through void* to get rid of alignment warnings */
  sa = (struct sockaddr_storage *)(void*)((u8_t*)ai + sizeof(struct addrinfo));
  if (IP_IS_V6_VAL(addr)) {
#if LWIP_IPV6
    struct sockaddr_in6 *sa6 = (struct sockaddr_in6*)sa;
    /* set up sockaddr */
    inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr));
    sa6->sin6_family = AF_INET6;
    sa6->sin6_len = sizeof(struct sockaddr_in6);
    sa6->sin6_port = lwip_htons((u16_t)port_nr);
    ai->ai_family = AF_INET6;
#endif /* LWIP_IPV6 */
  } else {
#if LWIP_IPV4
    struct sockaddr_in *sa4 = (struct sockaddr_in*)sa;
    /* set up sockaddr */
    inet4_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr));
    sa4->sin_family = AF_INET;
    sa4->sin_len = sizeof(struct sockaddr_in);
    sa4->sin_port = lwip_htons((u16_t)port_nr);
    ai->ai_family = AF_INET;
#endif /* LWIP_IPV4 */
  }

  /* set up addrinfo */
  if (hints != NULL) {
    /* copy socktype & protocol from hints if specified */
    ai->ai_socktype = hints->ai_socktype;
    ai->ai_protocol = hints->ai_protocol;
  }
  if (nodename != NULL) {
    /* copy nodename to canonname if specified */
    ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage));
    MEMCPY(ai->ai_canonname, nodename, namelen);
    ai->ai_canonname[namelen] = 0;
  }
  ai->ai_addrlen = sizeof(struct sockaddr_storage);
  ai->ai_addr = (struct sockaddr*)sa;

  *res = ai;

  return 0;
}