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