back to topotato report
topotato coverage report
Current view: top level - lib - imsg-buffer.c (source / functions) Hit Total Coverage
Test: test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP Lines: 0 147 0.0 %
Date: 2023-11-16 17:19:14 Functions: 0 32 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: ISC
       2             : /*      $OpenBSD$       */
       3             : 
       4             : /*
       5             :  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
       6             :  */
       7             : 
       8             : #include <zebra.h>
       9             : 
      10             : #include "queue.h"
      11             : #include "imsg.h"
      12             : 
      13             : static int ibuf_realloc(struct ibuf *, size_t);
      14             : static void ibuf_enqueue(struct msgbuf *, struct ibuf *);
      15             : static void ibuf_dequeue(struct msgbuf *, struct ibuf *);
      16             : 
      17           0 : struct ibuf *ibuf_open(size_t len)
      18             : {
      19           0 :         struct ibuf *buf;
      20             : 
      21           0 :         if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
      22             :                 return NULL;
      23           0 :         if ((buf->buf = malloc(len)) == NULL) {
      24           0 :                 free(buf);
      25           0 :                 return NULL;
      26             :         }
      27           0 :         buf->size = buf->max = len;
      28           0 :         buf->fd = -1;
      29             : 
      30           0 :         return (buf);
      31             : }
      32             : 
      33           0 : struct ibuf *ibuf_dynamic(size_t len, size_t max)
      34             : {
      35           0 :         struct ibuf *buf;
      36             : 
      37           0 :         if (max < len)
      38             :                 return NULL;
      39             : 
      40           0 :         if ((buf = ibuf_open(len)) == NULL)
      41             :                 return NULL;
      42             : 
      43           0 :         if (max > 0)
      44           0 :                 buf->max = max;
      45             : 
      46             :         return (buf);
      47             : }
      48             : 
      49           0 : static int ibuf_realloc(struct ibuf *buf, size_t len)
      50             : {
      51           0 :         uint8_t *b;
      52             : 
      53             :         /* on static buffers max is eq size and so the following fails */
      54           0 :         if (buf->wpos + len > buf->max) {
      55           0 :                 errno = ERANGE;
      56           0 :                 return -1;
      57             :         }
      58             : 
      59           0 :         b = realloc(buf->buf, buf->wpos + len);
      60           0 :         if (b == NULL)
      61             :                 return -1;
      62           0 :         buf->buf = b;
      63           0 :         buf->size = buf->wpos + len;
      64             : 
      65           0 :         return 0;
      66             : }
      67             : 
      68           0 : int ibuf_add(struct ibuf *buf, const void *data, size_t len)
      69             : {
      70           0 :         if (buf->wpos + len > buf->size)
      71           0 :                 if (ibuf_realloc(buf, len) == -1)
      72             :                         return -1;
      73             : 
      74           0 :         memcpy(buf->buf + buf->wpos, data, len);
      75           0 :         buf->wpos += len;
      76           0 :         return 0;
      77             : }
      78             : 
      79           0 : void *ibuf_reserve(struct ibuf *buf, size_t len)
      80             : {
      81           0 :         void *b;
      82             : 
      83           0 :         if (buf->wpos + len > buf->size)
      84           0 :                 if (ibuf_realloc(buf, len) == -1)
      85             :                         return NULL;
      86             : 
      87           0 :         b = buf->buf + buf->wpos;
      88           0 :         buf->wpos += len;
      89           0 :         return (b);
      90             : }
      91             : 
      92           0 : void *ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
      93             : {
      94             :         /* only allowed to seek in already written parts */
      95           0 :         if (pos + len > buf->wpos)
      96             :                 return NULL;
      97             : 
      98           0 :         return (buf->buf + pos);
      99             : }
     100             : 
     101           0 : size_t ibuf_size(struct ibuf *buf)
     102             : {
     103           0 :         return (buf->wpos);
     104             : }
     105             : 
     106           0 : size_t ibuf_left(struct ibuf *buf)
     107             : {
     108           0 :         return (buf->max - buf->wpos);
     109             : }
     110             : 
     111           0 : void ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
     112             : {
     113           0 :         ibuf_enqueue(msgbuf, buf);
     114           0 : }
     115             : 
     116           0 : int ibuf_write(struct msgbuf *msgbuf)
     117             : {
     118           0 :         struct iovec iov[IOV_MAX];
     119           0 :         struct ibuf *buf;
     120           0 :         unsigned int i = 0;
     121           0 :         ssize_t n;
     122             : 
     123           0 :         memset(&iov, 0, sizeof(iov));
     124           0 :         TAILQ_FOREACH (buf, &msgbuf->bufs, entry) {
     125           0 :                 if (i >= IOV_MAX)
     126             :                         break;
     127           0 :                 iov[i].iov_base = buf->buf + buf->rpos;
     128           0 :                 iov[i].iov_len = buf->wpos - buf->rpos;
     129           0 :                 i++;
     130             :         }
     131             : 
     132           0 : again:
     133           0 :         if ((n = writev(msgbuf->fd, iov, i)) == -1) {
     134           0 :                 if (errno == EINTR)
     135           0 :                         goto again;
     136           0 :                 if (errno == ENOBUFS)
     137           0 :                         errno = EAGAIN;
     138           0 :                 return -1;
     139             :         }
     140             : 
     141           0 :         if (n == 0) { /* connection closed */
     142           0 :                 errno = 0;
     143           0 :                 return 0;
     144             :         }
     145             : 
     146           0 :         msgbuf_drain(msgbuf, n);
     147             : 
     148           0 :         return 1;
     149             : }
     150             : 
     151           0 : void ibuf_free(struct ibuf *buf)
     152             : {
     153           0 :         if (buf == NULL)
     154             :                 return;
     155           0 :         free(buf->buf);
     156           0 :         free(buf);
     157             : }
     158             : 
     159           0 : void msgbuf_init(struct msgbuf *msgbuf)
     160             : {
     161           0 :         msgbuf->queued = 0;
     162           0 :         msgbuf->fd = -1;
     163           0 :         TAILQ_INIT(&msgbuf->bufs);
     164           0 : }
     165             : 
     166           0 : void msgbuf_drain(struct msgbuf *msgbuf, size_t n)
     167             : {
     168           0 :         struct ibuf *buf, *next;
     169             : 
     170           0 :         for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
     171             :              buf = next) {
     172           0 :                 next = TAILQ_NEXT(buf, entry);
     173           0 :                 if (buf->rpos + n >= buf->wpos) {
     174           0 :                         n -= buf->wpos - buf->rpos;
     175             : 
     176           0 :                         TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
     177           0 :                         ibuf_dequeue(msgbuf, buf);
     178             :                 } else {
     179           0 :                         buf->rpos += n;
     180           0 :                         n = 0;
     181             :                 }
     182             :         }
     183           0 : }
     184             : 
     185           0 : void msgbuf_clear(struct msgbuf *msgbuf)
     186             : {
     187           0 :         struct ibuf *buf;
     188             : 
     189           0 :         while ((buf = TAILQ_POP_FIRST(&msgbuf->bufs, entry)) != NULL)
     190           0 :                 ibuf_dequeue(msgbuf, buf);
     191           0 : }
     192             : 
     193           0 : int msgbuf_write(struct msgbuf *msgbuf)
     194             : {
     195           0 :         struct iovec iov[IOV_MAX];
     196           0 :         struct ibuf *buf;
     197           0 :         unsigned int i = 0;
     198           0 :         ssize_t n;
     199           0 :         struct msghdr msg;
     200           0 :         struct cmsghdr *cmsg;
     201           0 :         union {
     202             :                 struct cmsghdr hdr;
     203             :                 char buf[CMSG_SPACE(sizeof(int))];
     204             :         } cmsgbuf;
     205             : 
     206           0 :         memset(&iov, 0, sizeof(iov));
     207           0 :         memset(&msg, 0, sizeof(msg));
     208           0 :         memset(&cmsgbuf, 0, sizeof(cmsgbuf));
     209           0 :         TAILQ_FOREACH (buf, &msgbuf->bufs, entry) {
     210           0 :                 if (i >= IOV_MAX)
     211             :                         break;
     212           0 :                 iov[i].iov_base = buf->buf + buf->rpos;
     213           0 :                 iov[i].iov_len = buf->wpos - buf->rpos;
     214           0 :                 i++;
     215           0 :                 if (buf->fd != -1)
     216             :                         break;
     217             :         }
     218             : 
     219           0 :         msg.msg_iov = iov;
     220           0 :         msg.msg_iovlen = i;
     221             : 
     222           0 :         if (buf != NULL && buf->fd != -1) {
     223           0 :                 msg.msg_control = (caddr_t)&cmsgbuf.buf;
     224           0 :                 msg.msg_controllen = sizeof(cmsgbuf.buf);
     225           0 :                 cmsg = CMSG_FIRSTHDR(&msg);
     226           0 :                 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
     227           0 :                 cmsg->cmsg_level = SOL_SOCKET;
     228           0 :                 cmsg->cmsg_type = SCM_RIGHTS;
     229           0 :                 memcpy(CMSG_DATA(cmsg), &buf->fd, sizeof(int));
     230             :         }
     231             : 
     232           0 : again:
     233           0 :         if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
     234           0 :                 if (errno == EINTR)
     235           0 :                         goto again;
     236           0 :                 if (errno == ENOBUFS)
     237           0 :                         errno = EAGAIN;
     238           0 :                 return -1;
     239             :         }
     240             : 
     241           0 :         if (n == 0) { /* connection closed */
     242           0 :                 errno = 0;
     243           0 :                 return 0;
     244             :         }
     245             : 
     246             :         /*
     247             :          * assumption: fd got sent if sendmsg sent anything
     248             :          * this works because fds are passed one at a time
     249             :          */
     250           0 :         if (buf != NULL && buf->fd != -1) {
     251           0 :                 close(buf->fd);
     252           0 :                 buf->fd = -1;
     253             :         }
     254             : 
     255           0 :         msgbuf_drain(msgbuf, n);
     256             : 
     257           0 :         return 1;
     258             : }
     259             : 
     260           0 : static void ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
     261             : {
     262           0 :         TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
     263           0 :         msgbuf->queued++;
     264             : }
     265             : 
     266           0 : static void ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
     267             : {
     268             :         /* TAILQ_REMOVE done by caller */
     269           0 :         if (buf->fd != -1)
     270           0 :                 close(buf->fd);
     271             : 
     272           0 :         msgbuf->queued--;
     273           0 :         ibuf_free(buf);
     274           0 : }

Generated by: LCOV version v1.16-topotato