BIO_S_DATAGRAM(3)
π¦ BIO_S_DATAGRAM(3)
okay bestie sit down because we're talking about the datagram socket BIO today, straight out of the Library Functions Manual, and honestly? she's a whole vibe. there's a lot here but it's all gonna make sense, i promise π«Ά
β¨ NAME β¨
BIO_s_datagram, BIO_new_dgram, BIO_dgram_set_peer, BIO_ctrl_dgram_connect, BIO_dgram_get_peer, BIO_ctrl_set_connected, BIO_dgram_recv_timedout, BIO_dgram_send_timedout, BIO_dgram_non_fatal_error β literally all of these are the datagram socket BIO π
π SYNOPSIS π
#include <openssl/bio.h>
const BIO_METHOD *
BIO_s_datagram(void);
BIO *
BIO_new_dgram(int fd, int close_flag);
int
BIO_dgram_set_peer(BIO *b, struct sockaddr *sa);
int
BIO_ctrl_dgram_connect(BIO *b, struct sockaddr *sa);
int
BIO_dgram_get_peer(BIO *b, struct sockaddr *sa);
int
BIO_ctrl_set_connected(BIO *b, long argl, struct sockaddr *sa);
int
BIO_dgram_recv_timedout(BIO *b);
int
BIO_dgram_send_timedout(BIO *b);
int
BIO_dgram_non_fatal_error(int errnum);
πΈ DESCRIPTION πΈ
so BIO_s_datagram() hands you back the datagram socket BIO method. the classic use case, the main character application if you will, is transmitting data using the IPv4 or IPv6 udp(4) protocol π₯
and when you call it on a datagram socket BIO object: BIO_method_type(3) returns the constant BIO_TYPE_DGRAM, and BIO_method_name(3) returns a pointer to the static string "datagram socket". cute, right? π
π§ Constructors and destructors
BIO_new(3) allocates a brand new datagram socket BIO object and initializes all its data to zero β and when we say all, we mean the datagram socket file descriptor, the peer address, the init flag that you can retrieve with BIO_get_init(3), the connected flag, the MTU, and every last bit of timeout and error information. the reference count and the close flag are set to 1. periodt β¨
BIO_new_dgram() allocates and initializes a new datagram socket BIO object with BIO_new(3), then sets the datagram socket file descriptor and the close flag according to its arguments, and sets the init flag to 1.
if the reference count hits 0 in BIO_free(3) and the close and init flags are set, then shutdown(2) and close(2) get called on the datagram socket file descriptor before the storage used by the BIO object is freed. she cleans up after herself π
when a chain containing a datagram socket BIO gets copied with BIO_dup_chain(3), these get automatically copied from the original BIO object to the new one:
- the datagram socket file descriptor
- the init flag
- the close flag
- the flags accessible with
BIO_test_flags(3) - any data that was set with
BIO_set_ex_data(3)
but these are not copied β they're initialized to zero instead, no cap:
- the peer address
- the connected flag
- the MTU
- all timeout and error information
π¦ Initialization and configuration
if the close flag is set in b, BIO_set_fd(3) clears all flags that are set in b, and if the init flag was set, it calls shutdown(2) and close(2) on the previously assigned file descriptor. in any case, BIO_set_fd(3) then sets the new file descriptor and the new close flag according to its arguments and sets the init flag to 1.
if the init flag is set in b, BIO_get_fd(3) returns its datagram socket file descriptor, and unless the c argument is a NULL pointer, it also stores the file descriptor in *c. if the init flag is not set, BIO_get_fd(3) fails and returns -1 π
BIO_set_close(3) sets the close flag in b to the flag argument. BIO_get_close(3) returns the value of the close flag from b.
for datagram socket BIO objects, the shutdown flag is literally the same flag as the close flag. so consequently: BIO_set_shutdown(3) has the same effect as BIO_set_close(3), and BIO_get_shutdown(3) has the same effect as BIO_get_close(3). they're twins, iykyk π«Ά
BIO_dgram_set_peer() copies sa as the peer address into b.
BIO_ctrl_dgram_connect() does exactly the same as BIO_dgram_set_peer(). bestie, its name is even more misleading than the name of BIO_ctrl_set_connected() π and on top of what's said there, BIO_ctrl_dgram_connect() doesn't even set the connected flag in b. iconic behavior honestly.
BIO_dgram_get_peer() copies the peer address from b to *sa. before calling this function, the caller has to make sure the peer address is actually set in b, and that there's sufficient memory available starting at sa to copy a complete struct sockaddr, struct sockaddr_in, or struct sockaddr_in6 to that place β depending on which address family b is currently used for. so like, know what you're doing π
unless sa is NULL, BIO_ctrl_set_connected() sets the connected flag in b and copies sa as the peer address into b. if sa is NULL, BIO_ctrl_set_connected() clears the connected flag and the peer address in b. and considering that communication using a datagram protocol is connectionless, the name of this function is misleading β it is neither establishing or terminating a connection nor changing anything with respect to the state of the datagram socket, it's merely modifying some purely informational data in the wrapping BIO object. the additional argl argument gets passed through to the callbacks documented in BIO_set_callback(3) if any such callbacks are installed, but otherwise it's just ignored, lowkey a vibe π
BIO_ctrl(3) with a cmd of BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT interprets the parg argument as a pointer to a struct timeval and sets the read timeout to the specified absolute UTC time β°
BIO_ctrl(3) with a cmd of BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, BIO_CTRL_DGRAM_GET_RECV_TIMEOUT, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, or BIO_CTRL_DGRAM_GET_SEND_TIMEOUT interprets the parg argument as a pointer to a struct timeval and calls setsockopt(2) or getsockopt(2) on the datagram socket file descriptor of b with an argument of SO_RCVTIMEO or SO_SNDTIMEO, respectively. here's the receipts:
BIO_CTRL_DGRAM_SET_RECV_TIMEOUTandBIO_CTRL_DGRAM_SET_SEND_TIMEOUTreturn1on successBIO_CTRL_DGRAM_GET_RECV_TIMEOUTandBIO_CTRL_DGRAM_GET_SEND_TIMEOUTreturn the number of bytes written to*parg- all four return
-1on failure
and remember, BIO_read(3) may actually use a shorter timeout when BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT is in effect π
BIO_ctrl(3) with a cmd of BIO_CTRL_DGRAM_GET_FALLBACK_MTU returns 1232 if the peer address is an IPv6 address that is not IPv4 mapped, or 548 otherwise. making sure that a peer address is set before issuing this command is the responsibility of the caller, so like, that's on you bestie π
BIO_ctrl(3) with a cmd of BIO_CTRL_DGRAM_SET_MTU sets the MTU attribute of b to the value of the larg argument and also returns that argument. BIO_ctrl(3) with a cmd of BIO_CTRL_DGRAM_GET_MTU returns the MTU attribute of b or 0 if it was not set.
BIO_ctrl(3) with a cmd of BIO_CTRL_DGRAM_MTU_EXCEEDED returns 1 if the most recent non-fatal failure of BIO_read(3) or BIO_write(3) was caused by EMSGSIZE, or 0 otherwise. this command also clears the errno(2) value that was saved internally for this particular purpose, so issuing the same command again will return 0 until the next EMSGSIZE failure occurs. it's giving one-time-use π
BIO_dgram_recv_timedout() and BIO_dgram_send_timedout() check whether the most recent non-fatal failure of BIO_read(3) or BIO_write(3) was caused by EAGAIN. and despite having different names, both functions do exactly the same thing, and both inspect the most recent non-fatal I/O failure β no matter whether it occurred during a receive or a send operation. both functions also clear the errno(2) value that was saved internally for this particular purpose, so calling these functions again will return 0 until the next EAGAIN failure occurs. twin icons behavior π
datagram socket BIOs do not support BIO_eof(3), BIO_get_mem_data(3), BIO_pending(3), BIO_reset(3), BIO_seek(3), BIO_tell(3), and BIO_wpending(3) β attempting any such operation results in failure and returns a value of 0. not her thing, respect it π
ββοΈ
control commands correspond to accessor functions like this:
BIO_C_GET_FDβBIO_get_fd(3)BIO_C_SET_FDβBIO_set_fd(3)BIO_CTRL_DGRAM_CONNECTβBIO_ctrl_dgram_connect()(deprecated)BIO_CTRL_DGRAM_GET_PEERβBIO_dgram_get_peer()BIO_CTRL_DGRAM_GET_RECV_TIMER_EXPβBIO_dgram_recv_timedout()BIO_CTRL_DGRAM_GET_SEND_TIMER_EXPβBIO_dgram_send_timedout()BIO_CTRL_DGRAM_SET_CONNECTEDβBIO_ctrl_set_connected()BIO_CTRL_DGRAM_SET_PEERβBIO_dgram_set_peer()BIO_CTRL_GET_CLOSEβBIO_get_close(3)BIO_CTRL_SET_CLOSEβBIO_set_close(3)
π Input and output operations
BIO_read(3) attempts to read up to len bytes into buf from the datagram socket file descriptor using recvfrom(2). if a read timeout is set, setsockopt(2) is used with an argument of SO_RCVTIMEO to temporarily shorten the timeout on the datagram socket during the recvfrom(2) call β such that it returns before the read timeout expires. sneaky but smart π
if recvfrom(2) succeeds and the connected flag is not yet set, BIO_read(3) also copies the peer address received from recvfrom(2) into b.
if recvfrom(2) is attempted, BIO_read(3) clears the flags BIO_FLAGS_WRITE and BIO_FLAGS_IO_SPECIAL in b and clears or sets the flags BIO_FLAGS_READ and BIO_FLAGS_SHOULD_RETRY as appropriate.
if the connected flag is set in b, BIO_write(3) attempts to write(2) len bytes from buf to the datagram socket file descriptor. if the connected flag is not set, it attempts to transmit len bytes from buf to the peer using sendto(2).
if write(2) or sendto(2) is attempted, BIO_write(3) clears the flags BIO_FLAGS_READ and BIO_FLAGS_IO_SPECIAL in b and clears or sets the flags BIO_FLAGS_WRITE and BIO_FLAGS_SHOULD_RETRY as appropriate.
the effect of BIO_puts(3) is similar to the effect of BIO_write(3) with a len argument of strlen(string).
datagram socket BIOs do not support BIO_gets(3). calling this function fails and returns -2. she said no π
BIO_flush(3) has no effect on a datagram socket BIO. it always succeeds and returns 1 β unbothered, moisturized, in her lane πΈ
π RETURN VALUES π
okay so here's what everything actually gives you back:
BIO_s_datagram()returns the datagram socket BIO method.BIO_new_dgram()returns a newly allocated datagram socket BIO object orNULLon failure.BIO_dgram_set_peer(),BIO_ctrl_dgram_connect(), andBIO_ctrl_set_connected()return1on success or a value less than or equal to zero on failure. they can only fail ifbis not a datagram socket BIO object.BIO_dgram_get_peer()returns the number of bytes copied tosaor a value less than or equal to zero on failure. it can only fail ifbis not a datagram socket BIO object.BIO_dgram_recv_timedout()andBIO_dgram_send_timedout()return1if the most recent non-fatal I/O error was caused byEAGAINor0otherwise.BIO_dgram_non_fatal_error()returns1if errnum isEAGAIN,EALREADY,EINPROGRESS, orEINTR, or0otherwise β even if errnum is0. yes, even then. that's the rule β¨
π SEE ALSO π
close(2), getsockopt(2), recvfrom(2), sendto(2), shutdown(2), BIO_ctrl(3), BIO_get_init(3), BIO_new(3), BIO_read(3), BIO_s_connect(3), BIO_set_fd(3), BIO_should_retry(3), udp(4)
π HISTORY π
BIO_s_datagram(), BIO_new_dgram(), BIO_dgram_set_peer(), BIO_ctrl_dgram_connect(), BIO_ctrl_set_connected(), BIO_dgram_recv_timedout(), BIO_dgram_send_timedout(), and BIO_dgram_non_fatal_error() first appeared in OpenSSL 0.9.8 and have been available since OpenBSD 4.5. vintage, honestly π
BIO_dgram_get_peer() first appeared in OpenSSL 0.9.8m and has been available since OpenBSD 4.9. fashionably late but she made it π¦
π BUGS (okay so there are a couple of messy things, bestie)
- Fr fr, if
getsockopt(2)orsetsockopt(2)fails whileBIO_read(3)is doing its thing, the library will print an error message to standard error output β and then justβ¦ ignore the whole problem? π Like it literally moves on. Which means it may end up using unintended timeout values. No cap, that's the actual behaviour. Not iconic of it, lowkey devastating. π - And listen, the
errno(2)situation is giving main character energy:BIO_read(3)andBIO_write(3)may clear the global variableerrno(2)before they attempt therecvfrom(2)orsendto(2)system call β but they may not clear it if they fail before reaching that point. So yeah, don't go trustingerrnounconditionally after a fail, bestie. π«Ά
β¨ Important vibe check: these are real, documented quirks, not me being dramatic. Treat errno after a failed call with the same suspicion you'd treat a "we need to talk" text. π
That's the whole page, bestie! π You made it to the end β proud of you fr fr πΈ This one comes from Debian, dated April 28, 2023, and the page itself is BIO_S_DATAGRAM(3) π Go forth and slay your datagram sockets responsibly π
β¨π
π¦ where this page comes from
- opensuse-leap 16.0: libressl-devel-doc 4.1.0-bp160.1.1 Β· 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