Skip to content

Commit

Permalink
Merge pull request #94 from ssahani/dev
Browse files Browse the repository at this point in the history
Allow to set TCP socket options
  • Loading branch information
ssahani authored May 14, 2024
2 parents 1929cfd + d97df91 commit a172ae1
Show file tree
Hide file tree
Showing 11 changed files with 232 additions and 8 deletions.
10 changes: 10 additions & 0 deletions conf/netlogd.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,13 @@
#Address=239.0.0.1:6000
#Protocol=udp
#LogFormat=rfc5424
#StructuredData=
#UseSysLogStructuredData=no
#UseSysLogMsgId=no
#ConnectionRetrySec=30s
#KeepAlive=
#KeepAliveTimeSec=
#KeepAliveIntervalSec=
#KeepAliveProbes=
#NoDelay=
#SendBuffer=
2 changes: 2 additions & 0 deletions src/netlog/netlog-gperf.gperf
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ Network.KeepAlive, config_parse_bool, 0, off
Network.KeepAliveTimeSec, config_parse_sec, 0, offsetof(Manager, keep_alive_time)
Network.KeepAliveIntervalSec, config_parse_sec, 0, offsetof(Manager, keep_alive_interval)
Network.KeepAliveProbes, config_parse_unsigned, 0, offsetof(Manager, keep_alive_cnt)
Network.NoDelay, config_parse_bool, 0, offsetof(Manager, no_delay)
Network.SendBuffer, config_parse_iec_size, 0, offsetof(Manager, send_buffer)
4 changes: 4 additions & 0 deletions src/netlog/netlog-manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,12 @@ struct Manager {
TLSManager *tls;

bool keep_alive;
bool no_delay;

unsigned keep_alive_cnt;

size_t send_buffer;

usec_t timeout_usec;
usec_t keep_alive_time;
usec_t keep_alive_interval;
Expand Down
22 changes: 14 additions & 8 deletions src/netlog/netlog-network.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,16 +410,22 @@ int manager_open_network_socket(Manager *m) {
switch (m->protocol) {
case SYSLOG_TRANSMISSION_PROTOCOL_UDP: {
r = setsockopt_int(m->socket, IPPROTO_IP, IP_MULTICAST_LOOP, true);
if (r < 0) {
r = -errno;
log_error_errno(errno, "UDP: Failed to set IP_MULTICAST_LOOP: %m");
goto fail;
}}
if (r < 0)
log_debug_errno(errno, "UDP: Failed to set IP_MULTICAST_LOOP: %m");
}
break;
case SYSLOG_TRANSMISSION_PROTOCOL_TCP: {
r = setsockopt_int(m->socket, IPPROTO_TCP, TCP_NODELAY, true);
if (r < 0)
log_debug_errno(r, "Failed to enable TCP_NODELAY mode, ignoring: %m");
if (m->no_delay) {
r = setsockopt_int(m->socket, IPPROTO_TCP, TCP_NODELAY, true);
if (r < 0)
log_debug_errno(r, "Failed to enable TCP_NODELAY mode, ignoring: %m");
}

if (m->send_buffer > 0) {
r = fd_set_sndbuf(m->socket, m->send_buffer, false);
if (r < 0)
log_debug_errno(r, "SO_SNDBUF/SO_SNDBUFFORCE failed: %m");
}

if (m->keep_alive) {
r = setsockopt_int(m->socket, SOL_SOCKET, SO_KEEPALIVE, true);
Expand Down
32 changes: 32 additions & 0 deletions src/share/conf-parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,38 @@ int config_parse_bool(
return 0;
}

int config_parse_iec_size(
const char* unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {

size_t *sz = ASSERT_PTR(data);
uint64_t v;
int r;

assert(filename);
assert(lvalue);
assert(rvalue);

r = parse_size(rvalue, 1024, &v);
if (r >= 0 && (uint64_t) (size_t) v != v)
r = -ERANGE;
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
return 0;
}

*sz = (size_t) v;
return 0;
}

#define DEFINE_PARSER(type, vartype, conv_func) \
DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")

Expand Down
1 change: 1 addition & 0 deletions src/share/conf-parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_string);
CONFIG_PARSER_PROTOTYPE(config_parse_bool);
CONFIG_PARSER_PROTOTYPE(config_parse_sec);
CONFIG_PARSER_PROTOTYPE(config_parse_unsigned);
CONFIG_PARSER_PROTOTYPE(config_parse_iec_size);
127 changes: 127 additions & 0 deletions src/share/parse-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,130 @@ int safe_atolli(const char *s, long long int *ret_lli) {
*ret_lli = l;
return 0;
}

int parse_size(const char *t, uint64_t base, uint64_t *size) {

/* Soo, sometimes we want to parse IEC binary suffixes, and
* sometimes SI decimal suffixes. This function can parse
* both. Which one is the right way depends on the
* context. Wikipedia suggests that SI is customary for
* hardware metrics and network speeds, while IEC is
* customary for most data sizes used by software and volatile
* (RAM) memory. Hence be careful which one you pick!
*
* In either case we use just K, M, G as suffix, and not Ki,
* Mi, Gi or so (as IEC would suggest). That's because that's
* frickin' ugly. But this means you really need to make sure
* to document which base you are parsing when you use this
* call. */

struct table {
const char *suffix;
unsigned long long factor;
};

static const struct table iec[] = {
{ "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
{ "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
{ "T", 1024ULL*1024ULL*1024ULL*1024ULL },
{ "G", 1024ULL*1024ULL*1024ULL },
{ "M", 1024ULL*1024ULL },
{ "K", 1024ULL },
{ "B", 1ULL },
{ "", 1ULL },
};

static const struct table si[] = {
{ "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
{ "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
{ "T", 1000ULL*1000ULL*1000ULL*1000ULL },
{ "G", 1000ULL*1000ULL*1000ULL },
{ "M", 1000ULL*1000ULL },
{ "K", 1000ULL },
{ "B", 1ULL },
{ "", 1ULL },
};

const struct table *table;
const char *p;
unsigned long long r = 0;
unsigned n_entries, start_pos = 0;

assert(t);
assert(IN_SET(base, 1000, 1024));
assert(size);

if (base == 1000) {
table = si;
n_entries = ELEMENTSOF(si);
} else {
table = iec;
n_entries = ELEMENTSOF(iec);
}

p = t;
do {
unsigned long long l, tmp;
double frac = 0;
char *e;
unsigned i;

p += strspn(p, WHITESPACE);

errno = 0;
l = strtoull(p, &e, 10);
if (errno > 0)
return -errno;
if (e == p)
return -EINVAL;
if (*p == '-')
return -ERANGE;

if (*e == '.') {
e++;

/* strtoull() itself would accept space/+/- */
if (ascii_isdigit(*e)) {
unsigned long long l2;
char *e2;

l2 = strtoull(e, &e2, 10);
if (errno > 0)
return -errno;

/* Ignore failure. E.g. 10.M is valid */
frac = l2;
for (; e < e2; e++)
frac /= 10;
}
}

e += strspn(e, WHITESPACE);

for (i = start_pos; i < n_entries; i++)
if (startswith(e, table[i].suffix))
break;

if (i >= n_entries)
return -EINVAL;
if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
return -ERANGE;

tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
if (tmp > ULLONG_MAX - r)
return -ERANGE;

r += tmp;
if ((unsigned long long) (uint64_t) r != r)
return -ERANGE;

p = e + strlen(table[i].suffix);

start_pos = i + 1;

} while (*p);

*size = r;

return 0;
}
2 changes: 2 additions & 0 deletions src/share/parse-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ static inline int safe_atou32(const char *s, uint32_t *ret_u) {
return safe_atou(s, (unsigned*) ret_u);
}

int parse_size(const char *t, uint64_t base, uint64_t *size);

#if LONG_MAX == INT_MAX
static inline int safe_atolu(const char *s, unsigned long *ret_u) {
assert_cc(sizeof(unsigned long) == sizeof(unsigned));
Expand Down
31 changes: 31 additions & 0 deletions src/share/socket-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,34 @@ int sockaddr_pretty(
*ret = p;
return 0;
}

int fd_set_sndbuf(int fd, size_t n, bool increase) {
int r, value;
socklen_t l = sizeof(value);

if (n > INT_MAX)
return -ERANGE;

r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2)
return 0;

/* First, try to set the buffer size with SO_SNDBUF. */
r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUF, n);
if (r < 0)
return r;

/* SO_SNDBUF above may set to the kernel limit, instead of the requested size.
* So, we need to check the actual buffer size here. */
l = sizeof(value);
r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2)
return 1;

/* If we have the privileges we will ignore the kernel limit. */
r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUFFORCE, n);
if (r < 0)
return r;

return 1;
}
2 changes: 2 additions & 0 deletions src/share/socket-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,5 @@ static inline int getsockopt_int(int fd, int level, int optname, int *ret) {
*ret = v;
return 0;
}

int fd_set_sndbuf(int fd, size_t n, bool increase);
7 changes: 7 additions & 0 deletions src/share/string-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#define ALPHANUMERICAL LETTERS DIGITS
#define HEXDIGITS DIGITS "abcdefABCDEF"

typedef char sd_char;

#define streq(a,b) (strcmp((a),(b)) == 0)
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
Expand Down Expand Up @@ -112,6 +114,11 @@ char *strjoin(const char *x, ...) _sentinel_;
_d_; \
})

static inline bool ascii_isdigit(sd_char a) {
/* A pure ASCII, locale independent version of isdigit() */
return a >= '0' && a <= '9';
}

char *strstrip(char *s);
char *truncate_nl(char *s);

Expand Down

0 comments on commit a172ae1

Please sign in to comment.