OLD | NEW |
(Empty) | |
| 1 #include <stdlib.h> |
| 2 #include <sys/socket.h> |
| 3 #include <netinet/in.h> |
| 4 #include <netdb.h> |
| 5 #include <string.h> |
| 6 #include "lookup.h" |
| 7 |
| 8 int getaddrinfo(const char *restrict host, const char *restrict serv, const stru
ct addrinfo *restrict hint, struct addrinfo **restrict res) |
| 9 { |
| 10 struct service ports[MAXSERVS]; |
| 11 struct address addrs[MAXADDRS]; |
| 12 char canon[256], *outcanon; |
| 13 int nservs, naddrs, nais, canon_len, i, j, k; |
| 14 int family = AF_UNSPEC, flags = 0, proto = 0, socktype = 0; |
| 15 struct aibuf { |
| 16 struct addrinfo ai; |
| 17 union sa { |
| 18 struct sockaddr_in sin; |
| 19 struct sockaddr_in6 sin6; |
| 20 } sa; |
| 21 } *out; |
| 22 |
| 23 if (!host && !serv) return EAI_NONAME; |
| 24 |
| 25 if (hint) { |
| 26 family = hint->ai_family; |
| 27 flags = hint->ai_flags; |
| 28 proto = hint->ai_protocol; |
| 29 socktype = hint->ai_socktype; |
| 30 |
| 31 const int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | |
| 32 AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG | AI_NUMERICSERV; |
| 33 if ((flags & mask) != flags) |
| 34 return EAI_BADFLAGS; |
| 35 |
| 36 switch (family) { |
| 37 case AF_INET: |
| 38 case AF_INET6: |
| 39 case AF_UNSPEC: |
| 40 break; |
| 41 default: |
| 42 return EAI_FAMILY; |
| 43 } |
| 44 } |
| 45 |
| 46 nservs = __lookup_serv(ports, serv, proto, socktype, flags); |
| 47 if (nservs < 0) return nservs; |
| 48 |
| 49 naddrs = __lookup_name(addrs, canon, host, family, flags); |
| 50 if (naddrs < 0) return naddrs; |
| 51 |
| 52 nais = nservs * naddrs; |
| 53 canon_len = strlen(canon); |
| 54 out = calloc(1, nais * sizeof(*out) + canon_len + 1); |
| 55 if (!out) return EAI_MEMORY; |
| 56 |
| 57 if (canon_len) { |
| 58 outcanon = (void *)&out[nais]; |
| 59 memcpy(outcanon, canon, canon_len+1); |
| 60 } else { |
| 61 outcanon = 0; |
| 62 } |
| 63 |
| 64 for (k=i=0; i<naddrs; i++) for (j=0; j<nservs; j++, k++) { |
| 65 out[k].ai = (struct addrinfo){ |
| 66 .ai_family = addrs[i].family, |
| 67 .ai_socktype = ports[j].socktype, |
| 68 .ai_protocol = ports[j].proto, |
| 69 .ai_addrlen = addrs[i].family == AF_INET |
| 70 ? sizeof(struct sockaddr_in) |
| 71 : sizeof(struct sockaddr_in6), |
| 72 .ai_addr = (void *)&out[k].sa, |
| 73 .ai_canonname = outcanon, |
| 74 .ai_next = &out[k+1].ai }; |
| 75 switch (addrs[i].family) { |
| 76 case AF_INET: |
| 77 out[k].sa.sin.sin_family = AF_INET; |
| 78 out[k].sa.sin.sin_port = htons(ports[j].port); |
| 79 memcpy(&out[k].sa.sin.sin_addr, &addrs[i].addr, 4); |
| 80 break; |
| 81 case AF_INET6: |
| 82 out[k].sa.sin6.sin6_family = AF_INET6; |
| 83 out[k].sa.sin6.sin6_port = htons(ports[j].port); |
| 84 out[k].sa.sin6.sin6_scope_id = addrs[i].scopeid; |
| 85 memcpy(&out[k].sa.sin6.sin6_addr, &addrs[i].addr, 16); |
| 86 break; |
| 87 } |
| 88 } |
| 89 out[nais-1].ai.ai_next = 0; |
| 90 *res = &out->ai; |
| 91 return 0; |
| 92 } |
OLD | NEW |