Mercurial > flash_v2
view packages/net/common/current/src/getaddrinfo.c @ 957:db3e0a2fda2f
2003-04-12 Andrew Lunn <andrew.lunn@ascom.ch>
* src/network_support.c (init_loopback_interface): Close the
socket when things go wrong otherwise we leak sockets.
* src/tftp_server.c (tftpd_server): Added support for IPv6 as well
as IPv4. Extended the multithreading support so that it works
correctly when there are multiple servers on multiple ports.
* doc/tcpip.sgml: Documentation for the changes made to the tftp
server.
2003-04-10 Andrew Lunn <andrew.lunn@ascom.ch>
* src/network_support.c (init_all_network_interfaces): Wait upto 4
seconds for a router solicit message to be received. Once we have
received the message we know we have a valid IPv6 address.
* src/tftp_client.c: Added support for IPv6. This requires two new
functions, tftp_client_{get|put} which are protocol version
independent.
* tests/tftp_client_test.c (tftp_test): Added tests which use IPv6
addresses.
2003-04-07 Andrew Lunn <andrew.lunn@ascom.ch>
* src/getaddrinfo.c (getaddrinfo): Correctly deal with node when
its not NULL. Its OK for the address to not parse for an address
family when AF_UNSPEC is passed in hints. Also get the socktype
correct when wildcarding for services that use UDP.
* tests/addr_test.c: Added more test cases which test IP addresses
in number format as node.
2003-04-05 Andrew Lunn <andrew.lunn@ascom.ch>
* cdl/net.cdl: Added addr_tests to the HW tests.
* tests/addr_test.c (net_test): void function not int.
* tests/ping_test.c (net_test): Added IPv6 ping test. This pings
the router which answers our router solicit message.
* src/ipv6_routing_thread.c (cyg_rs): Print out the router
advertisement message. Cleaned up the debug messages so they can
be disabled.
* src/ipv6_routing_thread.c (cyg_net_get_ipv6_advrouter): New
function to return the address of the router.
* include/network.h: Added prototype for above and
ipv6_start_routing_thread which did not have a prototype.
* src/ipv6_routing_thread.c (cyg_rs): Only wait 2 seconds before
sending the first solicit request rather than 10.
* src/dhcp_prot.c (do_dhcp_down_net): clear the if_laddrreq
before using it. If the request fails finish the IPv4 code rather
than returning,.
2003-04-02 Andrew Lunn <andrew.lunn@ascom.ch>
* tests/ping_lo_test.c: Added IPv6 ping test.
* src/getproto.c: Added the protocol ipv6-icmp.
| author | asl |
|---|---|
| date | Wed, 23 Apr 2003 08:52:08 +0000 |
| parents | c16ef62116ec |
| children | 16d247bb9c70 |
line wrap: on
line source
//========================================================================== // // lib/getaddrinfo.c // // getaddrinfo(), freeaddrinfo(), gai_strerror(), getnameinfo() // //========================================================================== //####ECOSPDCOPYRIGHTBEGIN#### // // Copyright (C) 2000, 2001, 2002 Red Hat, Inc. // Copyright (C) 2003 Gary Thomas // Copyright (C) 2003 andrew.lunn@ascom.ch // All Rights Reserved. // // Permission is granted to use, copy, modify and redistribute this // file. // //####ECOSPDCOPYRIGHTEND#### //========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas // Contributors: gthomas, andrew.lunn@ascom.ch // Date: 2002-03-05 // Purpose: // Description: // // //####DESCRIPTIONEND#### // //========================================================================== #include <sys/param.h> #include <sys/socket.h> // PF_xxx #include <netinet/in.h> // IPPROTO_xx #include <net/netdb.h> #include <netdb.h> // DNS support routines #include <errno.h> #include <cyg/infra/cyg_ass.h> 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 static int _getaddr(struct addrinfo *ai, const char *node, const struct addrinfo *hints, int family, int port) { struct hostent *_hent; 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; } 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); #endif } } else { _hent = gethostbyname(node); if (_hent) { memcpy(&sa->sin_addr.s_addr, _hent->h_addr, sizeof(struct in_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 } } } } 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; } 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 } } } break; #endif } return EAI_NONE; } int getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { struct addrinfo dflt_hints; struct protoent *proto = (struct protoent *)NULL; struct addrinfo *ai; #ifdef CYGPKG_NET_INET6 struct addrinfo *nai; #endif char *protoname; char *endptr; int port = 0; int err; int used = 0; if (hints == (struct addrinfo *)NULL) { dflt_hints.ai_flags = 0; // No special flags dflt_hints.ai_family = PF_UNSPEC; dflt_hints.ai_socktype = 0; dflt_hints.ai_protocol = 0; hints = &dflt_hints; } // Prevalidate parameters if ((nodename == (char *)NULL) && (servname == (char *)NULL)) { return EAI_NONAME; } switch (hints->ai_family) { case PF_UNSPEC: case PF_INET: break; #ifdef CYGPKG_NET_INET6 case PF_INET6: break; #endif default: return EAI_FAMILY; } // Allocate the first/primary result *res = ai = (struct addrinfo *)calloc(1, sizeof(struct addrinfo)); if (ai == (struct addrinfo *)NULL) { return EAI_MEMORY; } // Handle request if (hints->ai_protocol != 0) { proto = getprotobynumber(hints->ai_protocol); } if (servname != (char *)NULL) { switch (hints->ai_socktype) { case 0: case SOCK_STREAM: protoname = "tcp"; ai->ai_socktype = SOCK_STREAM; break; case SOCK_DGRAM: protoname = "udp"; ai->ai_socktype = SOCK_DGRAM; break; default: freeaddrinfo(ai); return EAI_SOCKTYPE; } // See if this is just a port # if (((port = strtol(servname, &endptr, 0)) >= 0) && (endptr > servname)) { ai->ai_socktype = hints->ai_socktype; if (hints->ai_socktype == 0) { // Need to have complete binding type/port freeaddrinfo(ai); return EAI_SERVICE; } } else { struct servent *serv = (struct servent *)NULL; serv = getservbyname(servname, protoname); if (serv == (struct servent *)NULL) { if (hints->ai_socktype == 0) { protoname = "udp"; serv = getservbyname(servname, protoname); } } if (serv == (struct servent *)NULL) { freeaddrinfo(ai); 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)) { freeaddrinfo(ai); return EAI_SOCKTYPE; } 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)) { 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 (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 (ai->ai_canonname) { strcpy(ai->ai_canonname, nodename); } } if (hints->ai_flags & AI_PASSIVE) { // Incomplete addressing - used for bind/listen } else { // Complete addressing - used for connect/send/... } return EAI_NONE; // No errors } void freeaddrinfo(struct addrinfo *ai) { struct addrinfo *next = ai; while ((ai = next) != (struct addrinfo *)NULL) { if (ai->ai_canonname) free(ai->ai_canonname); if (ai->ai_addr) free(ai->ai_addr); next = ai->ai_next; free(ai); } } char *gai_strerror(int err) { switch (err) { case EAI_NONE: return "EAI - no error"; case EAI_AGAIN: return "EAI - temporary failure in name resolution"; case EAI_BADFLAGS: return "EAI - invalid flags"; case EAI_FAIL: return "EAI - non-recoverable failure in name resolution"; case EAI_FAMILY: return "EAI - family not supported"; case EAI_MEMORY: return "EAI - memory allocation failure"; case EAI_NONAME: return "EAI - hostname nor servname provided, or not known"; case EAI_SERVICE: return "EAI - servname not supported for socket type"; case EAI_SOCKTYPE: return "EAI - socket type not supported"; case EAI_SYSTEM: return "EAI - system error"; case EAI_BADHINTS: return "EAI - inconsistent hints"; case EAI_PROTOCOL: return "EAI - bad protocol"; default: return "EAI - unknown error"; } } // Set of flags implemented #define NI_MASK (NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM) int getnameinfo (const struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, unsigned int flags) { int port; char *s; struct servent *se; if ((flags & ~NI_MASK) != 0) { return EAI_BADFLAGS; } switch (sa->sa_family) { case PF_INET: #ifdef CYGPKG_NET_INET6 case PF_INET6: #endif if (host != (char *)NULL) { s = _inet_ntop((struct sockaddr *)sa, host, hostlen); if (!s) { return EAI_FAIL; } } if (serv != (char *)NULL) { port = _inet_port((struct sockaddr *)sa); if (!port) { return EAI_FAIL; } se = (struct servent *)NULL; if ((flags & NI_NUMERICSERV) == 0) { if ((flags & NI_DGRAM) == 0) { se = getservbyport(port, "tcp"); } if (se == (struct servent *)NULL) { se = getservbyport(port, "ucp"); } } if (se != (struct servent *)NULL) { sprintf(serv, "%s/%s", se->s_name, se->s_proto); } else { sprintf(serv, "%d", port); } } break; default: return EAI_FAMILY; } return EAI_NONE; }
