mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-02-08 18:19:08 +08:00
170 lines
5.2 KiB
C
170 lines
5.2 KiB
C
/*************************************************************************\
|
|
* Copyright (C) Michael Kerrisk, 2018. *
|
|
* *
|
|
* This program is free software. You may use, modify, and redistribute it *
|
|
* under the terms of the GNU General Public License as published by the *
|
|
* Free Software Foundation, either version 3 or (at your option) any *
|
|
* later version. This program is distributed without any warranty. See *
|
|
* the file COPYING.gpl-v3 for details. *
|
|
\*************************************************************************/
|
|
|
|
/* Supplementary program for Chapter 61 */
|
|
|
|
/* scm_rights_recv.c
|
|
|
|
Used in conjunction with scm_rights_send.c to demonstrate passing of
|
|
file descriptors via a UNIX domain socket.
|
|
|
|
This program receives a file descriptor sent to a UNIX domain socket.
|
|
|
|
Usage is as shown in the usageErr() call below.
|
|
|
|
File descriptors can be exchanged over stream or datagram sockets. This
|
|
program uses stream sockets by default; the "-d" command-line option
|
|
specifies that datagram sockets should be used instead.
|
|
|
|
This program is Linux-specific.
|
|
|
|
See also scm_multi_recv.c.
|
|
*/
|
|
#include "scm_rights.h"
|
|
|
|
#define BUF_SIZE 100
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int data, lfd, sfd, fd, opt;
|
|
ssize_t nr;
|
|
Boolean useDatagramSocket;
|
|
struct msghdr msgh;
|
|
struct iovec iov;
|
|
|
|
/* Allocate a char array of suitable size to hold the ancillary data.
|
|
However, since this buffer is in reality a 'struct cmsghdr', use a
|
|
union to ensure that it is aligned as required for that structure.
|
|
Alternatively, we could allocate the buffer using malloc(), which
|
|
returns a buffer that satisfies the strictest alignment
|
|
requirements of any type */
|
|
|
|
union {
|
|
char buf[CMSG_SPACE(sizeof(int))];
|
|
/* Space large enough to hold an 'int' */
|
|
struct cmsghdr align;
|
|
} controlMsg;
|
|
struct cmsghdr *cmsgp; /* Pointer used to iterate through
|
|
headers in ancillary data */
|
|
|
|
/* Parse command-line options */
|
|
|
|
useDatagramSocket = FALSE;
|
|
|
|
while ((opt = getopt(argc, argv, "d")) != -1) {
|
|
switch (opt) {
|
|
case 'd':
|
|
useDatagramSocket = TRUE;
|
|
break;
|
|
|
|
default:
|
|
usageErr("%s [-d]\n"
|
|
" -d use datagram socket\n", argv[0]);
|
|
}
|
|
}
|
|
|
|
/* Create socket bound to a well-known address. In the case where
|
|
we are using stream sockets, also make the socket a listening
|
|
socket and accept a connection on the socket. */
|
|
|
|
if (remove(SOCK_PATH) == -1 && errno != ENOENT)
|
|
errExit("remove-%s", SOCK_PATH);
|
|
|
|
if (useDatagramSocket) {
|
|
sfd = unixBind(SOCK_PATH, SOCK_DGRAM);
|
|
if (sfd == -1)
|
|
errExit("unixBind");
|
|
|
|
} else {
|
|
lfd = unixBind(SOCK_PATH, SOCK_STREAM);
|
|
if (lfd == -1)
|
|
errExit("unixBind");
|
|
|
|
if (listen(lfd, 5) == -1)
|
|
errExit("listen");
|
|
|
|
sfd = accept(lfd, NULL, NULL);
|
|
if (sfd == -1)
|
|
errExit("accept");
|
|
}
|
|
|
|
/* The 'msg_name' field can be set to point to a buffer where the
|
|
kernel will place the address of the peer socket. However, we don't
|
|
need the address of the peer, so we set this field to NULL. */
|
|
|
|
msgh.msg_name = NULL;
|
|
msgh.msg_namelen = 0;
|
|
|
|
/* Set fields of 'msgh' to point to buffer used to receive the (real)
|
|
data read by recvmsg() */
|
|
|
|
msgh.msg_iov = &iov;
|
|
msgh.msg_iovlen = 1;
|
|
iov.iov_base = &data;
|
|
iov.iov_len = sizeof(int);
|
|
|
|
/* Set 'msgh' fields to describe the ancillary data buffer */
|
|
|
|
msgh.msg_control = controlMsg.buf;
|
|
msgh.msg_controllen = sizeof(controlMsg.buf);
|
|
|
|
/* Receive real plus ancillary data */
|
|
|
|
nr = recvmsg(sfd, &msgh, 0);
|
|
if (nr == -1)
|
|
errExit("recvmsg");
|
|
fprintf(stderr, "recvmsg() returned %ld\n", (long) nr);
|
|
|
|
if (nr > 0)
|
|
fprintf(stderr, "Received data = %d\n", data);
|
|
|
|
/* Get the address of the first 'cmsghdr' in the received
|
|
ancillary data */
|
|
|
|
cmsgp = CMSG_FIRSTHDR(&msgh);
|
|
|
|
/* Check the validity of the 'cmsghdr' */
|
|
|
|
if (cmsgp == NULL || cmsgp->cmsg_len != CMSG_LEN(sizeof(int)))
|
|
fatal("bad cmsg header / message length");
|
|
if (cmsgp->cmsg_level != SOL_SOCKET)
|
|
fatal("cmsg_level != SOL_SOCKET");
|
|
if (cmsgp->cmsg_type != SCM_RIGHTS)
|
|
fatal("cmsg_type != SCM_RIGHTS");
|
|
|
|
/* The data area of the 'cmsghdr' is an 'int', so assign
|
|
the address of the data area to a suitable pointer. The data
|
|
is the received file descriptor (which is typically a different
|
|
file descriptor number than was used in the sending process). */
|
|
|
|
fd = *((int *) CMSG_DATA(cmsgp));
|
|
fprintf(stderr, "Received FD %d\n", fd);
|
|
|
|
/* Having obtained the file descriptor, read the file's contents and
|
|
print them on standard output */
|
|
|
|
for (;;) {
|
|
char buf[BUF_SIZE];
|
|
ssize_t numRead;
|
|
|
|
numRead = read(fd, buf, BUF_SIZE);
|
|
if (numRead == -1)
|
|
errExit("read");
|
|
|
|
if (numRead == 0)
|
|
break;
|
|
|
|
write(STDOUT_FILENO, buf, numRead);
|
|
}
|
|
|
|
exit(EXIT_SUCCESS);
|
|
}
|