📄 getaddrinfo.c
字号:
/* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *//* * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. * * Issues to be discussed: * - Thread safe-ness must be checked. * - Return values. There are nonstandard return values defined and used * in the source code. This is because RFC2553 is silent about which error * code must be returned for which situation. * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag. */#include <sys/types.h>#include <sys/param.h>#include <sys/sysctl.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <arpa/nameser.h>#include <netdb.h>#include <resolv.h>#include <string.h>#include <stdlib.h>#include <stddef.h>#include <ctype.h>#include <unistd.h>#include "missing/addrinfo.h"#if defined(__KAME__) && defined(INET6)# define FAITH#endif#define SUCCESS 0#define ANY 0#define YES 1#define NO 0#ifdef FAITHstatic int translate = NO;static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT;#endifstatic const char in_addrany[] = { 0, 0, 0, 0 };static const char in6_addrany[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};static const char in_loopback[] = { 127, 0, 0, 1 }; static const char in6_loopback[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};struct sockinet { u_char si_len; u_char si_family; u_short si_port;};static struct afd { int a_af; int a_addrlen; int a_socklen; int a_off; const char *a_addrany; const char *a_loopback; } afdl [] = {#ifdef INET6#define N_INET6 0 {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), offsetof(struct sockaddr_in6, sin6_addr), in6_addrany, in6_loopback},#define N_INET 1#else#define N_INET 0#endif {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), offsetof(struct sockaddr_in, sin_addr), in_addrany, in_loopback}, {0, 0, 0, 0, NULL, NULL},};#ifdef INET6#define PTON_MAX 16#else#define PTON_MAX 4#endifstatic int get_name __P((const char *, struct afd *, struct addrinfo **, char *, struct addrinfo *, int));static int get_addr __P((const char *, int, struct addrinfo **, struct addrinfo *, int));static int get_addr0 __P((const char *, int, struct addrinfo **, struct addrinfo *, int));static int str_isnumber __P((const char *)); static char *ai_errlist[] = { "Success", "Address family for hostname not supported", /* EAI_ADDRFAMILY */ "Temporary failure in name resolution", /* EAI_AGAIN */ "Invalid value for ai_flags", /* EAI_BADFLAGS */ "Non-recoverable failure in name resolution", /* EAI_FAIL */ "ai_family not supported", /* EAI_FAMILY */ "Memory allocation failure", /* EAI_MEMORY */ "No address associated with hostname", /* EAI_NODATA */ "hostname nor servname provided, or not known",/* EAI_NONAME */ "servname not supported for ai_socktype", /* EAI_SERVICE */ "ai_socktype not supported", /* EAI_SOCKTYPE */ "System error returned in errno", /* EAI_SYSTEM */ "Invalid value for hints", /* EAI_BADHINTS */ "Resolved protocol is unknown", /* EAI_PROTOCOL */ "Unknown error", /* EAI_MAX */};#define GET_CANONNAME(ai, str) \if (pai->ai_flags & AI_CANONNAME) {\ if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\ strcpy((ai)->ai_canonname, (str));\ } else {\ error = EAI_MEMORY;\ goto free;\ }\}#define GET_AI(ai, afd, addr, port) {\ char *p;\ if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\ ((afd)->a_socklen)))\ == NULL) {\ error = EAI_MEMORY;\ goto free;\ }\ memcpy(ai, pai, sizeof(struct addrinfo));\ (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\ memset((ai)->ai_addr, 0, (afd)->a_socklen);\ (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (afd)->a_socklen;\ (ai)->ai_addr->sa_family = (ai)->ai_family = (afd)->a_af;\ ((struct sockinet *)(ai)->ai_addr)->si_port = port;\ p = (char *)((ai)->ai_addr);\ memcpy(p + (afd)->a_off, (addr), (afd)->a_addrlen);\}#define ERR(err) { error = (err); goto bad; }char *gai_strerror(ecode) int ecode;{ if (ecode < 0 || ecode > EAI_MAX) ecode = EAI_MAX; return ai_errlist[ecode];}voidfreeaddrinfo(ai) struct addrinfo *ai;{ struct addrinfo *next; do { next = ai->ai_next; if (ai->ai_canonname) free(ai->ai_canonname); /* no need to free(ai->ai_addr) */ free(ai); } while ((ai = next) != NULL);}static intstr_isnumber(p) const char *p;{ char *q = (char *)p; while (*q) { if (! isdigit(*q)) return NO; q++; } return YES;}intgetaddrinfo(hostname, servname, hints, res) const char *hostname, *servname; const struct addrinfo *hints; struct addrinfo **res;{ struct addrinfo sentinel; struct addrinfo *top = NULL; struct addrinfo *cur; int i, error = 0; char pton[PTON_MAX]; struct addrinfo ai; struct addrinfo *pai; u_short port;#ifdef FAITH static int firsttime = 1; if (firsttime) { /* translator hack */ { char *q = getenv("GAI"); if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1) translate = YES; } firsttime = 0; }#endif /* initialize file static vars */ sentinel.ai_next = NULL; cur = &sentinel; pai = &ai; pai->ai_flags = 0; pai->ai_family = PF_UNSPEC; pai->ai_socktype = ANY; pai->ai_protocol = ANY; pai->ai_addrlen = 0; pai->ai_canonname = NULL; pai->ai_addr = NULL; pai->ai_next = NULL; port = ANY; if (hostname == NULL && servname == NULL) return EAI_NONAME; if (hints) { /* error check for hints */ if (hints->ai_addrlen || hints->ai_canonname || hints->ai_addr || hints->ai_next) ERR(EAI_BADHINTS); /* xxx */ if (hints->ai_flags & ~AI_MASK) ERR(EAI_BADFLAGS); switch (hints->ai_family) { case PF_UNSPEC: case PF_INET:#ifdef INET6 case PF_INET6:#endif break; default: ERR(EAI_FAMILY); } memcpy(pai, hints, sizeof(*pai)); switch (pai->ai_socktype) { case ANY: switch (pai->ai_protocol) { case ANY: break; case IPPROTO_UDP: pai->ai_socktype = SOCK_DGRAM; break; case IPPROTO_TCP: pai->ai_socktype = SOCK_STREAM; break; default: pai->ai_socktype = SOCK_RAW; break; } break; case SOCK_RAW: break; case SOCK_DGRAM: if (pai->ai_protocol != IPPROTO_UDP && pai->ai_protocol != ANY) ERR(EAI_BADHINTS); /*xxx*/ pai->ai_protocol = IPPROTO_UDP; break; case SOCK_STREAM: if (pai->ai_protocol != IPPROTO_TCP && pai->ai_protocol != ANY) ERR(EAI_BADHINTS); /*xxx*/ pai->ai_protocol = IPPROTO_TCP; break; default: ERR(EAI_SOCKTYPE); break; } } /* * service port */ if (servname) { if (str_isnumber(servname)) { if (pai->ai_socktype == ANY) { /* caller accept *ANY* socktype */ pai->ai_socktype = SOCK_DGRAM; pai->ai_protocol = IPPROTO_UDP; } port = htons(atoi(servname)); } else { struct servent *sp; char *proto; proto = NULL; switch (pai->ai_socktype) { case ANY: proto = NULL; break; case SOCK_DGRAM: proto = "udp"; break; case SOCK_STREAM: proto = "tcp"; break; default: fprintf(stderr, "panic!\n"); break; } if ((sp = getservbyname(servname, proto)) == NULL) ERR(EAI_SERVICE); port = sp->s_port; if (pai->ai_socktype == ANY) { if (strcmp(sp->s_proto, "udp") == 0) { pai->ai_socktype = SOCK_DGRAM; pai->ai_protocol = IPPROTO_UDP; } else if (strcmp(sp->s_proto, "tcp") == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -