New option setsockopt-listen using dalan

This commit is contained in:
Gerhard Rieger 2020-12-29 16:45:33 +01:00
parent 411b658939
commit 10680c8aad
11 changed files with 470 additions and 230 deletions

View file

@ -104,6 +104,14 @@ New features:
Test: GOPENUNIXSEQPACKET Test: GOPENUNIXSEQPACKET
Feature suggested by vi0oss. Feature suggested by vi0oss.
Features:
The generic setsockopt-int and related options are, in case of
listening/accepting addresses, applied to the connected socket(s). To enable
setting options on the listening socket, a new option setsockopt-listen
has been implemented. See the documentation for info on data types.
Tests: SETSOCKOPT SETSOCKOPT_LISTEN
Thanks to Steven Danna and Korian Edeline for reporting this issue.
####################### V 1.7.3.4: ####################### V 1.7.3.4:
Corrections: Corrections:

197
dalan.c
View file

@ -6,6 +6,7 @@
primitive subset exists. */ primitive subset exists. */
#include "config.h" #include "config.h"
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#if HAVE_STDBOOL_H #if HAVE_STDBOOL_H
@ -70,56 +71,35 @@ void dalan_init(void) {
_dalan_dflts(&dalan_opts); _dalan_dflts(&dalan_opts);
} }
/* read data description from line, write result to data; do not write /* Parses and coverts a data item.
so much data that *p exceeds n ! Returns 0 on success,
p must be initialized to 0.
return 0 on success,
-1 if the data was cut due to n limit, -1 if the data was cut due to n limit,
1 if a syntax error occurred 1 if a syntax error occurred
*p is a global data counter; especially it must be used when calculating 2 if the actual character is white space
alignment. On successful return from the function *p must be actual! 3 if the first character is not a type specifier
*/ */
int dalan(const char *line, char *data, size_t *p, size_t n) { static int dalan_item(int c, const char **line0, uint8_t *data, size_t *p, size_t n) {
int align, mask, i, x; const char *line = *line0;
size_t p1 = *p; size_t p1 = *p;
char c;
/*fputs(line, stderr); fputc('\n', stderr);*/
while (c = *line++) {
switch (c) { switch (c) {
case ' ': case ' ':
case '\t': case '\t':
case '\r': case '\r':
case '\n': case '\n':
break; return 2;
case ',':
align = 2;
while (*line == ',') {
align <<= 1;
++line;
}
mask = align - 1; /* create the bitmask */
i = (align - (p1 & mask)) & mask;
while (i && p1<n) data[p1++] = 0, --i;
if (i) { *p = p1; return -1; }
break;
case ';':
align = dalan_opts.c_int;
mask = align - 1;
i = (align - (p1 & mask)) & mask;
while (i && p1<n) data[p1++] = 0, --i;
if (i) { *p = p1; return -1; }
break;
case '"': case '"':
while (1) { while (1) {
switch (c = *line++) { switch (c = *line++) {
case '\0': fputs("unterminated string\n", stderr); case '\0': fputs("unterminated string\n", stderr);
*line0 = line;
return 1; return 1;
case '"': case '"':
break; break;
case '\\': case '\\':
if (!(c = *line++)) { if (!(c = *line++)) {
fputs("continuation line not implemented\n", stderr); fputs("continuation line not implemented\n", stderr);
*line0 = line;
return 1; return 1;
} }
switch (c) { switch (c) {
@ -138,7 +118,11 @@ int dalan(const char *line, char *data, size_t *p, size_t n) {
} }
/* PASSTHROUGH */ /* PASSTHROUGH */
default: default:
if (p1 >= n) { *p = p1; return -1; } if (p1 >= n) {
*p = p1;
*line0 = line;
return -1;
}
data[p1++] = c; data[p1++] = c;
continue; continue;
} }
@ -149,12 +133,15 @@ int dalan(const char *line, char *data, size_t *p, size_t n) {
case '\'': case '\'':
switch (c = *line++) { switch (c = *line++) {
case '\0': fputs("unterminated character\n", stderr); case '\0': fputs("unterminated character\n", stderr);
*line0 = line;
return 1; return 1;
case '\'': fputs("error in character\n", stderr); case '\'': fputs("error in character\n", stderr);
*line0 = line;
return 1; return 1;
case '\\': case '\\':
if (!(c = *line++)) { if (!(c = *line++)) {
fputs("continuation line not implemented\n", stderr); fputs("continuation line not implemented\n", stderr);
*line0 = line;
return 1; return 1;
} }
switch (c) { switch (c) {
@ -178,25 +165,16 @@ int dalan(const char *line, char *data, size_t *p, size_t n) {
} }
if (*line != '\'') { if (*line != '\'') {
fputs("error in character termination\n", stderr); fputs("error in character termination\n", stderr);
*p = p1; return 1; *p = p1;
*line0 = line;
return 1;
} }
++line; ++line;
break; break;
#if LATER
case '0':
c = *line++;
if (c == 'x') {
/* hexadecimal */ ;
} else if (isdigit(c&0xff)) {
/* octal */
} else {
/* it was only 0 */
}
break;
#endif /* LATER */
case 'x': case 'x':
/* expecting hex data, must be an even number of digits!! */ /* expecting hex data, must be an even number of digits!! */
while (true) { while (true) {
int x;
c = *line; c = *line;
if (isdigit(c&0xff)) { if (isdigit(c&0xff)) {
x = (c-'0') << 4; x = (c-'0') << 4;
@ -212,18 +190,135 @@ int dalan(const char *line, char *data, size_t *p, size_t n) {
x |= (c&0x07) + 9; x |= (c&0x07) + 9;
} else { } else {
fputs("odd number of hexadecimal digits\n", stderr); fputs("odd number of hexadecimal digits\n", stderr);
*p = p1; return 1; *p = p1;
*line0 = line;
return 1;
} }
++line; ++line;
if (p1 >= n) { *p = p1; return -1; } if (p1 >= n) {
*p = p1;
*line0 = line;
return -1;
}
data[p1++] = x; data[p1++] = x;
} }
break; break;
case 'A': case 'a': case 'l':
case 'C': case 'c': /* expecting decimal number, with target type long */
default: fprintf(stderr, "syntax error in \"%s\"\n", line-1); {
return 1; char *endptr;
*(long *)&data[p1] = strtol(line, &endptr, 10);
p1 += sizeof(long);
line = endptr;
} }
break;
case 'L':
/* expecting decimal number, with target type unsigned long */
{
char *endptr;
*(unsigned long *)&data[p1] = strtol(line, &endptr, 10);
p1 += sizeof(unsigned long);
line = endptr;
} }
*p = p1; return 0; break;
case 'i':
/* expecting decimal number, with target type int */
{
char *endptr;
*(int *)&data[p1] = strtol(line, &endptr, 10);
p1 += sizeof(int);
line = endptr;
}
break;
case 'I':
/* expecting decimal number, with target type unsigned int */
{
char *endptr;
*(unsigned int *)&data[p1] = strtol(line, &endptr, 10);
p1 += sizeof(unsigned int);
line = endptr;
}
break;
case 's':
/* expecting decimal number, with target type short */
{
char *endptr;
*(short *)&data[p1] = strtol(line, &endptr, 10);
p1 += sizeof(short);
line = endptr;
}
break;
case 'S':
/* expecting decimal number, with target type unsigned short */
{
char *endptr;
*(unsigned short *)&data[p1] = strtol(line, &endptr, 10);
p1 += sizeof(unsigned short);
line = endptr;
}
break;
case 'b':
/* expecting decimal number, with target type byte (int8_t) */
{
char *endptr;
*(int8_t *)&data[p1] = strtoul(line, &endptr, 10);
p1 += sizeof(uint8_t);
line = endptr;
}
case 'B':
/* expecting decimal number, with target type byte (uint8_t) */
{
char *endptr;
*(uint8_t *)&data[p1] = strtoul(line, &endptr, 10);
p1 += sizeof(uint8_t);
line = endptr;
}
break;
default:
*line0 = line;
return 3;
}
*p = p1;
*line0 = line;
return 0;
}
/* read data description from line (\0-terminated), write result to data; do
not write so much data that *p exceeds n !
p must be initialized to 0.
return 0 on success,
-1 if the data was cut due to n limit,
1 if a syntax error occurred
*p is a global data counter; especially it must be used when calculating
alignment. On successful return from the function *p must be actual!
*/
int dalan(const char *line, uint8_t *data, size_t *p, size_t n, char deflt) {
size_t p0;
char c;
int rc;
while (1) {
/* assume there is a type specifier on beginning of rest of line */
c = *line++;
if (c == '\0')
break;
p0 = *p;
rc = dalan_item(c, &line, data, p, n);
if (rc == 0) {
deflt = c; /* continue with this type as default */
} else if (rc == 2) {
/* white space */
continue;
} else if (rc == 3) {
/* no, we did not recognize c as type specifier, try default type */
--line;
rc = dalan_item(deflt, &line, data, p, n);
}
if (rc != 0) {
return rc;
}
/* rc == 0 */
n -= (*p-p0);
}
return 0;
} }

View file

@ -25,6 +25,6 @@ extern struct dalan_opts_s dalan_opts;
extern void dalan_init(void); extern void dalan_init(void);
extern struct dalan_opts_s *dalan_props(void); extern struct dalan_opts_s *dalan_props(void);
extern int dalan(const char *line, char *data, size_t *p, size_t n); extern int dalan(const char *line, uint8_t *data, size_t *p, size_t n, char deflt);
#endif /* !defined(__dalan_h_included) */ #endif /* !defined(__dalan_h_included) */

View file

@ -708,9 +708,7 @@ label(ADDRESS_SOCKET_CONNECT)dit(bf(tt(SOCKET-CONNECT:<domain>:<protocol>:<remot
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(CHILD)(GROUP_CHILD),link(RETRY)(GROUP_RETRY)nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(CHILD)(GROUP_CHILD),link(RETRY)(GROUP_RETRY)nl()
Useful options: Useful options:
link(bind)(OPTION_BIND), link(bind)(OPTION_BIND),
link(setsockopt-int)(OPTION_SETSOCKOPT_INT), link(setsockopt)(OPTION_SETSOCKOPT),
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN),
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
nl() nl()
See also: See also:
link(TCP)(ADDRESS_TCP_CONNECT), link(TCP)(ADDRESS_TCP_CONNECT),
@ -733,9 +731,7 @@ label(ADDRESS_SOCKET_DATAGRAM)dit(bf(tt(SOCKET-DATAGRAM:<domain>:<type>:<protoco
Useful options: Useful options:
link(bind)(OPTION_BIND), link(bind)(OPTION_BIND),
link(range)(OPTION_RANGE), link(range)(OPTION_RANGE),
link(setsockopt-int)(OPTION_SETSOCKOPT_INT), link(setsockopt)(OPTION_SETSOCKOPT),
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN),
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
nl() nl()
See also: See also:
link(UDP-DATAGRAM)(ADDRESS_UDP_DATAGRAM), link(UDP-DATAGRAM)(ADDRESS_UDP_DATAGRAM),
@ -756,9 +752,8 @@ label(ADDRESS_SOCKET_LISTEN)dit(bf(tt(SOCKET-LISTEN:<domain>:<protocol>:<local-a
link(-g)(option_g).nl() link(-g)(option_g).nl()
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(LISTEN)(GROUP_LISTEN),link(RANGE)(GROUP_RANGE),link(CHILD)(GROUP_CHILD),link(RETRY)(GROUP_RETRY)nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(LISTEN)(GROUP_LISTEN),link(RANGE)(GROUP_RANGE),link(CHILD)(GROUP_CHILD),link(RETRY)(GROUP_RETRY)nl()
Useful options: Useful options:
link(setsockopt-int)(OPTION_SETSOCKOPT_INT), link(setsockopt)(OPTION_SETSOCKOPT),
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN), link(setsockopt-listen)(OPTION_SETSOCKOPT_LISTEN),
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
nl() nl()
See also: See also:
link(TCP)(ADDRESS_TCP_LISTEN), link(TCP)(ADDRESS_TCP_LISTEN),
@ -777,9 +772,8 @@ label(ADDRESS_SOCKET_RECV)dit(bf(tt(SOCKET-RECV:<domain>:<type>:<protocol>:<loca
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(RANGE)(GROUP_RANGE)nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(RANGE)(GROUP_RANGE)nl()
Useful options: Useful options:
link(range)(OPTION_RANGE), link(range)(OPTION_RANGE),
link(setsockopt-int)(OPTION_SETSOCKOPT_INT), link(setsockopt)(OPTION_SETSOCKOPT),
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN), link(setsockopt-listen)(OPTION_SETSOCKOPT_LISTEN)
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
nl() nl()
See also: See also:
link(UDP-RECV)(ADDRESS_UDP_RECV), link(UDP-RECV)(ADDRESS_UDP_RECV),
@ -800,9 +794,8 @@ label(ADDRESS_SOCKET_RECVFROM)dit(bf(tt(SOCKET-RECVFROM:<domain>:<type>:<protoco
Useful options: Useful options:
link(fork)(OPTION_FORK), link(fork)(OPTION_FORK),
link(range)(OPTION_RANGE), link(range)(OPTION_RANGE),
link(setsockopt-int)(OPTION_SETSOCKOPT_INT), link(setsockopt)(OPTION_SETSOCKOPT),
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN), link(setsockopt-listen)(OPTION_SETSOCKOPT_LISTEN)
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
nl() nl()
See also: See also:
link(UDP-RECVFROM)(ADDRESS_UDP_RECVFROM), link(UDP-RECVFROM)(ADDRESS_UDP_RECVFROM),
@ -822,9 +815,8 @@ label(ADDRESS_SOCKET_SENDTO)dit(bf(tt(SOCKET-SENDTO:<domain>:<type>:<protocol>:<
Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET)nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET)nl()
Useful options: Useful options:
link(bind)(OPTION_BIND), link(bind)(OPTION_BIND),
link(setsockopt-int)(OPTION_SETSOCKOPT_INT), link(setsockopt)(OPTION_SETSOCKOPT),
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN), link(setsockopt-listen)(OPTION_SETSOCKOPT_LISTEN)
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
nl() nl()
See also: See also:
link(UDP-SENDTO)(ADDRESS_UDP_SENDTO), link(UDP-SENDTO)(ADDRESS_UDP_SENDTO),
@ -1921,22 +1913,24 @@ COMMENT(label(OPTION_USEIFBUFS)dit(bf(tt(useifbufs)))
label(OPTION_SO_TIMESTAMP)dit(bf(tt(so-timestamp))) label(OPTION_SO_TIMESTAMP)dit(bf(tt(so-timestamp)))
Sets the SO_TIMESTAMP socket option. This enables receiving and logging of Sets the SO_TIMESTAMP socket option. This enables receiving and logging of
timestamp ancillary messages. timestamp ancillary messages.
label(OPTION_SETSOCKOPT_INT)dit(bf(tt(setsockopt-int=<level>:<optname>:<optval>))) label(OPTION_SETSOCKOPT)dit(bf(tt(setsockopt=<level>:<optname>:<optval>)))
Invokes tt(setsockopt()) for the socket with the given parameters. tt(level) Invokes tt(setsockopt()) for the socket with the given parameters. tt(level)
[link(int)(TYPE_INT)] is used as second argument to tt(setsockopt()) and [link(int)(TYPE_INT)] is used as second argument to tt(setsockopt()) and
specifies the layer, e.g. SOL_TCP for TCP (6 on Linux), or SOL_SOCKET for specifies the layer, e.g. SOL_TCP for TCP (6 on Linux), or SOL_SOCKET for
the socket layer (1 on Linux). tt(optname) [link(int)(TYPE_INT)] is the the socket layer (1 on Linux). tt(optname) [link(int)(TYPE_INT)] is the
third argument to tt(setsockopt()) and tells which socket option is to be third argument to tt(setsockopt()) and tells which socket option is to be
set. For the actual numbers you might have to look up the appropriate include set. For the actual numbers you might have to look up the appropriate include
files of your system. The 4th tt(setsockopt()) parameter, tt(value) files of your system. For the 4th and 5th tt(setsockopt()) parameters,
[link(int)(TYPE_INT)], is passed to the function per pointer, and for the tt(value) [link(dalan)(TYPE_DATA)] specifies an arbitrary sequence of bytes
length parameter NOEXPAND(sizeof(int)) is taken implicitely. that are passed to the function per pointer, with the automatically derived
label(OPTION_SETSOCKOPT_BIN)dit(bf(tt(setsockopt-bin=<level>:<optname>:<optval>))) length parameter.
Like tt(setsockopt-int), but <optval> must be provided in label(OPTION_SETSOCKOPT_INT)dit(bf(tt(setsockopt-int=<level>:<optname>:<optval>)))
link(dalan)(TYPE_DATA) format and specifies an arbitrary sequence of bytes; Like tt(setsockopt), but <optval> is a pointer to int [link(int)(TYPE_INT)]
the length parameter is automatically derived from the data. label(OPTION_SETSOCKOPT_LISTEN)dit(bf(tt(setsockopt-listen=<level>:<optname>:<optval>)))
Like tt(setsockopt), but for listen type addresses it is applied to the
listening socket instead of the connected socket.
label(OPTION_SETSOCKOPT_STRING)dit(bf(tt(setsockopt-string=<level>:<optname>:<optval>))) label(OPTION_SETSOCKOPT_STRING)dit(bf(tt(setsockopt-string=<level>:<optname>:<optval>)))
Like tt(setsockopt-int), but <optval> must be a link(string)(TYPE_STRING). Like tt(setsockopt), but <optval> is a link(string)(TYPE_STRING).
This string is passed to the function with trailing null character, and the This string is passed to the function with trailing null character, and the
length parameter is automatically derived from the data. length parameter is automatically derived from the data.
enddit() enddit()
@ -2805,9 +2799,36 @@ label(TYPE_COMMAND_LINE)dit(command-line)
A string specifying a program name and its arguments, separated by single A string specifying a program name and its arguments, separated by single
spaces. spaces.
label(TYPE_DATA)dit(data) label(TYPE_DATA)dit(data)
A raw data specification following em(dalan) syntax. Currently the only This is a more general data specification. The given text string contains
valid form is a string starting with 'x' followed by an even number of hex information about the target data type and value. Generally a leading
digits, specifying a sequence of bytes. character specifies the type of the following data item. In its specific
context a default data type may exist.nl()
Currently only the following specifications are implemented:nl()
description(
dit(i) A signed integer number, stored in host byte order.nl()
Example: bf(i-1000) (Integer number -1000)
dit(I) An unsigned integer number, stored in host byte order.nl()
dit(l) A signed long integer number, stored in host byte order.nl()
dit(L) An unsigned long integer number, stored in host byte order.nl()
dit(s) A signed short integer number, stored in host byte order.nl()
dit(S) An unsigned short integer number, stored in host byte order.nl()
dit(b) A signed byte (signed char).nl()
dit(B) An unsigned byte (unsigned char).nl()
dit(x) Following is an even number of hex digits, stored as sequence of
bytes.nl()
Example: bf(x7f000001) (IP address 127.0.0.1)
dit(") Following is a string that is used with the common conversions
\n \r \t \f \b \a \e \0; the string must be closed with '"'. Please note
that the quotes and backslashes need to be escaped from shell and socat()
conversion.nl()
Example: bf("Hello world!\n")
dit(') A single char, with the usual conversions. Please note that the
quotes and backslashes need to be escaped from shell and socat() conversion.
nl()
Example: bf('a')
)
Data items may be separated with white space without need to repeat the type
specifier again.
label(TYPE_DIRECTORY)dit(directory) label(TYPE_DIRECTORY)dit(directory)
A string with usual unix() directory name semantics. A string with usual unix() directory name semantics.
label(TYPE_FACILITY)dit(facility) label(TYPE_FACILITY)dit(facility)
@ -2838,7 +2859,7 @@ label(TYPE_IPV4_ADDRESS)dit(IPv4 address)
an IPv4 address.nl() an IPv4 address.nl()
Examples: 127.0.0.1, www.dest-unreach.org, dns2 Examples: 127.0.0.1, www.dest-unreach.org, dns2
label(TYPE_IPV6_ADDRESS)dit(IPv6 address) label(TYPE_IPV6_ADDRESS)dit(IPv6 address)
An iPv6 address in hexnumbers-and-colons notation enclosed in brackets, or a An IPv6 address in hexnumbers-and-colons notation enclosed in brackets, or a
hostname that resolves to an IPv6 address.nl() hostname that resolves to an IPv6 address.nl()
Examples: [::1], [1234:5678:9abc:def0:1234:5678:9abc:def0], Examples: [::1], [1234:5678:9abc:def0:1234:5678:9abc:def0],
ip6name.domain.org ip6name.domain.org

View file

@ -159,6 +159,8 @@ int procan_cdefs(FILE *outfile) {
#ifdef SO_REUSEADDR #ifdef SO_REUSEADDR
fprintf(outfile, "#define SO_REUSEADDR %d\n", SO_REUSEADDR); fprintf(outfile, "#define SO_REUSEADDR %d\n", SO_REUSEADDR);
#endif #endif
#ifdef TCP_MAXSEG
fprintf(outfile, "#define TCP_MAXSEG %d\n", TCP_MAXSEG);
#endif
return 0; return 0;
} }

125
test.sh
View file

@ -11121,14 +11121,90 @@ N=$((N+1))
SOL_SOCKET="$($PROCAN -c |grep "^#define[[:space:]]*SOL_SOCKET[[:space:]]" |cut -d' ' -f3)" SOL_SOCKET="$($PROCAN -c |grep "^#define[[:space:]]*SOL_SOCKET[[:space:]]" |cut -d' ' -f3)"
SO_REUSEADDR="$($PROCAN -c |grep "^#define[[:space:]]*SO_REUSEADDR[[:space:]]" |cut -d' ' -f3)" SO_REUSEADDR="$($PROCAN -c |grep "^#define[[:space:]]*SO_REUSEADDR[[:space:]]" |cut -d' ' -f3)"
TCP_MAXSEG="$($PROCAN -c |grep "^#define[[:space:]]*TCP_MAXSEG[[:space:]]" |cut -d' ' -f3)"
# test the generic setsockopt-int option # Test the generic setsockopt option
if false; then NAME=SETSOCKOPT
# this test no longer works due to fix for options on listening sockets
NAME=SETSOCKOPT_INT
case "$TESTS" in case "$TESTS" in
*%$N%*|*%functions%*|*%ip4%*|*%tcp%*|*%generic%*|*%$NAME%*) *%$N%*|*%functions%*|*%ip4%*|*%tcp%*|*%generic%*|*%$NAME%*)
TEST="$NAME: test the setsockopt-int option" TEST="$NAME: test the setsockopt option"
# Set the TCP_MAXSEG (MSS) option with a reasonable value, this should succeed.
# The try again with TCP_MAXSEG=1, this fails at least on Linux.
# Thus:
# process 0 provides a tcp listening,forking socket
# process 1 connects to this port using reasonably MSS, data transfer should
# succeed.
# Then,
# process 2 connects to this port using a very small MSS, this should fail
if ! eval $NUMCOND; then :;
elif [ -z "$TCP_MAXSEG" ]; then
# we use the numeric value of TCP_MAXSEG which might be system dependent
$PRINTF "test $F_n $TEST... ${YELLOW}value of TCPMAXSEG not known${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
else
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"
CMD0="$TRACE $SOCAT $opts TCP4-L:$PORT,so-reuseaddr,fork PIPE"
CMD1="$TRACE $SOCAT $opts - TCP:$LOCALHOST:$PORT,setsockopt=6:$TCP_MAXSEG:512"
CMD2="$TRACE $SOCAT $opts - TCP:$LOCALHOST:$PORT,setsockopt=6:$TCP_MAXSEG:1"
printf "test $F_n $TEST... " $N
$CMD0 >/dev/null 2>"${te}0" &
pid0=$!
waittcp4port $PORT 1
(echo "$da"; sleep 1) |$CMD1 >"${tf}1" 2>"${te}1" # this should always work
rc1=$?
usleep 1000000
(echo "$da"; sleep 1) |$CMD2 >"${tf}2" 2>"${te}2" # this should fail
rc2=$?
kill $pid0 $pid1 $pid2 2>/dev/null; wait
if ! echo "$da" |diff - "${tf}1" >"$tdiff"; then
$PRINTF "${YELLOW}phase 1 failed${NORMAL}\n"
echo "$CMD0 &"
cat ${te}0
echo "$CMD1"
cat ${te}1
cat "$tdiff"
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif [ $rc1 -ne 0 ]; then
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
echo "$CMD0 &"
cat ${te}0
echo "$CMD1"
cat ${te}1
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
elif [ $rc2 -eq 0 ]; then
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
echo "$CMD0 &"
cat ${te}0
echo "$CMD2"
cat ${te}2
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat "${te}0" "${te}1" "${te}2"; fi
numOK=$((numOK+1))
fi
fi # NUMCOND, SO_REUSEADDR
;;
esac
PORT=$((PORT+1))
N=$((N+1))
# Test the generic setsockopt-listen option
# This test, with setsockopt-int, no longer worked due to fix for options on
# listening sockets
# Now it got a chance again using new option setsockopt-listen
#NAME=SETSOCKOPT_INT
NAME=SETSOCKOPT_LISTEN
case "$TESTS" in
*%$N%*|*%functions%*|*%ip4%*|*%tcp%*|*%generic%*|*%$NAME%*)
TEST="$NAME: test the setsockopt-listen option"
# there are not many socket options that apply to non global resources, do not # there are not many socket options that apply to non global resources, do not
# require root, do not require a network connection, and can easily be # require root, do not require a network connection, and can easily be
# tested. SO_REUSEADDR seems to fit: # tested. SO_REUSEADDR seems to fit:
@ -11145,50 +11221,59 @@ elif [ -z "$SO_REUSEADDR" ]; then
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
listCANT="$listCANT $N" listCANT="$listCANT $N"
else else
tp="$PORT"
tf="$td/test$N.stdout" tf="$td/test$N.stdout"
te="$td/test$N.stderr" te="$td/test$N.stderr"
tdiff="$td/test$N.diff" tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM" da="test$N $(date) $RANDOM"
CMD0="$TRACE $SOCAT $opts TCP4-L:$tp,setsockopt-int=$SOL_SOCKET:$SO_REUSEADDR:1 PIPE" CMD0="$TRACE $SOCAT $opts TCP4-L:$PORT,setsockopt-listen=$SOL_SOCKET:$SO_REUSEADDR:1 PIPE"
CMD1="$TRACE $SOCAT $opts - TCP:localhost:$tp" CMD1="$TRACE $SOCAT $opts - TCP:$LOCALHOST:$PORT"
CMD2="$CMD0" CMD2="$CMD0"
CMD3="$CMD1" CMD3="$CMD1"
printf "test $F_n $TEST... " $N printf "test $F_n $TEST... " $N
$CMD0 >/dev/null 2>"${te}0" & $CMD0 >/dev/null 2>"${te}0" &
pid0=$! pid0=$!
waittcp4port $tp 1 waittcp4port $PORT 1
(echo "$da"; sleep 3) |$CMD1 >"$tf" 2>"${te}1" & # this should always work echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" # this should always work
pid1=$! rc1=$?
usleep 1000000 kill $pid0 2>/dev/null; wait
$CMD2 >/dev/null 2>"${te}2" & $CMD2 >/dev/null 2>"${te}2" &
pid2=$! pid2=$!
waittcp4port $tp 1 waittcp4port $PORT 1
(echo "$da") |$CMD3 >"${tf}3" 2>"${te}3" echo "$da" |$CMD3 >"${tf}3" 2>"${te}3"
rc3=$? rc3=$?
kill $pid0 $pid1 $pid2 2>/dev/null; wait kill $pid2 2>/dev/null; wait
if ! echo "$da" |diff - "$tf"; then if ! echo "$da" |diff - "${tf}1" >"${tdiff}1"; then
$PRINTF "${YELLOW}phase 1 failed${NORMAL}\n" $PRINTF "${YELLOW}phase 1 failed${NORMAL}\n"
echo "$CMD0 &" echo "$CMD0 &"
cat ${te}0
echo "$CMD1" echo "$CMD1"
cat ${te}1
cat "${tdiff}1"
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
listCANT="$listCANT $N" listCANT="$listCANT $N"
elif [ $rc3 -ne 0 ]; then elif [ $rc3 -ne 0 ]; then
$PRINTF "$FAILED: $TRACE $SOCAT:\n" $PRINTF "$FAILED: $TRACE $SOCAT:\n"
echo "$CMD0 &" echo "$CMD0 &"
cat ${te}0
echo "$CMD1" echo "$CMD1"
cat ${te}1
echo "$CMD2 &" echo "$CMD2 &"
cat ${te}2
echo "$CMD3" echo "$CMD3"
cat "${te}2" "${te}3" cat ${te}3
numFAIL=$((numFAIL+1)) numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N" listFAIL="$listFAIL $N"
elif ! echo "$da" |diff - "${tf}3"; then elif ! echo "$da" |diff - "${tf}3" >"${tdiff}3"; then
$PRINTF "$FAILED: $TRACE $SOCAT:\n" $PRINTF "$FAILED: $TRACE $SOCAT:\n"
echo "$CMD0 &" echo "$CMD0 &"
cat ${te}0
echo "$CMD1" echo "$CMD1"
cat ${te}1
echo "$CMD2 &" echo "$CMD2 &"
cat ${te}2
echo "$CMD3" echo "$CMD3"
echo "$da" |diff - "${tf}3" cat ${te}3
cat "${tdiff}3"
numCANT=$((numCANT+1)) numCANT=$((numCANT+1))
listCANT="$listCANT $N" listCANT="$listCANT $N"
else else
@ -11201,8 +11286,6 @@ fi # NUMCOND, SO_REUSEADDR
esac esac
PORT=$((PORT+1)) PORT=$((PORT+1))
N=$((N+1)) N=$((N+1))
#
fi
NAME=SCTP4STREAM NAME=SCTP4STREAM

View file

@ -146,6 +146,7 @@ int _xioopen_listen(struct single *xfd, int xioflags, struct sockaddr *us, sockl
if ((xfd->fd = xiosocket(opts, us->sa_family, socktype, proto, level)) < 0) { if ((xfd->fd = xiosocket(opts, us->sa_family, socktype, proto, level)) < 0) {
return STAT_RETRYLATER; return STAT_RETRYLATER;
} }
applyopts(xfd->fd, opts, PH_PASTSOCKET);
applyopts_cloexec(xfd->fd, opts); applyopts_cloexec(xfd->fd, opts);

View file

@ -186,9 +186,11 @@ const struct optdesc opt_protocol_family = { "protocol-family", "pf", OPT_PROTOC
const struct optdesc opt_protocol = { "protocol", NULL, OPT_PROTOCOL, GROUP_SOCKET, PH_PRESOCKET, TYPE_STRING, OFUNC_SPEC }; const struct optdesc opt_protocol = { "protocol", NULL, OPT_PROTOCOL, GROUP_SOCKET, PH_PRESOCKET, TYPE_STRING, OFUNC_SPEC };
/* generic setsockopt() options */ /* generic setsockopt() options */
const struct optdesc opt_setsockopt_int = { "setsockopt-int", "sockopt-int", OPT_SETSOCKOPT_INT, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_INT, OFUNC_SOCKOPT_GENERIC, 0, 0 }; const struct optdesc opt_setsockopt = { "setsockopt", "sockopt", OPT_SETSOCKOPT_BIN, GROUP_SOCKET,PH_CONNECTED, TYPE_INT_INT_BIN, OFUNC_SOCKOPT_GENERIC, 0, 0 };
const struct optdesc opt_setsockopt_bin = { "setsockopt-bin", "sockopt-bin", OPT_SETSOCKOPT_BIN, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_BIN, OFUNC_SOCKOPT_GENERIC, 0, 0 }; const struct optdesc opt_setsockopt_int = { "setsockopt-int", "sockopt-int", OPT_SETSOCKOPT_INT, GROUP_SOCKET,PH_CONNECTED, TYPE_INT_INT_INT, OFUNC_SOCKOPT_GENERIC, 0, 0 };
const struct optdesc opt_setsockopt_string = { "setsockopt-string", "sockopt-string", OPT_SETSOCKOPT_STRING, GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT_INT_STRING, OFUNC_SOCKOPT_GENERIC, 0, 0 }; const struct optdesc opt_setsockopt_bin = { "setsockopt-bin", "sockopt-bin", OPT_SETSOCKOPT_BIN, GROUP_SOCKET,PH_CONNECTED, TYPE_INT_INT_BIN, OFUNC_SOCKOPT_GENERIC, 0, 0 };
const struct optdesc opt_setsockopt_string = { "setsockopt-string", "sockopt-string", OPT_SETSOCKOPT_STRING, GROUP_SOCKET,PH_CONNECTED, TYPE_INT_INT_STRING, OFUNC_SOCKOPT_GENERIC, 0, 0 };
const struct optdesc opt_setsockopt_listen = { "setsockopt-listen", "sockopt-listen", OPT_SETSOCKOPT_LISTEN, GROUP_SOCKET,PH_PREBIND, TYPE_INT_INT_BIN, OFUNC_SOCKOPT_GENERIC, 0, 0 };
const struct optdesc opt_null_eof = { "null-eof", NULL, OPT_NULL_EOF, GROUP_SOCKET, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, XIO_OFFSETOF(para.socket.null_eof) }; const struct optdesc opt_null_eof = { "null-eof", NULL, OPT_NULL_EOF, GROUP_SOCKET, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, XIO_OFFSETOF(para.socket.null_eof) };
@ -239,7 +241,7 @@ int xioopen_socket_connect(int argc, const char *argv[], struct opt *opts,
themsize = 0; themsize = 0;
if ((result = if ((result =
dalan(address, (char *)&them.soa.sa_data, &themsize, sizeof(them))) dalan(address, (uint8_t *)&them.soa.sa_data, &themsize, sizeof(them), 'i'))
< 0) { < 0) {
Error1("data too long: \"%s\"", address); Error1("data too long: \"%s\"", address);
} else if (result > 0) { } else if (result > 0) {
@ -316,7 +318,7 @@ int xioopen_socket_listen(int argc, const char *argv[], struct opt *opts,
socket_init(0, &us); socket_init(0, &us);
ussize = 0; ussize = 0;
if ((result = if ((result =
dalan(usname, (char *)&us.soa.sa_data, &ussize, sizeof(us))) dalan(usname, (uint8_t *)&us.soa.sa_data, &ussize, sizeof(us), 'i'))
< 0) { < 0) {
Error1("data too long: \"%s\"", usname); Error1("data too long: \"%s\"", usname);
} else if (result > 0) { } else if (result > 0) {
@ -407,8 +409,8 @@ int _xioopen_socket_sendto(const char *pfname, const char *type,
xfd->peersa.soa.sa_family = pf; xfd->peersa.soa.sa_family = pf;
themsize = 0; themsize = 0;
if ((result = if ((result =
dalan(address, (char *)&xfd->peersa.soa.sa_data, &themsize, dalan(address, (uint8_t *)&xfd->peersa.soa.sa_data, &themsize,
sizeof(xfd->peersa))) sizeof(xfd->peersa), 'i'))
< 0) { < 0) {
Error1("data too long: \"%s\"", address); Error1("data too long: \"%s\"", address);
} else if (result > 0) { } else if (result > 0) {
@ -438,7 +440,7 @@ int _xioopen_socket_sendto(const char *pfname, const char *type,
if (retropt_string(opts, OPT_BIND, &bindstring) == 0) { if (retropt_string(opts, OPT_BIND, &bindstring) == 0) {
ussize = 0; ussize = 0;
if ((result = if ((result =
dalan(bindstring, (char *)&us.soa.sa_data, &ussize, sizeof(us))) dalan(bindstring, (uint8_t *)&us.soa.sa_data, &ussize, sizeof(us), 'i'))
< 0) { < 0) {
Error1("data too long: \"%s\"", bindstring); Error1("data too long: \"%s\"", bindstring);
} else if (result > 0) { } else if (result > 0) {
@ -504,7 +506,7 @@ int xioopen_socket_recvfrom(int argc, const char *argv[], struct opt *opts,
ussize = 0; ussize = 0;
if ((result = if ((result =
dalan(address, (char *)&us->soa.sa_data, &ussize, sizeof(*us))) dalan(address, (uint8_t *)&us->soa.sa_data, &ussize, sizeof(*us), 'i'))
< 0) { < 0) {
Error1("data too long: \"%s\"", address); Error1("data too long: \"%s\"", address);
} else if (result > 0) { } else if (result > 0) {
@ -581,7 +583,7 @@ int xioopen_socket_recv(int argc, const char *argv[], struct opt *opts,
ussize = 0; ussize = 0;
if ((result = if ((result =
dalan(address, (char *)&us.soa.sa_data, &ussize, sizeof(us))) dalan(address, (uint8_t *)&us.soa.sa_data, &ussize, sizeof(us), 'i'))
< 0) { < 0) {
Error1("data too long: \"%s\"", address); Error1("data too long: \"%s\"", address);
} else if (result > 0) { } else if (result > 0) {
@ -649,8 +651,8 @@ int xioopen_socket_datagram(int argc, const char *argv[], struct opt *opts,
xfd->peersa.soa.sa_family = pf; xfd->peersa.soa.sa_family = pf;
themsize = 0; themsize = 0;
if ((result = if ((result =
dalan(address, (char *)&xfd->peersa.soa.sa_data, &themsize, dalan(address, (uint8_t *)&xfd->peersa.soa.sa_data, &themsize,
sizeof(xfd->peersa))) sizeof(xfd->peersa), 'i'))
< 0) { < 0) {
Error1("data too long: \"%s\"", address); Error1("data too long: \"%s\"", address);
} else if (result > 0) { } else if (result > 0) {
@ -1992,9 +1994,9 @@ int xioparsenetwork(const char *rangename, int pf, struct xiorange *range) {
strncpy(addrname, rangename, maskname-rangename-1); /* ok */ strncpy(addrname, rangename, maskname-rangename-1); /* ok */
addrname[maskname-rangename-1] = '\0'; addrname[maskname-rangename-1] = '\0';
result = result =
dalan(addrname, (char *)&range->netaddr.soa.sa_data, &addrlen, dalan(addrname, (uint8_t *)&range->netaddr.soa.sa_data, &addrlen,
sizeof(range->netaddr)-(size_t)(&((struct sockaddr *)0)->sa_data) sizeof(range->netaddr)-(size_t)(&((struct sockaddr *)0)->sa_data)
/* data length */); /* data length */, 'i');
if (result < 0) { if (result < 0) {
Error1("data too long: \"%s\"", addrname); Error1("data too long: \"%s\"", addrname);
free(addrname); return STAT_NORETRY; free(addrname); return STAT_NORETRY;
@ -2004,9 +2006,9 @@ int xioparsenetwork(const char *rangename, int pf, struct xiorange *range) {
} }
free(addrname); free(addrname);
result = result =
dalan(maskname, (char *)&range->netmask.soa.sa_data, &masklen, dalan(maskname, (uint8_t *)&range->netmask.soa.sa_data, &masklen,
sizeof(range->netaddr)-(size_t)(&((struct sockaddr *)0)->sa_data) sizeof(range->netaddr)-(size_t)(&((struct sockaddr *)0)->sa_data)
/* data length */); /* data length */, 'i');
if (result < 0) { if (result < 0) {
Error1("data too long: \"%s\"", maskname); Error1("data too long: \"%s\"", maskname);
return STAT_NORETRY; return STAT_NORETRY;

View file

@ -62,9 +62,11 @@ extern const struct optdesc opt_fiosetown;
extern const struct optdesc opt_siocspgrp; extern const struct optdesc opt_siocspgrp;
extern const struct optdesc opt_bind; extern const struct optdesc opt_bind;
extern const struct optdesc opt_protocol_family; extern const struct optdesc opt_protocol_family;
extern const struct optdesc opt_setsockopt;
extern const struct optdesc opt_setsockopt_int; extern const struct optdesc opt_setsockopt_int;
extern const struct optdesc opt_setsockopt_bin; extern const struct optdesc opt_setsockopt_bin;
extern const struct optdesc opt_setsockopt_string; extern const struct optdesc opt_setsockopt_string;
extern const struct optdesc opt_setsockopt_listen;
extern const struct optdesc opt_null_eof; extern const struct optdesc opt_null_eof;

View file

@ -1402,8 +1402,10 @@ const struct optname optionnames[] = {
#if WITH_EXEC || WITH_SYSTEM #if WITH_EXEC || WITH_SYSTEM
IF_EXEC ("setsid", &opt_setsid) IF_EXEC ("setsid", &opt_setsid)
#endif #endif
IF_SOCKET ("setsockopt", &opt_setsockopt)
IF_SOCKET ("setsockopt-bin", &opt_setsockopt_bin) IF_SOCKET ("setsockopt-bin", &opt_setsockopt_bin)
IF_SOCKET ("setsockopt-int", &opt_setsockopt_int) IF_SOCKET ("setsockopt-int", &opt_setsockopt_int)
IF_SOCKET ("setsockopt-listen", &opt_setsockopt_listen)
IF_SOCKET ("setsockopt-string", &opt_setsockopt_string) IF_SOCKET ("setsockopt-string", &opt_setsockopt_string)
IF_ANY ("setuid", &opt_setuid) IF_ANY ("setuid", &opt_setuid)
IF_ANY ("setuid-early", &opt_setuid_early) IF_ANY ("setuid-early", &opt_setuid_early)
@ -1517,8 +1519,10 @@ const struct optname optionnames[] = {
#ifdef SO_USELOOPBACK /* AIX433, Solaris */ #ifdef SO_USELOOPBACK /* AIX433, Solaris */
IF_SOCKET ("so-useloopback", &opt_so_useloopback) IF_SOCKET ("so-useloopback", &opt_so_useloopback)
#endif /* SO_USELOOPBACK */ #endif /* SO_USELOOPBACK */
IF_SOCKET ("sockopt", &opt_setsockopt)
IF_SOCKET ("sockopt-bin", &opt_setsockopt_bin) IF_SOCKET ("sockopt-bin", &opt_setsockopt_bin)
IF_SOCKET ("sockopt-int", &opt_setsockopt_int) IF_SOCKET ("sockopt-int", &opt_setsockopt_int)
IF_SOCKET ("sockopt-listen", &opt_setsockopt_listen)
IF_SOCKET ("sockopt-string", &opt_setsockopt_string) IF_SOCKET ("sockopt-string", &opt_setsockopt_string)
IF_SOCKS4 ("socksport", &opt_socksport) IF_SOCKS4 ("socksport", &opt_socksport)
IF_SOCKS4 ("socksuser", &opt_socksuser) IF_SOCKS4 ("socksuser", &opt_socksuser)
@ -1824,7 +1828,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
char token[2048], *tokp; size_t len; char token[2048], *tokp; size_t len;
int parsres; int parsres;
int result; int result;
char optbuf[256]; size_t optlen; uint8_t optbuf[256]; size_t optlen;
const char *endkey[6+1]; const char *endkey[6+1];
const char *endval[5+1]; const char *endval[5+1];
const char *assign_str = "="; const char *assign_str = "=";
@ -1895,15 +1899,15 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
ent = (struct optname *) ent = (struct optname *)
keyw((struct wordent *)optionnames, token, optionnum); keyw((struct wordent *)optionnames, token, optionnum);
if (ent == NULL) { if (ent == NULL) {
Error1("parseopts(): unknown option \"%s\"", token); Error1("parseopts_table(): unknown option \"%s\"", token);
continue; continue;
} }
if (!(ent->desc->group & groups) && !(ent->desc->group & GROUP_ANY) && if (!(ent->desc->group & groups) && !(ent->desc->group & GROUP_ANY) &&
!xioopts_ignoregroups) { !xioopts_ignoregroups) {
Error1("parseopts(): option \"%s\" not supported with this address type", Error1("parseopts_table(): option \"%s\" not supported with this address type",
token /*a0*/); token /*a0*/);
Info2("parseopts() groups=%08x, ent->group=%08x", Info2("parseopts_table() groups=%08x, ent->group=%08x",
groups, ent->desc->group); groups, ent->desc->group);
#if 0 #if 0
continue; continue;
@ -1946,8 +1950,8 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
if (!assign) { Error1("option \"%s\": value required", a0); if (!assign) { Error1("option \"%s\": value required", a0);
continue; } continue; }
optlen = 0; optlen = 0;
if ((result = dalan(token, optbuf, &optlen, sizeof(optbuf))) != 0) { if ((result = dalan(token, optbuf, &optlen, sizeof(optbuf), 'i')) != 0) {
Error1("parseopts(): problem with \"%s\" data", token); Error1("parseopts_table(): problem with \"%s\" data", token);
continue; continue;
} }
if (((*opts)[i].value.u_bin.b_data = memdup(optbuf, optlen)) == NULL) { if (((*opts)[i].value.u_bin.b_data = memdup(optbuf, optlen)) == NULL) {
@ -1962,7 +1966,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
char *rest; char *rest;
ul = strtoul(token, &rest/*!*/, 0); ul = strtoul(token, &rest/*!*/, 0);
if (ul > UCHAR_MAX) { if (ul > UCHAR_MAX) {
Error3("parseopts(%s): byte value exceeds limit (%lu vs. %u), using max", Error3("parseopts_table(%s): byte value exceeds limit (%lu vs. %u), using max",
a0, ul, UCHAR_MAX); a0, ul, UCHAR_MAX);
(*opts)[i].value.u_byte = UCHAR_MAX; (*opts)[i].value.u_byte = UCHAR_MAX;
} else { } else {
@ -2011,7 +2015,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
char *rest; char *rest;
ulongval = strtoul(token, &rest/*!*/, 0); ulongval = strtoul(token, &rest/*!*/, 0);
if (ulongval > UINT_MAX) { if (ulongval > UINT_MAX) {
Error3("parseopts(%s): unsigned int value exceeds limit (%lu vs. %u), using max", Error3("parseopts_table(%s): unsigned int value exceeds limit (%lu vs. %u), using max",
a0, ulongval, UINT_MAX); a0, ulongval, UINT_MAX);
} }
(*opts)[i].value.u_uint = ulongval; (*opts)[i].value.u_uint = ulongval;
@ -2030,7 +2034,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
char *rest; char *rest;
ulongval = strtoul(token, &rest/*!*/, 0); ulongval = strtoul(token, &rest/*!*/, 0);
if (ulongval > USHRT_MAX) { if (ulongval > USHRT_MAX) {
Error3("parseopts(%s): unsigned short value exceeds limit (%lu vs. %u), using max", Error3("parseopts_table(%s): unsigned short value exceeds limit (%lu vs. %u), using max",
a0, ulongval, USHRT_MAX); a0, ulongval, USHRT_MAX);
} }
(*opts)[i].value.u_ushort = ulongval; (*opts)[i].value.u_ushort = ulongval;
@ -2266,8 +2270,8 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
} }
++rest; ++rest;
optlen = 0; optlen = 0;
if ((result = dalan(rest, optbuf, &optlen, sizeof(optbuf))) != 0) { if ((result = dalan(rest, optbuf, &optlen, sizeof(optbuf), 'i')) != 0) {
Error1("parseopts(): problem with \"%s\" data", rest); Error1("parseopts_table(): problem with \"%s\" data", rest);
continue; continue;
} }
if (((*opts)[i].value2.u_bin.b_data = memdup(optbuf, optlen)) == NULL) { if (((*opts)[i].value2.u_bin.b_data = memdup(optbuf, optlen)) == NULL) {
@ -2327,6 +2331,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
break; break;
case TYPE_INT_INT_BIN: case TYPE_INT_INT_BIN:
case TYPE_INT_INT_GENERIC:
if (!assign) { if (!assign) {
Error1("option \"%s\": values required", a0); Error1("option \"%s\": values required", a0);
continue; continue;
@ -2346,8 +2351,8 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
} }
++rest; ++rest;
optlen = 0; optlen = 0;
if ((result = dalan(rest, optbuf, &optlen, sizeof(optbuf))) != 0) { if ((result = dalan(rest, optbuf, &optlen, sizeof(optbuf), 'i')) != 0) {
Error1("parseopts(): problem with \"%s\" data", rest); Error1("parseopts_table(): problem with \"%s\" data", rest);
continue; continue;
} }
if (((*opts)[i].value3.u_bin.b_data = memdup(optbuf, optlen)) == NULL) { if (((*opts)[i].value3.u_bin.b_data = memdup(optbuf, optlen)) == NULL) {
@ -2494,8 +2499,25 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
break; break;
#endif /* defined(WITH_IP4) */ #endif /* defined(WITH_IP4) */
case TYPE_GENERIC:
if (!assign) {
(*opts)[i].value.u_int = 1;
} else {
int rc;
size_t binlen = 64; /*!!!*/
if (((*opts[i]).value.u_bin.b_data = Malloc(binlen)) == NULL) Error("!!!");
(*opts)[i].value.u_bin.b_len = 0;
rc = dalan(token, (*opts)[i].value.u_bin.b_data,
&(*opts)[i].value.u_bin.b_len, binlen, 'i');
if (rc != 0) {
Error("!!!");
}
//(*opts)[i].value.u_bin.b_len
}
break;
default: default:
Error2("parseopts(): internal error on option \"%s\": unimplemented type %d", Error2("parseopts_table(): internal error on option \"%s\": unimplemented type %d",
ent->desc->defname, ent->desc->type); ent->desc->defname, ent->desc->type);
continue; continue;
} }
@ -2964,7 +2986,7 @@ int retropt_bind(struct opt *opts,
case AF_UNSPEC: case AF_UNSPEC:
{ {
size_t p = 0; size_t p = 0;
dalan(bindname, (char *)sa->sa_data, &p, *salen-sizeof(sa->sa_family)); dalan(bindname, (uint8_t *)sa->sa_data, &p, *salen-sizeof(sa->sa_family), 'i');
*salen = p + sizeof(sa->sa_family); *salen = p + sizeof(sa->sa_family);
*salen = p + *salen = p +
#if HAVE_STRUCT_SOCKADDR_SALEN #if HAVE_STRUCT_SOCKADDR_SALEN

View file

@ -64,6 +64,7 @@ enum e_types {
TYPE_INT_INT_INT, /* 3 params: first and second are int, 3rd is int */ TYPE_INT_INT_INT, /* 3 params: first and second are int, 3rd is int */
TYPE_INT_INT_BIN, /* 3 params: first and second are int, 3rd is binary */ TYPE_INT_INT_BIN, /* 3 params: first and second are int, 3rd is binary */
TYPE_INT_INT_STRING, /* 3 params: first and second are int, 3rd is string */ TYPE_INT_INT_STRING, /* 3 params: first and second are int, 3rd is string */
TYPE_INT_INT_GENERIC, /* 3 params: first and second are int, 3rd is specified by value (dalan syntax) */
TYPE_IP4NAME, /* IPv4 hostname or address */ TYPE_IP4NAME, /* IPv4 hostname or address */
#if HAVE_STRUCT_LINGER #if HAVE_STRUCT_LINGER
@ -72,6 +73,8 @@ enum e_types {
#if HAVE_STRUCT_IP_MREQ || HAVE_STRUCT_IP_MREQN #if HAVE_STRUCT_IP_MREQ || HAVE_STRUCT_IP_MREQN
TYPE_IP_MREQN, /* for struct ip_mreq or struct ip_mreqn */ TYPE_IP_MREQN, /* for struct ip_mreq or struct ip_mreqn */
#endif #endif
TYPE_GENERIC, /* type is determined from (text) data provided */
} ; } ;
enum e_func { enum e_func {
@ -596,6 +599,7 @@ enum e_optcode {
OPT_SETSID, OPT_SETSID,
OPT_SETSOCKOPT_BIN, OPT_SETSOCKOPT_BIN,
OPT_SETSOCKOPT_INT, OPT_SETSOCKOPT_INT,
OPT_SETSOCKOPT_LISTEN,
OPT_SETSOCKOPT_STRING, OPT_SETSOCKOPT_STRING,
OPT_SETUID, OPT_SETUID,
OPT_SETUID_EARLY, OPT_SETUID_EARLY,