blob: e63d08b15dda887e3a62528f43505b64b7bbc99f [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
opatomic2b2acf12020-04-24 10:00:36 -040052#if !defined(_WIN32_WINNT)
Manuel Pégourié-Gonnard3b6269a2014-03-21 10:31:12 +010053/* Enables getaddrinfo() & Co */
Manuel Pégourié-Gonnard13211352013-12-17 17:38:55 +010054#define _WIN32_WINNT 0x0501
Fabio Alessandrellidf608562018-04-03 19:40:11 +020055#endif
56
Manuel Pégourié-Gonnard6a398d42013-12-17 16:10:58 +010057#include <ws2tcpip.h>
Manuel Pégourié-Gonnard6a398d42013-12-17 16:10:58 +010058
Manuel Pégourié-Gonnard13211352013-12-17 17:38:55 +010059#include <winsock2.h>
60#include <windows.h>
opatomic2b2acf12020-04-24 10:00:36 -040061#if (_WIN32_WINNT < 0x0501)
62#include <wspiapi.h>
63#endif
Manuel Pégourié-Gonnard13211352013-12-17 17:38:55 +010064
Paul Bakkerf0fc2a22013-12-30 15:42:43 +010065#if defined(_MSC_VER)
Paul Bakker5121ce52009-01-03 21:22:43 +000066#if defined(_WIN32_WCE)
67#pragma comment( lib, "ws2.lib" )
68#else
69#pragma comment( lib, "ws2_32.lib" )
70#endif
Paul Bakkerf0fc2a22013-12-30 15:42:43 +010071#endif /* _MSC_VER */
Paul Bakker5121ce52009-01-03 21:22:43 +000072
Gilles Peskine449bd832023-01-11 14:50:10 +010073#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)
Paul Bakker5121ce52009-01-03 21:22:43 +000075#define close(fd) closesocket(fd)
76
77static int wsa_init_done = 0;
78
Paul Bakkerdb20c102014-06-17 14:34:44 +020079#else /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +000080
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>
Paul Bakkerb3bb6c02009-07-27 21:09:47 +000091
Gilles Peskine449bd832023-01-11 14:50:10 +010092#define IS_EINTR(ret) ((ret) == EINTR)
Hanno Beckeref527962018-03-15 15:49:24 +000093
Paul Bakkerdb20c102014-06-17 14:34:44 +020094#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +000095
Manuel Pégourié-Gonnard9de64f52015-07-01 15:51:43 +020096/* Some MS functions want int and MSVC warns if we pass size_t,
Andres Amaya Garciabd9d42c2017-07-12 14:04:40 +010097 * but the standard functions use socklen_t, so cast only for MSVC */
Manuel Pégourié-Gonnard9de64f52015-07-01 15:51:43 +020098#if defined(_MSC_VER)
99#define MSVC_INT_CAST (int)
100#else
101#define MSVC_INT_CAST
102#endif
103
Paul Bakker5121ce52009-01-03 21:22:43 +0000104#include <stdio.h>
Paul Bakkerfa9b1002013-07-03 15:31:03 +0200105
Andrzej Kurek108bf522022-03-02 10:55:08 -0500106#if defined(MBEDTLS_HAVE_TIME)
Paul Bakker5121ce52009-01-03 21:22:43 +0000107#include <time.h>
Andrzej Kurek108bf522022-03-02 10:55:08 -0500108#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000109
Manuel Pégourié-Gonnard93866642015-06-22 19:21:23 +0200110#include <stdint.h>
Paul Bakker5c2364c2012-10-01 14:41:15 +0000111
Paul Bakker5121ce52009-01-03 21:22:43 +0000112/*
Manuel Pégourié-Gonnard2e5c3162013-12-13 11:55:32 +0100113 * Prepare for using the sockets interface
Paul Bakker5121ce52009-01-03 21:22:43 +0000114 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100115static int net_prepare(void)
Paul Bakker5121ce52009-01-03 21:22:43 +0000116{
Gilles Peskine449bd832023-01-11 14:50:10 +0100117#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100118 !defined(EFI32)
Paul Bakker5121ce52009-01-03 21:22:43 +0000119 WSADATA wsaData;
120
Gilles Peskine449bd832023-01-11 14:50:10 +0100121 if (wsa_init_done == 0) {
122 if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
123 return MBEDTLS_ERR_NET_SOCKET_FAILED;
124 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000125
126 wsa_init_done = 1;
127 }
128#else
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100129#if !defined(EFIX64) && !defined(EFI32)
Gilles Peskine449bd832023-01-11 14:50:10 +0100130 signal(SIGPIPE, SIG_IGN);
Paul Bakker5121ce52009-01-03 21:22:43 +0000131#endif
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100132#endif
Gilles Peskine449bd832023-01-11 14:50:10 +0100133 return 0;
Manuel Pégourié-Gonnard2e5c3162013-12-13 11:55:32 +0100134}
135
136/*
Gilles Peskine05360002021-06-20 23:08:19 +0200137 * Return 0 if the file descriptor is valid, an error otherwise.
138 * If for_select != 0, check whether the file descriptor is within the range
139 * allowed for fd_set used for the FD_xxx macros and the select() function.
140 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100141static int check_fd(int fd, int for_select)
Gilles Peskine05360002021-06-20 23:08:19 +0200142{
Gilles Peskine449bd832023-01-11 14:50:10 +0100143 if (fd < 0) {
144 return MBEDTLS_ERR_NET_INVALID_CONTEXT;
145 }
Gilles Peskine05360002021-06-20 23:08:19 +0200146
Gilles Peskinea5dd7bd2021-06-20 22:01:36 +0200147#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
148 !defined(EFI32)
149 (void) for_select;
150#else
Gilles Peskine05360002021-06-20 23:08:19 +0200151 /* A limitation of select() is that it only works with file descriptors
152 * that are strictly less than FD_SETSIZE. This is a limitation of the
153 * fd_set type. Error out early, because attempting to call FD_SET on a
154 * large file descriptor is a buffer overflow on typical platforms. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100155 if (for_select && fd >= FD_SETSIZE) {
156 return MBEDTLS_ERR_NET_POLL_FAILED;
157 }
Gilles Peskinea5dd7bd2021-06-20 22:01:36 +0200158#endif
Gilles Peskine05360002021-06-20 23:08:19 +0200159
Gilles Peskine449bd832023-01-11 14:50:10 +0100160 return 0;
Gilles Peskine05360002021-06-20 23:08:19 +0200161}
162
163/*
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200164 * Initialize a context
165 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100166void mbedtls_net_init(mbedtls_net_context *ctx)
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200167{
168 ctx->fd = -1;
169}
170
171/*
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100172 * Initiate a TCP connection with host:port and the given protocol
Manuel Pégourié-Gonnard2e5c3162013-12-13 11:55:32 +0100173 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100174int mbedtls_net_connect(mbedtls_net_context *ctx, const char *host,
175 const char *port, int proto)
Manuel Pégourié-Gonnard2e5c3162013-12-13 11:55:32 +0100176{
Janos Follath865b3eb2019-12-16 11:46:15 +0000177 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100178 struct addrinfo hints, *addr_list, *cur;
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100179
Gilles Peskine449bd832023-01-11 14:50:10 +0100180 if ((ret = net_prepare()) != 0) {
181 return ret;
182 }
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100183
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100184 /* Do name resolution with both IPv6 and IPv4 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100185 memset(&hints, 0, sizeof(hints));
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100186 hints.ai_family = AF_UNSPEC;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200187 hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
188 hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100189
Gilles Peskine449bd832023-01-11 14:50:10 +0100190 if (getaddrinfo(host, port, &hints, &addr_list) != 0) {
191 return MBEDTLS_ERR_NET_UNKNOWN_HOST;
192 }
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100193
194 /* Try the sockaddrs until a connection succeeds */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200195 ret = MBEDTLS_ERR_NET_UNKNOWN_HOST;
Gilles Peskine449bd832023-01-11 14:50:10 +0100196 for (cur = addr_list; cur != NULL; cur = cur->ai_next) {
197 ctx->fd = (int) socket(cur->ai_family, cur->ai_socktype,
198 cur->ai_protocol);
199 if (ctx->fd < 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200200 ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100201 continue;
202 }
203
Gilles Peskine449bd832023-01-11 14:50:10 +0100204 if (connect(ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen) == 0) {
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100205 ret = 0;
206 break;
207 }
208
Gilles Peskine449bd832023-01-11 14:50:10 +0100209 close(ctx->fd);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200210 ret = MBEDTLS_ERR_NET_CONNECT_FAILED;
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100211 }
212
Gilles Peskine449bd832023-01-11 14:50:10 +0100213 freeaddrinfo(addr_list);
Manuel Pégourié-Gonnard10934de2013-12-13 12:54:09 +0100214
Gilles Peskine449bd832023-01-11 14:50:10 +0100215 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000216}
217
218/*
219 * Create a listening socket on bind_ip:port
220 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100221int mbedtls_net_bind(mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto)
Paul Bakker5121ce52009-01-03 21:22:43 +0000222{
Manuel Pégourié-Gonnard173402b2013-12-17 15:57:05 +0100223 int n, ret;
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100224 struct addrinfo hints, *addr_list, *cur;
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100225
Gilles Peskine449bd832023-01-11 14:50:10 +0100226 if ((ret = net_prepare()) != 0) {
227 return ret;
228 }
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100229
Manuel Pégourié-Gonnarddb2468d2015-06-30 17:19:48 +0200230 /* Bind to IPv6 and/or IPv4, but only in the desired protocol */
Gilles Peskine449bd832023-01-11 14:50:10 +0100231 memset(&hints, 0, sizeof(hints));
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100232 hints.ai_family = AF_UNSPEC;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200233 hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
234 hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;
Gilles Peskine449bd832023-01-11 14:50:10 +0100235 if (bind_ip == NULL) {
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100236 hints.ai_flags = AI_PASSIVE;
Gilles Peskine449bd832023-01-11 14:50:10 +0100237 }
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100238
Gilles Peskine449bd832023-01-11 14:50:10 +0100239 if (getaddrinfo(bind_ip, port, &hints, &addr_list) != 0) {
240 return MBEDTLS_ERR_NET_UNKNOWN_HOST;
241 }
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100242
243 /* Try the sockaddrs until a binding succeeds */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200244 ret = MBEDTLS_ERR_NET_UNKNOWN_HOST;
Gilles Peskine449bd832023-01-11 14:50:10 +0100245 for (cur = addr_list; cur != NULL; cur = cur->ai_next) {
246 ctx->fd = (int) socket(cur->ai_family, cur->ai_socktype,
247 cur->ai_protocol);
248 if (ctx->fd < 0) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200249 ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100250 continue;
251 }
252
Manuel Pégourié-Gonnardfd6b4cc2013-12-17 13:59:01 +0100253 n = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100254 if (setsockopt(ctx->fd, SOL_SOCKET, SO_REUSEADDR,
255 (const char *) &n, sizeof(n)) != 0) {
256 close(ctx->fd);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200257 ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
Paul Bakker874bd642014-04-17 12:43:05 +0200258 continue;
259 }
Manuel Pégourié-Gonnardfd6b4cc2013-12-17 13:59:01 +0100260
Gilles Peskine449bd832023-01-11 14:50:10 +0100261 if (bind(ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen) != 0) {
262 close(ctx->fd);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200263 ret = MBEDTLS_ERR_NET_BIND_FAILED;
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100264 continue;
265 }
266
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100267 /* Listen only makes sense for TCP */
Gilles Peskine449bd832023-01-11 14:50:10 +0100268 if (proto == MBEDTLS_NET_PROTO_TCP) {
269 if (listen(ctx->fd, MBEDTLS_NET_LISTEN_BACKLOG) != 0) {
270 close(ctx->fd);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200271 ret = MBEDTLS_ERR_NET_LISTEN_FAILED;
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100272 continue;
273 }
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100274 }
275
Brian J Murray2adecba2016-11-06 04:45:15 -0800276 /* Bind was successful */
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100277 ret = 0;
278 break;
279 }
280
Gilles Peskine449bd832023-01-11 14:50:10 +0100281 freeaddrinfo(addr_list);
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100282
Gilles Peskine449bd832023-01-11 14:50:10 +0100283 return ret;
Manuel Pégourié-Gonnard389ce632013-12-13 14:00:51 +0100284
Paul Bakker5121ce52009-01-03 21:22:43 +0000285}
286
Gilles Peskine449bd832023-01-11 14:50:10 +0100287#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100288 !defined(EFI32)
Paul Bakker80025412014-01-23 20:59:49 +0100289/*
290 * Check if the requested operation would be blocking on a non-blocking socket
291 * and thus 'failed' with a negative return value.
292 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100293static int net_would_block(const mbedtls_net_context *ctx)
Paul Bakker80025412014-01-23 20:59:49 +0100294{
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200295 ((void) ctx);
Gilles Peskine449bd832023-01-11 14:50:10 +0100296 return WSAGetLastError() == WSAEWOULDBLOCK;
Paul Bakker80025412014-01-23 20:59:49 +0100297}
Paul Bakker5121ce52009-01-03 21:22:43 +0000298#else
Paul Bakker80025412014-01-23 20:59:49 +0100299/*
300 * Check if the requested operation would be blocking on a non-blocking socket
301 * and thus 'failed' with a negative return value.
302 *
303 * Note: on a blocking socket this function always returns 0!
304 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100305static int net_would_block(const mbedtls_net_context *ctx)
Paul Bakker80025412014-01-23 20:59:49 +0100306{
Hanno Beckera6ed9c52017-05-04 13:39:22 +0100307 int err = errno;
Hanno Beckerf4e5b7e2018-04-03 16:28:09 +0100308
Paul Bakker80025412014-01-23 20:59:49 +0100309 /*
Jaeden Ameroa152e422019-05-29 09:38:29 +0100310 * Never return 'WOULD BLOCK' on a blocking socket
Paul Bakker80025412014-01-23 20:59:49 +0100311 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100312 if ((fcntl(ctx->fd, F_GETFL) & O_NONBLOCK) != O_NONBLOCK) {
Hanno Beckera6ed9c52017-05-04 13:39:22 +0100313 errno = err;
Gilles Peskine449bd832023-01-11 14:50:10 +0100314 return 0;
Hanno Beckera6ed9c52017-05-04 13:39:22 +0100315 }
Paul Bakker80025412014-01-23 20:59:49 +0100316
Gilles Peskine449bd832023-01-11 14:50:10 +0100317 switch (errno = err) {
Paul Bakker5121ce52009-01-03 21:22:43 +0000318#if defined EAGAIN
319 case EAGAIN:
320#endif
321#if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN
322 case EWOULDBLOCK:
323#endif
Gilles Peskine449bd832023-01-11 14:50:10 +0100324 return 1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000325 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100326 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000327}
Paul Bakkerdb20c102014-06-17 14:34:44 +0200328#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +0000329
330/*
331 * Accept a connection from a remote client
332 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100333int mbedtls_net_accept(mbedtls_net_context *bind_ctx,
334 mbedtls_net_context *client_ctx,
335 void *client_ip, size_t buf_size, size_t *ip_len)
Paul Bakker5121ce52009-01-03 21:22:43 +0000336{
Janos Follath865b3eb2019-12-16 11:46:15 +0000337 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100338 int type;
339
Manuel Pégourié-Gonnard6e315a92013-12-13 16:21:25 +0100340 struct sockaddr_storage client_addr;
Paul Bakker5121ce52009-01-03 21:22:43 +0000341
Paul Bakker394c56f2011-12-20 12:19:03 +0000342#if defined(__socklen_t_defined) || defined(_SOCKLEN_T) || \
nia0b01fd92020-06-11 12:29:15 +0100343 defined(_SOCKLEN_T_DECLARED) || defined(__DEFINED_socklen_t) || \
okhowang(王沛文)76158ce2020-09-03 15:36:36 +0800344 defined(socklen_t) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L)
Gilles Peskine449bd832023-01-11 14:50:10 +0100345 socklen_t n = (socklen_t) sizeof(client_addr);
346 socklen_t type_len = (socklen_t) sizeof(type);
Paul Bakker5121ce52009-01-03 21:22:43 +0000347#else
Gilles Peskine449bd832023-01-11 14:50:10 +0100348 int n = (int) sizeof(client_addr);
349 int type_len = (int) sizeof(type);
Paul Bakker5121ce52009-01-03 21:22:43 +0000350#endif
351
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100352 /* Is this a TCP or UDP socket? */
Gilles Peskine449bd832023-01-11 14:50:10 +0100353 if (getsockopt(bind_ctx->fd, SOL_SOCKET, SO_TYPE,
354 (void *) &type, &type_len) != 0 ||
355 (type != SOCK_STREAM && type != SOCK_DGRAM)) {
356 return MBEDTLS_ERR_NET_ACCEPT_FAILED;
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100357 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000358
Gilles Peskine449bd832023-01-11 14:50:10 +0100359 if (type == SOCK_STREAM) {
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100360 /* TCP: actual accept() */
Gilles Peskine449bd832023-01-11 14:50:10 +0100361 ret = client_ctx->fd = (int) accept(bind_ctx->fd,
362 (struct sockaddr *) &client_addr, &n);
363 } else {
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100364 /* UDP: wait for a message, but keep it in the queue */
365 char buf[1] = { 0 };
366
Gilles Peskine449bd832023-01-11 14:50:10 +0100367 ret = (int) recvfrom(bind_ctx->fd, buf, sizeof(buf), MSG_PEEK,
368 (struct sockaddr *) &client_addr, &n);
Manuel Pégourié-Gonnard16a17a42015-06-30 11:20:22 +0200369
370#if defined(_WIN32)
Gilles Peskine449bd832023-01-11 14:50:10 +0100371 if (ret == SOCKET_ERROR &&
372 WSAGetLastError() == WSAEMSGSIZE) {
Manuel Pégourié-Gonnard16a17a42015-06-30 11:20:22 +0200373 /* We know buf is too small, thanks, just peeking here */
374 ret = 0;
375 }
376#endif
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100377 }
378
Gilles Peskine449bd832023-01-11 14:50:10 +0100379 if (ret < 0) {
380 if (net_would_block(bind_ctx) != 0) {
381 return MBEDTLS_ERR_SSL_WANT_READ;
382 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000383
Gilles Peskine449bd832023-01-11 14:50:10 +0100384 return MBEDTLS_ERR_NET_ACCEPT_FAILED;
Paul Bakker5121ce52009-01-03 21:22:43 +0000385 }
386
Manuel Pégourié-Gonnardabc729e2015-07-01 01:28:24 +0200387 /* UDP: hijack the listening socket to communicate with the client,
388 * then bind a new socket to accept new connections */
Gilles Peskine449bd832023-01-11 14:50:10 +0100389 if (type != SOCK_STREAM) {
Manuel Pégourié-Gonnardabc729e2015-07-01 01:28:24 +0200390 struct sockaddr_storage local_addr;
391 int one = 1;
392
Gilles Peskine449bd832023-01-11 14:50:10 +0100393 if (connect(bind_ctx->fd, (struct sockaddr *) &client_addr, n) != 0) {
394 return MBEDTLS_ERR_NET_ACCEPT_FAILED;
395 }
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100396
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200397 client_ctx->fd = bind_ctx->fd;
Manuel Pégourié-Gonnardabc729e2015-07-01 01:28:24 +0200398 bind_ctx->fd = -1; /* In case we exit early */
399
Gilles Peskine449bd832023-01-11 14:50:10 +0100400 n = sizeof(struct sockaddr_storage);
401 if (getsockname(client_ctx->fd,
402 (struct sockaddr *) &local_addr, &n) != 0 ||
403 (bind_ctx->fd = (int) socket(local_addr.ss_family,
404 SOCK_DGRAM, IPPROTO_UDP)) < 0 ||
405 setsockopt(bind_ctx->fd, SOL_SOCKET, SO_REUSEADDR,
406 (const char *) &one, sizeof(one)) != 0) {
407 return MBEDTLS_ERR_NET_SOCKET_FAILED;
Manuel Pégourié-Gonnardabc729e2015-07-01 01:28:24 +0200408 }
409
Gilles Peskine449bd832023-01-11 14:50:10 +0100410 if (bind(bind_ctx->fd, (struct sockaddr *) &local_addr, n) != 0) {
411 return MBEDTLS_ERR_NET_BIND_FAILED;
Manuel Pégourié-Gonnardabc729e2015-07-01 01:28:24 +0200412 }
Manuel Pégourié-Gonnardf5a13122014-03-23 17:38:16 +0100413 }
414
Gilles Peskine449bd832023-01-11 14:50:10 +0100415 if (client_ip != NULL) {
416 if (client_addr.ss_family == AF_INET) {
Manuel Pégourié-Gonnard6e315a92013-12-13 16:21:25 +0100417 struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr;
Gilles Peskine449bd832023-01-11 14:50:10 +0100418 *ip_len = sizeof(addr4->sin_addr.s_addr);
Manuel Pégourié-Gonnard0b104b02015-05-14 21:52:40 +0200419
Gilles Peskine449bd832023-01-11 14:50:10 +0100420 if (buf_size < *ip_len) {
421 return MBEDTLS_ERR_NET_BUFFER_TOO_SMALL;
422 }
Manuel Pégourié-Gonnard0b104b02015-05-14 21:52:40 +0200423
Gilles Peskine449bd832023-01-11 14:50:10 +0100424 memcpy(client_ip, &addr4->sin_addr.s_addr, *ip_len);
425 } else {
Manuel Pégourié-Gonnard6e315a92013-12-13 16:21:25 +0100426 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &client_addr;
Gilles Peskine449bd832023-01-11 14:50:10 +0100427 *ip_len = sizeof(addr6->sin6_addr.s6_addr);
Manuel Pégourié-Gonnard0b104b02015-05-14 21:52:40 +0200428
Gilles Peskine449bd832023-01-11 14:50:10 +0100429 if (buf_size < *ip_len) {
430 return MBEDTLS_ERR_NET_BUFFER_TOO_SMALL;
431 }
Manuel Pégourié-Gonnard0b104b02015-05-14 21:52:40 +0200432
Gilles Peskine449bd832023-01-11 14:50:10 +0100433 memcpy(client_ip, &addr6->sin6_addr.s6_addr, *ip_len);
Manuel Pégourié-Gonnard6e315a92013-12-13 16:21:25 +0100434 }
Manuel Pégourié-Gonnard6e315a92013-12-13 16:21:25 +0100435 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000436
Gilles Peskine449bd832023-01-11 14:50:10 +0100437 return 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000438}
439
440/*
441 * Set the socket blocking or non-blocking
442 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100443int mbedtls_net_set_block(mbedtls_net_context *ctx)
Paul Bakker5121ce52009-01-03 21:22:43 +0000444{
Gilles Peskine449bd832023-01-11 14:50:10 +0100445#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100446 !defined(EFI32)
Paul Bakkerf4f69682011-04-24 16:08:12 +0000447 u_long n = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100448 return ioctlsocket(ctx->fd, FIONBIO, &n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000449#else
Gilles Peskine449bd832023-01-11 14:50:10 +0100450 return fcntl(ctx->fd, F_SETFL, fcntl(ctx->fd, F_GETFL) & ~O_NONBLOCK);
Paul Bakker5121ce52009-01-03 21:22:43 +0000451#endif
452}
453
Gilles Peskine449bd832023-01-11 14:50:10 +0100454int mbedtls_net_set_nonblock(mbedtls_net_context *ctx)
Paul Bakker5121ce52009-01-03 21:22:43 +0000455{
Gilles Peskine449bd832023-01-11 14:50:10 +0100456#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100457 !defined(EFI32)
Paul Bakkerf4f69682011-04-24 16:08:12 +0000458 u_long n = 1;
Gilles Peskine449bd832023-01-11 14:50:10 +0100459 return ioctlsocket(ctx->fd, FIONBIO, &n);
Paul Bakker5121ce52009-01-03 21:22:43 +0000460#else
Gilles Peskine449bd832023-01-11 14:50:10 +0100461 return fcntl(ctx->fd, F_SETFL, fcntl(ctx->fd, F_GETFL) | O_NONBLOCK);
Paul Bakker5121ce52009-01-03 21:22:43 +0000462#endif
463}
464
465/*
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100466 * Check if data is available on the socket
467 */
468
Gilles Peskine449bd832023-01-11 14:50:10 +0100469int mbedtls_net_poll(mbedtls_net_context *ctx, uint32_t rw, uint32_t timeout)
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100470{
Janos Follath865b3eb2019-12-16 11:46:15 +0000471 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100472 struct timeval tv;
473
474 fd_set read_fds;
475 fd_set write_fds;
476
477 int fd = ctx->fd;
478
Gilles Peskine449bd832023-01-11 14:50:10 +0100479 ret = check_fd(fd, 1);
480 if (ret != 0) {
481 return ret;
482 }
Gilles Peskineddf43742021-02-24 19:49:44 +0100483
Gilles Peskineec4733b2018-04-05 14:55:47 +0200484#if defined(__has_feature)
485#if __has_feature(memory_sanitizer)
486 /* Ensure that memory sanitizers consider read_fds and write_fds as
487 * initialized even on platforms such as Glibc/x86_64 where FD_ZERO
488 * is implemented in assembly. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100489 memset(&read_fds, 0, sizeof(read_fds));
490 memset(&write_fds, 0, sizeof(write_fds));
Gilles Peskineec4733b2018-04-05 14:55:47 +0200491#endif
492#endif
Hanno Beckerf4e5b7e2018-04-03 16:28:09 +0100493
Gilles Peskine449bd832023-01-11 14:50:10 +0100494 FD_ZERO(&read_fds);
495 if (rw & MBEDTLS_NET_POLL_READ) {
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100496 rw &= ~MBEDTLS_NET_POLL_READ;
Gilles Peskine449bd832023-01-11 14:50:10 +0100497 FD_SET(fd, &read_fds);
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100498 }
499
Gilles Peskine449bd832023-01-11 14:50:10 +0100500 FD_ZERO(&write_fds);
501 if (rw & MBEDTLS_NET_POLL_WRITE) {
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100502 rw &= ~MBEDTLS_NET_POLL_WRITE;
Gilles Peskine449bd832023-01-11 14:50:10 +0100503 FD_SET(fd, &write_fds);
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100504 }
505
Gilles Peskine449bd832023-01-11 14:50:10 +0100506 if (rw != 0) {
507 return MBEDTLS_ERR_NET_BAD_INPUT_DATA;
508 }
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100509
510 tv.tv_sec = timeout / 1000;
Gilles Peskine449bd832023-01-11 14:50:10 +0100511 tv.tv_usec = (timeout % 1000) * 1000;
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100512
Gilles Peskine449bd832023-01-11 14:50:10 +0100513 do {
514 ret = select(fd + 1, &read_fds, &write_fds, NULL,
515 timeout == (uint32_t) -1 ? NULL : &tv);
516 } while (IS_EINTR(ret));
517
518 if (ret < 0) {
519 return MBEDTLS_ERR_NET_POLL_FAILED;
Hanno Becker80e06d72018-03-15 14:41:55 +0000520 }
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100521
522 ret = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100523 if (FD_ISSET(fd, &read_fds)) {
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100524 ret |= MBEDTLS_NET_POLL_READ;
Gilles Peskine449bd832023-01-11 14:50:10 +0100525 }
526 if (FD_ISSET(fd, &write_fds)) {
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100527 ret |= MBEDTLS_NET_POLL_WRITE;
Gilles Peskine449bd832023-01-11 14:50:10 +0100528 }
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100529
Gilles Peskine449bd832023-01-11 14:50:10 +0100530 return ret;
Hanno Beckere09ca3d2017-05-22 15:06:06 +0100531}
532
533/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000534 * Portable usleep helper
535 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100536void mbedtls_net_usleep(unsigned long usec)
Paul Bakker5121ce52009-01-03 21:22:43 +0000537{
Manuel Pégourié-Gonnardacecb652015-07-01 11:29:31 +0200538#if defined(_WIN32)
Gilles Peskine449bd832023-01-11 14:50:10 +0100539 Sleep((usec + 999) / 1000);
Manuel Pégourié-Gonnardacecb652015-07-01 11:29:31 +0200540#else
Paul Bakker5121ce52009-01-03 21:22:43 +0000541 struct timeval tv;
Manuel Pégourié-Gonnarde4232462014-11-21 09:52:23 +0100542 tv.tv_sec = usec / 1000000;
Manuel Pégourié-Gonnardacecb652015-07-01 11:29:31 +0200543#if defined(__unix__) || defined(__unix) || \
Gilles Peskine449bd832023-01-11 14:50:10 +0100544 (defined(__APPLE__) && defined(__MACH__))
Manuel Pégourié-Gonnarde4232462014-11-21 09:52:23 +0100545 tv.tv_usec = (suseconds_t) usec % 1000000;
Sander Niemeijeref5087d2014-08-16 12:45:52 +0200546#else
Manuel Pégourié-Gonnarde4232462014-11-21 09:52:23 +0100547 tv.tv_usec = usec % 1000000;
Sander Niemeijeref5087d2014-08-16 12:45:52 +0200548#endif
Gilles Peskine449bd832023-01-11 14:50:10 +0100549 select(0, NULL, NULL, NULL, &tv);
Manuel Pégourié-Gonnardacecb652015-07-01 11:29:31 +0200550#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000551}
552
553/*
554 * Read at most 'len' characters
555 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100556int mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len)
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100557{
Janos Follath865b3eb2019-12-16 11:46:15 +0000558 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200559 int fd = ((mbedtls_net_context *) ctx)->fd;
Manuel Pégourié-Gonnard9bd0afd2015-07-01 19:03:27 +0200560
Gilles Peskine449bd832023-01-11 14:50:10 +0100561 ret = check_fd(fd, 0);
562 if (ret != 0) {
563 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000564 }
565
Gilles Peskine449bd832023-01-11 14:50:10 +0100566 ret = (int) read(fd, buf, len);
567
568 if (ret < 0) {
569 if (net_would_block(ctx) != 0) {
570 return MBEDTLS_ERR_SSL_WANT_READ;
571 }
572
573#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
574 !defined(EFI32)
575 if (WSAGetLastError() == WSAECONNRESET) {
576 return MBEDTLS_ERR_NET_CONN_RESET;
577 }
578#else
579 if (errno == EPIPE || errno == ECONNRESET) {
580 return MBEDTLS_ERR_NET_CONN_RESET;
581 }
582
583 if (errno == EINTR) {
584 return MBEDTLS_ERR_SSL_WANT_READ;
585 }
586#endif
587
588 return MBEDTLS_ERR_NET_RECV_FAILED;
589 }
590
591 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000592}
593
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200594/*
Manuel Pégourié-Gonnardc8d8e972014-10-01 15:01:39 +0200595 * Read at most 'len' characters, blocking for at most 'timeout' ms
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200596 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100597int mbedtls_net_recv_timeout(void *ctx, unsigned char *buf,
598 size_t len, uint32_t timeout)
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200599{
Janos Follath865b3eb2019-12-16 11:46:15 +0000600 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200601 struct timeval tv;
602 fd_set read_fds;
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200603 int fd = ((mbedtls_net_context *) ctx)->fd;
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200604
Gilles Peskine449bd832023-01-11 14:50:10 +0100605 ret = check_fd(fd, 1);
606 if (ret != 0) {
607 return ret;
608 }
Gilles Peskineddf43742021-02-24 19:49:44 +0100609
Gilles Peskine449bd832023-01-11 14:50:10 +0100610 FD_ZERO(&read_fds);
611 FD_SET(fd, &read_fds);
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200612
Manuel Pégourié-Gonnardc8d8e972014-10-01 15:01:39 +0200613 tv.tv_sec = timeout / 1000;
Gilles Peskine449bd832023-01-11 14:50:10 +0100614 tv.tv_usec = (timeout % 1000) * 1000;
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200615
Gilles Peskine449bd832023-01-11 14:50:10 +0100616 ret = select(fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv);
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200617
618 /* Zero fds ready means we timed out */
Gilles Peskine449bd832023-01-11 14:50:10 +0100619 if (ret == 0) {
620 return MBEDTLS_ERR_SSL_TIMEOUT;
621 }
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200622
Gilles Peskine449bd832023-01-11 14:50:10 +0100623 if (ret < 0) {
624#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
625 !defined(EFI32)
626 if (WSAGetLastError() == WSAEINTR) {
627 return MBEDTLS_ERR_SSL_WANT_READ;
628 }
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200629#else
Gilles Peskine449bd832023-01-11 14:50:10 +0100630 if (errno == EINTR) {
631 return MBEDTLS_ERR_SSL_WANT_READ;
632 }
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200633#endif
634
Gilles Peskine449bd832023-01-11 14:50:10 +0100635 return MBEDTLS_ERR_NET_RECV_FAILED;
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200636 }
637
638 /* This call will not block */
Gilles Peskine449bd832023-01-11 14:50:10 +0100639 return mbedtls_net_recv(ctx, buf, len);
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200640}
Manuel Pégourié-Gonnard9d9b0032014-09-18 11:22:45 +0200641
Paul Bakker5121ce52009-01-03 21:22:43 +0000642/*
643 * Write at most 'len' characters
644 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100645int mbedtls_net_send(void *ctx, const unsigned char *buf, size_t len)
Paul Bakker5121ce52009-01-03 21:22:43 +0000646{
Janos Follath865b3eb2019-12-16 11:46:15 +0000647 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200648 int fd = ((mbedtls_net_context *) ctx)->fd;
Manuel Pégourié-Gonnard9bd0afd2015-07-01 19:03:27 +0200649
Gilles Peskine449bd832023-01-11 14:50:10 +0100650 ret = check_fd(fd, 0);
651 if (ret != 0) {
652 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000653 }
654
Gilles Peskine449bd832023-01-11 14:50:10 +0100655 ret = (int) write(fd, buf, len);
656
657 if (ret < 0) {
658 if (net_would_block(ctx) != 0) {
659 return MBEDTLS_ERR_SSL_WANT_WRITE;
660 }
661
662#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \
663 !defined(EFI32)
664 if (WSAGetLastError() == WSAECONNRESET) {
665 return MBEDTLS_ERR_NET_CONN_RESET;
666 }
667#else
668 if (errno == EPIPE || errno == ECONNRESET) {
669 return MBEDTLS_ERR_NET_CONN_RESET;
670 }
671
672 if (errno == EINTR) {
673 return MBEDTLS_ERR_SSL_WANT_WRITE;
674 }
675#endif
676
677 return MBEDTLS_ERR_NET_SEND_FAILED;
678 }
679
680 return ret;
Paul Bakker5121ce52009-01-03 21:22:43 +0000681}
682
683/*
Robert Larsendf8e5112019-08-23 10:55:47 +0200684 * Close the connection
685 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100686void mbedtls_net_close(mbedtls_net_context *ctx)
Robert Larsendf8e5112019-08-23 10:55:47 +0200687{
Gilles Peskine449bd832023-01-11 14:50:10 +0100688 if (ctx->fd == -1) {
Robert Larsendf8e5112019-08-23 10:55:47 +0200689 return;
Gilles Peskine449bd832023-01-11 14:50:10 +0100690 }
Robert Larsendf8e5112019-08-23 10:55:47 +0200691
Gilles Peskine449bd832023-01-11 14:50:10 +0100692 close(ctx->fd);
Robert Larsendf8e5112019-08-23 10:55:47 +0200693
694 ctx->fd = -1;
695}
696
697/*
Paul Bakker5121ce52009-01-03 21:22:43 +0000698 * Gracefully close the connection
699 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100700void mbedtls_net_free(mbedtls_net_context *ctx)
Paul Bakker5121ce52009-01-03 21:22:43 +0000701{
Gilles Peskine449bd832023-01-11 14:50:10 +0100702 if (ctx->fd == -1) {
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200703 return;
Gilles Peskine449bd832023-01-11 14:50:10 +0100704 }
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200705
Gilles Peskine449bd832023-01-11 14:50:10 +0100706 shutdown(ctx->fd, 2);
707 close(ctx->fd);
Manuel Pégourié-Gonnard91895852015-06-30 13:34:45 +0200708
709 ctx->fd = -1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000710}
711
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200712#endif /* MBEDTLS_NET_C */