mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 07:22:34 +00:00
New option setsockopt-listen using dalan
This commit is contained in:
parent
411b658939
commit
10680c8aad
11 changed files with 470 additions and 230 deletions
8
CHANGES
8
CHANGES
|
@ -104,6 +104,14 @@ New features:
|
|||
Test: GOPENUNIXSEQPACKET
|
||||
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:
|
||||
|
||||
Corrections:
|
||||
|
|
197
dalan.c
197
dalan.c
|
@ -6,6 +6,7 @@
|
|||
primitive subset exists. */
|
||||
|
||||
#include "config.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#if HAVE_STDBOOL_H
|
||||
|
@ -70,56 +71,35 @@ void dalan_init(void) {
|
|||
_dalan_dflts(&dalan_opts);
|
||||
}
|
||||
|
||||
/* read data description from line, write result to data; do not write
|
||||
so much data that *p exceeds n !
|
||||
p must be initialized to 0.
|
||||
return 0 on success,
|
||||
/* Parses and coverts a data item.
|
||||
Returns 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!
|
||||
2 if the actual character is white space
|
||||
3 if the first character is not a type specifier
|
||||
*/
|
||||
int dalan(const char *line, char *data, size_t *p, size_t n) {
|
||||
int align, mask, i, x;
|
||||
static int dalan_item(int c, const char **line0, uint8_t *data, size_t *p, size_t n) {
|
||||
const char *line = *line0;
|
||||
size_t p1 = *p;
|
||||
char c;
|
||||
|
||||
/*fputs(line, stderr); fputc('\n', stderr);*/
|
||||
while (c = *line++) {
|
||||
switch (c) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
break;
|
||||
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;
|
||||
return 2;
|
||||
case '"':
|
||||
while (1) {
|
||||
switch (c = *line++) {
|
||||
case '\0': fputs("unterminated string\n", stderr);
|
||||
*line0 = line;
|
||||
return 1;
|
||||
case '"':
|
||||
break;
|
||||
case '\\':
|
||||
if (!(c = *line++)) {
|
||||
fputs("continuation line not implemented\n", stderr);
|
||||
*line0 = line;
|
||||
return 1;
|
||||
}
|
||||
switch (c) {
|
||||
|
@ -138,7 +118,11 @@ int dalan(const char *line, char *data, size_t *p, size_t n) {
|
|||
}
|
||||
/* PASSTHROUGH */
|
||||
default:
|
||||
if (p1 >= n) { *p = p1; return -1; }
|
||||
if (p1 >= n) {
|
||||
*p = p1;
|
||||
*line0 = line;
|
||||
return -1;
|
||||
}
|
||||
data[p1++] = c;
|
||||
continue;
|
||||
}
|
||||
|
@ -149,12 +133,15 @@ int dalan(const char *line, char *data, size_t *p, size_t n) {
|
|||
case '\'':
|
||||
switch (c = *line++) {
|
||||
case '\0': fputs("unterminated character\n", stderr);
|
||||
*line0 = line;
|
||||
return 1;
|
||||
case '\'': fputs("error in character\n", stderr);
|
||||
*line0 = line;
|
||||
return 1;
|
||||
case '\\':
|
||||
if (!(c = *line++)) {
|
||||
fputs("continuation line not implemented\n", stderr);
|
||||
*line0 = line;
|
||||
return 1;
|
||||
}
|
||||
switch (c) {
|
||||
|
@ -178,25 +165,16 @@ int dalan(const char *line, char *data, size_t *p, size_t n) {
|
|||
}
|
||||
if (*line != '\'') {
|
||||
fputs("error in character termination\n", stderr);
|
||||
*p = p1; return 1;
|
||||
*p = p1;
|
||||
*line0 = line;
|
||||
return 1;
|
||||
}
|
||||
++line;
|
||||
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':
|
||||
/* expecting hex data, must be an even number of digits!! */
|
||||
while (true) {
|
||||
int x;
|
||||
c = *line;
|
||||
if (isdigit(c&0xff)) {
|
||||
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;
|
||||
} else {
|
||||
fputs("odd number of hexadecimal digits\n", stderr);
|
||||
*p = p1; return 1;
|
||||
*p = p1;
|
||||
*line0 = line;
|
||||
return 1;
|
||||
}
|
||||
++line;
|
||||
if (p1 >= n) { *p = p1; return -1; }
|
||||
if (p1 >= n) {
|
||||
*p = p1;
|
||||
*line0 = line;
|
||||
return -1;
|
||||
}
|
||||
data[p1++] = x;
|
||||
}
|
||||
break;
|
||||
case 'A': case 'a':
|
||||
case 'C': case 'c':
|
||||
default: fprintf(stderr, "syntax error in \"%s\"\n", line-1);
|
||||
return 1;
|
||||
case 'l':
|
||||
/* expecting decimal number, with target type long */
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
2
dalan.h
2
dalan.h
|
@ -25,6 +25,6 @@ extern struct dalan_opts_s dalan_opts;
|
|||
|
||||
extern void dalan_init(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) */
|
||||
|
|
83
doc/socat.yo
83
doc/socat.yo
|
@ -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()
|
||||
Useful options:
|
||||
link(bind)(OPTION_BIND),
|
||||
link(setsockopt-int)(OPTION_SETSOCKOPT_INT),
|
||||
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN),
|
||||
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
|
||||
link(setsockopt)(OPTION_SETSOCKOPT),
|
||||
nl()
|
||||
See also:
|
||||
link(TCP)(ADDRESS_TCP_CONNECT),
|
||||
|
@ -733,9 +731,7 @@ label(ADDRESS_SOCKET_DATAGRAM)dit(bf(tt(SOCKET-DATAGRAM:<domain>:<type>:<protoco
|
|||
Useful options:
|
||||
link(bind)(OPTION_BIND),
|
||||
link(range)(OPTION_RANGE),
|
||||
link(setsockopt-int)(OPTION_SETSOCKOPT_INT),
|
||||
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN),
|
||||
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
|
||||
link(setsockopt)(OPTION_SETSOCKOPT),
|
||||
nl()
|
||||
See also:
|
||||
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()
|
||||
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:
|
||||
link(setsockopt-int)(OPTION_SETSOCKOPT_INT),
|
||||
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN),
|
||||
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
|
||||
link(setsockopt)(OPTION_SETSOCKOPT),
|
||||
link(setsockopt-listen)(OPTION_SETSOCKOPT_LISTEN),
|
||||
nl()
|
||||
See also:
|
||||
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()
|
||||
Useful options:
|
||||
link(range)(OPTION_RANGE),
|
||||
link(setsockopt-int)(OPTION_SETSOCKOPT_INT),
|
||||
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN),
|
||||
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
|
||||
link(setsockopt)(OPTION_SETSOCKOPT),
|
||||
link(setsockopt-listen)(OPTION_SETSOCKOPT_LISTEN)
|
||||
nl()
|
||||
See also:
|
||||
link(UDP-RECV)(ADDRESS_UDP_RECV),
|
||||
|
@ -800,9 +794,8 @@ label(ADDRESS_SOCKET_RECVFROM)dit(bf(tt(SOCKET-RECVFROM:<domain>:<type>:<protoco
|
|||
Useful options:
|
||||
link(fork)(OPTION_FORK),
|
||||
link(range)(OPTION_RANGE),
|
||||
link(setsockopt-int)(OPTION_SETSOCKOPT_INT),
|
||||
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN),
|
||||
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
|
||||
link(setsockopt)(OPTION_SETSOCKOPT),
|
||||
link(setsockopt-listen)(OPTION_SETSOCKOPT_LISTEN)
|
||||
nl()
|
||||
See also:
|
||||
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()
|
||||
Useful options:
|
||||
link(bind)(OPTION_BIND),
|
||||
link(setsockopt-int)(OPTION_SETSOCKOPT_INT),
|
||||
link(setsockopt-bin)(OPTION_SETSOCKOPT_BIN),
|
||||
link(setsockopt-string)(OPTION_SETSOCKOPT_STRING)
|
||||
link(setsockopt)(OPTION_SETSOCKOPT),
|
||||
link(setsockopt-listen)(OPTION_SETSOCKOPT_LISTEN)
|
||||
nl()
|
||||
See also:
|
||||
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)))
|
||||
Sets the SO_TIMESTAMP socket option. This enables receiving and logging of
|
||||
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)
|
||||
[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
|
||||
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
|
||||
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)
|
||||
[link(int)(TYPE_INT)], is passed to the function per pointer, and for the
|
||||
length parameter NOEXPAND(sizeof(int)) is taken implicitely.
|
||||
label(OPTION_SETSOCKOPT_BIN)dit(bf(tt(setsockopt-bin=<level>:<optname>:<optval>)))
|
||||
Like tt(setsockopt-int), but <optval> must be provided in
|
||||
link(dalan)(TYPE_DATA) format and specifies an arbitrary sequence of bytes;
|
||||
the length parameter is automatically derived from the data.
|
||||
files of your system. For the 4th and 5th tt(setsockopt()) parameters,
|
||||
tt(value) [link(dalan)(TYPE_DATA)] specifies an arbitrary sequence of bytes
|
||||
that are passed to the function per pointer, with the automatically derived
|
||||
length parameter.
|
||||
label(OPTION_SETSOCKOPT_INT)dit(bf(tt(setsockopt-int=<level>:<optname>:<optval>)))
|
||||
Like tt(setsockopt), but <optval> is a pointer to int [link(int)(TYPE_INT)]
|
||||
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>)))
|
||||
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
|
||||
length parameter is automatically derived from the data.
|
||||
enddit()
|
||||
|
@ -2805,9 +2799,36 @@ label(TYPE_COMMAND_LINE)dit(command-line)
|
|||
A string specifying a program name and its arguments, separated by single
|
||||
spaces.
|
||||
label(TYPE_DATA)dit(data)
|
||||
A raw data specification following em(dalan) syntax. Currently the only
|
||||
valid form is a string starting with 'x' followed by an even number of hex
|
||||
digits, specifying a sequence of bytes.
|
||||
This is a more general data specification. The given text string contains
|
||||
information about the target data type and value. Generally a leading
|
||||
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)
|
||||
A string with usual unix() directory name semantics.
|
||||
label(TYPE_FACILITY)dit(facility)
|
||||
|
@ -2838,7 +2859,7 @@ label(TYPE_IPV4_ADDRESS)dit(IPv4 address)
|
|||
an IPv4 address.nl()
|
||||
Examples: 127.0.0.1, www.dest-unreach.org, dns2
|
||||
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()
|
||||
Examples: [::1], [1234:5678:9abc:def0:1234:5678:9abc:def0],
|
||||
ip6name.domain.org
|
||||
|
|
|
@ -159,6 +159,8 @@ int procan_cdefs(FILE *outfile) {
|
|||
#ifdef SO_REUSEADDR
|
||||
fprintf(outfile, "#define SO_REUSEADDR %d\n", SO_REUSEADDR);
|
||||
#endif
|
||||
|
||||
#ifdef TCP_MAXSEG
|
||||
fprintf(outfile, "#define TCP_MAXSEG %d\n", TCP_MAXSEG);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
|
125
test.sh
125
test.sh
|
@ -11121,14 +11121,90 @@ N=$((N+1))
|
|||
|
||||
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)"
|
||||
TCP_MAXSEG="$($PROCAN -c |grep "^#define[[:space:]]*TCP_MAXSEG[[:space:]]" |cut -d' ' -f3)"
|
||||
|
||||
# test the generic setsockopt-int option
|
||||
if false; then
|
||||
# this test no longer works due to fix for options on listening sockets
|
||||
NAME=SETSOCKOPT_INT
|
||||
# Test the generic setsockopt option
|
||||
NAME=SETSOCKOPT
|
||||
case "$TESTS" in
|
||||
*%$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
|
||||
# require root, do not require a network connection, and can easily be
|
||||
# tested. SO_REUSEADDR seems to fit:
|
||||
|
@ -11145,50 +11221,59 @@ elif [ -z "$SO_REUSEADDR" ]; then
|
|||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
tp="$PORT"
|
||||
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:$tp,setsockopt-int=$SOL_SOCKET:$SO_REUSEADDR:1 PIPE"
|
||||
CMD1="$TRACE $SOCAT $opts - TCP:localhost:$tp"
|
||||
CMD0="$TRACE $SOCAT $opts TCP4-L:$PORT,setsockopt-listen=$SOL_SOCKET:$SO_REUSEADDR:1 PIPE"
|
||||
CMD1="$TRACE $SOCAT $opts - TCP:$LOCALHOST:$PORT"
|
||||
CMD2="$CMD0"
|
||||
CMD3="$CMD1"
|
||||
printf "test $F_n $TEST... " $N
|
||||
$CMD0 >/dev/null 2>"${te}0" &
|
||||
pid0=$!
|
||||
waittcp4port $tp 1
|
||||
(echo "$da"; sleep 3) |$CMD1 >"$tf" 2>"${te}1" & # this should always work
|
||||
pid1=$!
|
||||
usleep 1000000
|
||||
waittcp4port $PORT 1
|
||||
echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" # this should always work
|
||||
rc1=$?
|
||||
kill $pid0 2>/dev/null; wait
|
||||
$CMD2 >/dev/null 2>"${te}2" &
|
||||
pid2=$!
|
||||
waittcp4port $tp 1
|
||||
(echo "$da") |$CMD3 >"${tf}3" 2>"${te}3"
|
||||
waittcp4port $PORT 1
|
||||
echo "$da" |$CMD3 >"${tf}3" 2>"${te}3"
|
||||
rc3=$?
|
||||
kill $pid0 $pid1 $pid2 2>/dev/null; wait
|
||||
if ! echo "$da" |diff - "$tf"; then
|
||||
kill $pid2 2>/dev/null; wait
|
||||
if ! echo "$da" |diff - "${tf}1" >"${tdiff}1"; then
|
||||
$PRINTF "${YELLOW}phase 1 failed${NORMAL}\n"
|
||||
echo "$CMD0 &"
|
||||
cat ${te}0
|
||||
echo "$CMD1"
|
||||
cat ${te}1
|
||||
cat "${tdiff}1"
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
elif [ $rc3 -ne 0 ]; then
|
||||
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
|
||||
echo "$CMD0 &"
|
||||
cat ${te}0
|
||||
echo "$CMD1"
|
||||
cat ${te}1
|
||||
echo "$CMD2 &"
|
||||
cat ${te}2
|
||||
echo "$CMD3"
|
||||
cat "${te}2" "${te}3"
|
||||
cat ${te}3
|
||||
numFAIL=$((numFAIL+1))
|
||||
listFAIL="$listFAIL $N"
|
||||
elif ! echo "$da" |diff - "${tf}3"; then
|
||||
elif ! echo "$da" |diff - "${tf}3" >"${tdiff}3"; then
|
||||
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
|
||||
echo "$CMD0 &"
|
||||
cat ${te}0
|
||||
echo "$CMD1"
|
||||
cat ${te}1
|
||||
echo "$CMD2 &"
|
||||
cat ${te}2
|
||||
echo "$CMD3"
|
||||
echo "$da" |diff - "${tf}3"
|
||||
cat ${te}3
|
||||
cat "${tdiff}3"
|
||||
numCANT=$((numCANT+1))
|
||||
listCANT="$listCANT $N"
|
||||
else
|
||||
|
@ -11201,8 +11286,6 @@ fi # NUMCOND, SO_REUSEADDR
|
|||
esac
|
||||
PORT=$((PORT+1))
|
||||
N=$((N+1))
|
||||
#
|
||||
fi
|
||||
|
||||
|
||||
NAME=SCTP4STREAM
|
||||
|
|
|
@ -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) {
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
applyopts(xfd->fd, opts, PH_PASTSOCKET);
|
||||
|
||||
applyopts_cloexec(xfd->fd, opts);
|
||||
|
||||
|
|
34
xio-socket.c
34
xio-socket.c
|
@ -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 };
|
||||
|
||||
/* 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_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_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 = { "setsockopt", "sockopt", OPT_SETSOCKOPT_BIN, GROUP_SOCKET,PH_CONNECTED, 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_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) };
|
||||
|
||||
|
@ -239,7 +241,7 @@ int xioopen_socket_connect(int argc, const char *argv[], struct opt *opts,
|
|||
|
||||
themsize = 0;
|
||||
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) {
|
||||
Error1("data too long: \"%s\"", address);
|
||||
} else if (result > 0) {
|
||||
|
@ -316,7 +318,7 @@ int xioopen_socket_listen(int argc, const char *argv[], struct opt *opts,
|
|||
socket_init(0, &us);
|
||||
ussize = 0;
|
||||
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) {
|
||||
Error1("data too long: \"%s\"", usname);
|
||||
} else if (result > 0) {
|
||||
|
@ -407,8 +409,8 @@ int _xioopen_socket_sendto(const char *pfname, const char *type,
|
|||
xfd->peersa.soa.sa_family = pf;
|
||||
themsize = 0;
|
||||
if ((result =
|
||||
dalan(address, (char *)&xfd->peersa.soa.sa_data, &themsize,
|
||||
sizeof(xfd->peersa)))
|
||||
dalan(address, (uint8_t *)&xfd->peersa.soa.sa_data, &themsize,
|
||||
sizeof(xfd->peersa), 'i'))
|
||||
< 0) {
|
||||
Error1("data too long: \"%s\"", address);
|
||||
} 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) {
|
||||
ussize = 0;
|
||||
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) {
|
||||
Error1("data too long: \"%s\"", bindstring);
|
||||
} else if (result > 0) {
|
||||
|
@ -504,7 +506,7 @@ int xioopen_socket_recvfrom(int argc, const char *argv[], struct opt *opts,
|
|||
|
||||
ussize = 0;
|
||||
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) {
|
||||
Error1("data too long: \"%s\"", address);
|
||||
} else if (result > 0) {
|
||||
|
@ -581,7 +583,7 @@ int xioopen_socket_recv(int argc, const char *argv[], struct opt *opts,
|
|||
|
||||
ussize = 0;
|
||||
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) {
|
||||
Error1("data too long: \"%s\"", address);
|
||||
} 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;
|
||||
themsize = 0;
|
||||
if ((result =
|
||||
dalan(address, (char *)&xfd->peersa.soa.sa_data, &themsize,
|
||||
sizeof(xfd->peersa)))
|
||||
dalan(address, (uint8_t *)&xfd->peersa.soa.sa_data, &themsize,
|
||||
sizeof(xfd->peersa), 'i'))
|
||||
< 0) {
|
||||
Error1("data too long: \"%s\"", address);
|
||||
} 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 */
|
||||
addrname[maskname-rangename-1] = '\0';
|
||||
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)
|
||||
/* data length */);
|
||||
/* data length */, 'i');
|
||||
if (result < 0) {
|
||||
Error1("data too long: \"%s\"", addrname);
|
||||
free(addrname); return STAT_NORETRY;
|
||||
|
@ -2004,9 +2006,9 @@ int xioparsenetwork(const char *rangename, int pf, struct xiorange *range) {
|
|||
}
|
||||
free(addrname);
|
||||
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)
|
||||
/* data length */);
|
||||
/* data length */, 'i');
|
||||
if (result < 0) {
|
||||
Error1("data too long: \"%s\"", maskname);
|
||||
return STAT_NORETRY;
|
||||
|
|
|
@ -62,9 +62,11 @@ extern const struct optdesc opt_fiosetown;
|
|||
extern const struct optdesc opt_siocspgrp;
|
||||
extern const struct optdesc opt_bind;
|
||||
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_bin;
|
||||
extern const struct optdesc opt_setsockopt_string;
|
||||
extern const struct optdesc opt_setsockopt_listen;
|
||||
extern const struct optdesc opt_null_eof;
|
||||
|
||||
|
||||
|
|
52
xioopts.c
52
xioopts.c
|
@ -1402,8 +1402,10 @@ const struct optname optionnames[] = {
|
|||
#if WITH_EXEC || WITH_SYSTEM
|
||||
IF_EXEC ("setsid", &opt_setsid)
|
||||
#endif
|
||||
IF_SOCKET ("setsockopt", &opt_setsockopt)
|
||||
IF_SOCKET ("setsockopt-bin", &opt_setsockopt_bin)
|
||||
IF_SOCKET ("setsockopt-int", &opt_setsockopt_int)
|
||||
IF_SOCKET ("setsockopt-listen", &opt_setsockopt_listen)
|
||||
IF_SOCKET ("setsockopt-string", &opt_setsockopt_string)
|
||||
IF_ANY ("setuid", &opt_setuid)
|
||||
IF_ANY ("setuid-early", &opt_setuid_early)
|
||||
|
@ -1517,8 +1519,10 @@ const struct optname optionnames[] = {
|
|||
#ifdef SO_USELOOPBACK /* AIX433, Solaris */
|
||||
IF_SOCKET ("so-useloopback", &opt_so_useloopback)
|
||||
#endif /* SO_USELOOPBACK */
|
||||
IF_SOCKET ("sockopt", &opt_setsockopt)
|
||||
IF_SOCKET ("sockopt-bin", &opt_setsockopt_bin)
|
||||
IF_SOCKET ("sockopt-int", &opt_setsockopt_int)
|
||||
IF_SOCKET ("sockopt-listen", &opt_setsockopt_listen)
|
||||
IF_SOCKET ("sockopt-string", &opt_setsockopt_string)
|
||||
IF_SOCKS4 ("socksport", &opt_socksport)
|
||||
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;
|
||||
int parsres;
|
||||
int result;
|
||||
char optbuf[256]; size_t optlen;
|
||||
uint8_t optbuf[256]; size_t optlen;
|
||||
const char *endkey[6+1];
|
||||
const char *endval[5+1];
|
||||
const char *assign_str = "=";
|
||||
|
@ -1895,15 +1899,15 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
ent = (struct optname *)
|
||||
keyw((struct wordent *)optionnames, token, optionnum);
|
||||
if (ent == NULL) {
|
||||
Error1("parseopts(): unknown option \"%s\"", token);
|
||||
Error1("parseopts_table(): unknown option \"%s\"", token);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(ent->desc->group & groups) && !(ent->desc->group & GROUP_ANY) &&
|
||||
!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*/);
|
||||
Info2("parseopts() groups=%08x, ent->group=%08x",
|
||||
Info2("parseopts_table() groups=%08x, ent->group=%08x",
|
||||
groups, ent->desc->group);
|
||||
#if 0
|
||||
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);
|
||||
continue; }
|
||||
optlen = 0;
|
||||
if ((result = dalan(token, optbuf, &optlen, sizeof(optbuf))) != 0) {
|
||||
Error1("parseopts(): problem with \"%s\" data", token);
|
||||
if ((result = dalan(token, optbuf, &optlen, sizeof(optbuf), 'i')) != 0) {
|
||||
Error1("parseopts_table(): problem with \"%s\" data", token);
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
ul = strtoul(token, &rest/*!*/, 0);
|
||||
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);
|
||||
(*opts)[i].value.u_byte = UCHAR_MAX;
|
||||
} else {
|
||||
|
@ -2011,7 +2015,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
char *rest;
|
||||
ulongval = strtoul(token, &rest/*!*/, 0);
|
||||
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);
|
||||
}
|
||||
(*opts)[i].value.u_uint = ulongval;
|
||||
|
@ -2030,7 +2034,7 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
char *rest;
|
||||
ulongval = strtoul(token, &rest/*!*/, 0);
|
||||
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);
|
||||
}
|
||||
(*opts)[i].value.u_ushort = ulongval;
|
||||
|
@ -2266,8 +2270,8 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
}
|
||||
++rest;
|
||||
optlen = 0;
|
||||
if ((result = dalan(rest, optbuf, &optlen, sizeof(optbuf))) != 0) {
|
||||
Error1("parseopts(): problem with \"%s\" data", rest);
|
||||
if ((result = dalan(rest, optbuf, &optlen, sizeof(optbuf), 'i')) != 0) {
|
||||
Error1("parseopts_table(): problem with \"%s\" data", rest);
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
|
||||
case TYPE_INT_INT_BIN:
|
||||
case TYPE_INT_INT_GENERIC:
|
||||
if (!assign) {
|
||||
Error1("option \"%s\": values required", a0);
|
||||
continue;
|
||||
|
@ -2346,8 +2351,8 @@ int parseopts_table(const char **a, unsigned int groups, struct opt **opts,
|
|||
}
|
||||
++rest;
|
||||
optlen = 0;
|
||||
if ((result = dalan(rest, optbuf, &optlen, sizeof(optbuf))) != 0) {
|
||||
Error1("parseopts(): problem with \"%s\" data", rest);
|
||||
if ((result = dalan(rest, optbuf, &optlen, sizeof(optbuf), 'i')) != 0) {
|
||||
Error1("parseopts_table(): problem with \"%s\" data", rest);
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
#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:
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
|
@ -2964,7 +2986,7 @@ int retropt_bind(struct opt *opts,
|
|||
case AF_UNSPEC:
|
||||
{
|
||||
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 +
|
||||
#if HAVE_STRUCT_SOCKADDR_SALEN
|
||||
|
|
|
@ -64,6 +64,7 @@ enum e_types {
|
|||
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_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 */
|
||||
#if HAVE_STRUCT_LINGER
|
||||
|
@ -72,6 +73,8 @@ enum e_types {
|
|||
#if HAVE_STRUCT_IP_MREQ || HAVE_STRUCT_IP_MREQN
|
||||
TYPE_IP_MREQN, /* for struct ip_mreq or struct ip_mreqn */
|
||||
#endif
|
||||
|
||||
TYPE_GENERIC, /* type is determined from (text) data provided */
|
||||
} ;
|
||||
|
||||
enum e_func {
|
||||
|
@ -596,6 +599,7 @@ enum e_optcode {
|
|||
OPT_SETSID,
|
||||
OPT_SETSOCKOPT_BIN,
|
||||
OPT_SETSOCKOPT_INT,
|
||||
OPT_SETSOCKOPT_LISTEN,
|
||||
OPT_SETSOCKOPT_STRING,
|
||||
OPT_SETUID,
|
||||
OPT_SETUID_EARLY,
|
||||
|
|
Loading…
Reference in a new issue