Go back to previous page
Go back to home page
Last update:
01-Jun-2010
Author: R. Koucha
Is
inet_ntoa()
reentrant
?
Introduction
This paper focuses on the Linux GLIBC service inet_ntoa() which translates an
internet address into ASCII. This service is widely used in network
applications but it must be used with care...
Recap
The GLIBC service inet_ntoa()
function converts the Internet host address in given in network byte
order to a string in standard numbers-and-dots
notation. The prototype of this service is:
char
*inet_ntoa(struct in_addr in);
Limitation
The manual adds the following interesting information: "The string is returned in a statically
allocated buffer, which subsequent calls will overwrite".
This means that the following code is wrong:
char *p1, *p2;
p1 = inet_ntoa(ip1);
p2 = inet_ntoa(ip2);
because p1 points on the
statically allocated buffer into which is stored the translation of ip1 but the second call modifies
this buffer to put the translation of ip2.
So,
this
results
in
the
fact
that
both
p1
and p2 point on the
translation of ip2 (i.e. the
translation of ip1 is lost !).
So, a fix for the previous code consists to copy the result of the
service into a local buffer:
// XXX.XXX.XXX.XXX\0 = 1- bytes
char p1[16], p2[16];
strcpy(p1, inet_ntoa(ip1));
strcpy(p2, inet_ntoa(ip2));
In a mono-threaded process, the previous code works fine. But what
about the multi-threaded environment ? The manual does not give any
tips about it.
Multi-threaded environment
At first sight, the previous code snippet does not work in a
multi-threaded environment as a strcpy()
call is not atomic. While running the strcpy()
service, the running thread can be preempted by another thread running inet_ntoa(). So, the static buffer
of inet_ntoa() call may be
corrupted.
When we look at the source of inet_ntoa() in the GLIBC 2.9, we get the
following:
/* The interface of this function is completely stupid, it
requires a
static buffer. We relax this a bit in that we allow
one buffer for
each thread. */
static __thread
char buffer[18];
char *
inet_ntoa (struct in_addr in)
{
unsigned char *bytes = (unsigned char *) ∈
__snprintf (buffer, sizeof (buffer), "%d.%d.%d.%d",
bytes[0], bytes[1],
bytes[2], bytes[3]);
return buffer;
}
The directive __thread tells
the linker to allocate one buffer per thread (i.e. Thread Local
Storage) as explained here.
So,
this
proves
that
inet_ntoa()
is MT-safe.
Enhanced version of inet_ntoa()
Some operating systems like BSD or AIX offer a full reentrant and
MT-safe version of inet_ntoa().
But
this
is
not
available
under
the
GLIBC.
So,
here is an
implementation of this new function which would be called inet_ntoa_r():
int inet_ntoa_r(
struct
in_addr
in,
char
*s,
unsigned
int
slen
)
{
unsigned char *bytes = (unsigned
char *)&(in.s_addr);
if (slen < 16 || !s)
{
errno = EINVAL;
return
-1;
}
snprintf(s, slen,
"%u.%u.%u.%u", bytes[0], bytes[1], bytes[2],
bytes[3]);
return 0;
}
New standard service
Actually, inet_ntoa() is now
deprecated and should be replaced by the full reetrant and MT-safe inet_ntop() call:
const char *inet_ntop(int af,
const void *src, char *dst, socklen_t size);
This function converts the network address structure src in the af address family into a
character string. The resulting string is copied to the buffer pointed
to by dst, which must
be a non-NULL pointer. The caller specifies the number of bytes
available in this buffer in the argument size.
inet_ntop() extends the inet_ntoa() function to support
multiple address families. The following address families are
currently supported:
- AF_INET: src
points
to
a
struct in_addr
(in network byte order) which is converted to an IPv4 network address
in the dotted-decimal format, "ddd.ddd.ddd.ddd". The buffer dst must be at least INET_ADDRSTRLEN bytes long.
- AF_INET6: src
points to a struct in6_addr
(in network byte order) which is converted to a representation of this
address in the most appropriate IPv6 network address format for this
address. The buffer dst
must be at least INET6_ADDRSTRLEN
bytes long.
About the
author
The author is an engineer in computer sciences located in France. He
can be contacted here or
you can have
a look at his WEB
home page.