⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 getaddrinfo.c

📁 unix网络编程第一卷socket编程书上的全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
				if ( (sin6ptr = calloc(1, sizeof(struct sockaddr_in6))) == NULL)					error(EAI_MEMORY);#ifdef	SIN6_LEN				sin6ptr->sin6_len = sizeof(struct sockaddr_in6);#endif				sin6ptr->sin6_family = AF_INET6;				memcpy(&sin6ptr->sin6_addr, *ap, sizeof(struct in6_addr));				ai->ai_addr = (struct sockaddr *) sin6ptr;				ai->ai_addrlen = sizeof(struct sockaddr_in6);				break;#endif	/* IPV6 */		}	}	/* "aihead" points to the first structure in the linked list */	if (hints.ai_flags & AI_CANONNAME) {		/*		 * Posix.1g doesn't say what to do if this flag is set and		 * multiple addrinfo structures are returned.		 * We return the canonical name only in the first addrinfo{}.		 */		if (hptr->h_name != NULL) {			if ( (aihead->ai_canonname = strdup(hptr->h_name)) == NULL)				error(EAI_MEMORY);		} else {			/*			 * Posix.1g says we can just set ai_canonname to point to the			 * "host" argument, but that makes freeaddrinfo() harder.			 * We dynamically allocate room for a copy of "host".			 */			if ( (aihead->ai_canonname = strdup(host)) == NULL)				error(EAI_MEMORY);		}	}	/*	 * Now look up the service, if specified.	 */	if (serv != NULL && serv[0] != '\0') {		if ( (rc = getaddrinfo_serv(aihead, &hints, serv, &sent,									hentbuf, HENTBUFSIZ)) != 0)			error(rc);	}	*result = aihead;	/* pointer to first structure in linked list */	return(0);bad:	freeaddrinfo(aihead);	/* free any alloc'ed memory */	return(error);}/* * This function handles the host string. */static intgetaddrinfo_host(const char *host,				 struct hostent *hptr, struct hostent **hptrptr,				 char *buf, int bufsiz, int family){#ifdef	REENTRANT	int		h_errno;#endif	/* REENTRANT */#ifdef	IPV4	/*	 * We explicitly check for an IPv4 dotted-decimal string.	 * Recent versions of gethostbyname(), starting around BIND 4.9.2	 * do this too, but we have the check here so we don't depend on	 * this newer feature.  (You wouldn't believe the ancient versions	 * of BIND that some vendors ship.)	 */	if (isdigit(host[0])) {		if (inet_pton(AF_INET, host, hptr->h_addr_list[0]) == 1) {				/* Success.  Finish making up the hostent{} as though				   we had called gethostbyname(). */			strncpy(hptr->h_name, host, bufsiz-1);			buf[bufsiz-1] = '\0';			hptr->h_addrtype = AF_INET;			hptr->h_length = sizeof(struct in_addr);			return(0);		}	}#endif	/* IPV4 */#ifdef	IPV6	/*	 * Check for an IPv6 hex string.	 */	if (isxdigit(host[0]) || host[0] == ':') {		if (inet_pton(AF_INET6, host, hptr->h_addr_list[0]) == 1) {				/* Success.  Finish making up a hostent{} as though				   we had called gethostbyname(). */			strncpy(buf, host, bufsiz-1);			buf[bufsiz-1] = '\0';			hptr->h_addrtype = AF_INET6;			hptr->h_length = sizeof(struct in6_addr);			return(0);		}	}#endif	/* IPV6 */	/*	 * Not an address, must be a hostname, try the DNS.	 * Initialize the resolver, if not already initialized.	 */	if ((_res.options & RES_INIT) == 0)		res_init();			/* need this to set _res.options below */#ifdef	IPV6	/*	 * Notice that the following might be considered optional, and	 * could be #ifdef'ed out if your <resolv.h> does not define	 * RES_USE_INET6.  But I am assuming you have BIND-4.9.4 installed	 * and want the IPv4/IPv6 semantics that it defines for gethostbyname().	 */#ifndef	RES_USE_INET6	/* This is a gross hack; following line from BIND-4.9.4 release ... */	/* (if you're using 4.9.4, but have not installed the include files) */#define	RES_USE_INET6	0x00002000	/* use/map IPv6 in gethostbyname() */#endif	if (family == AF_INET6)		_res.options |= RES_USE_INET6;#endif	/* IPV6 */#ifdef	REENTRANT	hptr = gethostbyname_r(host, hptr, buf, bufsiz, &h_errno);#else	hptr = gethostbyname(host);#endif	/* REENTRANT */	if (hptr == NULL) {		switch (h_errno) {			case HOST_NOT_FOUND:	return(EAI_NONAME);			case TRY_AGAIN:			return(EAI_AGAIN);			case NO_RECOVERY:		return(EAI_FAIL);			case NO_DATA:			return(EAI_NODATA);			default:				return(EAI_NONAME);		}	}	*hptrptr = hptr;	return(0);}/* * This function handles the service string. */static intgetaddrinfo_serv(struct addrinfo *aihead,				 const struct addrinfo *hintsptr, const char *serv,				 struct servent *sptrarg, char *buf, int bufsiz){	int				port, rc;	int				nfound = 0;	struct servent	*sptr;	/*	 * We allow the service to be a numeric string, which we	 * interpret as a decimal port number.  Posix.1g doesn't	 * explicitly say to do this, but it just makes sense.	 * But to do this the caller must specify a socket type,	 * else there's no way to return values for socket().	 */	if (isdigit(serv[0]) && hintsptr->ai_socktype != 0) {		port = htons(atoi(serv));		if ( (rc = getaddrinfo_port(aihead, port, hintsptr->ai_socktype)) == 0)			return(EAI_NONAME);		else if (rc < 0)			return(EAI_MEMORY);		else			return(0);	}	/*	 * Not a special case, try the "/etc/services" file (or whatever).	 * We first try TCP, if applicable.	 */	if (hintsptr->ai_socktype == 0 || hintsptr->ai_socktype == SOCK_STREAM) {#ifdef	REENTRANT		sptr = getservbyname_r(serv, "tcp", sptrarg, buf, bufsiz);#else		sptr = getservbyname(serv, "tcp");#endif	/* REENTRANT */		if (sptr != NULL) {			rc = getaddrinfo_port(aihead, sptr->s_port, SOCK_STREAM);			if (rc < 0)				return(EAI_MEMORY);			nfound += rc;		}	}	/*	 * Now try UDP, if applicable.	 */	if (hintsptr->ai_socktype == 0 || hintsptr->ai_socktype == SOCK_DGRAM) {#ifdef	REENTRANT		sptr = getservbyname_r(serv, "udp", sptrarg, buf, bufsiz);#else		sptr = getservbyname(serv, "udp");#endif	/* REENTRANT */		if (sptr != NULL) {			rc = getaddrinfo_port(aihead, sptr->s_port, SOCK_DGRAM);			if (rc < 0)				return(EAI_MEMORY);			nfound += rc;		}	}	if (nfound == 0) {			/* You could call getservbyname() one more time, with no			   protocol specified, but "tcp" and "udp" are all that			   are supported today. */		if (hintsptr->ai_socktype == 0)			return(EAI_NONAME);	/* all calls to getservbyname() failed */		else			return(EAI_SERVICE);/* service not supported for socket type */	}	return(0);}/* * Go through all the addrinfo structures, checking for a match of the * socket type and filling in the socket type, and then the port number * in the corresponding socket address structures. * * The AI_CLONE flag works as follows.  Consider a multihomed host with * two IP addresses and no socket type specified by the caller.  After * the "host" search there are two addrinfo structures, one per IP address. * Assuming a service supported by both TCP and UDP (say the daytime * service) we need to return *four* addrinfo structures: *		IP#1, SOCK_STREAM, TCP port, *		IP#1, SOCK_DGRAM, UDP port, *		IP#2, SOCK_STREAM, TCP port, *		IP#2, SOCK_DGRAM, UDP port. * To do this, when the "host" loop creates an addrinfo structure, if the * caller has not specified a socket type (hints->ai_socktype == 0), the * AI_CLONE flag is set.  When the following function finds an entry like * this it is handled as follows: If the entry's ai_socktype is still 0, * this is the first use of the structure, and the ai_socktype field is set. * But, if the entry's ai_socktype is nonzero, then we clone a new addrinfo * structure and set it's ai_socktype to the new value.  Although we only * need two socket types today (SOCK_STREAM and SOCK_DGRAM) this algorithm * will handle any number.  Also notice that Posix.1g requires all socket * types to be nonzero. */static intgetaddrinfo_port(struct addrinfo *aihead, int port, int socktype)		/* port must be in network byte order */{	int				nfound = 0;	struct addrinfo	*ai;	for (ai = aihead; ai != NULL; ai = ai->ai_next) {		/*		 * We set the socket type but not the protocol, because if a		 * port number is specified, the protocol must be TCP or UDP,		 * and a protocol of 0 for socket() is fine for TCP and UDP.		 * The only time a nonzero protocol argument is required by		 * socket() is for a raw socket, in which case a service will		 * not be specified to getaddrinfo().		 */		if (ai->ai_flags & AI_CLONE) {			if (ai->ai_socktype != 0) {				if ( (ai = getaddrinfo_clone(ai)) == NULL)					return(-1);	/* tell caller it's a memory allocation error */				/* ai points to newly cloned entry, which is what we want */			}		} else if (ai->ai_socktype != socktype)			continue;		/* ignore if mismatch on socket type */		ai->ai_socktype = socktype;		switch (ai->ai_family) {#ifdef	IPV4			case AF_INET:				((struct sockaddr_in *) ai->ai_addr)->sin_port = port;				nfound++;				break;#endif#ifdef	IPV6			case AF_INET6:				((struct sockaddr_in6 *) ai->ai_addr)->sin6_port = port;				nfound++;				break;#endif		}	}	return(nfound);}/* * Clone a new addrinfo structure from an existing one. */static struct addrinfo *getaddrinfo_clone(struct addrinfo *ai){	struct addrinfo	*new;	if ( (new = calloc(1, sizeof(struct addrinfo))) == NULL)		return(NULL);	new->ai_next = ai->ai_next;	ai->ai_next = new;	new->ai_flags = 0;				/* make sure AI_CLONE is off */	new->ai_family = ai->ai_family;	new->ai_socktype = ai->ai_socktype;	new->ai_protocol = ai->ai_protocol;	new->ai_canonname = NULL;	new->ai_addrlen = ai->ai_addrlen;	if ( (new->ai_addr = malloc(ai->ai_addrlen)) == NULL)		return(NULL);	memcpy(new->ai_addr, ai->ai_addr, ai->ai_addrlen);	return(new);}#ifdef	LOCAL/* * Do everything for a Unix domain socket. * Only one addrinfo{} is returned. */static intaddrinfo_local(const char *path, struct addrinfo *hints,			   struct addrinfo **result){	struct addrinfo		*ai;	struct sockaddr_un	*unp;	if (hints->ai_socktype == 0)		return(EAI_SOCKTYPE);	/* we cannot tell socket type from service */	if ( (ai = calloc(1, sizeof(struct addrinfo))) == NULL)		return(NULL);	ai->ai_flags = 0;	ai->ai_family = AF_LOCAL;	ai->ai_socktype = hints->ai_socktype;	ai->ai_protocol = 0;		/* allocate and fill in a socket address structure */	ai->ai_addrlen = sizeof(struct sockaddr_un);	if ( (ai->ai_addr = malloc(ai->ai_addrlen)) == NULL)		return(EAI_MEMORY);	unp = (struct sockaddr_un *) ai->ai_addr;	unp->sun_family = AF_UNIX;	strncpy(unp->sun_path, path, sizeof(unp->sun_path));	ai->ai_canonname = NULL;	/* maybe return the i-node number :-) */	ai->ai_next = NULL;	*result = ai;	if (hints->ai_flags & AI_PASSIVE)		unlink(path);		/* OK if this fails */	return(0);		/* success */}#endif	/* LOCAL */voidfreeaddrinfo(struct addrinfo *aihead){	struct addrinfo	*ai, *ainext;	for (ai = aihead; ai != NULL; ai = ainext) {		if (ai->ai_addr != NULL)			free(ai->ai_addr);		/* the socket address structure */		if (ai->ai_canonname != NULL)			free(ai->ai_canonname);	/* the canonical name */		ainext = ai->ai_next;		/* can't fetch ai_next after free() */		free(ai);					/* the addrinfo{} itself */	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -