More IPv6 patches
Andrew Lunn
andrew.lunn@ascom.ch
Thu May 8 07:25:00 GMT 2003
Attached is a big patch for IPv6 related things:
The DNS client can now lookup AAAA records and reverse loopup IPv6 addresses.
The DNS test program has been rewritten to be more strict and do IPv6 tests.
getaddrinfo and getnameinfo have been nearly re-written.
Some more tests for getaddrinfo.
The FTP client is now IPv6 aware and the test program does IPv6 get/puts.
The HTTP server is IPv6 aware. I also added a small test program.
A few minor tweaks where getnameinfo was used without NI_NUMERICHOST.
Andrew
-------------- next part --------------
Index: net//bsd_tcpip/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/bsd_tcpip/current/ChangeLog,v
retrieving revision 1.22
diff -u -r1.22 ChangeLog
--- net//bsd_tcpip/current/ChangeLog 4 May 2003 17:37:28 -0000 1.22
+++ net//bsd_tcpip/current/ChangeLog 8 May 2003 07:12:58 -0000
@@ -6,9 +6,15 @@
on some hardware as the init sequence can totally foul up a
network [debug] connection.
+2003-04-28 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * src/ecos/support.c (cyg_net_malloc): Honour the flag M_ZERO,
+ otherwise we end up with junk where we don't want it.
+
2003-04-11 Michael Checky <Michael_Checky@Thermoking.com>
- * cdl/freebsd_net.cdl: Deleted the 'CYGPKG_NET_FREEBSD_STACK_BUILD_TESTS'
+ * cdl/freebsd_net.cdl: Deleted the
+ 'CYGPKG_NET_FREEBSD_STACK_BUILD_TESTS'
component because these tests are in the net.cdl component
'CYGPKG_NET_BUILD_TESTS' and selecting this option in freebsd_net.cdl
causes build errors.
Index: net//bsd_tcpip/current/src/ecos/support.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/bsd_tcpip/current/src/ecos/support.c,v
retrieving revision 1.7
diff -u -r1.7 support.c
--- net//bsd_tcpip/current/src/ecos/support.c 4 May 2003 17:37:28 -0000 1.7
+++ net//bsd_tcpip/current/src/ecos/support.c 8 May 2003 07:12:58 -0000
@@ -72,6 +72,11 @@
#include <cyg/hal/hal_if.h>
#include <cyg/infra/cyg_ass.h>
+#ifdef CYGPKG_NET_INET6
+#include <netinet/in.h>
+#include <netinet6/in6_var.h>
+#endif
+
#if !CYGPKG_NET_DRIVER_FRAMEWORK // Interface
#error At least one network driver framework must be defined!
#else
@@ -202,6 +207,9 @@
} else {
res = cyg_mempool_var_alloc(net_mem, size);
}
+ if ((flags & M_ZERO) && res) {
+ memset(res,0,size);
+ }
FINISH_STATS(stats_malloc);
log(LOG_MDEBUG, "%p\n", res);
return (res);
@@ -945,17 +953,32 @@
TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
if (ifa->ifa_addr->sa_family != AF_LINK) {
(*pr)("%-8s", name);
- getnameinfo (ifa->ifa_addr, ifa->ifa_addr->sa_len, addr, sizeof(addr), 0, 0, 0);
+ getnameinfo (ifa->ifa_addr, ifa->ifa_addr->sa_len, addr,
+ sizeof(addr), 0, 0, NI_NUMERICHOST);
if (ifa->ifa_addr->sa_family == AF_INET) {
- getnameinfo (ifa->ifa_dstaddr, ifa->ifa_dstaddr->sa_len, broadcast, sizeof(broadcast), 0, 0, 0);
+ getnameinfo (ifa->ifa_dstaddr, ifa->ifa_dstaddr->sa_len,
+ broadcast, sizeof(broadcast),
+ 0, 0, NI_NUMERICHOST);
_mask(ifa->ifa_netmask, netmask, 64);
- (*pr)("IP: %s, Broadcast: %s, Netmask: %s\n", addr, broadcast, netmask);
- }
-#ifdef CYGPKG_NET_INET6
- if (ifa->ifa_addr->sa_family == AF_INET6) {
- _mask6(ifa->ifa_netmask, netmask, 64);
- (*pr)("IP: %s/%s\n", addr,netmask);
+ (*pr)("IP: %s, Broadcast: %s, Netmask: %s\n",
+ addr, broadcast, netmask);
}
+#ifdef CYGPKG_NET_INET6
+ if (ifa->ifa_addr->sa_family == AF_INET6) {
+ struct in6_ifaddr * ifa6 = (struct in6_ifaddr *) ifa;
+ _mask6(ifa->ifa_netmask, netmask, 64);
+ (*pr)("IP: %s/%s ", addr,netmask);
+ if (ifa6->ia6_flags & IN6_IFF_ANYCAST) (*pr) ("Anycast ");
+ if (ifa6->ia6_flags & IN6_IFF_TENTATIVE) (*pr) ("Tentative ");
+ if (ifa6->ia6_flags & IN6_IFF_DUPLICATED) (*pr) ("Duplicate ");
+ if (ifa6->ia6_flags & IN6_IFF_DETACHED) (*pr) ("Detached ");
+ if (ifa6->ia6_flags & IN6_IFF_DEPRECATED) (*pr) ("Deprecated ");
+ if (ifa6->ia6_flags & IN6_IFF_NODAD) (*pr) ("NoDAD ");
+ if (ifa6->ia6_flags & IN6_IFF_AUTOCONF) (*pr) ("AutoConf ");
+ if (ifa6->ia6_flags & IN6_IFF_TEMPORARY) (*pr) ("Tempory ");
+ if (ifa6->ia6_flags & IN6_IFF_HOME) (*pr) ("Home ");
+ (*pr) ("\n");
+ }
#endif
(*pr)(" ");
if ((ifp->if_flags & IFF_UP)) (*pr)("UP ");
@@ -966,8 +989,10 @@
if ((ifp->if_flags & IFF_MULTICAST)) (*pr)("MULTICAST ");
if ((ifp->if_flags & IFF_ALLMULTI)) (*pr)("ALLMULTI ");
(*pr)("MTU: %d, Metric: %d\n", ifp->if_mtu, ifp->if_metric);
- (*pr)(" Rx - Packets: %d, Bytes: %d", ifa->if_data.ifi_ipackets, ifa->if_data.ifi_ibytes);
- (*pr)(", Tx - Packets: %d, Bytes: %d\n", ifa->if_data.ifi_opackets, ifa->if_data.ifi_obytes);
+ (*pr)(" Rx - Packets: %d, Bytes: %d",
+ ifa->if_data.ifi_ipackets, ifa->if_data.ifi_ibytes);
+ (*pr)(", Tx - Packets: %d, Bytes: %d\n",
+ ifa->if_data.ifi_opackets, ifa->if_data.ifi_obytes);
}
}
}
Index: net//common/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/common/current/ChangeLog,v
retrieving revision 1.32
diff -u -r1.32 ChangeLog
--- net//common/current/ChangeLog 23 Apr 2003 23:45:37 -0000 1.32
+++ net//common/current/ChangeLog 8 May 2003 07:12:58 -0000
@@ -1,7 +1,39 @@
+2003-04-26 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * src/getaddrinfo.c (getaddrinfo): Correctly return TCP when it is!
+ * tests/addr_test.c (net_test): Added a test which uses protocol TCP
+ * src/tftp_client.c (tftp_get): If we timeout on the first block,
+ try other addresses for the server if we have any.
+ * src/network_support.c (init_all_network_interfaces): After
+ router solicitation has given us an address, wait a couple of
+ seconds for duplicate address detection to do its work. While DAD
+ is active, we cannot use the new address.
+
2003-04-24 Jonathan Larmour <jifl@eCosCentric.com>
* doc/tcpip.sgml: Fix some docbook errors only reported by certain
Jade versions.
+
+2003-04-24 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * src/tftp_client.c (tftp_client_put): Fixed compiler warning.
+
+2003-04-21 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * src/getaddrinfo.c (getnameinfo): Fixed some endian issues with
+ port numbers and a typo. Added an interface to the DNS client for
+ reverse lookups.
+ * tests/addr_test.c (net_test): Added tests for getnameinfo. Fixed
+ some memory leaks.
+
+2003-04-20 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * src/getaddrinfo.c (getaddrinfo): Virtually a re-write to
+ interface to the DNS client.
+
+2003-04-14 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * include/net/netdb.h: const correctness.
2003-04-12 Andrew Lunn <andrew.lunn@ascom.ch>
Index: net//common/current/include/net/netdb.h
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/common/current/include/net/netdb.h,v
retrieving revision 1.2
diff -u -r1.2 netdb.h
--- net//common/current/include/net/netdb.h 23 May 2002 23:08:03 -0000 1.2
+++ net//common/current/include/net/netdb.h 8 May 2003 07:12:58 -0000
@@ -133,8 +133,8 @@
// Miscellaneous address manipulation functions
#include <netinet/in.h>
char *inet_ntoa(struct in_addr);
-char *inet_ntop(int af, char *src, char *dst, size_t len);
-int inet_pton(int af, char *src, char *dst);
+char *inet_ntop(int af, const char *src, char *dst, size_t len);
+int inet_pton(int af, const char *src, char *dst);
char *_inet_ntop(struct sockaddr *sa, char *dst, size_t len);
u_int16_t _inet_port(struct sockaddr *sa);
Index: net//common/current/src/getaddrinfo.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/common/current/src/getaddrinfo.c,v
retrieving revision 1.4
diff -u -r1.4 getaddrinfo.c
--- net//common/current/src/getaddrinfo.c 23 Apr 2003 08:52:09 -0000 1.4
+++ net//common/current/src/getaddrinfo.c 8 May 2003 07:12:58 -0000
@@ -38,87 +38,232 @@
#include <errno.h>
#include <cyg/infra/cyg_ass.h>
+#include <pkgconf/system.h>
+#ifdef CYGPKG_NS_DNS
+#include <pkgconf/ns_dns.h>
+#include <cyg/ns/dns/dns.h>
+#endif
+
extern int sprintf(char *, const char *, ...);
extern long strtol(const char *, char **, int);
extern void *malloc(size_t);
extern void *calloc(int, size_t);
extern void free(void *);
-// This routine is the real meat of the host->address translation
+// Allocate a new addrinfo structure and if passed an existing
+// addrinfo copy all the port, protocol info into the new structure
+// and then link the new onto the old.
+
+struct addrinfo * alloc_addrinfo(struct addrinfo * ai) {
+
+ struct addrinfo * nai;
+ struct sockaddr * sa;
+
+ nai = (struct addrinfo *)malloc(sizeof(struct addrinfo));
+ if (!nai) {
+ return NULL;
+ }
+ sa = (struct sockaddr *) malloc(sizeof(struct sockaddr));
+ if (!sa) {
+ free (nai);
+ return NULL;
+ }
+ memset(sa,0,sizeof(*sa));
+
+ if (ai) {
+ memcpy(nai,ai,sizeof(struct addrinfo));
+ ai->ai_next = nai;
+ } else {
+ memset(nai,0,sizeof(*nai));
+ }
+ nai->ai_addr = sa;
+ nai->ai_addrlen = sizeof(*sa);
+
+ return nai;
+}
+
+// getaddrinfo has not been passed a hostname. So it should use the
+// loopback or the any address.
static int
-_getaddr(struct addrinfo *ai, const char *node,
- const struct addrinfo *hints, int family, int port)
-{
- struct hostent *_hent;
+no_node_addr(struct addrinfo *ai, const struct addrinfo *hints, int port) {
- switch (family) {
- case AF_INET:
- {
- struct sockaddr_in *sa;
- sa = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
- memset(sa, 0, sizeof(*sa));
- ai->ai_addr = (struct sockaddr *)sa;
- ai->ai_addrlen = sizeof(*sa);
- if (ai->ai_addr == (struct sockaddr *)NULL) {
- return EAI_MEMORY;
+ switch (hints->ai_family) {
+ case AF_INET: {
+ struct sockaddr_in *sa = (struct sockaddr_in *) ai->ai_addr;
+ if (hints->ai_flags & AI_PASSIVE) {
+ sa->sin_addr.s_addr = htonl(INADDR_ANY);
+ } else {
+ sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
}
- sa->sin_family = AF_INET;
sa->sin_len = sizeof(*sa);
sa->sin_port = htons(port);
- if (node == (char *)NULL) {
- if (hints->ai_flags & AI_PASSIVE) {
- sa->sin_addr.s_addr = htonl(INADDR_ANY);
- } else {
-#ifdef CYGPKG_NET_OPENBSD_STACK
- sa->sin_addr.s_addr = INADDR_LOOPBACK;
-#else
- sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ sa->sin_family = AF_INET;
+ ai->ai_family = AF_INET;
+ break;
+ }
+#ifdef CYGPKG_NET_INET6
+ case AF_INET6: {
+ struct sockaddr_in6 *sa = (struct sockaddr_in6 *) ai->ai_addr;
+ if (hints->ai_flags & AI_PASSIVE) {
+ memcpy(&sa->sin6_addr, &in6addr_any, sizeof(sa->sin6_addr));
+ } else {
+ memcpy(&sa->sin6_addr, &in6addr_loopback, sizeof(sa->sin6_addr));
+ }
+ sa->sin6_len = sizeof(*sa);
+ sa->sin6_port = htons(port);
+ sa->sin6_family = AF_INET6;
+ ai->ai_family = AF_INET6;
+ break;
+ }
#endif
- }
+ case PF_UNSPEC: {
+ struct sockaddr_in *sa = (struct sockaddr_in *) ai->ai_addr;
+ if (hints->ai_flags & AI_PASSIVE) {
+ sa->sin_addr.s_addr = htonl(INADDR_ANY);
} else {
- _hent = gethostbyname(node);
- if (_hent) {
- memcpy(&sa->sin_addr.s_addr, _hent->h_addr, sizeof(struct in_addr));
+ sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ }
+ sa->sin_len = sizeof(*sa);
+ sa->sin_port = htons(port);
+ sa->sin_family = AF_INET;
+ ai->ai_family = AF_INET;
+#ifdef CYGPKG_NET_INET6
+ {
+ struct sockaddr_in6 *sa6;
+ ai=alloc_addrinfo(ai);
+ if (ai == NULL) {
+ return EAI_MEMORY;
+ }
+ sa6 = (struct sockaddr_in6 *) ai->ai_addr;
+ if (hints->ai_flags & AI_PASSIVE) {
+ memcpy(&sa6->sin6_addr, &in6addr_any, sizeof(sa6->sin6_addr));
} else {
- // For now, only numeric "presentation" addresses supported
- if (!inet_pton(AF_INET, (char *)node, (char *)&sa->sin_addr.s_addr)) {
- return EAI_FAIL; // Couldn't resolve name
- }
+ memcpy(&sa6->sin6_addr, &in6addr_loopback, sizeof(sa6->sin6_addr));
}
+ sa6->sin6_len = sizeof(*sa);
+ sa6->sin6_port = htons(port);
+ sa6->sin6_family = AF_INET6;
+ ai->ai_family = AF_INET6;
+ }
+#endif
+ break;
+ }
+ }
+ return EAI_NONE;
+}
+
+
+// We have been asked to convert only numeric addresses so as to not
+// need a DNS server query.
+static int
+numeric_node_addr(struct addrinfo *ai, const char *node,
+ const struct addrinfo *hints, int port) {
+
+ switch (hints->ai_family) {
+ case AF_INET: {
+ struct sockaddr_in *sa = (struct sockaddr_in *) ai->ai_addr;
+ if (!inet_pton(AF_INET, node, (void *)&sa->sin_addr.s_addr)) {
+ return EAI_FAIL;
}
+ sa->sin_port = htons(port);
+ sa->sin_family = AF_INET;
+ sa->sin_len = sizeof(*sa);
+ ai->ai_family = AF_INET;
+ break;
}
- break;
#ifdef CYGPKG_NET_INET6
- case AF_INET6:
- {
- struct sockaddr_in6 *sa;
- sa = (struct sockaddr_in6 *)malloc(sizeof(struct sockaddr_in6));
- memset(sa, 0, sizeof(*sa));
- ai->ai_addr = (struct sockaddr *)sa;
- ai->ai_addrlen = sizeof(*sa);
- if (ai->ai_addr == (struct sockaddr *)NULL) {
- return EAI_MEMORY;
+ case AF_INET6: {
+ struct sockaddr_in6 *sa = (struct sockaddr_in6 *) ai->ai_addr;
+ if (!inet_pton(AF_INET6, node, (void *)&sa->sin6_addr.s6_addr)) {
+ return EAI_FAIL;
}
+ sa->sin6_port = htons(port);
sa->sin6_family = AF_INET6;
sa->sin6_len = sizeof(*sa);
- sa->sin6_port = htons(port);
- if (node == (char *)NULL) {
- if (hints->ai_flags & AI_PASSIVE) {
- sa->sin6_addr = in6addr_any;
- } else {
- sa->sin6_addr = in6addr_loopback;
- }
- } else {
- // For now, only numeric "presentation" addresses supported
- if (!inet_pton(AF_INET6, (char *)node, (char *)&sa->sin6_addr)) {
- return EAI_FAIL; // Couldn't resolve name
+ ai->ai_family = AF_INET6;
+ break;
+ }
+#endif
+ case PF_UNSPEC: {
+ struct sockaddr_in *sa = (struct sockaddr_in *) ai->ai_addr;
+ sa->sin_len = sizeof(*sa);
+ sa->sin_port = htons(port);
+ sa->sin_family = AF_INET;
+ ai->ai_family = AF_INET;
+ if (inet_pton(AF_INET, node, (void *)&sa->sin_addr.s_addr)) {
+ return EAI_NONE;
+ }
+#ifdef CYGPKG_NET_INET6
+ {
+ struct sockaddr_in6 *sa = (struct sockaddr_in6 *) ai->ai_addr;
+ sa->sin6_len = sizeof(*sa);
+ sa->sin6_port = htons(port);
+ sa->sin6_family = AF_INET6;
+ ai->ai_family = AF_INET6;
+ if (inet_pton(AF_INET6, node, (void *)&sa->sin6_addr.s6_addr)) {
+ return EAI_NONE;
}
}
+#endif
+ return EAI_FAIL;
+ break;
+ }
+ }
+ return EAI_NONE;
+}
+
+// We have a host name. Use the DNS client to perform a lookup. If the
+// DNS client is not part of the configuration try using the numeric
+// convertion.
+static int
+with_node_addr(struct addrinfo *ai, const char *node,
+ const struct addrinfo *hints, int port) {
+
+#ifdef CYGPKG_NS_DNS
+ struct sockaddr addrs[CYGNUM_NS_DNS_GETADDRINFO_ADDRESSES];
+ int nresults;
+ int i;
+ char ** canon = NULL;
+
+ if (hints->ai_flags & AI_CANONNAME) {
+ canon = &ai->ai_canonname;
+ }
+ nresults = cyg_dns_getaddrinfo(node,
+ addrs, CYGNUM_NS_DNS_GETADDRINFO_ADDRESSES,
+ hints->ai_family, canon);
+ if (nresults < 0) {
+ return -nresults;
}
- break;
+
+ for (i=0; i < nresults; i++) {
+ if (i != 0) {
+ ai = alloc_addrinfo(ai);
+ if (ai == NULL) {
+ return EAI_MEMORY;
+ }
+ }
+ memcpy(ai->ai_addr, &addrs[i], sizeof(addrs[i]));
+ ai->ai_family = addrs[i].sa_family;
+ ai->ai_addrlen = addrs[i].sa_len;
+ switch (ai->ai_family) {
+ case AF_INET: {
+ struct sockaddr_in *sa = (struct sockaddr_in *) ai->ai_addr;
+ sa->sin_port = htons(port);
+ break;
+ }
+#ifdef CYGPKG_NET_INET6
+ case AF_INET6: {
+ struct sockaddr_in6 *sa = (struct sockaddr_in6 *) ai->ai_addr;
+ sa->sin6_port = htons(port);
+ break;
+ }
#endif
+ }
}
return EAI_NONE;
+#else
+ return (numeric_node_addr(ai, node, hints, hints->ai_family, port));
+#endif
}
int
@@ -135,8 +280,8 @@
char *endptr;
int port = 0;
int err;
- int used = 0;
-
+ int used;
+
if (hints == (struct addrinfo *)NULL) {
dflt_hints.ai_flags = 0; // No special flags
dflt_hints.ai_family = PF_UNSPEC;
@@ -151,16 +296,16 @@
switch (hints->ai_family) {
case PF_UNSPEC:
case PF_INET:
- break;
+ break;
#ifdef CYGPKG_NET_INET6
case PF_INET6:
- break;
+ break;
#endif
default:
return EAI_FAMILY;
}
// Allocate the first/primary result
- *res = ai = (struct addrinfo *)calloc(1, sizeof(struct addrinfo));
+ *res = ai = alloc_addrinfo(NULL);
if (ai == (struct addrinfo *)NULL) {
return EAI_MEMORY;
}
@@ -168,6 +313,9 @@
if (hints->ai_protocol != 0) {
proto = getprotobynumber(hints->ai_protocol);
}
+
+ // Note: this does not handle the case where a given service can be
+ // handled via multiple protocols, e.g. http/tcp & http/udp
if (servname != (char *)NULL) {
switch (hints->ai_socktype) {
case 0:
@@ -185,7 +333,7 @@
}
// See if this is just a port #
if (((port = strtol(servname, &endptr, 0)) >= 0) &&
- (endptr > servname)) {
+ (endptr > servname)) {
ai->ai_socktype = hints->ai_socktype;
if (hints->ai_socktype == 0) {
// Need to have complete binding type/port
@@ -194,11 +342,12 @@
}
} else {
struct servent *serv = (struct servent *)NULL;
-
+
serv = getservbyname(servname, protoname);
if (serv == (struct servent *)NULL) {
if (hints->ai_socktype == 0) {
protoname = "udp";
+ ai->ai_socktype = SOCK_DGRAM;
serv = getservbyname(servname, protoname);
}
}
@@ -207,7 +356,6 @@
return EAI_SERVICE;
}
port = ntohs(serv->s_port);
- ai->ai_socktype = SOCK_DGRAM;
}
proto = getprotobyname(protoname);
if (hints->ai_protocol && (hints->ai_protocol != proto->p_proto)) {
@@ -216,81 +364,59 @@
}
ai->ai_protocol = proto->p_proto;
}
- // Iterate through address types and create addresses
- // Note: this does not handle the case where a given service can be
- // handled via multiple protocols, e.g. http/tcp & http/udp
- if ((hints->ai_family == AF_INET) || (hints->ai_family == PF_UNSPEC)) {
- err = _getaddr(ai, nodename, hints, AF_INET, port);
- if ((err != EAI_NONE) && (hints->ai_family == AF_INET)) {
+
+ if (nodename) {
+ if (hints->ai_flags & AI_NUMERICHOST) {
+ err = numeric_node_addr(ai, nodename, hints, port);
+ } else {
+ err = with_node_addr(ai, nodename, hints, port );
+ }
+ } else {
+ err = no_node_addr(ai, hints, port);
+ }
+
+ if (err != EAI_NONE) {
freeaddrinfo(ai);
return err;
- }
- if (err == EAI_NONE) {
- ai->ai_family = AF_INET;
- used = 1;
- }
}
-#ifdef CYGPKG_NET_INET6
- if ((hints->ai_family == AF_INET6) || (hints->ai_family == PF_UNSPEC)) {
- if (1 == used) {
- nai = (struct addrinfo *)calloc(1,sizeof(struct addrinfo));
- if (nai == (struct addrinfo *)NULL) {
- freeaddrinfo(ai);
- return EAI_MEMORY;
- }
- ai->ai_next = nai;
- nai->ai_socktype = ai->ai_socktype;
- nai->ai_protocol = ai->ai_protocol;
- } else {
- nai = ai;
- }
- err = _getaddr(nai, nodename, hints, AF_INET6, port);
- if ((err != EAI_NONE) && (hints->ai_family == AF_INET6)) {
- freeaddrinfo(ai);
- return err;
- }
- // Free the second entry which has not been used
- if ((err != EAI_NONE) && (1 == used)) {
- ai->ai_next = NULL;
- free(nai);
- }
- if (err == EAI_NONE) {
- nai->ai_family = AF_INET6;
- used = 1;
- }
- }
-#endif
- // Do we have at least one address?
- if (0 == used) {
- return EAI_NONAME;
- }
- // Note: null nodename is the same as 'localhost'
- if (nodename == (char *)NULL) {
- nodename = (const char *)"localhost";
+ if (err == EAI_NONE) {
+ ai->ai_family = AF_INET;
+ used = 1;
}
- if (hints->ai_flags & AI_CANONNAME) {
- // Hack - until host name handling is more complete
- ai = *res; // Canonical name is only in primary record
- ai->ai_canonname = malloc(strlen(nodename)+1);
+
+ if ((hints->ai_flags & AI_CANONNAME) && !nodename) {
+ ai->ai_canonname = malloc(strlen("localhost")+1);
if (ai->ai_canonname) {
- strcpy(ai->ai_canonname, nodename);
+ strcpy(ai->ai_canonname, "localhost");
+ } else {
+ freeaddrinfo(ai);
+ return EAI_MEMORY;
}
}
- if (hints->ai_flags & AI_PASSIVE) {
- // Incomplete addressing - used for bind/listen
- } else {
- // Complete addressing - used for connect/send/...
+
+ /* The DNS code may have filled in the official address. If not
+ and we have been asked for it, return an error */
+ if ((hints->ai_flags & AI_CANONNAME) & !ai->ai_canonname) {
+ freeaddrinfo(ai);
+ return EAI_FAIL;
}
return EAI_NONE; // No errors
}
+// The canonname will probably point to the same memory in each
+// addrinfo in the linked list. Don't free it multiple times.
void
freeaddrinfo(struct addrinfo *ai)
{
struct addrinfo *next = ai;
+ char * last_canonname = NULL;
while ((ai = next) != (struct addrinfo *)NULL) {
- if (ai->ai_canonname) free(ai->ai_canonname);
+ if ((ai->ai_canonname) &&
+ (ai->ai_canonname != last_canonname)) {
+ free(ai->ai_canonname);
+ last_canonname = ai->ai_canonname;
+ }
if (ai->ai_addr) free(ai->ai_addr);
next = ai->ai_next;
free(ai);
@@ -342,6 +468,8 @@
int port;
char *s;
struct servent *se;
+ int error;
+ int numeric = (flags & NI_NUMERICHOST);
if ((flags & ~NI_MASK) != 0) {
return EAI_BADFLAGS;
@@ -352,11 +480,31 @@
case PF_INET6:
#endif
if (host != (char *)NULL) {
- s = _inet_ntop((struct sockaddr *)sa, host, hostlen);
- if (!s) {
- return EAI_FAIL;
+ if ( !numeric) {
+ error = EAI_NONAME;
+#ifdef CYGPKG_NS_DNS
+ error = -cyg_dns_getnameinfo(sa, host,hostlen);
+#endif
+ if ((error == EAI_NONAME) && (flags & NI_NAMEREQD)) {
+ return EAI_NONAME;
+ }
+ // If lookup failed, try it as numeric address
+ numeric = !(error == EAI_NONE);
+ }
+ if (numeric) {
+ s = _inet_ntop((struct sockaddr *)sa, host, hostlen);
+ if (!s) {
+ return EAI_FAIL;
+ }
+ }
+ if (!numeric && flags & NI_NOFQDN) {
+ s = index(host, '.');
+ if (s) {
+ *s = '\0';
+ }
}
}
+
if (serv != (char *)NULL) {
port = _inet_port((struct sockaddr *)sa);
if (!port) {
@@ -365,16 +513,16 @@
se = (struct servent *)NULL;
if ((flags & NI_NUMERICSERV) == 0) {
if ((flags & NI_DGRAM) == 0) {
- se = getservbyport(port, "tcp");
+ se = getservbyport(htons(port), "tcp");
}
if (se == (struct servent *)NULL) {
- se = getservbyport(port, "ucp");
+ se = getservbyport(htons(port), "udp");
}
}
if (se != (struct servent *)NULL) {
- sprintf(serv, "%s/%s", se->s_name, se->s_proto);
+ diag_snprintf(serv,servlen, "%s/%s", se->s_name, se->s_proto);
} else {
- sprintf(serv, "%d", port);
+ diag_snprintf(serv,servlen, "%d", port);
}
}
break;
Index: net//common/current/src/ifaddrs.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/common/current/src/ifaddrs.c,v
retrieving revision 1.2
diff -u -r1.2 ifaddrs.c
--- net//common/current/src/ifaddrs.c 23 Apr 2003 08:52:09 -0000 1.2
+++ net//common/current/src/ifaddrs.c 8 May 2003 07:12:58 -0000
@@ -205,7 +205,8 @@
ifp = iflist;
while (ifp != (struct ifaddrs *)NULL) {
if (ifp->ifa_addr->sa_family != AF_LINK) {
- getnameinfo (ifp->ifa_addr, ifp->ifa_addr->sa_len, addr, sizeof(addr), 0, 0, 0);
+ getnameinfo (ifp->ifa_addr, ifp->ifa_addr->sa_len, addr,
+ sizeof(addr), 0, 0, NI_NUMERICHOST);
diag_printf("%p - %s - %s\n", ifp, ifp->ifa_name, addr);
}
ifp = ifp->ifa_next;
Index: net//common/current/src/ipv6_routing_thread.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/common/current/src/ipv6_routing_thread.c,v
retrieving revision 1.3
diff -u -r1.3 ipv6_routing_thread.c
--- net//common/current/src/ipv6_routing_thread.c 23 Apr 2003 08:52:09 -0000 1.3
+++ net//common/current/src/ipv6_routing_thread.c 8 May 2003 07:12:59 -0000
@@ -340,6 +340,7 @@
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
+ hints.ai_flags = AI_NUMERICHOST;
err = getaddrinfo(ALLROUTER, NULL, &hints, &res);
if (err) {
dprnt("%s - failed to get ALL ROUTER: %s",
Index: net//common/current/src/network_support.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/common/current/src/network_support.c,v
retrieving revision 1.5
diff -u -r1.5 network_support.c
--- net//common/current/src/network_support.c 23 Apr 2003 08:52:09 -0000 1.5
+++ net//common/current/src/network_support.c 8 May 2003 07:12:59 -0000
@@ -469,7 +469,10 @@
}
if (rs_wait == 0 ) {
diag_printf("No router solicit received\n");
- }
+ } else {
+ // Give Duplicate Address Detection time to work
+ cyg_thread_delay(200);
+ }
#endif
#ifdef CYGDAT_NS_DNS_DEFAULT_SERVER
Index: net//common/current/src/tftp_client.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/common/current/src/tftp_client.c,v
retrieving revision 1.5
diff -u -r1.5 tftp_client.c
--- net//common/current/src/tftp_client.c 23 Apr 2003 08:52:09 -0000 1.5
+++ net//common/current/src/tftp_client.c 8 May 2003 07:12:59 -0000
@@ -158,9 +158,9 @@
}
if (bind(s,&local_addr,addrinfo->ai_addrlen) < 0) {
- *err = TFTP_NETERR;
- goto out;
- }
+ *err = TFTP_NETERR;
+ goto out;
+ }
// Send request
if (sendto(s, data, (int)(cp-data), 0,
@@ -179,21 +179,38 @@
FD_ZERO(&fds);
FD_SET(s, &fds);
if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
- if ((++total_timeouts > TFTP_TIMEOUT_MAX)
- || (last_good_block == 0)) {
- // Timeout - no data received
+ total_timeouts++;
+ if ((last_good_block == 0) && (total_timeouts > TFTP_RETRIES_MAX)) {
+ // Timeout - no data received. Probably no server.
*err = TFTP_TIMEOUT;
- goto out;
- }
- // Try resending last ACK
- hdr->th_opcode = htons(ACK);
- hdr->th_block = htons(last_good_block);
- if (sendto(s, data, 4 /* FIXME */, 0,
- &from_addr, from_len) < 0) {
- // Problem sending request
- *err = TFTP_NETERR;
- goto out;
+ goto nextaddr;
+ }
+ if (total_timeouts > TFTP_TIMEOUT_MAX) {
+ // Timeout - have received data. Network problem?
+ *err = TFTP_TIMEOUT;
+ goto out;
}
+
+ if (last_good_block == 0 ) {
+ // Send request
+ if (sendto(s, data, (int)(cp-data), 0,
+ addrinfo->ai_addr,
+ addrinfo->ai_addrlen) < 0) {
+ // Problem sending request
+ *err = TFTP_NETERR;
+ goto nextaddr;
+ }
+ } else {
+ // Try resending last ACK
+ hdr->th_opcode = htons(ACK);
+ hdr->th_block = htons(last_good_block);
+ if (sendto(s, data, 4 /* FIXME */, 0,
+ &from_addr, from_len) < 0) {
+ // Problem sending request
+ *err = TFTP_NETERR;
+ goto out;
+ }
+ }
} else {
recv_len = sizeof(data);
from_len = sizeof(from_addr);
@@ -335,7 +352,7 @@
int *err) {
int result = 0;
- int s, actual_len, data_len, recv_len, from_len;
+ int s = -1, actual_len, data_len, recv_len, from_len;
static int put_port = 7800;
struct sockaddr local_addr, from_addr;
char data[SEGSIZE+sizeof(struct tftphdr)];
@@ -436,7 +453,7 @@
FD_ZERO(&fds);
FD_SET(s, &fds);
if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
- if (++total_timeouts > TFTP_TIMEOUT_MAX) {
+ if (++total_timeouts > TFTP_RETRIES_MAX) {
// Timeout - no ACK received
*err = TFTP_TIMEOUT;
goto nextaddr;
@@ -547,5 +564,3 @@
}
// EOF tftp_client.c
-
-
Index: net//common/current/src/tftp_server.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/common/current/src/tftp_server.c,v
retrieving revision 1.4
diff -u -r1.4 tftp_server.c
--- net//common/current/src/tftp_server.c 23 Apr 2003 08:52:09 -0000 1.4
+++ net//common/current/src/tftp_server.c 8 May 2003 07:12:59 -0000
@@ -600,6 +600,9 @@
ai = server->res;
memset(server->s,0,sizeof(server->s));
server->num_s = 0;
+#ifdef CYGSEM_NET_TFTPD_MULTITHREADED
+ sem_wait(server->port);
+#endif
while (ai && (server->num_s < CYGNUM_NET_MAX_INET_PROTOS)) {
server->s[server->num_s] = socket(ai->ai_family,
ai->ai_socktype,
@@ -613,9 +616,6 @@
set_port(ai->ai_addr, server->port);
-#ifdef CYGSEM_NET_TFTPD_MULTITHREADED
- sem_wait(server->port);
-#endif
if (bind(server->s[server->num_s],ai->ai_addr, ai->ai_addrlen) < 0) {
// Problem setting up my end
diag_printf("TFTPD [%x]: can't bind to server port\n",p);
Index: net//common/current/tests/addr_test.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/common/current/tests/addr_test.c,v
retrieving revision 1.2
diff -u -r1.2 addr_test.c
--- net//common/current/tests/addr_test.c 23 Apr 2003 08:52:09 -0000 1.2
+++ net//common/current/tests/addr_test.c 8 May 2003 07:12:59 -0000
@@ -67,107 +67,190 @@
{
int err;
struct addrinfo *addrs, hints;
+ size_t hostlen = 128;
+ size_t servlen = 64;
+ char host[hostlen];
+ char serv[servlen];
bzero(&hints, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_PASSIVE;
+ hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST;
if ((err = getaddrinfo(NULL, "7734", &hints, &addrs)) != EAI_NONE) {
diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
pexit("getaddrinfo");
}
walk_addrs(addrs, "all passive");
+ err = getnameinfo(addrs->ai_addr, addrs->ai_addrlen,
+ NULL, 0, serv,servlen, 0);
+ if (err != EAI_NONE) {
+ diag_printf("<ERROR> can't getnameinfo(): %s\n", gai_strerror(err));
+ pexit("getnameinfo");
+ }
+ diag_printf("INFO: service: %s\n",serv);
+ freeaddrinfo(addrs);
+
bzero(&hints, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = 0;
+ hints.ai_flags = AI_NUMERICHOST;
if ((err = getaddrinfo(NULL, "7734", &hints, &addrs)) != EAI_NONE) {
diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
pexit("getaddrinfo");
}
walk_addrs(addrs, "all active");
+ freeaddrinfo(addrs);
bzero(&hints, sizeof(hints));
hints.ai_family = PF_INET;
hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_PASSIVE;
+ hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST;
if ((err = getaddrinfo(NULL, "7734", &hints, &addrs)) != EAI_NONE) {
diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
pexit("getaddrinfo");
}
walk_addrs(addrs, "IPv4 passive");
+ freeaddrinfo(addrs);
bzero(&hints, sizeof(hints));
hints.ai_family = PF_INET;
hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_PASSIVE;
+ hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST;
if ((err = getaddrinfo("192.168.1.2", "7734", &hints, &addrs)) != EAI_NONE) {
diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
pexit("getaddrinfo");
}
walk_addrs(addrs, "IPv4 passive 192.168.1.2");
+ err = getnameinfo(addrs->ai_addr, addrs->ai_addrlen,
+ host, hostlen, serv, servlen, NI_NUMERICHOST);
+ if (err != EAI_NONE) {
+ diag_printf("<ERROR> can't getnameinfo(): %s\n", gai_strerror(err));
+ pexit("getnameinfo");
+ }
+ diag_printf("INFO: host: %s service: %s\n",host, serv);
+ freeaddrinfo(addrs);
+
bzero(&hints, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_PASSIVE;
+ hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST;
if ((err = getaddrinfo("192.168.1.2", "7734", &hints, &addrs)) != EAI_NONE) {
diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
pexit("getaddrinfo");
}
walk_addrs(addrs, "all passive 192.168.1.2");
+ freeaddrinfo(addrs);
#ifdef CYGPKG_NET_INET6
bzero(&hints, sizeof(hints));
hints.ai_family = PF_INET6;
hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_PASSIVE;
+ hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST;
if ((err = getaddrinfo(NULL, "7734", &hints, &addrs)) != EAI_NONE) {
diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
pexit("getaddrinfo");
}
walk_addrs(addrs, "IPv6 passive");
+ err = getnameinfo(addrs->ai_addr, addrs->ai_addrlen,
+ NULL, 0, serv,servlen, 0);
+ if (err != EAI_NONE) {
+ diag_printf("<ERROR> can't getnameinfo(): %s\n", gai_strerror(err));
+ pexit("getnameinfo");
+ }
+ diag_printf("INFO: service: %s\n",serv);
+ freeaddrinfo(addrs);
+
bzero(&hints, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_NUMERICHOST;
if ((err = getaddrinfo(NULL, "7734", &hints, &addrs)) != EAI_NONE) {
diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
pexit("getaddrinfo");
}
walk_addrs(addrs, "all passive");
-
+ freeaddrinfo(addrs);
+
bzero(&hints, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_NUMERICHOST;
if ((err = getaddrinfo("fe80::260:97ff:feb0:866e", "7734", &hints, &addrs))
!= EAI_NONE) {
diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
pexit("getaddrinfo");
}
walk_addrs(addrs, "all passive fe80::260:97ff:feb0:866e");
+
+ err = getnameinfo(addrs->ai_addr, addrs->ai_addrlen,
+ host, hostlen, serv, servlen, NI_NUMERICHOST);
+ if (err != EAI_NONE) {
+ diag_printf("<ERROR> can't getnameinfo(): %s\n", gai_strerror(err));
+ pexit("getnameinfo");
+ }
+ diag_printf("INFO: host: %s service: %s\n",host, serv);
+ freeaddrinfo(addrs);
#endif
bzero(&hints, sizeof(hints));
hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST;
+ if ((err = getaddrinfo(NULL, "ftp", &hints, &addrs)) != EAI_NONE) {
+ diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
+ pexit("getaddrinfo");
+ }
+ walk_addrs(addrs, "all snmp/udp");
+
+ err = getnameinfo(addrs->ai_addr, addrs->ai_addrlen,
+ NULL, 0, serv,servlen, 0);
+ if (err != EAI_NONE) {
+ diag_printf("<ERROR> can't getnameinfo(): %s\n", gai_strerror(err));
+ pexit("getnameinfo");
+ }
+ diag_printf("INFO: service: %s\n",serv);
+ freeaddrinfo(addrs);
+
+ bzero(&hints, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
- hints.ai_flags = AI_PASSIVE;
+ hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST;
if ((err = getaddrinfo(NULL, "snmp", &hints, &addrs)) != EAI_NONE) {
diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
pexit("getaddrinfo");
}
walk_addrs(addrs, "all snmp/udp");
+ err = getnameinfo(addrs->ai_addr, addrs->ai_addrlen,
+ NULL, 0, serv,servlen, 0);
+ if (err != EAI_NONE) {
+ diag_printf("<ERROR> can't getnameinfo(): %s\n", gai_strerror(err));
+ pexit("getnameinfo");
+ }
+ diag_printf("INFO: service: %s\n",serv);
+ freeaddrinfo(addrs);
+
bzero(&hints, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = 0;
- hints.ai_flags = AI_PASSIVE;
+ hints.ai_flags = AI_NUMERICHOST;
if ((err = getaddrinfo(NULL, "snmp", &hints, &addrs)) != EAI_NONE) {
diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
pexit("getaddrinfo");
}
walk_addrs(addrs, "all snmp/*");
+
+ err = getnameinfo(addrs->ai_addr, addrs->ai_addrlen,
+ NULL, 0, serv,servlen, NI_NUMERICSERV);
+ if (err != EAI_NONE) {
+ diag_printf("<ERROR> can't getnameinfo(): %s\n", gai_strerror(err));
+ pexit("getnameinfo");
+ }
+ diag_printf("INFO: service: %s\n",serv);
+ freeaddrinfo(addrs);
+
CYG_TEST_PASS_FINISH("Address [library] test OK");
}
Index: net//common/current/tests/ga_server_test.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/common/current/tests/ga_server_test.c,v
retrieving revision 1.1
diff -u -r1.1 ga_server_test.c
--- net//common/current/tests/ga_server_test.c 20 May 2002 22:25:05 -0000 1.1
+++ net//common/current/tests/ga_server_test.c 8 May 2003 07:12:59 -0000
@@ -121,7 +121,8 @@
getpeername(client, &client_addr, &client_len);
if (getnameinfo (&client_addr, client_len,
host_addr_buf, sizeof(host_addr_buf),
- host_port_buf, sizeof(host_port_buf), 0) == EAI_NONE) {
+ host_port_buf, sizeof(host_port_buf),
+ NI_NUMERIC) == EAI_NONE) {
diag_printf("connection from %s(%s)\n", host_addr_buf, host_port_buf);
diag_sprintf(buf, "Hello %s(%s)\n", host_addr_buf, host_port_buf);
} else {
Index: net//ftpclient/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/ftpclient/current/ChangeLog,v
retrieving revision 1.6
diff -u -r1.6 ChangeLog
--- net//ftpclient/current/ChangeLog 24 Feb 2003 14:29:52 -0000 1.6
+++ net//ftpclient/current/ChangeLog 8 May 2003 07:12:59 -0000
@@ -1,3 +1,13 @@
+2003-04-28 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * src/ftpclient.c (connect_to_server): Added support for
+ IPv6. This meant changing from using the PORT command to using
+ EPRT, when setting up the data connection. EPRT is protocol
+ independant.
+ * tests/ftpclient1.c (ftp_test): Added tests which use IPv6
+ addresses. Fixed a few minor bugs with format strings.
+ * doc/ftpclient.sgml: Mention we support IPv6 and DNS.
+
2003-02-24 Jonathan Larmour <jifl@eCosCentric.com>
* cdl/ftpclient.cdl: Add doc link.
@@ -25,6 +35,7 @@
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Andrew Lunn.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
Index: net//ftpclient/current/doc/ftpclient.sgml
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/ftpclient/current/doc/ftpclient.sgml,v
retrieving revision 1.2
diff -u -r1.2 ftpclient.sgml
--- net//ftpclient/current/doc/ftpclient.sgml 15 Sep 2002 21:43:45 -0000 1.2
+++ net//ftpclient/current/doc/ftpclient.sgml 8 May 2003 07:12:59 -0000
@@ -11,6 +11,7 @@
<!-- -->
<!-- =============================================================== -->
<!-- Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -->
+<!-- Copyright (C) 2003 Andrew Lunn. -->
<!-- This material may be distributed only subject to the terms -->
<!-- and conditions set forth in the Open Publication License, v1.0 -->
<!-- or later (the latest version is presently available at -->
@@ -34,7 +35,8 @@
<PARTINTRO>
<PARA>
The ftpclient package provides an FTP (File Transfer Protocol) client
-for use with the TCP/IP stack in eCos.
+for use with the TCP/IP stack in eCos. It supports both IPv4 and IPv6
+and will use the DNS client, when its is part of the eCos configuration.
</PARA>
</PARTINTRO>
<CHAPTER id="net-ftpclient-features">
Index: net//ftpclient/current/src/ftpclient.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/ftpclient/current/src/ftpclient.c,v
retrieving revision 1.5
diff -u -r1.5 ftpclient.c
--- net//ftpclient/current/src/ftpclient.c 7 Aug 2002 08:00:34 -0000 1.5
+++ net//ftpclient/current/src/ftpclient.c 8 May 2003 07:12:59 -0000
@@ -209,66 +209,54 @@
static int
connect_to_server(char *hostname,
- struct sockaddr_in * local,
+ struct sockaddr * local,
ftp_printf_t ftp_printf)
{
- struct sockaddr_in host;
- struct servent *sent;
-#ifdef CYGPKG_NS_DNS
- struct hostent *hp=NULL;
-#endif
int s, len;
+ int error;
+ struct addrinfo *res, *nai;
+ char name[80];
+ char port[8];
- s = socket(AF_INET, SOCK_STREAM, 0);
- if (s < 0) {
- ftp_printf(1,"socket: %s\n",strerror(errno));
- return FTP_BAD;
- }
-
- sent = getservbyname("ftp", "tcp");
- if (sent == (struct servent *)0) {
- ftp_printf(1,"FTP: unknown serivice\n");
- close(s);
- return FTP_BAD;
+ error = getaddrinfo(hostname, "ftp", NULL, &res);
+ if (error != EAI_NONE) {
+ return FTP_NOSUCHHOST;
}
-#ifdef CYGPKG_NS_DNS
- hp = gethostbyname(hostname);
-
-
- if (hp) { /* try name first */
- host.sin_family = hp->h_addrtype;
- bcopy(hp->h_addr, &host.sin_addr, hp->h_length);
- } else
-#endif
- { /* maybe it's a numeric address ?*/
- host.sin_family = AF_INET;
+ nai=res;
+ while (nai) {
+ s = socket(nai->ai_family, nai->ai_socktype,nai->ai_protocol);
+ if (s < 0) {
+ nai = nai->ai_next;
+ continue;
+ }
- if (inet_aton(hostname,&host.sin_addr) == 0) {
- ftp_printf(1,"host not found: %s\n", hostname);
+ if (connect(s, nai->ai_addr, nai->ai_addrlen) < 0) {
+ getnameinfo(nai->ai_addr, nai->ai_addrlen,
+ name, sizeof(name), NULL,0, NI_NUMERICHOST);
+ ftp_printf(1,"FTP Connect to %s failed: %s\n",name, strerror(errno));
close (s);
- return FTP_NOSUCHHOST;
+ nai = nai->ai_next;
+ continue;
}
+
+ len = sizeof(struct sockaddr);
+ if (getsockname(s, (struct sockaddr *)local, &len) < 0) {
+ ftp_printf(1,"getsockname failed %s\n",strerror(errno));
+ close(s);
+ nai = nai->ai_next;
+ continue;
+ }
+ getnameinfo(nai->ai_addr, nai->ai_addrlen,
+ name, sizeof(name), port, sizeof(port),
+ NI_NUMERICHOST|NI_NUMERICSERV);
+
+ ftp_printf(0,"FTP: Connected to %s:%s\n", name, port);
+ freeaddrinfo(res);
+ return (s);
}
-
- host.sin_port = sent->s_port;
-
- if (connect(s, (struct sockaddr *)&host, sizeof(host)) < 0) {
- ftp_printf(1,"FTP Connect failed: %s\n",strerror(errno));
- close (s);
- return FTP_NOSUCHHOST;
- }
-
- len = sizeof(struct sockaddr_in);
- if (getsockname(s, (struct sockaddr *)local, &len) < 0) {
- ftp_printf(1,"getsockname failed %s\n",strerror(errno));
- close(s);
- return FTP_BAD;
- }
- ftp_printf(0,"FTP: Connected to %s.%d\n",
- inet_ntoa(host.sin_addr), ntohs(host.sin_port));
-
- return (s);
+ freeaddrinfo(res);
+ return FTP_NOSUCHHOST;
}
/* Perform a login to the server. Pass the username and password and
@@ -320,20 +308,21 @@
port we are listening on.*/
static int
opendatasock(int ctrl_s,
- struct sockaddr_in ctrl,
+ struct sockaddr *ctrl,
char *msgbuf,
unsigned msgbuflen,
ftp_printf_t ftp_printf) {
- struct sockaddr_in local;
+ struct sockaddr local;
+ char name[64];
+ char port[10];
socklen_t len;
int on = 1;
- char buf[4*6+1];
- char *a, *p;
+ char buf[80];
int ret;
int s;
- s = socket(AF_INET, SOCK_STREAM, 0);
+ s = socket(ctrl->sa_family, SOCK_STREAM, 0);
if (s < 0) {
ftp_printf(1,"socket: %s\n",strerror(errno));
return FTP_BAD;
@@ -344,18 +333,34 @@
close(s);
return FTP_BAD;
}
+
+ memcpy(&local,ctrl,sizeof(struct sockaddr));
+ switch (ctrl->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in * sa4 = (struct sockaddr_in *) &local;
+ sa4->sin_port = 0;
+ break;
+ }
+#ifdef CYGPKG_NET_INET6
+ case AF_INET6: {
+ struct sockaddr_in6 * sa6 = (struct sockaddr_in6 *) &local;
+ sa6->sin6_port = 0;
+ break;
+ }
+#endif
+ default:
+ close (s);
+ return FTP_BAD;
+ }
- local = ctrl;
- local.sin_family = AF_INET;
- local.sin_port = 0;
- if (bind(s,(struct sockaddr *)&local,sizeof(local)) < 0) {
+ if (bind(s,&local,local.sa_len) < 0) {
ftp_printf(1,"bind: %s\n",strerror(errno));
close(s);
return FTP_BAD;
}
len = sizeof(local);
- if (getsockname(s,(struct sockaddr *)&local,&len) < 0) {
+ if (getsockname(s,&local,&len) < 0) {
ftp_printf(1,"getsockname: %s\n",strerror(errno));
close(s);
return FTP_BAD;
@@ -366,15 +371,26 @@
close(s);
return FTP_BAD;
}
+
+ getnameinfo(&local,sizeof(local),name,sizeof(name), port, sizeof(port),
+ NI_NUMERICHOST|NI_NUMERICSERV);
+ switch (local.sa_family) {
+ case AF_INET: {
+ sprintf(buf,"|1|%s|%s|", name, port);
+ break;
+ }
+#ifdef CYGPKG_NET_INET6
+ case AF_INET6: {
+ sprintf(buf,"|2|%s|%s|", name, port);
+ break;
+ }
+#endif
+ default:
+ close (s);
+ return (FTP_BAD);
+ }
-#define BtoI(b) (((int)b)&0xff)
- a = (char *)&local.sin_addr;
- p = (char *)&local.sin_port;
- sprintf(buf,"%d,%d,%d,%d,%d,%d",
- BtoI(a[0]),BtoI(a[1]),BtoI(a[2]),BtoI(a[3]),
- BtoI(p[0]),BtoI(p[1]));
-
- ret = command("PORT",buf,ctrl_s,msgbuf,msgbuflen,ftp_printf);
+ ret = command("EPRT",buf,ctrl_s,msgbuf,msgbuflen,ftp_printf);
if (ret < 0) {
close(s);
return (ret);
@@ -511,7 +527,7 @@
ftp_printf_t ftp_printf)
{
- struct sockaddr_in local;
+ struct sockaddr local;
char msgbuf[256];
int s,data_s;
int bytes;
@@ -538,7 +554,7 @@
/* We are now logged in and ready to transfer the file. Open the
data socket ready to receive the file. It also build the PORT
command ready to send */
- data_s = opendatasock(s,local,msgbuf,sizeof(msgbuf),ftp_printf);
+ data_s = opendatasock(s,&local,msgbuf,sizeof(msgbuf),ftp_printf);
if (data_s < 0) {
close (s);
return (data_s);
@@ -604,7 +620,7 @@
ftp_printf_t ftp_printf)
{
- struct sockaddr_in local;
+ struct sockaddr local;
char msgbuf[256];
int s,data_s;
int ret;
@@ -630,7 +646,7 @@
/* We are now logged in and ready to transfer the file. Open the
data socket ready to receive the file. It also build the PORT
command ready to send */
- data_s = opendatasock(s,local,msgbuf,sizeof(msgbuf),ftp_printf);
+ data_s = opendatasock(s,&local,msgbuf,sizeof(msgbuf),ftp_printf);
if (data_s < 0) {
close (s);
return (data_s);
Index: net//ftpclient/current/tests/ftpclient1.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/ftpclient/current/tests/ftpclient1.c,v
retrieving revision 1.3
diff -u -r1.3 ftpclient1.c
--- net//ftpclient/current/tests/ftpclient1.c 23 May 2002 23:08:04 -0000 1.3
+++ net//ftpclient/current/tests/ftpclient1.c 8 May 2003 07:12:59 -0000
@@ -9,6 +9,7 @@
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Andrew Lunn.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
@@ -65,8 +66,8 @@
#define __string(_x) #_x
#define __xstring(_x) __string(_x)
-#define _FTP_SRV __xstring(172.16.19.254) // farmnet dns0 address
-
+#define _FTP_SRV __xstring(192.168.10.1) // farmnet dns0 address
+#define _FTP_SRV_V6 __xstring(fec0:0:0:2::1)
#define FTPBUFSIZE (1024 * 64)
char ftpbuf[FTPBUFSIZE];
char ftpbuf1[FTPBUFSIZE];
@@ -80,13 +81,13 @@
init_all_network_interfaces();
- CYG_TEST_INFO("Getting /etc/passwd from %s\n" _FTP_SRV);
+ CYG_TEST_INFO("Getting /etc/passwd from " _FTP_SRV);
ret = ftp_get(_FTP_SRV,"anonymous","ftpclient1",
"/etc/passwd",ftpbuf,FTPBUFSIZE,
ftpclient_printf);
if (ret > 0) {
- diag_printf("PASS:< %s bytes received>\n",ret);
+ diag_printf("PASS:< %d bytes received>\n",ret);
} else {
diag_printf("FAIL:< ftp_get returned %d>\n",ret);
}
@@ -108,13 +109,51 @@
ftpclient_printf);
if (ret > 0) {
- diag_printf("PASS:< %s bytes received>\n",ret);
+ diag_printf("PASS:< %d bytes received>\n",ret);
} else {
diag_printf("FAIL:< ftp_get returned %d>\n",ret);
}
CYG_TEST_PASS_FAIL(!memcmp(ftpbuf,ftpbuf1,ret),"Transfer integrity");
+#ifdef CYGPKG_NET_INET6
+ CYG_TEST_INFO("Getting /etc/passwd from " _FTP_SRV_V6);
+ ret = ftp_get(_FTP_SRV_V6,"anonymous","ftpclient1",
+ "/etc/passwd",ftpbuf,FTPBUFSIZE,
+ ftpclient_printf);
+
+ if (ret > 0) {
+ diag_printf("PASS:< %d bytes received>\n",ret);
+ } else {
+ diag_printf("FAIL:< ftp_get returned %d>\n",ret);
+ }
+
+ CYG_TEST_INFO("Putting passwd file back in /incoming/passwd\n");
+ ret = ftp_put(_FTP_SRV_V6,"anonymous","ftpclient1",
+ "/incoming/passwd",ftpbuf,ret,
+ ftpclient_printf);
+
+ if (ret > 0) {
+ diag_printf("PASS:\n");
+ } else {
+ diag_printf("FAIL:< ftp_get returned %d>\n",ret);
+ }
+
+ CYG_TEST_INFO("Reading back /incoming/passwd\n");
+ ret = ftp_get(_FTP_SRV_V6,"anonymous","ftpclient1",
+ "/incoming/passwd",ftpbuf1,FTPBUFSIZE,
+ ftpclient_printf);
+
+ if (ret > 0) {
+ diag_printf("PASS:< %d bytes received>\n",ret);
+ } else {
+ diag_printf("FAIL:< ftp_get returned %d>\n",ret);
+ }
+
+ CYG_TEST_PASS_FAIL(!memcmp(ftpbuf,ftpbuf1,ret),"Transfer integrity");
+
+#endif
+
CYG_TEST_INFO("ftp_Get'ing with a bad username\n");
ret = ftp_get(_FTP_SRV,"nosuchuser","ftpclient1",
"/incoming/passwd",ftpbuf1,FTPBUFSIZE,
@@ -140,7 +179,7 @@
CYG_TEST_PASS_FAIL(ret==FTP_NOSUCHHOST,"Bad server");
CYG_TEST_INFO("ftp_get'ing a file which is too big");
- ret = ftp_get(_FTP_SRV,"nobody","ftpclient1",
+ ret = ftp_get(_FTP_SRV,"anonymous","ftpclient1",
"/incoming/passwd",ftpbuf,2,
ftpclient_printf);
CYG_TEST_PASS_FAIL(ret==FTP_TOOBIG,"File too big");
Index: net//httpd/current/cdl/httpd.cdl
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/httpd/current/cdl/httpd.cdl,v
retrieving revision 1.3
diff -u -r1.3 httpd.cdl
--- net//httpd/current/cdl/httpd.cdl 23 Apr 2003 03:02:55 -0000 1.3
+++ net//httpd/current/cdl/httpd.cdl 8 May 2003 07:12:59 -0000
@@ -150,6 +150,17 @@
compile -library=libextras.a monitor.c
}
+ cdl_component CYGPKG_HTTPD_TESTS {
+ display "HTTPD tests"
+ flavor data
+ no_define
+ calculated {
+ "tests/httpd1"
+ }
+ description "
+ This option causes the building of a simple test server."
+ }
+
cdl_component CYGPKG_HTTPD_OPTIONS {
display "HTTP server build options"
flavor none
Index: net//httpd/current/src/httpd.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/httpd/current/src/httpd.c,v
retrieving revision 1.1
diff -u -r1.1 httpd.c
--- net//httpd/current/src/httpd.c 22 Dec 2002 11:09:02 -0000 1.1
+++ net//httpd/current/src/httpd.c 8 May 2003 07:12:59 -0000
@@ -10,6 +10,7 @@
* This file is part of eCos, the Embedded Configurable Operating
* System.
* Copyright (C) 2002 Nick Garnett.
+ * Copyright (C) 2003 Andrew Lunn.
*
* eCos is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
@@ -43,7 +44,7 @@
* #####DESCRIPTIONBEGIN####
*
* Author(s): nickg@calivar.com
- * Contributors: nickg@calivar.com
+ * Contributors: nickg@calivar.com, Andrew.lunn@ascom.ch
* Date: 2002-10-14
* Purpose:
* Description:
@@ -74,7 +75,7 @@
/* ================================================================= */
-#if 0
+#if 1
#define HTTPD_DIAG diag_printf
#else
#define HTTPD_DIAG(...)
@@ -87,6 +88,10 @@
static struct sockaddr_in server_address;
static int server_socket = -1;
+#ifdef CYGPKG_NET_INET6
+static int server_socket6 = -1;
+static struct sockaddr_in6 server_address6;
+#endif
/* ================================================================= */
/* Thread stacks, etc.
@@ -143,12 +148,117 @@
return false;
}
+
+/* ================================================================= */
+/* Main processing function */
+/* */
+/* Reads the HTTP header, look it up in the table and calls the */
+/* handler. */
+static void cyg_httpd_process( int client_socket, struct sockaddr *client_address ) {
+
+ int calen = sizeof(*client_address);
+ int nlc = 0;
+ char request[CYGNUM_HTTPD_SERVER_BUFFER_SIZE];
+ FILE *client;
+ cyg_httpd_table_entry *entry = cyg_httpd_table;
+ char *filename;
+ char *formdata = NULL;
+ char *p;
+ cyg_bool success = false;
+ char name[64];
+ char port[10];
+
+ getnameinfo(client_address, calen, name, sizeof(name),
+ port, sizeof(port), NI_NUMERICHOST|NI_NUMERICSERV);
+ HTTPD_DIAG("Connection from %s[%s]\n",name,port);
+
+ /* Convert the file descriptor to a C library FILE object so
+ * we can use fprintf() and friends on it.
+ */
+ client = fdopen( client_socket, "r+");
+
+ /* We are really only interested in the first line.
+ */
+ fgets( request, sizeof(request), client );
+
+ HTTPD_DIAG("Request >%s<\n", request );
+
+ /* Absorb the rest of the header. We nibble it away a
+ * character at a time like this to avoid having to define
+ * another buffer to read lines into. If we ever need to take
+ * more interest in the header fields, we will need to be a
+ * lot more sophisticated than this.
+ */
+ do{
+ int c = getc( client );
+ HTTPD_DIAG("%c",c);
+ if( c == '\n' )
+ nlc++;
+ else if( c != '\r' )
+ nlc = 0;
+ } while(nlc < 2);
+
+ /* Extract the filename and any form data being returned.
+ * We know that the "GET " request takes 4 bytes.
+ * TODO: handle POST type requests as well as GET's.
+ */
+
+ filename = p = request+4;
+
+ /* Now scan the filename until we hit a space or a '?'. If we
+ * end on a '?' then the rest is a form request. Put NULs at
+ * the end of each string.
+ */
+ while( *p != ' ' && *p != '?' )
+ p++;
+ if( *p == '?' )
+ formdata = p+1;
+ *p = 0;
+
+ if( formdata != NULL )
+ {
+ while( *p != ' ' )
+ p++;
+ *p = 0;
+ }
+
+ HTTPD_DIAG("Request filename >%s< formdata >%s<\n",filename,formdata?formdata:"-NULL-");
+
+ HTTPD_DIAG("table: %08x...%08x\n",cyg_httpd_table, cyg_httpd_table_end);
+
+ /* Now scan the table for a matching entry. If we find one
+ * call the handler routine. If that returns true then we
+ * terminate the scan, otherwise we keep looking.
+ */
+ while( entry != cyg_httpd_table_end )
+ {
+ HTTPD_DIAG("try %08x: %s\n", entry, entry->pattern);
+
+ if( match( filename, entry->pattern ) )
+ {
+ if( (success = entry->handler( client, filename, formdata, entry->arg )) )
+ break;
+ }
+
+ entry++;
+ }
+
+ /* If we failed to find a match in the table, send a "not
+ * found" response.
+ * TODO: add an optional fallback to go look for files in
+ * some filesystem, somewhere.
+ */
+ if( !success )
+ cyg_httpd_send_html( client, NULL, NULL, cyg_httpd_not_found );
+
+ fclose(client);
+}
+
/* ================================================================= */
/* Main HTTP server
*
- * This just loops, collects client connections, reads the HTTP
- * header, look it up in the table and calls the handler.
- */
+ * This just loops, collects client connections, and calls the main
+ * process function on the connects*/
static void cyg_httpd_server( cyg_addrword_t arg )
{
@@ -156,108 +266,35 @@
{
int err;
int client_socket;
- struct sockaddr_in client_address;
- int calen;
- int nlc = 0;
- char request[CYGNUM_HTTPD_SERVER_BUFFER_SIZE];
- FILE *client;
- cyg_httpd_table_entry *entry = cyg_httpd_table;
- char *filename;
- char *formdata = NULL;
- char *p;
- cyg_bool success = false;
+ struct sockaddr client_address;
+ int calen = sizeof(client_address);
+ fd_set readfds;
+ int n;
/* Wait for a connection.
*/
- client_socket = accept( server_socket, (struct sockaddr *)&client_address, &calen );
-
- HTTPD_DIAG("Connection from %08x[%d]\n",client_address.sin_addr.s_addr,
- client_address.sin_port);
-
- /* Convert the file descriptor to a C library FILE object so
- * we can use fprintf() and friends on it.
- */
- client = fdopen( client_socket, "r+");
-
- /* We are really only interested in the first line.
- */
- fgets( request, sizeof(request), client );
-
- HTTPD_DIAG("Request >%s<\n", request );
+ FD_ZERO(&readfds);
+ FD_SET(server_socket, &readfds);
+#ifdef CYGPKG_NET_INET6
+ FD_SET(server_socket6, &readfds);
+#endif
+ n = (server_socket > server_socket6 ? server_socket : server_socket6) + 1;
- /* Absorb the rest of the header. We nibble it away a
- * character at a time like this to avoid having to define
- * another buffer to read lines into. If we ever need to take
- * more interest in the header fields, we will need to be a
- * lot more sophisticated than this.
- */
- do{
- int c = getc( client );
- HTTPD_DIAG("%c",c);
- if( c == '\n' )
- nlc++;
- else if( c != '\r' )
- nlc = 0;
- } while(nlc < 2);
-
- /* Extract the filename and any form data being returned.
- * We know that the "GET " request takes 4 bytes.
- * TODO: handle POST type requests as well as GET's.
- */
-
- filename = p = request+4;
-
- /* Now scan the filename until we hit a space or a '?'. If we
- * end on a '?' then the rest is a form request. Put NULs at
- * the end of each string.
- */
- while( *p != ' ' && *p != '?' )
- p++;
- if( *p == '?' )
- formdata = p+1;
- *p = 0;
-
- if( formdata != NULL )
- {
- while( *p != ' ' )
- p++;
- *p = 0;
+ select(n,&readfds,NULL,NULL,NULL);
+ if (FD_ISSET(server_socket, &readfds)) {
+ client_socket = accept( server_socket, &client_address, &calen );
+ cyg_httpd_process(client_socket, &client_address);
+ err = close( client_socket );
+ CYG_ASSERT( err == 0, "fclose() returned error");
}
-
- HTTPD_DIAG("Request filename >%s< formdata >%s<\n",filename,formdata?formdata:"-NULL-");
-
- HTTPD_DIAG("table: %08x...%08x\n",cyg_httpd_table, cyg_httpd_table_end);
-
- /* Now scan the table for a matching entry. If we find one
- * call the handler routine. If that returns true then we
- * terminate the scan, otherwise we keep looking.
- */
- while( entry != cyg_httpd_table_end )
- {
- HTTPD_DIAG("try %08x: %s\n", entry, entry->pattern);
-
- if( match( filename, entry->pattern ) )
- {
- if( (success = entry->handler( client, filename, formdata, entry->arg )) )
- break;
- }
-
- entry++;
+#ifdef CYGPKG_NET_INET6
+ if (FD_ISSET(server_socket6, &readfds)) {
+ client_socket = accept( server_socket6, &client_address, &calen );
+ cyg_httpd_process(client_socket, &client_address);
+ err = close( client_socket );
+ CYG_ASSERT( err == 0, "fclose(AF_INET6) returned error");
}
-
- /* If we failed to find a match in the table, send a "not
- * found" response.
- * TODO: add an optional fallback to go look for files in
- * some filesystem, somewhere.
- */
- if( !success )
- cyg_httpd_send_html( client, NULL, NULL, cyg_httpd_not_found );
-
- /* All done, close the connection
- */
- err = fclose( client );
- CYG_ASSERT( err == 0, "fclose() returned error");
-
+#endif
} while(1);
}
@@ -288,7 +325,12 @@
server_address.sin_len = sizeof(server_address);
server_address.sin_addr.s_addr = INADDR_ANY;
server_address.sin_port = htons(CYGNUM_HTTPD_SERVER_PORT);
-
+#ifdef CYGPKG_NET_INET6
+ server_address6.sin6_family = AF_INET6;
+ server_address6.sin6_len = sizeof(server_address6);
+ server_address6.sin6_addr = in6addr_any;
+ server_address6.sin6_port = htons(CYGNUM_HTTPD_SERVER_PORT);
+#endif
/* Get the network going. This is benign if the application has
* already done this.
*/
@@ -305,7 +347,17 @@
err = listen( server_socket, SOMAXCONN );
CYG_ASSERT( err == 0, "listen() returned error" );
+#ifdef CYGPKG_NET_INET6
+ server_socket6 = socket( AF_INET6, SOCK_STREAM, IPPROTO_TCP );
+ CYG_ASSERT( server_socket6 > 0, "Socket AF_INET6 create failed");
+
+ err = bind( server_socket6, (struct sockaddr *)&server_address6,
+ sizeof(server_address6) );
+ CYG_ASSERT( err == 0, "bind(AF_INET6) returned error");
+ err = listen( server_socket6, SOMAXCONN );
+ CYG_ASSERT( err == 0, "listen(AF_INET6) returned error" );
+#endif
/* If we are configured to have more than one server thread,
* create them now.
*/
@@ -428,7 +480,7 @@
list[i] = p;
- while( *p != 0 && i < size-1 )
+ while( p && *p != 0 && i < size-1 )
{
if( *p == '&' )
{
Index: net//ns/dns/current/ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/ns/dns/current/ChangeLog,v
retrieving revision 1.13
diff -u -r1.13 ChangeLog
--- net//ns/dns/current/ChangeLog 3 Mar 2003 17:57:10 -0000 1.13
+++ net//ns/dns/current/ChangeLog 8 May 2003 07:13:00 -0000
@@ -1,3 +1,30 @@
+2003-04-25 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * doc/dns.sgml: Updated to reflect changes for IPv6.
+
+2003-04-24 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * include/dns_impl.inl (setdomainname): Append a . to the end of
+ the domainname if it does not have one.
+ * cdl/dns.cdl: CYGOPT_NS_DNS_FIRST_FAMILTY to control order of
+ results.
+ * src/dns.c: Order the results from cyg_dns_getaddrinfo.
+ * test/dns1.c: Re-written to perform better testing and for
+ getaddrinfo and getnameinfo.
+ * test/dns2.c: Removed. It does not add anything useful.
+
+2003-04-21 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * src/dns.c (cyg_dns_getnameinfo): New. Interface between
+ getnameinfo and the DNS client.
+
+2003-04-19 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * src/dns.c (cyg_dns_getaddrinfo): New. Interface between
+ getaddrinfo and the DNS client. This supports both IPv4 and IPv6
+ * test/dns1.c: Added tests for getnameinfo using both IPv4 and
+ IPv6 addresses.
+
2003-03-03 Jonathan Larmour <jifl@eCosCentric.com>
* tests/dns1.c: Use BOOTP info where possible in preference to
Index: net//ns/dns/current/cdl/dns.cdl
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/ns/dns/current/cdl/dns.cdl,v
retrieving revision 1.6
diff -u -r1.6 dns.cdl
--- net//ns/dns/current/cdl/dns.cdl 24 Feb 2003 14:30:35 -0000 1.6
+++ net//ns/dns/current/cdl/dns.cdl 8 May 2003 07:13:00 -0000
@@ -108,6 +108,31 @@
default_value { "default.domain.com" }
}
}
+
+ cdl_option CYGNUM_NS_DNS_GETADDRINFO_ADDRESSES {
+ display "Max number of results for getaddrinfo"
+ flavor data
+ default_value 5
+ description "
+ This option controls the number of addresses the DNS client
+ can return to getaddrinfo and hence the size of the buffer
+ passed to the DNS client."
+ }
+
+ cdl_option CYGOPT_NS_DNS_FIRST_FAMILY {
+ display "AF_INET or AF_INET6 first in the getaddrinfo list"
+ active_if CYGPKG_NET_INET6
+ flavor data
+ default_value {"AF_INET6"}
+ legal_values {"AF_INET4" "AF_INET6"}
+ description "
+ This option controls the order DNS results will appear in the
+ information returned by getaddrinfo. This will in turn control
+ the order in which network clients try talking to servers,
+ ie does it try IPv6 or IPv4 addresses first when it has both
+ types of addresses."
+ }
+
cdl_component CYGPKG_NS_DNS_OPTIONS {
display "DNS support build options"
flavor none
@@ -142,7 +167,7 @@
flavor data
active_if CYGPKG_NS_DNS_BUILD
no_define
- calculated { "tests/dns1 tests/dns2" }
+ calculated { "tests/dns1" }
description "
This option specifies the set of tests for the DNS package."
Index: net//ns/dns/current/doc/dns.sgml
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/ns/dns/current/doc/dns.sgml,v
retrieving revision 1.5
diff -u -r1.5 dns.sgml
--- net//ns/dns/current/doc/dns.sgml 22 Jan 2003 06:39:19 -0000 1.5
+++ net//ns/dns/current/doc/dns.sgml 8 May 2003 07:13:00 -0000
@@ -11,6 +11,7 @@
<!-- -->
<!-- =============================================================== -->
<!-- Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -->
+<!-- Copyright (c) 2003 Andrew Lunn -->
<!-- This material may be distributed only subject to the terms -->
<!-- and conditions set forth in the Open Publication License, v1.0 -->
<!-- or later (the latest version is presently available at -->
@@ -43,19 +44,18 @@
<SECT1 id="net-ns-dns-api1">
<TITLE>DNS API</TITLE>
<PARA>The DNS client uses the normal BSD API for performing lookups:
-<function>gethostbyname()</function> and
-<FUNCTION>gethostbyaddr()</FUNCTION>.
+<function>gethostbyname(),</function>
+<FUNCTION>gethostbyaddr()</FUNCTION>,
+<FUNCTION>getaddrinfo()</function>,
+<FUNCTION>getnameinfo()</function>.
</PARA>
<PARA>There are a few restrictions:</PARA>
<ITEMIZEDLIST>
<LISTITEM>
-<PARA>Only IPv4 is supported, ie IPv6 addresses cannot be looked
-up.</PARA>
-</LISTITEM>
-<LISTITEM>
<PARA>If the DNS server returns multiple authoritive records
-for a host name, the hostent will only contain a record for the
-first entry.</PARA>
+for a host name to <function>gethostbyname</function>, the hostent will only contain a record for the
+first entry. If multiple records are desired, use
+<function>getaddrinfo</function>, which will return multiple results.</PARA>
</LISTITEM>
<LISTITEM>
<PARA>The code has been made thread safe. ie multiple threads
@@ -67,7 +67,15 @@
and
<FUNCTION>gethostbyaddr()</FUNCTION>.
A call to one will destroy the results from the previous call
-to the other function.</PARA>
+to the other function. <FUNCTION>getaddrinfo()</FUNCTION> is thread
+safe and so is the preferred interface.</PARA>
+</LISTITEM>
+<LISTITEM>
+<PARA>The client only uses IPv4 to access the DNS server.</PARA>
+</LISTITEM>
+<LISTITEM><PARA>The DNS client will only return IPv4 addresses to
+RedBoot. At the moment this is not really a limitation,
+since RedBoot only supports IPv4 and not IPv6.</PARA>
</LISTITEM>
</ITEMIZEDLIST>
<PARA>To initialise the DNS client the following function must be
@@ -77,12 +85,14 @@
<PARA>where dns_server is the address of the DNS server
the client should query. On Error this function returns -1, otherwise
0 for success. If lookups are attemped before this function has
-been called, they will fail and return NULL.</PARA>
+been called, they will fail and return NULL, unless numeric host addresses
+are passed. In this cause, the address will be converted and returned
+without the need for a lookup.</PARA>
<PARA>A default, hard coded, server may be specified in the CDL option
<literal>CYGDAT_NS_DNS_DEFAULT_SERVER</literal>. The use of this is
controlled by <literal>CYGPKG_NS_DNS_DEFAULT</literal>. If this is
-enabled, <literal>init_all_network_interfaces</literal> will
+enabled, <literal>init_all_network_interfaces()</literal> will
initialize the resolver with the hard coded address. The DHCP client
or user code my override this address by calling
<literal>cyg_dns_res_init</literal> again. </PARA>
@@ -110,9 +120,95 @@
and the domain name is taken from
<literal>CYGPKG_NS_DNS_DOMAINNAME_NAME</literal>.</PARA>
-<PARA>Once set, the DNS client will first perform a lookup with the domain
-name appended. If this fails it will then perform a second lookup
-without the appended domain name. </PARA>
-</SECT1>
-</CHAPTER>
+<PARA>Once set, the DNS client will use some simple heuristics when
+ deciding how to use the domainname. If the name given to the
+ client ends with a "." it is assumed to be a FQDN and the domain
+ name will not be used. If the name contains a "." somewhere
+ within it, first a lookup will be performed without the
+ domainname. If that fails the domainname will be appended and
+ looked up. If the name does not contain a ".", the domainname is
+ appended and used for the first query. If that fails, the
+ unadorned name is lookup.
+</PARA>
+ <PARA>The <FUNCTION>getaddrinfo</FUNCTION> will return both IPv4 and
+ IPv6 addresses for a given host name, when IPv6 is enabled in
+ the eCos configuration. The CDL option
+ <LITERAL>CYGOPT_NS_DNS_FIRST_FAMILY</LITERAL> controls the order
+ IPv6 and IPv4 addresses are returned in the linked list of
+ <LITERAL>addrinfo</LITERAL> structures. If the value
+ <LITERAL>AF_INET</LITERAL> is used, the IPv4 addresses will be
+ first. If the value <LITERAL>AF_INET6</LITERAL>, which is the
+ default, is used, IPv6 address will be first. This ordering will
+ control how clients attempt to connect to servers, ie using IPv6
+ or IPv4 first.
+ </PARA>
+ </SECT1>
+ <SECT1 id="net-ns-dns-testing">
+ <TITLE>DNS Client Testing</TITLE>
+
+ <PARA>The DNS client has a test program, dns1.c, which tests many of
+ the features of the DNS client and the functions
+ <FUNCTION>gethostbyname(),</FUNCTION>
+ <FUNCTION>gethostbyaddr()</FUNCTION>,
+ <FUNCTION>getaddrinfo()</FUNCTION>,
+ <FUNCTION>getnameinfo()</FUNCTION>.
+ </PARA>
+ <PARA>In order for this test to work, a DNS server must be configured
+ with a number of names and addresses. The following is an example
+ forward address resolution database for bind v9, which explains the
+ requirements.</para>
+
+ <PROGRAMLISTING>
+ $TTL 680400
+ @ IN SOA lunn.org. andrew.lunn.lunn.org (
+ 2003041801 ; serial
+ 10800 ; refresh
+ 1800 ; retry
+ 3600000 ; expire
+ 259200) ; mimimum
+ IN NS londo.lunn.org.
+
+ hostnamev4 IN A 192.168.88.1
+ cnamev4 IN CNAME hostnamev4
+ hostnamev6 IN AAAA fec0::88:4:3:2:1
+ cnamev6 IN CNAME hostnamev6
+ hostnamev46 IN A 192.168.88.2
+ hostnamev46 IN AAAA fec0::88:4:3:2:2
+ cnamev46 IN CNAME hostnamev46
+ </PROGRAMLISTING>
+ <PARA>The actual names and addresses do not matter, since they are
+ configurable in the test. What is important is the relationship
+ between the names and the addresses and there family. ie
+ hostnamev4 should map to one IPv4 address. hostnamev46 should
+ map to both an IPv4 and an IPv6 address. cnamev4 should be a
+ CNAME record for hostname4. Reverse lookup information is also
+ needed by the test.
+ </PARA>
+ <PARA>The information placed into the DNS server is also need in the
+ test case. A structure is defined to hold this
+ information:</PARA>
+ <PROGRAMLISTING>
+ struct test_info_s {
+ char * dns_server;
+ char * domain_name;
+ char * hostname_v4;
+ char * cname_v4;
+ char * ip_addr_v4;
+ char * hostname_v6;
+ char * cname_v6;
+ char * ip_addr_v6;
+ char * hostname_v46;
+ char * cname_v46;
+ char * ip_addr_v46_v4;
+ char * ip_addr_v46_v6;
+ };
+ </PROGRAMLISTING>
+ <PARA>The test program may hold a number of such structures for
+ different DNS server. The test will use each structure in turn
+ to perform the tests. If IPv6 is not enabled in the eCos
+ configuration, the entries which use IPv6 may be assigned to
+ NULL.
+ </PARA>
+ </SECT1>
+ </CHAPTER>
</PART>
Index: net//ns/dns/current/include/dns.h
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/ns/dns/current/include/dns.h,v
retrieving revision 1.3
diff -u -r1.3 dns.h
--- net//ns/dns/current/include/dns.h 18 Jan 2003 04:18:49 -0000 1.3
+++ net//ns/dns/current/include/dns.h 8 May 2003 07:13:00 -0000
@@ -83,6 +83,15 @@
#define NO_RECOVERY 3
#define NO_DATA 4
+// Interface between the DNS client and getaddrinfo
+externC int
+cyg_dns_getaddrinfo(const char * hostname,
+ struct sockaddr addrs[], int num,
+ int family, char **canon);
+// Interface between the DNS client and getnameinfo
+externC int
+cyg_dns_getnameinfo(const struct sockaddr * sa, char * host, size_t hostlen);
+
//-----------------------------------------------------------------------------
#endif // CYGONCE_NS_DNS_DNS_H
// End of dns.h
Index: net//ns/dns/current/include/dns_impl.inl
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/ns/dns/current/include/dns_impl.inl,v
retrieving revision 1.4
diff -u -r1.4 dns_impl.inl
--- net//ns/dns/current/include/dns_impl.inl 18 Jan 2003 04:18:49 -0000 1.4
+++ net//ns/dns/current/include/dns_impl.inl 8 May 2003 07:13:00 -0000
@@ -191,7 +191,7 @@
/* Build a query message which can be sent to the server. If something
goes wrong return -1, otherwise the length of the query message */
static int
-build_query(char * msg, const char * hostname, short rr_type)
+build_query(const char * msg, const char * hostname, short rr_type)
{
struct dns_header *dns_hdr;
char *ptr;
@@ -251,6 +251,33 @@
return hent;
}
+#ifdef CYGPKG_NET_INET6
+/* Check if the hostname is actually colon format of IPv6. If so convert it
+ and return host entity structure. If not, return NULL. */
+static struct hostent *
+colon_hostname(const char *hostname)
+{
+ struct sockaddr_in6 addr;
+ struct hostent *hent = NULL;
+
+ if (inet_pton(AF_INET6, hostname, (void *)&addr)) {
+ hent = alloc_hent();
+ if (hent) {
+ memcpy(hent->h_addr_list[0], &addr, sizeof(addr));
+ hent->h_addrtype = AF_INET6;
+ hent->h_length = sizeof(addr);
+ hent->h_name = alloc_string(strlen(hostname)+1);
+ if (!hent->h_name) {
+ free_hent(hent);
+ return NULL;
+ }
+ strcpy(hent->h_name, hostname);
+ }
+ }
+ return hent;
+}
+#endif
+
/* Decode the answer from the server. Returns NULL if failed, or
a hostent structure containing different data depending on the
query type:
@@ -418,14 +445,37 @@
return hent;
}
+/* Build message, send, receive and decode */
+static struct hostent *
+do_query(const char * hostname)
+{
+ unsigned char msg[MAXDNSMSGSIZE];
+ int len;
+
+ memset(msg, 0, sizeof(msg));
+ len = build_query(msg, hostname, DNS_TYPE_A);
+ if (len < 0) {
+ return NULL;
+ }
+
+ /* Send the query and wait for an answer */
+ len = send_recv(msg, len, sizeof(msg));
+ if (len < 0) {
+ return NULL;
+ }
+
+ /* Decode the answer */
+ return parse_answer(msg, DNS_TYPE_A);
+}
+
+
/* Given a hostname find out the IP address */
struct hostent *
gethostbyname(const char * hostname)
{
- unsigned char msg[MAXDNSMSGSIZE];
char name[256];
+ char * dot;
struct hostent *hent;
- int len;
CYG_REPORT_FUNCNAMETYPE( "gethostbyname", "returning %08x" );
CYG_REPORT_FUNCARG1( "hostname=%08x", hostname );
@@ -448,42 +498,25 @@
free_stored_hent();
if (!valid_hostname(hostname)) {
- /* It could be a dot address */
- hent = dot_hostname(hostname);
- store_hent(hent);
- CYG_REPORT_RETVAL( hent );
- return hent;
+ /* It could be a dot address */
+ if ((hent = dot_hostname(hostname)) != NULL) {
+ store_hent(hent);
+ CYG_REPORT_RETVAL( hent );
+ return hent;
+ }
+#ifdef CYGPKG_NET_INET6
+ /* It could be a colon seperated IPv6 address */
+ if ((hent = colon_hostname(hostname)) != NULL) {
+ store_hent(hent);
+ CYG_REPORT_RETVAL( hent );
+ return hent;
+ }
+#endif
+ CYG_REPORT_RETVAL( hent );
+ return hent;
}
-
cyg_drv_mutex_lock(&dns_mutex);
- /* First try the name as passed in */
- memset(msg, 0, sizeof(msg));
- len = build_query(msg, hostname, DNS_TYPE_A);
- if (len < 0) {
- cyg_drv_mutex_unlock(&dns_mutex);
- CYG_REPORT_RETVAL( NULL );
- return NULL;
- }
-
- /* Send the query and wait for an answer */
- len = send_recv(msg, len, sizeof(msg));
- if (len < 0) {
- cyg_drv_mutex_unlock(&dns_mutex);
- CYG_REPORT_RETVAL( NULL );
- return NULL;
- }
-
- /* Decode the answer */
- hent = parse_answer(msg, DNS_TYPE_A);
- if (hent) {
- cyg_drv_mutex_unlock(&dns_mutex);
- store_hent(hent);
- CYG_REPORT_RETVAL( hent );
- return hent;
- }
-
- /* If no match, try appending the domainname if we have one */
if (domainname) {
if ((strlen(hostname) + strlen(domainname)) > 254) {
h_errno = NO_RECOVERY;
@@ -494,27 +527,36 @@
strcpy(name, hostname);
strcat(name, ".");
strcat(name, domainname);
-
- memset(msg, 0, sizeof(msg));
- len = build_query(msg, name, DNS_TYPE_A);
- if (len < 0) {
- cyg_drv_mutex_unlock(&dns_mutex);
- CYG_REPORT_RETVAL( NULL );
- return NULL;
+ }
+
+ /* If the hostname ends with . it a FQDN. Don't bother adding the
+ domainname. If it does not contain a . , try appending with the
+ domainname first. If it does have a . , try without a domain name
+ first. */
+
+ dot = rindex(hostname,'.');
+ if (dot) {
+ if (*(dot+1) == '\0') {
+ /* FQDN */
+ hent = do_query(hostname);
+ } else {
+ /* Dot somewhere */
+ hent = do_query(hostname);
+ if (domainname && (hent == NULL)) {
+ hent = do_query(name);
+ }
}
-
- /* Send the query and wait for an answer */
- len = send_recv(msg, len, sizeof(msg));
- if (len < 0) {
- cyg_drv_mutex_unlock(&dns_mutex);
- CYG_REPORT_RETVAL( NULL );
- return NULL;
+ } else {
+ /* No Dot. Try adding domainname first */
+ hent = NULL;
+ if (domainname) {
+ hent = do_query(name);
+ }
+ if (hent == NULL) {
+ hent = do_query(hostname);
}
-
- /* Decode the answer */
- hent = parse_answer(msg, DNS_TYPE_A);
}
-
+
cyg_drv_mutex_unlock(&dns_mutex);
store_hent(hent);
CYG_REPORT_RETVAL( hent );
@@ -526,6 +568,7 @@
setdomainname(const char *name, size_t len)
{
char * ptr;
+ int length;
CYG_REPORT_FUNCNAMETYPE( "setdomainname", "returning %d" );
CYG_REPORT_FUNCARG2( "name=%08x, len=%d", name, len );
@@ -537,13 +580,28 @@
}
if (len != 0) {
CYG_CHECK_DATA_PTR( name, "name is not a valid pointer!" );
- ptr = alloc_string(len+1);
+ length = strlen(name);
+ if (length > len) {
+ h_errno = NO_RECOVERY;
+ CYG_REPORT_RETVAL( -1 );
+ return -1;
+ }
+ if (name[length-1] != '.') {
+ length++;
+ }
+ ptr = alloc_string(length+1);
if (!ptr) {
+ h_errno = NO_RECOVERY;
CYG_REPORT_RETVAL( -1 );
return -1;
}
memcpy(ptr, name, len);
- ptr[len]=0;
+ if (name[length-1] != '.') {
+ ptr[length-1] = '.';
+ ptr[length] = '\0';
+ } else {
+ ptr[len]=0;
+ }
} else {
ptr = NULL;
}
Index: net//ns/dns/current/include/dns_priv.h
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/ns/dns/current/include/dns_priv.h,v
retrieving revision 1.3
diff -u -r1.3 dns_priv.h
--- net//ns/dns/current/include/dns_priv.h 29 Aug 2002 10:10:40 -0000 1.3
+++ net//ns/dns/current/include/dns_priv.h 8 May 2003 07:13:00 -0000
@@ -112,6 +112,7 @@
#define DNS_TYPE_NS 2 /* Authoritative name server */
#define DNS_TYPE_CNAME 5 /* Canonical name for an alias */
#define DNS_TYPE_PTR 12 /* Domain name pointer */
+#define DNS_TYPE_AAAA 28 /* IPv6 host address */
/* DNS CLASSs */
#define DNS_CLASS_IN 1 /* Internet */
Index: net//ns/dns/current/src/dns.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/ns/dns/current/src/dns.c,v
retrieving revision 1.4
diff -u -r1.4 dns.c
--- net//ns/dns/current/src/dns.c 31 May 2002 01:05:55 -0000 1.4
+++ net//ns/dns/current/src/dns.c 8 May 2003 07:13:00 -0000
@@ -315,3 +315,399 @@
CYG_REPORT_RETVAL( 0 );
return 0;
}
+
+/* add_answer checks to see if we already have this answer and if not,
+ adds it to the answers. */
+static int
+add_answer(char *rdata, short rr_type, int family,
+ struct sockaddr addrs[], int num, int used) {
+ int i;
+ int found = 0;
+
+ for (i = 0; i < used ; i++) {
+ if ((addrs[i].sa_family == family) &&
+ !memcmp(addrs[i].sa_data, rdata, addrs[i].sa_len)) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ memset(&addrs[used],0,sizeof(addrs[used]));
+ addrs[used].sa_family = family;
+
+ switch(family) {
+ case AF_INET: {
+ struct sockaddr_in * addr = (struct sockaddr_in *) &addrs[used];
+ addr->sin_len = sizeof(*addr);
+ memcpy(&addr->sin_addr, rdata, sizeof(struct in_addr));
+ used++;
+ break;
+ }
+#ifdef CYGPKG_NET_INET6
+ case AF_INET6: {
+ struct sockaddr_in6 * addr = (struct sockaddr_in6 *) &addrs[used];
+ addr->sin6_len = sizeof(*addr);
+ memcpy(&addr->sin6_addr, rdata, sizeof(struct in6_addr));
+ used++;
+ break;
+ }
+#endif
+ default:
+ used = -EAI_FAMILY;
+ }
+ }
+ return used;
+}
+
+/* This decodes the answer and puts the results into the addrs
+ array. This function can deal with IPv6 AAAA records as well as A
+ records. Thus its more complex than the parse_answer function in
+ the inline code. This complexity is only needed by getaddrinfo, so
+ i decided to leave parse_anser alone. */
+
+static int
+decode(char *msg, short rr_type, int family,
+ struct sockaddr addrs[], int num, int used, char **canon) {
+
+ struct dns_header *dns_hdr;
+ struct resource_record rr, *rr_p = NULL;
+ char *qname = NULL;
+ char *ptr;
+
+ dns_hdr = (struct dns_header *)msg;
+
+ if (DNS_REPLY_NAME_ERROR == dns_hdr->rcode) {
+ h_errno = HOST_NOT_FOUND;
+ return -EAI_NONAME;
+ }
+
+ if ((dns_hdr->qr != 1) ||
+ (dns_hdr->opcode != DNS_QUERY)) {
+ return -EAI_FAIL;
+ }
+
+ if (dns_hdr->rcode != DNS_REPLY_NOERR) {
+ return -EAI_NONAME;
+ }
+
+ dns_hdr->ancount = ntohs(dns_hdr->ancount);
+ dns_hdr->qdcount = ntohs(dns_hdr->qdcount);
+ ptr = (char *)&dns_hdr[1];
+
+ /* Skip over the query section */
+ if (dns_hdr->qdcount > 0) {
+ while (dns_hdr->qdcount) {
+ ptr += qname_len(ptr);
+ ptr += 4; /* skip type & class */
+ dns_hdr->qdcount--;
+ }
+ }
+
+ /* Read the answers resource records to find an answer of the
+ correct type. */
+ while (dns_hdr->ancount && (used >= 0) && (used < num)) {
+ qname = ptr;
+ ptr += qname_len(ptr);
+ rr_p = (struct resource_record *)ptr;
+ memcpy(&rr, ptr, sizeof(rr));
+ if ((rr.rr_type == htons(rr_type)) &&
+ (rr.class == htons(DNS_CLASS_IN))) {
+ used = add_answer(rr_p->rdata, rr_type, family, addrs, num, used);
+ if (canon && !*canon) {
+ *canon = real_name(msg,qname);
+ }
+ }
+ ptr += sizeof(struct resource_record) -
+ sizeof(rr.rdata) + ntohs(rr.rdlength);
+ dns_hdr->ancount--;
+ }
+ if (used == 0) {
+ return -EAI_NONAME;
+ }
+ return used;
+}
+
+/* Do a lookup for a particular type of resource record. */
+static int
+do_lookup (const char * hostname,
+ struct sockaddr addrs[], int num, int used,
+ short rr_type, int family, char **canon) {
+
+ unsigned char msg[MAXDNSMSGSIZE];
+ int error;
+ int len;
+
+ /* First try the name as passed in */
+ memset(msg, 0, sizeof(msg));
+ len = build_query(msg, hostname, rr_type);
+ if (len < 0) {
+ return -EAI_FAIL;
+ }
+
+ /* Send the query and wait for an answer */
+ len = send_recv(msg, len, sizeof(msg));
+ if (len < 0) {
+ return -EAI_FAIL;
+ }
+
+ /* Decode the answer */
+ error = decode(msg, rr_type, family, addrs, num, used, canon);
+ return error;
+}
+
+static int do_lookups(const char * hostname,
+ struct sockaddr addrs[], int num,
+ int family, char ** canon) {
+ int error;
+#ifdef CYGPKG_NET_INET6
+ int error6;
+#endif
+
+ switch (family) {
+ case AF_INET:
+ error = do_lookup(hostname, addrs, num, 0, DNS_TYPE_A, AF_INET, canon);
+ break;
+#ifdef CYGPKG_NET_INET6
+ case AF_INET6:
+ error = do_lookup(hostname, addrs, num, 0, DNS_TYPE_AAAA, AF_INET6, canon);
+ break;
+#endif
+ case PF_UNSPEC:
+#ifndef CYGPKG_NET_INET6
+ error = do_lookup(hostname, addrs, num, 0, DNS_TYPE_A, AF_INET, canon);
+#else
+#ifdef CYGOPT_NS_DNS_FIRST_FAMILTY_AF_INET
+ error = do_lookup(hostname, addrs, num, 0, DNS_TYPE_A, AF_INET, canon);
+ if (error > 0 ) {
+ error6 = do_lookup(hostname, addrs, num, error, DNS_TYPE_AAAA,
+ AF_INET6, canon);
+ } else {
+ error6 = do_lookup(hostname, addrs, num, 0, DNS_TYPE_AAAA,
+ AF_INET6, canon);
+ }
+ if (error6 > 0) {
+ error = error6;
+ }
+#else // CYGOPT_NS_DNS_FIRST_FAMILY_AF_INET
+ error6 = do_lookup(hostname, addrs, num, 0, DNS_TYPE_AAAA,
+ AF_INET6, canon);
+ if (error6> 0 ) {
+ error = do_lookup(hostname, addrs, num, error6, DNS_TYPE_A,
+ AF_INET, canon);
+ } else {
+ error = do_lookup(hostname, addrs, num, 0, DNS_TYPE_A,
+ AF_INET, canon);
+ }
+#endif // CYGOPT_NS_DNS_FIRST_FAMILY_AF_INET
+#endif // CYGPKG_NET_INET6
+ break;
+ default:
+ error = -EAI_FAMILY;
+ }
+ return error;
+}
+
+/* This implements the interface between getaddrinfo and the dns
+ client. hostent is not used here since that only works with IPv4
+ addresses, where as this function needs to be protocol
+ independent. */
+int
+cyg_dns_getaddrinfo(const char * hostname,
+ struct sockaddr addrs[], int num,
+ int family,
+ char ** canon)
+{
+ int error;
+ char name[256];
+ char * dot;
+
+ CYG_REPORT_FUNCNAMETYPE( "cyg_dns_getaddrinfo", "returning %08x" );
+ CYG_REPORT_FUNCARG3( "hostname=%08x, addrs=%08x, num=%2d",
+ hostname, addrs, num );
+
+ if ( !hostname || !addrs || !num ) {
+ CYG_REPORT_RETVAL( NULL );
+ return -EAI_FAIL;
+ }
+
+ CYG_CHECK_DATA_PTR( hostname, "hostname is not a valid pointer!" );
+ CYG_CHECK_DATA_PTR( addrs, "addrs is not a valid pointer!");
+ CYG_ASSERT( num > 0, "Invalid number of sockaddr stuctures");
+
+ if (!valid_hostname(hostname)) {
+ /* it could be a dot address */
+ struct sockaddr_in * sa4 = (struct sockaddr_in *)&addrs[0];
+ memset(&addrs[0],0,sizeof(struct sockaddr));
+ if (inet_pton(AF_INET, hostname, (char *)&sa4->sin_addr.s_addr)) {
+ sa4->sin_family = AF_INET;
+ sa4->sin_len = sizeof(*sa4);
+ CYG_REPORT_RETVAL (1);
+ return 1;
+ }
+#ifdef CYGPKG_NET_INET6
+ {
+ /* it could be a colon address */
+ struct sockaddr_in6 * sa6 = (struct sockaddr_in6 *)&addrs[0];
+ memset(&addrs[0],0,sizeof(struct sockaddr));
+ if (inet_pton(AF_INET6, hostname, (char *)&sa6->sin6_addr.s6_addr)) {
+ sa6->sin6_family = AF_INET6;
+ sa6->sin6_len = sizeof(*sa6);
+ CYG_REPORT_RETVAL (1);
+ return 1;
+ }
+ }
+#endif
+ CYG_REPORT_RETVAL (-EAI_NONAME);
+ return -EAI_NONAME;
+ }
+
+ /* Has the socket to the DNS server been opened? */
+ if (s < 0) {
+ CYG_REPORT_RETVAL( -EIA_FAIL );
+ return -EAI_FAIL;
+ }
+
+ if (domainname) {
+ if ((strlen(hostname) + strlen(domainname)) > 254) {
+ cyg_drv_mutex_unlock(&dns_mutex);
+ CYG_REPORT_RETVAL( -EAI_FAIL );
+ return -EAI_FAIL;
+ }
+ strcpy(name, hostname);
+ strcat(name, ".");
+ strcat(name, domainname);
+ }
+ cyg_drv_mutex_lock(&dns_mutex);
+
+ /* If the hostname ends with . it a FQDN. Don't bother adding the
+ domainname. If it does not contain a . , try appending with the
+ domainname first. If it does have a . , try without a domain name
+ first. */
+
+ dot = rindex(hostname,'.');
+ if (dot) {
+ if (*(dot+1) == '\0') {
+ /* FQDN */
+ error = do_lookups(hostname, addrs, num, family, canon);
+ } else {
+ /* Dot somewhere */
+ error = do_lookups(hostname, addrs, num, family, canon);
+ if (domainname && (error == -EAI_NONAME)) {
+ error = do_lookups(name, addrs, num, family, canon);
+ }
+ }
+ } else {
+ /* No Dot. Try adding domainname first */
+ error = -EAI_NONAME;
+ if (domainname) {
+ error = do_lookups(name, addrs, num, family, canon);
+ }
+ if (error == -EAI_NONAME) {
+ error = do_lookups(hostname, addrs, num, family, canon);
+ }
+ }
+ cyg_drv_mutex_unlock(&dns_mutex);
+ CYG_REPORT_RETVAL( error );
+ return error;
+}
+
+/* This implements the interface between getnameinfo and the dns
+ client. */
+externC int
+cyg_dns_getnameinfo(const struct sockaddr * sa, char * host, size_t hostlen)
+{
+ char hostname[80];
+ unsigned char msg[MAXDNSMSGSIZE];
+ struct hostent * hent;
+ int len;
+
+ CYG_REPORT_FUNCNAMETYPE( "cyg_dns_getnameinfo", "returning %08x" );
+ CYG_REPORT_FUNCARG3( "sa=%08x, host=%08x, hostlen=%3d",
+ sa, host, hostlen );
+
+ CYG_CHECK_DATA_PTR( sa, "sa is not a valid pointer");
+ CYG_CHECK_DATA_PTR( host, "host is not a valid data pointer");
+ CYG_ASSERT(hostlen >0, "Invalid host length");
+
+ /* Has the socket to the DNS server been opened? */
+ if (s < 0) {
+ CYG_REPORT_RETVAL( -EIA_FAIL );
+ return -EAI_FAIL;
+ }
+
+ cyg_drv_mutex_lock(&dns_mutex);
+
+ switch (sa->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in * sa4 = (struct sockaddr_in *)sa;
+ unsigned char * addr = (char *)&sa4->sin_addr.s_addr;
+ sprintf(hostname, "%d.%d.%d.%d.IN-ADDR.ARPA.",
+ addr[3],addr[2],addr[1],addr[0]);
+ break;
+ }
+#ifdef CYGPKG_NET_INET6
+ case AF_INET6: {
+ struct sockaddr_in6 * sa6 = (struct sockaddr_in6 *)sa;
+ int i;
+
+ for (i=15; i >= 0; i--) {
+ sprintf(&hostname[(15*2*2) - (i*2*2)], "%x.%x.",
+ sa6->sin6_addr.s6_addr[i] & 0x0f,
+ (sa6->sin6_addr.s6_addr[i] & 0xf0) >> 4);
+ }
+ sprintf(&hostname[16*2*2],"IP6.INT");
+ break;
+ }
+#endif
+ default:
+ cyg_drv_mutex_lock(&dns_mutex);
+ CYG_REPORT_RETVAL( -EAI_FAMILY);
+ return -EAI_FAMILY;
+ }
+
+ memset(msg, 0, sizeof(msg));
+
+ /* Build a PTR type request using the hostname */
+ len = build_query(msg, hostname, DNS_TYPE_PTR);
+ if (len < 0) {
+ cyg_drv_mutex_unlock(&dns_mutex);
+ CYG_REPORT_RETVAL( -EAI_FAIL );
+ return -EAI_FAIL;
+ }
+
+ /* Send the request and wait for an answer */
+ len = send_recv(msg, len, sizeof(msg));
+ if (len < 0) {
+ cyg_drv_mutex_unlock(&dns_mutex);
+ CYG_REPORT_RETVAL( -EAI_FAIL );
+ return -EAI_FAIL;
+ }
+
+ /* Parse the answer for the host name */
+ hent = parse_answer(msg, DNS_TYPE_PTR);
+
+ /* If no name is known return an error */
+ if (!hent) {
+ cyg_drv_mutex_unlock(&dns_mutex);
+ CYG_REPORT_RETVAL( -EAI_NONAME );
+ return -EAI_NONAME;
+ }
+
+ /* Otherwise copy it into our results buffer and tidy up */
+ strncpy(host, hent->h_name,hostlen);
+ free_hent(hent);
+
+ cyg_drv_mutex_unlock(&dns_mutex);
+ CYG_REPORT_RETVAL( -EAI_NONE );
+ return -EAI_NONE;
+}
+
+
+
+
+
+
+
+
+
+
Index: net//ns/dns/current/tests/dns1.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/ns/dns/current/tests/dns1.c,v
retrieving revision 1.4
diff -u -r1.4 dns1.c
--- net//ns/dns/current/tests/dns1.c 3 Mar 2003 17:57:10 -0000 1.4
+++ net//ns/dns/current/tests/dns1.c 8 May 2003 07:13:00 -0000
@@ -9,6 +9,7 @@
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Andrew Lunn
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
@@ -44,7 +45,7 @@
// Contributors: andrew.lunn, jskov
// Date: 2001-09-18
// Purpose:
-// Description: Test DNS functions. Note that the _XXX defines below
+// Description: Test DNS functions. Note that the structure below that
// control what addresses the test uses. These must be
// changed to match the particular testing network in which
// the test is to be run.
@@ -52,6 +53,7 @@
//####DESCRIPTIONEND####
//
//==========================================================================
+#include <pkgconf/ns_dns.h>
#include <network.h>
#include <netdb.h>
@@ -65,105 +67,772 @@
static cyg_thread thread_data;
static cyg_handle_t thread_handle;
-#define __string(_x) #_x
-#define __xstring(_x) __string(_x)
+#define NELEM(x) (sizeof(x) / sizeof(x[0]))
-// Change the following if you aren't using BOOTP! It's almost certainly not right for you.
-#define _DNS_IP __xstring(172.16.1.254) // test farm host addr
-#define _LOOKUP_FQDN __xstring(b.root-servers.net.) // should stay the same?
-#define _LOOKUP_DOMAINNAME __xstring(root-servers.net.)
-#define _LOOKUP_HOSTNAME __xstring(b)
-#define _LOOKUP_IP __xstring(128.9.0.107) // must be same as _LOOKUP_FQDN
-#define _LOOKUP_IP_BAD __xstring(10.0.0.0)
+struct test_info_s {
+ char * dns_server;
+ char * domain_name;
+ char * hostname_v4;
+ char * cname_v4;
+ char * ip_addr_v4;
+ char * hostname_v6;
+ char * cname_v6;
+ char * ip_addr_v6;
+ char * hostname_v46;
+ char * cname_v46;
+ char * ip_addr_v46_v4;
+ char * ip_addr_v46_v6;
+};
+
+struct test_info_s test_info[] = {
+ {
+ "192.168.10.1",
+ "lunn.org.",
+ "hostnamev4",
+ "cnamev4",
+ "192.168.88.1",
+ "hostnamev6",
+ "cnamev6",
+ "fec0::88:4:3:2:1",
+ "hostnamev46",
+ "cnamev46",
+ "192.168.88.2",
+ "fec0::88:4:3:2:2"
+ }
+};
-void
-dns_test(cyg_addrword_t p)
-{
+char * familytoa(int family) {
+
+ switch (family) {
+ case AF_INET:
+ return "AF_INET";
+#ifdef CYGPKG_NET_INET6
+ case AF_INET6:
+ return "AF_INET6";
+#endif
+ default:
+ return "Unknown";
+ }
+}
+
+void dns_test(struct test_info_s *info) {
struct in_addr addr;
struct hostent *hent;
char dn[256];
- int i;
+ char name[256];
+ char cname[256];
+ char buffer[256];
+ char buff[64];
+ size_t hostlen = 128;
+ char host[hostlen];
+ struct addrinfo * res;
+ struct addrinfo hints;
+ struct sockaddr_in sa4;
+#ifdef CYGPKG_NET_INET6
+ struct sockaddr_in6 sa6;
+ struct addrinfo *ai4, *ai6;
+#endif
+ int error;
+
+ if (inet_pton(AF_INET, info->dns_server, (void *)&addr) < 0) {
+ CYG_TEST_FAIL_FINISH("Error with DNS server address");
+ }
+ cyg_dns_res_init(&addr);
- CYG_TEST_INIT();
+ setdomainname(NULL,0);
+
+ inet_aton(info->ip_addr_v4, &addr);
+ strcpy(name,info->hostname_v4);
+ strcat(name,".");
+ strcat(name,info->domain_name);
+ strcpy(cname,info->cname_v4);
+ strcat(cname,".");
+ strcat(cname,info->domain_name);
+
+ // Lookup the IPv4 FQDN hostname
+ hent = gethostbyname(name);
+ if (hent != NULL) {
+ diag_sprintf(buffer,"Lookup %s: Result <%s is %s>",
+ name,
+ hent->h_name,
+ inet_ntoa(*(struct in_addr *)hent->h_addr));
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void*)&addr,
+ (void*)(hent->h_addr),
+ sizeof(struct in_addr))),
+ "IPv4 FQDN hostname address");
+ CYG_TEST_PASS_FAIL((0 == strcmp(name, hent->h_name)),
+ "IPv4 FQDN hostname name");
+ } else {
+ diag_sprintf(buffer,"IPv4 FQDN hostname: error %s",
+ hstrerror(h_errno));
+ CYG_TEST_FAIL(buffer);
+ }
+
+ // Lookup the IPv4 FQDN cname
+ hent = gethostbyname(cname);
+ if (hent != NULL) {
+ diag_sprintf(buffer,"Lookup %s: Result <%s is %s>",
+ cname,
+ hent->h_name,
+ inet_ntoa(*(struct in_addr *)hent->h_addr));
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void*)&addr,
+ (void*)(hent->h_addr),
+ sizeof(struct in_addr))),
+ "IPv4 FQDN cname address");
+ CYG_TEST_PASS_FAIL((0 == strcmp(name, hent->h_name)),
+ "IPv4 FQDN hostname name");
+ } else {
+ diag_sprintf(buffer,"IPv4 FQDN cname: error %s", hstrerror(h_errno));
+ CYG_TEST_FAIL(buffer);
+ }
+
+ // Lookup the IP address as a string. This does not require a DNS
+ // lookup. Just turn the value into binary
+ hent = gethostbyname(info->ip_addr_v4);
+ if (hent != NULL) {
+ diag_sprintf(buffer,"Lookup %s: Result <%s is %s>",
+ info->ip_addr_v4,
+ hent->h_name,
+ inet_ntoa(*(struct in_addr *)hent->h_addr));
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void*)&addr,
+ (void*)(hent->h_addr),
+ sizeof(struct in_addr))),
+ "IPv4 IP address");
+ CYG_TEST_PASS_FAIL((0 == strcmp(info->ip_addr_v4, hent->h_name)),
+ "IPv4 IP address name");
+
+ } else {
+ diag_sprintf(buffer,"IPv4 IP address: error %s", hstrerror(h_errno));
+ CYG_TEST_FAIL(buffer);
+ }
+
+ // Reverse lookup the IPv4 address, expect the FQDN hostname
+ hent = gethostbyaddr((char *)&addr, sizeof(struct in_addr), AF_INET);
+ if (hent != NULL) {
+ inet_ntop(AF_INET,(void *)&addr, buff, sizeof(buff));
+ diag_sprintf(buffer,"Reverse lookup %s: Result <%s is %s>",
+ buff,
+ hent->h_name,
+ inet_ntoa(*(struct in_addr *)hent->h_addr));
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void*)&addr,
+ (void*)(hent->h_addr),
+ sizeof(struct in_addr))),
+ "Reverse lookup IPv4 IP address");
+
+ CYG_TEST_PASS_FAIL((0 == strcmp(name, hent->h_name)),
+ "Reverse lookup IPv4 IP address name");
+ } else {
+ diag_sprintf(buffer,"Reverse lookup IPv4 IP address: error %s",
+ hstrerror(h_errno));
+ CYG_TEST_FAIL(buffer);
+ }
+
+ // Setup a domainname. We now don't have to use fully qualified
+ // domain names
+ setdomainname(info->domain_name, strlen(info->domain_name));
+ getdomainname(dn, sizeof(dn));
+ CYG_TEST_PASS_FAIL(0 == strcmp(info->domain_name, dn),
+ "{get|set}domainname");
+
+ // Make sure FQDN still work
+ strcpy(name,info->hostname_v4);
+ strcat(name,".");
+ strcat(name,info->domain_name);
+
+ hent = gethostbyname(name);
+ if (hent != NULL) {
+ diag_sprintf(buffer,"Lookup %s: Result <%s is %s>",
+ name,
+ hent->h_name,
+ inet_ntoa(*(struct in_addr *)hent->h_addr));
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void*)&addr,
+ (void*)(hent->h_addr),
+ sizeof(struct in_addr))),
+ "IPv4 FQDN hostname address");
+ CYG_TEST_PASS_FAIL((0 == strcmp(name, hent->h_name)),
+ "IPv4 FQDN hostname name");
+ } else {
+ diag_sprintf(buffer,"IPv4 FQDN hostname: error %s",
+ hstrerror(h_errno));
+ CYG_TEST_FAIL(buffer);
+ }
+
+ // Now just the hostname
+ hent = gethostbyname(info->hostname_v4);
+ if (hent != NULL) {
+ diag_sprintf(buffer,"Lookup %s: Result <%s is %s>",
+ info->hostname_v4,
+ hent->h_name,
+ inet_ntoa(*(struct in_addr *)hent->h_addr));
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void*)&addr,
+ (void*)(hent->h_addr),
+ sizeof(struct in_addr))),
+ "IPv4 hostname address");
+ CYG_TEST_PASS_FAIL((0 == strcmp(name, hent->h_name)),
+ "IPv4 hostname name");
+ } else {
+ diag_sprintf(buffer,"IPv4 hostname: error %s", hstrerror(h_errno));
+ CYG_TEST_FAIL(buffer);
+ }
+
+ // Run the same tests as above, but this time use getaddrinfo and
+ // getnameinfo.
+ setdomainname(NULL,0);
+
+ memset(&hints,0,sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ memset(&sa4,0,sizeof(sa4));
+ memcpy(&sa4.sin_addr, &addr, sizeof(addr));
+ sa4.sin_family=AF_INET;
+ sa4.sin_len = sizeof(sa4);
+
+ // Lookup the IPv4 FQDN hostname
+ error = getaddrinfo(name, NULL, &hints, &res);
+
+ if (error == EAI_NONE) {
+ getnameinfo(res->ai_addr, res->ai_addrlen,
+ buff, sizeof(buff),
+ NULL,0,NI_NUMERICHOST);
+ diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>",
+ name,
+ res->ai_canonname,
+ familytoa(res->ai_family),
+ buff);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa4,
+ (void*)res->ai_addr,
+ sizeof(sa4))) &&
+ (res->ai_family == AF_INET),
+ "IPv4 FQDN hostname address");
+ CYG_TEST_PASS_FAIL((0 == strcmp(name, res->ai_canonname)),
+ "IPv4 FQDN hostname name");
+ CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+ "IPv4 FQDN hostname one result");
+ freeaddrinfo(res);
+ } else {
+ diag_sprintf(buffer,"IPv4 FQDN hostname: error %s",
+ gai_strerror(error));
+ CYG_TEST_FAIL(buffer);
+ }
+
+ // Lookup the IPv4 FQDN cname
+ error = getaddrinfo(cname, NULL, &hints, &res);
+
+ if (error == EAI_NONE) {
+ getnameinfo(res->ai_addr, res->ai_addrlen,
+ buff, sizeof(buff),
+ NULL,0,NI_NUMERICHOST);
+ diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>",
+ cname,
+ res->ai_canonname,
+ familytoa(res->ai_family),
+ buff);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa4,
+ (void*)res->ai_addr,
+ sizeof(sa4))) &&
+ (res->ai_family == AF_INET),
+ "IPv4 FQDN cname address");
+ CYG_TEST_PASS_FAIL((0 == strcmp(name, res->ai_canonname)),
+ "IPv4 FQDN cname name");
+ CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+ "IPv4 FQDN cname one result");
+ freeaddrinfo(res);
+ } else {
+ diag_sprintf(buffer,"IPv4 FQDN cname: error %s", gai_strerror(error));
+ CYG_TEST_FAIL(buffer);
+ }
+
+ // Lookup the IP address as a string. This does not require a DNS
+ // lookup. Just turn the value into binary
+ hints.ai_flags = AI_NUMERICHOST;
+ error = getaddrinfo(info->ip_addr_v4, NULL, &hints, &res);
+
+ if (error == EAI_NONE) {
+ getnameinfo(res->ai_addr, res->ai_addrlen,
+ buff, sizeof(buff),
+ NULL,0,NI_NUMERICHOST);
+ diag_sprintf(buffer,"Lookup %s: Result <%s %s>",
+ info->ip_addr_v4,
+ familytoa(res->ai_family),
+ buff);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa4,
+ (void*)res->ai_addr,
+ sizeof(sa4))) &&
+ (res->ai_family == AF_INET),
+ "IPv4 IP address");
+ CYG_TEST_PASS_FAIL((NULL == res->ai_canonname),
+ "IPv4 IP address name");
+ CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+ "IPv4 IP address one result");
+ // Don't free results - use for next test.
+ } else {
+ diag_sprintf(buffer,"IPv4 IP address: error %s", gai_strerror(error));
+ CYG_TEST_FAIL(buffer);
+ }
- init_all_network_interfaces();
+ // Reverse lookup the IPv4 address, expect the FQDN hostname
+ error = getnameinfo(res->ai_addr,res->ai_addrlen,
+ host, hostlen, NULL, 0, 0);
+ if (error == EAI_NONE) {
+ diag_sprintf(buffer, "IPv4 Reverse lookup FDQN %s: Result %s",
+ info->ip_addr_v4,
+ host);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == strcmp(name, host)),
+ "IPv4 Reverse lookup FQDN");
+ } else {
+ diag_sprintf(buffer,"IPv4 Reverse lookup FQDN: error %s",
+ gai_strerror(error));
+ CYG_TEST_FAIL(buffer);
+ }
+ // Reverse lookup the IPv4 address, expect just the hostname part
+ error = getnameinfo(res->ai_addr,res->ai_addrlen,
+ host, hostlen, NULL, 0, NI_NOFQDN);
+ if (error == EAI_NONE) {
+ diag_sprintf(buffer, "IPv4 Reverse lookup hostname part %s: Result %s",
+ info->ip_addr_v4,
+ host);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == strcmp(info->hostname_v4, host)),
+ "IPv4 Reverse lookup hostname part");
+ } else {
+ diag_sprintf(buffer,"IPv4 Reverse lookup hostname part: error %s",
+ gai_strerror(error));
+ CYG_TEST_FAIL(buffer);
+ }
+ freeaddrinfo(res);
- CYG_TEST_INFO("Starting dns1 test");
+ // Setup a domainname. We now don't have to use fully qualified
+ // domain names
+ setdomainname(info->domain_name, strlen(info->domain_name));
+ getdomainname(dn, sizeof(dn));
+ CYG_TEST_PASS_FAIL(0 == strcmp(info->domain_name, dn),
+ "{get|set}domainname");
+
+ // Lookup the IPv4 FQDN hostname to make sure it still works
+ hints.ai_flags = AI_CANONNAME;
+ error = getaddrinfo(name, NULL, &hints, &res);
+
+ if (error == EAI_NONE) {
+ getnameinfo(res->ai_addr, res->ai_addrlen,
+ buff, sizeof(buff),
+ NULL,0,NI_NUMERICHOST);
+ diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>",
+ name,
+ res->ai_canonname,
+ familytoa(res->ai_family),
+ buff);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa4,
+ (void*)res->ai_addr,
+ sizeof(sa4))) &&
+ (res->ai_family == AF_INET),
+ "IPv4 FQDN hostname address");
+ CYG_TEST_PASS_FAIL((0 == strcmp(name, res->ai_canonname)),
+ "IPv4 FQDN hostname name");
+ CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+ "IPv4 FQDN hostname one result");
+ freeaddrinfo(res);
+ } else {
+ diag_sprintf(buffer,"IPv4 FQDN hostname: error %s",
+ gai_strerror(error));
+ CYG_TEST_FAIL(buffer);
+ }
+
+ // Now the host name without the domain name
+ error = getaddrinfo(info->hostname_v4, NULL, &hints, &res);
+
+ if (error == EAI_NONE) {
+ getnameinfo(res->ai_addr, res->ai_addrlen,
+ buff, sizeof(buff),
+ NULL,0,NI_NUMERICHOST);
+ diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>",
+ info->hostname_v4,
+ res->ai_canonname,
+ familytoa(res->ai_family),
+ buff);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa4,
+ (void*)res->ai_addr,
+ sizeof(sa4))) &&
+ (res->ai_family == AF_INET),
+ "IPv4 hostname address");
+ CYG_TEST_PASS_FAIL((0 == strcmp(name, res->ai_canonname)),
+ "IPv4 hostname name");
+ CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+ "IPv4 hostname one result");
+ freeaddrinfo(res);
+ } else {
+ diag_sprintf(buffer,"IPv4 hostname: error %s",
+ gai_strerror(error));
+ CYG_TEST_FAIL(buffer);
+ }
+#ifdef CYGPKG_NET_INET6
+ // Check we have the needed information for the IPv6 tests
+ if (!info->hostname_v6 || !info->cname_v6 || !info->ip_addr_v6) {
+ return;
+ }
setdomainname(NULL,0);
- for (i=0; i<2; i++) {
- /* Expect _LOOKUP_IP as the answer. This is a CNAME lookup */
- inet_aton(_LOOKUP_IP, &addr);
- hent = gethostbyname(_LOOKUP_FQDN);
- if (hent != NULL) {
- diag_printf("PASS:<%s is %s>\n", hent->h_name, inet_ntoa(*(struct in_addr *)hent->h_addr));
- if (0 != memcmp((void*)&addr, (void*)(hent->h_addr), sizeof(struct in_addr))) {
- diag_printf("FAIL:<expected " _LOOKUP_FQDN " to be " _LOOKUP_IP ">\n");
- }
- break;
- } else {
- diag_printf("FAIL:<Asked for " _LOOKUP_FQDN ". No answer: %s>\n", hstrerror(h_errno));
- CYG_TEST_INFO("Retrying with explicit DNS server");
- CYG_TEST_INFO("Connecting to DNS at " _DNS_IP);
- inet_aton(_DNS_IP, &addr);
- CYG_TEST_CHECK(cyg_dns_res_init(&addr) == 0, "Failed to initialize resolver");
- }
+ strcpy(name,info->hostname_v6);
+ strcat(name,".");
+ strcat(name,info->domain_name);
+ strcpy(cname,info->cname_v6);
+ strcat(cname,".");
+ strcat(cname,info->domain_name);
+
+ memset(&sa6,0,sizeof(sa6));
+ sa6.sin6_family = AF_INET6;
+ sa6.sin6_len = sizeof(sa6);
+ inet_pton(AF_INET6, info->ip_addr_v6, (void *)&sa6.sin6_addr);
+
+ // Lookup the IPv6 FQDN hostname
+ error = getaddrinfo(name, NULL, &hints, &res);
+
+ if (error == EAI_NONE) {
+ getnameinfo(res->ai_addr, res->ai_addrlen,
+ buff, sizeof(buff),
+ NULL,0,NI_NUMERICHOST);
+ diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>",
+ name,
+ res->ai_canonname,
+ familytoa(res->ai_family),
+ buff);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa6,
+ (void*)res->ai_addr,
+ sizeof(sa6))) &&
+ (res->ai_family == AF_INET6),
+ "IPv6 FQDN hostname address");
+ CYG_TEST_PASS_FAIL((0 == strcmp(name, res->ai_canonname)),
+ "IPv6 FQDN hostname name");
+ CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+ "IPv6 FQDN hostname one result");
+ freeaddrinfo(res);
+ } else {
+ diag_sprintf(buffer,"IPv6 FQDN hostname: error %s",
+ gai_strerror(error));
+ CYG_TEST_FAIL(buffer);
}
- /* Reverse lookup the _LOOKUP_IP addres, expect _LOOKUP_FQDN
- as the answer. */
- hent = gethostbyaddr((char *)&addr, sizeof(struct in_addr), AF_INET);
- if (hent != NULL) {
- diag_printf("PASS:<%s is %s>\n", hent->h_name, inet_ntoa(*(struct in_addr *)hent->h_addr));
- if (0 != strcmp(_LOOKUP_FQDN, hent->h_name)) {
- diag_printf("FAIL:<expected " _LOOKUP_IP " to be " _LOOKUP_FQDN ">\n");
- }
- } else {
- diag_printf("FAIL:<Asked for " _LOOKUP_IP ". No answer: %s>\n", hstrerror(h_errno));
- }
-
- /* This does not require a DNS lookup. Just turn the value into
- binary */
- hent = gethostbyname(_LOOKUP_IP);
- if (hent != NULL) {
- diag_printf("PASS:<%s is %s>\n", hent->h_name, inet_ntoa(*(struct in_addr *)hent->h_addr));
- } else {
- diag_printf("FAIL:<Asked for " _LOOKUP_IP ". No answer: %s>\n", hstrerror(h_errno));
- }
-
- /* Reverse lookup an address this is not in the server. Expect a
- NULL back */
- inet_aton(_LOOKUP_IP_BAD, &addr);
- hent = gethostbyaddr((char *)&addr, sizeof(struct in_addr), AF_INET);
- if (hent != NULL) {
- diag_printf("FAIL:<%s is %s>\n", hent->h_name, inet_ntoa(*(struct in_addr *)hent->h_addr));
+ // Lookup the IPv6 FQDN cname
+ error = getaddrinfo(cname, NULL, &hints, &res);
+
+ if (error == EAI_NONE) {
+ getnameinfo(res->ai_addr, res->ai_addrlen,
+ buff, sizeof(buff),
+ NULL,0,NI_NUMERICHOST);
+ diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>",
+ cname,
+ res->ai_canonname,
+ familytoa(res->ai_family),
+ buff);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa6,
+ (void*)res->ai_addr,
+ sizeof(sa6))) &&
+ (res->ai_family == AF_INET6),
+ "IPv6 FQDN cname address");
+ CYG_TEST_PASS_FAIL((0 == strcmp(name, res->ai_canonname)),
+ "IPv6 FQDN cname name");
+ CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+ "IPv6 FQDN cname one result");
+ freeaddrinfo(res);
} else {
- diag_printf("PASS:<Asked for bad IP " _LOOKUP_IP_BAD ". No answer: %s>\n", hstrerror(h_errno));
+ diag_sprintf(buffer,"IPv6 FQDN cname: error %s",
+ gai_strerror(error));
+ CYG_TEST_FAIL(buffer);
}
- /* Setup a domainname. We now don't have to use fully qualified
- domain names */
- setdomainname(_LOOKUP_DOMAINNAME, sizeof(_LOOKUP_DOMAINNAME));
+ // Lookup the IP address as a string. This does not require a DNS
+ // lookup. Just turn the value into binary
+ hints.ai_flags = AI_NUMERICHOST;
+ error = getaddrinfo(info->ip_addr_v6, NULL, &hints, &res);
+
+ if (error == EAI_NONE) {
+ getnameinfo(res->ai_addr, res->ai_addrlen,
+ buff, sizeof(buff),
+ NULL,0,NI_NUMERICHOST);
+ diag_sprintf(buffer,"Lookup %s: Result <%s %s>",
+ info->ip_addr_v6,
+ familytoa(res->ai_family),
+ buff);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa6,
+ (void*)res->ai_addr,
+ sizeof(sa6))) &&
+ (res->ai_family == AF_INET6),
+ "IPv6 IP address");
+ CYG_TEST_PASS_FAIL((NULL == res->ai_canonname),
+ "IPv6 IP address name");
+ CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+ "IPv6 IP address one result");
+ // Don't free the result, use it in the next tests
+ } else {
+ diag_sprintf(buffer,"IPv6 IP address: error %s", gai_strerror(error));
+ CYG_TEST_FAIL(buffer);
+ }
+
+ // Reverse lookup the IPv6 address, expect the FQDN hostname
+ error = getnameinfo(res->ai_addr,res->ai_addrlen,
+ host, hostlen, NULL, 0, 0);
+ if (error == EAI_NONE) {
+ diag_sprintf(buffer, "IPv6 Reverse lookup FDQN %s: Result %s",
+ info->ip_addr_v6,
+ host);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == strcmp(name, host)),
+ "IPv6 Reverse lookup FQDN");
+ } else {
+ diag_sprintf(buffer,"IPv6 Reverse lookup FQDN: error %s",
+ gai_strerror(error));
+ CYG_TEST_FAIL(buffer);
+ }
+ // Reverse lookup the IPv6 address, expect just the hostname part
+ error = getnameinfo(res->ai_addr,res->ai_addrlen,
+ host, hostlen, NULL, 0, NI_NOFQDN);
+ if (error == EAI_NONE) {
+ diag_sprintf(buffer, "IPv6 Reverse lookup hostname part %s: Result %s",
+ info->ip_addr_v6,
+ host);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == strcmp(info->hostname_v6, host)),
+ "IPv6 Reverse lookup hostname part");
+ } else {
+ diag_sprintf(buffer,"IPv6 Reverse lookup hostname part: error %s",
+ gai_strerror(error));
+ CYG_TEST_FAIL(buffer);
+ }
+ freeaddrinfo(res);
+
+ // Setup a domainname. We now don't have to use fully qualified
+ // domain names
+ setdomainname(info->domain_name, strlen(info->domain_name));
getdomainname(dn, sizeof(dn));
- diag_printf("INFO:<Domainname is now %s>\n", dn);
+ CYG_TEST_PASS_FAIL(0 == strcmp(info->domain_name, dn),
+ "{get|set}domainname");
- /* Make sure FQDN still work */
- hent = gethostbyname(_LOOKUP_FQDN);
- if (hent != NULL) {
- diag_printf("PASS:<%s is %s>\n", hent->h_name, inet_ntoa(*(struct in_addr *)hent->h_addr));
+ // Lookup the IPv6 FQDN hostname to make sure it still works
+ hints.ai_flags = AI_CANONNAME;
+ error = getaddrinfo(name, NULL, &hints, &res);
+
+ if (error == EAI_NONE) {
+ getnameinfo(res->ai_addr, res->ai_addrlen,
+ buff, sizeof(buff),
+ NULL,0,NI_NUMERICHOST);
+ diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>",
+ name,
+ res->ai_canonname,
+ familytoa(res->ai_family),
+ buff);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa6,
+ (void*)res->ai_addr,
+ sizeof(sa6))) &&
+ (res->ai_family == AF_INET6),
+ "IPv6 FQDN hostname address");
+ CYG_TEST_PASS_FAIL((0 == strcmp(name, res->ai_canonname)),
+ "IPv6 FQDN hostname name");
+ CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+ "IPv6 FQDN hostname one result");
+ freeaddrinfo(res);
} else {
- diag_printf("FAIL:<Asked for " _LOOKUP_FQDN ". No answer: %s>\n", hstrerror(h_errno));
+ diag_sprintf(buffer,"IPv6 FQDN hostname: error %s",
+ gai_strerror(error));
+ CYG_TEST_FAIL(buffer);
}
- /* Now just the hostname */
- hent = gethostbyname(_LOOKUP_HOSTNAME);
- if (hent != NULL) {
- diag_printf("PASS:<%s is %s>\n", _LOOKUP_HOSTNAME, inet_ntoa(*(struct in_addr *)hent->h_addr));
+ // Now the host name without the domain name
+ error = getaddrinfo(info->hostname_v6, NULL, &hints, &res);
+
+ if (error == EAI_NONE) {
+ getnameinfo(res->ai_addr, res->ai_addrlen,
+ buff, sizeof(buff),
+ NULL,0,NI_NUMERICHOST);
+ diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>",
+ info->hostname_v6,
+ res->ai_canonname,
+ familytoa(res->ai_family),
+ buff);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa6,
+ (void*)res->ai_addr,
+ sizeof(sa6))) &&
+ (res->ai_family == AF_INET6),
+ "IPv6 hostname address");
+ CYG_TEST_PASS_FAIL((0 == strcmp(name, res->ai_canonname)),
+ "IPv6 hostname name");
+ CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+ "IPv6 hostname one result");
+ freeaddrinfo(res);
} else {
- diag_printf("FAIL:<Asked for " _LOOKUP_HOSTNAME ". No answer: %s>\n", hstrerror(h_errno));
+ diag_sprintf(buffer,"IPv6 hostname: error %s",
+ gai_strerror(error));
+ CYG_TEST_FAIL(buffer);
}
+ // Check if we have the information to do tests which result in two
+ // answers, an AF_INET and an AF_INET6
+ if (!info->hostname_v46 || !info->cname_v46 ||
+ !info->ip_addr_v46_v4 || !info->ip_addr_v46_v6 ) {
+ return;
+ }
+ setdomainname(NULL,0);
+
+ strcpy(name,info->hostname_v46);
+ strcat(name,".");
+ strcat(name,info->domain_name);
+ strcpy(cname,info->cname_v46);
+ strcat(cname,".");
+ strcat(cname,info->domain_name);
+
+ inet_aton(info->ip_addr_v46_v4, &addr);
+ memset(&sa4,0,sizeof(sa4));
+ memcpy(&sa4.sin_addr, &addr, sizeof(addr));
+ sa4.sin_family=AF_INET;
+ sa4.sin_len = sizeof(sa4);
+
+ memset(&sa6,0,sizeof(sa6));
+ sa6.sin6_family = AF_INET6;
+ sa6.sin6_len = sizeof(sa6);
+ inet_pton(AF_INET6, info->ip_addr_v46_v6, (void *)&sa6.sin6_addr);
+
+ // Lookup the IPv4 and IPv6 FQDN hostname
+ error = getaddrinfo(name, NULL, &hints, &res);
+
+ if (error == EAI_NONE) {
+#ifdef CYGOPT_NS_DNS_FIRST_FAMILY_AF_INET6
+ ai6 = res;
+ ai4 = res->ai_next;
+ CYG_TEST_PASS_FAIL((NULL != ai6->ai_next),
+ "IPv6 FQDN hostname not one result");
+ CYG_TEST_PASS_FAIL((NULL == ai4->ai_next),
+ "IPv4 & IPv6 FQDN hostname two results");
+#else
+ ai4 = res;
+ ai6 = res->ai_next;
+ CYG_TEST_PASS_FAIL((NULL != ai4->ai_next),
+ "IPv6 FQDN hostname not one result");
+ CYG_TEST_PASS_FAIL((NULL == ai6->ai_next),
+ "IPv4 & IPv6 FQDN hostname two results");
+#endif
+ getnameinfo(ai4->ai_addr, ai4->ai_addrlen,
+ buff, sizeof(buff),
+ NULL,0,NI_NUMERICHOST);
+ diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>",
+ name,
+ ai4->ai_canonname,
+ familytoa(ai4->ai_family),
+ buff);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa4,
+ (void*)ai4->ai_addr,
+ sizeof(sa4))) &&
+ (ai4->ai_family == AF_INET),
+ "IPv4 & IPv6 FQDN hostname address IPv4");
+ CYG_TEST_PASS_FAIL((0 == strcmp(name, ai4->ai_canonname)),
+ "IPv4 & IPv6 FQDN hostname name");
+ getnameinfo(ai6->ai_addr, ai6->ai_addrlen,
+ buff, sizeof(buff),
+ NULL,0,NI_NUMERICHOST);
+ diag_sprintf(buffer,"Lookup %s: Result <%s %s>",
+ name,
+ familytoa(ai6->ai_family),
+ buff);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa6,
+ (void*)ai6->ai_addr,
+ sizeof(sa6))) &&
+ (ai6->ai_family == AF_INET6),
+ "IPv4 & IPv6 FQDN hostname address IPv6");
+ freeaddrinfo(res);
+ } else {
+ diag_sprintf(buffer,"IPv4 & IPv6 FQDN hostname: error %s",
+ gai_strerror(error));
+ CYG_TEST_FAIL(buffer);
+ }
+
+ // Lookup the IPv4 and IPv6 FQDN cname
+ error = getaddrinfo(cname, NULL, &hints, &res);
+
+ if (error == EAI_NONE) {
+#ifdef CYGOPT_NS_DNS_FIRST_FAMILY_AF_INET6
+ ai6 = res;
+ ai4 = res->ai_next;
+ CYG_TEST_PASS_FAIL((NULL != ai6->ai_next),
+ "IPv6 FQDN hostname not one result");
+ CYG_TEST_PASS_FAIL((NULL == ai4->ai_next),
+ "IPv4 & IPv6 FQDN hostname two results");
+#else
+ ai4 = res;
+ ai6 = res->ai_next;
+ CYG_TEST_PASS_FAIL((NULL != ai4->ai_next),
+ "IPv6 FQDN hostname not one result");
+ CYG_TEST_PASS_FAIL((NULL == ai6->ai_next),
+ "IPv4 & IPv6 FQDN hostname two results");
+#endif
+ getnameinfo(ai4->ai_addr, ai4->ai_addrlen,
+ buff, sizeof(buff),
+ NULL,0,NI_NUMERICHOST);
+ diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>",
+ cname,
+ ai4->ai_canonname,
+ familytoa(ai4->ai_family),
+ buff);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa4,
+ (void*)ai4->ai_addr,
+ sizeof(sa4))) &&
+ (ai4->ai_family == AF_INET),
+ "IPv4 & IPv6 FQDN cname address IPv4");
+ CYG_TEST_PASS_FAIL((0 == strcmp(name, ai4->ai_canonname)),
+ "IPv4 & IPv6 FQDN cname name");
+ getnameinfo(ai6->ai_addr, ai6->ai_addrlen,
+ buff, sizeof(buff),
+ NULL,0,NI_NUMERICHOST);
+ diag_sprintf(buffer,"Lookup %s: Result <%s %s>",
+ cname,
+ familytoa(ai6->ai_family),
+ buff);
+ CYG_TEST_INFO(buffer);
+ CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa6,
+ (void*)ai6->ai_addr,
+ sizeof(sa6))) &&
+ (ai6->ai_family == AF_INET6),
+ "IPv4 & IPv6 FQDN cname address IPv6");
+ freeaddrinfo(res);
+ } else {
+ diag_sprintf(buffer,"IPv4 & IPv6 FQDN cname: error %s",
+ gai_strerror(error));
+ CYG_TEST_FAIL(buffer);
+ }
+#endif
+}
+
+void
+dns_test_thread(cyg_addrword_t p)
+{
+ int i;
+
+ CYG_TEST_INIT();
+
+ init_all_network_interfaces();
+
+ CYG_TEST_INFO("Starting dns1 test");
+
+ for (i = 0; i < NELEM(test_info); i++) {
+ dns_test(&test_info[i]);
+ }
+
CYG_TEST_FINISH("dns1 test completed");
}
@@ -172,7 +841,7 @@
{
// Create a main thread, so we can run the scheduler and have time 'pass'
cyg_thread_create(10, // Priority - just a number
- dns_test, // entry
+ dns_test_thread, // entry
0, // entry parameter
"DNS test", // Name
&stack[0], // Stack
More information about the Ecos-patches
mailing list