back to topotato report
topotato coverage report
Current view: top level - lib - imsg.c (source / functions) Hit Total Coverage
Test: test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP Lines: 0 160 0.0 %
Date: 2023-11-16 17:19:14 Functions: 0 26 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 "memory.h"
      11             : #include "queue.h"
      12             : #include "imsg.h"
      13             : 
      14             : static int imsg_fd_overhead = 0;
      15             : 
      16             : static int imsg_get_fd(struct imsgbuf *);
      17             : 
      18             : #ifndef __OpenBSD__
      19             : /*
      20             :  * The original code calls getdtablecount() which is OpenBSD specific. Use
      21             :  * available_fds() from OpenSMTPD instead.
      22             :  */
      23           0 : static int available_fds(unsigned int n)
      24             : {
      25           0 :         unsigned int i;
      26           0 :         int ret, fds[256];
      27             : 
      28           0 :         if (n > (unsigned int)array_size(fds))
      29             :                 return 1;
      30             : 
      31           0 :         ret = 0;
      32           0 :         for (i = 0; i < n; i++) {
      33           0 :                 fds[i] = -1;
      34           0 :                 if ((fds[i] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
      35           0 :                         if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT)
      36           0 :                                 fds[i] = socket(AF_INET6, SOCK_DGRAM, 0);
      37           0 :                         if (fds[i] < 0) {
      38             :                                 ret = 1;
      39             :                                 break;
      40             :                         }
      41             :                 }
      42             :         }
      43             : 
      44           0 :         for (i = 0; i < n && fds[i] >= 0; i++)
      45           0 :                 close(fds[i]);
      46             : 
      47             :         return (ret);
      48             : }
      49             : #endif
      50             : 
      51           0 : void imsg_init(struct imsgbuf *ibuf, int fd)
      52             : {
      53           0 :         msgbuf_init(&ibuf->w);
      54           0 :         memset(&ibuf->r, 0, sizeof(ibuf->r));
      55           0 :         ibuf->fd = fd;
      56           0 :         ibuf->w.fd = fd;
      57           0 :         ibuf->pid = getpid();
      58           0 :         TAILQ_INIT(&ibuf->fds);
      59           0 : }
      60             : 
      61           0 : ssize_t imsg_read(struct imsgbuf *ibuf)
      62             : {
      63           0 :         struct msghdr msg;
      64           0 :         struct cmsghdr *cmsg;
      65           0 :         union {
      66             :                 struct cmsghdr hdr;
      67             :                 char buf[CMSG_SPACE(sizeof(int) * 1)];
      68             :         } cmsgbuf;
      69           0 :         struct iovec iov;
      70           0 :         ssize_t n;
      71           0 :         int fd;
      72           0 :         struct imsg_fd *ifd;
      73             : 
      74           0 :         memset(&msg, 0, sizeof(msg));
      75           0 :         memset(&cmsgbuf, 0, sizeof(cmsgbuf));
      76             : 
      77           0 :         iov.iov_base = ibuf->r.buf + ibuf->r.wpos;
      78           0 :         iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos;
      79           0 :         msg.msg_iov = &iov;
      80           0 :         msg.msg_iovlen = 1;
      81           0 :         msg.msg_control = &cmsgbuf.buf;
      82           0 :         msg.msg_controllen = sizeof(cmsgbuf.buf);
      83             : 
      84           0 :         if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL)
      85             :                 return -1;
      86             : 
      87           0 : again:
      88             : #ifdef __OpenBSD__
      89             :         if (getdtablecount() + imsg_fd_overhead
      90             :                     + (int)((CMSG_SPACE(sizeof(int)) - CMSG_SPACE(0))
      91             :                             / sizeof(int))
      92             :             >= getdtablesize()) {
      93             : #else
      94           0 :         if (available_fds(imsg_fd_overhead
      95             :                           + (CMSG_SPACE(sizeof(int)) - CMSG_SPACE(0))
      96             :                                     / sizeof(int))) {
      97             : #endif
      98           0 :                 errno = EAGAIN;
      99           0 :                 free(ifd);
     100           0 :                 return -1;
     101             :         }
     102             : 
     103           0 :         n = recvmsg(ibuf->fd, &msg, 0);
     104           0 :         if (n == -1) {
     105           0 :                 if (errno == EINTR)
     106           0 :                         goto again;
     107           0 :                 goto fail;
     108             :         }
     109             : 
     110           0 :         ibuf->r.wpos += n;
     111             : 
     112           0 :         for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
     113           0 :              cmsg = CMSG_NXTHDR(&msg, cmsg)) {
     114           0 :                 if (cmsg->cmsg_level == SOL_SOCKET
     115           0 :                     && cmsg->cmsg_type == SCM_RIGHTS) {
     116           0 :                         int i;
     117           0 :                         int j;
     118             : 
     119             :                         /*
     120             :                          * We only accept one file descriptor.  Due to C
     121             :                          * padding rules, our control buffer might contain
     122             :                          * more than one fd, and we must close them.
     123             :                          */
     124           0 :                         j = ((char *)cmsg + cmsg->cmsg_len
     125           0 :                              - (char *)CMSG_DATA(cmsg))
     126           0 :                             / sizeof(int);
     127           0 :                         for (i = 0; i < j; i++) {
     128           0 :                                 fd = ((int *)CMSG_DATA(cmsg))[i];
     129           0 :                                 if (ifd != NULL) {
     130           0 :                                         ifd->fd = fd;
     131           0 :                                         TAILQ_INSERT_TAIL(&ibuf->fds, ifd,
     132             :                                                           entry);
     133           0 :                                         ifd = NULL;
     134             :                                 } else
     135           0 :                                         close(fd);
     136             :                         }
     137             :                 }
     138             :                 /* we do not handle other ctl data level */
     139             :         }
     140             : 
     141           0 : fail:
     142           0 :         free(ifd);
     143           0 :         return (n);
     144             : }
     145             : 
     146           0 : ssize_t imsg_get(struct imsgbuf *ibuf, struct imsg *imsg)
     147             : {
     148           0 :         size_t av, left, datalen;
     149             : 
     150           0 :         av = ibuf->r.wpos;
     151             : 
     152           0 :         if (IMSG_HEADER_SIZE > av)
     153             :                 return 0;
     154             : 
     155           0 :         memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr));
     156           0 :         if (imsg->hdr.len < IMSG_HEADER_SIZE || imsg->hdr.len > MAX_IMSGSIZE) {
     157           0 :                 errno = ERANGE;
     158           0 :                 return -1;
     159             :         }
     160           0 :         if (imsg->hdr.len > av)
     161             :                 return 0;
     162           0 :         datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
     163           0 :         ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE;
     164           0 :         if (datalen == 0)
     165           0 :                 imsg->data = NULL;
     166           0 :         else if ((imsg->data = malloc(datalen)) == NULL)
     167             :                 return -1;
     168             : 
     169           0 :         if (imsg->hdr.flags & IMSGF_HASFD)
     170           0 :                 imsg->fd = imsg_get_fd(ibuf);
     171             :         else
     172           0 :                 imsg->fd = -1;
     173             : 
     174           0 :         if (imsg->data)
     175           0 :                 memcpy(imsg->data, ibuf->r.rptr, datalen);
     176             : 
     177           0 :         if (imsg->hdr.len < av) {
     178           0 :                 left = av - imsg->hdr.len;
     179           0 :                 memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left);
     180           0 :                 ibuf->r.wpos = left;
     181             :         } else
     182           0 :                 ibuf->r.wpos = 0;
     183             : 
     184           0 :         return (datalen + IMSG_HEADER_SIZE);
     185             : }
     186             : 
     187           0 : int imsg_compose(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid,
     188             :                  pid_t pid, int fd, const void *data, uint16_t datalen)
     189             : {
     190           0 :         struct ibuf *wbuf;
     191             : 
     192           0 :         if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
     193             :                 return -1;
     194             : 
     195           0 :         if (imsg_add(wbuf, data, datalen) == -1)
     196             :                 return -1;
     197             : 
     198           0 :         wbuf->fd = fd;
     199             : 
     200           0 :         imsg_close(ibuf, wbuf);
     201             : 
     202           0 :         return 1;
     203             : }
     204             : 
     205           0 : int imsg_composev(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid,
     206             :                   pid_t pid, int fd, const struct iovec *iov, int iovcnt)
     207             : {
     208           0 :         struct ibuf *wbuf;
     209           0 :         int i, datalen = 0;
     210             : 
     211           0 :         for (i = 0; i < iovcnt; i++)
     212           0 :                 datalen += iov[i].iov_len;
     213             : 
     214           0 :         if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
     215             :                 return -1;
     216             : 
     217           0 :         for (i = 0; i < iovcnt; i++)
     218           0 :                 if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
     219             :                         return -1;
     220             : 
     221           0 :         wbuf->fd = fd;
     222             : 
     223           0 :         imsg_close(ibuf, wbuf);
     224             : 
     225           0 :         return 1;
     226             : }
     227             : 
     228             : /* ARGSUSED */
     229           0 : struct ibuf *imsg_create(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid,
     230             :                          pid_t pid, uint16_t datalen)
     231             : {
     232           0 :         struct ibuf *wbuf;
     233           0 :         struct imsg_hdr hdr;
     234             : 
     235           0 :         memset(&hdr, 0x00, IMSG_HEADER_SIZE);
     236             : 
     237           0 :         datalen += IMSG_HEADER_SIZE;
     238           0 :         if (datalen > MAX_IMSGSIZE) {
     239           0 :                 errno = ERANGE;
     240           0 :                 return NULL;
     241             :         }
     242             : 
     243           0 :         hdr.type = type;
     244           0 :         hdr.flags = 0;
     245           0 :         hdr.peerid = peerid;
     246           0 :         if ((hdr.pid = pid) == 0)
     247           0 :                 hdr.pid = ibuf->pid;
     248           0 :         if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
     249             :                 return NULL;
     250             :         }
     251           0 :         if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
     252             :                 return NULL;
     253             : 
     254             :         return (wbuf);
     255             : }
     256             : 
     257           0 : int imsg_add(struct ibuf *msg, const void *data, uint16_t datalen)
     258             : {
     259           0 :         if (datalen)
     260           0 :                 if (ibuf_add(msg, data, datalen) == -1) {
     261           0 :                         ibuf_free(msg);
     262           0 :                         return -1;
     263             :                 }
     264           0 :         return (datalen);
     265             : }
     266             : 
     267           0 : void imsg_close(struct imsgbuf *ibuf, struct ibuf *msg)
     268             : {
     269           0 :         struct imsg_hdr *hdr;
     270             : 
     271           0 :         hdr = (struct imsg_hdr *)msg->buf;
     272             : 
     273           0 :         hdr->flags &= ~IMSGF_HASFD;
     274           0 :         if (msg->fd != -1)
     275           0 :                 hdr->flags |= IMSGF_HASFD;
     276             : 
     277           0 :         hdr->len = (uint16_t)msg->wpos;
     278             : 
     279           0 :         ibuf_close(&ibuf->w, msg);
     280           0 : }
     281             : 
     282           0 : void imsg_free(struct imsg *imsg)
     283             : {
     284           0 :         free(imsg->data);
     285           0 : }
     286             : 
     287           0 : int imsg_get_fd(struct imsgbuf *ibuf)
     288             : {
     289           0 :         int fd;
     290           0 :         struct imsg_fd *ifd;
     291             : 
     292           0 :         if ((ifd = TAILQ_POP_FIRST(&ibuf->fds, entry)) == NULL)
     293             :                 return -1;
     294             : 
     295           0 :         fd = ifd->fd;
     296           0 :         free(ifd);
     297             : 
     298           0 :         return (fd);
     299             : }
     300             : 
     301           0 : int imsg_flush(struct imsgbuf *ibuf)
     302             : {
     303           0 :         while (ibuf->w.queued)
     304           0 :                 if (msgbuf_write(&ibuf->w) <= 0)
     305             :                         return -1;
     306             :         return 0;
     307             : }
     308             : 
     309           0 : void imsg_clear(struct imsgbuf *ibuf)
     310             : {
     311           0 :         int fd;
     312             : 
     313           0 :         msgbuf_clear(&ibuf->w);
     314           0 :         while ((fd = imsg_get_fd(ibuf)) != -1)
     315           0 :                 close(fd);
     316           0 : }

Generated by: LCOV version v1.16-topotato