BIO_ACCEPT(3)
π BIO_ACCEPT(3) β wrappers for socket operations π
okay so bestie, this is a page from the Library Functions Manual for libcrypto (yeah, the OpenSSL-ish crypto library), and it's literally just a little pile of socket-helper functions. nothing scary. come sit with me π«Ά
β¨ NAME β¨
BIO_get_host_ip, BIO_get_port, BIO_get_accept_socket, BIO_accept, BIO_sock_error, BIO_sock_non_fatal_error, BIO_sock_should_retry, BIO_socket_nbio, BIO_set_tcp_ndelay β these are the wrappers for socket operations. yes, all nine of them, they're a package deal π
π SYNOPSIS π
this is the library βlibcryptoβ situation, and you get it via #include <openssl/bio.h>:
int
BIO_get_host_ip(const char *hostname, unsigned char *in_addr_buffer);
int
BIO_get_port(const char *servname, unsigned short *port);
int
BIO_get_accept_socket(char *host_port, int bind_mode);
int
BIO_accept(int socket, char **addr);
int
BIO_sock_error(int socket);
int
BIO_sock_non_fatal_error(int errnum);
int
BIO_sock_should_retry(int retval);
int
BIO_socket_nbio(int socket, int mode);
int
BIO_set_tcp_ndelay(int socket, int on);
like, copy-paste this verbatim, don't be cute with it π
πΈ DESCRIPTION πΈ
π¦ the lookup girlies
BIO_get_host_ip() looks up one IPv4 address for the given hostname using getaddrinfo(3), then writes the first returned IPv4 address into *in_addr_buffer. and like β the caller is responsible for handing over a buffer that's at least sizeof(in_addr_t) bytes long. no, she won't check for you, she trusts you. after a successful call you gotta cast in_addr_buffer to (in_addr_t *). yes, really. periodt.
BIO_get_port() looks up servname in the services(5) database using getaddrinfo(3) and stores the associated port number at the location specified by the port argument. slay.
π§ the socket-making girlies
BIO_get_accept_socket() creates an IPv4 TCP socket and listen(2)s for incoming connections. iconic behaviour. the string host_port gets parsed:
- if it contains a colon, the substring before the colon is interpreted as a local hostname of the interface to
bind(2)to. - if the hostname is empty, consists of a single asterisk (
"*:..."), or if there is no colon,INADDR_ANYis used instead of a local hostname. - the rest of the string host_port, or the whole string if it contains no colon, is treated as a service name.
- the hostname and the service name are converted to a local IP address and port number using
getaddrinfo(3).
and if bind_mode is the constant BIO_BIND_REUSEADDR, allowing local address reuse is attempted using setsockopt(2) with an argument of SO_REUSEADDR before calling bind(2). considerate queen π
BIO_accept() calls accept(2) to receive one connection on the socket. when it receives a connection, it free(3)s *addr, and if it's an IPv4 connection, it allocates a new string, writes the peer IP address in dotted decimal form, a colon, and the decimal port number into the string, and stores a pointer to the string in *addr. and for other address families, or if getnameinfo(3) or memory allocation fails, *addr is set to NULL but BIO_accept() succeeds anyway. she's flexible like that.
β the error-inspection girlies
BIO_sock_error() retrieves, clears, and returns the error status code of the socket by calling getsockopt(2) with arguments SOL_SOCKET and SO_ERROR. three jobs, one function.
BIO_sock_non_fatal_error() determines whether the error status code errnum represents a recoverable error.
BIO_sock_should_retry() determines whether a recoverable error occurred by inspecting both errno(2) and retval, which is supposed to usually be the return value of a previously called function like BIO_accept(), BIO_read(3), or BIO_write(3). iykyk.
π₯ the mode-setting girlies
BIO_socket_nbio() β if mode is non-zero, it switches the socket to non-blocking mode using fcntl(2). if mode is 0, it switches to blocking mode. binary queen.
BIO_set_tcp_ndelay() sets the TCP_NODELAY option on the socket if on is 1 or clears it if on is 0; see tcp(4) for details. no in-between, bestie. π
π RETURN VALUES π
BIO_get_host_ip(), BIO_get_port(), and BIO_socket_nbio() return 1 on success or 0 on failure. that's it. simple.
BIO_get_accept_socket() returns the file descriptor of the newly created listening socket, or -1 if:
- host_port is
NULL - no service is specified
getaddrinfo(3),socket(2),bind(2),listen(2), or memory allocation fails
BIO_accept() returns the file descriptor of the received connection, or:
-1on fatal errors β that is, when addr isNULLoraccept(2)fails fatally-2whenaccept(2)fails in a non-fatal way and might succeed when retried later
lowkey the-1vs-2distinction matters, don't sleep on it π«Ά
BIO_sock_error() returns an error status code like EAGAIN, ECONNABORTED, ECONNREFUSED, ECONNRESET, ELOOP, EMSGSIZE, ENOBUFS, ENOTCONN, EPIPE, ETIMEDOUT, or others, β or 0 if the socket is not in an error state, or 1 if getsockopt(2) fails. the way there are like three different kinds of return value here π
BIO_sock_non_fatal_error() returns 1 if errnum is EAGAIN, EALREADY, EINPROGRESS, EINTR, or ENOTCONN and 0 otherwise β even if errnum is 0. like, yes, even then. don't @ me.
BIO_sock_should_retry() returns 1 if BIO_sock_non_fatal_error(errno) is 1 and retval is either 0 or -1, or 0 otherwise.
BIO_set_tcp_ndelay() returns 0 on success or -1 on failure.
π ERRORS π
if BIO_get_host_ip(), BIO_get_port(), or BIO_get_accept_socket() fail, or BIO_accept() fails fatally, the following diagnostics can be retrieved with ERR_get_error(3), ERR_GET_REASON(3), and ERR_reason_error_string(3):
BIO_R_ACCEPT_ERROR"accept error"βaccept(2)failed fatally inBIO_accept().BIO_R_BAD_HOSTNAME_LOOKUP"bad hostname lookup"βgetaddrinfo(3)failed or hostname wasNULLinBIO_get_host_ip(), orgetaddrinfo(3)failed inBIO_get_accept_socket().BIO_R_INVALID_ARGUMENT"invalid argument"βgetaddrinfo(3)failed inBIO_get_port().ERR_R_MALLOC_FAILURE"malloc failure"β memory allocation failed inBIO_get_accept_socket(), orBIO_accept()succeeded but was unable to allocate memory for*addr. forBIO_accept(), the returned file descriptor is valid, and communication with the peer can be attempted using it. so like, it's fine? kind of? π«ΆBIO_R_NO_PORT_SPECIFIED"no port specified"β the servname argument wasNULLinBIO_get_port(), or host_port wasNULLor ended after the first colon inBIO_get_accept_socket().BIO_R_NULL_PARAMETER"null parameter"β the addr argument wasNULLinBIO_accept().BIO_R_UNABLE_TO_BIND_SOCKET"unable to bind socket"βbind(2)failed inBIO_get_accept_socket().BIO_R_UNABLE_TO_CREATE_SOCKET"unable to create socket"βsocket(2)failed inBIO_get_accept_socket().BIO_R_UNABLE_TO_LISTEN_SOCKET"unable to listen socket"βlisten(2)failed inBIO_get_accept_socket().
π SEE ALSO π
bind(2), connect(2), errno(2), fcntl(2), getsockopt(2), listen(2), sigaction(2), socket(2), BIO_new(3), BIO_read(3), getaddrinfo(3), ip(4), tcp(4)
go read them, they're all icons in their own right π
π HISTORY π
BIO_sock_should_retry() first appeared in SSLeay 0.6.5, and the other functions except BIO_socket_nbio() in SSLeay 0.8.0. they've all been available since OpenBSD 2.4. legacy behaviour, honestly.
BIO_socket_nbio() first appeared in SSLeay 0.9.1 and has been available since OpenBSD 2.6. she's the baby of the group π
and that's the whole page bestie, no cap. this one came out of Debian and it's dated September 10, 2026 β so like, future-dated and fabulous. go forth and accept(2) responsibly πβ¨π¦
π¦ where this page comes from
- arch rolling: libressl 4.4.0-1 Β· ISC AND custom:OpenSSL
- Copyright (c) 2022 Ingo Schwarze <schwarze@openbsd.org>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms