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