Final rfc2553 changes
[ntk/apt.git] / methods / rfc2553emu.cc
CommitLineData
934b6582
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
533151d3 3// $Id: rfc2553emu.cc,v 1.2 1999/05/26 04:08:39 jgg Exp $
934b6582
AL
4/* ######################################################################
5
6 RFC 2553 Emulation - Provides emulation for RFC 2553 getaddrinfo,
7 freeaddrinfo and getnameinfo
8
9 Originally written by Jason Gunthorpe <jgg@debian.org> and placed into
10 the Public Domain, do with it what you will.
11
12 ##################################################################### */
13 /*}}}*/
14#include "rfc2553emu.h"
15#include <stdlib.h>
16#include <arpa/inet.h>
533151d3
AL
17#include <string.h>
18#include <stdio.h>
934b6582
AL
19
20#ifndef HAVE_GETADDRINFO
533151d3
AL
21// getaddrinfo - Resolve a hostname /*{{{*/
22// ---------------------------------------------------------------------
23/* */
934b6582
AL
24int getaddrinfo(const char *nodename, const char *servname,
25 const struct addrinfo *hints,
26 struct addrinfo **res)
27{
28 struct addrinfo **Result;
29 hostent *Addr;
30 unsigned int Port;
31 int Proto;
32 const char *End;
33 char **CurAddr;
34
35 Addr = gethostbyname(nodename);
36 if (Addr == 0)
37 {
38 if (h_errno == TRY_AGAIN)
39 return EAI_AGAIN;
40 if (h_errno == NO_RECOVERY)
41 return EAI_FAIL;
42 return EAI_NONAME;
43 }
44
45 // No A records
46 if (Addr->h_addr_list[0] == 0)
47 return EAI_NONAME;
48
49 // Try to convert the service as a number
50 Port = htons(strtol(servname,(char **)&End,0));
51 Proto = SOCK_STREAM;
52
53 if (hints != 0 && hints->ai_socktype != 0)
54 Proto = hints->ai_socktype;
55
56 // Not a number, must be a name.
57 if (End != servname + strlen(End))
58 {
59 struct servent *Srv = 0;
60
61 // Do a lookup in the service database
62 if (hints == 0 || hints->ai_socktype == SOCK_STREAM)
63 Srv = getservbyname(servname,"tcp");
64 if (hints != 0 && hints->ai_socktype == SOCK_DGRAM)
65 Srv = getservbyname(servname,"udp");
66 if (Srv == 0)
67 return EAI_NONAME;
68
69 // Get the right protocol
70 Port = Srv->s_port;
71 if (strcmp(Srv->s_proto,"tcp") == 0)
72 Proto = SOCK_STREAM;
73 else
74 {
75 if (strcmp(Srv->s_proto,"udp") == 0)
76 Proto = SOCK_DGRAM;
77 else
78 return EAI_NONAME;
79 }
80
81 if (hints != 0 && hints->ai_socktype != Proto &&
82 hints->ai_socktype != 0)
83 return EAI_SERVICE;
84 }
85
86 // Start constructing the linked list
87 *res = 0;
88 for (CurAddr = Addr->h_addr_list; *CurAddr != 0; CurAddr++)
89 {
90 // New result structure
91 *Result = (struct addrinfo *)calloc(sizeof(**Result),1);
92 if (*Result == 0)
93 {
94 freeaddrinfo(*res);
95 return EAI_MEMORY;
96 }
97 if (*res == 0)
98 *res = *Result;
99
100 (*Result)->ai_family = AF_INET;
101 (*Result)->ai_socktype = Proto;
102
103 // If we have the IPPROTO defines we can set the protocol field
104 #ifdef IPPROTO_TCP
105 if (Proto == SOCK_STREAM)
106 (*Result)->ai_protocol = IPPROTO_TCP;
107 if (Proto == SOCK_DGRAM)
108 (*Result)->ai_protocol = IPPROTO_UDP;
109 #endif
110
111 // Allocate space for the address
112 (*Result)->ai_addrlen = sizeof(struct sockaddr_in);
113 (*Result)->ai_addr = (struct sockaddr *)calloc(sizeof(sockaddr_in),1);
114 if ((*Result)->ai_addr == 0)
115 {
116 freeaddrinfo(*res);
117 return EAI_MEMORY;
118 }
119
120 // Set the address
121 ((struct sockaddr_in *)(*Result)->ai_addr)->sin_family = AF_INET;
122 ((struct sockaddr_in *)(*Result)->ai_addr)->sin_port = Port;
123 ((struct sockaddr_in *)(*Result)->ai_addr)->sin_addr = *(in_addr *)(*CurAddr);
124
125 Result = &(*Result)->ai_next;
126 }
127
128 return 0;
129}
533151d3
AL
130 /*}}}*/
131// freeaddrinfo - Free the result of getaddrinfo /*{{{*/
132// ---------------------------------------------------------------------
133/* */
934b6582
AL
134void freeaddrinfo(struct addrinfo *ai)
135{
136 struct addrinfo *Tmp;
137 while (ai != 0)
138 {
139 free(ai->ai_addr);
140 Tmp = ai;
141 ai = ai->ai_next;
142 free(ai);
143 }
144}
533151d3 145 /*}}}*/
934b6582 146#endif // HAVE_GETADDRINFO
533151d3
AL
147
148#ifndef HAVE_GETNAMEINFO
149// getnameinfo - Convert a sockaddr to a string /*{{{*/
150// ---------------------------------------------------------------------
151/* */
152int getnameinfo(const struct sockaddr *sa, socklen_t salen,
153 char *host, size_t hostlen,
154 char *serv, size_t servlen,
155 int flags)
156{
157 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
158
159 // This routine only support internet addresses
160 if (sa->sa_family != AF_INET)
161 return EAI_ADDRFAMILY;
162
163 if (host != 0)
164 {
165 // Try to resolve the hostname
166 if ((flags & NI_NUMERICHOST) != NI_NUMERICHOST)
167 {
168 struct hostent *Ent = gethostbyaddr((char *)&sin->sin_addr,sizeof(sin->sin_addr),
169 AF_INET);
170 if (Ent != 0)
171 strncpy(host,Ent->h_name,hostlen);
172 else
173 {
174 if ((flags & NI_NAMEREQD) == NI_NAMEREQD)
175 {
176 if (h_errno == TRY_AGAIN)
177 return EAI_AGAIN;
178 if (h_errno == NO_RECOVERY)
179 return EAI_FAIL;
180 return EAI_NONAME;
181 }
182
183 flags |= NI_NUMERICHOST;
184 }
185 }
186
187 // Resolve as a plain numberic
188 if ((flags & NI_NUMERICHOST) == NI_NUMERICHOST)
189 {
190 strncpy(host,inet_ntoa(sin->sin_addr),hostlen);
191 }
192 }
193
194 if (serv != 0)
195 {
196 // Try to resolve the hostname
197 if ((flags & NI_NUMERICSERV) != NI_NUMERICSERV)
198 {
199 struct servent *Ent;
200 if ((flags & NI_DATAGRAM) == NI_DATAGRAM)
201 Ent = getservbyport(sin->sin_port,"udp");
202 else
203 Ent = getservbyport(sin->sin_port,"tcp");
204
205 if (Ent != 0)
206 strncpy(serv,Ent->s_name,servlen);
207 else
208 {
209 if ((flags & NI_NAMEREQD) == NI_NAMEREQD)
210 return EAI_NONAME;
211
212 flags |= NI_NUMERICSERV;
213 }
214 }
215
216 // Resolve as a plain numberic
217 if ((flags & NI_NUMERICSERV) == NI_NUMERICSERV)
218 {
219 snprintf(serv,servlen,"%u",sin->sin_port);
220 }
221 }
222
223 return 0;
224}
225 /*}}}*/
226#endif // HAVE_GETNAMEINFO