forked from unpbook/unpv13e
-
Notifications
You must be signed in to change notification settings - Fork 0
/
getnameinfo.c
122 lines (107 loc) · 3.4 KB
/
getnameinfo.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
* Copyright (c) 1996 W. Richard Stevens. All rights reserved.
*
* Permission to use or modify this software for educational or
* for commercial purposes, and without fee, is hereby granted,
* provided that the above copyright notice appears in connection
* with any and all uses, with clear indication as to any
* modifications made. The author RESERVES the sole rights of
* reproduction, publication and distribution and hence permission
* to print this source code in any book, reference manual,
* magazine, or other type of publication, including any digital
* medium, must be granted in writing by W. Richard Stevens.
*
* The author makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express
* or implied warranty.
*/
/* tabs set for 4 spaces, not 8 */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> /* hostent{}, servent{}, etc. */
#include <string.h> /* strncpy() */
/* We need a way to determine if the compiling host supports IPv4/IPv6.
Cannot test for AF_INET6, as some vendors #define it, even though
they don't support it. */
#ifdef AF_INET
#define IPV4 /* this is tested throughout the code that follows */
#endif
#ifdef IPV6ADDR_ANY_INIT
#define IPV6 /* this is tested throughout the code that follows */
#endif
/* Define following if the reentrant versions of get{host|serv}byaddr
are to be used.
Note that getaddrinfo{} must be reentrant if the underlying
get{host|serv}byaddr_r functions are provided. */
/* #define REENTRANT */
#define HENTBUFSIZ 8*1024
/* function prototypes for our own internal functions */
static int do_ipv46(char *, size_t, char *, size_t,
void *, size_t, int, int);
int
getnameinfo(const struct sockaddr *sa, size_t salen,
char *host, size_t hostlen, char *serv, size_t servlen)
{
switch (sa->sa_family) {
#ifdef IPV4
case AF_INET: {
struct sockaddr_in *sain = (struct sockaddr_in *) sa;
return(do_ipv46(host, hostlen, serv, servlen,
&sain->sin_addr, sizeof(struct in_addr), AF_INET,
sain->sin_port));
}
#endif /* IPV4 */
#ifdef IPV6
case AF_INET6: {
struct sockaddr_in6 *sain = (struct sockaddr_in6 *) sa;
return(do_ipv46(host, hostlen, serv, servlen,
&sain->sin6_addr, sizeof(struct in6_addr), AF_INET6,
sain->sin6_port));
}
#endif /* IPV6 */
default:
return(1);
}
}
/*
* Handle either an IPv4 or an IPv6 address and port.
*/
static int
do_ipv46(char *host, size_t hostlen, char *serv, size_t servlen,
void *aptr, size_t alen, int family, int port)
{
struct hostent *hptr, hent;
struct servent *sptr, sent;
char hentbuf[HENTBUFSIZ];
if (hostlen > 0) {
#ifdef REENTRANT
hptr = gethostbyaddr_r(aptr, alen, family,
&hent, hentbuf, HENTBUFSIZ, &h_errno);
#else
hptr = gethostbyaddr(aptr, alen, family);
#endif
if (hptr != NULL && hptr->h_name != NULL)
strncpy(host, hptr->h_name, hostlen);
else
return(1);
}
if (servlen > 0) {
/*
* Notice that we do not have enough information to pass a
* "protocol" argument to getservbyport(), so the assumption
* is that the protocol (TCP or UDP) does not matter.
*/
#ifdef REENTRANT
sptr = getservbyport_r(port, NULL,
&sent, hentbuf, HENTBUFSIZ);
#else
sptr = getservbyport(port, NULL);
#endif
if (sptr != NULL && sptr->s_name != NULL)
strncpy(serv, sptr->s_name, servlen);
else
return(1);
}
return(0);
}