| // Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include <openssl/bio.h> | |
| #if !defined(OPENSSL_NO_POSIX_IO) | |
| #include <errno.h> | |
| #include <string.h> | |
| #if !defined(OPENSSL_WINDOWS) | |
| #include <unistd.h> | |
| #else | |
| #include <io.h> | |
| #include <limits.h> | |
| #include <algorithm> | |
| #endif | |
| #include <openssl/err.h> | |
| #include <openssl/mem.h> | |
| #include "internal.h" | |
| #include "../internal.h" | |
| #if defined(OPENSSL_WINDOWS) | |
| #define BORINGSSL_CLOSE _close | |
| #define BORINGSSL_LSEEK _lseek | |
| #define BORINGSSL_READ _read | |
| #else | |
| #define BORINGSSL_CLOSE close | |
| #define BORINGSSL_LSEEK lseek | |
| #define BORINGSSL_READ read | |
| #endif | |
| using namespace bssl; | |
| BIO *BIO_new_fd(int fd, int close_flag) { | |
| BIO *ret = BIO_new(BIO_s_fd()); | |
| if (ret == nullptr) { | |
| return nullptr; | |
| } | |
| BIO_set_fd(ret, fd, close_flag); | |
| return ret; | |
| } | |
| static int fd_new(BIO *bio) { | |
| // num is used to store the file descriptor. | |
| FromOpaque(bio)->num = -1; | |
| return 1; | |
| } | |
| static int fd_free(BIO *bio) { | |
| if (BIO_get_shutdown(bio)) { | |
| if (BIO_get_init(bio)) { | |
| BORINGSSL_CLOSE(FromOpaque(bio)->num); | |
| } | |
| BIO_set_init(bio, 0); | |
| } | |
| return 1; | |
| } | |
| static int fd_read(BIO *b, char *out, int outl) { | |
| int ret = (int)BORINGSSL_READ(FromOpaque(b)->num, out, outl); | |
| BIO_clear_retry_flags(b); | |
| if (ret <= 0) { | |
| if (bio_errno_should_retry(ret)) { | |
| BIO_set_retry_read(b); | |
| } | |
| } | |
| return ret; | |
| } | |
| static int fd_write_ex(BIO *b, const char *in, size_t inl, | |
| size_t *out_written) { | |
| #if defined(OPENSSL_WINDOWS) | |
| inl = std::min(inl, size_t{UINT_MAX}); | |
| int ret = _write(FromOpaque(b)->num, in, static_cast<unsigned>(inl)); | |
| #else | |
| ssize_t ret = write(FromOpaque(b)->num, in, inl); | |
| #endif | |
| BIO_clear_retry_flags(b); | |
| if (ret <= 0) { | |
| if (bio_errno_should_retry(ret)) { | |
| BIO_set_retry_write(b); | |
| } | |
| return 0; | |
| } | |
| *out_written = ret; | |
| return 1; | |
| } | |
| static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) { | |
| switch (cmd) { | |
| case BIO_CTRL_RESET: | |
| num = 0; | |
| [[fallthrough]]; | |
| case BIO_C_FILE_SEEK: | |
| if (BIO_get_init(b)) { | |
| return (long)BORINGSSL_LSEEK(FromOpaque(b)->num, num, SEEK_SET); | |
| } | |
| return 0; | |
| case BIO_C_FILE_TELL: | |
| case BIO_CTRL_INFO: | |
| if (BIO_get_init(b)) { | |
| return (long)BORINGSSL_LSEEK(FromOpaque(b)->num, 0, SEEK_CUR); | |
| } | |
| return 0; | |
| case BIO_C_SET_FD: | |
| fd_free(b); | |
| FromOpaque(b)->num = *static_cast<int *>(ptr); | |
| BIO_set_shutdown(b, static_cast<int>(num)); | |
| BIO_set_init(b, 1); | |
| return 1; | |
| case BIO_C_GET_FD: | |
| if (BIO_get_init(b)) { | |
| int *out = static_cast<int *>(ptr); | |
| if (out != nullptr) { | |
| *out = FromOpaque(b)->num; | |
| } | |
| return FromOpaque(b)->num; | |
| } else { | |
| return -1; | |
| } | |
| case BIO_CTRL_GET_CLOSE: | |
| return BIO_get_shutdown(b); | |
| case BIO_CTRL_SET_CLOSE: | |
| BIO_set_shutdown(b, static_cast<int>(num)); | |
| return 1; | |
| case BIO_CTRL_FLUSH: | |
| return 1; | |
| default: | |
| return 0; | |
| } | |
| } | |
| static int fd_gets(BIO *bp, char *buf, int size) { | |
| if (size <= 0) { | |
| return 0; | |
| } | |
| char *ptr = buf; | |
| char *end = buf + size - 1; | |
| while (ptr < end && fd_read(bp, ptr, 1) > 0) { | |
| char c = ptr[0]; | |
| ptr++; | |
| if (c == '\n') { | |
| break; | |
| } | |
| } | |
| ptr[0] = '\0'; | |
| // The output length is bounded by `size`. | |
| return (int)(ptr - buf); | |
| } | |
| static const BIO_METHOD methods_fdp = { | |
| BIO_TYPE_FD, | |
| /*bwrite=*/nullptr, | |
| fd_write_ex, | |
| fd_read, | |
| fd_gets, | |
| fd_ctrl, | |
| fd_new, | |
| fd_free, | |
| /*callback_ctrl=*/nullptr, | |
| }; | |
| const BIO_METHOD *BIO_s_fd() { return &methods_fdp; } | |
| #endif // OPENSSL_NO_POSIX_IO | |
| int BIO_set_fd(BIO *bio, int fd, int close_flag) { | |
| return (int)BIO_int_ctrl(bio, BIO_C_SET_FD, close_flag, fd); | |
| } | |
| int BIO_get_fd(BIO *bio, int *out_fd) { | |
| return (int)BIO_ctrl(bio, BIO_C_GET_FD, 0, (char *) out_fd); | |
| } |