blob: db80447a31ec59426e0f61d5f76730800affdd54 [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
Manuel Pégourié-Gonnardf4acfe12014-09-17 10:56:54 +02002 * TCP/IP or UDP/IP networking functions
Paul Bakker5121ce52009-01-03 21:22:43 +00003 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02004 * Copyright The Mbed TLS Contributors
Manuel Pégourié-Gonnard37ff1402015-09-04 14:21:07 +02005 * 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.
Paul Bakker5121ce52009-01-03 21:22:43 +000018 */
19
Nicholas Wilson2682edf2017-12-05 12:08:15 +000020/* Enable definition of getaddrinfo() even when compiling with -std=c99. Must
Bence Szépkútibb0cfeb2021-05-28 09:42:25 +020021 * be set before mbedtls_config.h, which pulls in glibc's features.h indirectly.
Nicholas Wilson2682edf2017-12-05 12:08:15 +000022 * Harmless on other platforms. */
Flavio Ceolinb0257032020-05-27 22:41:19 -070023#ifndef _POSIX_C_SOURCE
Nicholas Wilson2682edf2017-12-05 12:08:15 +000024#define _POSIX_C_SOURCE 200112L
Flavio Ceolinb0257032020-05-27 22:41:19 -070025#endif
26#ifndef _XOPEN_SOURCE
nia0b01fd92020-06-11 12:29:15 +010027#define _XOPEN_SOURCE 600 /* sockaddr_storage */
Flavio Ceolinb0257032020-05-27 22:41:19 -070028#endif
Nicholas Wilson2682edf2017-12-05 12:08:15 +000029
Gilles Peskinedb09ef62020-06-03 01:43:33 +020030#include "common.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000031
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020032#if defined(MBEDTLS_NET_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000033
Manuel Pégourié-Gonnard325ce092016-02-22 10:33:34 +010034#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
Augustin Cavalier60bc47d2018-04-11 20:27:32 -040035 !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \
Ørjan Malde479d8de2020-05-20 09:32:39 +000036 !defined(__HAIKU__) && !defined(__midipix__)
Bence Szépkútibb0cfeb2021-05-28 09:42:25 +020037#error "This module only works on Unix and Windows, see MBEDTLS_NET_C in mbedtls_config.h"
Manuel Pégourié-Gonnard325ce092016-02-22 10:33:34 +010038#endif
39
SimonBd5800b72016-04-26 07:43:27 +010040#include "mbedtls/platform.h"
SimonBd5800b72016-04-26 07:43:27 +010041
Andres AG788aa4a2016-09-14 14:32:09 +010042#include "mbedtls/net_sockets.h"
Janos Follath73c616b2019-12-18 15:07:04 +000043#include "mbedtls/error.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000044
Rich Evans00ab4702015-02-06 13:43:58 +000045#include <string.h>
46
Paul Bakkerfa6a6202013-10-28 18:48:30 +010047#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
48 !defined(EFI32)
Paul Bakker5121ce52009-01-03 21:22:43 +000049
Gilles Peskine449bd832023-01-11 14:50:10 +010050#define IS_EINTR(ret) ((ret) == WSAEINTR)
Hanno Beckeref527962018-03-15 15:49:24 +000051
Manuel Pégourié-Gonnard6a398d42013-12-17 16:10:58 +010052#include <ws2tcpip.h>
Manuel Pégourié-Gonnard6a398d42013-12-17 16:10:58 +010053
Manuel Pégourié-Gonnard13211352013-12-17 17:38:55 +010054#include <winsock2.h>
55#include <windows.h>
opatomic2b2acf12020-04-24 10:00:36 -040056#if (_WIN32_WINNT < 0x0501)
57#include <wspiapi.h>
58#endif
Manuel Pégourié-Gonnard13211352013-12-17 17:38:55 +010059
Paul Bakkerf0fc2a22013-12-30 15:42:43 +010060#if defined(_MSC_VER)
Paul Bakker5121ce52009-01-03 21:22:43 +000061#if defined(_WIN32_WCE)
62#pragma comment( lib, "ws2.lib" )
63#else
64#pragma comment( lib, "ws2_32.lib" )
65#endif
Paul Bakkerf0fc2a22013-12-30 15:42:43 +010066#endif /* _MSC_VER */
Paul Bakker5121ce52009-01-03 21:22:43 +000067
Gilles Peskine449bd832023-01-11 14:50:10 +010068#define read(fd, buf, len) recv(fd, (char *) (buf), (int) (len), 0)
69#define write(fd, buf, len) send(fd, (char *) (buf), (int) (len), 0)
Paul Bakker5121ce52009-01-03 21:22:43 +000070#define close(fd) closesocket(fd)
71
72static int wsa_init_done = 0;
73
Paul Bakkerdb20c102014-06-17 14:34:44 +020074#else /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +000075
76#include <sys/types.h>
77#include <sys/socket.h>
78#include <netinet/in.h>
79#include <arpa/inet.h>
80#include <sys/time.h>
81#include <unistd.h>
82#include <signal.h>
83#include <fcntl.h>
84#include <netdb.h>
85#include <errno.h>
Paul Bakkerb3bb6c02009-07-27 21:09:47 +000086
Gilles Peskine449bd832023-01-11 14:50:10 +010087#define IS_EINTR(ret) ((ret) == EINTR)
Sergeyb57b0482023-03-06 15:51:39 -070088#define SOCKET int
Hanno Beckeref527962018-03-15 15:49:24 +000089
Paul Bakkerdb20c102014-06-17 14:34:44 +020090#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +000091
Manuel Pégourié-Gonnard9de64f52015-07-01 15:51:43 +020092/* Some MS functions want int and MSVC warns if we pass size_t,
Andres Amaya Garciabd9d42c2017-07-12 14:04:40 +010093 * but the standard functions use socklen_t, so cast only for MSVC */
Manuel Pégourié-Gonnard9de64f52015-07-01 15:51:43 +020094#if defined(_MSC_VER)
95#define MSVC_INT_CAST (int)
96#else
97#define MSVC_INT_CAST
98#endif
99
Paul Bakker5121ce52009-01-03 21:22:43 +0000100#include <stdio.h>
Paul Bakkerfa9b1002013-07-03 15:31:03 +0200101
Andrzej Kurek108bf522022-03-02 10:55:08 -0500102#if defined(MBEDTLS_HAVE_TIME)
Paul Bakker5121ce52009-01-03 21:22:43 +0000103#include <time.h>
Andrzej Kurek108bf522022-03-02 10:55:08 -0500104#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000105
Manuel Pégourié-Gonnard93866642015-06-22 19:21:23 +0200106#include <stdint.h>
Paul Bakker5c2364c2012-10-01 14:41:15 +0000107
Paul Bakker5121ce52009-01-03 21:22:43 +0000108/*
Manuel Pégourié-Gonnard2e5c3162013-12-13 11:55:32 +0100109 * Prepare for using the sockets interface
Paul Bakker5121ce52009-01-03 21:22:43 +0000110 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100111static int net_prepare(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000112{
Gilles Peskine449bd832023-01-11 14:50:10 +0100113#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100114 !defined(EFI32)
Paul Bakker5121ce52009-01-03 21:22:43 +0000115 WSADATA wsaData;
116
Gilles Peskine449bd832023-01-11 14:50:10 +0100117 if (wsa_init_done == 0) {
118 if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
119 return MBEDTLS_ERR_NET_SOCKET_FAILED;
120 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000121
122 wsa_init_done = 1;
123 }
124#else
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100125#if !defined(EFIX64) && !defined(EFI32)
Gilles Peskine449bd832023-01-11 14:50:10 +0100126 signal(SIGPIPE, SIG_IGN);
Paul Bakker5121ce52009-01-03 21:22:43 +0000127#endif
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100128#endif
Gilles Peskine449bd832023-01-11 14:50:10 +0100129 return 0;
Manuel Pégourié-Gonnard2e5c3162013-12-13 11:55:32 +0100130}
131
132/*
Gilles Peskine05360002021-06-20 23:08:19 +0200133 * Return 0 if the file descriptor is valid, an error otherwise.
134 * If for_select != 0, check whether the file descriptor is within the range
135 * allowed for fd_set used for the FD_xxx macros and the select() function.
136 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100137static int check_fd(int fd, int for_select)
Gilles Peskine05360002021-06-20 23:08:19 +0200138{
Gilles Peskine449bd832023-01-11 14:50:10 +0100139 if (fd < 0) {
140 return MBEDTLS_ERR_NET_INVALID_CONTEXT;
141 }
Gilles Peskine05360002021-06-20 23:08:19 +0200142
Gilles Peskinea5dd7bd2021-06-20 22:01:36 +0200143#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
144 !defined(EFI32)
145 (void) for_select;
146#else
Gilles Peskine05360002021-06-20 23:08:19 +0200147 /* A limitation of select() is that it only works with file descriptors
148 * that are strictly less than FD_SETSIZE. This is a limitation of the
149 * fd_set type. Error out early, because attempting to call FD_SET on a
150 * large file descriptor is a buffer overflow on typical platforms. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100151 if (for_select && fd >= FD_SETSIZE) {
152 return MBEDTLS_ERR_NET_POLL_FAILED;
153 }
Gilles Peskinea5dd7bd2021-06-20 22:01:36 +0200154#endif
Gilles Peskine05360002021-06-20 23:08:19 +0200155
Gilles Peskine449bd832023-01-11 14:50:10 +0100156 return 0;
Gilles Peskine05360002021-06-20 23:08:19 +0200157}
158
159/*
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200160 * Initialize a context
161 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100162void mbedtls_net_init(mbedtls_net_context *ctx)
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200163{
164 ctx->fd = -1;
165}
166
167/*
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100168 * Initiate a TCP connection with host:port and the given protocol
Manuel Pégourié-Gonnard2e5c3162013-12-13 11:55:32 +0100169 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100170int mbedtls_net_connect(mbedtls_net_context *ctx, const char *host,
171 const char *port, int proto)
Manuel Pégourié-Gonnard2e5c3162013-12-13 11:55:32 +0100172{
Janos Follath865b3eb2019-12-16 11:46:15 +0000173 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100174 struct addrinfo hints, *addr_list, *cur;
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100175
Gilles Peskine449bd832023-01-11 14:50:10 +0100176 if ((ret = net_prepare()) != 0) {
177 return ret;
178 }
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100179
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100180 /* Do name resolution with both IPv6 and IPv4 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100181 memset(&hints, 0, sizeof(hints));
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100182 hints.ai_family = AF_UNSPEC;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200183 hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
184 hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100185
Gilles Peskine449bd832023-01-11 14:50:10 +0100186 if (getaddrinfo(host, port, &hints, &addr_list) != 0) {
187 return MBEDTLS_ERR_NET_UNKNOWN_HOST;
188 }
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100189
190 /* Try the sockaddrs until a connection succeeds */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200191 ret = MBEDTLS_ERR_NET_UNKNOWN_HOST;
Gilles Peskine449bd832023-01-11 14:50:10 +0100192 for (cur = addr_list; cur != NULL; cur = cur->ai_next) {
193 ctx->fd = (int) socket(cur->ai_family, cur->ai_socktype,
194 cur->ai_protocol);
195 if (ctx->fd < 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200196 ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100197 continue;
198 }
199
Gilles Peskine449bd832023-01-11 14:50:10 +0100200 if (connect(ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen) == 0) {
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100201 ret = 0;
202 break;
203 }
204
Gilles Peskine449bd832023-01-11 14:50:10 +0100205 close(ctx->fd);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200206 ret = MBEDTLS_ERR_NET_CONNECT_FAILED;
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100207 }
208
Gilles Peskine449bd832023-01-11 14:50:10 +0100209 freeaddrinfo(addr_list);
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100210
Gilles Peskine449bd832023-01-11 14:50:10 +0100211 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000212}
213
214/*
215 * Create a listening socket on bind_ip:port
216 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100217int mbedtls_net_bind(mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto)
Paul Bakker5121ce52009-01-03 21:22:43 +0000218{
Manuel Pégourié-Gonnard173402b2013-12-17 15:57:05 +0100219 int n, ret;
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100220 struct addrinfo hints, *addr_list, *cur;
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100221
Gilles Peskine449bd832023-01-11 14:50:10 +0100222 if ((ret = net_prepare()) != 0) {
223 return ret;
224 }
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100225
Manuel Pégourié-Gonnarddb2468d2015-06-30 17:19:48 +0200226 /* Bind to IPv6 and/or IPv4, but only in the desired protocol */
Gilles Peskine449bd832023-01-11 14:50:10 +0100227 memset(&hints, 0, sizeof(hints));
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100228 hints.ai_family = AF_UNSPEC;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200229 hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
230 hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;
Gilles Peskine449bd832023-01-11 14:50:10 +0100231 if (bind_ip == NULL) {
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100232 hints.ai_flags = AI_PASSIVE;
Gilles Peskine449bd832023-01-11 14:50:10 +0100233 }
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100234
Gilles Peskine449bd832023-01-11 14:50:10 +0100235 if (getaddrinfo(bind_ip, port, &hints, &addr_list) != 0) {
236 return MBEDTLS_ERR_NET_UNKNOWN_HOST;
237 }
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100238
239 /* Try the sockaddrs until a binding succeeds */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200240 ret = MBEDTLS_ERR_NET_UNKNOWN_HOST;
Gilles Peskine449bd832023-01-11 14:50:10 +0100241 for (cur = addr_list; cur != NULL; cur = cur->ai_next) {
242 ctx->fd = (int) socket(cur->ai_family, cur->ai_socktype,
243 cur->ai_protocol);
244 if (ctx->fd < 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200245 ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100246 continue;
247 }
248
Manuel Pégourié-Gonnardfd6b4cc2013-12-17 13:59:01 +0100249 n = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100250 if (setsockopt(ctx->fd, SOL_SOCKET, SO_REUSEADDR,
251 (const char *) &n, sizeof(n)) != 0) {
252 close(ctx->fd);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200253 ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
Paul Bakker874bd642014-04-17 12:43:05 +0200254 continue;
255 }
Manuel Pégourié-Gonnardfd6b4cc2013-12-17 13:59:01 +0100256
Gilles Peskine449bd832023-01-11 14:50:10 +0100257 if (bind(ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen) != 0) {
258 close(ctx->fd);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200259 ret = MBEDTLS_ERR_NET_BIND_FAILED;
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100260 continue;
261 }
262
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100263 /* Listen only makes sense for TCP */
Gilles Peskine449bd832023-01-11 14:50:10 +0100264 if (proto == MBEDTLS_NET_PROTO_TCP) {
265 if (listen(ctx->fd, MBEDTLS_NET_LISTEN_BACKLOG) != 0) {
266 close(ctx->fd);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200267 ret = MBEDTLS_ERR_NET_LISTEN_FAILED;
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100268 continue;
269 }
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100270 }
271
Brian J Murray2adecba2016-11-06 04:45:15 -0800272 /* Bind was successful */
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100273 ret = 0;
274 break;
275 }
276
Gilles Peskine449bd832023-01-11 14:50:10 +0100277 freeaddrinfo(addr_list);
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100278
Gilles Peskine449bd832023-01-11 14:50:10 +0100279 return ret;
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100280
Paul Bakker5121ce52009-01-03 21:22:43 +0000281}
282
Gilles Peskine449bd832023-01-11 14:50:10 +0100283#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100284 !defined(EFI32)
Paul Bakker80025412014-01-23 20:59:49 +0100285/*
286 * Check if the requested operation would be blocking on a non-blocking socket
287 * and thus 'failed' with a negative return value.
288 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100289static int net_would_block(const mbedtls_net_context *ctx)
Paul Bakker80025412014-01-23 20:59:49 +0100290{
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200291 ((void) ctx);
Gilles Peskine449bd832023-01-11 14:50:10 +0100292 return WSAGetLastError() == WSAEWOULDBLOCK;
Paul Bakker80025412014-01-23 20:59:49 +0100293}
Paul Bakker5121ce52009-01-03 21:22:43 +0000294#else
Paul Bakker80025412014-01-23 20:59:49 +0100295/*
296 * Check if the requested operation would be blocking on a non-blocking socket
297 * and thus 'failed' with a negative return value.
298 *
299 * Note: on a blocking socket this function always returns 0!
300 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100301static int net_would_block(const mbedtls_net_context *ctx)
Paul Bakker80025412014-01-23 20:59:49 +0100302{
Hanno Beckera6ed9c52017-05-04 13:39:22 +0100303 int err = errno;
Hanno Beckerf4e5b7e2018-04-03 16:28:09 +0100304
Paul Bakker80025412014-01-23 20:59:49 +0100305 /*
Jaeden Ameroa152e422019-05-29 09:38:29 +0100306 * Never return 'WOULD BLOCK' on a blocking socket
Paul Bakker80025412014-01-23 20:59:49 +0100307 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100308 if ((fcntl(ctx->fd, F_GETFL) & O_NONBLOCK) != O_NONBLOCK) {
Hanno Beckera6ed9c52017-05-04 13:39:22 +0100309 errno = err;
Gilles Peskine449bd832023-01-11 14:50:10 +0100310 return 0;
Hanno Beckera6ed9c52017-05-04 13:39:22 +0100311 }
Paul Bakker80025412014-01-23 20:59:49 +0100312
Gilles Peskine449bd832023-01-11 14:50:10 +0100313 switch (errno = err) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000314#if defined EAGAIN
315 case EAGAIN:
316#endif
317#if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN
318 case EWOULDBLOCK:
319#endif
Gilles Peskine449bd832023-01-11 14:50:10 +0100320 return 1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000321 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100322 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000323}
Paul Bakkerdb20c102014-06-17 14:34:44 +0200324#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +0000325
326/*
327 * Accept a connection from a remote client
328 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100329int mbedtls_net_accept(mbedtls_net_context *bind_ctx,
330 mbedtls_net_context *client_ctx,
331 void *client_ip, size_t buf_size, size_t *ip_len)
Paul Bakker5121ce52009-01-03 21:22:43 +0000332{
Janos Follath865b3eb2019-12-16 11:46:15 +0000333 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100334 int type;
335
Manuel Pégourié-Gonnard6e315a92013-12-13 16:21:25 +0100336 struct sockaddr_storage client_addr;
Paul Bakker5121ce52009-01-03 21:22:43 +0000337
Paul Bakker394c56f2011-12-20 12:19:03 +0000338#if defined(__socklen_t_defined) || defined(_SOCKLEN_T) || \
nia0b01fd92020-06-11 12:29:15 +0100339 defined(_SOCKLEN_T_DECLARED) || defined(__DEFINED_socklen_t) || \
okhowang(王沛文)76158ce2020-09-03 15:36:36 +0800340 defined(socklen_t) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L)
Gilles Peskine449bd832023-01-11 14:50:10 +0100341 socklen_t n = (socklen_t) sizeof(client_addr);
342 socklen_t type_len = (socklen_t) sizeof(type);
Paul Bakker5121ce52009-01-03 21:22:43 +0000343#else
Gilles Peskine449bd832023-01-11 14:50:10 +0100344 int n = (int) sizeof(client_addr);
345 int type_len = (int) sizeof(type);
Paul Bakker5121ce52009-01-03 21:22:43 +0000346#endif
347
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100348 /* Is this a TCP or UDP socket? */
Gilles Peskine449bd832023-01-11 14:50:10 +0100349 if (getsockopt(bind_ctx->fd, SOL_SOCKET, SO_TYPE,
350 (void *) &type, &type_len) != 0 ||
351 (type != SOCK_STREAM && type != SOCK_DGRAM)) {
352 return MBEDTLS_ERR_NET_ACCEPT_FAILED;
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100353 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000354
Gilles Peskine449bd832023-01-11 14:50:10 +0100355 if (type == SOCK_STREAM) {
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100356 /* TCP: actual accept() */
Gilles Peskine449bd832023-01-11 14:50:10 +0100357 ret = client_ctx->fd = (int) accept(bind_ctx->fd,
358 (struct sockaddr *) &client_addr, &n);
359 } else {
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100360 /* UDP: wait for a message, but keep it in the queue */
361 char buf[1] = { 0 };
362
Gilles Peskine449bd832023-01-11 14:50:10 +0100363 ret = (int) recvfrom(bind_ctx->fd, buf, sizeof(buf), MSG_PEEK,
364 (struct sockaddr *) &client_addr, &n);
Manuel Pégourié-Gonnard16a17a42015-06-30 11:20:22 +0200365
366#if defined(_WIN32)
Gilles Peskine449bd832023-01-11 14:50:10 +0100367 if (ret == SOCKET_ERROR &&
368 WSAGetLastError() == WSAEMSGSIZE) {
Manuel Pégourié-Gonnard16a17a42015-06-30 11:20:22 +0200369 /* We know buf is too small, thanks, just peeking here */
370 ret = 0;
371 }
372#endif
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100373 }
374
Gilles Peskine449bd832023-01-11 14:50:10 +0100375 if (ret < 0) {
376 if (net_would_block(bind_ctx) != 0) {
377 return MBEDTLS_ERR_SSL_WANT_READ;
378 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000379
Gilles Peskine449bd832023-01-11 14:50:10 +0100380 return MBEDTLS_ERR_NET_ACCEPT_FAILED;
Paul Bakker5121ce52009-01-03 21:22:43 +0000381 }
382
Manuel Pégourié-Gonnardabc729e2015-07-01 01:28:24 +0200383 /* UDP: hijack the listening socket to communicate with the client,
384 * then bind a new socket to accept new connections */
Gilles Peskine449bd832023-01-11 14:50:10 +0100385 if (type != SOCK_STREAM) {
Manuel Pégourié-Gonnardabc729e2015-07-01 01:28:24 +0200386 struct sockaddr_storage local_addr;
387 int one = 1;
388
Gilles Peskine449bd832023-01-11 14:50:10 +0100389 if (connect(bind_ctx->fd, (struct sockaddr *) &client_addr, n) != 0) {
390 return MBEDTLS_ERR_NET_ACCEPT_FAILED;
391 }
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100392
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200393 client_ctx->fd = bind_ctx->fd;
Manuel Pégourié-Gonnardabc729e2015-07-01 01:28:24 +0200394 bind_ctx->fd = -1; /* In case we exit early */
395
Gilles Peskine449bd832023-01-11 14:50:10 +0100396 n = sizeof(struct sockaddr_storage);
397 if (getsockname(client_ctx->fd,
398 (struct sockaddr *) &local_addr, &n) != 0 ||
399 (bind_ctx->fd = (int) socket(local_addr.ss_family,
400 SOCK_DGRAM, IPPROTO_UDP)) < 0 ||
401 setsockopt(bind_ctx->fd, SOL_SOCKET, SO_REUSEADDR,
402 (const char *) &one, sizeof(one)) != 0) {
403 return MBEDTLS_ERR_NET_SOCKET_FAILED;
Manuel Pégourié-Gonnardabc729e2015-07-01 01:28:24 +0200404 }
405
Gilles Peskine449bd832023-01-11 14:50:10 +0100406 if (bind(bind_ctx->fd, (struct sockaddr *) &local_addr, n) != 0) {
407 return MBEDTLS_ERR_NET_BIND_FAILED;
Manuel Pégourié-Gonnardabc729e2015-07-01 01:28:24 +0200408 }
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100409 }
410
Gilles Peskine449bd832023-01-11 14:50:10 +0100411 if (client_ip != NULL) {
412 if (client_addr.ss_family == AF_INET) {
Manuel Pégourié-Gonnard6e315a92013-12-13 16:21:25 +0100413 struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr;
Gilles Peskine449bd832023-01-11 14:50:10 +0100414 *ip_len = sizeof(addr4->sin_addr.s_addr);
Manuel Pégourié-Gonnard0b104b02015-05-14 21:52:40 +0200415
Gilles Peskine449bd832023-01-11 14:50:10 +0100416 if (buf_size < *ip_len) {
417 return MBEDTLS_ERR_NET_BUFFER_TOO_SMALL;
418 }
Manuel Pégourié-Gonnard0b104b02015-05-14 21:52:40 +0200419
Gilles Peskine449bd832023-01-11 14:50:10 +0100420 memcpy(client_ip, &addr4->sin_addr.s_addr, *ip_len);
421 } else {
Manuel Pégourié-Gonnard6e315a92013-12-13 16:21:25 +0100422 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &client_addr;
Gilles Peskine449bd832023-01-11 14:50:10 +0100423 *ip_len = sizeof(addr6->sin6_addr.s6_addr);
Manuel Pégourié-Gonnard0b104b02015-05-14 21:52:40 +0200424
Gilles Peskine449bd832023-01-11 14:50:10 +0100425 if (buf_size < *ip_len) {
426 return MBEDTLS_ERR_NET_BUFFER_TOO_SMALL;
427 }
Manuel Pégourié-Gonnard0b104b02015-05-14 21:52:40 +0200428
Gilles Peskine449bd832023-01-11 14:50:10 +0100429 memcpy(client_ip, &addr6->sin6_addr.s6_addr, *ip_len);
Manuel Pégourié-Gonnard6e315a92013-12-13 16:21:25 +0100430 }
Manuel Pégourié-Gonnard6e315a92013-12-13 16:21:25 +0100431 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000432
Gilles Peskine449bd832023-01-11 14:50:10 +0100433 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000434}
435
436/*
437 * Set the socket blocking or non-blocking
438 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100439int mbedtls_net_set_block(mbedtls_net_context *ctx)
Paul Bakker5121ce52009-01-03 21:22:43 +0000440{
Gilles Peskine449bd832023-01-11 14:50:10 +0100441#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100442 !defined(EFI32)
Paul Bakkerf4f69682011-04-24 16:08:12 +0000443 u_long n = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100444 return ioctlsocket(ctx->fd, FIONBIO, &n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000445#else
Gilles Peskine449bd832023-01-11 14:50:10 +0100446 return fcntl(ctx->fd, F_SETFL, fcntl(ctx->fd, F_GETFL) & ~O_NONBLOCK);
Paul Bakker5121ce52009-01-03 21:22:43 +0000447#endif
448}
449
Gilles Peskine449bd832023-01-11 14:50:10 +0100450int mbedtls_net_set_nonblock(mbedtls_net_context *ctx)
Paul Bakker5121ce52009-01-03 21:22:43 +0000451{
Gilles Peskine449bd832023-01-11 14:50:10 +0100452#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100453 !defined(EFI32)
Paul Bakkerf4f69682011-04-24 16:08:12 +0000454 u_long n = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100455 return ioctlsocket(ctx->fd, FIONBIO, &n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000456#else
Gilles Peskine449bd832023-01-11 14:50:10 +0100457 return fcntl(ctx->fd, F_SETFL, fcntl(ctx->fd, F_GETFL) | O_NONBLOCK);
Paul Bakker5121ce52009-01-03 21:22:43 +0000458#endif
459}
460
461/*
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100462 * Check if data is available on the socket
463 */
464
Gilles Peskine449bd832023-01-11 14:50:10 +0100465int mbedtls_net_poll(mbedtls_net_context *ctx, uint32_t rw, uint32_t timeout)
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100466{
Janos Follath865b3eb2019-12-16 11:46:15 +0000467 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100468 struct timeval tv;
469
470 fd_set read_fds;
471 fd_set write_fds;
472
473 int fd = ctx->fd;
474
Gilles Peskine449bd832023-01-11 14:50:10 +0100475 ret = check_fd(fd, 1);
476 if (ret != 0) {
477 return ret;
478 }
Gilles Peskineddf43742021-02-24 19:49:44 +0100479
Gilles Peskineec4733b2018-04-05 14:55:47 +0200480#if defined(__has_feature)
481#if __has_feature(memory_sanitizer)
482 /* Ensure that memory sanitizers consider read_fds and write_fds as
483 * initialized even on platforms such as Glibc/x86_64 where FD_ZERO
484 * is implemented in assembly. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100485 memset(&read_fds, 0, sizeof(read_fds));
486 memset(&write_fds, 0, sizeof(write_fds));
Gilles Peskineec4733b2018-04-05 14:55:47 +0200487#endif
488#endif
Hanno Beckerf4e5b7e2018-04-03 16:28:09 +0100489
Gilles Peskine449bd832023-01-11 14:50:10 +0100490 FD_ZERO(&read_fds);
491 if (rw & MBEDTLS_NET_POLL_READ) {
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100492 rw &= ~MBEDTLS_NET_POLL_READ;
Sergeyb57b0482023-03-06 15:51:39 -0700493 FD_SET((SOCKET) fd, &read_fds);
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100494 }
495
Gilles Peskine449bd832023-01-11 14:50:10 +0100496 FD_ZERO(&write_fds);
497 if (rw & MBEDTLS_NET_POLL_WRITE) {
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100498 rw &= ~MBEDTLS_NET_POLL_WRITE;
Sergeyb57b0482023-03-06 15:51:39 -0700499 FD_SET((SOCKET) fd, &write_fds);
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100500 }
501
Gilles Peskine449bd832023-01-11 14:50:10 +0100502 if (rw != 0) {
503 return MBEDTLS_ERR_NET_BAD_INPUT_DATA;
504 }
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100505
506 tv.tv_sec = timeout / 1000;
Gilles Peskine449bd832023-01-11 14:50:10 +0100507 tv.tv_usec = (timeout % 1000) * 1000;
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100508
Gilles Peskine449bd832023-01-11 14:50:10 +0100509 do {
510 ret = select(fd + 1, &read_fds, &write_fds, NULL,
511 timeout == (uint32_t) -1 ? NULL : &tv);
512 } while (IS_EINTR(ret));
513
514 if (ret < 0) {
515 return MBEDTLS_ERR_NET_POLL_FAILED;
Hanno Becker80e06d72018-03-15 14:41:55 +0000516 }
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100517
518 ret = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100519 if (FD_ISSET(fd, &read_fds)) {
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100520 ret |= MBEDTLS_NET_POLL_READ;
Gilles Peskine449bd832023-01-11 14:50:10 +0100521 }
522 if (FD_ISSET(fd, &write_fds)) {
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100523 ret |= MBEDTLS_NET_POLL_WRITE;
Gilles Peskine449bd832023-01-11 14:50:10 +0100524 }
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100525
Gilles Peskine449bd832023-01-11 14:50:10 +0100526 return ret;
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100527}
528
529/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000530 * Portable usleep helper
531 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100532void mbedtls_net_usleep(unsigned long usec)
Paul Bakker5121ce52009-01-03 21:22:43 +0000533{
Manuel Pégourié-Gonnardacecb652015-07-01 11:29:31 +0200534#if defined(_WIN32)
Gilles Peskine449bd832023-01-11 14:50:10 +0100535 Sleep((usec + 999) / 1000);
Manuel Pégourié-Gonnardacecb652015-07-01 11:29:31 +0200536#else
Paul Bakker5121ce52009-01-03 21:22:43 +0000537 struct timeval tv;
Manuel Pégourié-Gonnarde4232462014-11-21 09:52:23 +0100538 tv.tv_sec = usec / 1000000;
Manuel Pégourié-Gonnardacecb652015-07-01 11:29:31 +0200539#if defined(__unix__) || defined(__unix) || \
Gilles Peskine449bd832023-01-11 14:50:10 +0100540 (defined(__APPLE__) && defined(__MACH__))
Manuel Pégourié-Gonnarde4232462014-11-21 09:52:23 +0100541 tv.tv_usec = (suseconds_t) usec % 1000000;
Sander Niemeijeref5087d2014-08-16 12:45:52 +0200542#else
Manuel Pégourié-Gonnarde4232462014-11-21 09:52:23 +0100543 tv.tv_usec = usec % 1000000;
Sander Niemeijeref5087d2014-08-16 12:45:52 +0200544#endif
Gilles Peskine449bd832023-01-11 14:50:10 +0100545 select(0, NULL, NULL, NULL, &tv);
Manuel Pégourié-Gonnardacecb652015-07-01 11:29:31 +0200546#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000547}
548
549/*
550 * Read at most 'len' characters
551 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100552int mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len)
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100553{
Janos Follath865b3eb2019-12-16 11:46:15 +0000554 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200555 int fd = ((mbedtls_net_context *) ctx)->fd;
Manuel Pégourié-Gonnard9bd0afd2015-07-01 19:03:27 +0200556
Gilles Peskine449bd832023-01-11 14:50:10 +0100557 ret = check_fd(fd, 0);
558 if (ret != 0) {
559 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000560 }
561
Gilles Peskine449bd832023-01-11 14:50:10 +0100562 ret = (int) read(fd, buf, len);
563
564 if (ret < 0) {
565 if (net_would_block(ctx) != 0) {
566 return MBEDTLS_ERR_SSL_WANT_READ;
567 }
568
569#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
570 !defined(EFI32)
571 if (WSAGetLastError() == WSAECONNRESET) {
572 return MBEDTLS_ERR_NET_CONN_RESET;
573 }
574#else
575 if (errno == EPIPE || errno == ECONNRESET) {
576 return MBEDTLS_ERR_NET_CONN_RESET;
577 }
578
579 if (errno == EINTR) {
580 return MBEDTLS_ERR_SSL_WANT_READ;
581 }
582#endif
583
584 return MBEDTLS_ERR_NET_RECV_FAILED;
585 }
586
587 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000588}
589
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200590/*
Manuel Pégourié-Gonnardc8d8e972014-10-01 15:01:39 +0200591 * Read at most 'len' characters, blocking for at most 'timeout' ms
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200592 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100593int mbedtls_net_recv_timeout(void *ctx, unsigned char *buf,
594 size_t len, uint32_t timeout)
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200595{
Janos Follath865b3eb2019-12-16 11:46:15 +0000596 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200597 struct timeval tv;
598 fd_set read_fds;
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200599 int fd = ((mbedtls_net_context *) ctx)->fd;
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200600
Gilles Peskine449bd832023-01-11 14:50:10 +0100601 ret = check_fd(fd, 1);
602 if (ret != 0) {
603 return ret;
604 }
Gilles Peskineddf43742021-02-24 19:49:44 +0100605
Gilles Peskine449bd832023-01-11 14:50:10 +0100606 FD_ZERO(&read_fds);
Sergeyb57b0482023-03-06 15:51:39 -0700607 FD_SET((SOCKET) fd, &read_fds);
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200608
Manuel Pégourié-Gonnardc8d8e972014-10-01 15:01:39 +0200609 tv.tv_sec = timeout / 1000;
Gilles Peskine449bd832023-01-11 14:50:10 +0100610 tv.tv_usec = (timeout % 1000) * 1000;
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200611
Gilles Peskine449bd832023-01-11 14:50:10 +0100612 ret = select(fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv);
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200613
614 /* Zero fds ready means we timed out */
Gilles Peskine449bd832023-01-11 14:50:10 +0100615 if (ret == 0) {
616 return MBEDTLS_ERR_SSL_TIMEOUT;
617 }
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200618
Gilles Peskine449bd832023-01-11 14:50:10 +0100619 if (ret < 0) {
620#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
621 !defined(EFI32)
622 if (WSAGetLastError() == WSAEINTR) {
623 return MBEDTLS_ERR_SSL_WANT_READ;
624 }
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200625#else
Gilles Peskine449bd832023-01-11 14:50:10 +0100626 if (errno == EINTR) {
627 return MBEDTLS_ERR_SSL_WANT_READ;
628 }
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200629#endif
630
Gilles Peskine449bd832023-01-11 14:50:10 +0100631 return MBEDTLS_ERR_NET_RECV_FAILED;
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200632 }
633
634 /* This call will not block */
Gilles Peskine449bd832023-01-11 14:50:10 +0100635 return mbedtls_net_recv(ctx, buf, len);
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200636}
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200637
Paul Bakker5121ce52009-01-03 21:22:43 +0000638/*
639 * Write at most 'len' characters
640 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100641int mbedtls_net_send(void *ctx, const unsigned char *buf, size_t len)
Paul Bakker5121ce52009-01-03 21:22:43 +0000642{
Janos Follath865b3eb2019-12-16 11:46:15 +0000643 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200644 int fd = ((mbedtls_net_context *) ctx)->fd;
Manuel Pégourié-Gonnard9bd0afd2015-07-01 19:03:27 +0200645
Gilles Peskine449bd832023-01-11 14:50:10 +0100646 ret = check_fd(fd, 0);
647 if (ret != 0) {
648 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000649 }
650
Gilles Peskine449bd832023-01-11 14:50:10 +0100651 ret = (int) write(fd, buf, len);
652
653 if (ret < 0) {
654 if (net_would_block(ctx) != 0) {
655 return MBEDTLS_ERR_SSL_WANT_WRITE;
656 }
657
658#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
659 !defined(EFI32)
660 if (WSAGetLastError() == WSAECONNRESET) {
661 return MBEDTLS_ERR_NET_CONN_RESET;
662 }
663#else
664 if (errno == EPIPE || errno == ECONNRESET) {
665 return MBEDTLS_ERR_NET_CONN_RESET;
666 }
667
668 if (errno == EINTR) {
669 return MBEDTLS_ERR_SSL_WANT_WRITE;
670 }
671#endif
672
673 return MBEDTLS_ERR_NET_SEND_FAILED;
674 }
675
676 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000677}
678
679/*
Robert Larsendf8e5112019-08-23 10:55:47 +0200680 * Close the connection
681 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100682void mbedtls_net_close(mbedtls_net_context *ctx)
Robert Larsendf8e5112019-08-23 10:55:47 +0200683{
Gilles Peskine449bd832023-01-11 14:50:10 +0100684 if (ctx->fd == -1) {
Robert Larsendf8e5112019-08-23 10:55:47 +0200685 return;
Gilles Peskine449bd832023-01-11 14:50:10 +0100686 }
Robert Larsendf8e5112019-08-23 10:55:47 +0200687
Gilles Peskine449bd832023-01-11 14:50:10 +0100688 close(ctx->fd);
Robert Larsendf8e5112019-08-23 10:55:47 +0200689
690 ctx->fd = -1;
691}
692
693/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000694 * Gracefully close the connection
695 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100696void mbedtls_net_free(mbedtls_net_context *ctx)
Paul Bakker5121ce52009-01-03 21:22:43 +0000697{
Gilles Peskine449bd832023-01-11 14:50:10 +0100698 if (ctx->fd == -1) {
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200699 return;
Gilles Peskine449bd832023-01-11 14:50:10 +0100700 }
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200701
Gilles Peskine449bd832023-01-11 14:50:10 +0100702 shutdown(ctx->fd, 2);
703 close(ctx->fd);
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200704
705 ctx->fd = -1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000706}
707
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200708#endif /* MBEDTLS_NET_C */