/*-
* Copyright (c)1996-2005 by Hartmut Brandt
* All rights reserved.
*
* Author: Harti Brandt <harti@freebsd.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Begemot: libbegemot/frame.c,v 1.13 2005/06/01 07:50:40 brandt_h Exp $
*/
# include <stdio.h>
# include <stdlib.h>
# include <stdarg.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/uio.h>
# ifdef HAVE_STREAMS
# include <stropts.h>
# endif
# include <netinet/in.h>
# include "begemot.h"
# define MAXIOVEC 100
# ifndef HAVE_OLDMSGHDR
struct passfd {
struct cmsghdr cmsg;
int fd;
};
# endif
struct hdr {
u_int bytes;
int fd;
};
int
frame_write(int fd, void *hdr, u_int hdr_len, void *arg, ...)
{
struct iovec iov[MAXIOVEC];
struct hdr *h;
u_int iovlen;
va_list ap;
u_int len;
int ret;
iovlen = 0;
h = (struct hdr *)hdr;
iov[iovlen].iov_base = (caddr_t)hdr;
iov[iovlen++].iov_len = hdr_len;
h->bytes = 0;
va_start(ap, arg);
while(arg != NULL) {
len = va_arg(ap, u_int);
if(len != 0) {
iov[iovlen].iov_base = (caddr_t)arg;
iov[iovlen++].iov_len = len;
h->bytes += len;
}
arg = va_arg(ap, void *);
}
va_end(ap);
h->bytes = htonl(h->bytes);
ret = writev(fd, iov, iovlen);
h->bytes = ntohl(h->bytes);
return ret;
}
int
frame_writev(int fd, void *hdr, u_int hdr_len, struct iovec *v, u_int vlen)
{
struct iovec iov[MAXIOVEC];
struct hdr *h;
u_int i, iovlen;
int ret;
iovlen = 0;
h = (struct hdr *)hdr;
iov[iovlen].iov_base = (caddr_t)hdr;
iov[iovlen++].iov_len = hdr_len;
h->bytes = 0;
for(i = 0; i < vlen; i++) {
if(v[i].iov_len != 0) {
h->bytes += v[i].iov_len;
iov[iovlen++] = v[i];
}
}
h->bytes = htonl(h->bytes);
ret = writev(fd, iov, iovlen);
h->bytes = ntohl(h->bytes);
return ret;
}
# ifdef SEND_FD_BUG
/*
* The Solaris 2.5 (and maybe earlier) socket emulation has a bug:
* If you send one piece of data and a file descriptor. You can't receive
* the data: the receiver must expect the data. So we send first the header
* so that the receiver knows whether to wait for a file descriptor or not
* and then the extensions together with the file descriptor.
*/
int
framefd_write(int fd, void *hdr, u_int hdr_len, void *arg, ...)
{
struct msghdr msg;
struct iovec iov[MAXIOVEC+1];
va_list ap;
u_int len;
struct hdr *h;
int sendfd, ret, ret1;
u_int iovlen;
h = (struct hdr *)hdr;
sendfd = h->fd;
iovlen = 0;
iov[iovlen].iov_base = (caddr_t)hdr;
iov[iovlen++].iov_len = sizeof(h->bytes);
iov[iovlen].iov_base = (caddr_t)((char *)hdr + sizeof(h->bytes));
iov[iovlen++].iov_len = hdr_len - sizeof(h->bytes);
h->bytes = 0;
h->fd = (sendfd >= 0);
va_start(ap, arg);
while(arg != NULL) {
len = va_arg(ap, u_int);
if(len != 0) {
iov[iovlen].iov_base = (caddr_t)arg;
iov[iovlen++].iov_len = len;
h->bytes += len;
}
arg = va_arg(ap, void *);
}
va_end(ap);
h->bytes = htonl(h->bytes);
/* send the 4 byte length only */
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_accrights = NULL;
msg.msg_accrightslen = 0;
ret = sendmsg(fd, &msg, 0);
h->bytes = ntohl(h->bytes);
if(ret != iov[0].iov_len)
return ret;
if(h->fd >= 0) {
sendfd = h->fd;
msg.msg_accrights = (caddr_t)&sendfd;
msg.msg_accrightslen = sizeof(sendfd);
} else {
msg.msg_accrights = NULL;
msg.msg_accrightslen = 0;
}
msg.msg_iov = iov + 1;
msg.msg_iovlen = iovlen - 1;
if((ret1 = sendmsg(fd, &msg, 0)) < 0)
return ret1;
return ret + ret1;
}
int
framefd_writev(int fd, void *hdr, u_int hdr_len, struct iovec *v, u_int vlen)
{
struct msghdr msg;
struct iovec iov[MAXIOVEC+1];
struct hdr *h;
int sendfd, ret, ret1;
u_int iovlen, i;
h = (struct hdr *)hdr;
sendfd = h->fd;
iovlen = 0;
iov[iovlen].iov_base = (caddr_t)hdr;
iov[iovlen++].iov_len = sizeof(h->bytes);
iov[iovlen].iov_base = (caddr_t)((char *)hdr + sizeof(h->bytes));
iov[iovlen++].iov_len = hdr_len - sizeof(h->bytes);
h->bytes = 0;
h->fd = (sendfd >= 0);
for(i = 0; i < vlen; i++) {
if(v[i].iov_len != 0) {
h->bytes += v[i].iov_len;
iov[iovlen++] = v[i];
}
}
h->bytes = htonl(h->bytes);
/* send the 4 byte length only */
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_accrights = NULL;
msg.msg_accrightslen = 0;
ret = sendmsg(fd, &msg, 0);
h->bytes = ntohl(h->bytes);
if(ret != iov[0].iov_len)
return ret;
if(h->fd >= 0) {
sendfd = h->fd;
msg.msg_accrights = (caddr_t)&sendfd;
msg.msg_accrightslen = sizeof(sendfd);
} else {
msg.msg_accrights = NULL;
msg.msg_accrightslen = 0;
}
msg.msg_iov = iov + 1;
msg.msg_iovlen = iovlen - 1;
if((ret1 = sendmsg(fd, &msg, 0)) < 0)
return ret1;
return ret + ret1;
}
# else
int
framefd_write(int fd, void *hdr, u_int hdr_len, void *arg, ...)
{
struct msghdr msg;
struct iovec iov[MAXIOVEC];
va_list ap;
u_int len;
int ret;
struct hdr *h;
# ifndef HAVE_OLDMSGHDR
struct passfd passfd;
# else
int sendfd;
# endif
h = (struct hdr *)hdr;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = 0;
if(h->fd >= 0) {
# ifdef HAVE_OLDMSGHDR
sendfd = h->fd;
msg.msg_accrights = (caddr_t)&sendfd;
msg.msg_accrightslen = sizeof(sendfd);
# else
passfd.fd = h->fd;
passfd.cmsg.cmsg_len = sizeof(passfd);
passfd.cmsg.cmsg_level = SOL_SOCKET;
passfd.cmsg.cmsg_type = SCM_RIGHTS;
msg.msg_control = (caddr_t)&passfd;
msg.msg_controllen = sizeof(passfd);
# endif
} else {
# ifdef HAVE_OLDMSGHDR
msg.msg_accrights = NULL;
msg.msg_accrightslen = 0;
# else
msg.msg_control = NULL;
msg.msg_controllen = 0;
# endif
}
iov[msg.msg_iovlen].iov_base = (caddr_t)hdr;
iov[msg.msg_iovlen++].iov_len = hdr_len;
h->bytes = 0;
# ifdef HAVE_OLDMSGHDR
h->fd = (sendfd >= 0);
# else
h->fd = (passfd.fd >= 0);
# endif
va_start(ap, arg);
while(arg != NULL) {
len = va_arg(ap, u_int);
if(len != 0) {
iov[msg.msg_iovlen].iov_base = (caddr_t)arg;
iov[msg.msg_iovlen++].iov_len = len;
h->bytes += len;
}
arg = va_arg(ap, void *);
}
va_end(ap);
h->bytes = htonl(h->bytes);
ret = sendmsg(fd, &msg, 0);
h->bytes = ntohl(h->bytes);
return ret;
}
int
framefd_writev(int fd, void *hdr, u_int hdr_len, struct iovec *v, u_int vlen)
{
struct msghdr msg;
struct iovec iov[MAXIOVEC];
u_int i;
int ret;
struct hdr *h;
# ifndef HAVE_OLDMSGHDR
struct passfd passfd;
# else
int sendfd;
# endif
h = (struct hdr *)hdr;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = 0;
if(h->fd >= 0) {
# ifdef HAVE_OLDMSGHDR
sendfd = h->fd;
msg.msg_accrights = (caddr_t)&sendfd;
msg.msg_accrightslen = sizeof(sendfd);
# else
passfd.fd = h->fd;
passfd.cmsg.cmsg_len = sizeof(passfd);
passfd.cmsg.cmsg_level = SOL_SOCKET;
passfd.cmsg.cmsg_type = SCM_RIGHTS;
msg.msg_control = (caddr_t)&passfd;
msg.msg_controllen = sizeof(passfd);
# endif
} else {
# ifdef HAVE_OLDMSGHDR
msg.msg_accrights = NULL;
msg.msg_accrightslen = 0;
# else
msg.msg_control = NULL;
msg.msg_controllen = 0;
# endif
}
iov[msg.msg_iovlen].iov_base = (caddr_t)hdr;
iov[msg.msg_iovlen++].iov_len = hdr_len;
h->bytes = 0;
# ifdef HAVE_OLDMSGHDR
h->fd = (sendfd >= 0);
# else
h->fd = (passfd.fd >= 0);
# endif
for(i = 0; i < vlen; i++) {
if(v[i].iov_len != 0) {
h->bytes += v[i].iov_len;
iov[msg.msg_iovlen++] = v[i];
}
}
h->bytes = htonl(h->bytes);
ret = sendmsg(fd, &msg, 0);
h->bytes = ntohl(h->bytes);
return ret;
}
# endif
int
frame_read(int fd, void *hdr, u_int hdr_len, void **parg, u_int *plen)
{
struct iovec iov[1];
struct hdr *h;
u_int iovlen;
int n, n1;
iovlen = 0;
h = (struct hdr *)hdr;
iov[iovlen].iov_base = (caddr_t)hdr;
iov[iovlen++].iov_len = hdr_len;
if((n = readv(fd, iov, iovlen)) < 0 || (u_int)n < hdr_len)
return n;
h->bytes = ntohl(h->bytes);
if(h->bytes == 0)
return n;
if(h->bytes > *plen) {
*parg = xrealloc(*parg, h->bytes);
*plen = h->bytes;
}
iovlen = 0;
iov[iovlen].iov_base = (caddr_t)*parg;
iov[iovlen++].iov_len = h->bytes;
if((n1 = readv(fd, iov, iovlen)) <= 0)
return n1;
*plen = n1;
return n + n1;
}
# ifdef SEND_FD_BUG
int
framefd_read(int fd, void *hdr, u_int hdr_len, void **parg, u_int *plen)
{
struct msghdr msg;
struct iovec iov[2];
struct hdr *h;
int n, n1;
int recvfd;
h = (struct hdr *)hdr;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_accrights = NULL;
msg.msg_accrightslen = 0;
iov[0].iov_base = (caddr_t)hdr;
iov[0].iov_len = sizeof(h->bytes);
if((n = recvmsg(fd, &msg, 0)) != sizeof(h->bytes))
return n;
h->bytes = ntohl(h->bytes);
iov[0].iov_base = (caddr_t)((char *)hdr + sizeof(h->bytes));
iov[0].iov_len = hdr_len - sizeof(h->bytes);
if(h->bytes > *plen) {
*parg = xrealloc(*parg, h->bytes);
*plen = h->bytes;
}
if(h->bytes) {
iov[1].iov_base = (caddr_t)*parg;
iov[1].iov_len = h->bytes;
}
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = (h->bytes ? 2 : 1);
msg.msg_accrights = (caddr_t)&recvfd;
msg.msg_accrightslen = sizeof(recvfd);
recvfd = -1;
if((n1 = recvmsg(fd, &msg, 0)) <= 0)
return n1;
if((u_int)n >= sizeof(struct hdr) - sizeof(h->bytes)) {
if(h->fd) {
# ifdef HAVE_OLDMSGHDR
if(recvfd == -1)
h->fd = -2;
else
h->fd = recvfd;
# else
if(passfd.fd == -1)
h->fd = -2;
else
h->fd = passfd.fd;
# endif
} else {
# ifdef HAVE_OLDMSGHDR
if(recvfd >= 0)
(void)close(recvfd);
# else
if(passfd.fd >= 0)
(void)close(passfd.fd);
# endif
h->fd = -1;
}
}
return n + n1;
}
# else
int
framefd_read(int fd, void *hdr, u_int hdr_len, void **parg, u_int *plen)
{
struct msghdr msg;
struct iovec iov[1];
struct hdr *h;
int n, n1;
# ifndef HAVE_OLDMSGHDR
struct passfd passfd;
# else
int recvfd;
# endif
h = (struct hdr *)hdr;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
# ifdef HAVE_OLDMSGHDR
msg.msg_accrights = (caddr_t)&recvfd;
msg.msg_accrightslen = sizeof(recvfd);
recvfd = -1;
# else
msg.msg_control = (caddr_t)&passfd;
msg.msg_controllen = sizeof(passfd);
passfd.cmsg.cmsg_len = sizeof(passfd);
passfd.cmsg.cmsg_level = SOL_SOCKET;
passfd.cmsg.cmsg_type = SCM_RIGHTS;
passfd.fd = -1;
# endif
iov[0].iov_base = (caddr_t)hdr;
iov[0].iov_len = hdr_len;
if((n = recvmsg(fd, &msg, 0)) < 0 || (u_int)n < sizeof(struct hdr))
return n;
h->bytes = ntohl(h->bytes);
if((u_int)n >= sizeof(struct hdr)) {
if(h->fd) {
# ifdef HAVE_OLDMSGHDR
if(recvfd == -1)
h->fd = -2;
else
h->fd = recvfd;
# else
if(passfd.fd == -1)
h->fd = -2;
else
h->fd = passfd.fd;
# endif
} else {
# ifdef HAVE_OLDMSGHDR
if(recvfd >= 0)
(void)close(recvfd);
# else
if(passfd.fd >= 0)
(void)close(passfd.fd);
# endif
h->fd = -1;
}
}
if((u_int)n < hdr_len)
return n;
if(h->bytes == 0)
return n;
if(h->bytes > *plen) {
*parg = xrealloc(*parg, h->bytes);
*plen = h->bytes;
}
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
# ifdef HAVE_OLDMSGHDR
msg.msg_accrights = NULL;
msg.msg_accrightslen = 0;
# else
msg.msg_control = NULL;
msg.msg_controllen = 0;
# endif
iov[0].iov_base = (caddr_t)*parg;
iov[0].iov_len = h->bytes;
if((n1 = recvmsg(fd, &msg, 0)) <= 0)
return n1;
*plen = n1;
return n + n1;
}
#endif
# ifdef TEST
# include <stdio.h>
# include <string.h>
# include <errno.h>
# include <fcntl.h>
# include <sys/stat.h>
int process(int argc, char *argv[]);
int
main(int argc, char *argv[])
{
int i, p[2];
pid_t pid;
if(strcmp(argv[0], "frame") == 0) {
/* sender */
for(i = 1; i < argc; i++)
if(strcmp(argv[i], "-") == 0)
break;
if(i == argc)
panic("missing arg delimiter");
if(socketpair(PF_UNIX, SOCK_STREAM, 0, p) == -1)
panic("socketpair: %s", strerror(errno));
# ifdef HAVE_STREAMS
ioctl(p[0], I_SRDOPT, RNORM);
ioctl(p[1], I_SRDOPT, RNORM);
# endif
if((pid = fork()) < 0)
panic("fork: %s", strerror(errno));
if(pid == 0) {
/* child */
(void)close(p[1]);
if(dup2(p[0], 0) == -1)
panic("dup2: %s", strerror(errno));
(void)close(p[0]);
argv[i] = "-frame";
argc -= i;
argv += i;
execv("frame", argv);
_exit(127);
}
(void)close(p[0]);
if(dup2(p[1], 1) == -1)
panic("dup2: %s", strerror(errno));
argv[i] = NULL;
argc = i;
return process(argc-1, argv+1);
} else {
/* receiver */
return process(argc-1, argv+1);
}
}
int
process(int argc, char *argv[])
{
struct {
struct hdr h;
u_int spare[3];
} hdr;
u_int data[1000];
int n, i;
u_int extlen;
void *ext;
struct stat statb;
for(i = 0; i < argc; i++) {
hdr.h.fd = 0;
ext = data;
extlen = sizeof(data);
if(strcmp(argv[i], "s") == 0) {
n = frame_write(1, &hdr, sizeof(hdr),
data, sizeof(data), 0);
if(n <= 0)
panic("write error: %s", strerror(errno));
if((u_int)n != hdr.h.bytes + sizeof(hdr))
panic("bad write: %d, %d", n, hdr.h.bytes +
sizeof(hdr));
} else if(strcmp(argv[i], "sf") == 0) {
hdr.h.fd = open("/dev/null", O_RDONLY);
n = framefd_write(1, &hdr, sizeof(hdr),
data, sizeof(data), 0);
if(n <= 0)
panic("write error: %s", strerror(errno));
if((u_int)n != hdr.h.bytes + sizeof(hdr))
panic("bad write: %d, %d", n, hdr.h.bytes +
sizeof(hdr));
} else if(strcmp(argv[i], "s0") == 0) {
hdr.h.fd = -1;
n = framefd_write(1, &hdr, sizeof(hdr),
data, sizeof(data), 0);
if(n <= 0)
panic("write error: %s", strerror(errno));
if((u_int)n != hdr.h.bytes + sizeof(hdr))
panic("bad write: %d, %d", n, hdr.h.bytes +
sizeof(hdr));
} else if(strcmp(argv[i], "r") == 0) {
n = frame_read(0, &hdr, sizeof(hdr),
&ext, &extlen);
if(n <= 0)
panic("read error: %s", strerror(errno));
if((u_int)n < sizeof(hdr))
panic("bad read: %d, %d", n, sizeof(hdr));
if((u_int)n != hdr.h.bytes + sizeof(hdr))
panic("bad read: %d, %d", n, sizeof(hdr) +
hdr.h.bytes);
printf("read: %u bytes\n", hdr.h.bytes);
} else if(strcmp(argv[i], "rf") == 0) {
n = framefd_read(0, &hdr, sizeof(hdr),
&ext, &extlen);
if(n <= 0)
panic("read error: %s", strerror(errno));
if((u_int)n < sizeof(hdr))
panic("bad read: %d, %d", n, sizeof(hdr));
if((u_int)n != hdr.h.bytes + sizeof(hdr))
panic("bad read: %d, %d", n, sizeof(hdr) +
hdr.h.bytes);
printf("read: %u bytes\n", hdr.h.bytes);
printf("fd: %d\n", hdr.h.fd);
if(hdr.h.fd >= 0) {
if(fstat(hdr.h.fd, &statb))
panic("fstat: %s", strerror(errno));
prstat(stdout, &statb);
}
} else
panic("bad key '%s'", argv[i]);
}
sleep(2);
return 0;
}
# endif
syntax highlighted by Code2HTML, v. 0.9.1