| 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 | while (ai != 0) |
| 158 | { |
| 159 | free(ai->ai_addr); |
| 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 |