1 /* 2 * TCP/IP or UDP/IP networking functions 3 * 4 * Copyright The Mbed TLS Contributors 5 * 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. 18 */ 19 20 /* Enable definition of getaddrinfo() even when compiling with -std=c99. Must 21 * be set before mbedtls_config.h, which pulls in glibc's features.h indirectly. 22 * Harmless on other platforms. */ 23 #ifndef _POSIX_C_SOURCE 24 #define _POSIX_C_SOURCE 200112L 25 #endif 26 #ifndef _XOPEN_SOURCE 27 #define _XOPEN_SOURCE 600 /* sockaddr_storage */ 28 #endif 29 30 #include "common.h" 31 32 #if defined(MBEDTLS_NET_C) 33 34 #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ 35 !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ 36 !defined(__HAIKU__) && !defined(__midipix__) 37 #error "This module only works on Unix and Windows, see MBEDTLS_NET_C in mbedtls_config.h" 38 #endif 39 40 #include "mbedtls/platform.h" 41 42 #include "mbedtls/net_sockets.h" 43 #include "mbedtls/error.h" 44 45 #include <string.h> 46 47 #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ 48 !defined(EFI32) 49 50 #define IS_EINTR(ret) ((ret) == WSAEINTR) 51 52 #if !defined(_WIN32_WINNT) 53 /* Enables getaddrinfo() & Co */ 54 #define _WIN32_WINNT 0x0501 55 #endif 56 57 #include <ws2tcpip.h> 58 59 #include <winsock2.h> 60 #include <windows.h> 61 #if (_WIN32_WINNT < 0x0501) 62 #include <wspiapi.h> 63 #endif 64 65 #if defined(_MSC_VER) 66 #if defined(_WIN32_WCE) 67 #pragma comment( lib, "ws2.lib" ) 68 #else 69 #pragma comment( lib, "ws2_32.lib" ) 70 #endif 71 #endif /* _MSC_VER */ 72 73 #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) 75 #define close(fd) closesocket(fd) 76 77 static int wsa_init_done = 0; 78 79 #else /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ 80 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> 91 92 #define IS_EINTR(ret) ((ret) == EINTR) 93 94 #endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ 95 96 /* Some MS functions want int and MSVC warns if we pass size_t, 97 * but the standard functions use socklen_t, so cast only for MSVC */ 98 #if defined(_MSC_VER) 99 #define MSVC_INT_CAST (int) 100 #else 101 #define MSVC_INT_CAST 102 #endif 103 104 #include <stdio.h> 105 106 #if defined(MBEDTLS_HAVE_TIME) 107 #include <time.h> 108 #endif 109 110 #include <stdint.h> 111 112 /* 113 * Prepare for using the sockets interface 114 */ 115 static int net_prepare(void) 116 { 117 #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ 118 !defined(EFI32) 119 WSADATA wsaData; 120 121 if (wsa_init_done == 0) { 122 if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) { 123 return MBEDTLS_ERR_NET_SOCKET_FAILED; 124 } 125 126 wsa_init_done = 1; 127 } 128 #else 129 #if !defined(EFIX64) && !defined(EFI32) 130 signal(SIGPIPE, SIG_IGN); 131 #endif 132 #endif 133 return 0; 134 } 135 136 /* 137 * 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 */ 141 static int check_fd(int fd, int for_select) 142 { 143 if (fd < 0) { 144 return MBEDTLS_ERR_NET_INVALID_CONTEXT; 145 } 146 147 #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ 148 !defined(EFI32) 149 (void) for_select; 150 #else 151 /* 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. */ 155 if (for_select && fd >= FD_SETSIZE) { 156 return MBEDTLS_ERR_NET_POLL_FAILED; 157 } 158 #endif 159 160 return 0; 161 } 162 163 /* 164 * Initialize a context 165 */ 166 void mbedtls_net_init(mbedtls_net_context *ctx) 167 { 168 ctx->fd = -1; 169 } 170 171 /* 172 * Initiate a TCP connection with host:port and the given protocol 173 */ 174 int mbedtls_net_connect(mbedtls_net_context *ctx, const char *host, 175 const char *port, int proto) 176 { 177 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 178 struct addrinfo hints, *addr_list, *cur; 179 180 if ((ret = net_prepare()) != 0) { 181 return ret; 182 } 183 184 /* Do name resolution with both IPv6 and IPv4 */ 185 memset(&hints, 0, sizeof(hints)); 186 hints.ai_family = AF_UNSPEC; 187 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; 189 190 if (getaddrinfo(host, port, &hints, &addr_list) != 0) { 191 return MBEDTLS_ERR_NET_UNKNOWN_HOST; 192 } 193 194 /* Try the sockaddrs until a connection succeeds */ 195 ret = MBEDTLS_ERR_NET_UNKNOWN_HOST; 196 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) { 200 ret = MBEDTLS_ERR_NET_SOCKET_FAILED; 201 continue; 202 } 203 204 if (connect(ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen) == 0) { 205 ret = 0; 206 break; 207 } 208 209 close(ctx->fd); 210 ret = MBEDTLS_ERR_NET_CONNECT_FAILED; 211 } 212 213 freeaddrinfo(addr_list); 214 215 return ret; 216 } 217 218 /* 219 * Create a listening socket on bind_ip:port 220 */ 221 int mbedtls_net_bind(mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto) 222 { 223 int n, ret; 224 struct addrinfo hints, *addr_list, *cur; 225 226 if ((ret = net_prepare()) != 0) { 227 return ret; 228 } 229 230 /* Bind to IPv6 and/or IPv4, but only in the desired protocol */ 231 memset(&hints, 0, sizeof(hints)); 232 hints.ai_family = AF_UNSPEC; 233 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; 235 if (bind_ip == NULL) { 236 hints.ai_flags = AI_PASSIVE; 237 } 238 239 if (getaddrinfo(bind_ip, port, &hints, &addr_list) != 0) { 240 return MBEDTLS_ERR_NET_UNKNOWN_HOST; 241 } 242 243 /* Try the sockaddrs until a binding succeeds */ 244 ret = MBEDTLS_ERR_NET_UNKNOWN_HOST; 245 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) { 249 ret = MBEDTLS_ERR_NET_SOCKET_FAILED; 250 continue; 251 } 252 253 n = 1; 254 if (setsockopt(ctx->fd, SOL_SOCKET, SO_REUSEADDR, 255 (const char *) &n, sizeof(n)) != 0) { 256 close(ctx->fd); 257 ret = MBEDTLS_ERR_NET_SOCKET_FAILED; 258 continue; 259 } 260 261 if (bind(ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen) != 0) { 262 close(ctx->fd); 263 ret = MBEDTLS_ERR_NET_BIND_FAILED; 264 continue; 265 } 266 267 /* Listen only makes sense for TCP */ 268 if (proto == MBEDTLS_NET_PROTO_TCP) { 269 if (listen(ctx->fd, MBEDTLS_NET_LISTEN_BACKLOG) != 0) { 270 close(ctx->fd); 271 ret = MBEDTLS_ERR_NET_LISTEN_FAILED; 272 continue; 273 } 274 } 275 276 /* Bind was successful */ 277 ret = 0; 278 break; 279 } 280 281 freeaddrinfo(addr_list); 282 283 return ret; 284 285 } 286 287 #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ 288 !defined(EFI32) 289 /* 290 * Check if the requested operation would be blocking on a non-blocking socket 291 * and thus 'failed' with a negative return value. 292 */ 293 static int net_would_block(const mbedtls_net_context *ctx) 294 { 295 ((void) ctx); 296 return WSAGetLastError() == WSAEWOULDBLOCK; 297 } 298 #else 299 /* 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 */ 305 static int net_would_block(const mbedtls_net_context *ctx) 306 { 307 int err = errno; 308 309 /* 310 * Never return 'WOULD BLOCK' on a blocking socket 311 */ 312 if ((fcntl(ctx->fd, F_GETFL) & O_NONBLOCK) != O_NONBLOCK) { 313 errno = err; 314 return 0; 315 } 316 317 switch (errno = err) { 318 #if defined EAGAIN 319 case EAGAIN: 320 #endif 321 #if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN 322 case EWOULDBLOCK: 323 #endif 324 return 1; 325 } 326 return 0; 327 } 328 #endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ 329 330 /* 331 * Accept a connection from a remote client 332 */ 333 int 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) 336 { 337 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 338 int type; 339 340 struct sockaddr_storage client_addr; 341 342 #if defined(__socklen_t_defined) || defined(_SOCKLEN_T) || \ 343 defined(_SOCKLEN_T_DECLARED) || defined(__DEFINED_socklen_t) || \ 344 defined(socklen_t) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) 345 socklen_t n = (socklen_t) sizeof(client_addr); 346 socklen_t type_len = (socklen_t) sizeof(type); 347 #else 348 int n = (int) sizeof(client_addr); 349 int type_len = (int) sizeof(type); 350 #endif 351 352 /* Is this a TCP or UDP socket? */ 353 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; 357 } 358 359 if (type == SOCK_STREAM) { 360 /* TCP: actual accept() */ 361 ret = client_ctx->fd = (int) accept(bind_ctx->fd, 362 (struct sockaddr *) &client_addr, &n); 363 } else { 364 /* UDP: wait for a message, but keep it in the queue */ 365 char buf[1] = { 0 }; 366 367 ret = (int) recvfrom(bind_ctx->fd, buf, sizeof(buf), MSG_PEEK, 368 (struct sockaddr *) &client_addr, &n); 369 370 #if defined(_WIN32) 371 if (ret == SOCKET_ERROR && 372 WSAGetLastError() == WSAEMSGSIZE) { 373 /* We know buf is too small, thanks, just peeking here */ 374 ret = 0; 375 } 376 #endif 377 } 378 379 if (ret < 0) { 380 if (net_would_block(bind_ctx) != 0) { 381 return MBEDTLS_ERR_SSL_WANT_READ; 382 } 383 384 return MBEDTLS_ERR_NET_ACCEPT_FAILED; 385 } 386 387 /* UDP: hijack the listening socket to communicate with the client, 388 * then bind a new socket to accept new connections */ 389 if (type != SOCK_STREAM) { 390 struct sockaddr_storage local_addr; 391 int one = 1; 392 393 if (connect(bind_ctx->fd, (struct sockaddr *) &client_addr, n) != 0) { 394 return MBEDTLS_ERR_NET_ACCEPT_FAILED; 395 } 396 397 client_ctx->fd = bind_ctx->fd; 398 bind_ctx->fd = -1; /* In case we exit early */ 399 400 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; 408 } 409 410 if (bind(bind_ctx->fd, (struct sockaddr *) &local_addr, n) != 0) { 411 return MBEDTLS_ERR_NET_BIND_FAILED; 412 } 413 } 414 415 if (client_ip != NULL) { 416 if (client_addr.ss_family == AF_INET) { 417 struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr; 418 *ip_len = sizeof(addr4->sin_addr.s_addr); 419 420 if (buf_size < *ip_len) { 421 return MBEDTLS_ERR_NET_BUFFER_TOO_SMALL; 422 } 423 424 memcpy(client_ip, &addr4->sin_addr.s_addr, *ip_len); 425 } else { 426 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &client_addr; 427 *ip_len = sizeof(addr6->sin6_addr.s6_addr); 428 429 if (buf_size < *ip_len) { 430 return MBEDTLS_ERR_NET_BUFFER_TOO_SMALL; 431 } 432 433 memcpy(client_ip, &addr6->sin6_addr.s6_addr, *ip_len); 434 } 435 } 436 437 return 0; 438 } 439 440 /* 441 * Set the socket blocking or non-blocking 442 */ 443 int mbedtls_net_set_block(mbedtls_net_context *ctx) 444 { 445 #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ 446 !defined(EFI32) 447 u_long n = 0; 448 return ioctlsocket(ctx->fd, FIONBIO, &n); 449 #else 450 return fcntl(ctx->fd, F_SETFL, fcntl(ctx->fd, F_GETFL) & ~O_NONBLOCK); 451 #endif 452 } 453 454 int mbedtls_net_set_nonblock(mbedtls_net_context *ctx) 455 { 456 #if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ 457 !defined(EFI32) 458 u_long n = 1; 459 return ioctlsocket(ctx->fd, FIONBIO, &n); 460 #else 461 return fcntl(ctx->fd, F_SETFL, fcntl(ctx->fd, F_GETFL) | O_NONBLOCK); 462 #endif 463 } 464 465 /* 466 * Check if data is available on the socket 467 */ 468 469 int mbedtls_net_poll(mbedtls_net_context *ctx, uint32_t rw, uint32_t timeout) 470 { 471 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 472 struct timeval tv; 473 474 fd_set read_fds; 475 fd_set write_fds; 476 477 int fd = ctx->fd; 478 479 ret = check_fd(fd, 1); 480 if (ret != 0) { 481 return ret; 482 } 483 484 #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. */ 489 memset(&read_fds, 0, sizeof(read_fds)); 490 memset(&write_fds, 0, sizeof(write_fds)); 491 #endif 492 #endif 493 494 FD_ZERO(&read_fds); 495 if (rw & MBEDTLS_NET_POLL_READ) { 496 rw &= ~MBEDTLS_NET_POLL_READ; 497 FD_SET(fd, &read_fds); 498 } 499 500 FD_ZERO(&write_fds); 501 if (rw & MBEDTLS_NET_POLL_WRITE) { 502 rw &= ~MBEDTLS_NET_POLL_WRITE; 503 FD_SET(fd, &write_fds); 504 } 505 506 if (rw != 0) { 507 return MBEDTLS_ERR_NET_BAD_INPUT_DATA; 508 } 509 510 tv.tv_sec = timeout / 1000; 511 tv.tv_usec = (timeout % 1000) * 1000; 512 513 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; 520 } 521 522 ret = 0; 523 if (FD_ISSET(fd, &read_fds)) { 524 ret |= MBEDTLS_NET_POLL_READ; 525 } 526 if (FD_ISSET(fd, &write_fds)) { 527 ret |= MBEDTLS_NET_POLL_WRITE; 528 } 529 530 return ret; 531 } 532 533 /* 534 * Portable usleep helper 535 */ 536 void mbedtls_net_usleep(unsigned long usec) 537 { 538 #if defined(_WIN32) 539 Sleep((usec + 999) / 1000); 540 #else 541 struct timeval tv; 542 tv.tv_sec = usec / 1000000; 543 #if defined(__unix__) || defined(__unix) || \ 544 (defined(__APPLE__) && defined(__MACH__)) 545 tv.tv_usec = (suseconds_t) usec % 1000000; 546 #else 547 tv.tv_usec = usec % 1000000; 548 #endif 549 select(0, NULL, NULL, NULL, &tv); 550 #endif 551 } 552 553 /* 554 * Read at most 'len' characters 555 */ 556 int mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len) 557 { 558 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 559 int fd = ((mbedtls_net_context *) ctx)->fd; 560 561 ret = check_fd(fd, 0); 562 if (ret != 0) { 563 return ret; 564 } 565 566 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; 592 } 593 594 /* 595 * Read at most 'len' characters, blocking for at most 'timeout' ms 596 */ 597 int mbedtls_net_recv_timeout(void *ctx, unsigned char *buf, 598 size_t len, uint32_t timeout) 599 { 600 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 601 struct timeval tv; 602 fd_set read_fds; 603 int fd = ((mbedtls_net_context *) ctx)->fd; 604 605 ret = check_fd(fd, 1); 606 if (ret != 0) { 607 return ret; 608 } 609 610 FD_ZERO(&read_fds); 611 FD_SET(fd, &read_fds); 612 613 tv.tv_sec = timeout / 1000; 614 tv.tv_usec = (timeout % 1000) * 1000; 615 616 ret = select(fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv); 617 618 /* Zero fds ready means we timed out */ 619 if (ret == 0) { 620 return MBEDTLS_ERR_SSL_TIMEOUT; 621 } 622 623 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 } 629 #else 630 if (errno == EINTR) { 631 return MBEDTLS_ERR_SSL_WANT_READ; 632 } 633 #endif 634 635 return MBEDTLS_ERR_NET_RECV_FAILED; 636 } 637 638 /* This call will not block */ 639 return mbedtls_net_recv(ctx, buf, len); 640 } 641 642 /* 643 * Write at most 'len' characters 644 */ 645 int mbedtls_net_send(void *ctx, const unsigned char *buf, size_t len) 646 { 647 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 648 int fd = ((mbedtls_net_context *) ctx)->fd; 649 650 ret = check_fd(fd, 0); 651 if (ret != 0) { 652 return ret; 653 } 654 655 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; 681 } 682 683 /* 684 * Close the connection 685 */ 686 void mbedtls_net_close(mbedtls_net_context *ctx) 687 { 688 if (ctx->fd == -1) { 689 return; 690 } 691 692 close(ctx->fd); 693 694 ctx->fd = -1; 695 } 696 697 /* 698 * Gracefully close the connection 699 */ 700 void mbedtls_net_free(mbedtls_net_context *ctx) 701 { 702 if (ctx->fd == -1) { 703 return; 704 } 705 706 shutdown(ctx->fd, 2); 707 close(ctx->fd); 708 709 ctx->fd = -1; 710 } 711 712 #endif /* MBEDTLS_NET_C */ 713