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

📄 getaddrinfo.c

📁 Rsync 3.0.5 source code
💻 C
字号:
/*PostgreSQL Database Management System(formerly known as Postgres, then as Postgres95)Portions Copyright (c) 1996-2005, The PostgreSQL Global Development GroupPortions Copyright (c) 1994, The Regents of the University of CaliforniaPermission to use, copy, modify, and distribute this software and itsdocumentation for any purpose, without fee, and without a written agreementis hereby granted, provided that the above copyright notice and this paragraphand the following two paragraphs appear in all copies.IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FORDIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDINGLOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OFSUCH DAMAGE.THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITYAND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER ISON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONSTO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.*//*------------------------------------------------------------------------- * * getaddrinfo.c *	  Support getaddrinfo() on platforms that don't have it. * * We also supply getnameinfo() here, assuming that the platform will have * it if and only if it has getaddrinfo().	If this proves false on some * platform, we'll need to split this file and provide a separate configure * test for getnameinfo(). * * Copyright (c) 2003-2007, PostgreSQL Global Development Group * * Copyright (C) 2007 Jeremy Allison. * Modified to return multiple IPv4 addresses for Samba. * *------------------------------------------------------------------------- */#include "rsync.h"#ifndef SMB_MALLOC#define SMB_MALLOC(s) malloc(s)#endif#ifndef SMB_STRDUP#define SMB_STRDUP(s) strdup(s)#endif#ifndef HOST_NAME_MAX#define HOST_NAME_MAX 255#endifstatic int check_hostent_err(struct hostent *hp){#ifndef INET6	extern int h_errno;#endif	if (!hp) {		switch (h_errno) {			case HOST_NOT_FOUND:			case NO_DATA:				return EAI_NONAME;			case TRY_AGAIN:				return EAI_AGAIN;			case NO_RECOVERY:			default:				return EAI_FAIL;		}	}	if (!hp->h_name || hp->h_addrtype != AF_INET) {		return EAI_FAIL;	}	return 0;}static char *canon_name_from_hostent(struct hostent *hp,				int *perr){	char *ret = NULL;	*perr = check_hostent_err(hp);	if (*perr) {		return NULL;	}	ret = SMB_STRDUP(hp->h_name);	if (!ret) {		*perr = EAI_MEMORY;	}	return ret;}static char *get_my_canon_name(int *perr){	char name[HOST_NAME_MAX+1];	if (gethostname(name, HOST_NAME_MAX) == -1) {		*perr = EAI_FAIL;		return NULL;	}	/* Ensure null termination. */	name[HOST_NAME_MAX] = '\0';	return canon_name_from_hostent(gethostbyname(name), perr);}static char *get_canon_name_from_addr(struct in_addr ip,				int *perr){	return canon_name_from_hostent(			gethostbyaddr((void *)&ip, sizeof ip, AF_INET),			perr);}static struct addrinfo *alloc_entry(const struct addrinfo *hints,				struct in_addr ip,				unsigned short port){	struct sockaddr_in *psin = NULL;	struct addrinfo *ai = SMB_MALLOC(sizeof(*ai));	if (!ai) {		return NULL;	}	memset(ai, '\0', sizeof(*ai));	psin = SMB_MALLOC(sizeof(*psin));	if (!psin) {		free(ai);		return NULL;	}	memset(psin, '\0', sizeof(*psin));	psin->sin_family = AF_INET;	psin->sin_port = htons(port);	psin->sin_addr = ip;	ai->ai_flags = 0;	ai->ai_family = AF_INET;	ai->ai_socktype = hints->ai_socktype;	ai->ai_protocol = hints->ai_protocol;	ai->ai_addrlen = sizeof(*psin);	ai->ai_addr = (struct sockaddr *) psin;	ai->ai_canonname = NULL;	ai->ai_next = NULL;	return ai;}/* * get address info for a single ipv4 address. * *	Bugs:	- servname can only be a number, not text. */static int getaddr_info_single_addr(const char *service,				uint32 addr,				const struct addrinfo *hints,				struct addrinfo **res){	struct addrinfo *ai = NULL;	struct in_addr ip;	unsigned short port = 0;	if (service) {		port = (unsigned short)atoi(service);	}	ip.s_addr = htonl(addr);	ai = alloc_entry(hints, ip, port);	if (!ai) {		return EAI_MEMORY;	}	/* If we're asked for the canonical name,	 * make sure it returns correctly. */	if (!(hints->ai_flags & AI_NUMERICSERV) &&			hints->ai_flags & AI_CANONNAME) {		int err;		if (addr == INADDR_LOOPBACK || addr == INADDR_ANY) {			ai->ai_canonname = get_my_canon_name(&err);		} else {			ai->ai_canonname =			get_canon_name_from_addr(ip,&err);		}		if (ai->ai_canonname == NULL) {			freeaddrinfo(ai);			return err;		}	}	*res = ai;	return 0;}/* * get address info for multiple ipv4 addresses. * *	Bugs:	- servname can only be a number, not text. */static int getaddr_info_name(const char *node,				const char *service,				const struct addrinfo *hints,				struct addrinfo **res){	struct addrinfo *listp = NULL, *prevp = NULL;	char **pptr = NULL;	int err;	struct hostent *hp = NULL;	unsigned short port = 0;	if (service) {		port = (unsigned short)atoi(service);	}	hp = gethostbyname(node);	err = check_hostent_err(hp);	if (err) {		return err;	}	for(pptr = hp->h_addr_list; *pptr; pptr++) {		struct in_addr ip = *(struct in_addr *)*pptr;		struct addrinfo *ai = alloc_entry(hints, ip, port);		if (!ai) {			freeaddrinfo(listp);			return EAI_MEMORY;		}		if (!listp) {			listp = ai;			prevp = ai;			ai->ai_canonname = SMB_STRDUP(hp->h_name);			if (!ai->ai_canonname) {				freeaddrinfo(listp);				return EAI_MEMORY;			}		} else {			prevp->ai_next = ai;			prevp = ai;		}	}	*res = listp;	return 0;}/* * get address info for ipv4 sockets. * *	Bugs:	- servname can only be a number, not text. */int getaddrinfo(const char *node,		const char *service,		const struct addrinfo * hintp,		struct addrinfo ** res){	struct addrinfo hints;	/* Setup the hints struct. */	if (hintp == NULL) {		memset(&hints, 0, sizeof(hints));		hints.ai_family = AF_INET;		hints.ai_socktype = SOCK_STREAM;	} else {		memcpy(&hints, hintp, sizeof(hints));	}	if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) {		return EAI_FAMILY;	}	if (hints.ai_socktype == 0) {		hints.ai_socktype = SOCK_STREAM;	}	if (!node && !service) {		return EAI_NONAME;	}	if (node) {		if (node[0] == '\0') {			return getaddr_info_single_addr(service,					INADDR_ANY,					&hints,					res);		} else if (hints.ai_flags & AI_NUMERICHOST) {			struct in_addr ip;			if (!inet_aton(node, &ip)) {				return EAI_FAIL;			}			return getaddr_info_single_addr(service,					ntohl(ip.s_addr),					&hints,					res);		} else {			return getaddr_info_name(node,						service,						&hints,						res);		}	} else if (hints.ai_flags & AI_PASSIVE) {		return getaddr_info_single_addr(service,					INADDR_ANY,					&hints,					res);	}	return getaddr_info_single_addr(service,					INADDR_LOOPBACK,					&hints,					res);}void freeaddrinfo(struct addrinfo *res){	struct addrinfo *next = NULL;	for (;res; res = next) {		next = res->ai_next;		if (res->ai_canonname) {			free(res->ai_canonname);		}		if (res->ai_addr) {			free(res->ai_addr);		}		free(res);	}}const char *gai_strerror(int errcode){#ifdef HAVE_HSTRERROR	int			hcode;	switch (errcode)	{		case EAI_NONAME:			hcode = HOST_NOT_FOUND;			break;		case EAI_AGAIN:			hcode = TRY_AGAIN;			break;		case EAI_FAIL:		default:			hcode = NO_RECOVERY;			break;	}	return hstrerror(hcode);#else							/* !HAVE_HSTRERROR */	switch (errcode)	{		case EAI_NONAME:			return "Unknown host";		case EAI_AGAIN:			return "Host name lookup failure";#ifdef EAI_BADFLAGS		case EAI_BADFLAGS:			return "Invalid argument";#endif#ifdef EAI_FAMILY		case EAI_FAMILY:			return "Address family not supported";#endif#ifdef EAI_MEMORY		case EAI_MEMORY:			return "Not enough memory";#endif#ifdef EAI_NODATA		case EAI_NODATA:			return "No host data of that type was found";#endif#ifdef EAI_SERVICE		case EAI_SERVICE:			return "Class type not found";#endif#ifdef EAI_SOCKTYPE		case EAI_SOCKTYPE:			return "Socket type not supported";#endif		default:			return "Unknown server error";	}#endif   /* HAVE_HSTRERROR */}static int gethostnameinfo(const struct sockaddr *sa,			char *node,			size_t nodelen,			int flags){	int ret = -1;	char *p = NULL;	if (!(flags & NI_NUMERICHOST)) {		struct hostent *hp = gethostbyaddr(				(void *)&((struct sockaddr_in *)sa)->sin_addr,				sizeof (struct in_addr),				sa->sa_family);		ret = check_hostent_err(hp);		if (ret == 0) {			/* Name looked up successfully. */			ret = snprintf(node, nodelen, "%s", hp->h_name);			if (ret < 0 || (size_t)ret >= nodelen) {				return EAI_MEMORY;			}			if (flags & NI_NOFQDN) {				p = strchr(node,'.');				if (p) {					*p = '\0';				}			}			return 0;		}		if (flags & NI_NAMEREQD) {			/* If we require a name and didn't get one,			 * automatically fail. */			return ret;		}		/* Otherwise just fall into the numeric host code... */	}	p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);	ret = snprintf(node, nodelen, "%s", p);	if (ret < 0 || (size_t)ret >= nodelen) {		return EAI_MEMORY;	}	return 0;}static int getservicenameinfo(const struct sockaddr *sa,			char *service,			size_t servicelen,			int flags){	int ret = -1;	int port = ntohs(((struct sockaddr_in *)sa)->sin_port);	if (!(flags & NI_NUMERICSERV)) {		struct servent *se = getservbyport(				port,				(flags & NI_DGRAM) ? "udp" : "tcp");		if (se && se->s_name) {			/* Service name looked up successfully. */			ret = snprintf(service, servicelen, "%s", se->s_name);			if (ret < 0 || (size_t)ret >= servicelen) {				return EAI_MEMORY;			}			return 0;		}		/* Otherwise just fall into the numeric service code... */	}	ret = snprintf(service, servicelen, "%d", port);	if (ret < 0 || (size_t)ret >= servicelen) {		return EAI_MEMORY;	}	return 0;}/* * Convert an ipv4 address to a hostname. * * Bugs:	- No IPv6 support. */int getnameinfo(const struct sockaddr *sa, socklen_t salen,			char *node, size_t nodelen,			char *service, size_t servicelen, int flags){	/* Invalid arguments. */	if (sa == NULL || (node == NULL && service == NULL)) {		return EAI_FAIL;	}	if (sa->sa_family != AF_INET) {		return EAI_FAIL;	}	if (salen < (socklen_t)sizeof (struct sockaddr_in)) {		return EAI_FAIL;	}	if (node) {		int ret = gethostnameinfo(sa, node, nodelen, flags);		if (ret)			return ret;	}	if (service) {		return getservicenameinfo(sa, service, servicelen, flags);	}	return 0;}

⌨️ 快捷键说明

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