"Fossies" - the Fresh Open Source Software Archive 
Member "zsync-0.6.2/getaddrinfo.c" (16 Sep 2010, 13914 Bytes) of package /linux/privat/old/zsync-0.6.2.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "getaddrinfo.c" see the
Fossies "Dox" file reference documentation.
1 /*
2 * Copyright (c) 2001, 02 Motoyuki Kasahara
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the project nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 /*
30 * This program provides getaddrinfo() and getnameinfo() described in
31 * RFC2133, 2553 and 3493. These functions are mainly used for IPv6
32 * application to resolve hostname or address.
33 *
34 * This program is designed to be working on traditional IPv4 systems
35 * which don't have those functions. Therefore, this implementation
36 * supports IPv4 only.
37 *
38 * This program is useful for application which should support both IPv6
39 * and traditional IPv4 systems. Use genuine getaddrinfo() and getnameinfo()
40 * provided by system if the system supports IPv6. Otherwise, use this
41 * implementation.
42 *
43 * This program is intended to be used in combination with GNU Autoconf.
44 *
45 * This program also provides freeaddrinfo() and gai_strerror().
46 *
47 * To use this program in your application, insert the following lines to
48 * C source files after including `sys/types.h', `sys/socket.h' and
49 * `netdb.h'. `getaddrinfo.h' defines `struct addrinfo' and AI_, NI_,
50 * EAI_ macros.
51 *
52 * #ifndef HAVE_GETADDRINFO
53 * #include "getaddrinfo.h"
54 * #endif
55 *
56 * Restriction:
57 * getaddrinfo() and getnameinfo() of this program are NOT thread
58 * safe, unless the cpp macro ENABLE_PTHREAD is defined.
59 */
60
61 /*
62 * Add the following code to your configure.ac (or configure.in).
63 * AC_C_CONST
64 * AC_HEADER_STDC
65 * AC_CHECK_HEADERS(string.h memory.h stdlib.h)
66 * AC_CHECK_FUNCS(memcpy)
67 * AC_REPLACE_FUNCS(memset)
68 * AC_TYPE_SOCKLEN_T
69 * AC_TYPE_IN_PORT_T
70 * AC_DECL_H_ERRNO
71 *
72 * AC_CHECK_FUNCS(getaddrinfo getnameinfo)
73 * if test "$ac_cv_func_getaddrinfo$ac_cv_func_getnameinfo" != yesyes ; then
74 * LIBOBJS="$LIBOBJS getaddrinfo.$ac_objext"
75 * fi
76 */
77
78 #include "zsglobal.h"
79
80 #include <sys/types.h>
81 #include <stdio.h>
82 #include <sys/socket.h>
83 #include <netinet/in.h>
84 #include <arpa/inet.h>
85 #include <netdb.h>
86
87 #if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
88 #include <string.h>
89 #if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
90 #include <memory.h>
91 #endif /* not STDC_HEADERS and HAVE_MEMORY_H */
92 #else /* not STDC_HEADERS and not HAVE_STRING_H */
93 #include <strings.h>
94 #endif /* not STDC_HEADERS and not HAVE_STRING_H */
95
96 #ifdef HAVE_STDLIB_H
97 #include <stdlib.h>
98 #endif
99
100 #ifdef ENABLE_PTHREAD
101 #include <pthread.h>
102 #endif
103
104 #ifdef ENABLE_NLS
105 #include <libintl.h>
106 #endif
107
108 #ifndef HAVE_MEMCPY
109 #define memcpy(d, s, n) bcopy((s), (d), (n))
110 #ifdef __STDC__
111 void *memchr(const void *, int, size_t);
112 int memcmp(const void *, const void *, size_t);
113 void *memmove(void *, const void *, size_t);
114 void *memset(void *, int, size_t);
115 #else /* not __STDC__ */
116 char *memchr();
117 int memcmp();
118 char *memmove();
119 char *memset();
120 #endif /* not __STDC__ */
121 #endif /* not HAVE_MEMCPY */
122
123 #ifndef H_ERRNO_DECLARED
124 extern int h_errno;
125 #endif
126
127 #include "getaddrinfo.h"
128
129 #ifdef ENABLE_NLS
130 #define _(string) gettext(string)
131 #ifdef gettext_noop
132 #define N_(string) gettext_noop(string)
133 #else
134 #define N_(string) (string)
135 #endif
136 #else
137 #define gettext(string) (string)
138 #define _(string) (string)
139 #define N_(string) (string)
140 #endif
141
142 /*
143 * Error messages for gai_strerror().
144 */
145 static const char *eai_errlist[] = {
146 N_("Success"),
147
148 /* EAI_ADDRFAMILY */
149 N_("Address family for hostname not supported"),
150
151 /* EAI_AGAIN */
152 N_("Temporary failure in name resolution"),
153
154 /* EAI_BADFLAGS */
155 N_("Invalid value for ai_flags"),
156
157 /* EAI_FAIL */
158 N_("Non-recoverable failure in name resolution"),
159
160 /* EAI_FAMILY */
161 N_("ai_family not supported"),
162
163 /* EAI_MEMORY */
164 N_("Memory allocation failure"),
165
166 /* EAI_NONAME */
167 N_("hostname nor servname provided, or not known"),
168
169 /* EAI_OVERFLOW */
170 N_("An argument buffer overflowed"),
171
172 /* EAI_SERVICE */
173 N_("servname not supported for ai_socktype"),
174
175 /* EAI_SOCKTYPE */
176 N_("ai_socktype not supported"),
177
178 /* EAI_SYSTEM */
179 N_("System error returned in errno")
180 };
181
182 /*
183 * Default hints for getaddrinfo().
184 */
185 static struct addrinfo default_hints = {
186 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL
187 };
188
189 /*
190 * Mutex.
191 */
192 #ifdef ENABLE_PTHREAD
193 static pthread_mutex_t gai_mutex = PTHREAD_MUTEX_INITIALIZER;
194 #endif
195
196 /*
197 * Declaration of static functions.
198 */
199 #ifdef __STDC__
200 static int is_integer(const char *);
201 static int is_address(const char *);
202 static int itoa_length(int);
203 #else
204 static int is_integer();
205 static int is_address();
206 static int itoa_length();
207 #endif
208
209 /*
210 * gai_strerror().
211 */
212 const char *
213 gai_strerror(ecode)
214 int ecode;
215 {
216 if (ecode < 0 || ecode > EAI_SYSTEM)
217 return _("Unknown error");
218
219 return gettext(eai_errlist[ecode]);
220 }
221
222 /*
223 * freeaddrinfo().
224 */
225 void
226 freeaddrinfo(ai)
227 struct addrinfo *ai;
228 {
229 struct addrinfo *next_ai;
230
231 while (ai != NULL) {
232 if (ai->ai_canonname != NULL)
233 free(ai->ai_canonname);
234 if (ai->ai_addr != NULL)
235 free(ai->ai_addr);
236 next_ai = ai->ai_next;
237 free(ai);
238 ai = next_ai;
239 }
240 }
241
242 /*
243 * Return 1 if the string `s' represents an integer.
244 */
245 static int
246 is_integer(s)
247 const char *s;
248 {
249 if (*s == '-' || *s == '+')
250 s++;
251 if (*s < '0' || '9' < *s)
252 return 0;
253
254 s++;
255 while ('0' <= *s && *s <= '9')
256 s++;
257
258 return (*s == '\0');
259 }
260
261 /*
262 * Return 1 if the string `s' represents an IPv4 address.
263 * Unlike inet_addr(), it doesn't permit malformed nortation such
264 * as "192.168".
265 */
266 static int
267 is_address(s)
268 const char *s;
269 {
270 static const char delimiters[] = {'.', '.', '.', '\0'};
271 int i, j;
272 int octet;
273
274 for (i = 0; i < 4; i++) {
275 if (*s == '0' && *(s + 1) != delimiters[i])
276 return 0;
277 for (j = 0, octet = 0; '0' <= *s && *s <= '9' && j < 3; s++, j++)
278 octet = octet * 10 + (*s - '0');
279 if (j == 0 || octet > 255 || *s != delimiters[i])
280 return 0;
281 s++;
282 }
283
284 return 1;
285 }
286
287 /*
288 * Calcurate length of the string `s', where `s' is set by
289 * sprintf(s, "%d", n).
290 */
291 static int
292 itoa_length(n)
293 int n;
294 {
295 int result = 1;
296
297 if (n < 0) {
298 n = -n;
299 result++;
300 }
301
302 while (n >= 10) {
303 result++;
304 n /= 10;
305 }
306
307 return result;
308 }
309
310 /*
311 * getaddrinfo().
312 */
313 int
314 getaddrinfo(nodename, servname, hints, res)
315 const char *nodename;
316 const char *servname;
317 const struct addrinfo *hints;
318 struct addrinfo **res;
319 {
320 struct addrinfo *head_res = NULL;
321 struct addrinfo *tail_res = NULL;
322 struct addrinfo *new_res;
323 struct sockaddr_in *sa_in;
324 struct in_addr **addr_list;
325 struct in_addr *addr_list_buf[2];
326 struct in_addr addr_buf;
327 struct in_addr **ap;
328 struct servent *servent;
329 struct hostent *hostent;
330 const char *canonname = NULL;
331 in_port_t port;
332 int saved_h_errno;
333 int result = 0;
334
335 #ifdef ENABLE_PTHREAD
336 pthread_mutex_lock(&gai_mutex);
337 #endif
338
339 saved_h_errno = h_errno;
340
341 if (nodename == NULL && servname == NULL) {
342 result = EAI_NONAME;
343 goto end;
344 }
345
346 if (hints != NULL) {
347 if (hints->ai_family != PF_INET && hints->ai_family != PF_UNSPEC) {
348 result = EAI_FAMILY;
349 goto end;
350 }
351 if (hints->ai_socktype != SOCK_DGRAM
352 && hints->ai_socktype != SOCK_STREAM
353 && hints->ai_socktype != 0) {
354 result = EAI_SOCKTYPE;
355 goto end;
356 }
357 } else {
358 hints = &default_hints;
359 }
360
361 if (servname != NULL) {
362 if (is_integer(servname))
363 port = htons(atoi(servname));
364 else {
365 if (hints->ai_flags & AI_NUMERICSERV) {
366 result = EAI_NONAME;
367 goto end;
368 }
369
370 if (hints->ai_socktype == SOCK_DGRAM)
371 servent = getservbyname(servname, "udp");
372 else if (hints->ai_socktype == SOCK_STREAM)
373 servent = getservbyname(servname, "tcp");
374 else if (hints->ai_socktype == 0)
375 servent = getservbyname(servname, "tcp");
376 else {
377 result = EAI_SOCKTYPE;
378 goto end;
379 }
380
381 if (servent == NULL) {
382 result = EAI_SERVICE;
383 goto end;
384 }
385 port = servent->s_port;
386 }
387 } else {
388 port = htons(0);
389 }
390
391 if (nodename != NULL) {
392 if (is_address(nodename)) {
393 addr_buf.s_addr = inet_addr(nodename);
394 addr_list_buf[0] = &addr_buf;
395 addr_list_buf[1] = NULL;
396 addr_list = addr_list_buf;
397
398 if (hints->ai_flags & AI_CANONNAME
399 && !(hints->ai_flags & AI_NUMERICHOST)) {
400 hostent = gethostbyaddr((char *)&addr_buf,
401 sizeof(struct in_addr), AF_INET);
402 if (hostent != NULL)
403 canonname = hostent->h_name;
404 else
405 canonname = nodename;
406 }
407 } else {
408 if (hints->ai_flags & AI_NUMERICHOST) {
409 result = EAI_NONAME;
410 goto end;
411 }
412
413 hostent = gethostbyname(nodename);
414 if (hostent == NULL) {
415 switch (h_errno) {
416 case HOST_NOT_FOUND:
417 case NO_DATA:
418 result = EAI_NONAME;
419 goto end;
420 case TRY_AGAIN:
421 result = EAI_AGAIN;
422 goto end;
423 default:
424 result = EAI_FAIL;
425 goto end;
426 }
427 }
428 addr_list = (struct in_addr **)hostent->h_addr_list;
429
430 if (hints->ai_flags & AI_CANONNAME)
431 canonname = hostent->h_name;
432 }
433 } else {
434 if (hints->ai_flags & AI_PASSIVE)
435 addr_buf.s_addr = htonl(INADDR_ANY);
436 else
437 addr_buf.s_addr = htonl(0x7F000001);
438 addr_list_buf[0] = &addr_buf;
439 addr_list_buf[1] = NULL;
440 addr_list = addr_list_buf;
441 }
442
443 for (ap = addr_list; *ap != NULL; ap++) {
444 new_res = (struct addrinfo *)malloc(sizeof(struct addrinfo));
445 if (new_res == NULL) {
446 if (head_res != NULL)
447 freeaddrinfo(head_res);
448 result = EAI_MEMORY;
449 goto end;
450 }
451
452 new_res->ai_family = PF_INET;
453 new_res->ai_socktype = hints->ai_socktype;
454 new_res->ai_protocol = hints->ai_protocol;
455 new_res->ai_addr = NULL;
456 new_res->ai_addrlen = sizeof(struct sockaddr_in);
457 new_res->ai_canonname = NULL;
458 new_res->ai_next = NULL;
459
460 new_res->ai_addr = (struct sockaddr *)
461 malloc(sizeof(struct sockaddr_in));
462 if (new_res->ai_addr == NULL) {
463 free(new_res);
464 if (head_res != NULL)
465 freeaddrinfo(head_res);
466 result = EAI_MEMORY;
467 goto end;
468 }
469
470 sa_in = (struct sockaddr_in *)new_res->ai_addr;
471 memset(sa_in, 0, sizeof(struct sockaddr_in));
472 sa_in->sin_family = PF_INET;
473 sa_in->sin_port = port;
474 memcpy(&sa_in->sin_addr, *ap, sizeof(struct in_addr));
475
476 if (head_res == NULL)
477 head_res = new_res;
478 else
479 tail_res->ai_next = new_res;
480 tail_res = new_res;
481 }
482
483 if (canonname != NULL && head_res != NULL) {
484 head_res->ai_canonname = (char *)malloc(strlen(canonname) + 1);
485 if (head_res->ai_canonname != NULL)
486 strcpy(head_res->ai_canonname, canonname);
487 }
488
489 *res = head_res;
490
491 end:
492 h_errno = saved_h_errno;
493 #ifdef ENABLE_PTHREAD
494 pthread_mutex_unlock(&gai_mutex);
495 #endif
496 return result;
497 }
498
499 /*
500 * getnameinfo().
501 */
502 int
503 getnameinfo(sa, salen, node, nodelen, serv, servlen, flags)
504 const struct sockaddr *sa;
505 socklen_t salen;
506 char *node;
507 socklen_t nodelen;
508 char *serv;
509 socklen_t servlen;
510 int flags;
511 {
512 const struct sockaddr_in *sa_in = (const struct sockaddr_in *)sa;
513 struct hostent *hostent;
514 struct servent *servent;
515 char *ntoa_address;
516 int saved_h_errno;
517 int result = 0;
518
519 #ifdef ENABLE_PTHREAD
520 pthread_mutex_lock(&gai_mutex);
521 #endif
522
523 saved_h_errno = h_errno;
524
525 if (sa_in->sin_family != PF_INET) {
526 result = EAI_FAMILY;
527 goto end;
528 } else if (node == NULL && serv == NULL) {
529 result = EAI_NONAME;
530 goto end;
531 }
532
533 if (serv != NULL && servlen > 0) {
534 if (flags & NI_NUMERICSERV)
535 servent = NULL;
536 else if (flags & NI_DGRAM)
537 servent = getservbyport(sa_in->sin_port, "udp");
538 else
539 servent = getservbyport(sa_in->sin_port, "tcp");
540
541 if (servent != NULL) {
542 if (servlen <= strlen(servent->s_name)) {
543 result = EAI_OVERFLOW;
544 goto end;
545 }
546 strcpy(serv, servent->s_name);
547 } else {
548 if (servlen <= itoa_length(ntohs(sa_in->sin_port))) {
549 result = EAI_OVERFLOW;
550 goto end;
551 }
552 sprintf(serv, "%d", ntohs(sa_in->sin_port));
553 }
554 }
555
556 if (node != NULL && nodelen > 0) {
557 if (flags & NI_NUMERICHOST)
558 hostent = NULL;
559 else {
560 hostent = gethostbyaddr((char *)&sa_in->sin_addr,
561 sizeof(struct in_addr), AF_INET);
562 }
563 if (hostent != NULL) {
564 if (nodelen <= strlen(hostent->h_name)) {
565 result = EAI_OVERFLOW;
566 goto end;
567 }
568 strcpy(node, hostent->h_name);
569 } else {
570 if (flags & NI_NAMEREQD) {
571 result = EAI_NONAME;
572 goto end;
573 }
574 ntoa_address = inet_ntoa(sa_in->sin_addr);
575 if (nodelen <= strlen(ntoa_address)) {
576 result = EAI_OVERFLOW;
577 goto end;
578 }
579 strcpy(node, ntoa_address);
580 }
581
582 }
583
584 end:
585 h_errno = saved_h_errno;
586 #ifdef ENABLE_PTHREAD
587 pthread_mutex_unlock(&gai_mutex);
588 #endif
589 return result;
590 }
591