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