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