Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ext/socket/getnameinfo.c

Go to the documentation of this file.

    00001 /*
    00002  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    00003  * All rights reserved.
    00004  *
    00005  * Redistribution and use in source and binary forms, with or without
    00006  * modification, are permitted provided that the following conditions
    00007  * are met:
    00008  * 1. Redistributions of source code must retain the above copyright
    00009  *    notice, this list of conditions and the following disclaimer.
    00010  * 2. Redistributions in binary form must reproduce the above copyright
    00011  *    notice, this list of conditions and the following disclaimer in the
    00012  *    documentation and/or other materials provided with the distribution.
    00013  * 3. Neither the name of the project nor the names of its contributors
    00014  *    may be used to endorse or promote products derived from this software
    00015  *    without specific prior written permission.
    00016  *
    00017  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
    00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
    00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    00027  * SUCH DAMAGE.
    00028  */
    00029
    00030 /*
    00031  * Issues to be discussed:
    00032  * - Thread safe-ness must be checked
    00033  * - Return values.  There seems to be no standard for return value (RFC2133)
    00034  *   but INRIA implementation returns EAI_xxx defined for getaddrinfo().
    00035  */
    00036
    00037 #include "ruby/config.h"
    00038 #ifdef RUBY_EXTCONF_H
    00039 #include RUBY_EXTCONF_H
    00040 #endif
    00041 #include <stdio.h>
    00042 #include <sys/types.h>
    00043 #ifndef _WIN32
    00044 #if defined(__BEOS__) && !defined(__HAIKU__) && !defined(BONE)
    00045 # include <net/socket.h>
    00046 #else
    00047 # include <sys/socket.h>
    00048 #endif
    00049 #include <netinet/in.h>
    00050 #if defined(HAVE_ARPA_INET_H)
    00051 #include <arpa/inet.h>
    00052 #endif
    00053 #if defined(HAVE_ARPA_NAMESER_H)
    00054 #include <arpa/nameser.h>
    00055 #endif
    00056 #include <netdb.h>
    00057 #if defined(HAVE_RESOLV_H)
    00058 #include <resolv.h>
    00059 #endif
    00060 #endif
    00061 #ifdef _WIN32
    00062 #include <winsock2.h>
    00063 #include <ws2tcpip.h>
    00064 #define snprintf _snprintf
    00065 #endif
    00066
    00067 #include <string.h>
    00068 #include <stddef.h>
    00069
    00070 #ifdef SOCKS5
    00071 #include <socks.h>
    00072 #endif
    00073
    00074 #include "addrinfo.h"
    00075 #include "sockport.h"
    00076
    00077 #define SUCCESS 0
    00078 #define ANY 0
    00079 #define YES 1
    00080 #define NO  0
    00081
    00082 struct sockinet {
    00083         u_char  si_len;
    00084         u_char  si_family;
    00085         u_short si_port;
    00086 };
    00087
    00088 static struct afd {
    00089         int a_af;
    00090         int a_addrlen;
    00091         int a_socklen;
    00092         int a_off;
    00093 } afdl [] = {
    00094 #ifdef INET6
    00095 #define N_INET6 0
    00096         {PF_INET6, sizeof(struct in6_addr),
    00097          sizeof(struct sockaddr_in6),
    00098          offsetof(struct sockaddr_in6, sin6_addr)},
    00099 #define N_INET  1
    00100 #else
    00101 #define N_INET  0
    00102 #endif
    00103         {PF_INET, sizeof(struct in_addr),
    00104          sizeof(struct sockaddr_in),
    00105          offsetof(struct sockaddr_in, sin_addr)},
    00106         {0, 0, 0, 0},
    00107 };
    00108
    00109 #define ENI_NOSOCKET    0
    00110 #define ENI_NOSERVNAME  1
    00111 #define ENI_NOHOSTNAME  2
    00112 #define ENI_MEMORY      3
    00113 #define ENI_SYSTEM      4
    00114 #define ENI_FAMILY      5
    00115 #define ENI_SALEN       6
    00116
    00117 #ifdef __HAIKU__
    00118 #define HAVE_INET_NTOP
    00119 #endif
    00120 #ifndef HAVE_INET_NTOP
    00121 static const char *
    00122 inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
    00123 {
    00124 #ifdef HAVE_INET_NTOA
    00125         struct in_addr in;
    00126         memcpy(&in.s_addr, addr, sizeof(in.s_addr));
    00127         snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in));
    00128 #else
    00129         unsigned long x = ntohl(*(unsigned long*)addr);
    00130         snprintf(numaddr, numaddr_len, "%d.%d.%d.%d",
    00131                  (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
    00132                  (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff);
    00133 #endif
    00134         return numaddr;
    00135 }
    00136 #endif
    00137
    00138 int
    00139 getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags)
    00140 {
    00141         struct afd *afd;
    00142         struct hostent *hp;
    00143         u_short port;
    00144         int family, len, i;
    00145         char *addr, *p;
    00146         u_long v4a;
    00147 #ifdef INET6
    00148         u_char pfx;
    00149 #endif
    00150         int h_error;
    00151         char numserv[512];
    00152         char numaddr[512];
    00153
    00154         if (sa == NULL)
    00155                 return ENI_NOSOCKET;
    00156
    00157         len = SA_LEN(sa);
    00158         if (len != salen) return ENI_SALEN;
    00159
    00160         family = sa->sa_family;
    00161         for (i = 0; afdl[i].a_af; i++)
    00162                 if (afdl[i].a_af == family) {
    00163                         afd = &afdl[i];
    00164                         goto found;
    00165                 }
    00166         return ENI_FAMILY;
    00167
    00168  found:
    00169         if (len != afd->a_socklen) return ENI_SALEN;
    00170
    00171         port = ((struct sockinet *)sa)->si_port; /* network byte order */
    00172         addr = (char *)sa + afd->a_off;
    00173
    00174         if (serv == NULL || servlen == 0) {
    00175                 /* what we should do? */
    00176         } else if (flags & NI_NUMERICSERV) {
    00177                 snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
    00178                 if (strlen(numserv) + 1 > servlen)
    00179                         return ENI_MEMORY;
    00180                 strcpy(serv, numserv);
    00181         } else {
    00182 #if defined(HAVE_GETSERVBYPORT)
    00183                 struct servent *sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
    00184                 if (sp) {
    00185                         if (strlen(sp->s_name) + 1 > servlen)
    00186                                 return ENI_MEMORY;
    00187                         strcpy(serv, sp->s_name);
    00188                 } else
    00189                         return ENI_NOSERVNAME;
    00190 #else
    00191                 return ENI_NOSERVNAME;
    00192 #endif
    00193         }
    00194
    00195         switch (sa->sa_family) {
    00196         case AF_INET:
    00197                 v4a = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
    00198                 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
    00199                         flags |= NI_NUMERICHOST;
    00200                 v4a >>= IN_CLASSA_NSHIFT;
    00201                 if (v4a == 0)
    00202                         flags |= NI_NUMERICHOST;
    00203                 break;
    00204 #ifdef INET6
    00205         case AF_INET6:
    00206 #ifdef HAVE_ADDR8
    00207                 pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr8[0];
    00208 #else
    00209                 pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[0];
    00210 #endif
    00211                 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
    00212                         flags |= NI_NUMERICHOST;
    00213                 break;
    00214 #endif
    00215         }
    00216         if (host == NULL || hostlen == 0) {
    00217                 /* what should we do? */
    00218         } else if (flags & NI_NUMERICHOST) {
    00219                 if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
    00220                     == NULL)
    00221                         return ENI_SYSTEM;
    00222                 if (strlen(numaddr) > hostlen)
    00223                         return ENI_MEMORY;
    00224                 strcpy(host, numaddr);
    00225         } else {
    00226 #ifdef INET6
    00227                 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
    00228 #else
    00229                 hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
    00230                 h_error = h_errno;
    00231 #endif
    00232
    00233                 if (hp) {
    00234                         if (flags & NI_NOFQDN) {
    00235                                 p = strchr(hp->h_name, '.');
    00236                                 if (p) *p = '\0';
    00237                         }
    00238                         if (strlen(hp->h_name) + 1 > hostlen) {
    00239 #ifdef INET6
    00240                                 freehostent(hp);
    00241 #endif
    00242                                 return ENI_MEMORY;
    00243                         }
    00244                         strcpy(host, hp->h_name);
    00245 #ifdef INET6
    00246                         freehostent(hp);
    00247 #endif
    00248                 } else {
    00249                         if (flags & NI_NAMEREQD)
    00250                                 return ENI_NOHOSTNAME;
    00251                         if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
    00252                             == NULL)
    00253                                 return ENI_NOHOSTNAME;
    00254                         if (strlen(numaddr) > hostlen)
    00255                                 return ENI_MEMORY;
    00256                         strcpy(host, numaddr);
    00257                 }
    00258         }
    00259         return SUCCESS;
    00260 }
    00261