upload http
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / srclib / apr / network_io / unix / sockaddr.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "apr_arch_networkio.h"
18 #include "apr_strings.h"
19 #include "apr.h"
20 #include "apr_lib.h"
21 #include "apr_strings.h"
22 #include "apr_private.h"
23
24 #if APR_HAVE_STDLIB_H
25 #include <stdlib.h>
26 #endif
27
28 #define APR_WANT_STRFUNC
29 #include "apr_want.h"
30
31 struct apr_ipsubnet_t {
32     int family;
33 #if APR_HAVE_IPV6
34     apr_uint32_t sub[4]; /* big enough for IPv4 and IPv6 addresses */
35     apr_uint32_t mask[4];
36 #else
37     apr_uint32_t sub[1];
38     apr_uint32_t mask[1];
39 #endif
40 };
41
42 #if !defined(NETWARE) && !defined(WIN32)
43 #ifdef HAVE_SET_H_ERRNO
44 #define SET_H_ERRNO(newval) set_h_errno(newval)
45 #else
46 #define SET_H_ERRNO(newval) h_errno = (newval)
47 #endif
48 #else
49 #define SET_H_ERRNO(newval)
50 #endif
51
52 #if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \
53     defined(HAVE_GETHOSTBYNAME_R)
54 /* This is the maximum size that may be returned from the reentrant
55  * gethostbyname_r function.  If the system tries to use more, it
56  * should return ERANGE.
57  */
58 #define GETHOSTBYNAME_BUFLEN 512
59 #endif
60
61 #ifdef _WIN32_WCE
62 /* XXX: BS solution.  Need an HAVE_GETSERVBYNAME and actually
63  * do something here, to provide the obvious proto mappings.
64  */
65 static void *getservbyname(const char *name, const char *proto)
66 {
67     return NULL;
68 }
69 #endif
70
71 static apr_status_t get_local_addr(apr_socket_t *sock)
72 {
73     sock->local_addr->salen = sizeof(sock->local_addr->sa);
74     if (getsockname(sock->socketdes, (struct sockaddr *)&sock->local_addr->sa,
75                     &sock->local_addr->salen) < 0) {
76         return apr_get_netos_error();
77     }
78     else {
79         sock->local_port_unknown = sock->local_interface_unknown = 0;
80         /* XXX assumes sin_port and sin6_port at same offset */
81         sock->local_addr->port = ntohs(sock->local_addr->sa.sin.sin_port);
82         return APR_SUCCESS;
83     }
84 }
85
86 static apr_status_t get_remote_addr(apr_socket_t *sock)
87 {
88     sock->remote_addr->salen = sizeof(sock->remote_addr->sa);
89     if (getpeername(sock->socketdes, (struct sockaddr *)&sock->remote_addr->sa,
90                     &sock->remote_addr->salen) < 0) {
91         return apr_get_netos_error();
92     }
93     else {
94         sock->remote_addr_unknown = 0;
95         /* XXX assumes sin_port and sin6_port at same offset */
96         sock->remote_addr->port = ntohs(sock->remote_addr->sa.sin.sin_port);
97         return APR_SUCCESS;
98     }
99 }
100
101 APR_DECLARE(apr_status_t) apr_sockaddr_port_set(apr_sockaddr_t *sockaddr,
102                                        apr_port_t port)
103 {
104     sockaddr->port = port;
105     /* XXX IPv6: assumes sin_port and sin6_port at same offset */
106     sockaddr->sa.sin.sin_port = htons(port);
107     return APR_SUCCESS;
108 }
109
110 /* XXX assumes IPv4... I don't think this function is needed anyway
111  * since we have apr_sockaddr_info_get(), but we need to clean up Apache's 
112  * listen.c a bit more first.
113  */
114 APR_DECLARE(apr_status_t) apr_sockaddr_ip_set(apr_sockaddr_t *sockaddr,
115                                          const char *addr)
116 {
117     apr_uint32_t ipaddr;
118     
119     if (!strcmp(addr, APR_ANYADDR)) {
120         sockaddr->sa.sin.sin_addr.s_addr = htonl(INADDR_ANY);
121         return APR_SUCCESS;
122     }
123     
124     ipaddr = inet_addr(addr);
125     if (ipaddr == (apr_uint32_t)-1) {
126 #ifdef WIN32
127         return WSAEADDRNOTAVAIL;
128 #else
129         return errno;
130 #endif
131     }
132     
133     sockaddr->sa.sin.sin_addr.s_addr = ipaddr;
134     return APR_SUCCESS;
135 }
136
137 APR_DECLARE(apr_status_t) apr_sockaddr_port_get(apr_port_t *port,
138                                        apr_sockaddr_t *sockaddr)
139 {
140     *port = sockaddr->port;
141     return APR_SUCCESS;
142 }
143
144 APR_DECLARE(apr_status_t) apr_sockaddr_ip_get(char **addr,
145                                          apr_sockaddr_t *sockaddr)
146 {
147     *addr = apr_palloc(sockaddr->pool, sockaddr->addr_str_len);
148     apr_inet_ntop(sockaddr->family,
149                   sockaddr->ipaddr_ptr,
150                   *addr,
151                   sockaddr->addr_str_len);
152 #if APR_HAVE_IPV6
153     if (sockaddr->family == AF_INET6 &&
154         IN6_IS_ADDR_V4MAPPED((struct in6_addr *)sockaddr->ipaddr_ptr)) {
155         /* This is an IPv4-mapped IPv6 address; drop the leading
156          * part of the address string so we're left with the familiar
157          * IPv4 format.
158          */
159         *addr += strlen("::ffff:");
160     }
161 #endif
162     return APR_SUCCESS;
163 }
164
165 void apr_sockaddr_vars_set(apr_sockaddr_t *addr, int family, apr_port_t port)
166 {
167     addr->family = family;
168     addr->sa.sin.sin_family = family;
169     if (port) {
170         /* XXX IPv6: assumes sin_port and sin6_port at same offset */
171         addr->sa.sin.sin_port = htons(port);
172         addr->port = port;
173     }
174
175     if (family == APR_INET) {
176         addr->salen = sizeof(struct sockaddr_in);
177         addr->addr_str_len = 16;
178         addr->ipaddr_ptr = &(addr->sa.sin.sin_addr);
179         addr->ipaddr_len = sizeof(struct in_addr);
180     }
181 #if APR_HAVE_IPV6
182     else if (family == APR_INET6) {
183         addr->salen = sizeof(struct sockaddr_in6);
184         addr->addr_str_len = 46;
185         addr->ipaddr_ptr = &(addr->sa.sin6.sin6_addr);
186         addr->ipaddr_len = sizeof(struct in6_addr);
187     }
188 #endif
189 }
190
191 APR_DECLARE(apr_status_t) apr_socket_addr_get(apr_sockaddr_t **sa,
192                                            apr_interface_e which,
193                                            apr_socket_t *sock)
194 {
195     if (which == APR_LOCAL) {
196         if (sock->local_interface_unknown || sock->local_port_unknown) {
197             apr_status_t rv = get_local_addr(sock);
198
199             if (rv != APR_SUCCESS) {
200                 return rv;
201             }
202         }
203         *sa = sock->local_addr;
204     }
205     else if (which == APR_REMOTE) {
206         if (sock->remote_addr_unknown) {
207             apr_status_t rv = get_remote_addr(sock);
208
209             if (rv != APR_SUCCESS) {
210                 return rv;
211             }
212         }
213         *sa = sock->remote_addr;
214     }
215     else {
216         *sa = NULL;
217         return APR_EINVAL;
218     }
219     return APR_SUCCESS;
220 }
221
222 APR_DECLARE(apr_status_t) apr_parse_addr_port(char **addr,
223                                               char **scope_id,
224                                               apr_port_t *port,
225                                               const char *str,
226                                               apr_pool_t *p)
227 {
228     const char *ch, *lastchar;
229     int big_port;
230     apr_size_t addrlen;
231
232     *addr = NULL;         /* assume not specified */
233     *scope_id = NULL;     /* assume not specified */
234     *port = 0;            /* assume not specified */
235
236     /* First handle the optional port number.  That may be all that
237      * is specified in the string.
238      */
239     ch = lastchar = str + strlen(str) - 1;
240     while (ch >= str && apr_isdigit(*ch)) {
241         --ch;
242     }
243
244     if (ch < str) {       /* Entire string is the port. */
245         big_port = atoi(str);
246         if (big_port < 1 || big_port > 65535) {
247             return APR_EINVAL;
248         }
249         *port = big_port;
250         return APR_SUCCESS;
251     }
252
253     if (*ch == ':' && ch < lastchar) { /* host and port number specified */
254         if (ch == str) {               /* string starts with ':' -- bad */
255             return APR_EINVAL;
256         }
257         big_port = atoi(ch + 1);
258         if (big_port < 1 || big_port > 65535) {
259             return APR_EINVAL;
260         }
261         *port = big_port;
262         lastchar = ch - 1;
263     }
264
265     /* now handle the hostname */
266     addrlen = lastchar - str + 1;
267
268 /* XXX we don't really have to require APR_HAVE_IPV6 for this; 
269  * just pass char[] for ipaddr (so we don't depend on struct in6_addr)
270  * and always define APR_INET6 
271  */
272 #if APR_HAVE_IPV6
273     if (*str == '[') {
274         const char *end_bracket = memchr(str, ']', addrlen);
275         struct in6_addr ipaddr;
276         const char *scope_delim;
277
278         if (!end_bracket || end_bracket != lastchar) {
279             *port = 0;
280             return APR_EINVAL;
281         }
282
283         /* handle scope id; this is the only context where it is allowed */
284         scope_delim = memchr(str, '%', addrlen);
285         if (scope_delim) {
286             if (scope_delim == end_bracket - 1) { /* '%' without scope id */
287                 *port = 0;
288                 return APR_EINVAL;
289             }
290             addrlen = scope_delim - str - 1;
291             *scope_id = apr_palloc(p, end_bracket - scope_delim);
292             memcpy(*scope_id, scope_delim + 1, end_bracket - scope_delim - 1);
293             (*scope_id)[end_bracket - scope_delim - 1] = '\0';
294         }
295         else {
296             addrlen = addrlen - 2; /* minus 2 for '[' and ']' */
297         }
298
299         *addr = apr_palloc(p, addrlen + 1);
300         memcpy(*addr,
301                str + 1,
302                addrlen);
303         (*addr)[addrlen] = '\0';
304         if (apr_inet_pton(AF_INET6, *addr, &ipaddr) != 1) {
305             *addr = NULL;
306             *scope_id = NULL;
307             *port = 0;
308             return APR_EINVAL;
309         }
310     }
311     else 
312 #endif
313     {
314         /* XXX If '%' is not a valid char in a DNS name, we *could* check 
315          *     for bogus scope ids first.
316          */
317         *addr = apr_palloc(p, addrlen + 1);
318         memcpy(*addr, str, addrlen);
319         (*addr)[addrlen] = '\0';
320     }
321     return APR_SUCCESS;
322 }
323
324 #if defined(HAVE_GETADDRINFO)
325
326 static apr_status_t call_resolver(apr_sockaddr_t **sa,
327                                   const char *hostname, apr_int32_t family,
328                                   apr_port_t port, apr_int32_t flags, 
329                                   apr_pool_t *p)
330 {
331     struct addrinfo hints, *ai, *ai_list;
332     apr_sockaddr_t *prev_sa;
333     int error;
334     char *servname = NULL; 
335
336     memset(&hints, 0, sizeof(hints));
337     hints.ai_family = family;
338     hints.ai_socktype = SOCK_STREAM;
339     if(hostname == NULL) {
340 #ifdef AI_PASSIVE 
341         /* If hostname is NULL, assume we are trying to bind to all
342          * interfaces. */
343         hints.ai_flags |= AI_PASSIVE;
344 #endif
345         /* getaddrinfo according to RFC 2553 must have either hostname
346          * or servname non-NULL.
347          */
348 #ifdef _AIX
349         /* But current AIX getaddrinfo() doesn't like servname = "0";
350          * the "1" won't hurt since we use the port parameter to fill
351          * in the returned socket addresses later
352          */
353         if (!port) {
354             servname = "1";
355         }
356         else
357 #endif
358         servname = apr_itoa(p, port);
359     }
360     error = getaddrinfo(hostname, servname, &hints, &ai_list);
361     if (error) {
362 #ifndef WIN32
363         if (error == EAI_SYSTEM) {
364             return errno;
365         }
366         else 
367 #endif
368         {
369             /* issues with representing this with APR's error scheme:
370              * glibc uses negative values for these numbers, perhaps so 
371              * they don't conflict with h_errno values...  Tru64 uses 
372              * positive values which conflict with h_errno values
373              */
374 #if defined(NEGATIVE_EAI)
375             error = -error;
376 #endif
377             return error + APR_OS_START_EAIERR;
378         }
379     }
380
381     prev_sa = NULL;
382     ai = ai_list;
383     while (ai) { /* while more addresses to report */
384         apr_sockaddr_t *new_sa;
385
386         /* Ignore anything bogus: getaddrinfo in some old versions of
387          * glibc will return AF_UNIX entries for AF_UNSPEC+AI_PASSIVE
388          * lookups. */
389         if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
390             ai = ai->ai_next;
391             continue;
392         }
393
394         new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t));
395
396         new_sa->pool = p;
397         memcpy(&new_sa->sa, ai->ai_addr, ai->ai_addrlen);
398         apr_sockaddr_vars_set(new_sa, ai->ai_family, port);
399
400         if (!prev_sa) { /* first element in new list */
401             if (hostname) {
402                 new_sa->hostname = apr_pstrdup(p, hostname);
403             }
404             *sa = new_sa;
405         }
406         else {
407             new_sa->hostname = prev_sa->hostname;
408             prev_sa->next = new_sa;
409         }
410
411         prev_sa = new_sa;
412         ai = ai->ai_next;
413     }
414     freeaddrinfo(ai_list);
415     return APR_SUCCESS;
416 }
417
418 static apr_status_t find_addresses(apr_sockaddr_t **sa, 
419                                    const char *hostname, apr_int32_t family,
420                                    apr_port_t port, apr_int32_t flags, 
421                                    apr_pool_t *p)
422 {
423     if (flags & APR_IPV4_ADDR_OK) {
424         apr_status_t error = call_resolver(sa, hostname, AF_INET, port, flags, p);
425
426 #if APR_HAVE_IPV6
427         if (error) {
428             family = AF_INET6; /* try again */
429         }
430         else
431 #endif
432         return error;
433     }
434 #if APR_HAVE_IPV6
435     else if (flags & APR_IPV6_ADDR_OK) {
436         apr_status_t error = call_resolver(sa, hostname, AF_INET6, port, flags, p);
437
438         if (error) {
439             family = AF_INET; /* try again */
440         }
441         else {
442             return APR_SUCCESS;
443         }
444     }
445 #endif
446
447     return call_resolver(sa, hostname, family, port, flags, p);
448 }
449
450 #else /* end of HAVE_GETADDRINFO code */
451
452 static apr_status_t find_addresses(apr_sockaddr_t **sa, 
453                                    const char *hostname, apr_int32_t family,
454                                    apr_port_t port, apr_int32_t flags, 
455                                    apr_pool_t *p)
456 {
457     struct hostent *hp;
458     apr_sockaddr_t *prev_sa;
459     int curaddr;
460 #if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \
461     defined(HAVE_GETHOSTBYNAME_R) && !defined(BEOS)
462 #ifdef GETHOSTBYNAME_R_HOSTENT_DATA
463     struct hostent_data hd;
464 #else
465     /* If you see ERANGE, that means GETHOSBYNAME_BUFLEN needs to be
466      * bumped. */
467     char tmp[GETHOSTBYNAME_BUFLEN];
468 #endif
469     int hosterror;
470 #endif
471     struct hostent hs;
472     struct in_addr ipaddr;
473     char *addr_list[2];
474     const char *orig_hostname = hostname;
475
476     if (hostname == NULL) {
477         /* if we are given a NULL hostname, assume '0.0.0.0' */
478         hostname = "0.0.0.0";
479     }
480
481     if (*hostname >= '0' && *hostname <= '9' &&
482         strspn(hostname, "0123456789.") == strlen(hostname)) {
483
484         ipaddr.s_addr = inet_addr(hostname);
485         addr_list[0] = (char *)&ipaddr;
486         addr_list[1] = NULL; /* just one IP in list */
487         hs.h_addr_list = (char **)addr_list;
488         hp = &hs;
489     }
490     else {
491 #if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \
492     defined(HAVE_GETHOSTBYNAME_R) && !defined(BEOS)
493 #if defined(GETHOSTBYNAME_R_HOSTENT_DATA)
494         /* AIX, HP/UX, D/UX et alia */
495         gethostbyname_r(hostname, &hs, &hd);
496         hp = &hs;
497 #else
498 #if defined(GETHOSTBYNAME_R_GLIBC2)
499         /* Linux glibc2+ */
500         gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, 
501                         &hp, &hosterror);
502 #else
503         /* Solaris, Irix et alia */
504         hp = gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1,
505                              &hosterror);
506 #endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */
507         if (!hp) {
508             return (hosterror + APR_OS_START_SYSERR);
509         }
510 #endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */
511 #else
512         hp = gethostbyname(hostname);
513 #endif
514
515         if (!hp) {
516 #ifdef WIN32
517             return apr_get_netos_error();
518 #else
519             return (h_errno + APR_OS_START_SYSERR);
520 #endif
521         }
522     }
523
524     prev_sa = NULL;
525     curaddr = 0;
526     while (hp->h_addr_list[curaddr]) {
527         apr_sockaddr_t *new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t));
528
529         new_sa->pool = p;
530         new_sa->sa.sin.sin_addr = *(struct in_addr *)hp->h_addr_list[curaddr];
531         apr_sockaddr_vars_set(new_sa, AF_INET, port);
532
533         if (!prev_sa) { /* first element in new list */
534             if (orig_hostname) {
535                 new_sa->hostname = apr_pstrdup(p, orig_hostname);
536             }
537             *sa = new_sa;
538         }
539         else {
540             new_sa->hostname = prev_sa->hostname;
541             prev_sa->next = new_sa;
542         }
543
544         prev_sa = new_sa;
545         ++curaddr;
546     }
547
548     return APR_SUCCESS;
549 }
550
551 #endif /* end of !HAVE_GETADDRINFO code */
552
553 APR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa,
554                                                 const char *hostname, 
555                                                 apr_int32_t family, apr_port_t port,
556                                                 apr_int32_t flags, apr_pool_t *p)
557 {
558     apr_int32_t masked;
559     *sa = NULL;
560
561     if ((masked = flags & (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK))) {
562         if (!hostname ||
563             family != AF_UNSPEC ||
564             masked == (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK)) {
565             return APR_EINVAL;
566         }
567 #if !APR_HAVE_IPV6
568         if (flags & APR_IPV6_ADDR_OK) {
569             return APR_ENOTIMPL;
570         }
571 #endif
572     }
573 #if !APR_HAVE_IPV6
574     /* What may happen is that APR is not IPv6-enabled, but we're still
575      * going to call getaddrinfo(), so we have to tell the OS we only
576      * want IPv4 addresses back since we won't know what to do with
577      * IPv6 addresses.
578      */
579     if (family == APR_UNSPEC) {
580         family = APR_INET;
581     }
582 #endif
583
584     return find_addresses(sa, hostname, family, port, flags, p);
585 }
586
587 APR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname,
588                                           apr_sockaddr_t *sockaddr,
589                                           apr_int32_t flags)
590 {
591 #if defined(HAVE_GETNAMEINFO)
592     int rc;
593 #if defined(NI_MAXHOST)
594     char tmphostname[NI_MAXHOST];
595 #else
596     char tmphostname[256];
597 #endif
598
599     /* don't know if it is portable for getnameinfo() to set h_errno;
600      * clear it then see if it was set */
601     SET_H_ERRNO(0);
602
603     /* default flags are NI_NAMREQD; otherwise, getnameinfo() will return
604      * a numeric address string if it fails to resolve the host name;
605      * that is *not* what we want here
606      *
607      * For IPv4-mapped IPv6 addresses, drop down to IPv4 before calling
608      * getnameinfo() to avoid getnameinfo bugs (MacOS X, glibc).
609      */
610 #if APR_HAVE_IPV6
611     if (sockaddr->family == AF_INET6 &&
612         IN6_IS_ADDR_V4MAPPED(&sockaddr->sa.sin6.sin6_addr)) {
613         struct sockaddr_in tmpsa;
614         tmpsa.sin_family = AF_INET;
615         tmpsa.sin_port = 0;
616         tmpsa.sin_addr.s_addr = ((apr_uint32_t *)sockaddr->ipaddr_ptr)[3];
617 #ifdef SIN6_LEN
618         tmpsa.sin_len = sizeof(tmpsa);
619 #endif
620
621         rc = getnameinfo((const struct sockaddr *)&tmpsa, sizeof(tmpsa),
622                          tmphostname, sizeof(tmphostname), NULL, 0,
623                          flags != 0 ? flags : NI_NAMEREQD);
624     }
625     else
626 #endif
627     rc = getnameinfo((const struct sockaddr *)&sockaddr->sa, sockaddr->salen,
628                      tmphostname, sizeof(tmphostname), NULL, 0,
629                      flags != 0 ? flags : NI_NAMEREQD);
630     if (rc != 0) {
631         *hostname = NULL;
632
633 #ifndef WIN32
634         /* something went wrong. Look at the EAI_ error code */
635         if (rc == EAI_SYSTEM) {
636             /* EAI_SYSTEM      System error returned in errno. */
637             /* IMHO, Implementations that set h_errno a simply broken. */
638             if (h_errno) { /* for broken implementations which set h_errno */
639                 return h_errno + APR_OS_START_SYSERR;
640             }
641             else { /* "normal" case */
642                 return errno + APR_OS_START_SYSERR;
643             }
644         }
645         else 
646 #endif
647         {
648 #if defined(NEGATIVE_EAI)
649             if (rc < 0) rc = -rc;
650 #endif
651             return rc + APR_OS_START_EAIERR; /* return the EAI_ error */
652         }
653     }
654     *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, 
655                                                  tmphostname);
656     return APR_SUCCESS;
657 #else
658 #if APR_HAS_THREADS && !defined(GETHOSTBYADDR_IS_THREAD_SAFE) && \
659     defined(HAVE_GETHOSTBYADDR_R) && !defined(BEOS)
660 #ifdef GETHOSTBYNAME_R_HOSTENT_DATA
661     struct hostent_data hd;
662 #else
663     char tmp[GETHOSTBYNAME_BUFLEN];
664 #endif
665     int hosterror;
666     struct hostent hs, *hptr;
667
668 #if defined(GETHOSTBYNAME_R_HOSTENT_DATA)
669     /* AIX, HP/UX, D/UX et alia */
670     gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, 
671                   sizeof(struct in_addr), AF_INET, &hs, &hd);
672     hptr = &hs;
673 #else
674 #if defined(GETHOSTBYNAME_R_GLIBC2)
675     /* Linux glibc2+ */
676     gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, 
677                     sizeof(struct in_addr), AF_INET,
678                     &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, &hptr, &hosterror);
679 #else
680     /* Solaris, Irix et alia */
681     hptr = gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, 
682                            sizeof(struct in_addr), AF_INET,
683                            &hs, tmp, GETHOSTBYNAME_BUFLEN, &hosterror);
684 #endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */
685     if (!hptr) {
686         *hostname = NULL;
687         return hosterror + APR_OS_START_SYSERR;
688     }
689 #endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */
690 #else
691     struct hostent *hptr;
692     hptr = gethostbyaddr((char *)&sockaddr->sa.sin.sin_addr, 
693                          sizeof(struct in_addr), AF_INET);
694 #endif
695
696     if (hptr) {
697         *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, hptr->h_name);
698         return APR_SUCCESS;
699     }
700     *hostname = NULL;
701 #if defined(WIN32)
702     return apr_get_netos_error();
703 #elif defined(OS2)
704     return h_errno;
705 #else
706     return h_errno + APR_OS_START_SYSERR;
707 #endif
708 #endif
709 }
710
711 APR_DECLARE(apr_status_t) apr_getservbyname(apr_sockaddr_t *sockaddr,
712                                             const char *servname)
713 {
714     struct servent *se;
715
716     if (servname == NULL)
717         return APR_EINVAL;
718
719     if ((se = getservbyname(servname, NULL)) != NULL){
720         sockaddr->port = htons(se->s_port);
721         sockaddr->servname = apr_pstrdup(sockaddr->pool, servname);
722         sockaddr->sa.sin.sin_port = se->s_port;
723         return APR_SUCCESS;
724     }
725     return APR_ENOENT;
726 }
727
728 #define V4MAPPED_EQUAL(a,b)                                   \
729 ((a)->sa.sin.sin_family == AF_INET &&                         \
730  (b)->sa.sin.sin_family == AF_INET6 &&                        \
731  IN6_IS_ADDR_V4MAPPED((struct in6_addr *)(b)->ipaddr_ptr) &&  \
732  !memcmp((a)->ipaddr_ptr,                                     \
733          &((struct in6_addr *)(b)->ipaddr_ptr)->s6_addr[12],  \
734          (a)->ipaddr_len))
735
736 APR_DECLARE(int) apr_sockaddr_equal(const apr_sockaddr_t *addr1,
737                                     const apr_sockaddr_t *addr2)
738 {
739     if (addr1->ipaddr_len == addr2->ipaddr_len &&
740         !memcmp(addr1->ipaddr_ptr, addr2->ipaddr_ptr, addr1->ipaddr_len)) {
741         return 1;
742     }
743 #if APR_HAVE_IPV6
744     if (V4MAPPED_EQUAL(addr1, addr2)) {
745         return 1;
746     }
747     if (V4MAPPED_EQUAL(addr2, addr1)) {
748         return 1;
749     }
750 #endif
751     return 0; /* not equal */
752 }
753
754 static apr_status_t parse_network(apr_ipsubnet_t *ipsub, const char *network)
755 {
756     /* legacy syntax for ip addrs: a.b.c. ==> a.b.c.0/24 for example */
757     int shift;
758     char *s, *t;
759     int octet;
760     char buf[sizeof "255.255.255.255"];
761
762     if (strlen(network) < sizeof buf) {
763         strcpy(buf, network);
764     }
765     else {
766         return APR_EBADIP;
767     }
768
769     /* parse components */
770     s = buf;
771     ipsub->sub[0] = 0;
772     ipsub->mask[0] = 0;
773     shift = 24;
774     while (*s) {
775         t = s;
776         if (!apr_isdigit(*t)) {
777             return APR_EBADIP;
778         }
779         while (apr_isdigit(*t)) {
780             ++t;
781         }
782         if (*t == '.') {
783             *t++ = 0;
784         }
785         else if (*t) {
786             return APR_EBADIP;
787         }
788         if (shift < 0) {
789             return APR_EBADIP;
790         }
791         octet = atoi(s);
792         if (octet < 0 || octet > 255) {
793             return APR_EBADIP;
794         }
795         ipsub->sub[0] |= octet << shift;
796         ipsub->mask[0] |= 0xFFUL << shift;
797         s = t;
798         shift -= 8;
799     }
800     ipsub->sub[0] = ntohl(ipsub->sub[0]);
801     ipsub->mask[0] = ntohl(ipsub->mask[0]);
802     ipsub->family = AF_INET;
803     return APR_SUCCESS;
804 }
805
806 /* return values:
807  * APR_EINVAL     not an IP address; caller should see if it is something else
808  * APR_BADIP      IP address portion is is not valid
809  * APR_BADMASK    mask portion is not valid
810  */
811
812 static apr_status_t parse_ip(apr_ipsubnet_t *ipsub, const char *ipstr, int network_allowed)
813 {
814     /* supported flavors of IP:
815      *
816      * . IPv6 numeric address string (e.g., "fe80::1")
817      * 
818      *   IMPORTANT: Don't store IPv4-mapped IPv6 address as an IPv6 address.
819      *
820      * . IPv4 numeric address string (e.g., "127.0.0.1")
821      *
822      * . IPv4 network string (e.g., "9.67")
823      *
824      *   IMPORTANT: This network form is only allowed if network_allowed is on.
825      */
826     int rc;
827
828 #if APR_HAVE_IPV6
829     rc = apr_inet_pton(AF_INET6, ipstr, ipsub->sub);
830     if (rc == 1) {
831         if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ipsub->sub)) {
832             /* apr_ipsubnet_test() assumes that we don't create IPv4-mapped IPv6
833              * addresses; this of course forces the user to specify IPv4 addresses
834              * in a.b.c.d style instead of ::ffff:a.b.c.d style.
835              */
836             return APR_EBADIP;
837         }
838         ipsub->family = AF_INET6;
839     }
840     else
841 #endif
842     {
843         rc = apr_inet_pton(AF_INET, ipstr, ipsub->sub);
844         if (rc == 1) {
845             ipsub->family = AF_INET;
846         }
847     }
848     if (rc != 1) {
849         if (network_allowed) {
850             return parse_network(ipsub, ipstr);
851         }
852         else {
853             return APR_EBADIP;
854         }
855     }
856     return APR_SUCCESS;
857 }
858
859 static int looks_like_ip(const char *ipstr)
860 {
861     if (strchr(ipstr, ':')) {
862         /* definitely not a hostname; assume it is intended to be an IPv6 address */
863         return 1;
864     }
865
866     /* simple IPv4 address string check */
867     while ((*ipstr == '.') || apr_isdigit(*ipstr))
868         ipstr++;
869     return (*ipstr == '\0');
870 }
871
872 static void fix_subnet(apr_ipsubnet_t *ipsub)
873 {
874     /* in case caller specified more bits in network address than are
875      * valid according to the mask, turn off the extra bits
876      */
877     int i;
878
879     for (i = 0; i < sizeof ipsub->mask / sizeof(apr_int32_t); i++) {
880         ipsub->sub[i] &= ipsub->mask[i];
881     }
882 }
883
884 /* be sure not to store any IPv4 address as a v4-mapped IPv6 address */
885 APR_DECLARE(apr_status_t) apr_ipsubnet_create(apr_ipsubnet_t **ipsub, const char *ipstr, 
886                                               const char *mask_or_numbits, apr_pool_t *p)
887 {
888     apr_status_t rv;
889     char *endptr;
890     long bits, maxbits = 32;
891
892     /* filter out stuff which doesn't look remotely like an IP address; this helps 
893      * callers like mod_access which have a syntax allowing hostname or IP address;
894      * APR_EINVAL tells the caller that it was probably not intended to be an IP
895      * address
896      */
897     if (!looks_like_ip(ipstr)) {
898         return APR_EINVAL;
899     }
900
901     *ipsub = apr_pcalloc(p, sizeof(apr_ipsubnet_t));
902
903     /* assume ipstr is an individual IP address, not a subnet */
904     memset((*ipsub)->mask, 0xFF, sizeof (*ipsub)->mask);
905
906     rv = parse_ip(*ipsub, ipstr, mask_or_numbits == NULL);
907     if (rv != APR_SUCCESS) {
908         return rv;
909     }
910
911     if (mask_or_numbits) {
912 #if APR_HAVE_IPV6
913         if ((*ipsub)->family == AF_INET6) {
914             maxbits = 128;
915         }
916 #endif
917         bits = strtol(mask_or_numbits, &endptr, 10);
918         if (*endptr == '\0' && bits > 0 && bits <= maxbits) {
919             /* valid num-bits string; fill in mask appropriately */
920             int cur_entry = 0;
921             apr_int32_t cur_bit_value;
922
923             memset((*ipsub)->mask, 0, sizeof (*ipsub)->mask);
924             while (bits > 32) {
925                 (*ipsub)->mask[cur_entry] = 0xFFFFFFFF; /* all 32 bits */
926                 bits -= 32;
927                 ++cur_entry;
928             }
929             cur_bit_value = 0x80000000;
930             while (bits) {
931                 (*ipsub)->mask[cur_entry] |= cur_bit_value;
932                 --bits;
933                 cur_bit_value /= 2;
934             }
935             (*ipsub)->mask[cur_entry] = htonl((*ipsub)->mask[cur_entry]);
936         }
937         else if (apr_inet_pton(AF_INET, mask_or_numbits, (*ipsub)->mask) == 1 &&
938             (*ipsub)->family == AF_INET) {
939             /* valid IPv4 netmask */
940         }
941         else {
942             return APR_EBADMASK;
943         }
944     }
945
946     fix_subnet(*ipsub);
947
948     return APR_SUCCESS;
949 }
950
951 APR_DECLARE(int) apr_ipsubnet_test(apr_ipsubnet_t *ipsub, apr_sockaddr_t *sa)
952 {
953 #if APR_HAVE_IPV6
954     /* XXX This line will segv on Win32 build with APR_HAVE_IPV6,
955      * but without the IPV6 drivers installed.
956      */
957     if (sa->sa.sin.sin_family == AF_INET) {
958         if (ipsub->family == AF_INET &&
959             ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0])) {
960             return 1;
961         }
962     }
963     else if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)sa->ipaddr_ptr)) {
964         if (ipsub->family == AF_INET &&
965             (((apr_uint32_t *)sa->ipaddr_ptr)[3] & ipsub->mask[0]) == ipsub->sub[0]) {
966             return 1;
967         }
968     }
969     else {
970         apr_uint32_t *addr = (apr_uint32_t *)sa->ipaddr_ptr;
971
972         if ((addr[0] & ipsub->mask[0]) == ipsub->sub[0] &&
973             (addr[1] & ipsub->mask[1]) == ipsub->sub[1] &&
974             (addr[2] & ipsub->mask[2]) == ipsub->sub[2] &&
975             (addr[3] & ipsub->mask[3]) == ipsub->sub[3]) {
976             return 1;
977         }
978     }
979 #else
980     if ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0]) {
981         return 1;
982     }
983 #endif /* APR_HAVE_IPV6 */
984     return 0; /* no match */
985 }