1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
/* ISC license. */
#include <skalibs/sysdeps.h>
#include <skalibs/nonposix.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <skalibs/uint.h>
#include <skalibs/cbuffer.h>
#include <skalibs/djbunix.h>
#include <skalibs/error.h>
#include <skalibs/allreadwrite.h>
#include <skalibs/stralloc.h>
#include <skalibs/siovec.h>
#include <skalibs/unixmessage.h>
#ifdef SKALIBS_HASOKWAITALL
# ifdef SKALIBS_HASCMSGCLOEXEC
# define RECV(fd, hdr) recvmsg(fd, (hdr), MSG_WAITALL | MSG_CMSG_CLOEXEC)
# else
# define RECV(fd, hdr) recvmsg(fd, (hdr), MSG_WAITALL)
# endif
#else
# ifdef SKALIBS_HASCMSGCLOEXEC
# define RECV(fd, hdr) recvmsg(fd, (hdr), MSG_CMSG_CLOEXEC)
# else
# define RECV(fd, hdr) recvmsg(fd, (hdr), 0)
# endif
#endif
static int unixmessage_receiver_fill (unixmessage_receiver_t *b)
{
char ancilbuf[CMSG_SPACE(b->auxb.a - 1)] ;
struct iovec iov[2] ;
struct msghdr msghdr =
{
.msg_name = 0,
.msg_namelen = 0,
.msg_iov = iov,
.msg_iovlen = 2,
.msg_flags = 0,
.msg_control = ancilbuf,
.msg_controllen = sizeof(ancilbuf)
} ;
unsigned int auxlen ;
int r ;
if (cbuffer_isfull(&b->mainb) || cbuffer_isfull(&b->auxb))
return (errno = ENOBUFS, -1) ;
{
siovec_t v[2] ;
cbuffer_wpeek(&b->mainb, v) ;
iovec_from_siovec(iov, v, 2) ;
}
r = RECV(b->fd, &msghdr) ;
if (r <= 0) return r ;
{
struct cmsghdr *c = CMSG_FIRSTHDR(&msghdr) ;
if (c)
{
if (c->cmsg_level != SOL_SOCKET
|| c->cmsg_type != SCM_RIGHTS) return (errno = EPROTO, -1) ;
auxlen = (unsigned int)(c->cmsg_len - (CMSG_DATA(c) - (unsigned char *)c)) ;
#ifndef SKALIBS_HASCMSGCLOEXEC
{
register unsigned int i = 0 ;
for (; i < auxlen/sizeof(int) ; i++)
if (coe(((int *)CMSG_DATA(c))[i]) < 0) return -1 ;
}
#endif
if (msghdr.msg_flags & MSG_CTRUNC) return (errno = EPROTO, -1) ;
if (cbuffer_put(&b->auxb, (char *)CMSG_DATA(c), auxlen) < auxlen)
return (errno = ENOBUFS, -1) ;
}
}
cbuffer_WSEEK(&b->mainb, r) ;
return 1 ;
}
int unixmessage_receive (unixmessage_receiver_t *b, unixmessage_t *m)
{
if (b->maindata.len == b->mainlen && b->auxdata.len == b->auxlen)
{
char pack[sizeof(unsigned int) << 1] ;
if (cbuffer_len(&b->mainb) < sizeof(unsigned int) << 1)
{
register int r = sanitize_read(unixmessage_receiver_fill(b)) ;
if (r <= 0) return r ;
if (cbuffer_len(&b->mainb) < sizeof(unsigned int) << 1)
return (errno = EWOULDBLOCK, 0) ;
}
cbuffer_get(&b->mainb, pack, sizeof(unsigned int) << 1) ;
uint_unpack_big(pack, &b->mainlen) ;
uint_unpack_big(pack + sizeof(unsigned int), &b->auxlen) ;
b->auxlen *= sizeof(int) ;
if (!stralloc_ready(&b->maindata, b->mainlen)) return -1 ;
b->maindata.len = 0 ;
if (!stralloc_ready(&b->auxdata, b->auxlen)) return -1 ;
b->auxdata.len = 0 ;
}
for (;;)
{
register int r ;
register unsigned int n = cbuffer_len(&b->mainb) ;
if (n > b->mainlen - b->maindata.len) n = b->mainlen - b->maindata.len ;
b->maindata.len += cbuffer_get(&b->mainb, b->maindata.s + b->maindata.len, n) ;
n = cbuffer_len(&b->auxb) ;
if (n > b->auxlen - b->auxdata.len) n = b->auxlen - b->auxdata.len ;
b->auxdata.len += cbuffer_get(&b->auxb, b->auxdata.s + b->auxdata.len, n) ;
if (b->maindata.len == b->mainlen && b->auxdata.len == b->auxlen) break ;
r = sanitize_read(unixmessage_receiver_fill(b)) ;
if (r <= 0) return r ;
}
m->s = b->maindata.s ;
m->len = b->maindata.len ;
m->fds = (int *)b->auxdata.s ;
m->nfds = b->auxlen / sizeof(int) ;
return 1 ;
}
|