]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Use a dynamically sized buffer for reading route(4) messages on BSD
authorRoy Marples <roy@marples.name>
Thu, 1 Sep 2016 14:37:48 +0000 (14:37 +0000)
committerRoy Marples <roy@marples.name>
Thu, 1 Sep 2016 14:37:48 +0000 (14:37 +0000)
instead of a fixed 2048 byte buffer.

common.c
common.h
dhcpcd.c
dhcpcd.h
if-bsd.c

index 8c6060c6b32b98352a825dcb3ff3bccb56293b77..98d196b0bb3784048c94d660e3d4f65ff28673cc 100644 (file)
--- a/common.c
+++ b/common.c
@@ -53,6 +53,9 @@
 #  define _PATH_DEVNULL "/dev/null"
 #endif
 
+/* Most route(4) messages are less than 256 bytes. */
+#define IOVEC_BUFSIZ   256
+
 #if USE_LOGFILE
 void
 logger_open(struct dhcpcd_ctx *ctx)
@@ -374,3 +377,53 @@ read_hwaddr_aton(uint8_t **data, const char *path)
        fclose(fp);
        return len;
 }
+
+static void *
+iovec_realloc(struct iovec *iov, size_t size)
+{
+
+       if (iov->iov_len < size) {
+               void *n;
+
+               if ((n = realloc(iov->iov_base, size)) == NULL)
+                       return NULL;
+               iov->iov_base = n;
+               iov->iov_len = size;
+       }
+       return iov->iov_base;
+}
+
+ssize_t
+recvmsg_alloc(int fd, struct msghdr *msg)
+{
+       ssize_t bytes;
+
+       if (msg->msg_iovlen == 0)
+               msg->msg_iovlen = 1;
+
+       for (;;) {
+               msg->msg_flags = 0;
+               if ((bytes = recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC)) == -1)
+                       return -1;
+               if (!(msg->msg_flags & MSG_TRUNC))
+                       break;
+
+               /* Some buggy kernels return the truncated size. */
+               if (msg->msg_iov->iov_len == (size_t)bytes) {
+                       size_t nl;
+
+                       nl = (size_t)roundup(bytes + 1, IOVEC_BUFSIZ);
+                       if (iovec_realloc(msg->msg_iov, nl) == NULL)
+                               return -1;
+               } else {
+                       if (iovec_realloc(msg->msg_iov, (size_t)bytes) == NULL)
+                               return -1;
+                       break;
+               }
+
+               printf ("NEW SIZE %zu", msg->msg_iov->iov_len);
+       }
+
+       bytes = recvmsg(fd, msg, 0);
+       return msg->msg_flags & MSG_TRUNC ? -1 : bytes;
+}
index 822db2d2d4694a4cf06a986155329a0777e5b339..38924bc3bc40d34d3f7119c3cd7477a1f213d123 100644 (file)
--- a/common.h
+++ b/common.h
@@ -196,4 +196,6 @@ ssize_t addvard(struct dhcpcd_ctx *,
 char *hwaddr_ntoa(const uint8_t *, size_t, char *, size_t);
 size_t hwaddr_aton(uint8_t *, const char *);
 size_t read_hwaddr_aton(uint8_t **, const char *);
+
+ssize_t recvmsg_alloc(int fd, struct msghdr *msg);
 #endif
index 7535c816c394252f04a27d00e1321ab7008c001c..a33e67f6b30cd1bdf826bdb0466c09da674032c7 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -1970,6 +1970,7 @@ exit1:
        if (control_stop(&ctx) == -1)
                logger(&ctx, LOG_ERR, "control_stop: %m:");
        eloop_free(ctx.eloop);
+       free(ctx.iov.iov_base);
 
        if (ctx.options & DHCPCD_STARTED && !(ctx.options & DHCPCD_FORKED))
                logger(&ctx, LOG_INFO, PACKAGE " exited");
index fdb1c6d0b9aab8165775320f548dadc10f1462ef..7d8244f79cfcb6a7df7322c5ffc293ff14b3bee7 100644 (file)
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -121,6 +121,7 @@ struct dhcpcd_ctx {
        int link_fd;
        int seq;        /* route message sequence no */
        int sseq;       /* successful seq no sent */
+       struct iovec iov;       /* generic iovec buffer */
 
 #ifdef USE_SIGNALS
        sigset_t sigset;
index 2ba2c61ddd5663ab89bf707844d72238aac4c1b3..fbcb517260c2b48fca7efa7e1fa70fcfae3756e2 100644 (file)
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -1516,21 +1516,15 @@ if_dispatch(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
 int
 if_handlelink(struct dhcpcd_ctx *ctx)
 {
-       /* route and ifwatchd like a msg buf size of 2048 */
-       char buf[2048];
-       const char *p, *e;
-       size_t msglen;
+       struct msghdr msg;
        ssize_t bytes;
-       const struct rt_msghdr *rtm;
 
-       if ((bytes = read(ctx->link_fd, buf, sizeof(buf))) == -1)
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_iov = &ctx->iov;
+
+       if ((bytes = recvmsg_alloc(ctx->link_fd, &msg)) == -1)
                return -1;
-       e = buf + bytes;
-       for (p = buf; p < e; p += msglen) {
-               rtm = (const void *)p;
-               msglen = rtm->rtm_msglen;
-               if_dispatch(ctx, rtm);
-       }
+       if_dispatch(ctx, ctx->iov.iov_base);
        return 0;
 }