Annotation of embedaddon/rsync/lib/getaddrinfo.c, revision 1.1.1.1
1.1 misho 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>