mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-02-02 12:30:24 +08:00
Cygwin: AF_UNIX: update tests
This commit is contained in:
parent
1b4df3a0be
commit
953308f403
@ -19,14 +19,15 @@ EXE = ud_ucase_sv ud_ucase_cl \
|
||||
fork_socketpair \
|
||||
select_sv select_cl \
|
||||
is_seqnum_v2_sv is_seqnum_v3_sv is_seqnum_v2_cl \
|
||||
send_pty_slave
|
||||
recv_pty_slave send_pty_slave
|
||||
|
||||
all:
|
||||
cd lib; ${MAKE}
|
||||
@ ${MAKE} ${EXE}
|
||||
all: ${EXE}
|
||||
|
||||
${EXE}: ${AF_UNIX_LIB} # True as a rough approximation
|
||||
|
||||
${AF_UNIX_LIB}:
|
||||
cd lib; ${MAKE}
|
||||
|
||||
*.o: ${AF_UNIX_HDR}
|
||||
|
||||
scm_cred_recv.o scm_cred_send.o: scm_cred.h
|
||||
@ -51,6 +52,8 @@ select_sv.o select_cl.o: select_test.h
|
||||
|
||||
is_seqnum_v2_sv.o is_seqnum_v3_sv.o is_seqnum_v2_cl.o: is_seqnum_v2.h
|
||||
|
||||
recv_pty_slave.o send_pty_slave.o: pty_slave.h
|
||||
|
||||
clean:
|
||||
cd lib; ${MAKE} clean
|
||||
${RM} *.exe *.o ${AF_UNIX_LIB}
|
||||
|
@ -192,10 +192,43 @@
|
||||
Sequence number: 0
|
||||
|
||||
11. Ancillary data test (SCM_RIGHTS, pty slave descriptor).
|
||||
send_pty_slave creates pty pair and a shell subprocess connected
|
||||
to the slave. It sends the slave descriptor over an AF_UNIX
|
||||
socket to recv_pty_slave. It then monitors its stdin and the pty
|
||||
master for input. Anything it reads from stdin is written to the
|
||||
pty master (and so read by the shell). Anything it reads from the
|
||||
pty master is written to stdout. This is normally just the shell
|
||||
output. But recv_pty_slave writes "hello" to the slave and so is
|
||||
read by send_pty_slave and written to stdout as though it were
|
||||
written by the shell.
|
||||
|
||||
In two terminals:
|
||||
|
||||
# Terminal 1:
|
||||
$ ./recv_pty_slave.exe
|
||||
Waiting for sender to connect and send descriptor...
|
||||
|
||||
# Terminal 2:
|
||||
$ ./send_pty_slave.exe
|
||||
parent sending descriptor 5 for /dev/pty3 to child
|
||||
child read 6 bytes (including newline) from fd 4: hello
|
||||
$ ./send_pty_slave.exe
|
||||
hello
|
||||
|
||||
TODO: Go through the above and check if all programs work with all
|
||||
options.
|
||||
#Terminal 1 now shows:
|
||||
$ ./recv_pty_slave.exe
|
||||
Waiting for sender to connect and send descriptor...
|
||||
Received descriptor 5.
|
||||
Writing "hello" to that descriptor.
|
||||
This should appear in the other terminal as though it were output by the shell.
|
||||
|
||||
Can now exit the shell in terminal 2.
|
||||
|
||||
To test all this when the pty is connected to a pseudo terminal,
|
||||
set SHELL=cmd before running send_pty_slave. Terminal 2 then
|
||||
looks like this:
|
||||
|
||||
$ SHELL=cmd ./send_pty_slave.exe
|
||||
hello
|
||||
Microsoft Windows [Version 10.0.18363.1256]
|
||||
(c) 2019 Microsoft Corporation. All rights reserved.
|
||||
|
||||
C:\Users\kbrown\src\cygdll\af_unix\winsup\cygwin\socket_tests>exit
|
||||
|
@ -4,7 +4,7 @@ AF_UNIX_LIB = ../libafunix.a
|
||||
|
||||
all: ${AF_UNIX_LIB}
|
||||
|
||||
${AF_UNIX_LIB}: *.c ename.c.inc
|
||||
${AF_UNIX_LIB}: *.c *.h ename.c.inc
|
||||
${CC} -c ${CFLAGS} *.c
|
||||
${RM} ${AF_UNIX_LIB}
|
||||
${AR} rs ${AF_UNIX_LIB} *.o
|
||||
|
117
winsup/cygwin/socket_tests/lib/pty_fork.c
Normal file
117
winsup/cygwin/socket_tests/lib/pty_fork.c
Normal file
@ -0,0 +1,117 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (C) Michael Kerrisk, 2018. *
|
||||
* *
|
||||
* This program is free software. You may use, modify, and redistribute it *
|
||||
* under the terms of the GNU Lesser 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 files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. *
|
||||
\*************************************************************************/
|
||||
|
||||
/* Listing 64-2 */
|
||||
|
||||
/* pty_fork.c
|
||||
|
||||
Implements ptyFork(), a function that creates a child process connected to
|
||||
the parent (i.e., the calling process) via a pseudoterminal (pty). The child
|
||||
is placed in a new session, with the pty slave as its controlling terminal,
|
||||
and its standard input, output, and error connected to the pty slave.
|
||||
|
||||
In the parent, 'masterFd' is used to return the file descriptor for the
|
||||
pty master.
|
||||
|
||||
If 'slaveName' is non-NULL, then it is used to return the name of the pty
|
||||
slave. If 'slaveName' is not NULL, then 'snLen' should be set to indicate
|
||||
the size of the buffer pointed to by 'slaveName'.
|
||||
|
||||
If 'slaveTermios' and 'slaveWS' are non-NULL, then they are used respectively
|
||||
to set the terminal attributes and window size of the pty slave.
|
||||
|
||||
Returns:
|
||||
in child: 0
|
||||
in parent: PID of child or -1 on error
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include "pty_master_open.h"
|
||||
#include "pty_fork.h" /* Declares ptyFork() */
|
||||
#include "af_unix_hdr.h"
|
||||
|
||||
#define MAX_SNAME 1000 /* Maximum size for pty slave name */
|
||||
|
||||
pid_t
|
||||
ptyFork(int *masterFd, char *slaveName, size_t snLen,
|
||||
const struct termios *slaveTermios, const struct winsize *slaveWS)
|
||||
{
|
||||
int mfd, slaveFd, savedErrno;
|
||||
pid_t childPid;
|
||||
char slname[MAX_SNAME];
|
||||
|
||||
mfd = ptyMasterOpen(slname, MAX_SNAME);
|
||||
if (mfd == -1)
|
||||
return -1;
|
||||
|
||||
if (slaveName != NULL) { /* Return slave name to caller */
|
||||
if (strlen(slname) < snLen) {
|
||||
strncpy(slaveName, slname, snLen);
|
||||
|
||||
} else { /* 'slaveName' was too small */
|
||||
close(mfd);
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
childPid = fork();
|
||||
|
||||
if (childPid == -1) { /* fork() failed */
|
||||
savedErrno = errno; /* close() might change 'errno' */
|
||||
close(mfd); /* Don't leak file descriptors */
|
||||
errno = savedErrno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (childPid != 0) { /* Parent */
|
||||
*masterFd = mfd; /* Only parent gets master fd */
|
||||
return childPid; /* Like parent of fork() */
|
||||
}
|
||||
|
||||
/* Child falls through to here */
|
||||
|
||||
if (setsid() == -1) /* Start a new session */
|
||||
err_exit("ptyFork:setsid");
|
||||
|
||||
close(mfd); /* Not needed in child */
|
||||
|
||||
slaveFd = open(slname, O_RDWR); /* Becomes controlling tty */
|
||||
if (slaveFd == -1)
|
||||
err_exit("ptyFork:open-slave");
|
||||
|
||||
/* #ifdef TIOCSCTTY /\* Acquire controlling tty on BSD *\/ */
|
||||
/* if (ioctl(slaveFd, TIOCSCTTY, 0) == -1) */
|
||||
/* err_exit("ptyFork:ioctl-TIOCSCTTY"); */
|
||||
/* #endif */
|
||||
|
||||
if (slaveTermios != NULL) /* Set slave tty attributes */
|
||||
if (tcsetattr(slaveFd, TCSANOW, slaveTermios) == -1)
|
||||
err_exit("ptyFork:tcsetattr");
|
||||
|
||||
if (slaveWS != NULL) /* Set slave tty window size */
|
||||
if (ioctl(slaveFd, TIOCSWINSZ, slaveWS) == -1)
|
||||
err_exit("ptyFork:ioctl-TIOCSWINSZ");
|
||||
|
||||
/* Duplicate pty slave to be child's stdin, stdout, and stderr */
|
||||
|
||||
if (dup2(slaveFd, STDIN_FILENO) != STDIN_FILENO)
|
||||
err_exit("ptyFork:dup2-STDIN_FILENO");
|
||||
if (dup2(slaveFd, STDOUT_FILENO) != STDOUT_FILENO)
|
||||
err_exit("ptyFork:dup2-STDOUT_FILENO");
|
||||
if (dup2(slaveFd, STDERR_FILENO) != STDERR_FILENO)
|
||||
err_exit("ptyFork:dup2-STDERR_FILENO");
|
||||
|
||||
if (slaveFd > STDERR_FILENO) /* Safety check */
|
||||
close(slaveFd); /* No longer need this fd */
|
||||
|
||||
return 0; /* Like child of fork() */
|
||||
}
|
27
winsup/cygwin/socket_tests/lib/pty_fork.h
Normal file
27
winsup/cygwin/socket_tests/lib/pty_fork.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (C) Michael Kerrisk, 2018. *
|
||||
* *
|
||||
* This program is free software. You may use, modify, and redistribute it *
|
||||
* under the terms of the GNU Lesser 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 files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. *
|
||||
\*************************************************************************/
|
||||
|
||||
/* Header file for Listing 64-2 */
|
||||
|
||||
/* pty_fork.h
|
||||
|
||||
Header file for pty_fork.c.
|
||||
*/
|
||||
#ifndef FORK_PTY_H
|
||||
#define FORK_PTY_H
|
||||
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
pid_t ptyFork(int *masterFd, char *slaveName, size_t snLen,
|
||||
const struct termios *slaveTermios, const struct winsize *slaveWS);
|
||||
|
||||
#endif
|
93
winsup/cygwin/socket_tests/lib/pty_master_open.c
Normal file
93
winsup/cygwin/socket_tests/lib/pty_master_open.c
Normal file
@ -0,0 +1,93 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (C) Michael Kerrisk, 2018. *
|
||||
* *
|
||||
* This program is free software. You may use, modify, and redistribute it *
|
||||
* under the terms of the GNU Lesser 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 files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. *
|
||||
\*************************************************************************/
|
||||
|
||||
/* Listing 64-1 */
|
||||
|
||||
/* pty_master_open.c
|
||||
|
||||
Implement our ptyMasterOpen() function, based on UNIX 98 pseudoterminals.
|
||||
See comments below.
|
||||
|
||||
See also pty_master_open_bsd.c.
|
||||
*/
|
||||
#if ! defined(__sun)
|
||||
/* Prevents ptsname() declaration being visible on Solaris 8 */
|
||||
#if ! defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < 600
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include "pty_master_open.h" /* Declares ptyMasterOpen() */
|
||||
#include "af_unix_hdr.h"
|
||||
|
||||
/* Some implementations don't have posix_openpt() */
|
||||
|
||||
#if defined(__sun) /* Not on Solaris 8 */
|
||||
#define NO_POSIX_OPENPT
|
||||
#endif
|
||||
|
||||
#ifdef NO_POSIX_OPENPT
|
||||
|
||||
static int
|
||||
posix_openpt(int flags)
|
||||
{
|
||||
return open("/dev/ptmx", flags);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Open a pty master, returning file descriptor, or -1 on error.
|
||||
On successful completion, the name of the corresponding pty
|
||||
slave is returned in 'slaveName'. 'snLen' should be set to
|
||||
indicate the size of the buffer pointed to by 'slaveName'. */
|
||||
|
||||
int
|
||||
ptyMasterOpen(char *slaveName, size_t snLen)
|
||||
{
|
||||
int masterFd, savedErrno;
|
||||
char *p;
|
||||
|
||||
masterFd = posix_openpt(O_RDWR | O_NOCTTY); /* Open pty master */
|
||||
if (masterFd == -1)
|
||||
return -1;
|
||||
|
||||
if (grantpt(masterFd) == -1) { /* Grant access to slave pty */
|
||||
savedErrno = errno;
|
||||
close(masterFd); /* Might change 'errno' */
|
||||
errno = savedErrno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (unlockpt(masterFd) == -1) { /* Unlock slave pty */
|
||||
savedErrno = errno;
|
||||
close(masterFd); /* Might change 'errno' */
|
||||
errno = savedErrno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = ptsname(masterFd); /* Get slave pty name */
|
||||
if (p == NULL) {
|
||||
savedErrno = errno;
|
||||
close(masterFd); /* Might change 'errno' */
|
||||
errno = savedErrno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strlen(p) < snLen) {
|
||||
strncpy(slaveName, p, snLen);
|
||||
} else { /* Return an error if buffer too small */
|
||||
close(masterFd);
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return masterFd;
|
||||
}
|
24
winsup/cygwin/socket_tests/lib/pty_master_open.h
Normal file
24
winsup/cygwin/socket_tests/lib/pty_master_open.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (C) Michael Kerrisk, 2018. *
|
||||
* *
|
||||
* This program is free software. You may use, modify, and redistribute it *
|
||||
* under the terms of the GNU Lesser 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 files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. *
|
||||
\*************************************************************************/
|
||||
|
||||
/* Header file for Listing 64-1 */
|
||||
|
||||
/* pty_open.h
|
||||
|
||||
Header file for pty_open.c (and pty_master_open_bsd.c).
|
||||
*/
|
||||
#ifndef PTY_MASTER_OPEN_H
|
||||
#define PTY_MASTER_OPEN_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
int ptyMasterOpen(char *slaveName, size_t snLen);
|
||||
|
||||
#endif
|
89
winsup/cygwin/socket_tests/lib/tty_functions.c
Normal file
89
winsup/cygwin/socket_tests/lib/tty_functions.c
Normal file
@ -0,0 +1,89 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (C) Michael Kerrisk, 2018. *
|
||||
* *
|
||||
* This program is free software. You may use, modify, and redistribute it *
|
||||
* under the terms of the GNU Lesser 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 files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. *
|
||||
\*************************************************************************/
|
||||
|
||||
/* Listing 62-3 */
|
||||
|
||||
/* tty_functions.c
|
||||
|
||||
Implement ttySetCbreak() and ttySetRaw().
|
||||
*/
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include "tty_functions.h" /* Declares functions defined here */
|
||||
|
||||
/* Place terminal referred to by 'fd' in cbreak mode (noncanonical mode
|
||||
with echoing turned off). This function assumes that the terminal is
|
||||
currently in cooked mode (i.e., we shouldn't call it if the terminal
|
||||
is currently in raw mode, since it does not undo all of the changes
|
||||
made by the ttySetRaw() function below). Return 0 on success, or -1
|
||||
on error. If 'prevTermios' is non-NULL, then use the buffer to which
|
||||
it points to return the previous terminal settings. */
|
||||
|
||||
int
|
||||
ttySetCbreak(int fd, struct termios *prevTermios)
|
||||
{
|
||||
struct termios t;
|
||||
|
||||
if (tcgetattr(fd, &t) == -1)
|
||||
return -1;
|
||||
|
||||
if (prevTermios != NULL)
|
||||
*prevTermios = t;
|
||||
|
||||
t.c_lflag &= ~(ICANON | ECHO);
|
||||
t.c_lflag |= ISIG;
|
||||
|
||||
t.c_iflag &= ~ICRNL;
|
||||
|
||||
t.c_cc[VMIN] = 1; /* Character-at-a-time input */
|
||||
t.c_cc[VTIME] = 0; /* with blocking */
|
||||
|
||||
if (tcsetattr(fd, TCSAFLUSH, &t) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Place terminal referred to by 'fd' in raw mode (noncanonical mode
|
||||
with all input and output processing disabled). Return 0 on success,
|
||||
or -1 on error. If 'prevTermios' is non-NULL, then use the buffer to
|
||||
which it points to return the previous terminal settings. */
|
||||
|
||||
int
|
||||
ttySetRaw(int fd, struct termios *prevTermios)
|
||||
{
|
||||
struct termios t;
|
||||
|
||||
if (tcgetattr(fd, &t) == -1)
|
||||
return -1;
|
||||
|
||||
if (prevTermios != NULL)
|
||||
*prevTermios = t;
|
||||
|
||||
t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO);
|
||||
/* Noncanonical mode, disable signals, extended
|
||||
input processing, and echoing */
|
||||
|
||||
t.c_iflag &= ~(BRKINT | ICRNL | IGNBRK | IGNCR | INLCR |
|
||||
INPCK | ISTRIP | IXON | PARMRK);
|
||||
/* Disable special handling of CR, NL, and BREAK.
|
||||
No 8th-bit stripping or parity error handling.
|
||||
Disable START/STOP output flow control. */
|
||||
|
||||
t.c_oflag &= ~OPOST; /* Disable all output processing */
|
||||
|
||||
t.c_cc[VMIN] = 1; /* Character-at-a-time input */
|
||||
t.c_cc[VTIME] = 0; /* with blocking */
|
||||
|
||||
if (tcsetattr(fd, TCSAFLUSH, &t) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
26
winsup/cygwin/socket_tests/lib/tty_functions.h
Normal file
26
winsup/cygwin/socket_tests/lib/tty_functions.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (C) Michael Kerrisk, 2018. *
|
||||
* *
|
||||
* This program is free software. You may use, modify, and redistribute it *
|
||||
* under the terms of the GNU Lesser 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 files COPYING.lgpl-v3 and COPYING.gpl-v3 for details. *
|
||||
\*************************************************************************/
|
||||
|
||||
/* Header file for Listing 62-3 */
|
||||
|
||||
/* tty_functions.h
|
||||
|
||||
Header file for tty_functions.c.
|
||||
*/
|
||||
#ifndef TTY_FUNCTIONS_H
|
||||
#define TTY_FUNCTIONS_H
|
||||
|
||||
#include <termios.h>
|
||||
|
||||
int ttySetCbreak(int fd, struct termios *prevTermios);
|
||||
|
||||
int ttySetRaw(int fd, struct termios *prevTermios);
|
||||
|
||||
#endif
|
46
winsup/cygwin/socket_tests/lib/unp.c.sav
Normal file
46
winsup/cygwin/socket_tests/lib/unp.c.sav
Normal file
@ -0,0 +1,46 @@
|
||||
/* Adapted from Steven, Unix Network Programming
|
||||
https://github.com/unpbook/unpv13e.git */
|
||||
|
||||
#include "af_unix_hdr.h"
|
||||
|
||||
ssize_t
|
||||
write_fd (int fd, void *ptr, size_t nbytes, int sendfd)
|
||||
{
|
||||
struct msghdr msg;
|
||||
struct iovec iov[1];
|
||||
|
||||
union {
|
||||
struct cmsghdr cm;
|
||||
char control[CMSG_SPACE(sizeof(int))];
|
||||
} control_un;
|
||||
struct cmsghdr *cmptr;
|
||||
|
||||
msg.msg_control = control_un.control;
|
||||
msg.msg_controllen = sizeof control_un.control;
|
||||
|
||||
cmptr = CMSG_FIRSTHDR (&msg);
|
||||
cmptr->cmsg_len = CMSG_LEN (sizeof (int));
|
||||
cmptr->cmsg_level = SOL_SOCKET;
|
||||
cmptr->cmsg_type = SCM_RIGHTS;
|
||||
*((int *) CMSG_DATA (cmptr)) = sendfd;
|
||||
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
|
||||
iov[0].iov_base = ptr;
|
||||
iov[0].iov_len = nbytes;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
return sendmsg (fd, &msg, 0);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
Write_fd (int fd, void *ptr, size_t nbytes, int sendfd)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
if ((n = write_fd (fd, ptr, nbytes, sendfd)) < 0)
|
||||
errExit ("write_fd");
|
||||
return n;
|
||||
}
|
322
winsup/cygwin/socket_tests/lib/unp.h.sav
Normal file
322
winsup/cygwin/socket_tests/lib/unp.h.sav
Normal file
@ -0,0 +1,322 @@
|
||||
/* Adapted from Steven, Unix Network Programming
|
||||
https://github.com/unpbook/unpv13e.git */
|
||||
|
||||
#ifndef __unp_h
|
||||
#define __unp_h
|
||||
|
||||
/* #include "../config.h" /\* configuration options for current OS *\/ */
|
||||
/* /\* "../config.h" is generated by configure *\/ */
|
||||
|
||||
/* If anything changes in the following list of #includes, must change
|
||||
acsite.m4 also, for configure's tests. */
|
||||
|
||||
#include <sys/types.h> /* basic system data types */
|
||||
#include <sys/socket.h> /* basic socket definitions */
|
||||
#include <sys/time.h> /* timeval{} for select() */
|
||||
#include <time.h> /* timespec{} for pselect() */
|
||||
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
|
||||
#include <arpa/inet.h> /* inet(3) functions */
|
||||
#include <errno.h>
|
||||
#include <fcntl.h> /* for nonblocking */
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h> /* for S_xxx file mode constants */
|
||||
#include <sys/uio.h> /* for iovec{} and readv/writev */
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/un.h> /* for Unix domain sockets */
|
||||
#include <sys/select.h> /* for convenience */
|
||||
#include <poll.h> /* for convenience */
|
||||
#include <strings.h> /* for convenience */
|
||||
#include <sys/ioctl.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/* The structure returned by recvfrom_flags() */
|
||||
struct unp_in_pktinfo {
|
||||
struct in_addr ipi_addr; /* dst IPv4 address */
|
||||
int ipi_ifindex;/* received interface index */
|
||||
};
|
||||
|
||||
/* POSIX requires that an #include of <poll.h> DefinE INFTIM, but many
|
||||
systems still DefinE it in <sys/stropts.h>. We don't want to include
|
||||
all the STREAMS stuff if it's not needed, so we just DefinE INFTIM here.
|
||||
This is the standard value, but there's no guarantee it is -1. */
|
||||
#ifndef INFTIM
|
||||
#define INFTIM (-1) /* infinite poll timeout */
|
||||
/* $$.Ic INFTIM$$ */
|
||||
#define INFTIM_UNPH /* tell unpxti.h we defined it */
|
||||
#endif
|
||||
|
||||
/* Following could be derived from SOMAXCONN in <sys/socket.h>, but many
|
||||
kernels still #define it as 5, while actually supporting many more */
|
||||
#define LISTENQ 1024 /* 2nd argument to listen() */
|
||||
|
||||
/* Miscellaneous constants */
|
||||
#define MAXLINE 4096 /* max text line length */
|
||||
#define BUFFSIZE 8192 /* buffer size for reads and writes */
|
||||
|
||||
/* Define some port number that can be used for our examples */
|
||||
#define SERV_PORT 9877 /* TCP and UDP */
|
||||
#define SERV_PORT_STR "9877" /* TCP and UDP */
|
||||
#define UNIXSTR_PATH "/tmp/unix.str" /* Unix domain stream */
|
||||
#define UNIXDG_PATH "/tmp/unix.dg" /* Unix domain datagram */
|
||||
|
||||
/* Following shortens all the typecasts of pointer arguments: */
|
||||
#define SA struct sockaddr
|
||||
|
||||
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
|
||||
/* default file access permissions for new files */
|
||||
#define DIR_MODE (FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH)
|
||||
/* default permissions for new directories */
|
||||
|
||||
typedef void Sigfunc(int); /* for signal handlers */
|
||||
|
||||
|
||||
/* prototypes for our own library functions */
|
||||
/* int connect_nonb(int, const SA *, socklen_t, int); */
|
||||
/* int connect_timeo(int, const SA *, socklen_t, int); */
|
||||
/* int daemon_init(const char *, int); */
|
||||
/* void daemon_inetd(const char *, int); */
|
||||
/* void dg_cli(FILE *, int, const SA *, socklen_t); */
|
||||
/* void dg_echo(int, SA *, socklen_t); */
|
||||
/* int family_to_level(int); */
|
||||
/* char *gf_time(void); */
|
||||
/* void heartbeat_cli(int, int, int); */
|
||||
/* void heartbeat_serv(int, int, int); */
|
||||
/* struct addrinfo *host_serv(const char *, const char *, int, int); */
|
||||
/* int inet_srcrt_add(char *); */
|
||||
/* u_char *inet_srcrt_init(int); */
|
||||
/* void inet_srcrt_print(u_char *, int); */
|
||||
/* void inet6_srcrt_print(void *); */
|
||||
/* char **my_addrs(int *); */
|
||||
/* int readable_timeo(int, int); */
|
||||
/* ssize_t readline(int, void *, size_t); */
|
||||
/* ssize_t readn(int, void *, size_t); */
|
||||
/* ssize_t read_fd(int, void *, size_t, int *); */
|
||||
/* ssize_t recvfrom_flags(int, void *, size_t, int *, SA *, socklen_t *, */
|
||||
/* struct unp_in_pktinfo *); */
|
||||
/* Sigfunc *signal_intr(int, Sigfunc *); */
|
||||
/* int sock_bind_wild(int, int); */
|
||||
/* int sock_cmp_addr(const SA *, const SA *, socklen_t); */
|
||||
/* int sock_cmp_port(const SA *, const SA *, socklen_t); */
|
||||
/* int sock_get_port(const SA *, socklen_t); */
|
||||
/* void sock_set_addr(SA *, socklen_t, const void *); */
|
||||
/* void sock_set_port(SA *, socklen_t, int); */
|
||||
/* void sock_set_wild(SA *, socklen_t); */
|
||||
/* char *sock_ntop(const SA *, socklen_t); */
|
||||
/* char *sock_ntop_host(const SA *, socklen_t); */
|
||||
/* int sockfd_to_family(int); */
|
||||
/* void str_echo(int); */
|
||||
/* void str_cli(FILE *, int); */
|
||||
/* int tcp_connect(const char *, const char *); */
|
||||
/* int tcp_listen(const char *, const char *, socklen_t *); */
|
||||
/* void tv_sub(struct timeval *, struct timeval *); */
|
||||
/* int udp_client(const char *, const char *, SA **, socklen_t *); */
|
||||
/* int udp_connect(const char *, const char *); */
|
||||
/* int udp_server(const char *, const char *, socklen_t *); */
|
||||
/* int writable_timeo(int, int); */
|
||||
/* ssize_t writen(int, const void *, size_t); */
|
||||
ssize_t write_fd(int, void *, size_t, int);
|
||||
|
||||
/* #ifdef MCAST */
|
||||
/* int mcast_leave(int, const SA *, socklen_t); */
|
||||
/* int mcast_join(int, const SA *, socklen_t, const char *, u_int); */
|
||||
/* int mcast_leave_source_group(int sockfd, const SA *src, socklen_t srclen, */
|
||||
/* const SA *grp, socklen_t grplen); */
|
||||
/* int mcast_join_source_group(int sockfd, const SA *src, socklen_t srclen, */
|
||||
/* const SA *grp, socklen_t grplen, */
|
||||
/* const char *ifname, u_int ifindex); */
|
||||
/* int mcast_block_source(int sockfd, const SA *src, socklen_t srclen, */
|
||||
/* const SA *grp, socklen_t grplen); */
|
||||
/* int mcast_unblock_source(int sockfd, const SA *src, socklen_t srclen, */
|
||||
/* const SA *grp, socklen_t grplen); */
|
||||
/* int mcast_get_if(int); */
|
||||
/* int mcast_get_loop(int); */
|
||||
/* int mcast_get_ttl(int); */
|
||||
/* int mcast_set_if(int, const char *, u_int); */
|
||||
/* int mcast_set_loop(int, int); */
|
||||
/* int mcast_set_ttl(int, int); */
|
||||
|
||||
/* void Mcast_leave(int, const SA *, socklen_t); */
|
||||
/* void Mcast_join(int, const SA *, socklen_t, const char *, u_int); */
|
||||
/* void Mcast_leave_source_group(int sockfd, const SA *src, socklen_t srclen, */
|
||||
/* const SA *grp, socklen_t grplen); */
|
||||
/* void Mcast_join_source_group(int sockfd, const SA *src, socklen_t srclen, */
|
||||
/* const SA *grp, socklen_t grplen, */
|
||||
/* const char *ifname, u_int ifindex); */
|
||||
/* void Mcast_block_source(int sockfd, const SA *src, socklen_t srclen, */
|
||||
/* const SA *grp, socklen_t grplen); */
|
||||
/* void Mcast_unblock_source(int sockfd, const SA *src, socklen_t srclen, */
|
||||
/* const SA *grp, socklen_t grplen); */
|
||||
/* int Mcast_get_if(int); */
|
||||
/* int Mcast_get_loop(int); */
|
||||
/* int Mcast_get_ttl(int); */
|
||||
/* void Mcast_set_if(int, const char *, u_int); */
|
||||
/* void Mcast_set_loop(int, int); */
|
||||
/* void Mcast_set_ttl(int, int); */
|
||||
/* #endif */
|
||||
|
||||
/* uint16_t in_cksum(uint16_t *, int); */
|
||||
|
||||
/* #ifndef HAVE_GETADDRINFO_PROTO */
|
||||
/* int getaddrinfo(const char *, const char *, const struct addrinfo *, */
|
||||
/* struct addrinfo **); */
|
||||
/* void freeaddrinfo(struct addrinfo *); */
|
||||
/* char *gai_strerror(int); */
|
||||
/* #endif */
|
||||
|
||||
/* #ifndef HAVE_GETNAMEINFO_PROTO */
|
||||
/* int getnameinfo(const SA *, socklen_t, char *, size_t, char *, size_t, int); */
|
||||
/* #endif */
|
||||
|
||||
/* #ifndef HAVE_GETHOSTNAME_PROTO */
|
||||
/* int gethostname(char *, int); */
|
||||
/* #endif */
|
||||
|
||||
/* #ifndef HAVE_HSTRERROR_PROTO */
|
||||
/* const char *hstrerror(int); */
|
||||
/* #endif */
|
||||
|
||||
/* #ifndef HAVE_IF_NAMETOINDEX_PROTO */
|
||||
/* unsigned int if_nametoindex(const char *); */
|
||||
/* char *if_indextoname(unsigned int, char *); */
|
||||
/* void if_freenameindex(struct if_nameindex *); */
|
||||
/* struct if_nameindex *if_nameindex(void); */
|
||||
/* #endif */
|
||||
|
||||
/* #ifndef HAVE_INET_PTON_PROTO */
|
||||
/* int inet_pton(int, const char *, void *); */
|
||||
/* const char *inet_ntop(int, const void *, char *, size_t); */
|
||||
/* #endif */
|
||||
|
||||
/* #ifndef HAVE_INET_ATON_PROTO */
|
||||
/* int inet_aton(const char *, struct in_addr *); */
|
||||
/* #endif */
|
||||
|
||||
/* #ifndef HAVE_PSELECT_PROTO */
|
||||
/* int pselect(int, fd_set *, fd_set *, fd_set *, */
|
||||
/* const struct timespec *, const sigset_t *); */
|
||||
/* #endif */
|
||||
|
||||
/* #ifndef HAVE_SOCKATMARK_PROTO */
|
||||
/* int sockatmark(int); */
|
||||
/* #endif */
|
||||
|
||||
/* #ifndef HAVE_SNPRINTF_PROTO */
|
||||
/* int snprintf(char *, size_t, const char *, ...); */
|
||||
/* #endif */
|
||||
|
||||
/* /\* prototypes for our own library wrapper functions *\/ */
|
||||
/* void Connect_timeo(int, const SA *, socklen_t, int); */
|
||||
/* int Family_to_level(int); */
|
||||
/* struct addrinfo *Host_serv(const char *, const char *, int, int); */
|
||||
/* const char *Inet_ntop(int, const void *, char *, size_t); */
|
||||
/* void Inet_pton(int, const char *, void *); */
|
||||
/* char *If_indextoname(unsigned int, char *); */
|
||||
/* unsigned int If_nametoindex(const char *); */
|
||||
/* struct if_nameindex *If_nameindex(void); */
|
||||
/* char **My_addrs(int *); */
|
||||
/* ssize_t Read_fd(int, void *, size_t, int *); */
|
||||
/* int Readable_timeo(int, int); */
|
||||
/* ssize_t Recvfrom_flags(int, void *, size_t, int *, SA *, socklen_t *, */
|
||||
/* struct unp_in_pktinfo *); */
|
||||
/* Sigfunc *Signal(int, Sigfunc *); */
|
||||
/* Sigfunc *Signal_intr(int, Sigfunc *); */
|
||||
/* int Sock_bind_wild(int, int); */
|
||||
/* char *Sock_ntop(const SA *, socklen_t); */
|
||||
/* char *Sock_ntop_host(const SA *, socklen_t); */
|
||||
/* int Sockfd_to_family(int); */
|
||||
/* int Tcp_connect(const char *, const char *); */
|
||||
/* int Tcp_listen(const char *, const char *, socklen_t *); */
|
||||
/* int Udp_client(const char *, const char *, SA **, socklen_t *); */
|
||||
/* int Udp_connect(const char *, const char *); */
|
||||
/* int Udp_server(const char *, const char *, socklen_t *); */
|
||||
ssize_t Write_fd(int, void *, size_t, int);
|
||||
/* int Writable_timeo(int, int); */
|
||||
|
||||
/* /\* prototypes for our Unix wrapper functions: see {Sec errors} *\/ */
|
||||
/* void *Calloc(size_t, size_t); */
|
||||
/* void Close(int); */
|
||||
/* void Dup2(int, int); */
|
||||
/* int Fcntl(int, int, int); */
|
||||
/* void Gettimeofday(struct timeval *, void *); */
|
||||
/* int Ioctl(int, int, void *); */
|
||||
/* pid_t Fork(void); */
|
||||
/* void *Malloc(size_t); */
|
||||
/* int Mkstemp(char *); */
|
||||
/* void *Mmap(void *, size_t, int, int, int, off_t); */
|
||||
/* int Open(const char *, int, mode_t); */
|
||||
/* void Pipe(int *fds); */
|
||||
/* ssize_t Read(int, void *, size_t); */
|
||||
/* void Sigaddset(sigset_t *, int); */
|
||||
/* void Sigdelset(sigset_t *, int); */
|
||||
/* void Sigemptyset(sigset_t *); */
|
||||
/* void Sigfillset(sigset_t *); */
|
||||
/* int Sigismember(const sigset_t *, int); */
|
||||
/* void Sigpending(sigset_t *); */
|
||||
/* void Sigprocmask(int, const sigset_t *, sigset_t *); */
|
||||
/* char *Strdup(const char *); */
|
||||
/* long Sysconf(int); */
|
||||
/* void Sysctl(int *, u_int, void *, size_t *, void *, size_t); */
|
||||
/* void Unlink(const char *); */
|
||||
/* pid_t Wait(int *); */
|
||||
/* pid_t Waitpid(pid_t, int *, int); */
|
||||
/* void Write(int, void *, size_t); */
|
||||
|
||||
/* /\* prototypes for our stdio wrapper functions: see {Sec errors} *\/ */
|
||||
/* void Fclose(FILE *); */
|
||||
/* FILE *Fdopen(int, const char *); */
|
||||
/* char *Fgets(char *, int, FILE *); */
|
||||
/* FILE *Fopen(const char *, const char *); */
|
||||
/* void Fputs(const char *, FILE *); */
|
||||
|
||||
/* /\* prototypes for our socket wrapper functions: see {Sec errors} *\/ */
|
||||
/* int Accept(int, SA *, socklen_t *); */
|
||||
/* void Bind(int, const SA *, socklen_t); */
|
||||
/* void Connect(int, const SA *, socklen_t); */
|
||||
/* void Getpeername(int, SA *, socklen_t *); */
|
||||
/* void Getsockname(int, SA *, socklen_t *); */
|
||||
/* void Getsockopt(int, int, int, void *, socklen_t *); */
|
||||
/* #ifdef HAVE_INET6_RTH_INIT */
|
||||
/* int Inet6_rth_space(int, int); */
|
||||
/* void *Inet6_rth_init(void *, socklen_t, int, int); */
|
||||
/* void Inet6_rth_add(void *, const struct in6_addr *); */
|
||||
/* void Inet6_rth_reverse(const void *, void *); */
|
||||
/* int Inet6_rth_segments(const void *); */
|
||||
/* struct in6_addr *Inet6_rth_getaddr(const void *, int); */
|
||||
/* #endif */
|
||||
/* #ifdef HAVE_KQUEUE */
|
||||
/* int Kqueue(void); */
|
||||
/* int Kevent(int, const struct kevent *, int, */
|
||||
/* struct kevent *, int, const struct timespec *); */
|
||||
/* #endif */
|
||||
/* void Listen(int, int); */
|
||||
/* #ifdef HAVE_POLL */
|
||||
/* int Poll(struct pollfd *, unsigned long, int); */
|
||||
/* #endif */
|
||||
/* ssize_t Readline(int, void *, size_t); */
|
||||
/* ssize_t Readn(int, void *, size_t); */
|
||||
/* ssize_t Recv(int, void *, size_t, int); */
|
||||
/* ssize_t Recvfrom(int, void *, size_t, int, SA *, socklen_t *); */
|
||||
/* ssize_t Recvmsg(int, struct msghdr *, int); */
|
||||
/* int Select(int, fd_set *, fd_set *, fd_set *, struct timeval *); */
|
||||
/* void Send(int, const void *, size_t, int); */
|
||||
/* void Sendto(int, const void *, size_t, int, const SA *, socklen_t); */
|
||||
/* void Sendmsg(int, const struct msghdr *, int); */
|
||||
/* void Setsockopt(int, int, int, const void *, socklen_t); */
|
||||
/* void Shutdown(int, int); */
|
||||
/* int Sockatmark(int); */
|
||||
/* int Socket(int, int, int); */
|
||||
/* void Socketpair(int, int, int, int *); */
|
||||
/* void Writen(int, void *, size_t); */
|
||||
|
||||
/* void err_dump(const char *, ...); */
|
||||
/* void err_msg(const char *, ...); */
|
||||
/* void err_quit(const char *, ...); */
|
||||
/* void err_ret(const char *, ...); */
|
||||
/* void err_sys(const char *, ...); */
|
||||
|
||||
#endif /* __unp_h */
|
5
winsup/cygwin/socket_tests/pty_slave.h
Normal file
5
winsup/cygwin/socket_tests/pty_slave.h
Normal file
@ -0,0 +1,5 @@
|
||||
/* pty_slave.h
|
||||
|
||||
Header file for send_pty_slave.c and recv_pty_slave.c
|
||||
*/
|
||||
#define SOCK_PATH "/tmp/pty_slave"
|
3
winsup/cygwin/socket_tests/rec_pty_slave.c
Normal file
3
winsup/cygwin/socket_tests/rec_pty_slave.c
Normal file
@ -0,0 +1,3 @@
|
||||
#include "af_unix_hdr.h"
|
||||
#include "pty_slave.h"
|
||||
|
37
winsup/cygwin/socket_tests/recv_pty_slave.c
Normal file
37
winsup/cygwin/socket_tests/recv_pty_slave.c
Normal file
@ -0,0 +1,37 @@
|
||||
#include "af_unix_hdr.h"
|
||||
#include "pty_slave.h"
|
||||
#define BUF_SIZE 100
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int lfd, connfd, ptyfd;
|
||||
|
||||
if (remove (SOCK_PATH) == -1 && errno != ENOENT)
|
||||
errExit ("remove-%s", SOCK_PATH);
|
||||
|
||||
lfd = unixBind (SOCK_PATH, SOCK_STREAM);
|
||||
if (lfd < 0)
|
||||
errExit ("unixBind");
|
||||
printf ("Waiting for sender to connect and send descriptor...\n");
|
||||
if (listen (lfd, 5) < 0)
|
||||
errExit ("listen");
|
||||
connfd = accept (lfd, NULL, NULL);
|
||||
if (connfd < 0)
|
||||
errExit ("accept");
|
||||
ptyfd = recvfd (connfd);
|
||||
if (ptyfd < 0)
|
||||
errExit ("recvfd");
|
||||
printf ("Received descriptor %d.\n", ptyfd);
|
||||
printf ("Writing \"hello\" to that descriptor.\n"
|
||||
"This should appear in the other terminal "
|
||||
"as though it were output by the shell.\n");
|
||||
if (write (ptyfd, "hello\n", 6) != 6)
|
||||
errExit ("write");
|
||||
if (close (ptyfd) < 0)
|
||||
errMsg ("close");
|
||||
if (close (lfd) < 0)
|
||||
errMsg ("close");
|
||||
if (close (connfd) < 0)
|
||||
errMsg ("close");
|
||||
}
|
144
winsup/cygwin/socket_tests/send_pty_slave.c
Normal file
144
winsup/cygwin/socket_tests/send_pty_slave.c
Normal file
@ -0,0 +1,144 @@
|
||||
/* Adapted from Kerrisk's script.c by Ken Brown */
|
||||
|
||||
/*
|
||||
Create a pty pair and fork/exec a shell running on the slave. Send
|
||||
the slave fd across an AF_UNIX socket to a process running
|
||||
recv_pty_slave.
|
||||
*/
|
||||
|
||||
/*************************************************************************\
|
||||
* 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. *
|
||||
\*************************************************************************/
|
||||
|
||||
/* Listing 64-3 */
|
||||
|
||||
/* script.c
|
||||
|
||||
A simple version of script(1).
|
||||
*/
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <termios.h>
|
||||
#if ! defined(__hpux)
|
||||
/* HP-UX 11 doesn't have this header file */
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
#include "pty_fork.h" /* Declaration of ptyFork() */
|
||||
#include "tty_functions.h" /* Declaration of ttySetRaw() */
|
||||
#include "af_unix_hdr.h"
|
||||
#include "pty_slave.h"
|
||||
|
||||
#define BUF_SIZE 256
|
||||
#define MAX_SNAME 1000
|
||||
|
||||
struct termios ttyOrig;
|
||||
|
||||
static void /* Reset terminal mode on program exit */
|
||||
ttyReset(void)
|
||||
{
|
||||
if (tcsetattr(STDIN_FILENO, TCSANOW, &ttyOrig) == -1)
|
||||
errExit("tcsetattr");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char slaveName[MAX_SNAME];
|
||||
char *shell;
|
||||
int masterFd, slaveFd, connFd;
|
||||
struct winsize ws;
|
||||
fd_set inFds;
|
||||
char buf[BUF_SIZE];
|
||||
ssize_t numRead;
|
||||
pid_t childPid;
|
||||
|
||||
/* Retrieve the attributes of terminal on which we are started */
|
||||
|
||||
if (tcgetattr(STDIN_FILENO, &ttyOrig) == -1)
|
||||
errExit("tcgetattr");
|
||||
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0)
|
||||
errExit("ioctl-TIOCGWINSZ");
|
||||
|
||||
/* Create a child process, with parent and child connected via a
|
||||
pty pair. The child is connected to the pty slave and its terminal
|
||||
attributes are set to be the same as those retrieved above. */
|
||||
|
||||
childPid = ptyFork(&masterFd, slaveName, MAX_SNAME, &ttyOrig, &ws);
|
||||
if (childPid == -1)
|
||||
errExit("ptyFork");
|
||||
|
||||
if (childPid == 0) { /* Child: execute a shell on pty slave */
|
||||
|
||||
/* If the SHELL variable is set, use its value to determine
|
||||
the shell execed in child. Otherwise use /bin/sh. */
|
||||
|
||||
shell = getenv("SHELL");
|
||||
if (shell == NULL || *shell == '\0')
|
||||
shell = "/bin/sh";
|
||||
|
||||
execlp(shell, shell, (char *) NULL);
|
||||
errExit("execlp"); /* If we get here, something went wrong */
|
||||
}
|
||||
|
||||
/* Parent */
|
||||
|
||||
if ((connFd = unixConnect (SOCK_PATH, SOCK_STREAM)) < 0)
|
||||
errExit ("unixConnect");
|
||||
|
||||
/* Open slave and send its fd across the socket. */
|
||||
if ((slaveFd = open (slaveName, O_RDWR | O_NOCTTY)) < 0)
|
||||
errExit ("open");
|
||||
if (sendfd (connFd, slaveFd) < 0)
|
||||
errExit ("sendfd");
|
||||
if (close (slaveFd) < 0)
|
||||
errMsg ("close");
|
||||
if (close (connFd) < 0)
|
||||
errMsg ("close");
|
||||
|
||||
/* Place terminal in raw mode so that we can pass all terminal
|
||||
input to the pseudoterminal master untouched */
|
||||
|
||||
ttySetRaw(STDIN_FILENO, &ttyOrig);
|
||||
|
||||
if (atexit(ttyReset) != 0)
|
||||
errExit("atexit");
|
||||
|
||||
/* Loop monitoring terminal and pty master for input. If the
|
||||
terminal is ready for input, then read some bytes and write
|
||||
them to the pty master. If the pty master is ready for input,
|
||||
then read some bytes and write them to the terminal. */
|
||||
|
||||
for (;;) {
|
||||
FD_ZERO(&inFds);
|
||||
FD_SET(STDIN_FILENO, &inFds);
|
||||
FD_SET(masterFd, &inFds);
|
||||
|
||||
if (select(masterFd + 1, &inFds, NULL, NULL, NULL) == -1)
|
||||
errExit("select");
|
||||
|
||||
if (FD_ISSET(STDIN_FILENO, &inFds)) { /* stdin --> pty */
|
||||
numRead = read(STDIN_FILENO, buf, BUF_SIZE);
|
||||
if (numRead <= 0)
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
if (write(masterFd, buf, numRead) != numRead)
|
||||
fatal("partial/failed write (masterFd)");
|
||||
}
|
||||
|
||||
if (FD_ISSET(masterFd, &inFds)) { /* pty --> stdout */
|
||||
numRead = read(masterFd, buf, BUF_SIZE);
|
||||
if (numRead <= 0)
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
if (write(STDOUT_FILENO, buf, numRead) != numRead)
|
||||
fatal("partial/failed write (STDOUT_FILENO)");
|
||||
}
|
||||
}
|
||||
}
|
102
winsup/cygwin/socket_tests/send_pty_slave_fork.c
Normal file
102
winsup/cygwin/socket_tests/send_pty_slave_fork.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
Fork a subprocess, open a pty pair, and send the pty slave file
|
||||
descriptor to the subprocess over an AF_UNIX socket. Invoke with
|
||||
--debug to allow time to attach gdb to the child.
|
||||
*/
|
||||
|
||||
#include "af_unix_hdr.h"
|
||||
#include "pty_master_open.h"
|
||||
#include "read_line.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#define BUF_SIZE 100
|
||||
#define MAX_SNAME 100 /* Maximum size for pty slave name */
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
Boolean debug = FALSE;
|
||||
pid_t pid;
|
||||
int pipefd[2];
|
||||
int pfd; /* parent's end */
|
||||
int cfd; /* child's end */
|
||||
|
||||
if (argc > 1 && strcmp (argv[1], "--debug") == 0)
|
||||
debug = TRUE;
|
||||
|
||||
if (socketpair (AF_UNIX, SOCK_STREAM, 0, pipefd) < 0)
|
||||
errExit ("socketpair");
|
||||
pfd = pipefd[1];
|
||||
cfd = pipefd[0];
|
||||
|
||||
if ((pid = fork ()) < 0)
|
||||
errExit ("fork");
|
||||
else if (pid > 0) /* parent */
|
||||
{
|
||||
int mfd, sfd, junk;
|
||||
char slname[MAX_SNAME];
|
||||
|
||||
if (close (cfd) < 0)
|
||||
errExit ("close");
|
||||
if ((mfd = ptyMasterOpen (slname, MAX_SNAME)) < 0)
|
||||
errExit ("ptyMasterOpen");
|
||||
if ((sfd = open (slname, O_RDWR | O_NOCTTY)) < 0)
|
||||
errExit ("open");
|
||||
if (debug)
|
||||
{
|
||||
printf ("parent pid %d, child pid %d, sleeping...\n", getpid (), pid);
|
||||
sleep (30);
|
||||
}
|
||||
|
||||
printf ("parent sending descriptor %d for %s to child\n", sfd, slname);
|
||||
if (sendfd (pfd, sfd) < 0)
|
||||
errExit ("sendfd");
|
||||
if (close (sfd) < 0)
|
||||
errMsg ("close");
|
||||
if (write (mfd, "hello\n", 6) < 0)
|
||||
errExit ("write");
|
||||
/* Wait for child. */
|
||||
if (read (pfd, &junk, sizeof junk) != sizeof junk)
|
||||
errMsg ("read");
|
||||
if (close (pfd) < 0)
|
||||
errMsg ("close");
|
||||
if (close (mfd) < 0)
|
||||
errMsg ("close");
|
||||
}
|
||||
else /* child */
|
||||
{
|
||||
int fd, junk;
|
||||
ssize_t nr;
|
||||
char buf[BUF_SIZE];
|
||||
|
||||
if (close (pfd) < 0)
|
||||
errExit ("close");
|
||||
if (debug)
|
||||
sleep (30);
|
||||
|
||||
/* Read fd from parent. */
|
||||
fd = recvfd (cfd);
|
||||
if (fd < 0)
|
||||
errExit ("recvfd");
|
||||
|
||||
/* Read a line from fd. */
|
||||
if ((nr = readLine (fd, buf, BUF_SIZE)) < 0)
|
||||
{
|
||||
close (fd);
|
||||
errExit ("readLine");
|
||||
}
|
||||
|
||||
/* Kill newline. */
|
||||
buf[nr - 1] = '\0';
|
||||
printf ("child read %zd bytes (including newline) from fd %d: %s\n", nr,
|
||||
fd, buf);
|
||||
if (close (fd) == -1)
|
||||
errMsg ("close");
|
||||
/* Tell parent we're done. */
|
||||
if (write (cfd, &junk, sizeof junk) != sizeof junk)
|
||||
errMsg ("write");
|
||||
if (close (cfd) < 0)
|
||||
errExit ("close");
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user