1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2 #include "socket.h"
3
4 #include <errno.h>
5 #include <limits.h>
6 #include <stddef.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/socket.h>
10
pldm_socket_sndbuf_init(struct pldm_socket_sndbuf * ctx,int socket)11 int pldm_socket_sndbuf_init(struct pldm_socket_sndbuf *ctx, int socket)
12 {
13 FILE *fp;
14 long max_buf_size;
15 char line[128];
16 char *endptr;
17
18 if (socket == -1) {
19 return -1;
20 }
21 ctx->socket = socket;
22
23 fp = fopen("/proc/sys/net/core/wmem_max", "r");
24 if (fp == NULL) {
25 return -1;
26 }
27
28 if (fgets(line, sizeof(line), fp) == NULL) {
29 fclose(fp);
30 return -1;
31 }
32
33 errno = 0;
34 max_buf_size = strtol(line, &endptr, 10);
35 if (errno != 0 || endptr == line) {
36 fclose(fp);
37 return -1;
38 }
39
40 fclose(fp);
41
42 if (max_buf_size > INT_MAX) {
43 max_buf_size = INT_MAX;
44 }
45 ctx->max_size = (int)max_buf_size;
46
47 if (pldm_socket_sndbuf_get(ctx)) {
48 return -1;
49 }
50
51 return 0;
52 }
53
pldm_socket_sndbuf_accomodate(struct pldm_socket_sndbuf * ctx,int msg_len)54 int pldm_socket_sndbuf_accomodate(struct pldm_socket_sndbuf *ctx, int msg_len)
55 {
56 if (msg_len < ctx->size) {
57 return 0;
58 }
59 /* If message is bigger than the max size, don't return a failure. Set
60 * the buffer to the max size and see what happens. We don't know how
61 * much of the extra space the kernel actually uses so let it tell us if
62 * there wasn't enough space */
63 if (msg_len > ctx->max_size) {
64 msg_len = ctx->max_size;
65 }
66 if (ctx->size == ctx->max_size) {
67 return 0;
68 }
69 int rc = setsockopt(ctx->socket, SOL_SOCKET, SO_SNDBUF, &(msg_len),
70 sizeof(msg_len));
71 if (rc == -1) {
72 return -1;
73 }
74 ctx->size = msg_len;
75 return 0;
76 }
77
pldm_socket_sndbuf_get(struct pldm_socket_sndbuf * ctx)78 int pldm_socket_sndbuf_get(struct pldm_socket_sndbuf *ctx)
79 {
80 /* size returned by getsockopt is the actual size of the buffer - twice
81 * the size of the value used by setsockopt. So for consistency, return
82 * half of the buffer size */
83 int buf_size;
84 socklen_t optlen = sizeof(buf_size);
85 int rc = getsockopt(ctx->socket, SOL_SOCKET, SO_SNDBUF, &(buf_size),
86 &optlen);
87 if (rc == -1) {
88 return -1;
89 }
90 ctx->size = buf_size / 2;
91 return 0;
92 }
93