mirror of
https://repo.or.cz/socat.git
synced 2024-12-23 15:52:33 +00:00
187 lines
5 KiB
C
187 lines
5 KiB
C
|
/* $Id$ */
|
||
|
/* Copyright Gerhard Rieger 2007 */
|
||
|
/* Published under the GNU General Public License V.2, see file COPYING */
|
||
|
|
||
|
/* this is the source of the internal xiosocketpair function */
|
||
|
|
||
|
#include "xiosysincludes.h"
|
||
|
#include "sycls.h"
|
||
|
#include "error.h"
|
||
|
#include "xio.h"
|
||
|
|
||
|
#if defined(HAVE_DEV_PTMX)
|
||
|
# define PTMX "/dev/ptmx" /* Linux */
|
||
|
#elif HAVE_DEV_PTC
|
||
|
# define PTMX "/dev/ptc" /* AIX */
|
||
|
#endif
|
||
|
|
||
|
#define MAXPTYNAMELEN 64
|
||
|
|
||
|
/* how: 0...socketpair; 1...pipes pair; 2...pty (master, slave)
|
||
|
how==0: var args (int)domain, (int)type, (int)protocol
|
||
|
how==1: no var args
|
||
|
how==2: var args (int)useptmx
|
||
|
returns -1 on error or 0 on success */
|
||
|
|
||
|
int xiosocketpair(xiofile_t **xfd1p, xiofile_t **xfd2p, int how, ...) {
|
||
|
va_list ap;
|
||
|
xiofile_t *xfd1, *xfd2;
|
||
|
int result = 0;
|
||
|
|
||
|
if ((xfd1 = xioallocfd()) == NULL) {
|
||
|
return -1;
|
||
|
}
|
||
|
if ((xfd2 = xioallocfd()) == NULL) {
|
||
|
xiofreefd(xfd1);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
switch (how) {
|
||
|
case 0: /* socketpair */
|
||
|
{
|
||
|
int sv[2];
|
||
|
int domain, type, protocol;
|
||
|
|
||
|
va_start(ap, how);
|
||
|
domain = va_arg(ap, int);
|
||
|
type = va_arg(ap, int);
|
||
|
protocol = va_arg(ap, int);
|
||
|
va_end(ap);
|
||
|
if (Socketpair(domain, type, protocol, sv) < 0) {
|
||
|
Error5("socketpair(%d, %d, %d, %p): %s",
|
||
|
domain, type, protocol, sv, strerror(errno));
|
||
|
xiofreefd(xfd1); xiofreefd(xfd2);
|
||
|
return -1;
|
||
|
}
|
||
|
assert(xfd1->stream.fdtype == FDTYPE_SINGLE);
|
||
|
xfd1->stream.fd1 = sv[0];
|
||
|
assert(xfd2->stream.fdtype == FDTYPE_SINGLE);
|
||
|
xfd2->stream.fd1 = sv[1];
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 1:
|
||
|
{
|
||
|
int filedes1[2], filedes2[2];
|
||
|
if (Pipe(filedes1) < 0) {
|
||
|
Error2("pipe(%p): %s", filedes1, strerror(errno));
|
||
|
xiofreefd(xfd1); xiofreefd(xfd2);
|
||
|
return -1;
|
||
|
}
|
||
|
if (Pipe(filedes2) < 0) {
|
||
|
Error2("pipe(%p): %s", filedes2, strerror(errno));
|
||
|
xiofreefd(xfd1); xiofreefd(xfd2);
|
||
|
Close(filedes1[0]); Close(filedes1[1]);
|
||
|
return -1;
|
||
|
}
|
||
|
xfd1->stream.fd1 = filedes1[0];
|
||
|
xfd1->stream.fd2 = filedes2[1];
|
||
|
xfd1->stream.fdtype = FDTYPE_DOUBLE;
|
||
|
xfd1->stream.dtype = XIODATA_2PIPE;
|
||
|
xfd2->stream.fd1 = filedes2[0];
|
||
|
xfd2->stream.fd2 = filedes1[1];
|
||
|
xfd2->stream.fdtype = FDTYPE_DOUBLE;
|
||
|
xfd2->stream.dtype = XIODATA_2PIPE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
#if HAVE_DEV_PTMX || HAVE_DEV_PTC
|
||
|
case 2: /* pty (master, slave) */
|
||
|
{
|
||
|
int useptmx;
|
||
|
char ptyname[MAXPTYNAMELEN];
|
||
|
int ptyfd = -1, ttyfd;
|
||
|
|
||
|
va_start(ap, how);
|
||
|
useptmx = va_arg(ap, int);
|
||
|
va_end(ap);
|
||
|
|
||
|
if (useptmx) {
|
||
|
if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) {
|
||
|
Warn1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620): %s",
|
||
|
strerror(errno));
|
||
|
/*!*/
|
||
|
} else {
|
||
|
;/*0 Info1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620) -> %d", ptyfd);*/
|
||
|
}
|
||
|
if (ptyfd >= 0) {
|
||
|
char *tn = NULL;
|
||
|
|
||
|
/* we used PTMX before forking */
|
||
|
/*0 extern char *ptsname(int);*/
|
||
|
#if HAVE_GRANTPT /* AIX, not Linux */
|
||
|
if (Grantpt(ptyfd)/*!*/ < 0) {
|
||
|
Warn2("grantpt(%d): %s", ptyfd, strerror(errno));
|
||
|
}
|
||
|
#endif /* HAVE_GRANTPT */
|
||
|
#if HAVE_UNLOCKPT
|
||
|
if (Unlockpt(ptyfd)/*!*/ < 0) {
|
||
|
Warn2("unlockpt(%d): %s", ptyfd, strerror(errno));
|
||
|
}
|
||
|
#endif /* HAVE_UNLOCKPT */
|
||
|
#if HAVE_PTSNAME /* AIX, not Linux */
|
||
|
if ((tn = Ptsname(ptyfd)) == NULL) {
|
||
|
Warn2("ptsname(%d): %s", ptyfd, strerror(errno));
|
||
|
} else {
|
||
|
Notice1("PTY is %s", tn);
|
||
|
}
|
||
|
#endif /* HAVE_PTSNAME */
|
||
|
#if 0
|
||
|
if (tn == NULL) {
|
||
|
/*! ttyname_r() */
|
||
|
if ((tn = Ttyname(ptyfd)) == NULL) {
|
||
|
Warn2("ttyname(%d): %s", ptyfd, strerror(errno));
|
||
|
}
|
||
|
}
|
||
|
strncpy(ptyname, tn, MAXPTYNAMELEN);
|
||
|
#endif
|
||
|
if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) {
|
||
|
Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno));
|
||
|
} else {
|
||
|
/*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", tn, ttyfd);*/
|
||
|
}
|
||
|
|
||
|
#ifdef I_PUSH
|
||
|
/* Linux: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> -1 EINVAL */
|
||
|
/* AIX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 1 */
|
||
|
/* SunOS: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
|
||
|
/* HP-UX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
|
||
|
if (Ioctl(ttyfd, I_FIND, "ldterm") == 0) {
|
||
|
Ioctl(ttyfd, I_PUSH, "ptem"); /* 0 */
|
||
|
Ioctl(ttyfd, I_PUSH, "ldterm"); /* 0 */
|
||
|
Ioctl(ttyfd, I_PUSH, "ttcompat"); /* HP-UX: -1 */
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
#if HAVE_OPENPTY
|
||
|
if (ptyfd < 0) {
|
||
|
int result;
|
||
|
if ((result = Openpty(&ptyfd, &ttyfd, ptyname, NULL, NULL)) < 0) {
|
||
|
Error4("openpty(%p, %p, %p, NULL, NULL): %s",
|
||
|
&ptyfd, &ttyfd, ptyname, strerror(errno));
|
||
|
return -1;
|
||
|
}
|
||
|
Notice1("PTY is %s", ptyname);
|
||
|
}
|
||
|
#endif /* HAVE_OPENPTY */
|
||
|
assert(xfd1->stream.fdtype == FDTYPE_SINGLE);
|
||
|
xfd1->stream.fd1 = ttyfd;
|
||
|
assert(xfd2->stream.fdtype == FDTYPE_SINGLE);
|
||
|
xfd2->stream.fd1 = ptyfd;
|
||
|
}
|
||
|
break;
|
||
|
#endif /* HAVE_DEV_PTMX || HAVE_DEV_PTC */
|
||
|
|
||
|
default:
|
||
|
Error1("undefined socketpair mechanism %d", how);
|
||
|
xiofreefd(xfd1); xiofreefd(xfd2);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
*xfd1p = xfd1;
|
||
|
*xfd2p = xfd2;
|
||
|
return 0;
|
||
|
}
|
||
|
|