mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 15:32:35 +00:00
New option children-shutup
This commit is contained in:
parent
fe4444a70b
commit
8c9b185890
18 changed files with 128 additions and 23 deletions
6
CHANGES
6
CHANGES
|
@ -53,6 +53,10 @@ Features:
|
|||
Socat now installs as socat1 and is referenced by symbolic link socat,
|
||||
same with man page (socat1.1 by socat.1)
|
||||
|
||||
New option children-shutup[=1|2...] decreases severity of log
|
||||
messages in LISTEN and CONNECT type sub processes.
|
||||
Test: CHILDREN_SHUTUP
|
||||
|
||||
Corrections:
|
||||
When a sub process (EXEC, SYSTEM) terminated with exit code other than
|
||||
0, its last sent data might have been lost depending on timing of read/
|
||||
|
@ -76,7 +80,7 @@ Corrections:
|
|||
|
||||
In previous Socat versions errors on shutdown() were ignored (info
|
||||
level).
|
||||
Now Socat handles EPIPE and ECONNRESET as error to indicate possible
|
||||
Now Socat handles EPIPE and ECONNRESET as errors to indicate possible
|
||||
failure of data transfer.
|
||||
|
||||
Coding:
|
||||
|
|
20
doc/socat.yo
20
doc/socat.yo
|
@ -1628,6 +1628,8 @@ label(OPTION_COOL_WRITE)dit(bf(tt(cool-write[=<bool>])))
|
|||
abort the connection. Use this option only with option
|
||||
link(fork)(OPTION_FORK) because otherwise it might cause socat() to exit
|
||||
with code 0 even on failure.nl()
|
||||
This option is deprecated, consider using
|
||||
link(option children-shutup)(OPTION_CHILDRED_SHUTUP) instead.
|
||||
label(OPTION_END_CLOSE)dit(bf(tt(end-close[=<bool>])))
|
||||
Changes the (address dependent) method of ending a connection to just close
|
||||
the file descriptors. This is useful when the connection is to be reused by
|
||||
|
@ -2514,16 +2516,15 @@ label(OPTION_BACKLOG)dit(bf(tt(backlog=<count>)))
|
|||
label(OPTION_ACCEPT_TIMEOUT)dit(bf(tt(accept-timeout=<seconds>)))
|
||||
End waiting for a connection after <seconds> [link(timeval)(TYPE_TIMEVAL)]
|
||||
with error status.
|
||||
label(OPTION_MAX_CHILDREN)dit(bf(tt(max-children=<count>)))
|
||||
Limits the number of concurrent child processes [link(int)(TYPE_INT)].
|
||||
Default is no limit.
|
||||
enddit()
|
||||
startdit()enddit()nl()
|
||||
|
||||
|
||||
label(GROUP_CHILD)em(bf(CHILD option group))
|
||||
|
||||
Options for addresses with multiple connections via child processes.
|
||||
Addresses of LISTEN and CONNECT type take the
|
||||
link(fork)(OPTION_FORK) option to handle multiple connections via child
|
||||
processes.
|
||||
startdit()
|
||||
label(OPTION_FORK)dit(bf(tt(fork)))
|
||||
After establishing a connection, handles its channel in a child process and
|
||||
|
@ -2537,6 +2538,17 @@ label(OPTION_FORK)dit(bf(tt(fork)))
|
|||
inherited by the child process.nl()
|
||||
On some operating systems (e.g. FreeBSD) this option does not work for
|
||||
UDP-LISTEN addresses.nl()
|
||||
label(OPTION_MAX_CHILDREN)dit(bf(tt(max-children=<count>)))
|
||||
Limits the number of concurrent child processes [link(int)(TYPE_INT)].
|
||||
Default is no limit.
|
||||
label(OPTION_CHILDRED_SHUTUP)dit(bf(tt(children-shutup[=1|2|..])))
|
||||
Decreases the severity of log messages produced by child processes. For
|
||||
example, with value 1 notices are logged as info (or dropped depending on
|
||||
link(option -dX)(option_d)), and errors are logged as warnings but still
|
||||
cause termination of the child process.nl()
|
||||
This option is intended to reduce logging of high volume servers or
|
||||
proxies.nl()
|
||||
This option succeeds link(option cool-write)(OPTION_COOL_WRITE).
|
||||
enddit()
|
||||
|
||||
startdit()enddit()nl()
|
||||
|
|
23
error.c
23
error.c
|
@ -29,6 +29,7 @@ int syslevel[] = {
|
|||
struct diag_opts {
|
||||
const char *progname;
|
||||
int msglevel;
|
||||
int shutup; /* decrease msglevel by this value */
|
||||
int exitlevel;
|
||||
int syslog;
|
||||
FILE *logfile;
|
||||
|
@ -45,7 +46,7 @@ static void _diag_exit(int status);
|
|||
|
||||
|
||||
struct diag_opts diagopts =
|
||||
{ NULL, E_WARN, E_ERROR, 0, NULL, LOG_DAEMON, false, 0, false, NULL, true } ;
|
||||
{ NULL, E_WARN, 0, E_ERROR, 0, NULL, LOG_DAEMON, false, 0, false, NULL, true } ;
|
||||
|
||||
static void msg2(
|
||||
#if HAVE_CLOCK_GETTIME
|
||||
|
@ -215,6 +216,10 @@ void diag_set_int(char what, int arg) {
|
|||
diagopts.hostname = strdup(ubuf.nodename);
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
diagopts.shutup = arg;
|
||||
diagopts.exitlevel -= arg;
|
||||
break;
|
||||
default: msg(E_ERROR, "unknown diagnostic option %c", what);
|
||||
}
|
||||
}
|
||||
|
@ -283,7 +288,12 @@ void msg(int level, const char *format, ...) {
|
|||
diag_flush();
|
||||
}
|
||||
|
||||
if (level < diagopts.msglevel) { return; }
|
||||
level -= diagopts.shutup; /* decrease severity of messages? */
|
||||
|
||||
/* Just ignore this call when level too low for both logging and exiting */
|
||||
if (level < diagopts.msglevel && level < diagopts.exitlevel)
|
||||
return;
|
||||
|
||||
va_start(ap, format);
|
||||
|
||||
/* we do only a minimum in the outer parts which may run in a signal handler
|
||||
|
@ -299,7 +309,10 @@ void msg(int level, const char *format, ...) {
|
|||
#endif
|
||||
diag_dgram.level = level;
|
||||
diag_dgram.exitcode = diagopts.exitstatus;
|
||||
if (level >= diagopts.msglevel)
|
||||
vsnprintf_r(diag_dgram.text, sizeof(diag_dgram.text), format, ap);
|
||||
else
|
||||
diag_dgram.text[0] = '\0';
|
||||
if (diagopts.signalsafe && diag_in_handler && !diag_immediate_msg) {
|
||||
send(diag_sock_send, &diag_dgram, sizeof(diag_dgram)-TEXTLEN + strlen(diag_dgram.text)+1,
|
||||
0 /* for canonical reasons */
|
||||
|
@ -337,9 +350,10 @@ void msg2(
|
|||
struct tm struct_tm;
|
||||
#endif
|
||||
#define MSGLEN 512
|
||||
char buff[MSGLEN+2], *bufp = buff, *syslp;
|
||||
char buff[MSGLEN+2], *bufp = buff, *syslp = NULL;
|
||||
size_t bytes;
|
||||
|
||||
if (text[0] != '\0') {
|
||||
#if HAVE_CLOCK_GETTIME
|
||||
epoch = now->tv_sec;
|
||||
#elif HAVE_PROTOTYPE_LIB_gettimeofday
|
||||
|
@ -391,8 +405,9 @@ void msg2(
|
|||
bufp = strchr(bufp, '\0');
|
||||
strcpy(bufp, "\n");
|
||||
_msg(level, buff, syslp);
|
||||
}
|
||||
if (level >= diagopts.exitlevel) {
|
||||
if (E_NOTICE >= diagopts.msglevel) {
|
||||
if (E_NOTICE >= diagopts.msglevel && text[0] != '\0') {
|
||||
if ((syslp - buff) + 16 > MSGLEN+1)
|
||||
syslp = buff + MSGLEN - 15;
|
||||
snprintf_r(syslp, 16, "N exit(%d)\n", exitcode?exitcode:(diagopts.exitstatus?diagopts.exitstatus:1));
|
||||
|
|
61
test.sh
61
test.sh
|
@ -15521,6 +15521,67 @@ esac
|
|||
N=$((N+1))
|
||||
|
||||
|
||||
# Test the children-shutup option
|
||||
NAME=CHILDREN_SHUTUP
|
||||
case "$TESTS" in
|
||||
*%$N%*|*%functions%*|*%exec%*|*%fork%*|*%socket%*|*%unix%*|*%$NAME%*)
|
||||
TEST="$NAME: test the children-shutup option"
|
||||
# Run a UNIX domain listening server with options fork and children-shutup, and
|
||||
# an TCP client to invalid port that will fail.
|
||||
# Connect to the server and check if it logs the connect failure as warning.
|
||||
if ! eval $NUMCOND; then :;
|
||||
elif ! F=$(testfeats UNIX LISTEN EXEC FILE); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
elif ! A=$(testaddrs UNIX-LISTEN TCP4 FILE UNIX-CONNECT); then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
elif ! o=$(testoptions fork children-shutup) >/dev/null; then
|
||||
$PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
newport tcp4
|
||||
ts="$td/test$N.sock"
|
||||
tf="$td/test$N.stdout"
|
||||
te="$td/test$N.stderr"
|
||||
tdiff="$td/test$N.diff"
|
||||
da="test$N $(date) $RANDOM"
|
||||
CMD0="$TRACE $SOCAT $opts UNIX-LISTEN:$ts,fork,children-shutup TCP4:localhost:$PORT"
|
||||
CMD1="$TRACE $SOCAT $opts -u FILE:/dev/null UNIX-CONNECT:$ts"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD0 >/dev/null 2>"${te}0" &
|
||||
pid0=$!
|
||||
waitunixport $ts 1
|
||||
$CMD1 2>"${te}1"
|
||||
rc1=$?
|
||||
kill $pid0 2>/dev/null; wait
|
||||
relsleep 1 # child process might need more time
|
||||
if grep -q " W connect" ${te}0; then
|
||||
$PRINTF "$OK\n"
|
||||
if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}0" >&2; fi
|
||||
if [ "$VERBOSE" ]; then echo "$CMD1"; fi
|
||||
if [ "$DEBUG" ]; then cat "${te}1" >&2; fi
|
||||
numOK=$((numOK+1))
|
||||
else
|
||||
$PRINTF "$FAILED\n"
|
||||
echo "$CMD0 &"
|
||||
cat "${te}0" >&2
|
||||
echo "$CMD1"
|
||||
cat "${te}1" >&2
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
namesFAIL="$namesFAIL $NAME"
|
||||
fi
|
||||
fi # NUMCOND
|
||||
;;
|
||||
esac
|
||||
N=$((N+1))
|
||||
|
||||
|
||||
# end of common tests
|
||||
|
||||
##################################################################################
|
||||
|
|
|
@ -110,7 +110,7 @@ int xioopen_ipapp_connect(int argc, const char *argv[], struct opt *opts,
|
|||
level = E_WARN; /* most users won't expect a problem here,
|
||||
so Notice is too weak */
|
||||
}
|
||||
while ((pid = xio_fork(false, level)) < 0) {
|
||||
while ((pid = xio_fork(false, level, xfd->para.socket.shutup)) < 0) {
|
||||
if (xfd->forever || --xfd->retry) {
|
||||
Nanosleep(&xfd->intervall, NULL); continue;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
const struct optdesc opt_backlog = { "backlog", NULL, OPT_BACKLOG, GROUP_LISTEN, PH_LISTEN, TYPE_INT, OFUNC_SPEC };
|
||||
const struct optdesc opt_fork = { "fork", NULL, OPT_FORK, GROUP_CHILD, PH_PASTACCEPT, TYPE_BOOL, OFUNC_SPEC };
|
||||
const struct optdesc opt_max_children = { "max-children", NULL, OPT_MAX_CHILDREN, GROUP_CHILD, PH_PASTACCEPT, TYPE_INT, OFUNC_SPEC };
|
||||
const struct optdesc opt_children_shutup = { "children-shutup", "child-shutup", OPT_CHILDREN_SHUTUP, GROUP_CHILD, PH_PASTACCEPT, TYPE_INT, OFUNC_OFFSET, XIO_OFFSETOF(para.socket.shutup) };
|
||||
/**/
|
||||
#if (WITH_UDP || WITH_TCP)
|
||||
const struct optdesc opt_range = { "range", NULL, OPT_RANGE, GROUP_RANGE, PH_ACCEPT, TYPE_STRING, OFUNC_SPEC };
|
||||
|
@ -343,7 +344,10 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
|
|||
sigaddset(&mask_sigchld, SIGCHLD);
|
||||
Sigprocmask(SIG_BLOCK, &mask_sigchld, NULL);
|
||||
|
||||
if ((pid = xio_fork(false, level==E_ERROR?level:E_WARN)) < 0) {
|
||||
if ((pid =
|
||||
xio_fork(false, level==E_ERROR?level:E_WARN,
|
||||
xfd->para.socket.shutup))
|
||||
< 0) {
|
||||
Close(xfd->fd);
|
||||
Sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL);
|
||||
return STAT_RETRYLATER;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
extern const struct optdesc opt_backlog;
|
||||
extern const struct optdesc opt_fork;
|
||||
extern const struct optdesc opt_max_children;
|
||||
extern const struct optdesc opt_children_shutup;
|
||||
extern const struct optdesc opt_range;
|
||||
extern const struct optdesc opt_accept_timeout;
|
||||
|
||||
|
|
|
@ -409,7 +409,7 @@ static int
|
|||
if (xfd->forever || xfd->retry) {
|
||||
level = E_WARN;
|
||||
}
|
||||
while ((pid = xio_fork(false, level)) < 0) {
|
||||
while ((pid = xio_fork(false, level, xfd->para.socket.shutup)) < 0) {
|
||||
if (xfd->forever || --xfd->retry) {
|
||||
Nanosleep(&xfd->intervall, NULL); continue;
|
||||
}
|
||||
|
|
|
@ -385,7 +385,7 @@ int _xioopen_foxec(int xioflags, /* XIO_RDONLY etc. */
|
|||
|
||||
if (withfork) {
|
||||
Socketpair(PF_UNIX, SOCK_STREAM, 0, trigger);
|
||||
pid = xio_fork(true, E_ERROR);
|
||||
pid = xio_fork(true, E_ERROR, 0);
|
||||
if (pid < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -199,7 +199,7 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
|
|||
if (xfd->forever || xfd->retry) {
|
||||
level = E_WARN;
|
||||
}
|
||||
while ((pid = xio_fork(false, level)) < 0) {
|
||||
while ((pid = xio_fork(false, level, xfd->para.socket.shutup)) < 0) {
|
||||
if (xfd->forever || --xfd->retry) {
|
||||
Nanosleep(&xfd->intervall, NULL); continue;
|
||||
}
|
||||
|
|
|
@ -993,7 +993,7 @@ int xioopen_connect(struct single *xfd, union sockaddr_union *us, size_t uslen,
|
|||
so Notice is too weak */
|
||||
}
|
||||
|
||||
while ((pid = xio_fork(false, level)) < 0) {
|
||||
while ((pid = xio_fork(false, level, xfd->para.socket.shutup)) < 0) {
|
||||
--xfd->retry;
|
||||
if (xfd->forever || xfd->retry) {
|
||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
||||
|
@ -1287,7 +1287,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
|
|||
Error1("socketpair(PF_UNIX, SOCK_STREAM, 0, ...): %s", strerror(errno));
|
||||
}
|
||||
|
||||
if ((pid = xio_fork(false, level)) < 0) {
|
||||
if ((pid = xio_fork(false, level, xfd->para.socket.shutup)) < 0) {
|
||||
Close(trigger[0]);
|
||||
Close(trigger[1]);
|
||||
Close(xfd->fd);
|
||||
|
|
|
@ -175,7 +175,7 @@ static int xioopen_socks4_connect(int argc, const char *argv[], struct opt *opts
|
|||
level = E_WARN; /* most users won't expect a problem here,
|
||||
so Notice is too weak */
|
||||
}
|
||||
while ((pid = xio_fork(false, level)) < 0) {
|
||||
while ((pid = xio_fork(false, level, xfd->para.socket.shutup)) < 0) {
|
||||
if (xfd->forever || --xfd->retry) {
|
||||
Nanosleep(&xfd->intervall, NULL);
|
||||
continue;
|
||||
|
|
|
@ -214,7 +214,7 @@ int _xioopen_ipdgram_listen(struct single *sfd,
|
|||
sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)));
|
||||
|
||||
if (dofork) {
|
||||
pid = xio_fork(false, E_ERROR);
|
||||
pid = xio_fork(false, E_ERROR, sfd->para.socket.shutup);
|
||||
if (pid < 0) {
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
|
|
@ -315,7 +315,7 @@ static int xioopen_unix_connect(int argc, const char *argv[], struct opt *opts,
|
|||
so Notice is too weak */
|
||||
}
|
||||
|
||||
while ((pid = xio_fork(false, level)) < 0) {
|
||||
while ((pid = xio_fork(false, level, xfd->para.socket.shutup)) < 0) {
|
||||
--xfd->retry;
|
||||
if (xfd->forever || xfd->retry) {
|
||||
dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
|
||||
|
|
4
xio.h
4
xio.h
|
@ -223,6 +223,7 @@ typedef struct single {
|
|||
#if _WITH_IP4 || _WITH_IP6
|
||||
struct para_ip ip;
|
||||
#endif /* _WITH_IP4 || _WITH_IP6 */
|
||||
int shutup;
|
||||
/* up to here, keep consistent copy in openssl part !!! */
|
||||
#if WITH_UNIX
|
||||
struct {
|
||||
|
@ -263,6 +264,7 @@ typedef struct single {
|
|||
#if _WITH_IP4 || _WITH_IP6
|
||||
struct para_ip ip;
|
||||
#endif /* _WITH_IP4 || _WITH_IP6 */
|
||||
int shutup;
|
||||
/* end of the para.socket structure copy */
|
||||
SSL_CTX* ctx; /* for freeing on close */
|
||||
SSL *ssl;
|
||||
|
@ -440,7 +442,7 @@ extern int num_child;
|
|||
|
||||
extern int xioinitialize(void);
|
||||
extern int xioinitialize2(void);
|
||||
extern pid_t xio_fork(bool subchild, int level);
|
||||
extern pid_t xio_fork(bool subchild, int level, int shutup);
|
||||
extern int xio_forked_inchild(void);
|
||||
extern int xiosetopt(char what, const char *arg);
|
||||
extern int xioinqopt(char what, char *arg, size_t n);
|
||||
|
|
|
@ -205,7 +205,10 @@ int xio_forked_inchild(void) {
|
|||
/* subchild != 0 means that the current process is already a child process of
|
||||
the master process and thus the new sub child process should not set the
|
||||
SOCAT_PID variable */
|
||||
pid_t xio_fork(bool subchild, int level) {
|
||||
pid_t xio_fork(bool subchild,
|
||||
int level, /* log level */
|
||||
int shutup) /* decrease log level in child process */
|
||||
{
|
||||
pid_t pid;
|
||||
const char *forkwaitstring;
|
||||
int forkwaitsecs = 0;
|
||||
|
@ -240,6 +243,7 @@ pid_t xio_fork(bool subchild, int level) {
|
|||
if (xio_forked_inchild() != 0) {
|
||||
Exit(1);
|
||||
}
|
||||
diag_set_int('u', shutup);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -289,6 +289,7 @@ const struct optname optionnames[] = {
|
|||
IF_OPENSSL("cert", &opt_openssl_certificate)
|
||||
IF_OPENSSL("certificate", &opt_openssl_certificate)
|
||||
IF_TERMIOS("cfmakeraw", &opt_termios_cfmakeraw)
|
||||
IF_ANY ("children-shutup", &opt_children_shutup)
|
||||
IF_ANY ("chroot", &opt_chroot)
|
||||
IF_ANY ("chroot-early", &opt_chroot_early)
|
||||
/*IF_TERMIOS("cibaud", &opt_cibaud)*/
|
||||
|
|
|
@ -247,6 +247,7 @@ enum e_optcode {
|
|||
# endif
|
||||
OPT_BSDLY, /* termios.c_oflag */
|
||||
#endif
|
||||
OPT_CHILDREN_SHUTUP,
|
||||
OPT_CHROOT, /* chroot() past file system access */
|
||||
OPT_CHROOT_EARLY, /* chroot() before file system access */
|
||||
/*OPT_CIBAUD,*/ /* termios.c_cflag */
|
||||
|
|
Loading…
Reference in a new issue