Skip to content

Commit a172ae1

Browse files
authored
Merge pull request #94 from ssahani/dev
Allow to set TCP socket options
2 parents 1929cfd + d97df91 commit a172ae1

File tree

11 files changed

+232
-8
lines changed

11 files changed

+232
-8
lines changed

conf/netlogd.conf.in

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,13 @@
22
#Address=239.0.0.1:6000
33
#Protocol=udp
44
#LogFormat=rfc5424
5+
#StructuredData=
6+
#UseSysLogStructuredData=no
7+
#UseSysLogMsgId=no
8+
#ConnectionRetrySec=30s
9+
#KeepAlive=
10+
#KeepAliveTimeSec=
11+
#KeepAliveIntervalSec=
12+
#KeepAliveProbes=
13+
#NoDelay=
14+
#SendBuffer=

src/netlog/netlog-gperf.gperf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,5 @@ Network.KeepAlive, config_parse_bool, 0, off
2929
Network.KeepAliveTimeSec, config_parse_sec, 0, offsetof(Manager, keep_alive_time)
3030
Network.KeepAliveIntervalSec, config_parse_sec, 0, offsetof(Manager, keep_alive_interval)
3131
Network.KeepAliveProbes, config_parse_unsigned, 0, offsetof(Manager, keep_alive_cnt)
32+
Network.NoDelay, config_parse_bool, 0, offsetof(Manager, no_delay)
33+
Network.SendBuffer, config_parse_iec_size, 0, offsetof(Manager, send_buffer)

src/netlog/netlog-manager.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,12 @@ struct Manager {
7777
TLSManager *tls;
7878

7979
bool keep_alive;
80+
bool no_delay;
8081

8182
unsigned keep_alive_cnt;
83+
84+
size_t send_buffer;
85+
8286
usec_t timeout_usec;
8387
usec_t keep_alive_time;
8488
usec_t keep_alive_interval;

src/netlog/netlog-network.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -410,16 +410,22 @@ int manager_open_network_socket(Manager *m) {
410410
switch (m->protocol) {
411411
case SYSLOG_TRANSMISSION_PROTOCOL_UDP: {
412412
r = setsockopt_int(m->socket, IPPROTO_IP, IP_MULTICAST_LOOP, true);
413-
if (r < 0) {
414-
r = -errno;
415-
log_error_errno(errno, "UDP: Failed to set IP_MULTICAST_LOOP: %m");
416-
goto fail;
417-
}}
413+
if (r < 0)
414+
log_debug_errno(errno, "UDP: Failed to set IP_MULTICAST_LOOP: %m");
415+
}
418416
break;
419417
case SYSLOG_TRANSMISSION_PROTOCOL_TCP: {
420-
r = setsockopt_int(m->socket, IPPROTO_TCP, TCP_NODELAY, true);
421-
if (r < 0)
422-
log_debug_errno(r, "Failed to enable TCP_NODELAY mode, ignoring: %m");
418+
if (m->no_delay) {
419+
r = setsockopt_int(m->socket, IPPROTO_TCP, TCP_NODELAY, true);
420+
if (r < 0)
421+
log_debug_errno(r, "Failed to enable TCP_NODELAY mode, ignoring: %m");
422+
}
423+
424+
if (m->send_buffer > 0) {
425+
r = fd_set_sndbuf(m->socket, m->send_buffer, false);
426+
if (r < 0)
427+
log_debug_errno(r, "SO_SNDBUF/SO_SNDBUFFORCE failed: %m");
428+
}
423429

424430
if (m->keep_alive) {
425431
r = setsockopt_int(m->socket, SOL_SOCKET, SO_KEEPALIVE, true);

src/share/conf-parser.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,38 @@ int config_parse_bool(
481481
return 0;
482482
}
483483

484+
int config_parse_iec_size(
485+
const char* unit,
486+
const char *filename,
487+
unsigned line,
488+
const char *section,
489+
unsigned section_line,
490+
const char *lvalue,
491+
int ltype,
492+
const char *rvalue,
493+
void *data,
494+
void *userdata) {
495+
496+
size_t *sz = ASSERT_PTR(data);
497+
uint64_t v;
498+
int r;
499+
500+
assert(filename);
501+
assert(lvalue);
502+
assert(rvalue);
503+
504+
r = parse_size(rvalue, 1024, &v);
505+
if (r >= 0 && (uint64_t) (size_t) v != v)
506+
r = -ERANGE;
507+
if (r < 0) {
508+
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
509+
return 0;
510+
}
511+
512+
*sz = (size_t) v;
513+
return 0;
514+
}
515+
484516
#define DEFINE_PARSER(type, vartype, conv_func) \
485517
DEFINE_CONFIG_PARSE_PTR(config_parse_##type, conv_func, vartype, "Failed to parse " #type " value")
486518

src/share/conf-parser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,3 +251,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_string);
251251
CONFIG_PARSER_PROTOTYPE(config_parse_bool);
252252
CONFIG_PARSER_PROTOTYPE(config_parse_sec);
253253
CONFIG_PARSER_PROTOTYPE(config_parse_unsigned);
254+
CONFIG_PARSER_PROTOTYPE(config_parse_iec_size);

src/share/parse-util.c

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,130 @@ int safe_atolli(const char *s, long long int *ret_lli) {
128128
*ret_lli = l;
129129
return 0;
130130
}
131+
132+
int parse_size(const char *t, uint64_t base, uint64_t *size) {
133+
134+
/* Soo, sometimes we want to parse IEC binary suffixes, and
135+
* sometimes SI decimal suffixes. This function can parse
136+
* both. Which one is the right way depends on the
137+
* context. Wikipedia suggests that SI is customary for
138+
* hardware metrics and network speeds, while IEC is
139+
* customary for most data sizes used by software and volatile
140+
* (RAM) memory. Hence be careful which one you pick!
141+
*
142+
* In either case we use just K, M, G as suffix, and not Ki,
143+
* Mi, Gi or so (as IEC would suggest). That's because that's
144+
* frickin' ugly. But this means you really need to make sure
145+
* to document which base you are parsing when you use this
146+
* call. */
147+
148+
struct table {
149+
const char *suffix;
150+
unsigned long long factor;
151+
};
152+
153+
static const struct table iec[] = {
154+
{ "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
155+
{ "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
156+
{ "T", 1024ULL*1024ULL*1024ULL*1024ULL },
157+
{ "G", 1024ULL*1024ULL*1024ULL },
158+
{ "M", 1024ULL*1024ULL },
159+
{ "K", 1024ULL },
160+
{ "B", 1ULL },
161+
{ "", 1ULL },
162+
};
163+
164+
static const struct table si[] = {
165+
{ "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
166+
{ "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
167+
{ "T", 1000ULL*1000ULL*1000ULL*1000ULL },
168+
{ "G", 1000ULL*1000ULL*1000ULL },
169+
{ "M", 1000ULL*1000ULL },
170+
{ "K", 1000ULL },
171+
{ "B", 1ULL },
172+
{ "", 1ULL },
173+
};
174+
175+
const struct table *table;
176+
const char *p;
177+
unsigned long long r = 0;
178+
unsigned n_entries, start_pos = 0;
179+
180+
assert(t);
181+
assert(IN_SET(base, 1000, 1024));
182+
assert(size);
183+
184+
if (base == 1000) {
185+
table = si;
186+
n_entries = ELEMENTSOF(si);
187+
} else {
188+
table = iec;
189+
n_entries = ELEMENTSOF(iec);
190+
}
191+
192+
p = t;
193+
do {
194+
unsigned long long l, tmp;
195+
double frac = 0;
196+
char *e;
197+
unsigned i;
198+
199+
p += strspn(p, WHITESPACE);
200+
201+
errno = 0;
202+
l = strtoull(p, &e, 10);
203+
if (errno > 0)
204+
return -errno;
205+
if (e == p)
206+
return -EINVAL;
207+
if (*p == '-')
208+
return -ERANGE;
209+
210+
if (*e == '.') {
211+
e++;
212+
213+
/* strtoull() itself would accept space/+/- */
214+
if (ascii_isdigit(*e)) {
215+
unsigned long long l2;
216+
char *e2;
217+
218+
l2 = strtoull(e, &e2, 10);
219+
if (errno > 0)
220+
return -errno;
221+
222+
/* Ignore failure. E.g. 10.M is valid */
223+
frac = l2;
224+
for (; e < e2; e++)
225+
frac /= 10;
226+
}
227+
}
228+
229+
e += strspn(e, WHITESPACE);
230+
231+
for (i = start_pos; i < n_entries; i++)
232+
if (startswith(e, table[i].suffix))
233+
break;
234+
235+
if (i >= n_entries)
236+
return -EINVAL;
237+
if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
238+
return -ERANGE;
239+
240+
tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
241+
if (tmp > ULLONG_MAX - r)
242+
return -ERANGE;
243+
244+
r += tmp;
245+
if ((unsigned long long) (uint64_t) r != r)
246+
return -ERANGE;
247+
248+
p = e + strlen(table[i].suffix);
249+
250+
start_pos = i + 1;
251+
252+
} while (*p);
253+
254+
*size = r;
255+
256+
return 0;
257+
}

src/share/parse-util.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ static inline int safe_atou32(const char *s, uint32_t *ret_u) {
2727
return safe_atou(s, (unsigned*) ret_u);
2828
}
2929

30+
int parse_size(const char *t, uint64_t base, uint64_t *size);
31+
3032
#if LONG_MAX == INT_MAX
3133
static inline int safe_atolu(const char *s, unsigned long *ret_u) {
3234
assert_cc(sizeof(unsigned long) == sizeof(unsigned));

src/share/socket-util.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,3 +287,34 @@ int sockaddr_pretty(
287287
*ret = p;
288288
return 0;
289289
}
290+
291+
int fd_set_sndbuf(int fd, size_t n, bool increase) {
292+
int r, value;
293+
socklen_t l = sizeof(value);
294+
295+
if (n > INT_MAX)
296+
return -ERANGE;
297+
298+
r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
299+
if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2)
300+
return 0;
301+
302+
/* First, try to set the buffer size with SO_SNDBUF. */
303+
r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUF, n);
304+
if (r < 0)
305+
return r;
306+
307+
/* SO_SNDBUF above may set to the kernel limit, instead of the requested size.
308+
* So, we need to check the actual buffer size here. */
309+
l = sizeof(value);
310+
r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
311+
if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2)
312+
return 1;
313+
314+
/* If we have the privileges we will ignore the kernel limit. */
315+
r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUFFORCE, n);
316+
if (r < 0)
317+
return r;
318+
319+
return 1;
320+
}

src/share/socket-util.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,5 @@ static inline int getsockopt_int(int fd, int level, int optname, int *ret) {
103103
*ret = v;
104104
return 0;
105105
}
106+
107+
int fd_set_sndbuf(int fd, size_t n, bool increase);

0 commit comments

Comments
 (0)