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