Branch data Line data Source code
1 : : /*
2 : : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License").
5 : : * You may not use this file except in compliance with the License.
6 : : * A copy of the License is located at
7 : : *
8 : : * http://aws.amazon.com/apache2.0
9 : : *
10 : : * or in the "license" file accompanying this file. This file is distributed
11 : : * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 : : * express or implied. See the License for the specific language governing
13 : : * permissions and limitations under the License.
14 : : */
15 : :
16 : : #include "utils/s2n_socket.h"
17 : :
18 : : #include <netinet/in.h>
19 : : #include <netinet/tcp.h>
20 : : #include <sys/socket.h>
21 : : #include <unistd.h>
22 : :
23 : : #include "tls/s2n_connection.h"
24 : : #include "utils/s2n_safety.h"
25 : :
26 : : #if TCP_CORK
27 : 6457 : #define S2N_CORK TCP_CORK
28 : 62 : #define S2N_CORK_ON 1
29 : 72 : #define S2N_CORK_OFF 0
30 : : #elif TCP_NOPUSH
31 : : #define S2N_CORK TCP_NOPUSH
32 : : #define S2N_CORK_ON 1
33 : : #define S2N_CORK_OFF 0
34 : : #elif TCP_NODELAY
35 : : #define S2N_CORK TCP_NODELAY
36 : : #define S2N_CORK_ON 0
37 : : #define S2N_CORK_OFF 1
38 : : #endif
39 : :
40 : : int s2n_socket_quickack(struct s2n_connection *conn)
41 : 95081 : {
42 : 95081 : #ifdef TCP_QUICKACK
43 [ # # ][ - + ]: 95081 : POSIX_ENSURE_REF(conn);
44 [ + + ]: 95081 : if (!conn->managed_recv_io) {
45 : 41024 : return 0;
46 : 41024 : }
47 : :
48 : 54057 : struct s2n_socket_read_io_context *r_io_ctx = (struct s2n_socket_read_io_context *) conn->recv_io_context;
49 [ # # ][ - + ]: 54057 : POSIX_ENSURE_REF(r_io_ctx);
50 [ + + ]: 54057 : if (r_io_ctx->tcp_quickack_set) {
51 : 9 : return 0;
52 : 9 : }
53 : :
54 : : /* Ignore the return value, if it fails it fails */
55 : 54048 : int optval = 1;
56 [ + + ]: 54048 : if (setsockopt(r_io_ctx->fd, IPPROTO_TCP, TCP_QUICKACK, &optval, sizeof(optval)) == 0) {
57 : 11 : r_io_ctx->tcp_quickack_set = 1;
58 : 11 : }
59 : 54048 : #endif
60 : :
61 : 54048 : return 0;
62 : 54057 : }
63 : :
64 : : int s2n_socket_write_snapshot(struct s2n_connection *conn)
65 : 6323 : {
66 : 6323 : #ifdef S2N_CORK
67 : 6323 : socklen_t corklen = sizeof(int);
68 [ # # ][ - + ]: 6323 : POSIX_ENSURE_REF(conn);
69 : 6323 : struct s2n_socket_write_io_context *w_io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context;
70 [ - + ][ # # ]: 6323 : POSIX_ENSURE_REF(w_io_ctx);
71 : :
72 : 6323 : getsockopt(w_io_ctx->fd, IPPROTO_TCP, S2N_CORK, &w_io_ctx->original_cork_val, &corklen);
73 [ # # ][ - + ]: 6323 : POSIX_ENSURE_EQ(corklen, sizeof(int));
74 : 6323 : w_io_ctx->original_cork_is_set = 1;
75 : 6323 : #endif
76 : :
77 : 6323 : return 0;
78 : 6323 : }
79 : :
80 : : int s2n_socket_read_snapshot(struct s2n_connection *conn)
81 : 6365 : {
82 : 6365 : #ifdef SO_RCVLOWAT
83 : 6365 : socklen_t watlen = sizeof(int);
84 [ - + ][ # # ]: 6365 : POSIX_ENSURE_REF(conn);
85 : 6365 : struct s2n_socket_read_io_context *r_io_ctx = (struct s2n_socket_read_io_context *) conn->recv_io_context;
86 [ - + ][ # # ]: 6365 : POSIX_ENSURE_REF(r_io_ctx);
87 : :
88 : 6365 : getsockopt(r_io_ctx->fd, SOL_SOCKET, SO_RCVLOWAT, &r_io_ctx->original_rcvlowat_val, &watlen);
89 [ - + ][ # # ]: 6365 : POSIX_ENSURE_EQ(watlen, sizeof(int));
90 : 6365 : r_io_ctx->original_rcvlowat_is_set = 1;
91 : 6365 : #endif
92 : :
93 : 6365 : return 0;
94 : 6365 : }
95 : :
96 : : int s2n_socket_write_restore(struct s2n_connection *conn)
97 : 0 : {
98 : 0 : #ifdef S2N_CORK
99 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(conn);
100 : 0 : struct s2n_socket_write_io_context *w_io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context;
101 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(w_io_ctx);
102 : :
103 [ # # ]: 0 : if (!w_io_ctx->original_cork_is_set) {
104 : 0 : return 0;
105 : 0 : }
106 : 0 : setsockopt(w_io_ctx->fd, IPPROTO_TCP, S2N_CORK, &w_io_ctx->original_cork_val, sizeof(w_io_ctx->original_cork_val));
107 : 0 : w_io_ctx->original_cork_is_set = 0;
108 : 0 : #endif
109 : :
110 : 0 : return 0;
111 : 0 : }
112 : :
113 : : int s2n_socket_read_restore(struct s2n_connection *conn)
114 : 0 : {
115 : 0 : #ifdef SO_RCVLOWAT
116 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(conn);
117 : 0 : struct s2n_socket_read_io_context *r_io_ctx = (struct s2n_socket_read_io_context *) conn->recv_io_context;
118 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(r_io_ctx);
119 : :
120 [ # # ]: 0 : if (!r_io_ctx->original_rcvlowat_is_set) {
121 : 0 : return 0;
122 : 0 : }
123 : 0 : setsockopt(r_io_ctx->fd, SOL_SOCKET, SO_RCVLOWAT, &r_io_ctx->original_rcvlowat_val, sizeof(r_io_ctx->original_rcvlowat_val));
124 : 0 : r_io_ctx->original_rcvlowat_is_set = 0;
125 : 0 : #endif
126 : :
127 : 0 : return 0;
128 : 0 : }
129 : :
130 : : int s2n_socket_was_corked(struct s2n_connection *conn)
131 : 340 : {
132 [ - + ][ # # ]: 340 : POSIX_ENSURE_REF(conn);
133 : : /* If we're not using custom I/O and a send fd has not been set yet, return false*/
134 [ - + ][ - + ]: 340 : if (!conn->managed_send_io || !conn->send) {
135 : 0 : return 0;
136 : 0 : }
137 : :
138 : 340 : struct s2n_socket_write_io_context *io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context;
139 [ # # ][ - + ]: 340 : POSIX_ENSURE_REF(io_ctx);
140 : :
141 : 340 : return io_ctx->original_cork_val;
142 : 340 : }
143 : :
144 : : int s2n_socket_write_cork(struct s2n_connection *conn)
145 : 62 : {
146 : 62 : #ifdef S2N_CORK
147 [ # # ][ - + ]: 62 : POSIX_ENSURE_REF(conn);
148 : 62 : int optval = S2N_CORK_ON;
149 : :
150 : 62 : struct s2n_socket_write_io_context *w_io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context;
151 [ - + ][ # # ]: 62 : POSIX_ENSURE_REF(w_io_ctx);
152 : :
153 : : /* Ignore the return value, if it fails it fails */
154 : 62 : setsockopt(w_io_ctx->fd, IPPROTO_TCP, S2N_CORK, &optval, sizeof(optval));
155 : 62 : #endif
156 : :
157 : 62 : return 0;
158 : 62 : }
159 : :
160 : : int s2n_socket_write_uncork(struct s2n_connection *conn)
161 : 72 : {
162 : 72 : #ifdef S2N_CORK
163 [ # # ][ - + ]: 72 : POSIX_ENSURE_REF(conn);
164 : 72 : int optval = S2N_CORK_OFF;
165 : :
166 : 72 : struct s2n_socket_write_io_context *w_io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context;
167 [ - + ][ # # ]: 72 : POSIX_ENSURE_REF(w_io_ctx);
168 : :
169 : : /* Ignore the return value, if it fails it fails */
170 : 72 : setsockopt(w_io_ctx->fd, IPPROTO_TCP, S2N_CORK, &optval, sizeof(optval));
171 : 72 : #endif
172 : :
173 : 72 : return 0;
174 : 72 : }
175 : :
176 : : int s2n_socket_set_read_size(struct s2n_connection *conn, int size)
177 : 0 : {
178 : 0 : #ifdef SO_RCVLOWAT
179 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(conn);
180 : 0 : struct s2n_socket_read_io_context *r_io_ctx = (struct s2n_socket_read_io_context *) conn->recv_io_context;
181 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(r_io_ctx);
182 : :
183 : 0 : setsockopt(r_io_ctx->fd, SOL_SOCKET, SO_RCVLOWAT, &size, sizeof(size));
184 : 0 : #endif
185 : :
186 : 0 : return 0;
187 : 0 : }
188 : :
189 : : int s2n_socket_read(void *io_context, uint8_t *buf, uint32_t len)
190 : 510479 : {
191 [ # # ][ - + ]: 510479 : POSIX_ENSURE_REF(io_context);
192 [ - + ][ # # ]: 510479 : POSIX_ENSURE_REF(buf);
193 : 510479 : int rfd = ((struct s2n_socket_read_io_context *) io_context)->fd;
194 [ - + ]: 510479 : if (rfd < 0) {
195 : 0 : errno = EBADF;
196 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_BAD_FD);
197 : 0 : }
198 : :
199 : : /* Clear the quickack flag so we know to reset it */
200 : 510479 : ((struct s2n_socket_read_io_context *) io_context)->tcp_quickack_set = 0;
201 : :
202 : : /* On success, the number of bytes read is returned. On failure, -1 is
203 : : * returned and errno is set appropriately. */
204 : 510479 : ssize_t result = read(rfd, buf, len);
205 [ - + ][ # # ]: 510479 : POSIX_ENSURE_INCLUSIVE_RANGE(INT_MIN, result, INT_MAX);
[ - + ][ # # ]
206 : 510479 : return result;
207 : 510479 : }
208 : :
209 : : int s2n_socket_write(void *io_context, const uint8_t *buf, uint32_t len)
210 : 371588 : {
211 [ # # ][ - + ]: 371588 : POSIX_ENSURE_REF(io_context);
212 [ # # ][ - + ]: 371588 : POSIX_ENSURE_REF(buf);
213 : 371588 : int wfd = ((struct s2n_socket_write_io_context *) io_context)->fd;
214 [ - + ]: 371588 : if (wfd < 0) {
215 : 0 : errno = EBADF;
216 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_BAD_FD);
217 : 0 : }
218 : :
219 : : /* On success, the number of bytes written is returned. On failure, -1 is
220 : : * returned and errno is set appropriately. */
221 : 371588 : ssize_t result = write(wfd, buf, len);
222 [ # # ][ - + ]: 371588 : POSIX_ENSURE_INCLUSIVE_RANGE(INT_MIN, result, INT_MAX);
[ # # ][ - + ]
223 : 371588 : return result;
224 : 371588 : }
225 : :
226 : : int s2n_socket_is_ipv6(int fd, uint8_t *ipv6)
227 : 6323 : {
228 [ - + ][ # # ]: 6323 : POSIX_ENSURE_REF(ipv6);
229 : :
230 : 6323 : socklen_t len = 0;
231 : 6323 : struct sockaddr_storage addr;
232 : 6323 : len = sizeof(addr);
233 [ + + ]: 6323 : POSIX_GUARD(getpeername(fd, (struct sockaddr *) &addr, &len));
234 : :
235 : 6297 : *ipv6 = 0;
236 [ - + ]: 6297 : if (AF_INET6 == addr.ss_family) {
237 : 0 : *ipv6 = 1;
238 : 0 : }
239 : :
240 : 6297 : return 0;
241 : 6323 : }
|