This is the mail archive of the mailing list for the glibc project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC: getifaddrs returns -1 with errno == 0, fix

postfix was misbehaving on my yeeloong (just upgraded to Parabola
GNU/Linux-blire) when I connected my freerunner to it.  It printed
âfatal: inet_addr_local[getifaddrs]: getifaddrs: Successâ and failed to
start daemons, to send messages, to print the mail queue, everything.
Without the freerunner, it worked just fine.

It turned out that getifaddrs() was indeed returning -1 without setting
errno, because the buffer allocated by __netlink_request wasn't large
enough to hold the response.  The received message was marked as
truncated, and we bailed out(_fail) without setting any errors.

Rather than just fail, I experimented with growing the buffer and
retrying.  I found out I had to consume the rest of the response to the
earlier request first, so I grew the buffer by just the right amount,
and that worked fine.

As an afterthought, I wondered if it would make more sense to just paste
the subsequent msgs into a larger buffer and be done with it, rather
than re-issuing the request.  I don't know enough about netlink to tell
whether that's guaranteed to get the correct answer.  Indeed, I'm not
even sure it's safe to consume the pending message fragments like I did.

Thoughts?  Comments?  Should I go with this, or grow the buffer
accummulating remaining fragments?

--- a/sysdeps/unix/sysv/linux/ifaddrs.c
+++ b/sysdeps/unix/sysv/linux/ifaddrs.c
@@ -135,13 +135,14 @@ __netlink_request (struct netlink_handle *h, int type)
 #ifdef PAGE_SIZE
   /* Help the compiler optimize out the malloc call if PAGE_SIZE
      is constant and smaller or equal to PTHREAD_STACK_MIN/4.  */
-  const size_t buf_size = PAGE_SIZE;
+  size_t buf_size = PAGE_SIZE;
-  const size_t buf_size = __getpagesize ();
+  size_t buf_size = __getpagesize ();
   bool use_malloc = false;
   char *buf;
+ retry:
   if (__libc_use_alloca (buf_size))
     buf = alloca (buf_size);
@@ -176,7 +177,23 @@ __netlink_request (struct netlink_handle *h, int type)
       if (__builtin_expect (msg.msg_flags & MSG_TRUNC, 0))
-	goto out_fail;
+	{
+	  /* Consume the rest of the truncated response, then retry
+	     with a larger buffer.  */
+	  do
+	    {
+	      read_len = TEMP_FAILURE_RETRY (__recvmsg (h->fd, &msg, 0));
+	      if (read_len < 0)
+		break;
+	      buf_size += read_len;
+	    }
+	  while ((msg.msg_flags & MSG_TRUNC) != 0);
+	  if (use_malloc)
+	    free (buf);
+	  goto retry;
+	}
       size_t count = 0;
       size_t remaining_len = read_len;

Alexandre Oliva, freedom fighter
You must be the change you wish to see in the world. -- Gandhi
Be Free! --   FSF Latin America board member
Free Software Evangelist      Red Hat Brazil Compiler Engineer

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]