1 | /* |
2 | * TCP/IP or UDP/IP networking functions |
3 | * |
4 | * Copyright The Mbed TLS Contributors |
5 | * SPDX-License-Identifier: Apache-2.0 |
6 | * |
7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may |
8 | * not use this file except in compliance with the License. |
9 | * You may obtain a copy of the License at |
10 | * |
11 | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | * |
13 | * Unless required by applicable law or agreed to in writing, software |
14 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
15 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | * See the License for the specific language governing permissions and |
17 | * limitations under the License. |
18 | */ |
19 | |
20 | /* Enable definition of getaddrinfo() even when compiling with -std=c99. Must |
21 | * be set before config.h, which pulls in glibc's features.h indirectly. |
22 | * Harmless on other platforms. */ |
23 | #ifndef _POSIX_C_SOURCE |
24 | #define _POSIX_C_SOURCE 200112L |
25 | #endif |
26 | #ifndef _XOPEN_SOURCE |
27 | #define _XOPEN_SOURCE 600 /* sockaddr_storage */ |
28 | #endif |
29 | |
30 | #include "common.h" |
31 | |
32 | #if defined(MBEDTLS_NET_C) |
33 | |
34 | #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ |
35 | !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ |
36 | !defined(__HAIKU__) && !defined(__midipix__) |
37 | #error "This module only works on Unix and Windows, see MBEDTLS_NET_C in config.h" |
38 | #endif |
39 | |
40 | #include "mbedtls/platform.h" |
41 | |
42 | #include "mbedtls/net_sockets.h" |
43 | #include "mbedtls/error.h" |
44 | |
45 | #include <string.h> |
46 | |
47 | #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ |
48 | !defined(EFI32) |
49 | |
50 | #define IS_EINTR(ret) ((ret) == WSAEINTR) |
51 | |
52 | #if !defined(_WIN32_WINNT) |
53 | /* Enables getaddrinfo() & Co */ |
54 | #define _WIN32_WINNT 0x0501 |
55 | #endif |
56 | |
57 | #include <ws2tcpip.h> |
58 | |
59 | #include <winsock2.h> |
60 | #include <windows.h> |
61 | #if (_WIN32_WINNT < 0x0501) |
62 | #include <wspiapi.h> |
63 | #endif |
64 | |
65 | #if defined(_MSC_VER) |
66 | #if defined(_WIN32_WCE) |
67 | #pragma comment( lib, "ws2.lib" ) |
68 | #else |
69 | #pragma comment( lib, "ws2_32.lib" ) |
70 | #endif |
71 | #endif /* _MSC_VER */ |
72 | |
73 | #define read(fd, buf, len) recv(fd, (char *) (buf), (int) (len), 0) |
74 | #define write(fd, buf, len) send(fd, (char *) (buf), (int) (len), 0) |
75 | #define close(fd) closesocket(fd) |
76 | |
77 | static int wsa_init_done = 0; |
78 | |
79 | #else /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ |
80 | |
81 | #include <sys/types.h> |
82 | #include <sys/socket.h> |
83 | #include <netinet/in.h> |
84 | #include <arpa/inet.h> |
85 | #include <sys/time.h> |
86 | #include <unistd.h> |
87 | #include <signal.h> |
88 | #include <fcntl.h> |
89 | #include <netdb.h> |
90 | #include <errno.h> |
91 | |
92 | #define IS_EINTR(ret) ((ret) == EINTR) |
93 | #define SOCKET int |
94 | |
95 | #endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ |
96 | |
97 | /* Some MS functions want int and MSVC warns if we pass size_t, |
98 | * but the standard functions use socklen_t, so cast only for MSVC */ |
99 | #if defined(_MSC_VER) |
100 | #define MSVC_INT_CAST (int) |
101 | #else |
102 | #define MSVC_INT_CAST |
103 | #endif |
104 | |
105 | #include <stdio.h> |
106 | |
107 | #if defined(MBEDTLS_HAVE_TIME) |
108 | #include <time.h> |
109 | #endif |
110 | |
111 | #include <stdint.h> |
112 | |
113 | /* |
114 | * Prepare for using the sockets interface |
115 | */ |
116 | static int net_prepare(void) |
117 | { |
118 | #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ |
119 | !defined(EFI32) |
120 | WSADATA wsaData; |
121 | |
122 | if (wsa_init_done == 0) { |
123 | if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) { |
124 | return MBEDTLS_ERR_NET_SOCKET_FAILED; |
125 | } |
126 | |
127 | wsa_init_done = 1; |
128 | } |
129 | #else |
130 | #if !defined(EFIX64) && !defined(EFI32) |
131 | signal(SIGPIPE, SIG_IGN); |
132 | #endif |
133 | #endif |
134 | return 0; |
135 | } |
136 | |
137 | /* |
138 | * Return 0 if the file descriptor is valid, an error otherwise. |
139 | * If for_select != 0, check whether the file descriptor is within the range |
140 | * allowed for fd_set used for the FD_xxx macros and the select() function. |
141 | */ |
142 | static int check_fd(int fd, int for_select) |
143 | { |
144 | if (fd < 0) { |
145 | return MBEDTLS_ERR_NET_INVALID_CONTEXT; |
146 | } |
147 | |
148 | #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ |
149 | !defined(EFI32) |
150 | (void) for_select; |
151 | #else |
152 | /* A limitation of select() is that it only works with file descriptors |
153 | * that are strictly less than FD_SETSIZE. This is a limitation of the |
154 | * fd_set type. Error out early, because attempting to call FD_SET on a |
155 | * large file descriptor is a buffer overflow on typical platforms. */ |
156 | if (for_select && fd >= FD_SETSIZE) { |
157 | return MBEDTLS_ERR_NET_POLL_FAILED; |
158 | } |
159 | #endif |
160 | |
161 | return 0; |
162 | } |
163 | |
164 | /* |
165 | * Initialize a context |
166 | */ |
167 | void mbedtls_net_init(mbedtls_net_context *ctx) |
168 | { |
169 | ctx->fd = -1; |
170 | } |
171 | |
172 | /* |
173 | * Initiate a TCP connection with host:port and the given protocol |
174 | */ |
175 | int mbedtls_net_connect(mbedtls_net_context *ctx, const char *host, |
176 | const char *port, int proto) |
177 | { |
178 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
179 | struct addrinfo hints, *addr_list, *cur; |
180 | |
181 | if ((ret = net_prepare()) != 0) { |
182 | return ret; |
183 | } |
184 | |
185 | /* Do name resolution with both IPv6 and IPv4 */ |
186 | memset(&hints, 0, sizeof(hints)); |
187 | hints.ai_family = AF_UNSPEC; |
188 | hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; |
189 | hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; |
190 | |
191 | if (getaddrinfo(host, port, &hints, &addr_list) != 0) { |
192 | return MBEDTLS_ERR_NET_UNKNOWN_HOST; |
193 | } |
194 | |
195 | /* Try the sockaddrs until a connection succeeds */ |
196 | ret = MBEDTLS_ERR_NET_UNKNOWN_HOST; |
197 | for (cur = addr_list; cur != NULL; cur = cur->ai_next) { |
198 | ctx->fd = (int) socket(cur->ai_family, cur->ai_socktype, |
199 | cur->ai_protocol); |
200 | if (ctx->fd < 0) { |
201 | ret = MBEDTLS_ERR_NET_SOCKET_FAILED; |
202 | continue; |
203 | } |
204 | |
205 | if (connect(ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen) == 0) { |
206 | ret = 0; |
207 | break; |
208 | } |
209 | |
210 | close(ctx->fd); |
211 | ret = MBEDTLS_ERR_NET_CONNECT_FAILED; |
212 | } |
213 | |
214 | freeaddrinfo(addr_list); |
215 | |
216 | return ret; |
217 | } |
218 | |
219 | /* |
220 | * Create a listening socket on bind_ip:port |
221 | */ |
222 | int mbedtls_net_bind(mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto) |
223 | { |
224 | int n, ret; |
225 | struct addrinfo hints, *addr_list, *cur; |
226 | |
227 | if ((ret = net_prepare()) != 0) { |
228 | return ret; |
229 | } |
230 | |
231 | /* Bind to IPv6 and/or IPv4, but only in the desired protocol */ |
232 | memset(&hints, 0, sizeof(hints)); |
233 | hints.ai_family = AF_UNSPEC; |
234 | hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; |
235 | hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; |
236 | if (bind_ip == NULL) { |
237 | hints.ai_flags = AI_PASSIVE; |
238 | } |
239 | |
240 | if (getaddrinfo(bind_ip, port, &hints, &addr_list) != 0) { |
241 | return MBEDTLS_ERR_NET_UNKNOWN_HOST; |
242 | } |
243 | |
244 | /* Try the sockaddrs until a binding succeeds */ |
245 | ret = MBEDTLS_ERR_NET_UNKNOWN_HOST; |
246 | for (cur = addr_list; cur != NULL; cur = cur->ai_next) { |
247 | ctx->fd = (int) socket(cur->ai_family, cur->ai_socktype, |
248 | cur->ai_protocol); |
249 | if (ctx->fd < 0) { |
250 | ret = MBEDTLS_ERR_NET_SOCKET_FAILED; |
251 | continue; |
252 | } |
253 | |
254 | n = 1; |
255 | if (setsockopt(ctx->fd, SOL_SOCKET, SO_REUSEADDR, |
256 | (const char *) &n, sizeof(n)) != 0) { |
257 | close(ctx->fd); |
258 | ret = MBEDTLS_ERR_NET_SOCKET_FAILED; |
259 | continue; |
260 | } |
261 | |
262 | if (bind(ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen) != 0) { |
263 | close(ctx->fd); |
264 | ret = MBEDTLS_ERR_NET_BIND_FAILED; |
265 | continue; |
266 | } |
267 | |
268 | /* Listen only makes sense for TCP */ |
269 | if (proto == MBEDTLS_NET_PROTO_TCP) { |
270 | if (listen(ctx->fd, MBEDTLS_NET_LISTEN_BACKLOG) != 0) { |
271 | close(ctx->fd); |
272 | ret = MBEDTLS_ERR_NET_LISTEN_FAILED; |
273 | continue; |
274 | } |
275 | } |
276 | |
277 | /* Bind was successful */ |
278 | ret = 0; |
279 | break; |
280 | } |
281 | |
282 | freeaddrinfo(addr_list); |
283 | |
284 | return ret; |
285 | |
286 | } |
287 | |
288 | #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ |
289 | !defined(EFI32) |
290 | /* |
291 | * Check if the requested operation would be blocking on a non-blocking socket |
292 | * and thus 'failed' with a negative return value. |
293 | */ |
294 | static int net_would_block(const mbedtls_net_context *ctx) |
295 | { |
296 | ((void) ctx); |
297 | return WSAGetLastError() == WSAEWOULDBLOCK; |
298 | } |
299 | #else |
300 | /* |
301 | * Check if the requested operation would be blocking on a non-blocking socket |
302 | * and thus 'failed' with a negative return value. |
303 | * |
304 | * Note: on a blocking socket this function always returns 0! |
305 | */ |
306 | static int net_would_block(const mbedtls_net_context *ctx) |
307 | { |
308 | int err = errno; |
309 | |
310 | /* |
311 | * Never return 'WOULD BLOCK' on a blocking socket |
312 | */ |
313 | if ((fcntl(ctx->fd, F_GETFL) & O_NONBLOCK) != O_NONBLOCK) { |
314 | errno = err; |
315 | return 0; |
316 | } |
317 | |
318 | switch (errno = err) { |
319 | #if defined EAGAIN |
320 | case EAGAIN: |
321 | #endif |
322 | #if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN |
323 | case EWOULDBLOCK: |
324 | #endif |
325 | return 1; |
326 | } |
327 | return 0; |
328 | } |
329 | #endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ |
330 | |
331 | /* |
332 | * Accept a connection from a remote client |
333 | */ |
334 | int mbedtls_net_accept(mbedtls_net_context *bind_ctx, |
335 | mbedtls_net_context *client_ctx, |
336 | void *client_ip, size_t buf_size, size_t *ip_len) |
337 | { |
338 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
339 | int type; |
340 | |
341 | struct sockaddr_storage client_addr; |
342 | |
343 | #if defined(__socklen_t_defined) || defined(_SOCKLEN_T) || \ |
344 | defined(_SOCKLEN_T_DECLARED) || defined(__DEFINED_socklen_t) || \ |
345 | defined(socklen_t) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) |
346 | socklen_t n = (socklen_t) sizeof(client_addr); |
347 | socklen_t type_len = (socklen_t) sizeof(type); |
348 | #else |
349 | int n = (int) sizeof(client_addr); |
350 | int type_len = (int) sizeof(type); |
351 | #endif |
352 | |
353 | /* Is this a TCP or UDP socket? */ |
354 | if (getsockopt(bind_ctx->fd, SOL_SOCKET, SO_TYPE, |
355 | (void *) &type, &type_len) != 0 || |
356 | (type != SOCK_STREAM && type != SOCK_DGRAM)) { |
357 | return MBEDTLS_ERR_NET_ACCEPT_FAILED; |
358 | } |
359 | |
360 | if (type == SOCK_STREAM) { |
361 | /* TCP: actual accept() */ |
362 | ret = client_ctx->fd = (int) accept(bind_ctx->fd, |
363 | (struct sockaddr *) &client_addr, &n); |
364 | } else { |
365 | /* UDP: wait for a message, but keep it in the queue */ |
366 | char buf[1] = { 0 }; |
367 | |
368 | ret = (int) recvfrom(bind_ctx->fd, buf, sizeof(buf), MSG_PEEK, |
369 | (struct sockaddr *) &client_addr, &n); |
370 | |
371 | #if defined(_WIN32) |
372 | if (ret == SOCKET_ERROR && |
373 | WSAGetLastError() == WSAEMSGSIZE) { |
374 | /* We know buf is too small, thanks, just peeking here */ |
375 | ret = 0; |
376 | } |
377 | #endif |
378 | } |
379 | |
380 | if (ret < 0) { |
381 | if (net_would_block(bind_ctx) != 0) { |
382 | return MBEDTLS_ERR_SSL_WANT_READ; |
383 | } |
384 | |
385 | return MBEDTLS_ERR_NET_ACCEPT_FAILED; |
386 | } |
387 | |
388 | /* UDP: hijack the listening socket to communicate with the client, |
389 | * then bind a new socket to accept new connections */ |
390 | if (type != SOCK_STREAM) { |
391 | struct sockaddr_storage local_addr; |
392 | int one = 1; |
393 | |
394 | if (connect(bind_ctx->fd, (struct sockaddr *) &client_addr, n) != 0) { |
395 | return MBEDTLS_ERR_NET_ACCEPT_FAILED; |
396 | } |
397 | |
398 | client_ctx->fd = bind_ctx->fd; |
399 | bind_ctx->fd = -1; /* In case we exit early */ |
400 | |
401 | n = sizeof(struct sockaddr_storage); |
402 | if (getsockname(client_ctx->fd, |
403 | (struct sockaddr *) &local_addr, &n) != 0 || |
404 | (bind_ctx->fd = (int) socket(local_addr.ss_family, |
405 | SOCK_DGRAM, IPPROTO_UDP)) < 0 || |
406 | setsockopt(bind_ctx->fd, SOL_SOCKET, SO_REUSEADDR, |
407 | (const char *) &one, sizeof(one)) != 0) { |
408 | return MBEDTLS_ERR_NET_SOCKET_FAILED; |
409 | } |
410 | |
411 | if (bind(bind_ctx->fd, (struct sockaddr *) &local_addr, n) != 0) { |
412 | return MBEDTLS_ERR_NET_BIND_FAILED; |
413 | } |
414 | } |
415 | |
416 | if (client_ip != NULL) { |
417 | if (client_addr.ss_family == AF_INET) { |
418 | struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr; |
419 | *ip_len = sizeof(addr4->sin_addr.s_addr); |
420 | |
421 | if (buf_size < *ip_len) { |
422 | return MBEDTLS_ERR_NET_BUFFER_TOO_SMALL; |
423 | } |
424 | |
425 | memcpy(client_ip, &addr4->sin_addr.s_addr, *ip_len); |
426 | } else { |
427 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &client_addr; |
428 | *ip_len = sizeof(addr6->sin6_addr.s6_addr); |
429 | |
430 | if (buf_size < *ip_len) { |
431 | return MBEDTLS_ERR_NET_BUFFER_TOO_SMALL; |
432 | } |
433 | |
434 | memcpy(client_ip, &addr6->sin6_addr.s6_addr, *ip_len); |
435 | } |
436 | } |
437 | |
438 | return 0; |
439 | } |
440 | |
441 | /* |
442 | * Set the socket blocking or non-blocking |
443 | */ |
444 | int mbedtls_net_set_block(mbedtls_net_context *ctx) |
445 | { |
446 | #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ |
447 | !defined(EFI32) |
448 | u_long n = 0; |
449 | return ioctlsocket(ctx->fd, FIONBIO, &n); |
450 | #else |
451 | return fcntl(ctx->fd, F_SETFL, fcntl(ctx->fd, F_GETFL) & ~O_NONBLOCK); |
452 | #endif |
453 | } |
454 | |
455 | int mbedtls_net_set_nonblock(mbedtls_net_context *ctx) |
456 | { |
457 | #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ |
458 | !defined(EFI32) |
459 | u_long n = 1; |
460 | return ioctlsocket(ctx->fd, FIONBIO, &n); |
461 | #else |
462 | return fcntl(ctx->fd, F_SETFL, fcntl(ctx->fd, F_GETFL) | O_NONBLOCK); |
463 | #endif |
464 | } |
465 | |
466 | /* |
467 | * Check if data is available on the socket |
468 | */ |
469 | |
470 | int mbedtls_net_poll(mbedtls_net_context *ctx, uint32_t rw, uint32_t timeout) |
471 | { |
472 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
473 | struct timeval tv; |
474 | |
475 | fd_set read_fds; |
476 | fd_set write_fds; |
477 | |
478 | int fd = ctx->fd; |
479 | |
480 | ret = check_fd(fd, 1); |
481 | if (ret != 0) { |
482 | return ret; |
483 | } |
484 | |
485 | #if defined(__has_feature) |
486 | #if __has_feature(memory_sanitizer) |
487 | /* Ensure that memory sanitizers consider read_fds and write_fds as |
488 | * initialized even on platforms such as Glibc/x86_64 where FD_ZERO |
489 | * is implemented in assembly. */ |
490 | memset(&read_fds, 0, sizeof(read_fds)); |
491 | memset(&write_fds, 0, sizeof(write_fds)); |
492 | #endif |
493 | #endif |
494 | |
495 | FD_ZERO(&read_fds); |
496 | if (rw & MBEDTLS_NET_POLL_READ) { |
497 | rw &= ~MBEDTLS_NET_POLL_READ; |
498 | FD_SET((SOCKET) fd, &read_fds); |
499 | } |
500 | |
501 | FD_ZERO(&write_fds); |
502 | if (rw & MBEDTLS_NET_POLL_WRITE) { |
503 | rw &= ~MBEDTLS_NET_POLL_WRITE; |
504 | FD_SET((SOCKET) fd, &write_fds); |
505 | } |
506 | |
507 | if (rw != 0) { |
508 | return MBEDTLS_ERR_NET_BAD_INPUT_DATA; |
509 | } |
510 | |
511 | tv.tv_sec = timeout / 1000; |
512 | tv.tv_usec = (timeout % 1000) * 1000; |
513 | |
514 | do { |
515 | ret = select(fd + 1, &read_fds, &write_fds, NULL, |
516 | timeout == (uint32_t) -1 ? NULL : &tv); |
517 | } while (IS_EINTR(ret)); |
518 | |
519 | if (ret < 0) { |
520 | return MBEDTLS_ERR_NET_POLL_FAILED; |
521 | } |
522 | |
523 | ret = 0; |
524 | if (FD_ISSET(fd, &read_fds)) { |
525 | ret |= MBEDTLS_NET_POLL_READ; |
526 | } |
527 | if (FD_ISSET(fd, &write_fds)) { |
528 | ret |= MBEDTLS_NET_POLL_WRITE; |
529 | } |
530 | |
531 | return ret; |
532 | } |
533 | |
534 | /* |
535 | * Portable usleep helper |
536 | */ |
537 | void mbedtls_net_usleep(unsigned long usec) |
538 | { |
539 | #if defined(_WIN32) |
540 | Sleep((usec + 999) / 1000); |
541 | #else |
542 | struct timeval tv; |
543 | tv.tv_sec = usec / 1000000; |
544 | #if defined(__unix__) || defined(__unix) || \ |
545 | (defined(__APPLE__) && defined(__MACH__)) |
546 | tv.tv_usec = (suseconds_t) usec % 1000000; |
547 | #else |
548 | tv.tv_usec = usec % 1000000; |
549 | #endif |
550 | select(0, NULL, NULL, NULL, &tv); |
551 | #endif |
552 | } |
553 | |
554 | /* |
555 | * Read at most 'len' characters |
556 | */ |
557 | int mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len) |
558 | { |
559 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
560 | int fd = ((mbedtls_net_context *) ctx)->fd; |
561 | |
562 | ret = check_fd(fd, 0); |
563 | if (ret != 0) { |
564 | return ret; |
565 | } |
566 | |
567 | ret = (int) read(fd, buf, len); |
568 | |
569 | if (ret < 0) { |
570 | if (net_would_block(ctx) != 0) { |
571 | return MBEDTLS_ERR_SSL_WANT_READ; |
572 | } |
573 | |
574 | #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ |
575 | !defined(EFI32) |
576 | if (WSAGetLastError() == WSAECONNRESET) { |
577 | return MBEDTLS_ERR_NET_CONN_RESET; |
578 | } |
579 | #else |
580 | if (errno == EPIPE || errno == ECONNRESET) { |
581 | return MBEDTLS_ERR_NET_CONN_RESET; |
582 | } |
583 | |
584 | if (errno == EINTR) { |
585 | return MBEDTLS_ERR_SSL_WANT_READ; |
586 | } |
587 | #endif |
588 | |
589 | return MBEDTLS_ERR_NET_RECV_FAILED; |
590 | } |
591 | |
592 | return ret; |
593 | } |
594 | |
595 | /* |
596 | * Read at most 'len' characters, blocking for at most 'timeout' ms |
597 | */ |
598 | int mbedtls_net_recv_timeout(void *ctx, unsigned char *buf, |
599 | size_t len, uint32_t timeout) |
600 | { |
601 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
602 | struct timeval tv; |
603 | fd_set read_fds; |
604 | int fd = ((mbedtls_net_context *) ctx)->fd; |
605 | |
606 | ret = check_fd(fd, 1); |
607 | if (ret != 0) { |
608 | return ret; |
609 | } |
610 | |
611 | FD_ZERO(&read_fds); |
612 | FD_SET((SOCKET) fd, &read_fds); |
613 | |
614 | tv.tv_sec = timeout / 1000; |
615 | tv.tv_usec = (timeout % 1000) * 1000; |
616 | |
617 | ret = select(fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv); |
618 | |
619 | /* Zero fds ready means we timed out */ |
620 | if (ret == 0) { |
621 | return MBEDTLS_ERR_SSL_TIMEOUT; |
622 | } |
623 | |
624 | if (ret < 0) { |
625 | #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ |
626 | !defined(EFI32) |
627 | if (WSAGetLastError() == WSAEINTR) { |
628 | return MBEDTLS_ERR_SSL_WANT_READ; |
629 | } |
630 | #else |
631 | if (errno == EINTR) { |
632 | return MBEDTLS_ERR_SSL_WANT_READ; |
633 | } |
634 | #endif |
635 | |
636 | return MBEDTLS_ERR_NET_RECV_FAILED; |
637 | } |
638 | |
639 | /* This call will not block */ |
640 | return mbedtls_net_recv(ctx, buf, len); |
641 | } |
642 | |
643 | /* |
644 | * Write at most 'len' characters |
645 | */ |
646 | int mbedtls_net_send(void *ctx, const unsigned char *buf, size_t len) |
647 | { |
648 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
649 | int fd = ((mbedtls_net_context *) ctx)->fd; |
650 | |
651 | ret = check_fd(fd, 0); |
652 | if (ret != 0) { |
653 | return ret; |
654 | } |
655 | |
656 | ret = (int) write(fd, buf, len); |
657 | |
658 | if (ret < 0) { |
659 | if (net_would_block(ctx) != 0) { |
660 | return MBEDTLS_ERR_SSL_WANT_WRITE; |
661 | } |
662 | |
663 | #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ |
664 | !defined(EFI32) |
665 | if (WSAGetLastError() == WSAECONNRESET) { |
666 | return MBEDTLS_ERR_NET_CONN_RESET; |
667 | } |
668 | #else |
669 | if (errno == EPIPE || errno == ECONNRESET) { |
670 | return MBEDTLS_ERR_NET_CONN_RESET; |
671 | } |
672 | |
673 | if (errno == EINTR) { |
674 | return MBEDTLS_ERR_SSL_WANT_WRITE; |
675 | } |
676 | #endif |
677 | |
678 | return MBEDTLS_ERR_NET_SEND_FAILED; |
679 | } |
680 | |
681 | return ret; |
682 | } |
683 | |
684 | /* |
685 | * Close the connection |
686 | */ |
687 | void mbedtls_net_close(mbedtls_net_context *ctx) |
688 | { |
689 | if (ctx->fd == -1) { |
690 | return; |
691 | } |
692 | |
693 | close(ctx->fd); |
694 | |
695 | ctx->fd = -1; |
696 | } |
697 | |
698 | /* |
699 | * Gracefully close the connection |
700 | */ |
701 | void mbedtls_net_free(mbedtls_net_context *ctx) |
702 | { |
703 | if (ctx->fd == -1) { |
704 | return; |
705 | } |
706 | |
707 | shutdown(ctx->fd, 2); |
708 | close(ctx->fd); |
709 | |
710 | ctx->fd = -1; |
711 | } |
712 | |
713 | #endif /* MBEDTLS_NET_C */ |
714 | |