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