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