Here are two programs. They both fork two clients that try to connect on
port 'portno' that is listened to in main(). It spawns a receive that
receives passed file descriptors passed from main(). It passes a file
descriptor of the client connection to receive twice. server_sample0.c uses
the man page code. server_sample.c uses my example. the former fails to
pass the file descriptor on the second try. the latter succeeds both times.
I don't think you have any more questions.
-Luke
On Sat, Apr 1, 2017 at 12:40 AM, Otto Moerbeek <[email protected]> wrote:
> On Fri, Mar 31, 2017 at 06:51:44PM +0000, Luke Small wrote:
>
> > I'm not asking for help. I'm suggesting a change to the man page. This
> code
> > performs the tasks performed in the existing examples better. The code on
> > the man page fails if you perform it a second time. This code works when
> > you do it twice. So if you use this code with one process sittting on a
> > port, listening for socket connections and it sends those file
> descriptors
> > to multiple processes, my examples will work and the existing one won't.
>
> You still do not say *what* is going wrong and how you observe that.
> Be explicit.
>
> When I made the man page example code, I tested it. Various daemons
> in OpenBSD use the same idiom. But if I find some time, I'll test it
> with you scenario: using the code to send muliple fd's.
>
> -Otto
>
> >
> > On Fri, Mar 31, 2017 at 11:07 AM Otto Moerbeek <[email protected]> wrote:
> >
> > On Fri, Mar 31, 2017 at 07:45:31AM +0000, Luke Small wrote:
> >
> > > I found the code from
> > > http://www.techdeviancy.com/uds.html, but there are many references to
> > code
> > > like this on google with the line:
> > > "message_buffer[0] = 'F';".
> > >
> > > I made an amalgamation of that code and the EXAMPLE section of
> > CMSG_DATA(3):
> > >
> > > EXAMPLES
> > > The following example constructs a control message containing a file
> > > descriptor and passes it over a socket:
> > >
> > > struct msghdr msg;
> > > struct iovec io_vector[1];
> > > struct cmsghdr *cmsg;
> > > char message_buffer[1];
> > > char ancillary_buffer[CMSG_SPACE(sizeof(int))];
> > >
> > > /*
> > > * at least one vector of one byte must be
> > > * sent or successive reads will fail.
> > > */
> > > message_buffer[0] = 'F';
> > > io_vector[0].iov_base = message_buffer;
> > > io_vector[0].iov_len = 1;
> > >
> > > memset(&msg, 0, sizeof(struct msghdr));
> > > msg.msg_iov = io_vector;
> > > msg.msg_iovlen = 1;
> > > memset(ancillary_buffer, 0, CMSG_SPACE(sizeof(int)));
> > > msg.msg_control = ancillary_buffer;
> > > msg.msg_controllen = CMSG_SPACE(sizeof(int));
> > >
> > > cmsg = CMSG_FIRSTHDR(&msg);
> > > cmsg->cmsg_level = SOL_SOCKET;
> > > cmsg->cmsg_type = SCM_RIGHTS;
> > > cmsg->cmsg_len = CMSG_LEN(sizeof(int));
> > > *((int *) CMSG_DATA(cmsg)) = fd;
> > >
> > > if (sendmsg(socket, &msg, 0) == -1)
> > > err(1, "sendmsg");
> > >
> > > And an example that receives and decomposes the control message:
> > >
> > > struct msghdr msg;
> > > struct cmsghdr *cmsg;
> > > struct iovec io_vector[1];
> > > char message_buffer[1];
> > > char ancillary_buffer[CMSG_SPACE(sizeof(int))];
> > >
> > > memset(&msg, 0, sizeof(struct msghdr));
> > > memset(ancillary_buffer, 0, CMSG_SPACE(sizeof(int)));
> > > io_vector[0].iov_base = message_buffer;
> > > io_vector[0].iov_len = 1;
> > > msg.msg_iov = io_vector;
> > > msg.msg_iovlen = 1;
> > > msg.msg_control = ancillary_buffer;
> > > msg.msg_controllen = CMSG_SPACE(sizeof(int));
> > >
> > > if (recvmsg(socket, &msg, 0) == -1)
> > > err(1, "recvmsg");
> > > if (message_buffer[0] != 'F')
> > > errx(1, "corrupted message");
> > > if ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC))
> > > errx(1, "control message truncated");
> > > for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
> > > cmsg = CMSG_NXTHDR(&msg, cmsg)) {
> > > if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) &&
> > > cmsg->cmsg_level == SOL_SOCKET &&
> > > cmsg->cmsg_type == SCM_RIGHTS) {
> > > fd = *((int *) CMSG_DATA(cmsg));
> > > /* Do something with the descriptor. */
> > > }
> > > }
> > >
> > >
> > >
> > >
> > > On Fri, Mar 31, 2017 at 12:03 AM Theo de Raadt <[email protected]>
> > wrote:
> > >
> > > > This is not a "i want help" group.
> > > >
> > > > If you have a diff, you can try submitting it.
> > > >
> > > > If you don't, your questions come off very false.
> > > >
> >
> > If you want help, this is not the right mailing list. This list is for
> > bug reports.
> >
> > And if you send stuff to anoyther mailing list show real, complete
> > example code demonstrating your problem, including a description of
> > expected and observed behaviour.
> >
> > -Otto
>
#include <err.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
int portno = 8004;
/* called to send a socket connection request to port "portno" */
int client()
{
int pid;
switch (pid = fork()) {
case -1:
err(1, "cannot fork");
break;
case 0:
break;
default:
return (pid);
}
setvbuf(stdout, NULL, _IOLBF, 0);
setvbuf(stderr, NULL, _IOLBF, 0);
int sockfd;
struct sockaddr_in serv_addr;
struct hostent *server;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
err(1, "ERROR opening socket");
server = gethostbyname("localhost");
if (server == NULL)
err(1, "ERROR, no such host\n");
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
err(1,"ERROR connecting to %d\n", portno);
//~ close(sockfd);
sleep(1);
_exit(0);
}
/* sends socket file descriptors generated by client() requests from main */
/* to here twice over socket "s"*/
int receive(int s[2])
{
int pid;
switch (pid = fork()) {
case -1:
err(1, "cannot fork");
break;
case 0:
break;
default:
return (pid);
}
setvbuf(stdout, NULL, _IOLBF, 0);
setvbuf(stderr, NULL, _IOLBF, 0);
close(s[1]);
int fd = -1;
struct msghdr msg;
struct cmsghdr *cmsg;
struct iovec io_vector[1];
char message_buffer[1];
char ancillary_buffer[CMSG_SPACE(sizeof(int))];
/* start clean */
cmsg = NULL;
memset(&msg, 0, sizeof(struct msghdr));
memset(ancillary_buffer, 0, CMSG_SPACE(sizeof(int)));
/* setup a place to fill in message contents */
io_vector[0].iov_base = message_buffer;
io_vector[0].iov_len = 1;
msg.msg_iov = io_vector;
msg.msg_iovlen = 1;
/* provide space for the ancillary data */
msg.msg_control = ancillary_buffer;
msg.msg_controllen = CMSG_SPACE(sizeof(int));
if(recvmsg(s[0], &msg, MSG_CMSG_CLOEXEC) < 0)
err(1, "recvmsg");
if(message_buffer[0] != 'F')
errx(1, "message != F");
if ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC))
errx(1, "control message truncated");
cmsg = CMSG_FIRSTHDR(&msg);
//~ if((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SCM_RIGHTS))
if( cmsg != NULL )
{
fd = *((int *) CMSG_DATA(cmsg));
printf("fd == %d\n", fd);
close(fd);
}
else
printf("cmsg == NULL\n");
/* do it again */
fd = -1;
/* start clean */
cmsg = NULL;
memset(&msg, 0, sizeof(struct msghdr));
memset(ancillary_buffer, 0, CMSG_SPACE(sizeof(int)));
/* setup a place to fill in message contents */
io_vector[0].iov_base = message_buffer;
io_vector[0].iov_len = 1;
msg.msg_iov = io_vector;
msg.msg_iovlen = 1;
/* provide space for the ancillary data */
msg.msg_control = ancillary_buffer;
msg.msg_controllen = CMSG_SPACE(sizeof(int));
if(recvmsg(s[0], &msg, MSG_CMSG_CLOEXEC) < 0)
err(1, "recvmsg");
if(message_buffer[0] != 'F')
errx(1, "message != F");
if ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC))
errx(1, "control message truncated");
cmsg = CMSG_FIRSTHDR(&msg);
//~ if((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SCM_RIGHTS))
if( cmsg != NULL )
{
fd = *((int *) CMSG_DATA(cmsg));
printf("fd == %d\n", fd);
close(fd);
}
else
printf("cmsg == NULL\n");
sleep(1);
close(s[0]);
_exit(0);
}
int main()
{
setvbuf(stdout, NULL, _IOLBF, 0);
setvbuf(stderr, NULL, _IOLBF, 0);
int s[2];
int sockfd, newsockfd;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
err(1, "ERROR opening socket");
//~ int yes = 1;
//~ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) {
//~ perror("setsockopt");
//~ return 1;
//~ }
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0)
err(1, "ERROR on binding on %d", portno);
if (listen(sockfd,2) == -1)
err(1, "listen failed");
clilen = sizeof(cli_addr);
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s) == -1)
err(1, "socketpair");
receive(s);
close(s[0]);
client();
newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &clilen);
struct msghdr msg;
struct iovec io_vector[1];
struct cmsghdr *cmsg = NULL;
char message_buffer[1];
/* storage space needed for an ancillary element with a payload of length
is CMSG_SPACE(sizeof(length)) */
char ancillary_element_buffer[CMSG_SPACE(sizeof(int))];
int available_ancillary_buffer_space;
/* at least one vector of one byte must be sent */
message_buffer[0] = 'F';
io_vector[0].iov_base = message_buffer;
io_vector[0].iov_len = 1;
/* initialize socket message */
memset(&msg, 0, sizeof(struct msghdr));
msg.msg_iov = io_vector;
msg.msg_iovlen = 1;
/* provide space for the ancillary data */
available_ancillary_buffer_space = CMSG_SPACE(sizeof(int));
memset(ancillary_element_buffer, 0, available_ancillary_buffer_space);
msg.msg_control = ancillary_element_buffer;
msg.msg_controllen = available_ancillary_buffer_space;
/* initialize a single ancillary data element for fd passing */
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
*((int *) CMSG_DATA(cmsg)) = newsockfd;
if (sendmsg(s[1], &msg, 0) == -1)
err(1, "sendmsg");
close(newsockfd);
client();
newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &clilen);
/* at least one vector of one byte must be sent */
message_buffer[0] = 'F';
io_vector[0].iov_base = message_buffer;
io_vector[0].iov_len = 1;
/* initialize socket message */
memset(&msg, 0, sizeof(struct msghdr));
msg.msg_iov = io_vector;
msg.msg_iovlen = 1;
/* provide space for the ancillary data */
available_ancillary_buffer_space = CMSG_SPACE(sizeof(int));
memset(ancillary_element_buffer, 0, available_ancillary_buffer_space);
msg.msg_control = ancillary_element_buffer;
msg.msg_controllen = available_ancillary_buffer_space;
/* initialize a single ancillary data element for fd passing */
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
*((int *) CMSG_DATA(cmsg)) = newsockfd;
if (sendmsg(s[1], &msg, 0) == -1)
err(1, "sendmsg");
close(newsockfd);
wait(NULL);
wait(NULL);
wait(NULL);
printf("done\n");
shutdown(sockfd, SHUT_RDWR);
close(sockfd);
return 0;
}
#include <err.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
int portno = 8002;
/* called to send a socket connection request to port "portno" */
int client()
{
int pid;
switch (pid = fork()) {
case -1:
err(1, "cannot fork");
break;
case 0:
break;
default:
return (pid);
}
setvbuf(stdout, NULL, _IOLBF, 0);
setvbuf(stderr, NULL, _IOLBF, 0);
int sockfd;
struct sockaddr_in serv_addr;
struct hostent *server;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
err(1, "ERROR opening socket");
server = gethostbyname("localhost");
if (server == NULL)
err(1, "ERROR, no such host\n");
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
err(1,"ERROR connecting to %d\n", portno);
//~ close(sockfd);
sleep(1);
_exit(0);
}
/* sends socket file descriptors generated by client() requests from main */
/* to here twice over socket "s"*/
int receive(int s[2])
{
int pid;
switch (pid = fork()) {
case -1:
err(1, "cannot fork");
break;
case 0:
break;
default:
return (pid);
}
setvbuf(stdout, NULL, _IOLBF, 0);
setvbuf(stderr, NULL, _IOLBF, 0);
int fd = -1;
close(s[1]);
struct msghdr msg;
struct cmsghdr *cmsg;
union {
struct cmsghdr hdr;
unsigned char buf[CMSG_SPACE(sizeof(int))];
} cmsgbuf;
memset(&msg, 0, sizeof(msg));
msg.msg_control = &cmsgbuf.buf;
msg.msg_controllen = sizeof(cmsgbuf.buf);
if (recvmsg(s[0], &msg, 0) == -1)
err(1, "recvmsg");
if ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC))
errx(1, "control message truncated");
cmsg = CMSG_FIRSTHDR(&msg);
if (cmsg != NULL)
{
if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) &&
cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_RIGHTS) {
fd = *(int *)CMSG_DATA(cmsg);
close(fd);
}
printf("fd == %d\n", fd);
}
else
printf("cmsg == NULL\n");
/* do it again */
fd = -1;
memset(&msg, 0, sizeof(msg));
msg.msg_control = &cmsgbuf.buf;
msg.msg_controllen = sizeof(cmsgbuf.buf);
if (recvmsg(s[0], &msg, 0) == -1)
err(1, "recvmsg");
if ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC))
errx(1, "control message truncated");
cmsg = CMSG_FIRSTHDR(&msg);
if (cmsg != NULL)
{
if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) &&
cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_RIGHTS) {
fd = *(int *)CMSG_DATA(cmsg);
close(fd);
}
printf("fd == %d\n", fd);
}
else
printf("cmsg == NULL\n");
sleep(1);
_exit(0);
}
int main()
{
setvbuf(stdout, NULL, _IOLBF, 0);
setvbuf(stderr, NULL, _IOLBF, 0);
int s[2];
int sockfd, newsockfd;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
err(1, "ERROR opening socket");
//~ int yes = 1;
//~ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) {
//~ perror("setsockopt");
//~ return 1;
//~ }
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0)
err(1, "ERROR on binding on %d", portno);
if (listen(sockfd,100000) == -1)
err(1, "listen failed");
clilen = sizeof(cli_addr);
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s) == -1)
err(1, "socketpair");
receive(s);
close(s[0]);
client();
newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &clilen);
struct msghdr msg;
struct cmsghdr *cmsg;
union {
struct cmsghdr hdr;
unsigned char buf[CMSG_SPACE(sizeof(int))];
} cmsgbuf;
memset(&msg, 0, sizeof(msg));
msg.msg_control = &cmsgbuf.buf;
msg.msg_controllen = sizeof(cmsgbuf.buf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*(int *)CMSG_DATA(cmsg) = newsockfd;
if (sendmsg(s[1], &msg, 0) == -1)
err(1, "sendmsg");
close(newsockfd);
client();
newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &clilen);
memset(&msg, 0, sizeof(msg));
msg.msg_control = &cmsgbuf.buf;
msg.msg_controllen = sizeof(cmsgbuf.buf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*(int *)CMSG_DATA(cmsg) = newsockfd;
if (sendmsg(s[1], &msg, 0) == -1)
err(1, "sendmsg");
close(newsockfd);
wait(NULL);
wait(NULL);
wait(NULL);
printf("done\n");
shutdown(sockfd, SHUT_RDWR);
close(sockfd);
return 0;
}