defnet(ns):'''`net_ring`, with an `sqe` of the ring.'''net_ring(ns) ns['sqe'] =io_uring_get_sqe(ns['ring'])
Example #2
# receive: the kernel fills `name`, the `iov` buffers and `control`>>> name, buf, control =Sockaddr(),bytearray(1024),bytearray(64)>>> msg =Msghdr(name, [buf], control)>>>io_uring_prep_recvmsg(sqe, sockfd, msg)True
Example #3
# multishot receive with provided buffers: only the lengths are given>>> msg =Msghdr(namelen=16,controllen=0)>>>io_uring_prep_recvmsg_multishot(sqe, sockfd, msg)True
Note
A request holds msg (and so what it was made from) until its completion: io_uring reads it when submitting and writes namelen, controllen and flags back when done.
iov is a list of buffers (bytes, bytearray, memoryview, ...); io_uring_prep_recvmsg* needs them and control writable (TypeError).
name, iov and control are kept alive and locked (no resize) by the Msghdr; namelen / controllen start as the size of the Sockaddr / control given and can be set (e.g. for a multishot receive, where the kernel puts both, with the data, into a provided buffer).
The msg_flags: set by the kernel at a receive's completion (MSG_TRUNC: the data did not fit the iov buffers, MSG_CTRUNC: the ancillary data did not fit control, MSG_EOR, MSG_OOB). A send's flags are the prep's flags argument, not this field.
# `out = io_uring_recvmsg_validate(buf, msg)` of a message that came with one `SCM_RIGHTS` fd>>> cmsg =io_uring_recvmsg_cmsg_firsthdr(out, msg)>>>while cmsg:... cmsg.level, cmsg.type, cmsg.data... cmsg =io_uring_recvmsg_cmsg_nexthdr(out, msg, cmsg)...(1, 1, b'\x07\x00\x00\x00')
Setup used to run this example
defreceived_fd(ns):'''`out` and `msg` of a received message with one `SCM_RIGHTS` control message (fd `7`), as the kernel lays it out in a provided buffer: `[header][name][control][payload]`.''' name =bytes(16) cmsg = struct.pack('=QII', struct.calcsize('=QII') +4, socket.SOL_SOCKET, socket.SCM_RIGHTS) cmsg += struct.pack('=i',7) +bytes(4) header = struct.pack('=IIII',len(name),len(cmsg),3,0) ns['msg'] = msg =Msghdr(namelen=len(name),controllen=len(cmsg)) ns['out'] =io_uring_recvmsg_validate(bytearray(header + name + cmsg +b'abc'), msg)
The length of the message data, as recvmsg would return it: it can be more than fit in the buffer (flags then has MSG_TRUNC); io_uring_recvmsg_payload_length is what is really there.
defnet(ns):'''`net_ring`, with an `sqe` of the ring.'''net_ring(ns) ns['sqe'] =io_uring_get_sqe(ns['ring'])
Note
IPv6 scope_id (an index or an interface name) can be added like so "ff01::fb%123", "fe80::1%eth0"
ValueError for a missing/invalid addr or port, OverflowError for port > 65_535, NotImplementedError for any other family.
Sockaddr() is low level setup, letting you serve/connect directly using path/ip. If you need higher level features you can use getaddrinfo() this lets you connect using domain names, ...
The address as text (AF_INET / AF_INET6, NotImplementedError otherwise): IPv6 as socket.inet_ntop writes it, with %scope_id when it has one (as Sockaddr(AF_INET6, ...) reads it).
Checks that buf holds a message received by io_uring_prep_recvmsg_multishot (ValueError if it is too short for the namelen and controllen of msgh) and gives its parts.
Type
return
RecvmsgOut
Note
The result's namelen, controllen, payloadlen and flags are what recvmsg would have reported for the message; msgh is the Msghdr the request was submitted with.
Needs Linux 6.19+ (SOCKET_URING_OP_GETSOCKNAME). cqe.res is the real size of the address (more than a Sockaddr holds: truncated); sockaddr.family, .ip, .port / .path then read it.