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