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 : : /* On Windows, s2n-tls does not provide built-in socket I/O.
17 : : * This file compiles to an empty translation unit on Windows.
18 : : */
19 : : #ifndef _WIN32
20 : :
21 : : #include "utils/s2n_socket.h"
22 : :
23 : : #include <netinet/in.h>
24 : : #include <netinet/tcp.h>
25 : : #include <sys/socket.h>
26 : : #include <unistd.h>
27 : :
28 : : #include "tls/s2n_connection.h"
29 : : #include "utils/s2n_safety.h"
30 : :
31 : : #if TCP_CORK
32 : 7099 : #define S2N_CORK TCP_CORK
33 : 62 : #define S2N_CORK_ON 1
34 : 72 : #define S2N_CORK_OFF 0
35 : : #elif TCP_NOPUSH
36 : : #define S2N_CORK TCP_NOPUSH
37 : : #define S2N_CORK_ON 1
38 : : #define S2N_CORK_OFF 0
39 : : #elif TCP_NODELAY
40 : : #define S2N_CORK TCP_NODELAY
41 : : #define S2N_CORK_ON 0
42 : : #define S2N_CORK_OFF 1
43 : : #endif
44 : :
45 : : int s2n_socket_quickack(struct s2n_connection *conn)
46 : 101245 : {
47 : 101245 : #ifdef TCP_QUICKACK
48 [ - + ][ # # ]: 101245 : POSIX_ENSURE_REF(conn);
49 [ + + ]: 101245 : if (!conn->managed_recv_io) {
50 : 41675 : return 0;
51 : 41675 : }
52 : :
53 : 59570 : struct s2n_socket_read_io_context *r_io_ctx = (struct s2n_socket_read_io_context *) conn->recv_io_context;
54 [ # # ][ - + ]: 59570 : POSIX_ENSURE_REF(r_io_ctx);
55 [ + + ]: 59570 : if (r_io_ctx->tcp_quickack_set) {
56 : 9 : return 0;
57 : 9 : }
58 : :
59 : : /* Ignore the return value, if it fails it fails */
60 : 59561 : int optval = 1;
61 [ + + ]: 59561 : if (setsockopt(r_io_ctx->fd, IPPROTO_TCP, TCP_QUICKACK, &optval, sizeof(optval)) == 0) {
62 : 11 : r_io_ctx->tcp_quickack_set = 1;
63 : 11 : }
64 : 59561 : #endif
65 : :
66 : 59561 : return 0;
67 : 59570 : }
68 : :
69 : : int s2n_socket_write_snapshot(struct s2n_connection *conn)
70 : 6965 : {
71 : 6965 : #ifdef S2N_CORK
72 : 6965 : socklen_t corklen = sizeof(int);
73 [ - + ][ # # ]: 6965 : POSIX_ENSURE_REF(conn);
74 : 6965 : struct s2n_socket_write_io_context *w_io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context;
75 [ # # ][ - + ]: 6965 : POSIX_ENSURE_REF(w_io_ctx);
76 : :
77 : 6965 : getsockopt(w_io_ctx->fd, IPPROTO_TCP, S2N_CORK, &w_io_ctx->original_cork_val, &corklen);
78 [ - + ][ # # ]: 6965 : POSIX_ENSURE_EQ(corklen, sizeof(int));
79 : 6965 : w_io_ctx->original_cork_is_set = 1;
80 : 6965 : #endif
81 : :
82 : 6965 : return 0;
83 : 6965 : }
84 : :
85 : : int s2n_socket_read_snapshot(struct s2n_connection *conn)
86 : 6960 : {
87 : 6960 : #ifdef SO_RCVLOWAT
88 : 6960 : socklen_t watlen = sizeof(int);
89 [ # # ][ - + ]: 6960 : POSIX_ENSURE_REF(conn);
90 : 6960 : struct s2n_socket_read_io_context *r_io_ctx = (struct s2n_socket_read_io_context *) conn->recv_io_context;
91 [ - + ][ # # ]: 6960 : POSIX_ENSURE_REF(r_io_ctx);
92 : :
93 : 6960 : getsockopt(r_io_ctx->fd, SOL_SOCKET, SO_RCVLOWAT, &r_io_ctx->original_rcvlowat_val, &watlen);
94 [ # # ][ - + ]: 6960 : POSIX_ENSURE_EQ(watlen, sizeof(int));
95 : 6960 : r_io_ctx->original_rcvlowat_is_set = 1;
96 : 6960 : #endif
97 : :
98 : 6960 : return 0;
99 : 6960 : }
100 : :
101 : : int s2n_socket_write_restore(struct s2n_connection *conn)
102 : 0 : {
103 : 0 : #ifdef S2N_CORK
104 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(conn);
105 : 0 : struct s2n_socket_write_io_context *w_io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context;
106 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(w_io_ctx);
107 : :
108 [ # # ]: 0 : if (!w_io_ctx->original_cork_is_set) {
109 : 0 : return 0;
110 : 0 : }
111 : 0 : setsockopt(w_io_ctx->fd, IPPROTO_TCP, S2N_CORK, &w_io_ctx->original_cork_val, sizeof(w_io_ctx->original_cork_val));
112 : 0 : w_io_ctx->original_cork_is_set = 0;
113 : 0 : #endif
114 : :
115 : 0 : return 0;
116 : 0 : }
117 : :
118 : : int s2n_socket_read_restore(struct s2n_connection *conn)
119 : 0 : {
120 : 0 : #ifdef SO_RCVLOWAT
121 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(conn);
122 : 0 : struct s2n_socket_read_io_context *r_io_ctx = (struct s2n_socket_read_io_context *) conn->recv_io_context;
123 [ # # ][ # # ]: 0 : POSIX_ENSURE_REF(r_io_ctx);
124 : :
125 [ # # ]: 0 : if (!r_io_ctx->original_rcvlowat_is_set) {
126 : 0 : return 0;
127 : 0 : }
128 : 0 : setsockopt(r_io_ctx->fd, SOL_SOCKET, SO_RCVLOWAT, &r_io_ctx->original_rcvlowat_val, sizeof(r_io_ctx->original_rcvlowat_val));
129 : 0 : r_io_ctx->original_rcvlowat_is_set = 0;
130 : 0 : #endif
131 : :
132 : 0 : return 0;
133 : 0 : }
134 : :
135 : : int s2n_socket_was_corked(struct s2n_connection *conn)
136 : 340 : {
137 [ - + ][ # # ]: 340 : POSIX_ENSURE_REF(conn);
138 : : /* If we're not using custom I/O and a send fd has not been set yet, return false*/
139 [ - + ][ - + ]: 340 : if (!conn->managed_send_io || !conn->send) {
140 : 0 : return 0;
141 : 0 : }
142 : :
143 : 340 : struct s2n_socket_write_io_context *io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context;
144 [ - + ][ # # ]: 340 : POSIX_ENSURE_REF(io_ctx);
145 : :
146 : 340 : return io_ctx->original_cork_val;
147 : 340 : }
148 : :
149 : : int s2n_socket_write_cork(struct s2n_connection *conn)
150 : 62 : {
151 : 62 : #ifdef S2N_CORK
152 [ # # ][ - + ]: 62 : POSIX_ENSURE_REF(conn);
153 : 62 : int optval = S2N_CORK_ON;
154 : :
155 : 62 : struct s2n_socket_write_io_context *w_io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context;
156 [ - + ][ # # ]: 62 : POSIX_ENSURE_REF(w_io_ctx);
157 : :
158 : : /* Ignore the return value, if it fails it fails */
159 : 62 : setsockopt(w_io_ctx->fd, IPPROTO_TCP, S2N_CORK, &optval, sizeof(optval));
160 : 62 : #endif
161 : :
162 : 62 : return 0;
163 : 62 : }
164 : :
165 : : int s2n_socket_write_uncork(struct s2n_connection *conn)
166 : 72 : {
167 : 72 : #ifdef S2N_CORK
168 [ # # ][ - + ]: 72 : POSIX_ENSURE_REF(conn);
169 : 72 : int optval = S2N_CORK_OFF;
170 : :
171 : 72 : struct s2n_socket_write_io_context *w_io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context;
172 [ # # ][ - + ]: 72 : POSIX_ENSURE_REF(w_io_ctx);
173 : :
174 : : /* Ignore the return value, if it fails it fails */
175 : 72 : setsockopt(w_io_ctx->fd, IPPROTO_TCP, S2N_CORK, &optval, sizeof(optval));
176 : 72 : #endif
177 : :
178 : 72 : return 0;
179 : 72 : }
180 : :
181 : : int s2n_socket_read(void *io_context, uint8_t *buf, uint32_t len)
182 : 467589 : {
183 [ - + ][ # # ]: 467589 : POSIX_ENSURE_REF(io_context);
184 [ - + ][ # # ]: 467589 : POSIX_ENSURE_REF(buf);
185 : 467589 : int rfd = ((struct s2n_socket_read_io_context *) io_context)->fd;
186 [ - + ]: 467589 : if (rfd < 0) {
187 : 0 : errno = EBADF;
188 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_BAD_FD);
189 : 0 : }
190 : :
191 : : /* Clear the quickack flag so we know to reset it */
192 : 467589 : ((struct s2n_socket_read_io_context *) io_context)->tcp_quickack_set = 0;
193 : :
194 : : /* On success, the number of bytes read is returned. On failure, -1 is
195 : : * returned and errno is set appropriately. */
196 : 467589 : ssize_t result = read(rfd, buf, len);
197 [ # # ][ - + ]: 467589 : POSIX_ENSURE_INCLUSIVE_RANGE(INT_MIN, result, INT_MAX);
[ # # ][ - + ]
198 : 467589 : return result;
199 : 467589 : }
200 : :
201 : : int s2n_socket_write(void *io_context, const uint8_t *buf, uint32_t len)
202 : 368603 : {
203 [ # # ][ - + ]: 368603 : POSIX_ENSURE_REF(io_context);
204 [ - + ][ # # ]: 368603 : POSIX_ENSURE_REF(buf);
205 : 368603 : int wfd = ((struct s2n_socket_write_io_context *) io_context)->fd;
206 [ - + ]: 368603 : if (wfd < 0) {
207 : 0 : errno = EBADF;
208 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_BAD_FD);
209 : 0 : }
210 : :
211 : : /* On success, the number of bytes written is returned. On failure, -1 is
212 : : * returned and errno is set appropriately. */
213 : 368603 : ssize_t result = write(wfd, buf, len);
214 [ # # ][ - + ]: 368603 : POSIX_ENSURE_INCLUSIVE_RANGE(INT_MIN, result, INT_MAX);
[ # # ][ - + ]
215 : 368603 : return result;
216 : 368603 : }
217 : :
218 : : #endif
219 : :
220 : : /* Suppress empty translation unit warning when compiled on Windows. */
221 : : #pragma clang diagnostic ignored "-Wempty-translation-unit"
|