1 /* ISC license. */
2 
3 #include <string.h>
4 #include <errno.h>
5 
6 #include <skalibs/bitarray.h>
7 #include <skalibs/disize.h>
8 #include <skalibs/stralloc.h>
9 #include <skalibs/genalloc.h>
10 #include <skalibs/siovec.h>
11 #include <skalibs/unixmessage.h>
12 #include <skalibs/posixishard.h>
13 
copyfds(char * s,int const * fds,unsigned int n,unsigned char const * bits,unixmessage_sender_closecb_func_t_ref closecb,void * closecbdata)14 static inline int copyfds (char *s, int const *fds, unsigned int n, unsigned char const *bits, unixmessage_sender_closecb_func_t_ref closecb, void *closecbdata)
15 {
16   unsigned int i = 0 ;
17   for (; i < n ; i++)
18   {
19     int fd = fds[i] ;
20     if (fd < 0) return (errno = EINVAL, -1) ;
21     if (bitarray_peek(bits, i)) fd = - fd - 1 ;
22     memcpy(s, (char const *)&fd, sizeof(int)) ;
23     s += sizeof(int) ;
24   }
25   return 1 ;
26 }
27 
reserve_and_copy(unixmessage_sender_t * b,size_t len,int const * fds,unsigned int nfds,unsigned char const * bits)28 static int reserve_and_copy (unixmessage_sender_t *b, size_t len, int const *fds, unsigned int nfds, unsigned char const *bits)
29 {
30   disize cur = { .left = b->data.len, .right = genalloc_len(int, &b->fds) } ;
31   if (len > UNIXMESSAGE_MAXSIZE || nfds > UNIXMESSAGE_MAXFDS)
32     return (errno = EPROTO, 0) ;
33   if (!genalloc_readyplus(disize, &b->offsets, 1)
34    || !genalloc_readyplus(int, &b->fds, nfds)
35    || !stralloc_readyplus(&b->data, len))
36     return 0 ;
37   if (!copyfds(b->fds.s + b->fds.len, fds, nfds, bits, b->closecb, b->closecbdata)) return 0 ;
38   genalloc_setlen(int, &b->fds, cur.right + nfds) ;
39   return genalloc_append(disize, &b->offsets, &cur) ;
40 }
41 
unixmessage_put_and_close(unixmessage_sender_t * b,unixmessage_t const * m,unsigned char const * bits)42 int unixmessage_put_and_close (unixmessage_sender_t *b, unixmessage_t const *m, unsigned char const *bits)
43 {
44   if (!reserve_and_copy(b, m->len, m->fds, m->nfds, bits)) return 0 ;
45   memmove(b->data.s + b->data.len, m->s, m->len) ;
46   b->data.len += m->len ;
47   return 1 ;
48 }
49 
unixmessage_putv_and_close(unixmessage_sender_t * b,unixmessage_v_t const * m,unsigned char const * bits)50 int unixmessage_putv_and_close (unixmessage_sender_t *b, unixmessage_v_t const *m, unsigned char const *bits)
51 {
52   size_t len = siovec_len(m->v, m->vlen) ;
53   if (!reserve_and_copy(b, len, m->fds, m->nfds, bits)) return 0 ;
54   b->data.len += siovec_gather(m->v, m->vlen, b->data.s + b->data.len, len) ;
55   return 1 ;
56 }
57