autoconf
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: inet_addr? inet_aton?


From: Russ Allbery
Subject: Re: inet_addr? inet_aton?
Date: Thu, 08 Aug 2002 14:13:52 -0700
User-agent: Gnus/5.090005 (Oort Gnus v0.05) XEmacs/21.4 (Honest Recruiter, sparc-sun-solaris2.6)

Austin Schutz <address@hidden> writes:

> My local system is Linux, which has:

> int inet_aton(const char *cp, struct in_addr *inp);)

>       but I would like it to be able to run on other systems, such as
> Solaris, which doesn't have inet_aton, but has:

> in_addr_t inet_addr(const char *cp);

Solaris does have inet_aton; it's just not documented.

dnl Check for inet_aton.  We have our own, but on Solaris the version in
dnl libresolv is more lenient in ways that Solaris's internal DNS resolution
dnl code requires, so if we use our own *and* link with libresolv (which may
dnl be forced by Perl) DNS resolution fails.
AC_SEARCH_LIBS(inet_aton, resolv)

> now, I've read various docs and I understand now, or at least will be
> able to figure out, how to use autoconf to detect which is available,
> then write #ifdefs, and pray that the user isn't on some platform which
> has different semantics for e.g. inet_addr() (or doesn't have it at
> all!) on their platform than are described in my system's man page.

What you want to do is use something like:

AC_REPLACE_FUNCS(inet_aton)

in configure.in and then put @LIBOBJS@ in the appropriate place in your
Makefile.in (see the autoconf manual) and use your own replacement
inet_aton.

Feel free to use the following if you wish; it's in the public domain.

/*  $Id: inet_aton.c,v 1.5 2001/12/12 09:06:00 rra Exp $
**
**  Replacement for a missing inet_aton.
**
**  Written by Russ Allbery <address@hidden>
**  This work is hereby placed in the public domain by its author.
**
**  Provides the same functionality as the standard library routine
**  inet_aton for those platforms that don't have it.  inet_aton is
**  thread-safe.
*/

#include "config.h"
#include "clibrary.h"
#include <netinet/in.h>

/* If we're running the test suite, rename inet_ntoa to avoid conflicts with
   the system version. */
#if TESTING
# define inet_aton test_inet_aton
int test_inet_aton(const char *, struct in_addr *);
#endif

int
inet_aton(const char *s, struct in_addr *addr)
{
    unsigned long octet[4], address;
    const char *p;
    int base, i;
    int part = 0;

    if (s == NULL) return 0;

    /* Step through each period-separated part of the address.  If we see
       more than four parts, the address is invalid. */
    for (p = s; *p != 0; part++) {
        if (part > 3) return 0;

        /* Determine the base of the section we're looking at.  Numbers are
           represented the same as in C; octal starts with 0, hex starts
           with 0x, and anything else is decimal. */
        if (*p == '0') {
            p++;
            if (*p == 'x') {
                p++;
                base = 16;
            } else {
                base = 8;
            }
        } else {
            base = 10;
        }

        /* Make sure there's actually a number.  (A section of just "0"
           would set base to 8 and leave us pointing at a period; allow
           that.) */
        if (*p == '.' && base != 8) return 0;
        octet[part] = 0;

        /* Now, parse this segment of the address.  For each digit, multiply
           the result so far by the base and then add the value of the
           digit.  Be careful of arithmetic overflow in cases where an
           unsigned long is 32 bits; we need to detect it *before* we
           multiply by the base since otherwise we could overflow and wrap
           and then not detect the error. */
        for (; *p != 0 && *p != '.'; p++) {
            if (octet[part] > 0xffffffffUL / base) return 0;

            /* Use a switch statement to parse each digit rather than
               assuming ASCII.  Probably pointless portability.... */
            switch (*p) {
                case '0':           i = 0;  break;
                case '1':           i = 1;  break;
                case '2':           i = 2;  break;
                case '3':           i = 3;  break;
                case '4':           i = 4;  break;
                case '5':           i = 5;  break;
                case '6':           i = 6;  break;
                case '7':           i = 7;  break;
                case '8':           i = 8;  break;
                case '9':           i = 9;  break;
                case 'A': case 'a': i = 10; break;
                case 'B': case 'b': i = 11; break;
                case 'C': case 'c': i = 12; break;
                case 'D': case 'd': i = 13; break;
                case 'E': case 'e': i = 14; break;
                case 'F': case 'f': i = 15; break;
                default:            return 0;
            }
            if (i >= base) return 0;
            octet[part] = (octet[part] * base) + i;
        }

        /* Advance over periods; the top of the loop will increment the
           count of parts we've seen.  We need a check here to detect an
           illegal trailing period. */
        if (*p == '.') {
            p++;
            if (*p == 0) return 0;
        }
    }
    if (part == 0) return 0;

    /* IPv4 allows three types of address specification:

           a.b
           a.b.c
           a.b.c.d

       If there are fewer than four segments, the final segment accounts for
       all of the remaining portion of the address.  For example, in the a.b
       form, b is the final 24 bits of the address.  We also allow a simple
       number, which is interpreted as the 32-bit number corresponding to
       the full IPv4 address.

       The first for loop below ensures that any initial segments represent
       only 8 bits of the address and builds the upper portion of the IPv4
       address.  Then, the remaining segment is checked to make sure it's no
       bigger than the remaining space in the address and then is added into
       the result. */
    address = 0;
    for (i = 0; i < part - 1; i++) {
        if (octet[i] > 0xff) return 0;
        address |= octet[i] << (8 * (3 - i));
    }
    if (octet[i] > (0xffffffffUL >> (i * 8))) return 0;
    address |= octet[i];
    if (addr != NULL) addr->s_addr = htonl(address);
    return 1;
}


-- 
Russ Allbery (address@hidden)             <http://www.eyrie.org/~eagle/>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]