socat/xiosocketpair.c
2008-02-17 14:59:16 +01:00

186 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;
}