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 #include "src/core/lib/iomgr/port.h"
23
24 #ifdef GRPC_POSIX_SOCKETUTILS
25 #include <fcntl.h>
26 #include <grpc/impl/grpc_types.h>
27 #include <sys/socket.h>
28 #include <unistd.h>
29
30 #include "src/core/lib/iomgr/sockaddr.h"
31 #include "src/core/lib/iomgr/socket_utils_posix.h"
32 #include "src/core/util/crash.h"
33 #endif
34
35 #ifdef GRPC_POSIX_SOCKET_TCP
36
37 #include "src/core/lib/event_engine/channel_args_endpoint_config.h"
38 #include "src/core/lib/iomgr/socket_utils_posix.h"
39 #include "src/core/util/strerror.h"
40
41 using ::grpc_event_engine::experimental::EndpointConfig;
42
43 using ::grpc_core::PosixTcpOptions;
44
45 namespace {
46
AdjustValue(int default_value,int min_value,int max_value,absl::optional<int> actual_value)47 int AdjustValue(int default_value, int min_value, int max_value,
48 absl::optional<int> actual_value) {
49 if (!actual_value.has_value() || *actual_value < min_value ||
50 *actual_value > max_value) {
51 return default_value;
52 }
53 return *actual_value;
54 }
55 } // namespace
56
TcpOptionsFromEndpointConfig(const EndpointConfig & config)57 PosixTcpOptions TcpOptionsFromEndpointConfig(const EndpointConfig& config) {
58 void* value;
59 PosixTcpOptions options;
60 options.tcp_read_chunk_size = AdjustValue(
61 PosixTcpOptions::kDefaultReadChunkSize, 1, PosixTcpOptions::kMaxChunkSize,
62 config.GetInt(GRPC_ARG_TCP_READ_CHUNK_SIZE));
63 options.tcp_min_read_chunk_size =
64 AdjustValue(PosixTcpOptions::kDefaultMinReadChunksize, 1,
65 PosixTcpOptions::kMaxChunkSize,
66 config.GetInt(GRPC_ARG_TCP_MIN_READ_CHUNK_SIZE));
67 options.tcp_max_read_chunk_size =
68 AdjustValue(PosixTcpOptions::kDefaultMaxReadChunksize, 1,
69 PosixTcpOptions::kMaxChunkSize,
70 config.GetInt(GRPC_ARG_TCP_MAX_READ_CHUNK_SIZE));
71 options.tcp_tx_zerocopy_send_bytes_threshold =
72 AdjustValue(PosixTcpOptions::kDefaultSendBytesThreshold, 0, INT_MAX,
73 config.GetInt(GRPC_ARG_TCP_TX_ZEROCOPY_SEND_BYTES_THRESHOLD));
74 options.tcp_tx_zerocopy_max_simultaneous_sends =
75 AdjustValue(PosixTcpOptions::kDefaultMaxSends, 0, INT_MAX,
76 config.GetInt(GRPC_ARG_TCP_TX_ZEROCOPY_MAX_SIMULT_SENDS));
77 options.tcp_receive_buffer_size =
78 AdjustValue(PosixTcpOptions::kReadBufferSizeUnset, 0, INT_MAX,
79 config.GetInt(GRPC_ARG_TCP_RECEIVE_BUFFER_SIZE));
80 options.tcp_tx_zero_copy_enabled =
81 (AdjustValue(PosixTcpOptions::kZerocpTxEnabledDefault, 0, 1,
82 config.GetInt(GRPC_ARG_TCP_TX_ZEROCOPY_ENABLED)) != 0);
83 options.keep_alive_time_ms =
84 AdjustValue(0, 1, INT_MAX, config.GetInt(GRPC_ARG_KEEPALIVE_TIME_MS));
85 options.keep_alive_timeout_ms =
86 AdjustValue(0, 1, INT_MAX, config.GetInt(GRPC_ARG_KEEPALIVE_TIMEOUT_MS));
87 options.expand_wildcard_addrs =
88 (AdjustValue(0, 1, INT_MAX,
89 config.GetInt(GRPC_ARG_EXPAND_WILDCARD_ADDRS)) != 0);
90 options.allow_reuse_port =
91 (AdjustValue(0, 1, INT_MAX, config.GetInt(GRPC_ARG_ALLOW_REUSEPORT)) !=
92 0);
93 options.dscp = AdjustValue(PosixTcpOptions::kDscpNotSet, 0, 63,
94 config.GetInt(GRPC_ARG_DSCP));
95
96 if (options.tcp_min_read_chunk_size > options.tcp_max_read_chunk_size) {
97 options.tcp_min_read_chunk_size = options.tcp_max_read_chunk_size;
98 }
99 options.tcp_read_chunk_size = grpc_core::Clamp(
100 options.tcp_read_chunk_size, options.tcp_min_read_chunk_size,
101 options.tcp_max_read_chunk_size);
102
103 value = config.GetVoidPointer(GRPC_ARG_RESOURCE_QUOTA);
104 if (value != nullptr) {
105 options.resource_quota =
106 reinterpret_cast<grpc_core::ResourceQuota*>(value)->Ref();
107 }
108 value = config.GetVoidPointer(GRPC_ARG_SOCKET_MUTATOR);
109 if (value != nullptr) {
110 options.socket_mutator =
111 grpc_socket_mutator_ref(static_cast<grpc_socket_mutator*>(value));
112 }
113 return options;
114 }
115
116 #endif // GRPC_POSIX_SOCKET_TCP
117
118 #ifdef GRPC_POSIX_SOCKETUTILS
119
grpc_accept4(int sockfd,grpc_resolved_address * resolved_addr,int nonblock,int cloexec)120 int grpc_accept4(int sockfd, grpc_resolved_address* resolved_addr, int nonblock,
121 int cloexec) {
122 int fd, flags;
123 fd = accept(sockfd, reinterpret_cast<grpc_sockaddr*>(resolved_addr->addr),
124 &resolved_addr->len);
125 if (fd >= 0) {
126 if (nonblock) {
127 flags = fcntl(fd, F_GETFL, 0);
128 if (flags < 0) goto close_and_error;
129 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) goto close_and_error;
130 }
131 if (cloexec) {
132 flags = fcntl(fd, F_GETFD, 0);
133 if (flags < 0) goto close_and_error;
134 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != 0) goto close_and_error;
135 }
136 }
137 return fd;
138
139 close_and_error:
140 close(fd);
141 return -1;
142 }
143
144 #endif // GRPC_POSIX_SOCKETUTILS
145