mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 15:32:35 +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
|
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:
|
||||||
|
|
385
dalan.c
385
dalan.c
|
@ -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,8 +71,220 @@ 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,
|
||||||
|
-1 if the data was cut due to n limit,
|
||||||
|
1 if a syntax error occurred
|
||||||
|
2 if the actual character is white space
|
||||||
|
3 if the first character is not a type specifier
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
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) {
|
||||||
|
case 'n': c = '\n'; break;
|
||||||
|
case 'r': c = '\r'; break;
|
||||||
|
case 't': c = '\t'; break;
|
||||||
|
case 'f': c = '\f'; break;
|
||||||
|
case 'b': c = '\b'; break;
|
||||||
|
case 'a': c = '\a'; break;
|
||||||
|
#if 0
|
||||||
|
case 'e': c = '\e'; break;
|
||||||
|
#else
|
||||||
|
case 'e': c = '\033'; break;
|
||||||
|
#endif
|
||||||
|
case '0': c = '\0'; break;
|
||||||
|
}
|
||||||
|
/* PASSTHROUGH */
|
||||||
|
default:
|
||||||
|
if (p1 >= n) {
|
||||||
|
*p = p1;
|
||||||
|
*line0 = line;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
data[p1++] = c;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == '"')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
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) {
|
||||||
|
case 'n': c = '\n'; break;
|
||||||
|
case 'r': c = '\r'; break;
|
||||||
|
case 't': c = '\t'; break;
|
||||||
|
case 'f': c = '\f'; break;
|
||||||
|
case 'b': c = '\b'; break;
|
||||||
|
case 'a': c = '\a'; break;
|
||||||
|
#if 0
|
||||||
|
case 'e': c = '\e'; break;
|
||||||
|
#else
|
||||||
|
case 'e': c = '\033'; break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/* PASSTHROUGH */
|
||||||
|
default:
|
||||||
|
if (p1 >= n) { *p = p1; return -1; }
|
||||||
|
data[p1++] = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*line != '\'') {
|
||||||
|
fputs("error in character termination\n", stderr);
|
||||||
|
*p = p1;
|
||||||
|
*line0 = line;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
++line;
|
||||||
|
break;
|
||||||
|
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;
|
||||||
|
} else if (isxdigit(c&0xff)) {
|
||||||
|
x = ((c&0x07) + 9) << 4;
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
++line;
|
||||||
|
c = *line;
|
||||||
|
if (isdigit(c&0xff)) {
|
||||||
|
x |= (c-'0');
|
||||||
|
} else if (isxdigit(c&0xff)) {
|
||||||
|
x |= (c&0x07) + 9;
|
||||||
|
} else {
|
||||||
|
fputs("odd number of hexadecimal digits\n", stderr);
|
||||||
|
*p = p1;
|
||||||
|
*line0 = line;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
++line;
|
||||||
|
if (p1 >= n) {
|
||||||
|
*p = p1;
|
||||||
|
*line0 = line;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
data[p1++] = x;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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.
|
p must be initialized to 0.
|
||||||
return 0 on success,
|
return 0 on success,
|
||||||
-1 if the data was cut due to n limit,
|
-1 if the data was cut due to n limit,
|
||||||
|
@ -79,151 +292,33 @@ void dalan_init(void) {
|
||||||
*p is a global data counter; especially it must be used when calculating
|
*p is a global data counter; especially it must be used when calculating
|
||||||
alignment. On successful return from the function *p must be actual!
|
alignment. On successful return from the function *p must be actual!
|
||||||
*/
|
*/
|
||||||
int dalan(const char *line, char *data, size_t *p, size_t n) {
|
int dalan(const char *line, uint8_t *data, size_t *p, size_t n, char deflt) {
|
||||||
int align, mask, i, x;
|
size_t p0;
|
||||||
size_t p1 = *p;
|
char c;
|
||||||
char c;
|
int rc;
|
||||||
|
|
||||||
/*fputs(line, stderr); fputc('\n', stderr);*/
|
while (1) {
|
||||||
while (c = *line++) {
|
/* assume there is a type specifier on beginning of rest of 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;
|
|
||||||
case '"':
|
|
||||||
while (1) {
|
|
||||||
switch (c = *line++) {
|
|
||||||
case '\0': fputs("unterminated string\n", stderr);
|
|
||||||
return 1;
|
|
||||||
case '"':
|
|
||||||
break;
|
|
||||||
case '\\':
|
|
||||||
if (!(c = *line++)) {
|
|
||||||
fputs("continuation line not implemented\n", stderr);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
switch (c) {
|
|
||||||
case 'n': c = '\n'; break;
|
|
||||||
case 'r': c = '\r'; break;
|
|
||||||
case 't': c = '\t'; break;
|
|
||||||
case 'f': c = '\f'; break;
|
|
||||||
case 'b': c = '\b'; break;
|
|
||||||
case 'a': c = '\a'; break;
|
|
||||||
#if 0
|
|
||||||
case 'e': c = '\e'; break;
|
|
||||||
#else
|
|
||||||
case 'e': c = '\033'; break;
|
|
||||||
#endif
|
|
||||||
case '0': c = '\0'; break;
|
|
||||||
}
|
|
||||||
/* PASSTHROUGH */
|
|
||||||
default:
|
|
||||||
if (p1 >= n) { *p = p1; return -1; }
|
|
||||||
data[p1++] = c;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '"')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '\'':
|
|
||||||
switch (c = *line++) {
|
|
||||||
case '\0': fputs("unterminated character\n", stderr);
|
|
||||||
return 1;
|
|
||||||
case '\'': fputs("error in character\n", stderr);
|
|
||||||
return 1;
|
|
||||||
case '\\':
|
|
||||||
if (!(c = *line++)) {
|
|
||||||
fputs("continuation line not implemented\n", stderr);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
switch (c) {
|
|
||||||
case 'n': c = '\n'; break;
|
|
||||||
case 'r': c = '\r'; break;
|
|
||||||
case 't': c = '\t'; break;
|
|
||||||
case 'f': c = '\f'; break;
|
|
||||||
case 'b': c = '\b'; break;
|
|
||||||
case 'a': c = '\a'; break;
|
|
||||||
#if 0
|
|
||||||
case 'e': c = '\e'; break;
|
|
||||||
#else
|
|
||||||
case 'e': c = '\033'; break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
/* PASSTHROUGH */
|
|
||||||
default:
|
|
||||||
if (p1 >= n) { *p = p1; return -1; }
|
|
||||||
data[p1++] = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (*line != '\'') {
|
|
||||||
fputs("error in character termination\n", stderr);
|
|
||||||
*p = p1; return 1;
|
|
||||||
}
|
|
||||||
++line;
|
|
||||||
break;
|
|
||||||
#if LATER
|
|
||||||
case '0':
|
|
||||||
c = *line++;
|
c = *line++;
|
||||||
if (c == 'x') {
|
if (c == '\0')
|
||||||
/* hexadecimal */ ;
|
break;
|
||||||
} else if (isdigit(c&0xff)) {
|
p0 = *p;
|
||||||
/* octal */
|
rc = dalan_item(c, &line, data, p, n);
|
||||||
} else {
|
if (rc == 0) {
|
||||||
/* it was only 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);
|
||||||
}
|
}
|
||||||
break;
|
if (rc != 0) {
|
||||||
#endif /* LATER */
|
return rc;
|
||||||
case 'x':
|
|
||||||
/* expecting hex data, must be an even number of digits!! */
|
|
||||||
while (true) {
|
|
||||||
c = *line;
|
|
||||||
if (isdigit(c&0xff)) {
|
|
||||||
x = (c-'0') << 4;
|
|
||||||
} else if (isxdigit(c&0xff)) {
|
|
||||||
x = ((c&0x07) + 9) << 4;
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
++line;
|
|
||||||
c = *line;
|
|
||||||
if (isdigit(c&0xff)) {
|
|
||||||
x |= (c-'0');
|
|
||||||
} else if (isxdigit(c&0xff)) {
|
|
||||||
x |= (c&0x07) + 9;
|
|
||||||
} else {
|
|
||||||
fputs("odd number of hexadecimal digits\n", stderr);
|
|
||||||
*p = p1; return 1;
|
|
||||||
}
|
|
||||||
++line;
|
|
||||||
if (p1 >= n) { *p = p1; return -1; }
|
|
||||||
data[p1++] = x;
|
|
||||||
}
|
}
|
||||||
break;
|
/* rc == 0 */
|
||||||
case 'A': case 'a':
|
n -= (*p-p0);
|
||||||
case 'C': case 'c':
|
}
|
||||||
default: fprintf(stderr, "syntax error in \"%s\"\n", line-1);
|
return 0;
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*p = p1; 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 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) */
|
||||||
|
|
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()
|
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
|
||||||
|
|
|
@ -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
125
test.sh
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
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 };
|
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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
|
52
xioopts.c
52
xioopts.c
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue