Hopefully improve control message passing over Unix domain sockets.

1) Allow the sending of more than one control message at a time
over a unix domain socket. This should cover the PR 29499.

2) This requires that unp_{ex,in}ternalize and unp_scan understand
mbufs with more than one control message at a time.

3) Internalize and externalize used to work on the mbuf in-place.
This made life quite complicated and the code for sizeof(int) <
sizeof(file *) could end up doing the wrong thing. The patch always
create a new mbuf/cluster now. This resulted in the change of the
prototype for the domain externalise function.

4) You can now send SCM_TIMESTAMP messages.

5) Always use CMSG_DATA(cm) to determine the start where the data
in unp_{ex,in}ternalize. It was using ((struct cmsghdr *)cm + 1)
in some places, which gives the wrong alignment on the alpha.
(NetBSD made this fix some time ago).

This results in an ABI change for discriptor passing and creds
passing on the alpha. (Probably on the IA64 and Spare ports too).

6) Fix userland programs to use CMSG_* macros too.

7) Be more careful about freeing mbufs containing (file *)s.
This is made possible by the prototype change of externalise.

PR:		29499
MFC after:	6 weeks
This commit is contained in:
David Malone 2001-10-04 13:11:48 +00:00
parent 15821eba77
commit 2bc21ed985
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=84472
10 changed files with 319 additions and 216 deletions

View File

@ -793,7 +793,10 @@ __msgread(sock, buf, cnt)
{
struct iovec iov[1];
struct msghdr msg;
struct cmessage cm;
union {
struct cmsghdr cmsg;
char control[CMSG_SPACE(sizeof(struct cmsgcred))];
} cm;
bzero((char *)&cm, sizeof(cm));
iov[0].iov_base = buf;
@ -804,7 +807,7 @@ __msgread(sock, buf, cnt)
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = (caddr_t)&cm;
msg.msg_controllen = sizeof(struct cmessage);
msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
msg.msg_flags = 0;
return(_recvmsg(sock, &msg, 0));
@ -818,7 +821,10 @@ __msgwrite(sock, buf, cnt)
{
struct iovec iov[1];
struct msghdr msg;
struct cmessage cm;
union {
struct cmsghdr cmsg;
char control[CMSG_SPACE(sizeof(struct cmsgcred))];
} cm;
bzero((char *)&cm, sizeof(cm));
iov[0].iov_base = buf;
@ -826,14 +832,14 @@ __msgwrite(sock, buf, cnt)
cm.cmsg.cmsg_type = SCM_CREDS;
cm.cmsg.cmsg_level = SOL_SOCKET;
cm.cmsg.cmsg_len = sizeof(struct cmessage);
cm.cmsg.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = (caddr_t)&cm;
msg.msg_controllen = sizeof(struct cmessage);
msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
msg.msg_flags = 0;
return(_sendmsg(sock, &msg, 0));

View File

@ -400,8 +400,6 @@ read_vc(xprtp, buf, len)
struct pollfd pollfd;
struct sockaddr *sa;
struct cmessage *cm;
struct cmsghdr *cmp;
struct sockcred *sc;
xprt = (SVCXPRT *)(void *)xprtp;
assert(xprt != NULL);
@ -429,9 +427,7 @@ read_vc(xprtp, buf, len)
if (sa->sa_family == AF_LOCAL) {
cm = (struct cmessage *)xprt->xp_verf.oa_base;
if ((len = __msgread_withcred(sock, buf, len, cm)) > 0) {
cmp = &cm->cmsg;
sc = (struct sockcred *)(void *)CMSG_DATA(cmp);
xprt->xp_p2 = sc;
xprt->xp_p2 = &cm->cmcred;
return (len);
}
} else {
@ -638,8 +634,14 @@ __msgread_withcred(sock, buf, cnt, cmp)
{
struct iovec iov[1];
struct msghdr msg;
union {
struct cmsghdr cmsg;
char control[CMSG_SPACE(sizeof(struct cmsgcred))];
} cm;
int ret;
bzero(cmp, sizeof(*cmp));
bzero(&cm, sizeof(cm));
iov[0].iov_base = buf;
iov[0].iov_len = cnt;
@ -647,11 +649,14 @@ __msgread_withcred(sock, buf, cnt, cmp)
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = cmp;
msg.msg_controllen = sizeof(struct cmessage);
msg.msg_control = &cm;
msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
msg.msg_flags = 0;
return(_recvmsg(sock, &msg, 0));
ret = _recvmsg(sock, &msg, 0);
bcopy(&cm.cmsg, &cmp->cmsg, sizeof(cmp->cmsg));
bcopy(CMSG_DATA(&cm), &cmp->cmcred, sizeof(cmp->cmcred));
return ret;
}
static int

View File

@ -113,9 +113,9 @@ int error;
int n;
struct iovec iov;
struct msghdr msg;
struct {
union {
struct cmsghdr cmsg;
int fd;
char control[CMSG_SPACE(sizeof(int))];
} ctl;
/*
@ -137,10 +137,10 @@ int error;
* construct a suitable rights control message.
*/
if (fd >= 0) {
ctl.fd = fd;
ctl.cmsg.cmsg_len = sizeof(ctl);
ctl.cmsg.cmsg_len = CMSG_LEN(sizeof(int));
ctl.cmsg.cmsg_level = SOL_SOCKET;
ctl.cmsg.cmsg_type = SCM_RIGHTS;
*((int *)CMSG_DATA(&ctl.cmsg)) = fd;
msg.msg_control = (caddr_t) &ctl;
msg.msg_controllen = ctl.cmsg.cmsg_len;
}

View File

@ -672,7 +672,7 @@ soreceive(so, psa, uio, mp0, controlp, flagsp)
struct mbuf **controlp;
int *flagsp;
{
register struct mbuf *m, **mp;
struct mbuf *m, **mp;
register int flags, len, error, s, offset;
struct protosw *pr = so->so_proto;
struct mbuf *nextrecord;
@ -798,23 +798,22 @@ soreceive(so, psa, uio, mp0, controlp, flagsp)
m = m->m_next;
} else {
sbfree(&so->so_rcv, m);
if (controlp) {
if (pr->pr_domain->dom_externalize &&
mtod(m, struct cmsghdr *)->cmsg_type ==
SCM_RIGHTS)
error = (*pr->pr_domain->dom_externalize)(m);
so->so_rcv.sb_mb = m->m_next;
m->m_next = NULL;
if (pr->pr_domain->dom_externalize)
error =
(*pr->pr_domain->dom_externalize)(m, controlp);
else if (controlp)
*controlp = m;
so->so_rcv.sb_mb = m->m_next;
m->m_next = 0;
m = so->so_rcv.sb_mb;
} else {
MFREE(m, so->so_rcv.sb_mb);
m = so->so_rcv.sb_mb;
}
else
m_freem(m);
m = so->so_rcv.sb_mb;
}
if (controlp) {
orig_resid = 0;
controlp = &(*controlp)->m_next;
do
controlp = &(*controlp)->m_next;
while (*controlp != NULL);
}
}
if (m) {

View File

@ -90,7 +90,8 @@ static void unp_gc __P((void));
static void unp_scan __P((struct mbuf *, void (*)(struct file *)));
static void unp_mark __P((struct file *));
static void unp_discard __P((struct file *));
static int unp_internalize __P((struct mbuf *, struct thread *));
static void unp_freerights __P((struct file **, int));
static int unp_internalize __P((struct mbuf **, struct thread *));
static int unp_listen __P((struct unpcb *, struct proc *));
static int
@ -274,7 +275,7 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
goto release;
}
if (control && (error = unp_internalize(control, td)))
if (control && (error = unp_internalize(&control, td)))
goto release;
switch (so->so_type) {
@ -952,80 +953,127 @@ unp_drain()
}
#endif
static void
unp_freerights(rp, fdcount)
struct file **rp;
int fdcount;
{
int i;
struct file *fp;
for (i = 0; i < fdcount; i++) {
fp = *rp;
/*
* zero the pointer before calling
* unp_discard since it may end up
* in unp_gc()..
*/
*rp++ = 0;
unp_discard(fp);
}
}
int
unp_externalize(rights)
struct mbuf *rights;
unp_externalize(control, controlp)
struct mbuf *control, **controlp;
{
struct thread *td = curthread; /* XXX */
register int i;
register struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
register int *fdp;
register struct file **rp;
register struct file *fp;
int newfds = (cm->cmsg_len - (CMSG_DATA(cm) - (u_char *)cm))
/ sizeof (struct file *);
struct cmsghdr *cm = mtod(control, struct cmsghdr *);
int i;
int *fdp;
struct file **rp;
struct file *fp;
void *data;
socklen_t clen = control->m_len, datalen;
int error, newfds;
int f;
u_int newlen;
/*
* if the new FD's will not fit, then we free them all
*/
if (!fdavail(td, newfds)) {
rp = (struct file **)CMSG_DATA(cm);
for (i = 0; i < newfds; i++) {
fp = *rp;
error = 0;
if (controlp != NULL) /* controlp == NULL => free control messages */
*controlp = NULL;
while (cm != NULL) {
if (sizeof(*cm) > clen || cm->cmsg_len > clen) {
error = EINVAL;
break;
}
data = CMSG_DATA(cm);
datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
if (cm->cmsg_level == SOL_SOCKET
&& cm->cmsg_type == SCM_RIGHTS) {
newfds = datalen / sizeof(struct file *);
rp = data;
/* If we're not outputting the discriptors free them. */
if (error || controlp == NULL) {
unp_freerights(rp, newfds);
goto next;
}
/* if the new FD's will not fit free them. */
if (!fdavail(td, newfds)) {
error = EMSGSIZE;
unp_freerights(rp, newfds);
goto next;
}
/*
* zero the pointer before calling unp_discard,
* since it may end up in unp_gc()..
* now change each pointer to an fd in the global
* table to an integer that is the index to the
* local fd table entry that we set up to point
* to the global one we are transferring.
*/
*rp++ = 0;
unp_discard(fp);
newlen = newfds * sizeof(int);
*controlp = sbcreatecontrol(NULL, newlen,
SCM_RIGHTS, SOL_SOCKET);
if (*controlp == NULL) {
error = E2BIG;
unp_freerights(rp, newfds);
goto next;
}
fdp = (int *)
CMSG_DATA(mtod(*controlp, struct cmsghdr *));
for (i = 0; i < newfds; i++) {
if (fdalloc(td, 0, &f))
panic("unp_externalize fdalloc failed");
fp = *rp++;
td->td_proc->p_fd->fd_ofiles[f] = fp;
fp->f_msgcount--;
unp_rights--;
*fdp++ = f;
}
} else { /* We can just copy anything else across */
if (error || controlp == NULL)
goto next;
*controlp = sbcreatecontrol(NULL, datalen,
cm->cmsg_type, cm->cmsg_level);
if (*controlp == NULL) {
error = ENOBUFS;
goto next;
}
bcopy(data,
CMSG_DATA(mtod(*controlp, struct cmsghdr *)),
datalen);
}
return (EMSGSIZE);
}
/*
* now change each pointer to an fd in the global table to
* an integer that is the index to the local fd table entry
* that we set up to point to the global one we are transferring.
* If sizeof (struct file *) is bigger than or equal to sizeof int,
* then do it in forward order. In that case, an integer will
* always come in the same place or before its corresponding
* struct file pointer.
* If sizeof (struct file *) is smaller than sizeof int, then
* do it in reverse order.
*/
if (sizeof (struct file *) >= sizeof (int)) {
fdp = (int *)(cm + 1);
rp = (struct file **)CMSG_DATA(cm);
for (i = 0; i < newfds; i++) {
if (fdalloc(td, 0, &f))
panic("unp_externalize");
fp = *rp++;
td->td_proc->p_fd->fd_ofiles[f] = fp;
fp->f_msgcount--;
unp_rights--;
*fdp++ = f;
}
} else {
fdp = (int *)(cm + 1) + newfds - 1;
rp = (struct file **)CMSG_DATA(cm) + newfds - 1;
for (i = 0; i < newfds; i++) {
if (fdalloc(td, 0, &f))
panic("unp_externalize");
fp = *rp--;
td->td_proc->p_fd->fd_ofiles[f] = fp;
fp->f_msgcount--;
unp_rights--;
*fdp-- = f;
controlp = &(*controlp)->m_next;
next:
if (CMSG_SPACE(datalen) < clen) {
clen -= CMSG_SPACE(datalen);
cm = (struct cmsghdr *)
((caddr_t)cm + CMSG_SPACE(datalen));
} else {
clen = 0;
cm = NULL;
}
}
/*
* Adjust length, in case sizeof(struct file *) and sizeof(int)
* differs.
*/
cm->cmsg_len = CMSG_LEN(newfds * sizeof(int));
rights->m_len = cm->cmsg_len;
return (0);
m_freem(control);
return (error);
}
void
@ -1043,109 +1091,134 @@ unp_init(void)
#endif
static int
unp_internalize(control, td)
struct mbuf *control;
unp_internalize(controlp, td)
struct mbuf **controlp;
struct thread *td;
{
struct mbuf *control = *controlp;
struct proc *p = td->td_proc;
struct filedesc *fdescp = p->p_fd;
register struct cmsghdr *cm = mtod(control, struct cmsghdr *);
register struct file **rp;
register struct file *fp;
register int i, fd, *fdp;
register struct cmsgcred *cmcred;
int oldfds;
struct cmsghdr *cm = mtod(control, struct cmsghdr *);
struct cmsgcred *cmcred;
struct file **rp;
struct file *fp;
struct timeval *tv;
int i, fd, *fdp;
void *data;
socklen_t clen = control->m_len, datalen;
int error, oldfds;
u_int newlen;
if ((cm->cmsg_type != SCM_RIGHTS && cm->cmsg_type != SCM_CREDS) ||
cm->cmsg_level != SOL_SOCKET || cm->cmsg_len != control->m_len)
return (EINVAL);
error = 0;
*controlp = NULL;
/*
* Fill in credential information.
*/
if (cm->cmsg_type == SCM_CREDS) {
cmcred = (struct cmsgcred *)(cm + 1);
cmcred->cmcred_pid = p->p_pid;
cmcred->cmcred_uid = p->p_ucred->cr_ruid;
cmcred->cmcred_gid = p->p_ucred->cr_rgid;
cmcred->cmcred_euid = p->p_ucred->cr_uid;
cmcred->cmcred_ngroups = MIN(p->p_ucred->cr_ngroups,
while (cm != NULL) {
if (sizeof(*cm) > clen || cm->cmsg_level != SOL_SOCKET
|| cm->cmsg_len > clen) {
error = EINVAL;
goto out;
}
data = CMSG_DATA(cm);
datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
switch (cm->cmsg_type) {
/*
* Fill in credential information.
*/
case SCM_CREDS:
*controlp = sbcreatecontrol(NULL, sizeof(*cmcred),
SCM_CREDS, SOL_SOCKET);
if (*controlp == NULL) {
error = ENOBUFS;
goto out;
}
cmcred = (struct cmsgcred *)
CMSG_DATA(mtod(*controlp, struct cmsghdr *));
cmcred->cmcred_pid = p->p_pid;
cmcred->cmcred_uid = p->p_ucred->cr_ruid;
cmcred->cmcred_gid = p->p_ucred->cr_rgid;
cmcred->cmcred_euid = p->p_ucred->cr_uid;
cmcred->cmcred_ngroups = MIN(p->p_ucred->cr_ngroups,
CMGROUP_MAX);
for (i = 0; i < cmcred->cmcred_ngroups; i++)
cmcred->cmcred_groups[i] = p->p_ucred->cr_groups[i];
return(0);
}
for (i = 0; i < cmcred->cmcred_ngroups; i++)
cmcred->cmcred_groups[i] =
p->p_ucred->cr_groups[i];
break;
oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
/*
* check that all the FDs passed in refer to legal OPEN files
* If not, reject the entire operation.
*/
fdp = (int *)(cm + 1);
for (i = 0; i < oldfds; i++) {
fd = *fdp++;
if ((unsigned)fd >= fdescp->fd_nfiles ||
fdescp->fd_ofiles[fd] == NULL)
return (EBADF);
}
/*
* Now replace the integer FDs with pointers to
* the associated global file table entry..
* Allocate a bigger buffer as necessary. But if an cluster is not
* enough, return E2BIG.
*/
newlen = CMSG_LEN(oldfds * sizeof(struct file *));
if (newlen > MCLBYTES)
return (E2BIG);
if (newlen - control->m_len > M_TRAILINGSPACE(control)) {
if (control->m_flags & M_EXT)
return (E2BIG);
MCLGET(control, M_TRYWAIT);
if ((control->m_flags & M_EXT) == 0)
return (ENOBUFS);
case SCM_RIGHTS:
oldfds = datalen / sizeof (int);
/*
* check that all the FDs passed in refer to legal files
* If not, reject the entire operation.
*/
fdp = data;
for (i = 0; i < oldfds; i++) {
fd = *fdp++;
if ((unsigned)fd >= fdescp->fd_nfiles ||
fdescp->fd_ofiles[fd] == NULL) {
error = EBADF;
goto out;
}
}
/*
* Now replace the integer FDs with pointers to
* the associated global file table entry..
*/
newlen = oldfds * sizeof(struct file *);
*controlp = sbcreatecontrol(NULL, newlen,
SCM_RIGHTS, SOL_SOCKET);
if (*controlp == NULL) {
error = E2BIG;
goto out;
}
/* copy the data to the cluster */
memcpy(mtod(control, char *), cm, cm->cmsg_len);
cm = mtod(control, struct cmsghdr *);
}
fdp = data;
rp = (struct file **)
CMSG_DATA(mtod(*controlp, struct cmsghdr *));
for (i = 0; i < oldfds; i++) {
fp = fdescp->fd_ofiles[*fdp++];
*rp++ = fp;
fp->f_count++;
fp->f_msgcount++;
unp_rights++;
}
break;
/*
* Adjust length, in case sizeof(struct file *) and sizeof(int)
* differs.
*/
control->m_len = cm->cmsg_len = newlen;
case SCM_TIMESTAMP:
*controlp = sbcreatecontrol(NULL, sizeof(*tv),
SCM_TIMESTAMP, SOL_SOCKET);
if (*controlp == NULL) {
error = ENOBUFS;
goto out;
}
tv = (struct timeval *)
CMSG_DATA(mtod(*controlp, struct cmsghdr *));
microtime(tv);
break;
/*
* Transform the file descriptors into struct file pointers.
* If sizeof (struct file *) is bigger than or equal to sizeof int,
* then do it in reverse order so that the int won't get until
* we're done.
* If sizeof (struct file *) is smaller than sizeof int, then
* do it in forward order.
*/
if (sizeof (struct file *) >= sizeof (int)) {
fdp = (int *)(cm + 1) + oldfds - 1;
rp = (struct file **)CMSG_DATA(cm) + oldfds - 1;
for (i = 0; i < oldfds; i++) {
fp = fdescp->fd_ofiles[*fdp--];
*rp-- = fp;
fp->f_count++;
fp->f_msgcount++;
unp_rights++;
default:
error = EINVAL;
goto out;
}
} else {
fdp = (int *)(cm + 1);
rp = (struct file **)CMSG_DATA(cm);
for (i = 0; i < oldfds; i++) {
fp = fdescp->fd_ofiles[*fdp++];
*rp++ = fp;
fp->f_count++;
fp->f_msgcount++;
unp_rights++;
controlp = &(*controlp)->m_next;
if (CMSG_SPACE(datalen) < clen) {
clen -= CMSG_SPACE(datalen);
cm = (struct cmsghdr *)
((caddr_t)cm + CMSG_SPACE(datalen));
} else {
clen = 0;
cm = NULL;
}
}
return (0);
out:
m_freem(control);
return (error);
}
static int unp_defer, unp_gcing;
@ -1343,28 +1416,48 @@ unp_scan(m0, op)
register struct mbuf *m0;
void (*op) __P((struct file *));
{
register struct mbuf *m;
register struct file **rp;
register struct cmsghdr *cm;
register int i;
struct mbuf *m;
struct file **rp;
struct cmsghdr *cm;
void *data;
int i;
socklen_t clen, datalen;
int qfds;
while (m0) {
for (m = m0; m; m = m->m_next)
if (m->m_type == MT_CONTROL &&
m->m_len >= sizeof(*cm)) {
cm = mtod(m, struct cmsghdr *);
if (cm->cmsg_level != SOL_SOCKET ||
cm->cmsg_type != SCM_RIGHTS)
continue;
qfds = (cm->cmsg_len -
(CMSG_DATA(cm) - (u_char *)cm))
/ sizeof (struct file *);
rp = (struct file **)CMSG_DATA(cm);
for (i = 0; i < qfds; i++)
(*op)(*rp++);
break; /* XXX, but saves time */
for (m = m0; m; m = m->m_next) {
if (m->m_type == MT_CONTROL)
continue;
cm = mtod(m, struct cmsghdr *);
clen = m->m_len;
while (cm != NULL) {
if (sizeof(*cm) > clen || cm->cmsg_len > clen)
break;
data = CMSG_DATA(cm);
datalen = (caddr_t)cm + cm->cmsg_len
- (caddr_t)data;
if (cm->cmsg_level == SOL_SOCKET &&
cm->cmsg_type == SCM_RIGHTS) {
qfds = datalen / sizeof (struct file *);
rp = data;
for (i = 0; i < qfds; i++)
(*op)(*rp++);
}
if (CMSG_SPACE(datalen) < clen) {
clen -= CMSG_SPACE(datalen);
cm = (struct cmsghdr *)
((caddr_t)cm + CMSG_SPACE(datalen));
} else {
clen = 0;
cm = NULL;
}
}
}
m0 = m0->m_act;
}
}

View File

@ -583,7 +583,7 @@ ng_internalize(struct mbuf *control, struct thread *td)
}
/* Check there is only one FD. XXX what would more than one signify? */
oldfds = (cm->cmsg_len - sizeof(*cm)) / sizeof(int);
oldfds = ((caddr_t)cm + cm->cmsg_len - (caddr_t)data) / sizeof (int);
if (oldfds != 1) {
TRAP_ERROR;
return (EINVAL);
@ -591,7 +591,7 @@ ng_internalize(struct mbuf *control, struct thread *td)
/* Check that the FD given is legit. and change it to a pointer to a
* struct file. */
fd = *(int *) (cm + 1);
fd = CMSG_DATA(cm);
if ((unsigned) fd >= fdp->fd_nfiles
|| (fp = fdp->fd_ofiles[fd]) == NULL) {
return (EBADF);

View File

@ -52,7 +52,7 @@ struct domain {
void (*dom_init) /* initialize domain data structures */
__P((void));
int (*dom_externalize) /* externalize access rights */
__P((struct mbuf *));
__P((struct mbuf *, struct mbuf **));
void (*dom_dispose) /* dispose of internalized rights */
__P((struct mbuf *));
struct protosw *dom_protosw, *dom_protoswNPROTOSW;

View File

@ -59,7 +59,7 @@ int uipc_usrreq __P((struct socket *so, int req, struct mbuf *m,
struct mbuf *nam, struct mbuf *control));
int unp_connect2 __P((struct socket *so, struct socket *so2));
void unp_dispose __P((struct mbuf *m));
int unp_externalize __P((struct mbuf *rights));
int unp_externalize __P((struct mbuf *mbuf, struct mbuf **controlp));
void unp_init __P((void));
extern struct pr_usrreqs uipc_usrreqs;
#else /* !_KERNEL */

View File

@ -113,9 +113,9 @@ int error;
int n;
struct iovec iov;
struct msghdr msg;
struct {
union {
struct cmsghdr cmsg;
int fd;
char control[CMSG_SPACE(sizeof(int))];
} ctl;
/*
@ -137,10 +137,10 @@ int error;
* construct a suitable rights control message.
*/
if (fd >= 0) {
ctl.fd = fd;
ctl.cmsg.cmsg_len = sizeof(ctl);
ctl.cmsg.cmsg_len = CMSG_LEN(sizeof(int));
ctl.cmsg.cmsg_level = SOL_SOCKET;
ctl.cmsg.cmsg_type = SCM_RIGHTS;
*((int *)CMSG_DATA(&ctl.cmsg)) = fd;
msg.msg_control = (caddr_t) &ctl;
msg.msg_controllen = ctl.cmsg.cmsg_len;
}

View File

@ -1364,8 +1364,8 @@ bundle_ReceiveDatalink(struct bundle *bundle, int s)
return;
}
fd = (int *)(cmsg + 1);
nfd = (cmsg->cmsg_len - sizeof *cmsg) / sizeof(int);
fd = (int *)CMSG_DATA(cmsg);
nfd = ((caddr_t)cmsg + cmsg->cmsg_len - (caddr_t)fd) / sizeof(int);
if (nfd < 2) {
log_Printf(LogERROR, "Recvmsg: %d descriptor%s received (too few) !\n",
@ -1457,7 +1457,7 @@ bundle_ReceiveDatalink(struct bundle *bundle, int s)
void
bundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun)
{
char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int) * SEND_MAXFD];
char cmsgbuf[CMSG_SPACE(sizeof(int) * SEND_MAXFD)];
const char *constlock;
char *lock;
struct cmsghdr *cmsg;
@ -1507,7 +1507,7 @@ bundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun)
msg.msg_iovlen = 1;
msg.msg_iov = iov;
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof *cmsg + sizeof(int) * nfd;
msg.msg_controllen = CMSG_SPACE(sizeof(int) * nfd);
msg.msg_flags = 0;
cmsg = (struct cmsghdr *)cmsgbuf;
@ -1516,7 +1516,7 @@ bundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun)
cmsg->cmsg_type = SCM_RIGHTS;
for (f = 0; f < nfd; f++)
*((int *)(cmsg + 1) + f) = fd[f];
*((int *)CMSG_DATA(cmsg) + f) = fd[f];
for (f = 1, expect = 0; f < niov; f++)
expect += iov[f].iov_len;