File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / lib / getaddrinfo.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 15:09:30 2012 UTC (12 years, 4 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_2_3, v3_1_2p5, rsync3_0_9p0, RSYNC3_1_0, RSYNC3_0_9, HEAD
rsync

    1: /*
    2: PostgreSQL Database Management System
    3: (formerly known as Postgres, then as Postgres95)
    4: 
    5: Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group
    6: 
    7: Portions Copyright (c) 1994, The Regents of the University of California
    8: 
    9: Permission to use, copy, modify, and distribute this software and its
   10: documentation for any purpose, without fee, and without a written agreement
   11: is hereby granted, provided that the above copyright notice and this paragraph
   12: and the following two paragraphs appear in all copies.
   13: 
   14: IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
   15: DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
   16: LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
   17: EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
   18: SUCH DAMAGE.
   19: 
   20: THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
   21: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
   22: AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
   23: ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS
   24: TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
   25: 
   26: */
   27: 
   28: /*-------------------------------------------------------------------------
   29:  *
   30:  * getaddrinfo.c
   31:  *	  Support getaddrinfo() on platforms that don't have it.
   32:  *
   33:  * We also supply getnameinfo() here, assuming that the platform will have
   34:  * it if and only if it has getaddrinfo().	If this proves false on some
   35:  * platform, we'll need to split this file and provide a separate configure
   36:  * test for getnameinfo().
   37:  *
   38:  * Copyright (c) 2003-2007, PostgreSQL Global Development Group
   39:  *
   40:  * Copyright (C) 2007 Jeremy Allison.
   41:  * Modified to return multiple IPv4 addresses for Samba.
   42:  *
   43:  *-------------------------------------------------------------------------
   44:  */
   45: 
   46: #include "rsync.h"
   47: 
   48: #ifndef SMB_MALLOC
   49: #define SMB_MALLOC(s) malloc(s)
   50: #endif
   51: 
   52: #ifndef SMB_STRDUP
   53: #define SMB_STRDUP(s) strdup(s)
   54: #endif
   55: 
   56: #ifndef HOST_NAME_MAX
   57: #define HOST_NAME_MAX 255
   58: #endif
   59: 
   60: static int check_hostent_err(struct hostent *hp)
   61: {
   62: #ifndef INET6
   63: 	extern int h_errno;
   64: #endif
   65: 	if (!hp) {
   66: 		switch (h_errno) {
   67: 			case HOST_NOT_FOUND:
   68: 			case NO_DATA:
   69: 				return EAI_NONAME;
   70: 			case TRY_AGAIN:
   71: 				return EAI_AGAIN;
   72: 			case NO_RECOVERY:
   73: 			default:
   74: 				return EAI_FAIL;
   75: 		}
   76: 	}
   77: 	if (!hp->h_name || hp->h_addrtype != AF_INET) {
   78: 		return EAI_FAIL;
   79: 	}
   80: 	return 0;
   81: }
   82: 
   83: static char *canon_name_from_hostent(struct hostent *hp,
   84: 				int *perr)
   85: {
   86: 	char *ret = NULL;
   87: 
   88: 	*perr = check_hostent_err(hp);
   89: 	if (*perr) {
   90: 		return NULL;
   91: 	}
   92: 	ret = SMB_STRDUP(hp->h_name);
   93: 	if (!ret) {
   94: 		*perr = EAI_MEMORY;
   95: 	}
   96: 	return ret;
   97: }
   98: 
   99: static char *get_my_canon_name(int *perr)
  100: {
  101: 	char name[HOST_NAME_MAX+1];
  102: 
  103: 	if (gethostname(name, HOST_NAME_MAX) == -1) {
  104: 		*perr = EAI_FAIL;
  105: 		return NULL;
  106: 	}
  107: 	/* Ensure null termination. */
  108: 	name[HOST_NAME_MAX] = '\0';
  109: 	return canon_name_from_hostent(gethostbyname(name), perr);
  110: }
  111: 
  112: static char *get_canon_name_from_addr(struct in_addr ip,
  113: 				int *perr)
  114: {
  115: 	return canon_name_from_hostent(
  116: 			gethostbyaddr((void *)&ip, sizeof ip, AF_INET),
  117: 			perr);
  118: }
  119: 
  120: static struct addrinfo *alloc_entry(const struct addrinfo *hints,
  121: 				struct in_addr ip,
  122: 				unsigned short port)
  123: {
  124: 	struct sockaddr_in *psin = NULL;
  125: 	struct addrinfo *ai = SMB_MALLOC(sizeof(*ai));
  126: 
  127: 	if (!ai) {
  128: 		return NULL;
  129: 	}
  130: 	memset(ai, '\0', sizeof(*ai));
  131: 
  132: 	psin = SMB_MALLOC(sizeof(*psin));
  133: 	if (!psin) {
  134: 		free(ai);
  135: 		return NULL;
  136: 	}
  137: 
  138: 	memset(psin, '\0', sizeof(*psin));
  139: 
  140: 	psin->sin_family = AF_INET;
  141: 	psin->sin_port = htons(port);
  142: 	psin->sin_addr = ip;
  143: 
  144: 	ai->ai_flags = 0;
  145: 	ai->ai_family = AF_INET;
  146: 	ai->ai_socktype = hints->ai_socktype;
  147: 	ai->ai_protocol = hints->ai_protocol;
  148: 	ai->ai_addrlen = sizeof(*psin);
  149: 	ai->ai_addr = (struct sockaddr *) psin;
  150: 	ai->ai_canonname = NULL;
  151: 	ai->ai_next = NULL;
  152: 
  153: 	return ai;
  154: }
  155: 
  156: /*
  157:  * get address info for a single ipv4 address.
  158:  *
  159:  *	Bugs:	- servname can only be a number, not text.
  160:  */
  161: 
  162: static int getaddr_info_single_addr(const char *service,
  163: 				uint32 addr,
  164: 				const struct addrinfo *hints,
  165: 				struct addrinfo **res)
  166: {
  167: 
  168: 	struct addrinfo *ai = NULL;
  169: 	struct in_addr ip;
  170: 	unsigned short port = 0;
  171: 
  172: 	if (service) {
  173: 		port = (unsigned short)atoi(service);
  174: 	}
  175: 	ip.s_addr = htonl(addr);
  176: 
  177: 	ai = alloc_entry(hints, ip, port);
  178: 	if (!ai) {
  179: 		return EAI_MEMORY;
  180: 	}
  181: 
  182: 	/* If we're asked for the canonical name,
  183: 	 * make sure it returns correctly. */
  184: 	if (!(hints->ai_flags & AI_NUMERICSERV) &&
  185: 			hints->ai_flags & AI_CANONNAME) {
  186: 		int err;
  187: 		if (addr == INADDR_LOOPBACK || addr == INADDR_ANY) {
  188: 			ai->ai_canonname = get_my_canon_name(&err);
  189: 		} else {
  190: 			ai->ai_canonname =
  191: 			get_canon_name_from_addr(ip,&err);
  192: 		}
  193: 		if (ai->ai_canonname == NULL) {
  194: 			freeaddrinfo(ai);
  195: 			return err;
  196: 		}
  197: 	}
  198: 
  199: 	*res = ai;
  200: 	return 0;
  201: }
  202: 
  203: /*
  204:  * get address info for multiple ipv4 addresses.
  205:  *
  206:  *	Bugs:	- servname can only be a number, not text.
  207:  */
  208: 
  209: static int getaddr_info_name(const char *node,
  210: 				const char *service,
  211: 				const struct addrinfo *hints,
  212: 				struct addrinfo **res)
  213: {
  214: 	struct addrinfo *listp = NULL, *prevp = NULL;
  215: 	char **pptr = NULL;
  216: 	int err;
  217: 	struct hostent *hp = NULL;
  218: 	unsigned short port = 0;
  219: 
  220: 	if (service) {
  221: 		port = (unsigned short)atoi(service);
  222: 	}
  223: 
  224: 	hp = gethostbyname(node);
  225: 	err = check_hostent_err(hp);
  226: 	if (err) {
  227: 		return err;
  228: 	}
  229: 
  230: 	for(pptr = hp->h_addr_list; *pptr; pptr++) {
  231: 		struct in_addr ip = *(struct in_addr *)*pptr;
  232: 		struct addrinfo *ai = alloc_entry(hints, ip, port);
  233: 
  234: 		if (!ai) {
  235: 			freeaddrinfo(listp);
  236: 			return EAI_MEMORY;
  237: 		}
  238: 
  239: 		if (!listp) {
  240: 			listp = ai;
  241: 			prevp = ai;
  242: 			ai->ai_canonname = SMB_STRDUP(hp->h_name);
  243: 			if (!ai->ai_canonname) {
  244: 				freeaddrinfo(listp);
  245: 				return EAI_MEMORY;
  246: 			}
  247: 		} else {
  248: 			prevp->ai_next = ai;
  249: 			prevp = ai;
  250: 		}
  251: 	}
  252: 	*res = listp;
  253: 	return 0;
  254: }
  255: 
  256: /*
  257:  * get address info for ipv4 sockets.
  258:  *
  259:  *	Bugs:	- servname can only be a number, not text.
  260:  */
  261: 
  262: int getaddrinfo(const char *node,
  263: 		const char *service,
  264: 		const struct addrinfo * hintp,
  265: 		struct addrinfo ** res)
  266: {
  267: 	struct addrinfo hints;
  268: 
  269: 	/* Setup the hints struct. */
  270: 	if (hintp == NULL) {
  271: 		memset(&hints, 0, sizeof(hints));
  272: 		hints.ai_family = AF_INET;
  273: 		hints.ai_socktype = SOCK_STREAM;
  274: 	} else {
  275: 		memcpy(&hints, hintp, sizeof(hints));
  276: 	}
  277: 
  278: 	if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) {
  279: 		return EAI_FAMILY;
  280: 	}
  281: 
  282: 	if (hints.ai_socktype == 0) {
  283: 		hints.ai_socktype = SOCK_STREAM;
  284: 	}
  285: 
  286: 	if (!node && !service) {
  287: 		return EAI_NONAME;
  288: 	}
  289: 
  290: 	if (node) {
  291: 		if (node[0] == '\0') {
  292: 			return getaddr_info_single_addr(service,
  293: 					INADDR_ANY,
  294: 					&hints,
  295: 					res);
  296: 		} else if (hints.ai_flags & AI_NUMERICHOST) {
  297: 			struct in_addr ip;
  298: 			if (inet_pton(AF_INET, node, &ip) <= 0)
  299: 				return EAI_FAIL;
  300: 			return getaddr_info_single_addr(service,
  301: 					ntohl(ip.s_addr),
  302: 					&hints,
  303: 					res);
  304: 		} else {
  305: 			return getaddr_info_name(node,
  306: 						service,
  307: 						&hints,
  308: 						res);
  309: 		}
  310: 	} else if (hints.ai_flags & AI_PASSIVE) {
  311: 		return getaddr_info_single_addr(service,
  312: 					INADDR_ANY,
  313: 					&hints,
  314: 					res);
  315: 	}
  316: 	return getaddr_info_single_addr(service,
  317: 					INADDR_LOOPBACK,
  318: 					&hints,
  319: 					res);
  320: }
  321: 
  322: 
  323: void freeaddrinfo(struct addrinfo *res)
  324: {
  325: 	struct addrinfo *next = NULL;
  326: 
  327: 	for (;res; res = next) {
  328: 		next = res->ai_next;
  329: 		if (res->ai_canonname) {
  330: 			free(res->ai_canonname);
  331: 		}
  332: 		if (res->ai_addr) {
  333: 			free(res->ai_addr);
  334: 		}
  335: 		free(res);
  336: 	}
  337: }
  338: 
  339: 
  340: const char *gai_strerror(int errcode)
  341: {
  342: #ifdef HAVE_HSTRERROR
  343: 	int			hcode;
  344: 
  345: 	switch (errcode)
  346: 	{
  347: 		case EAI_NONAME:
  348: 			hcode = HOST_NOT_FOUND;
  349: 			break;
  350: 		case EAI_AGAIN:
  351: 			hcode = TRY_AGAIN;
  352: 			break;
  353: 		case EAI_FAIL:
  354: 		default:
  355: 			hcode = NO_RECOVERY;
  356: 			break;
  357: 	}
  358: 
  359: 	return hstrerror(hcode);
  360: #else							/* !HAVE_HSTRERROR */
  361: 
  362: 	switch (errcode)
  363: 	{
  364: 		case EAI_NONAME:
  365: 			return "Unknown host";
  366: 		case EAI_AGAIN:
  367: 			return "Host name lookup failure";
  368: #ifdef EAI_BADFLAGS
  369: 		case EAI_BADFLAGS:
  370: 			return "Invalid argument";
  371: #endif
  372: #ifdef EAI_FAMILY
  373: 		case EAI_FAMILY:
  374: 			return "Address family not supported";
  375: #endif
  376: #ifdef EAI_MEMORY
  377: 		case EAI_MEMORY:
  378: 			return "Not enough memory";
  379: #endif
  380: #ifdef EAI_NODATA
  381: 		case EAI_NODATA:
  382: 			return "No host data of that type was found";
  383: #endif
  384: #ifdef EAI_SERVICE
  385: 		case EAI_SERVICE:
  386: 			return "Class type not found";
  387: #endif
  388: #ifdef EAI_SOCKTYPE
  389: 		case EAI_SOCKTYPE:
  390: 			return "Socket type not supported";
  391: #endif
  392: 		default:
  393: 			return "Unknown server error";
  394: 	}
  395: #endif   /* HAVE_HSTRERROR */
  396: }
  397: 
  398: static int gethostnameinfo(const struct sockaddr *sa,
  399: 			char *node,
  400: 			size_t nodelen,
  401: 			int flags)
  402: {
  403: 	int ret = -1;
  404: 	char *p = NULL;
  405: 
  406: 	if (!(flags & NI_NUMERICHOST)) {
  407: 		struct hostent *hp = gethostbyaddr(
  408: 				(void *)&((struct sockaddr_in *)sa)->sin_addr,
  409: 				sizeof (struct in_addr),
  410: 				sa->sa_family);
  411: 		ret = check_hostent_err(hp);
  412: 		if (ret == 0) {
  413: 			/* Name looked up successfully. */
  414: 			ret = snprintf(node, nodelen, "%s", hp->h_name);
  415: 			if (ret < 0 || (size_t)ret >= nodelen) {
  416: 				return EAI_MEMORY;
  417: 			}
  418: 			if (flags & NI_NOFQDN) {
  419: 				p = strchr(node,'.');
  420: 				if (p) {
  421: 					*p = '\0';
  422: 				}
  423: 			}
  424: 			return 0;
  425: 		}
  426: 
  427: 		if (flags & NI_NAMEREQD) {
  428: 			/* If we require a name and didn't get one,
  429: 			 * automatically fail. */
  430: 			return ret;
  431: 		}
  432: 		/* Otherwise just fall into the numeric host code... */
  433: 	}
  434: 	p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
  435: 	ret = snprintf(node, nodelen, "%s", p);
  436: 	if (ret < 0 || (size_t)ret >= nodelen) {
  437: 		return EAI_MEMORY;
  438: 	}
  439: 	return 0;
  440: }
  441: 
  442: static int getservicenameinfo(const struct sockaddr *sa,
  443: 			char *service,
  444: 			size_t servicelen,
  445: 			int flags)
  446: {
  447: 	int ret = -1;
  448: 	int port = ntohs(((struct sockaddr_in *)sa)->sin_port);
  449: 
  450: 	if (!(flags & NI_NUMERICSERV)) {
  451: 		struct servent *se = getservbyport(
  452: 				port,
  453: 				(flags & NI_DGRAM) ? "udp" : "tcp");
  454: 		if (se && se->s_name) {
  455: 			/* Service name looked up successfully. */
  456: 			ret = snprintf(service, servicelen, "%s", se->s_name);
  457: 			if (ret < 0 || (size_t)ret >= servicelen) {
  458: 				return EAI_MEMORY;
  459: 			}
  460: 			return 0;
  461: 		}
  462: 		/* Otherwise just fall into the numeric service code... */
  463: 	}
  464: 	ret = snprintf(service, servicelen, "%d", port);
  465: 	if (ret < 0 || (size_t)ret >= servicelen) {
  466: 		return EAI_MEMORY;
  467: 	}
  468: 	return 0;
  469: }
  470: 
  471: /*
  472:  * Convert an ipv4 address to a hostname.
  473:  *
  474:  * Bugs:	- No IPv6 support.
  475:  */
  476: int getnameinfo(const struct sockaddr *sa, socklen_t salen,
  477: 			char *node, size_t nodelen,
  478: 			char *service, size_t servicelen, int flags)
  479: {
  480: 
  481: 	/* Invalid arguments. */
  482: 	if (sa == NULL || (node == NULL && service == NULL)) {
  483: 		return EAI_FAIL;
  484: 	}
  485: 
  486: 	if (sa->sa_family != AF_INET) {
  487: 		return EAI_FAIL;
  488: 	}
  489: 
  490: 	if (salen < (socklen_t)sizeof (struct sockaddr_in)) {
  491: 		return EAI_FAIL;
  492: 	}
  493: 
  494: 	if (node) {
  495: 		int ret = gethostnameinfo(sa, node, nodelen, flags);
  496: 		if (ret)
  497: 			return ret;
  498: 	}
  499: 
  500: 	if (service) {
  501: 		return getservicenameinfo(sa, service, servicelen, flags);
  502: 	}
  503: 	return 0;
  504: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>