back to topotato report
topotato coverage report
Current view: top level - lib - imsg.c (source / functions) Hit Total Coverage
Test: test_ospf_topo1.py::OSPFTopo1Test Lines: 0 160 0.0 %
Date: 2023-02-24 18:38:32 Functions: 0 13 0.0 %

          Line data    Source code
       1             : /*      $OpenBSD$       */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : #include <zebra.h>
      20             : 
      21             : #include "memory.h"
      22             : #include "queue.h"
      23             : #include "imsg.h"
      24             : 
      25             : static int imsg_fd_overhead = 0;
      26             : 
      27             : static int imsg_get_fd(struct imsgbuf *);
      28             : 
      29             : #ifndef __OpenBSD__
      30             : /*
      31             :  * The original code calls getdtablecount() which is OpenBSD specific. Use
      32             :  * available_fds() from OpenSMTPD instead.
      33             :  */
      34           0 : static int available_fds(unsigned int n)
      35             : {
      36           0 :         unsigned int i;
      37           0 :         int ret, fds[256];
      38             : 
      39           0 :         if (n > (unsigned int)array_size(fds))
      40             :                 return 1;
      41             : 
      42           0 :         ret = 0;
      43           0 :         for (i = 0; i < n; i++) {
      44           0 :                 fds[i] = -1;
      45           0 :                 if ((fds[i] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
      46           0 :                         if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT)
      47           0 :                                 fds[i] = socket(AF_INET6, SOCK_DGRAM, 0);
      48           0 :                         if (fds[i] < 0) {
      49             :                                 ret = 1;
      50             :                                 break;
      51             :                         }
      52             :                 }
      53             :         }
      54             : 
      55           0 :         for (i = 0; i < n && fds[i] >= 0; i++)
      56           0 :                 close(fds[i]);
      57             : 
      58             :         return (ret);
      59             : }
      60             : #endif
      61             : 
      62           0 : void imsg_init(struct imsgbuf *ibuf, int fd)
      63             : {
      64           0 :         msgbuf_init(&ibuf->w);
      65           0 :         memset(&ibuf->r, 0, sizeof(ibuf->r));
      66           0 :         ibuf->fd = fd;
      67           0 :         ibuf->w.fd = fd;
      68           0 :         ibuf->pid = getpid();
      69           0 :         TAILQ_INIT(&ibuf->fds);
      70           0 : }
      71             : 
      72           0 : ssize_t imsg_read(struct imsgbuf *ibuf)
      73             : {
      74           0 :         struct msghdr msg;
      75           0 :         struct cmsghdr *cmsg;
      76           0 :         union {
      77             :                 struct cmsghdr hdr;
      78             :                 char buf[CMSG_SPACE(sizeof(int) * 1)];
      79             :         } cmsgbuf;
      80           0 :         struct iovec iov;
      81           0 :         ssize_t n;
      82           0 :         int fd;
      83           0 :         struct imsg_fd *ifd;
      84             : 
      85           0 :         memset(&msg, 0, sizeof(msg));
      86           0 :         memset(&cmsgbuf, 0, sizeof(cmsgbuf));
      87             : 
      88           0 :         iov.iov_base = ibuf->r.buf + ibuf->r.wpos;
      89           0 :         iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos;
      90           0 :         msg.msg_iov = &iov;
      91           0 :         msg.msg_iovlen = 1;
      92           0 :         msg.msg_control = &cmsgbuf.buf;
      93           0 :         msg.msg_controllen = sizeof(cmsgbuf.buf);
      94             : 
      95           0 :         if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL)
      96             :                 return -1;
      97             : 
      98           0 : again:
      99             : #ifdef __OpenBSD__
     100             :         if (getdtablecount() + imsg_fd_overhead
     101             :                     + (int)((CMSG_SPACE(sizeof(int)) - CMSG_SPACE(0))
     102             :                             / sizeof(int))
     103             :             >= getdtablesize()) {
     104             : #else
     105           0 :         if (available_fds(imsg_fd_overhead
     106             :                           + (CMSG_SPACE(sizeof(int)) - CMSG_SPACE(0))
     107             :                                     / sizeof(int))) {
     108             : #endif
     109           0 :                 errno = EAGAIN;
     110           0 :                 free(ifd);
     111           0 :                 return -1;
     112             :         }
     113             : 
     114           0 :         n = recvmsg(ibuf->fd, &msg, 0);
     115           0 :         if (n == -1) {
     116           0 :                 if (errno == EINTR)
     117           0 :                         goto again;
     118           0 :                 goto fail;
     119             :         }
     120             : 
     121           0 :         ibuf->r.wpos += n;
     122             : 
     123           0 :         for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
     124           0 :              cmsg = CMSG_NXTHDR(&msg, cmsg)) {
     125           0 :                 if (cmsg->cmsg_level == SOL_SOCKET
     126           0 :                     && cmsg->cmsg_type == SCM_RIGHTS) {
     127           0 :                         int i;
     128           0 :                         int j;
     129             : 
     130             :                         /*
     131             :                          * We only accept one file descriptor.  Due to C
     132             :                          * padding rules, our control buffer might contain
     133             :                          * more than one fd, and we must close them.
     134             :                          */
     135           0 :                         j = ((char *)cmsg + cmsg->cmsg_len
     136           0 :                              - (char *)CMSG_DATA(cmsg))
     137           0 :                             / sizeof(int);
     138           0 :                         for (i = 0; i < j; i++) {
     139           0 :                                 fd = ((int *)CMSG_DATA(cmsg))[i];
     140           0 :                                 if (ifd != NULL) {
     141           0 :                                         ifd->fd = fd;
     142           0 :                                         TAILQ_INSERT_TAIL(&ibuf->fds, ifd,
     143             :                                                           entry);
     144           0 :                                         ifd = NULL;
     145             :                                 } else
     146           0 :                                         close(fd);
     147             :                         }
     148             :                 }
     149             :                 /* we do not handle other ctl data level */
     150             :         }
     151             : 
     152           0 : fail:
     153           0 :         free(ifd);
     154           0 :         return (n);
     155             : }
     156             : 
     157           0 : ssize_t imsg_get(struct imsgbuf *ibuf, struct imsg *imsg)
     158             : {
     159           0 :         size_t av, left, datalen;
     160             : 
     161           0 :         av = ibuf->r.wpos;
     162             : 
     163           0 :         if (IMSG_HEADER_SIZE > av)
     164             :                 return 0;
     165             : 
     166           0 :         memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr));
     167           0 :         if (imsg->hdr.len < IMSG_HEADER_SIZE || imsg->hdr.len > MAX_IMSGSIZE) {
     168           0 :                 errno = ERANGE;
     169           0 :                 return -1;
     170             :         }
     171           0 :         if (imsg->hdr.len > av)
     172             :                 return 0;
     173           0 :         datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
     174           0 :         ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE;
     175           0 :         if (datalen == 0)
     176           0 :                 imsg->data = NULL;
     177           0 :         else if ((imsg->data = malloc(datalen)) == NULL)
     178             :                 return -1;
     179             : 
     180           0 :         if (imsg->hdr.flags & IMSGF_HASFD)
     181           0 :                 imsg->fd = imsg_get_fd(ibuf);
     182             :         else
     183           0 :                 imsg->fd = -1;
     184             : 
     185           0 :         if (imsg->data)
     186           0 :                 memcpy(imsg->data, ibuf->r.rptr, datalen);
     187             : 
     188           0 :         if (imsg->hdr.len < av) {
     189           0 :                 left = av - imsg->hdr.len;
     190           0 :                 memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left);
     191           0 :                 ibuf->r.wpos = left;
     192             :         } else
     193           0 :                 ibuf->r.wpos = 0;
     194             : 
     195           0 :         return (datalen + IMSG_HEADER_SIZE);
     196             : }
     197             : 
     198           0 : int imsg_compose(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid,
     199             :                  pid_t pid, int fd, const void *data, uint16_t datalen)
     200             : {
     201           0 :         struct ibuf *wbuf;
     202             : 
     203           0 :         if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
     204             :                 return -1;
     205             : 
     206           0 :         if (imsg_add(wbuf, data, datalen) == -1)
     207             :                 return -1;
     208             : 
     209           0 :         wbuf->fd = fd;
     210             : 
     211           0 :         imsg_close(ibuf, wbuf);
     212             : 
     213           0 :         return 1;
     214             : }
     215             : 
     216           0 : int imsg_composev(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid,
     217             :                   pid_t pid, int fd, const struct iovec *iov, int iovcnt)
     218             : {
     219           0 :         struct ibuf *wbuf;
     220           0 :         int i, datalen = 0;
     221             : 
     222           0 :         for (i = 0; i < iovcnt; i++)
     223           0 :                 datalen += iov[i].iov_len;
     224             : 
     225           0 :         if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
     226             :                 return -1;
     227             : 
     228           0 :         for (i = 0; i < iovcnt; i++)
     229           0 :                 if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
     230             :                         return -1;
     231             : 
     232           0 :         wbuf->fd = fd;
     233             : 
     234           0 :         imsg_close(ibuf, wbuf);
     235             : 
     236           0 :         return 1;
     237             : }
     238             : 
     239             : /* ARGSUSED */
     240           0 : struct ibuf *imsg_create(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid,
     241             :                          pid_t pid, uint16_t datalen)
     242             : {
     243           0 :         struct ibuf *wbuf;
     244           0 :         struct imsg_hdr hdr;
     245             : 
     246           0 :         memset(&hdr, 0x00, IMSG_HEADER_SIZE);
     247             : 
     248           0 :         datalen += IMSG_HEADER_SIZE;
     249           0 :         if (datalen > MAX_IMSGSIZE) {
     250           0 :                 errno = ERANGE;
     251           0 :                 return NULL;
     252             :         }
     253             : 
     254           0 :         hdr.type = type;
     255           0 :         hdr.flags = 0;
     256           0 :         hdr.peerid = peerid;
     257           0 :         if ((hdr.pid = pid) == 0)
     258           0 :                 hdr.pid = ibuf->pid;
     259           0 :         if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
     260             :                 return NULL;
     261             :         }
     262           0 :         if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
     263             :                 return NULL;
     264             : 
     265             :         return (wbuf);
     266             : }
     267             : 
     268           0 : int imsg_add(struct ibuf *msg, const void *data, uint16_t datalen)
     269             : {
     270           0 :         if (datalen)
     271           0 :                 if (ibuf_add(msg, data, datalen) == -1) {
     272           0 :                         ibuf_free(msg);
     273           0 :                         return -1;
     274             :                 }
     275           0 :         return (datalen);
     276             : }
     277             : 
     278           0 : void imsg_close(struct imsgbuf *ibuf, struct ibuf *msg)
     279             : {
     280           0 :         struct imsg_hdr *hdr;
     281             : 
     282           0 :         hdr = (struct imsg_hdr *)msg->buf;
     283             : 
     284           0 :         hdr->flags &= ~IMSGF_HASFD;
     285           0 :         if (msg->fd != -1)
     286           0 :                 hdr->flags |= IMSGF_HASFD;
     287             : 
     288           0 :         hdr->len = (uint16_t)msg->wpos;
     289             : 
     290           0 :         ibuf_close(&ibuf->w, msg);
     291           0 : }
     292             : 
     293           0 : void imsg_free(struct imsg *imsg)
     294             : {
     295           0 :         free(imsg->data);
     296           0 : }
     297             : 
     298           0 : int imsg_get_fd(struct imsgbuf *ibuf)
     299             : {
     300           0 :         int fd;
     301           0 :         struct imsg_fd *ifd;
     302             : 
     303           0 :         if ((ifd = TAILQ_POP_FIRST(&ibuf->fds, entry)) == NULL)
     304             :                 return -1;
     305             : 
     306           0 :         fd = ifd->fd;
     307           0 :         free(ifd);
     308             : 
     309           0 :         return (fd);
     310             : }
     311             : 
     312           0 : int imsg_flush(struct imsgbuf *ibuf)
     313             : {
     314           0 :         while (ibuf->w.queued)
     315           0 :                 if (msgbuf_write(&ibuf->w) <= 0)
     316             :                         return -1;
     317             :         return 0;
     318             : }
     319             : 
     320           0 : void imsg_clear(struct imsgbuf *ibuf)
     321             : {
     322           0 :         int fd;
     323             : 
     324           0 :         msgbuf_clear(&ibuf->w);
     325           0 :         while ((fd = imsg_get_fd(ibuf)) != -1)
     326           0 :                 close(fd);
     327           0 : }

Generated by: LCOV version v1.16-topotato