Ruby: ext/socket/getnameinfo.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

getnameinfo.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30/*
31 * Issues to be discussed:
32 * - Thread safe-ness must be checked
33 * - Return values. There seems to be no standard for return value (RFC2133)
34 * but INRIA implementation returns EAI_xxx defined for getaddrinfo().
35 */
36
37#include "ruby/config.h"
38#ifdef RUBY_EXTCONF_H
39#include RUBY_EXTCONF_H
40#endif
41#include <stdio.h>
42#include <sys/types.h>
43#ifndef _WIN32
44#include <sys/socket.h>
45#include <netinet/in.h>
46#if defined(HAVE_ARPA_INET_H)
47#include <arpa/inet.h>
48#endif
49#if defined(HAVE_ARPA_NAMESER_H)
50#include <arpa/nameser.h>
51#endif
52#include <netdb.h>
53#if defined(HAVE_RESOLV_H)
54#include <resolv.h>
55#endif
56#endif
57#ifdef _WIN32
58#if defined(_MSC_VER) && _MSC_VER <= 1200
59#include <windows.h>
60#endif
61#include <winsock2.h>
62#include <ws2tcpip.h>
63#define snprintf _snprintf
64#endif
65
66#include <string.h>
67#include <stddef.h>
68
69#ifdef SOCKS5
70#include <socks.h>
71#endif
72
73#ifndef HAVE_TYPE_SOCKLEN_T
74 typedef int socklen_t;
75#endif
76
77#include "addrinfo.h"
78#include "sockport.h"
79#include "rubysocket.h"
80
81#define SUCCESS 0
82#define ANY 0
83#define YES 1
84#define NO 0
85
86struct sockinet {
87 u_char si_len;
88 u_char si_family;
89 u_short si_port;
90};
91
92static struct afd {
93 int a_af;
94 int a_addrlen;
95 int a_socklen;
96 int a_off;
97} afdl [] = {
98#ifdef INET6
99#define N_INET6 0
100 {PF_INET6, sizeof(struct in6_addr),
101 sizeof(struct sockaddr_in6),
102 offsetof(struct sockaddr_in6, sin6_addr)},
103#define N_INET 1
104#else
105#define N_INET 0
106#endif
107 {PF_INET, sizeof(struct in_addr),
108 sizeof(struct sockaddr_in),
109 offsetof(struct sockaddr_in, sin_addr)},
110 {0, 0, 0, 0},
111};
112
113#define ENI_NOSOCKET 0
114#define ENI_NOSERVNAME 1
115#define ENI_NOHOSTNAME 2
116#define ENI_MEMORY 3
117#define ENI_SYSTEM 4
118#define ENI_FAMILY 5
119#define ENI_SALEN 6
120
121int
122 getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags)
123{
124 struct afd *afd;
125 struct hostent *hp;
126 u_short port;
127 int family, len, i;
128 char *addr, *p;
129 u_long v4a;
130#ifdef INET6
131 u_char pfx;
132#endif
133 int h_error;
134 char numserv[512];
135 char numaddr[512];
136
137 if (sa == NULL)
138 return ENI_NOSOCKET;
139
140 if (!VALIDATE_SOCKLEN(sa, salen)) return ENI_SALEN;
141 len = salen;
142
143 family = sa->sa_family;
144 for (i = 0; afdl[i].a_af; i++)
145 if (afdl[i].a_af == family) {
146 afd = &afdl[i];
147 goto found;
148 }
149 return ENI_FAMILY;
150
151 found:
152 if (len != afd->a_socklen) return ENI_SALEN;
153
154 port = ((struct sockinet *)sa)->si_port; /* network byte order */
155 addr = (char *)sa + afd->a_off;
156
157 if (serv == NULL || servlen == 0) {
158 /* what we should do? */
159 } else if (flags & NI_NUMERICSERV) {
160 snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
161 if (strlen(numserv) + 1 > servlen)
162 return ENI_MEMORY;
163 strcpy(serv, numserv);
164 } else {
165#if defined(HAVE_GETSERVBYPORT)
166 struct servent *sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
167 if (sp) {
168 if (strlen(sp->s_name) + 1 > servlen)
169 return ENI_MEMORY;
170 strcpy(serv, sp->s_name);
171 } else
172 return ENI_NOSERVNAME;
173#else
174 return ENI_NOSERVNAME;
175#endif
176 }
177
178 switch (sa->sa_family) {
179 case AF_INET:
180 v4a = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
181 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
182 flags |= NI_NUMERICHOST;
183 v4a >>= IN_CLASSA_NSHIFT;
184 if (v4a == 0)
185 flags |= NI_NUMERICHOST;
186 break;
187#ifdef INET6
188 case AF_INET6:
189#ifdef HAVE_ADDR8
190 pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr8[0];
191#else
192 pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[0];
193#endif
194 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
195 flags |= NI_NUMERICHOST;
196 break;
197#endif
198 }
199 if (host == NULL || hostlen == 0) {
200 /* what should we do? */
201 } else if (flags & NI_NUMERICHOST) {
202 if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
203 == NULL)
204 return ENI_SYSTEM;
205 if (strlen(numaddr) > hostlen)
206 return ENI_MEMORY;
207 strcpy(host, numaddr);
208 } else {
209#ifdef INET6
210 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
211#else
212 hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
213 h_error = h_errno;
214#endif
215
216 if (hp) {
217 if (flags & NI_NOFQDN) {
218 p = strchr(hp->h_name, '.');
219 if (p) *p = '\0';
220 }
221 if (strlen(hp->h_name) + 1 > hostlen) {
222#ifdef INET6
223 freehostent(hp);
224#endif
225 return ENI_MEMORY;
226 }
227 strcpy(host, hp->h_name);
228#ifdef INET6
229 freehostent(hp);
230#endif
231 } else {
232 if (flags & NI_NAMEREQD)
233 return ENI_NOHOSTNAME;
234 if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
235 == NULL)
236 return ENI_NOHOSTNAME;
237 if (strlen(numaddr) > hostlen)
238 return ENI_MEMORY;
239 strcpy(host, numaddr);
240 }
241 }
242 return SUCCESS;
243}
addrinfo.h
freehostent
#define freehostent
Definition: addrinfo.h:153
NI_NAMEREQD
#define NI_NAMEREQD
Definition: addrinfo.h:126
offsetof
#define offsetof(p_type, field)
Definition: addrinfo.h:186
NI_NUMERICHOST
#define NI_NUMERICHOST
Definition: addrinfo.h:125
getnameinfo
#define getnameinfo
Definition: addrinfo.h:149
NI_DGRAM
#define NI_DGRAM
Definition: addrinfo.h:128
NI_NOFQDN
#define NI_NOFQDN
Definition: addrinfo.h:124
NI_NUMERICSERV
#define NI_NUMERICSERV
Definition: addrinfo.h:127
strchr
char * strchr(char *, char)
len
uint8_t len
Definition: escape.c:17
socklen_t
int socklen_t
Definition: getaddrinfo.c:83
ENI_SALEN
#define ENI_SALEN
Definition: getnameinfo.c:119
ENI_NOHOSTNAME
#define ENI_NOHOSTNAME
Definition: getnameinfo.c:115
ENI_MEMORY
#define ENI_MEMORY
Definition: getnameinfo.c:116
socklen_t
int socklen_t
Definition: getnameinfo.c:74
ENI_NOSOCKET
#define ENI_NOSOCKET
Definition: getnameinfo.c:113
ENI_NOSERVNAME
#define ENI_NOSERVNAME
Definition: getnameinfo.c:114
SUCCESS
#define SUCCESS
Definition: getnameinfo.c:81
N_INET
#define N_INET
ENI_FAMILY
#define ENI_FAMILY
Definition: getnameinfo.c:118
ENI_SYSTEM
#define ENI_SYSTEM
Definition: getnameinfo.c:117
inet_ntop
const char * inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
Definition: option.c:651
NULL
#define NULL
Definition: regenc.h:69
rubysocket.h
sockport.h
VALIDATE_SOCKLEN
#define VALIDATE_SOCKLEN(addr, len)
Definition: sockport.h:16
PF_INET
#define PF_INET
Definition: sockport.h:109
IN_CLASSA_NSHIFT
#define IN_CLASSA_NSHIFT
Definition: sockport.h:93
IN_EXPERIMENTAL
#define IN_EXPERIMENTAL(i)
Definition: sockport.h:89
IN_MULTICAST
#define IN_MULTICAST(i)
Definition: sockport.h:85
strlen
size_t strlen(const char *)
sockinet
Definition: getaddrinfo.c:108
sockinet::si_len
u_char si_len
Definition: getaddrinfo.c:109
sockinet::si_family
u_char si_family
Definition: getaddrinfo.c:110
sockinet::si_port
u_short si_port
Definition: getaddrinfo.c:111
snprintf
#define snprintf
Definition: subst.h:14
u_long
#define u_long
Definition: vsnprintf.c:64
u_short
#define u_short
Definition: vsnprintf.c:65
if
if((ID)(DISPID) nameid !=nameid)
Definition: win32ole.c:357