BIO_READ(3SSL)

πŸ’– BIO_READ β€” the OpenSSL I/O page, bestie edition πŸ’–

okay so this is BIO_read(3SSL) from the OpenSSL manual, and it's literally the page about talking to BIOs β€” reading from them, writing to them, getting lines out of them. It's giving "the group chat of every I/O operation you'll ever do". Sit down, hydrate, and let's get into it 🫢


✨ NAME ✨

BIO_read_ex, BIO_write_ex, BIO_read, BIO_write, BIO_gets, BIO_get_line, BIO_puts β€” the BIO I/O functions. That's the whole squad. πŸ‘‘


🌸 SYNOPSIS 🌸

#include <openssl/bio.h>

int BIO_read_ex(BIO *b, void *data, size_t dlen, size_t *readbytes);
int BIO_write_ex(BIO *b, const void *data, size_t dlen, size_t *written);

int BIO_read(BIO *b, void *data, int dlen);
int BIO_gets(BIO *b, char *buf, int size);
int BIO_get_line(BIO *b, char *buf, int size);
int BIO_write(BIO *b, const void *data, int dlen);
int BIO_puts(BIO *b, const char *buf);

πŸ’… DESCRIPTION πŸ’…

Okay so, function by function, no skipping, we do not skip here:

  • BIO_read_ex() β€” tries to read dlen bytes out of BIO b and drops the data into data. If any bytes were successfully read, the number of bytes read gets stored in *readbytes. Iconic. ✨
  • BIO_write_ex() β€” tries to write dlen bytes coming from data into BIO b. If it succeeds, the number of bytes written gets stored in *written… unless written is NULL, in which case, no notes, it just doesn't. πŸ™ˆ
  • BIO_read() β€” tries to read len bytes from BIO b and places the data in buf. (Yes, the synopsis says dlen and this description says len β€” I don't make the rules, I just report them faithfully. πŸ’€)
  • BIO_gets() β€” does the BIO's "gets" operation and puts the data in buf. Usually it'll try to read one line of data from the BIO with a maximum length of size-1. BUT β€” plot twist β€” there are exceptions. For example, BIO_gets() on a digest BIO will calculate and return the digest, and other BIOs may not support BIO_gets() at all, periodt. The returned string is always NUL-terminated, and the '\n' is preserved if it was present in the input data. On binary input there may be NUL characters inside the string, and in that case the return value (if it's nonnegative) might give you an incorrect length. yes really. 😭
  • BIO_get_line() β€” tries to read from BIO b a line of data up to the next '\n', or until the maximum length size-1 is reached, then places the data in buf. The returned string is always NUL-terminated, and the '\n' is preserved if it was present in the input data. On binary input there may be NUL characters inside the string β€” and in this case the return value (if nonnegative) gives the actual length read. To implement this, unfortunately the data needs to be read byte-by-byte. sobbing, but it's fine, it's fine. 🧚
  • BIO_write() β€” tries to write len bytes from buf to BIO b.
  • BIO_puts() β€” tries to write a NUL-terminated string buf to BIO b, without the terminating NUL byte and without appending '\n'. So it's similar to fputs(3) and not puts(3). remember that, you'll thank yourself later πŸ’œ

πŸ”₯ RETURN VALUES πŸ”₯

  • BIO_read_ex() β€” returns 1 if data was successfully read, and 0 otherwise.
  • BIO_write_ex() β€” returns 1 if no error was encountered writing data, 0 otherwise. Requesting to write 0 bytes is not considered an error. zero is valid bestie!! πŸ’–
  • BIO_read() β€” returns the number of bytes read on success. A return value of 0 means end-of-file was reached, or that a read of zero bytes was requested. A negative return value means an error condition. πŸ’€
  • BIO_write() β€” returns -2 if the "write" operation isn't implemented by the BIO, or -1 on other errors. Otherwise it returns the number of bytes written. That may be 0 if the BIO b is NULL or dlen <= 0.
  • BIO_gets() β€” returns -2 if the "gets" operation isn't implemented by the BIO, or -1 on other errors. Otherwise it typically returns the amount of data read, but depending on the implementation it may return only the length up to the first NUL character contained in the data read. In any case, the trailing NUL that gets added after the data read is not included in the length returned. sneaky little NUL πŸŽ€
  • All the other functions β€” return either the amount of data successfully read or written (if the return value is positive), or that no data was successfully read or written if the result is 0 or -1. And if the return value is -2, the operation is not implemented in that specific BIO type.

🌈 NOTES 🌈

A 0 or -1 return is not necessarily an indication of an error. Especially when the source/sink is nonblocking or of a certain type, it may just mean "no data is currently available, try again later." vibe check, not a break-up text πŸ’”

One technique sometimes used with blocking sockets is to use a system call (like select(), poll() or an equivalent) to figure out when data is available, and then call read() to read it. The equivalent with BIOs β€” i.e. calling select() on the underlying I/O structure and then calling BIO_read() to read the data β€” should not be used, because a single call to BIO_read() can cause several reads (and writes, in the case of SSL BIOs) on the underlying I/O structure and may block as a result. Instead, select() (or equivalent) should be combined with non-blocking I/O so successive reads request a retry instead of blocking. not me telling you not to do the thing you were about to do 😭

Go read BIO_should_retry(3) for the details on how to determine the cause of a retry and other I/O issues. genuine required reading, iykyk πŸ“š

If the "gets" method isn't supported by a BIO, then BIO_get_line() can be used. It's also possible to make BIO_gets() usable even if the "gets" method isn't supported, by adding a buffering BIO BIO_f_buffer(3) to the chain. workaround slay ✨


πŸ¦‹ SEE ALSO πŸ¦‹


⭐ HISTORY ⭐

  • BIO_gets() on 1.1.0 and older, when called on a BIO_fd() based BIO, did not keep the '\n' at the end of the line in the buffer. ancient lore πŸ—Ώ
  • BIO_get_line() was added in OpenSSL 3.0.
  • BIO_write_ex() returns 1 if the size of the data to write is 0, and the written parameter of the function can be NULL, since OpenSSL 3.0.

Copyright 2000-2026 The OpenSSL Project Authors. All Rights Reserved.

Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy in the file LICENSE in the source distribution or at <https://www.openssl.org/source/license.html>.


okay that's the whole page, you made it, I'm so proud πŸ₯Ή this was 4.0.3, dated 2026-09-29, from the OpenSSL manual β€” and it's called BIO_READ(3SSL). go forth and BIO responsibly πŸ’–πŸŒΈπŸ’…

πŸ“¦ where this page comes from