mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-02-08 18:19:08 +08:00
139 lines
4.4 KiB
C
139 lines
4.4 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_send.c
|
|
|
|
Used in conjunction with scm_rights_recv.c to demonstrate passing of
|
|
file descriptors via a UNIX domain socket.
|
|
|
|
This program sends a file descriptor 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"
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int data, sfd, opt, fd;
|
|
ssize_t ns;
|
|
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] file\n"
|
|
" -d use datagram socket\n", argv[0]);
|
|
}
|
|
}
|
|
|
|
if (argc != optind + 1)
|
|
usageErr("%s [-d] file\n", argv[0]);
|
|
|
|
/* Open the file named on the command line */
|
|
|
|
fd = open(argv[optind], O_RDONLY);
|
|
if (fd == -1)
|
|
errExit("open");
|
|
|
|
/* The 'msg_name' field can be used to specify the address of the
|
|
destination socket when sending a datagram. However, we do not
|
|
need to use this field because we use connect() below, which sets
|
|
a default outgoing address for datagrams. */
|
|
|
|
msgh.msg_name = NULL;
|
|
msgh.msg_namelen = 0;
|
|
|
|
/* On Linux, we must transmit at least 1 byte of real data in
|
|
order to send ancillary data */
|
|
|
|
msgh.msg_iov = &iov;
|
|
msgh.msg_iovlen = 1;
|
|
iov.iov_base = &data;
|
|
iov.iov_len = sizeof(int);
|
|
data = 12345;
|
|
fprintf(stderr, "Sending data = %d\n", data);
|
|
|
|
/* Set 'msgh' fields to describe the ancillary data buffer */
|
|
|
|
msgh.msg_control = controlMsg.buf;
|
|
msgh.msg_controllen = sizeof(controlMsg.buf);
|
|
|
|
/* The control message buffer must be zero-initialized in order
|
|
for the CMSG_NXTHDR() macro to work correctly. Although we
|
|
don't need to use CMSG_NXTHDR() in this example (because
|
|
there is only one block of ancillary data), we show this
|
|
step to demonstrate best practice */
|
|
|
|
memset(controlMsg.buf, 0, sizeof(controlMsg.buf));
|
|
|
|
/* Set message header to describe the ancillary data that
|
|
we want to send */
|
|
|
|
cmsgp = CMSG_FIRSTHDR(&msgh);
|
|
cmsgp->cmsg_len = CMSG_LEN(sizeof(int));
|
|
cmsgp->cmsg_level = SOL_SOCKET;
|
|
cmsgp->cmsg_type = SCM_RIGHTS;
|
|
*((int *) CMSG_DATA(cmsgp)) = fd;
|
|
|
|
/* Connect to the peer socket */
|
|
|
|
sfd = unixConnect(SOCK_PATH, useDatagramSocket ? SOCK_DGRAM : SOCK_STREAM);
|
|
if (sfd == -1)
|
|
errExit("unixConnect");
|
|
|
|
fprintf(stderr, "Sending FD %d\n", fd);
|
|
|
|
/* Send real plus ancillary data */
|
|
|
|
ns = sendmsg(sfd, &msgh, 0);
|
|
if (ns == -1)
|
|
errExit("sendmsg");
|
|
|
|
fprintf(stderr, "sendmsg() returned %ld\n", (long) ns);
|
|
|
|
exit(EXIT_SUCCESS);
|
|
}
|