1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include <grpc/support/port_platform.h>
20
21 #include "absl/types/optional.h"
22
23 #include "src/core/lib/iomgr/port.h"
24
25 #ifdef GRPC_POSIX_SOCKETUTILS
26 #include <fcntl.h>
27 #include <sys/socket.h>
28 #include <unistd.h>
29
30 #include <grpc/impl/grpc_types.h>
31 #include <grpc/support/log.h>
32
33 #include "src/core/lib/gprpp/crash.h"
34 #include "src/core/lib/iomgr/sockaddr.h"
35 #include "src/core/lib/iomgr/socket_utils_posix.h"
36 #endif
37
38 #ifdef GRPC_POSIX_SOCKET_TCP
39
40 #include "src/core/lib/event_engine/channel_args_endpoint_config.h"
41 #include "src/core/lib/gprpp/strerror.h"
42 #include "src/core/lib/iomgr/socket_utils_posix.h"
43
44 using ::grpc_event_engine::experimental::EndpointConfig;
45
46 using ::grpc_core::PosixTcpOptions;
47
48 namespace {
49
AdjustValue(int default_value,int min_value,int max_value,absl::optional<int> actual_value)50 int AdjustValue(int default_value, int min_value, int max_value,
51 absl::optional<int> actual_value) {
52 if (!actual_value.has_value() || *actual_value < min_value ||
53 *actual_value > max_value) {
54 return default_value;
55 }
56 return *actual_value;
57 }
58 } // namespace
59
TcpOptionsFromEndpointConfig(const EndpointConfig & config)60 PosixTcpOptions TcpOptionsFromEndpointConfig(const EndpointConfig& config) {
61 void* value;
62 PosixTcpOptions options;
63 options.tcp_read_chunk_size = AdjustValue(
64 PosixTcpOptions::kDefaultReadChunkSize, 1, PosixTcpOptions::kMaxChunkSize,
65 config.GetInt(GRPC_ARG_TCP_READ_CHUNK_SIZE));
66 options.tcp_min_read_chunk_size =
67 AdjustValue(PosixTcpOptions::kDefaultMinReadChunksize, 1,
68 PosixTcpOptions::kMaxChunkSize,
69 config.GetInt(GRPC_ARG_TCP_MIN_READ_CHUNK_SIZE));
70 options.tcp_max_read_chunk_size =
71 AdjustValue(PosixTcpOptions::kDefaultMaxReadChunksize, 1,
72 PosixTcpOptions::kMaxChunkSize,
73 config.GetInt(GRPC_ARG_TCP_MAX_READ_CHUNK_SIZE));
74 options.tcp_tx_zerocopy_send_bytes_threshold =
75 AdjustValue(PosixTcpOptions::kDefaultSendBytesThreshold, 0, INT_MAX,
76 config.GetInt(GRPC_ARG_TCP_TX_ZEROCOPY_SEND_BYTES_THRESHOLD));
77 options.tcp_tx_zerocopy_max_simultaneous_sends =
78 AdjustValue(PosixTcpOptions::kDefaultMaxSends, 0, INT_MAX,
79 config.GetInt(GRPC_ARG_TCP_TX_ZEROCOPY_MAX_SIMULT_SENDS));
80 options.tcp_receive_buffer_size =
81 AdjustValue(PosixTcpOptions::kReadBufferSizeUnset, 0, INT_MAX,
82 config.GetInt(GRPC_ARG_TCP_RECEIVE_BUFFER_SIZE));
83 options.tcp_tx_zero_copy_enabled =
84 (AdjustValue(PosixTcpOptions::kZerocpTxEnabledDefault, 0, 1,
85 config.GetInt(GRPC_ARG_TCP_TX_ZEROCOPY_ENABLED)) != 0);
86 options.keep_alive_time_ms =
87 AdjustValue(0, 1, INT_MAX, config.GetInt(GRPC_ARG_KEEPALIVE_TIME_MS));
88 options.keep_alive_timeout_ms =
89 AdjustValue(0, 1, INT_MAX, config.GetInt(GRPC_ARG_KEEPALIVE_TIMEOUT_MS));
90 options.expand_wildcard_addrs =
91 (AdjustValue(0, 1, INT_MAX,
92 config.GetInt(GRPC_ARG_EXPAND_WILDCARD_ADDRS)) != 0);
93 options.allow_reuse_port =
94 (AdjustValue(0, 1, INT_MAX, config.GetInt(GRPC_ARG_ALLOW_REUSEPORT)) !=
95 0);
96
97 if (options.tcp_min_read_chunk_size > options.tcp_max_read_chunk_size) {
98 options.tcp_min_read_chunk_size = options.tcp_max_read_chunk_size;
99 }
100 options.tcp_read_chunk_size = grpc_core::Clamp(
101 options.tcp_read_chunk_size, options.tcp_min_read_chunk_size,
102 options.tcp_max_read_chunk_size);
103
104 value = config.GetVoidPointer(GRPC_ARG_RESOURCE_QUOTA);
105 if (value != nullptr) {
106 options.resource_quota =
107 reinterpret_cast<grpc_core::ResourceQuota*>(value)->Ref();
108 }
109 value = config.GetVoidPointer(GRPC_ARG_SOCKET_MUTATOR);
110 if (value != nullptr) {
111 options.socket_mutator =
112 grpc_socket_mutator_ref(static_cast<grpc_socket_mutator*>(value));
113 }
114 return options;
115 }
116
117 #endif // GRPC_POSIX_SOCKET_TCP
118
119 #ifdef GRPC_POSIX_SOCKETUTILS
120
grpc_accept4(int sockfd,grpc_resolved_address * resolved_addr,int nonblock,int cloexec)121 int grpc_accept4(int sockfd, grpc_resolved_address* resolved_addr, int nonblock,
122 int cloexec) {
123 int fd, flags;
124 fd = accept(sockfd, reinterpret_cast<grpc_sockaddr*>(resolved_addr->addr),
125 &resolved_addr->len);
126 if (fd >= 0) {
127 if (nonblock) {
128 flags = fcntl(fd, F_GETFL, 0);
129 if (flags < 0) goto close_and_error;
130 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) goto close_and_error;
131 }
132 if (cloexec) {
133 flags = fcntl(fd, F_GETFD, 0);
134 if (flags < 0) goto close_and_error;
135 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != 0) goto close_and_error;
136 }
137 }
138 return fd;
139
140 close_and_error:
141 close(fd);
142 return -1;
143 }
144
145 #endif // GRPC_POSIX_SOCKETUTILS
146