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 : 7009 : #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 : 100224 : {
42 : 100224 : #ifdef TCP_QUICKACK
43 [ - + ][ # # ]: 100224 : POSIX_ENSURE_REF(conn);
44 [ + + ]: 100224 : if (!conn->managed_recv_io) {
45 : 41462 : return 0;
46 : 41462 : }
47 : :
48 : 58762 : struct s2n_socket_read_io_context *r_io_ctx = (struct s2n_socket_read_io_context *) conn->recv_io_context;
49 [ # # ][ - + ]: 58762 : POSIX_ENSURE_REF(r_io_ctx);
50 [ + + ]: 58762 : 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 : 58753 : int optval = 1;
56 [ + + ]: 58753 : 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 : 58753 : #endif
60 : :
61 : 58753 : return 0;
62 : 58762 : }
63 : :
64 : : int s2n_socket_write_snapshot(struct s2n_connection *conn)
65 : 6875 : {
66 : 6875 : #ifdef S2N_CORK
67 : 6875 : socklen_t corklen = sizeof(int);
68 [ - + ][ # # ]: 6875 : POSIX_ENSURE_REF(conn);
69 : 6875 : struct s2n_socket_write_io_context *w_io_ctx = (struct s2n_socket_write_io_context *) conn->send_io_context;
70 [ # # ][ - + ]: 6875 : POSIX_ENSURE_REF(w_io_ctx);
71 : :
72 : 6875 : getsockopt(w_io_ctx->fd, IPPROTO_TCP, S2N_CORK, &w_io_ctx->original_cork_val, &corklen);
73 [ - + ][ # # ]: 6875 : POSIX_ENSURE_EQ(corklen, sizeof(int));
74 : 6875 : w_io_ctx->original_cork_is_set = 1;
75 : 6875 : #endif
76 : :
77 : 6875 : return 0;
78 : 6875 : }
79 : :
80 : : int s2n_socket_read_snapshot(struct s2n_connection *conn)
81 : 6917 : {
82 : 6917 : #ifdef SO_RCVLOWAT
83 : 6917 : socklen_t watlen = sizeof(int);
84 [ # # ][ - + ]: 6917 : POSIX_ENSURE_REF(conn);
85 : 6917 : struct s2n_socket_read_io_context *r_io_ctx = (struct s2n_socket_read_io_context *) conn->recv_io_context;
86 [ - + ][ # # ]: 6917 : POSIX_ENSURE_REF(r_io_ctx);
87 : :
88 : 6917 : getsockopt(r_io_ctx->fd, SOL_SOCKET, SO_RCVLOWAT, &r_io_ctx->original_rcvlowat_val, &watlen);
89 [ # # ][ - + ]: 6917 : POSIX_ENSURE_EQ(watlen, sizeof(int));
90 : 6917 : r_io_ctx->original_rcvlowat_is_set = 1;
91 : 6917 : #endif
92 : :
93 : 6917 : return 0;
94 : 6917 : }
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_read(void *io_context, uint8_t *buf, uint32_t len)
177 : 516698 : {
178 [ - + ][ # # ]: 516698 : POSIX_ENSURE_REF(io_context);
179 [ # # ][ - + ]: 516698 : POSIX_ENSURE_REF(buf);
180 : 516698 : int rfd = ((struct s2n_socket_read_io_context *) io_context)->fd;
181 [ - + ]: 516698 : if (rfd < 0) {
182 : 0 : errno = EBADF;
183 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_BAD_FD);
184 : 0 : }
185 : :
186 : : /* Clear the quickack flag so we know to reset it */
187 : 516698 : ((struct s2n_socket_read_io_context *) io_context)->tcp_quickack_set = 0;
188 : :
189 : : /* On success, the number of bytes read is returned. On failure, -1 is
190 : : * returned and errno is set appropriately. */
191 : 516698 : ssize_t result = read(rfd, buf, len);
192 [ # # ][ - + ]: 516698 : POSIX_ENSURE_INCLUSIVE_RANGE(INT_MIN, result, INT_MAX);
[ # # ][ - + ]
193 : 516698 : return result;
194 : 516698 : }
195 : :
196 : : int s2n_socket_write(void *io_context, const uint8_t *buf, uint32_t len)
197 : 389248 : {
198 [ # # ][ - + ]: 389248 : POSIX_ENSURE_REF(io_context);
199 [ - + ][ # # ]: 389248 : POSIX_ENSURE_REF(buf);
200 : 389248 : int wfd = ((struct s2n_socket_write_io_context *) io_context)->fd;
201 [ - + ]: 389248 : if (wfd < 0) {
202 : 0 : errno = EBADF;
203 [ # # ]: 0 : POSIX_BAIL(S2N_ERR_BAD_FD);
204 : 0 : }
205 : :
206 : : /* On success, the number of bytes written is returned. On failure, -1 is
207 : : * returned and errno is set appropriately. */
208 : 389248 : ssize_t result = write(wfd, buf, len);
209 [ # # ][ - + ]: 389248 : POSIX_ENSURE_INCLUSIVE_RANGE(INT_MIN, result, INT_MAX);
[ # # ][ - + ]
210 : 389248 : return result;
211 : 389248 : }
212 : :
213 : : int s2n_socket_is_ipv6(int fd, uint8_t *ipv6)
214 : 6875 : {
215 [ - + ][ # # ]: 6875 : POSIX_ENSURE_REF(ipv6);
216 : :
217 : 6875 : socklen_t len = 0;
218 : 6875 : struct sockaddr_storage addr;
219 : 6875 : len = sizeof(addr);
220 [ + + ]: 6875 : POSIX_GUARD(getpeername(fd, (struct sockaddr *) &addr, &len));
221 : :
222 : 6849 : *ipv6 = 0;
223 [ - + ]: 6849 : if (AF_INET6 == addr.ss_family) {
224 : 0 : *ipv6 = 1;
225 : 0 : }
226 : :
227 : 6849 : return 0;
228 : 6875 : }
|