xref: /openbmc/libpldm/src/transport/socket.c (revision 691668fe)
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