mirror of
https://github.com/moparisthebest/socat
synced 2024-12-21 22:48:48 -05:00
added address options: ioctl-void, ioctl-int, ioctl-intp, ioctl-bin, ioctl-string
added option types: TYPE_INT_INT, TYPE_INT_BIN, TYPE_INT_STRING added syscall wrapper: Ioctl_int() added test: IOCTL_VOID
This commit is contained in:
parent
d70b8963aa
commit
2c2508fc62
4
CHANGES
4
CHANGES
@ -1,4 +1,8 @@
|
||||
|
||||
new features:
|
||||
added address options IOCTL-VOID, IOCTL-INT, IOCTL-INTP, IOCTL-STRING,
|
||||
IOCTL-BIN for generic ioctl() calls.
|
||||
|
||||
corrections:
|
||||
some raw IP and UNIX datagram modes failed on BSD systems
|
||||
|
||||
|
6
EXAMPLES
6
EXAMPLES
@ -285,6 +285,12 @@ $ socat -d -d -d -d - udp-datagram:224.0.0.2:6666,bind=:6666,ip-add-membership=2
|
||||
// packets leave via wrong interface (set route: ...)
|
||||
// socket bound to specific address
|
||||
|
||||
//=============================================================================
|
||||
// IOCTL
|
||||
|
||||
// open CD drive (given value valid on Linux)
|
||||
$ socat /dev/cdrom,o-nonblock,ioctl-void=0x5309 -
|
||||
|
||||
===============================================================================
|
||||
|
||||
// not tested, just ideas, or have problems
|
||||
|
2
VERSION
2
VERSION
@ -1 +1 @@
|
||||
"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock"
|
||||
"1.6.0.1+ip4bind+recvfromfork+x64+execstderr+execspaces+cosmetics+poll+udplistencont+ignoreeofunblock+ioctl"
|
||||
|
12
sycls.c
12
sycls.c
@ -1,5 +1,5 @@
|
||||
/* source: sycls.c */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Copyright Gerhard Rieger 2001-2008 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* explicit system call and C library trace function, for those who miss strace
|
||||
@ -593,6 +593,16 @@ int Ioctl(int d, int request, void *argp) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
int Ioctl_int(int d, int request, int arg) {
|
||||
int retval, _errno;
|
||||
Debug3("ioctl(%d, 0x%x, %d)", d, request, arg);
|
||||
retval = ioctl(d, request, arg);
|
||||
_errno = errno;
|
||||
Debug1("ioctl() -> %d", retval);
|
||||
errno = _errno;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int Close(int fd) {
|
||||
int retval, _errno;
|
||||
Info1("close(%d)", fd);
|
||||
|
4
sycls.h
4
sycls.h
@ -1,5 +1,5 @@
|
||||
/* source: sycls.h */
|
||||
/* Copyright Gerhard Rieger 2001-2007 */
|
||||
/* Copyright Gerhard Rieger 2001-2008 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __sycls_h_included
|
||||
@ -64,6 +64,7 @@ int Ftruncate64(int fd, off64_t length);
|
||||
#endif /* HAVE_FTRUNCATE64 */
|
||||
int Flock(int fd, int operation);
|
||||
int Ioctl(int d, int request, void *argp);
|
||||
int Ioctl_int(int d, int request, int arg);
|
||||
int Close(int fd);
|
||||
int Fchown(int fd, uid_t owner, gid_t group);
|
||||
int Fchmod(int fd, mode_t mode);
|
||||
@ -195,6 +196,7 @@ void Add_history(const char *string);
|
||||
#define Ftruncate64(f,l) ftruncate64(f,l)
|
||||
#define Flock(f,o) flock(f,o)
|
||||
#define Ioctl(d,r,a) ioctl(d,r,a)
|
||||
#define Ioctl_int(d,r,a) ioctl(d,r,a)
|
||||
#define Close(f) close(f)
|
||||
#define Fchown(f,o,g) fchown(f,o,g)
|
||||
#define Fchmod(f,m) fchmod(f,m)
|
||||
|
58
test.sh
58
test.sh
@ -8447,6 +8447,64 @@ esac
|
||||
N=$((N+1))
|
||||
|
||||
|
||||
# test the generic ioctl-void option
|
||||
NAME=IOCTL_VOID
|
||||
case "$TESTS" in
|
||||
*%functions%*|*%ip4%*|*%udp%*|*%dgram%*|*%$NAME%*)
|
||||
TEST="$NAME: test the ioctl-void option"
|
||||
# there are not many ioctls that apply to non global resources and do not
|
||||
# require root. TIOCEXCL seems to fit:
|
||||
# process 0 provides a pty;
|
||||
# process 1 opens it with the TIOCEXCL ioctl;
|
||||
# process 2 opens it too and fails with "device or resource busy" only when the
|
||||
# previous ioctl was successful
|
||||
if [ "$UNAME" != Linux ]; then
|
||||
# we need access to more loopback addresses
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}only on Linux${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
else
|
||||
tp="$td/test$N.pty"
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="$(date)"
|
||||
CMD0="$SOCAT $opts PTY,LINK=$tp pipe"
|
||||
CMD1="$SOCAT $opts - file:$tp,ioctl-void=0x540c,raw,echo=0"
|
||||
CMD2="$SOCAT $opts - file:$tp,raw,echo=0"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD0 >/dev/null 2>"${te}0" &
|
||||
pid0=$!
|
||||
waitfile $tp 1
|
||||
(echo "$da"; sleep 2) |$CMD1 >"$tf" 2>"${te}1" & # this should always work
|
||||
pid1=$!
|
||||
usleep 1000000
|
||||
$CMD2 >/dev/null 2>"${te}2" </dev/null
|
||||
rc2=$?
|
||||
kill $pid0 $pid1 2>/dev/null; wait
|
||||
if ! echo "$da" |diff - "$tf"; then
|
||||
$PRINTF "${YELLOW}phase 1 failed{NORMAL}\n"
|
||||
echo "$CMD0 &"
|
||||
echo "$CMD1"
|
||||
numCANT=$((numCANT+1))
|
||||
elif [ $rc2 -eq 0 ]; then
|
||||
$PRINTF "$FAILED: $SOCAT:\n"
|
||||
echo "$CMD0 &"
|
||||
echo "$CMD1"
|
||||
echo "$CMD2"
|
||||
cat "${te}0" "${te}1" "${te}2"
|
||||
numFAIL=$((numFAIL+1))
|
||||
else
|
||||
$PRINTF "$OK\n"
|
||||
if [ -n "$debug" ]; then cat "${te}0" "${te}1" "${te}2"; fi
|
||||
numOK=$((numOK+1))
|
||||
fi
|
||||
fi # !Linux
|
||||
;;
|
||||
esac
|
||||
PORT=$((PORT+1))
|
||||
N=$((N+1))
|
||||
|
||||
|
||||
echo "summary: $((N-1)) tests; $numOK ok, $numFAIL failed, $numCANT could not be performed"
|
||||
|
||||
if [ "$numFAIL" -gt 0 ]; then
|
||||
|
9
xio-fd.c
9
xio-fd.c
@ -1,5 +1,5 @@
|
||||
/* source: xio-fd.c */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* Copyright Gerhard Rieger 2001-2008 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this file contains common file descriptor related option definitions */
|
||||
@ -75,3 +75,10 @@ const struct optdesc opt_cool_write = { "cool-write", "coolwrite", OPT_COOL_WRIT
|
||||
|
||||
/* control closing of connections */
|
||||
const struct optdesc opt_end_close = { "end-close", "close", OPT_END_CLOSE, GROUP_FD, PH_INIT, TYPE_CONST, OFUNC_OFFSET, (bool)&((xiofile_t *)0)->stream.howtoend, END_CLOSE };
|
||||
|
||||
/****** generic ioctl() options ******/
|
||||
const struct optdesc opt_ioctl_void = { "ioctl-void", "ioctl", OPT_IOCTL_VOID, GROUP_FD, PH_FD, TYPE_INT, OFUNC_SPEC, 0, 0, 0 };
|
||||
const struct optdesc opt_ioctl_int = { "ioctl-int", NULL, OPT_IOCTL_INT, GROUP_FD, PH_FD, TYPE_INT_INT, OFUNC_SPEC, 0, 0, 0 };
|
||||
const struct optdesc opt_ioctl_intp = { "ioctl-intp", NULL, OPT_IOCTL_INTP, GROUP_FD, PH_FD, TYPE_INT_INT, OFUNC_SPEC, 0, 0, 0 };
|
||||
const struct optdesc opt_ioctl_bin = { "ioctl-bin", NULL, OPT_IOCTL_BIN, GROUP_FD, PH_FD, TYPE_INT_BIN, OFUNC_SPEC, 0, 0, 0 };
|
||||
const struct optdesc opt_ioctl_string = { "ioctl-string",NULL, OPT_IOCTL_STRING,GROUP_FD, PH_FD, TYPE_INT_STRING,OFUNC_SPEC, 0, 0, 0 };
|
||||
|
7
xio-fd.h
7
xio-fd.h
@ -1,10 +1,15 @@
|
||||
/* source: xio-fd.h */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* Copyright Gerhard Rieger 2001-2008 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
#ifndef __xio_fd_h_included
|
||||
#define __xio_fd_h_included 1
|
||||
|
||||
extern const struct optdesc opt_ioctl_void;
|
||||
extern const struct optdesc opt_ioctl_int;
|
||||
extern const struct optdesc opt_ioctl_intp;
|
||||
extern const struct optdesc opt_ioctl_bin;
|
||||
extern const struct optdesc opt_ioctl_string;
|
||||
extern const struct optdesc opt_append;
|
||||
extern const struct optdesc opt_nonblock;
|
||||
extern const struct optdesc opt_o_ndelay;
|
||||
|
1
xio.h
1
xio.h
@ -355,6 +355,7 @@ union integral {
|
||||
struct opt {
|
||||
const struct optdesc *desc;
|
||||
union integral value;
|
||||
union integral value2;
|
||||
} ;
|
||||
|
||||
extern const char *PIPESEP;
|
||||
|
@ -29,6 +29,7 @@ static const char *optiontypenames[] = {
|
||||
"STRUCT-IP_MREQ",
|
||||
#endif
|
||||
"IP4NAME",
|
||||
"INT:INT", "INT:BIN", "INT:STRING",
|
||||
} ;
|
||||
|
||||
|
||||
|
137
xioopts.c
137
xioopts.c
@ -583,6 +583,12 @@ const struct optname optionnames[] = {
|
||||
IF_RETRY ("interval", &opt_intervall)
|
||||
IF_RETRY ("intervall", &opt_intervall)
|
||||
IF_TERMIOS("intr", &opt_vintr)
|
||||
IF_ANY ("ioctl", &opt_ioctl_void)
|
||||
IF_ANY ("ioctl-bin", &opt_ioctl_bin)
|
||||
IF_ANY ("ioctl-int", &opt_ioctl_int)
|
||||
IF_ANY ("ioctl-intp", &opt_ioctl_intp)
|
||||
IF_ANY ("ioctl-string", &opt_ioctl_string)
|
||||
IF_ANY ("ioctl-void", &opt_ioctl_void)
|
||||
#ifdef IP_ADD_MEMBERSHIP
|
||||
IF_IP ("ip-add-membership", &opt_ip_add_membership)
|
||||
#endif
|
||||
@ -1967,6 +1973,71 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
||||
(*opts)[i].value.u_linger.l_linger);
|
||||
break;
|
||||
#endif /* HAVE_STRUCT_LINGER */
|
||||
case TYPE_INT_INT:
|
||||
if (!assign) {
|
||||
Error1("option \"%s\": values required", a0);
|
||||
continue;
|
||||
}
|
||||
{
|
||||
char *rest;
|
||||
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
|
||||
if (*rest != ':') {
|
||||
Error1("option \"%s\": 2 arguments required",
|
||||
ent->desc->defname);
|
||||
}
|
||||
++rest;
|
||||
(*opts)[i].value2.u_int = strtoul(rest, &rest, 0);
|
||||
}
|
||||
Info3("setting option \"%s\" to %d:%d", ent->desc->defname,
|
||||
(*opts)[i].value.u_int, (*opts)[i].value2.u_int);
|
||||
break;
|
||||
case TYPE_INT_BIN:
|
||||
if (!assign) {
|
||||
Error1("option \"%s\": values required", a0);
|
||||
continue;
|
||||
}
|
||||
{
|
||||
char *rest;
|
||||
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
|
||||
if (*rest != ':') {
|
||||
Error1("option \"%s\": 2 arguments required",
|
||||
ent->desc->defname);
|
||||
}
|
||||
++rest;
|
||||
optlen = 0;
|
||||
if ((result = dalan(rest, optbuf, &optlen, sizeof(optbuf))) != 0) {
|
||||
Error1("parseopts(): problem with \"%s\" data", rest);
|
||||
continue;
|
||||
}
|
||||
if (((*opts)[i].value2.u_bin.b_data = memdup(optbuf, optlen)) == NULL) {
|
||||
Error1("memdup(, "F_Zu"): out of memory", optlen);
|
||||
return -1;
|
||||
}
|
||||
(*opts)[i].value2.u_bin.b_len = optlen;
|
||||
}
|
||||
Info2("setting option \"%s\" to %d:..."/*!!!*/, ent->desc->defname,
|
||||
(*opts)[i].value.u_int);
|
||||
break;
|
||||
case TYPE_INT_STRING:
|
||||
if (!assign) {
|
||||
Error1("option \"%s\": values required", a0);
|
||||
continue;
|
||||
}
|
||||
{
|
||||
char *rest;
|
||||
(*opts)[i].value.u_int = strtoul(token, &rest, 0);
|
||||
if (*rest != ':') {
|
||||
Error1("option \"%s\": 2 arguments required",
|
||||
ent->desc->defname);
|
||||
}
|
||||
++rest;
|
||||
if (((*opts)[i].value2.u_string = strdup(token)) == NULL) {
|
||||
Error("out of memory"); return -1;
|
||||
}
|
||||
}
|
||||
Info3("setting option \"%s\" to %d:\"$s\"", ent->desc->defname,
|
||||
(*opts)[i].value.u_int, (*opts)[i].value2.u_string);
|
||||
break;
|
||||
#if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)
|
||||
case TYPE_IP_MREQN:
|
||||
{
|
||||
@ -2998,6 +3069,72 @@ int applyopts(int fd, struct opt *opts, unsigned int phase) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OPT_IOCTL_VOID:
|
||||
switch (opt->desc->type) {
|
||||
case TYPE_INT:
|
||||
if (Ioctl(fd, opt->value.u_int, NULL) < 0) {
|
||||
Error3("ioctl(%d, 0x%x, NULL): %s",
|
||||
fd, opt->value.u_int, strerror(errno));
|
||||
opt->desc = ODESC_ERROR; ++opt; continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Error1("ioctl() data type %d not implemented", opt->desc->type);
|
||||
}
|
||||
break;
|
||||
case OPT_IOCTL_INT:
|
||||
switch (opt->desc->type) {
|
||||
case TYPE_INT_INT:
|
||||
if (Ioctl_int(fd, opt->value.u_int, opt->value2.u_int) < 0) {
|
||||
Error4("ioctl(%d, %d, %p): %s",
|
||||
fd, opt->value.u_int, opt->value2.u_int, strerror(errno));
|
||||
opt->desc = ODESC_ERROR; ++opt; continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Error1("ioctl() data type %d not implemented", opt->desc->type);
|
||||
}
|
||||
break;
|
||||
case OPT_IOCTL_INTP:
|
||||
switch (opt->desc->type) {
|
||||
case TYPE_INT_INT:
|
||||
if (Ioctl(fd, opt->value.u_int, (void *)&opt->value2.u_int) < 0) {
|
||||
Error4("ioctl(%d, 0x%x, %p): %s",
|
||||
fd, opt->value.u_int, (void *)&opt->value2.u_int, strerror(errno));
|
||||
opt->desc = ODESC_ERROR; ++opt; continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Error1("ioctl() data type %d not implemented", opt->desc->type);
|
||||
}
|
||||
break;
|
||||
case OPT_IOCTL_BIN:
|
||||
switch (opt->desc->type) {
|
||||
case TYPE_INT_BIN:
|
||||
if (Ioctl(fd, opt->value.u_int, (void *)opt->value2.u_bin.b_data) < 0) {
|
||||
Error4("ioctl(%d, 0x%x, %p): %s",
|
||||
fd, opt->value.u_int, (void *)opt->value2.u_bin.b_data, strerror(errno));
|
||||
opt->desc = ODESC_ERROR; ++opt; continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Error1("ioctl() data type %d not implemented", opt->desc->type);
|
||||
}
|
||||
break;
|
||||
case OPT_IOCTL_STRING:
|
||||
switch (opt->desc->type) {
|
||||
case TYPE_INT_STRING:
|
||||
if (Ioctl(fd, opt->value.u_int, (void *)opt->value2.u_string) < 0) {
|
||||
Error4("ioctl(%d, 0x%x, %p): %s",
|
||||
fd, opt->value.u_int, (void *)opt->value2.u_string, strerror(errno));
|
||||
opt->desc = ODESC_ERROR; ++opt; continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Error1("ioctl() data type %d not implemented", opt->desc->type);
|
||||
}
|
||||
break;
|
||||
|
||||
default: Error1("applyopts(): option \"%s\" not implemented",
|
||||
opt->desc->defname);
|
||||
opt->desc = ODESC_ERROR; ++opt; continue;
|
||||
|
11
xioopts.h
11
xioopts.h
@ -53,6 +53,9 @@ enum e_types {
|
||||
TYPE_IP_MREQN, /* for struct ip_mreq or struct ip_mreqn */
|
||||
#endif
|
||||
TYPE_IP4NAME, /* IPv4 hostname or address */
|
||||
TYPE_INT_INT, /* 2 parameters: first is int, second is int */
|
||||
TYPE_INT_BIN, /* 2 parameters: first is int, second is binary */
|
||||
TYPE_INT_STRING, /* 2 parameters: first is int, second is req string */
|
||||
|
||||
TYPE_2BYTE = TYPE_USHORT
|
||||
} ;
|
||||
@ -64,7 +67,8 @@ enum e_func {
|
||||
OFUNC_SEEK32, /* lseek(): arg1 is whence (SEEK_SET etc.) */
|
||||
OFUNC_SEEK64, /* lseek64(): arg1 is whence (SEEK_SET etc.) */
|
||||
OFUNC_FCNTL, /* fcntl(, ): arg1 is cmd */
|
||||
OFUNC_IOCTL, /* ioctl(): arg1 is request */
|
||||
OFUNC_IOCTL, /* ioctl(): arg1 of option description is request, arg2
|
||||
is int setrequest */
|
||||
OFUNC_IOCTL_MASK_LONG, /* arg1 is getrequest, arg2 is setrequest:
|
||||
ioctl(arg1, ); |= arg3; ioctl(arg2, ); */
|
||||
OFUNC_SOCKOPT, /* setsockopt() */
|
||||
@ -329,6 +333,11 @@ enum e_optcode {
|
||||
#if 0 /* see Linux: man 7 netlink; probably not what we need yet */
|
||||
OPT_IO_SIOCGIFNAME,
|
||||
#endif
|
||||
OPT_IOCTL_BIN, /* generic ioctl with binary value (pointed to) */
|
||||
OPT_IOCTL_INT, /* generic ioctl with integer value */
|
||||
OPT_IOCTL_INTP, /* generic ioctl with integer value (pointed to) */
|
||||
OPT_IOCTL_STRING, /* generic ioctl with integer value (pointed to) */
|
||||
OPT_IOCTL_VOID, /* generic ioctl without value */
|
||||
OPT_IP_ADD_MEMBERSHIP,
|
||||
#ifdef IP_HDRINCL
|
||||
OPT_IP_HDRINCL,
|
||||
|
Loading…
Reference in New Issue
Block a user