Skip to content

Commit 85ba7ed

Browse files
committed
socket: created setsockopt & getsockopt. Reworked
`io_uring_prep_cmd_sock`
1 parent d0acf56 commit 85ba7ed

9 files changed

Lines changed: 294 additions & 116 deletions

File tree

build.zig.zon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.{
22
.name = .liburing,
3-
.version = "2026.3.8",
3+
.version = "2026.3.10",
44
.fingerprint = 0x26de882ff0030dfe,
55
.dependencies = .{
66
.PyOZ = .{

lib/liburing

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ build-backend = "pyoz.backend"
66
name = "liburing"
77
readme = "README.md"
88
license = "CC0-1.0"
9-
version = "2026.3.8"
9+
version = "2026.3.10"
1010
authors = [{name="Ritesh"}]
1111
keywords = ["python", "socket", "async", "cython", "file", "python3", "io", "syscall", "futex", "statx",
1212
"io-uring", "uring", "liburing"]

src/liburing/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
from .version import * # noqa
33

44

5-
__version__ = "2026.3.8"
5+
__version__ = "2026.3.10"

src/liburing/enum.zig

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,14 @@ pub const io_uring_op = enum(u8) {
6767
IORING_OP_PIPE,
6868
IORING_OP_NOP128,
6969
IORING_OP_URING_CMD128,
70-
71-
// /* this goes last, obviously */
7270
IORING_OP_LAST,
7371
};
7472

7573
pub const io_uring_socket_op = enum(u8) {
76-
SOCKET_URING_OP_SIOCINQ,
77-
SOCKET_URING_OP_SIOCOUTQ,
78-
SOCKET_URING_OP_GETSOCKOPT,
79-
SOCKET_URING_OP_SETSOCKOPT,
80-
SOCKET_URING_OP_TX_TIMESTAMP,
81-
SOCKET_URING_OP_GETSOCKNAME,
74+
SOCKET_URING_OP_SIOCINQ = c.SOCKET_URING_OP_SIOCINQ,
75+
SOCKET_URING_OP_SIOCOUTQ = c.SOCKET_URING_OP_SIOCOUTQ,
76+
SOCKET_URING_OP_GETSOCKOPT = c.SOCKET_URING_OP_GETSOCKOPT,
77+
SOCKET_URING_OP_SETSOCKOPT = c.SOCKET_URING_OP_SETSOCKOPT,
78+
SOCKET_URING_OP_TX_TIMESTAMP = if (@hasDecl(c, "SOCKET_URING_OP_TX_TIMESTAMP")) c.SOCKET_URING_OP_TX_TIMESTAMP else 0, // 6.17
79+
SOCKET_URING_OP_GETSOCKNAME = if (@hasDecl(c, "SOCKET_URING_OP_GETSOCKNAME")) c.SOCKET_URING_OP_GETSOCKNAME else 0, // 6.19
8280
};

src/liburing/root.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ pub const Liburing = oz.module(.{
1111
oz.withSource(@import("helper.zig"), @embedFile("helper.zig")),
1212
oz.withSource(@import("uring.zig"), @embedFile("uring.zig")),
1313
oz.withSource(@import("statx.zig"), @embedFile("statx.zig")),
14+
oz.withSource(@import("socket.zig"), @embedFile("socket.zig")),
1415
},
1516
});

src/liburing/socket.zig

Lines changed: 140 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
const c = @import("c.zig").c;
33
const oz = @import("PyOZ");
44
const std = @import("std");
5-
6-
const AF = std.os.linux.AF;
5+
const SQE = @import("class.zig").SQE;
76

87
///Generic Socket Address.
98
///
@@ -14,7 +13,7 @@ const AF = std.os.linux.AF;
1413
/// >>> bind(sockfd, addr)
1514
///
1615
///Note
17-
/// - IPv6 `scope_id` can be added like so `b"ff01::fb%123"`
16+
/// - IPv6 `scope_id` can be added like so `"ff01::fb%123"`
1817
/// - `Sockaddr()` is low level setup, letting you serve/connect directly using path/ip.
1918
/// If you need higher level features you can use `getaddrinfo()` this lets you connect
2019
/// using domain names, ...
@@ -29,43 +28,43 @@ pub const Sockaddr = extern struct {
2928
var socklen: c.socklen_t = undefined;
3029
var sockaddr: usize = undefined;
3130

32-
if (addr.len == 0) return oz.raiseValueError("`sockaddr` - `addr` can not be empty!");
31+
if (addr.len == 0) return oz.raiseValueError("`Sockaddr` - `addr` can not be empty!");
3332

3433
switch (family) {
35-
AF.UNIX => {
36-
if (addr.len > 108) return oz.raiseValueError("`sockaddr` - length of `addr` can not be `> 108`");
34+
AF_UNIX => {
35+
if (addr.len > 108) return oz.raiseValueError("`Sockaddr` - length of `addr` can not be `> 108`");
3736

3837
socklen = @sizeOf(c.sockaddr_un);
3938
const _sock: *c.sockaddr_un = std.heap.c_allocator.create(c.sockaddr_un) catch {
40-
return oz.raiseMemoryError("`sockaddr()` - Out of Memory!");
39+
return oz.raiseMemoryError("`Sockaddr` - Out of Memory!");
4140
};
4241
_sock.sun_family = family;
4342
@memset(&_sock.sun_path, 0);
4443
@memcpy(_sock.sun_path[0..addr.len], addr);
4544
sockaddr = @intFromPtr(_sock);
4645
},
47-
AF.INET => {
46+
AF_INET => {
4847
socklen = @sizeOf(c.sockaddr_in);
4948
const _sock: *c.sockaddr_in = std.heap.c_allocator.create(c.sockaddr_in) catch {
50-
return oz.raiseMemoryError("`sockaddr()` - Out of Memory!");
49+
return oz.raiseMemoryError("`Sockaddr` - Out of Memory!");
5150
};
5251

5352
const _result = std.net.Ip4Address.parse(addr, port orelse 0) catch {
54-
return oz.raiseValueError("`sockaddr()` - `addr` or `port` not valid IPv4");
53+
return oz.raiseValueError("`Sockaddr` - `addr` or `port` not valid IPv4");
5554
};
5655
_sock.sin_family = family;
5756
_sock.sin_port = _result.sa.port;
5857
_sock.sin_addr.s_addr = _result.sa.addr;
5958
sockaddr = @intFromPtr(_sock);
6059
},
61-
AF.INET6 => {
60+
AF_INET6 => {
6261
socklen = @sizeOf(c.sockaddr_in6);
6362
const _sock: *c.sockaddr_in6 = std.heap.c_allocator.create(c.sockaddr_in6) catch {
64-
return oz.raiseMemoryError("`sockaddr()` - Out of Memory!");
63+
return oz.raiseMemoryError("`Sockaddr` - Out of Memory!");
6564
};
6665

6766
const _result = std.net.Ip6Address.parse(addr, port orelse 0) catch {
68-
return oz.raiseValueError("`sockaddr()` - `addr` or `port` not valid IPv6");
67+
return oz.raiseValueError("`Sockaddr` - `addr` or `port` not valid IPv6");
6968
};
7069
_sock.sin6_family = family;
7170
_sock.sin6_port = _result.sa.port;
@@ -74,22 +73,22 @@ pub const Sockaddr = extern struct {
7473
_sock.sin6_flowinfo = _result.sa.flowinfo;
7574
sockaddr = @intFromPtr(_sock);
7675
},
77-
else => return oz.raiseNotImplementedError(oz.fmt("`sockaddr()` - `family={d}` not supported!", .{family})),
76+
else => return oz.raiseNotImplementedError(oz.fmt("`Sockaddr` - `family={d}` not supported!", .{family})),
7877
}
7978
return .{ ._sockaddr = sockaddr, ._socklen = socklen, ._family = family };
8079
}
8180

8281
pub fn __del__(self: *Self) void {
8382
switch (self._family) {
84-
AF.UNIX => {
83+
AF_UNIX => {
8584
const ptr: *c.sockaddr_un = @ptrFromInt(self._sockaddr);
8685
std.heap.c_allocator.destroy(ptr);
8786
},
88-
AF.INET => {
87+
AF_INET => {
8988
const ptr: *c.sockaddr_in = @ptrFromInt(self._sockaddr);
9089
std.heap.c_allocator.destroy(ptr);
9190
},
92-
AF.INET6 => {
91+
AF_INET6 => {
9392
const ptr: *c.sockaddr_in6 = @ptrFromInt(self._sockaddr);
9493
std.heap.c_allocator.destroy(ptr);
9594
},
@@ -98,6 +97,61 @@ pub const Sockaddr = extern struct {
9897
}
9998
};
10099

100+
///Example
101+
/// >>> val = (1).to_bytes(4, "big")
102+
/// >>> sqe = io_uring_get_sqe(ring)
103+
/// >>> setsockopt(sqe, sockfd, SOL_SOCKET, SO_KEEPALIVE, val)
104+
///
105+
/// >>> val = (0).to_bytes(4, "big")
106+
/// >>> sqe = io_uring_get_sqe(ring)
107+
/// >>> setsockopt(sqe, sockfd, SOL_SOCKET, SO_KEEPALIVE, val)
108+
///
109+
/// >>> val = b"eth1"
110+
/// >>> sqe = io_uring_get_sqe(ring)
111+
/// >>> setsockopt(sqe, sockfd, SOL_SOCKET, SO_BINDTODEVICE, val)
112+
///
113+
///Note
114+
/// - remember to hold on to `val` reference till `sqe` has been submitted.
115+
/// - min length of `val` must be `4`.
116+
/// - watch out for "big" or "little" endian, keep is same or it will switch to systems default.
117+
pub fn setsockopt(sqe: *SQE, sockfd: i32, level: i32, optname: i32, optval: oz.Bytes) void {
118+
c.io_uring_prep_cmd_sock(
119+
sqe._sqe,
120+
c.SOCKET_URING_OP_SETSOCKOPT,
121+
sockfd,
122+
level,
123+
optname,
124+
@constCast(optval.data.ptr),
125+
@intCast(optval.data.len),
126+
);
127+
}
128+
129+
///Example
130+
/// # assuming `SO_KEEPALIVE` was previous set to `1`
131+
/// >>> buf = bytearray(4)
132+
/// >>> sqe = io_uring_get_sqe(ring)
133+
/// >>> getsockopt(sqe, sockfd, SOL_SOCKET, SO_KEEPALIVE, buf)
134+
/// ... # after submit and wait
135+
/// >>> int.from_bytes(buf)
136+
/// 1
137+
///
138+
///Note
139+
/// - remember to hold on to `buf` as new result will be populated into it.
140+
/// - `cqe.res` will return `len()` of populating data(`buf`).
141+
/// - min length of `buf` must be `4`.
142+
/// - watch out for "big" or "little" endian, keep is same or it will switch to systems default.
143+
pub fn getsockopt(sqe: *SQE, sockfd: i32, level: i32, optname: i32, optval: oz.ByteArray) void {
144+
c.io_uring_prep_cmd_sock(
145+
sqe._sqe,
146+
c.SOCKET_URING_OP_GETSOCKOPT,
147+
sockfd,
148+
level,
149+
optname,
150+
optval.data.ptr,
151+
@intCast(optval.data.len),
152+
);
153+
}
154+
101155
// Socket Family
102156
pub const AF_UNIX = c.AF_UNIX;
103157
pub const AF_INET = c.AF_INET;
@@ -120,80 +174,80 @@ pub const SHUT_WR = c.SHUT_WR;
120174
pub const SHUT_RDWR = c.SHUT_RDWR;
121175

122176
// Socket Proto
123-
pub const IPPROTO_IP = IPPROTO_IP;
124-
pub const IPPROTO_ICMP = IPPROTO_ICMP;
125-
pub const IPPROTO_IGMP = IPPROTO_IGMP;
126-
pub const IPPROTO_IPIP = IPPROTO_IPIP;
127-
pub const IPPROTO_TCP = IPPROTO_TCP;
128-
pub const IPPROTO_EGP = IPPROTO_EGP;
129-
pub const IPPROTO_PUP = IPPROTO_PUP;
130-
pub const IPPROTO_UDP = IPPROTO_UDP;
131-
pub const IPPROTO_IDP = IPPROTO_IDP;
132-
pub const IPPROTO_TP = IPPROTO_TP;
133-
pub const IPPROTO_DCCP = IPPROTO_DCCP;
134-
pub const IPPROTO_IPV6 = IPPROTO_IPV6;
135-
pub const IPPROTO_RSVP = IPPROTO_RSVP;
136-
pub const IPPROTO_GRE = IPPROTO_GRE;
137-
pub const IPPROTO_ESP = IPPROTO_ESP;
138-
pub const IPPROTO_AH = IPPROTO_AH;
139-
pub const IPPROTO_MTP = IPPROTO_MTP;
140-
pub const IPPROTO_BEETPH = IPPROTO_BEETPH;
141-
pub const IPPROTO_ENCAP = IPPROTO_ENCAP;
142-
pub const IPPROTO_PIM = IPPROTO_PIM;
143-
pub const IPPROTO_COMP = IPPROTO_COMP;
177+
pub const IPPROTO_IP = c.IPPROTO_IP;
178+
pub const IPPROTO_ICMP = c.IPPROTO_ICMP;
179+
pub const IPPROTO_IGMP = c.IPPROTO_IGMP;
180+
pub const IPPROTO_IPIP = c.IPPROTO_IPIP;
181+
pub const IPPROTO_TCP = c.IPPROTO_TCP;
182+
pub const IPPROTO_EGP = c.IPPROTO_EGP;
183+
pub const IPPROTO_PUP = c.IPPROTO_PUP;
184+
pub const IPPROTO_UDP = c.IPPROTO_UDP;
185+
pub const IPPROTO_IDP = c.IPPROTO_IDP;
186+
pub const IPPROTO_TP = c.IPPROTO_TP;
187+
pub const IPPROTO_DCCP = c.IPPROTO_DCCP;
188+
pub const IPPROTO_IPV6 = c.IPPROTO_IPV6;
189+
pub const IPPROTO_RSVP = c.IPPROTO_RSVP;
190+
pub const IPPROTO_GRE = c.IPPROTO_GRE;
191+
pub const IPPROTO_ESP = c.IPPROTO_ESP;
192+
pub const IPPROTO_AH = c.IPPROTO_AH;
193+
pub const IPPROTO_MTP = c.IPPROTO_MTP;
194+
pub const IPPROTO_BEETPH = c.IPPROTO_BEETPH;
195+
pub const IPPROTO_ENCAP = c.IPPROTO_ENCAP;
196+
pub const IPPROTO_PIM = c.IPPROTO_PIM;
197+
pub const IPPROTO_COMP = c.IPPROTO_COMP;
144198
// # note: not supported
145199
// pub const IPPROTO_L2TP = IPPROTO_L2TP;
146-
pub const IPPROTO_SCTP = IPPROTO_SCTP;
147-
pub const IPPROTO_UDPLITE = IPPROTO_UDPLITE;
148-
pub const IPPROTO_MPLS = IPPROTO_MPLS;
149-
pub const IPPROTO_ETHERNET = IPPROTO_ETHERNET;
150-
pub const IPPROTO_RAW = IPPROTO_RAW;
151-
pub const IPPROTO_MPTCP = IPPROTO_MPTCP;
200+
pub const IPPROTO_SCTP = c.IPPROTO_SCTP;
201+
pub const IPPROTO_UDPLITE = c.IPPROTO_UDPLITE;
202+
pub const IPPROTO_MPLS = c.IPPROTO_MPLS;
203+
pub const IPPROTO_ETHERNET = c.IPPROTO_ETHERNET;
204+
pub const IPPROTO_RAW = c.IPPROTO_RAW;
205+
pub const IPPROTO_MPTCP = c.IPPROTO_MPTCP;
152206

153207
// Setsockopt & Getsockopt start >>>
154-
pub const SOL_SOCKET = SOL_SOCKET;
155-
pub const SO_DEBUG = SO_DEBUG;
156-
pub const SO_REUSEADDR = SO_REUSEADDR;
157-
pub const SO_TYPE = SO_TYPE;
158-
pub const SO_ERROR = SO_ERROR;
159-
pub const SO_DONTROUTE = SO_DONTROUTE;
160-
pub const SO_BROADCAST = SO_BROADCAST;
161-
pub const SO_SNDBUF = SO_SNDBUF;
162-
pub const SO_RCVBUF = SO_RCVBUF;
163-
pub const SO_SNDBUFFORCE = SO_SNDBUFFORCE;
164-
pub const SO_RCVBUFFORCE = SO_RCVBUFFORCE;
165-
pub const SO_KEEPALIVE = SO_KEEPALIVE;
166-
pub const SO_OOBINLINE = SO_OOBINLINE;
167-
pub const SO_NO_CHECK = SO_NO_CHECK;
168-
pub const SO_PRIORITY = SO_PRIORITY;
169-
pub const SO_LINGER = SO_LINGER;
170-
pub const SO_BSDCOMPAT = SO_BSDCOMPAT;
171-
pub const SO_REUSEPORT = SO_REUSEPORT;
172-
pub const SO_PASSCRED = SO_PASSCRED;
173-
pub const SO_PEERCRED = SO_PEERCRED;
174-
pub const SO_RCVLOWAT = SO_RCVLOWAT;
175-
pub const SO_SNDLOWAT = SO_SNDLOWAT;
176-
pub const SO_BINDTODEVICE = SO_BINDTODEVICE;
208+
pub const SOL_SOCKET = c.SOL_SOCKET;
209+
pub const SO_DEBUG = c.SO_DEBUG;
210+
pub const SO_REUSEADDR = c.SO_REUSEADDR;
211+
pub const SO_TYPE = c.SO_TYPE;
212+
pub const SO_ERROR = c.SO_ERROR;
213+
pub const SO_DONTROUTE = c.SO_DONTROUTE;
214+
pub const SO_BROADCAST = c.SO_BROADCAST;
215+
pub const SO_SNDBUF = c.SO_SNDBUF;
216+
pub const SO_RCVBUF = c.SO_RCVBUF;
217+
pub const SO_SNDBUFFORCE = c.SO_SNDBUFFORCE;
218+
pub const SO_RCVBUFFORCE = c.SO_RCVBUFFORCE;
219+
pub const SO_KEEPALIVE = c.SO_KEEPALIVE;
220+
pub const SO_OOBINLINE = c.SO_OOBINLINE;
221+
pub const SO_NO_CHECK = c.SO_NO_CHECK;
222+
pub const SO_PRIORITY = c.SO_PRIORITY;
223+
pub const SO_LINGER = c.SO_LINGER;
224+
pub const SO_BSDCOMPAT = c.SO_BSDCOMPAT;
225+
pub const SO_REUSEPORT = c.SO_REUSEPORT;
226+
pub const SO_PASSCRED = c.SO_PASSCRED;
227+
pub const SO_PEERCRED = c.SO_PEERCRED;
228+
pub const SO_RCVLOWAT = c.SO_RCVLOWAT;
229+
pub const SO_SNDLOWAT = c.SO_SNDLOWAT;
230+
pub const SO_BINDTODEVICE = c.SO_BINDTODEVICE;
177231

178232
// Socket Filtering
179-
pub const SO_ATTACH_FILTER = SO_ATTACH_FILTER;
180-
pub const SO_DETACH_FILTER = SO_DETACH_FILTER;
181-
pub const SO_GET_FILTER = SO_GET_FILTER;
182-
pub const SO_PEERNAME = SO_PEERNAME;
183-
pub const SO_ACCEPTCONN = SO_ACCEPTCONN;
184-
pub const SO_PEERSEC = SO_PEERSEC;
185-
pub const SO_PASSSEC = SO_PASSSEC;
186-
pub const SO_MARK = SO_MARK;
187-
pub const SO_PROTOCOL = SO_PROTOCOL;
188-
pub const SO_DOMAIN = SO_DOMAIN;
189-
pub const SO_RXQ_OVFL = SO_RXQ_OVFL;
190-
pub const SO_WIFI_STATUS = SO_WIFI_STATUS;
191-
pub const SCM_WIFI_STATUS = SCM_WIFI_STATUS;
192-
pub const SO_PEEK_OFF = SO_PEEK_OFF;
233+
pub const SO_ATTACH_FILTER = c.SO_ATTACH_FILTER;
234+
pub const SO_DETACH_FILTER = c.SO_DETACH_FILTER;
235+
pub const SO_GET_FILTER = c.SO_GET_FILTER;
236+
pub const SO_PEERNAME = c.SO_PEERNAME;
237+
pub const SO_ACCEPTCONN = c.SO_ACCEPTCONN;
238+
pub const SO_PEERSEC = c.SO_PEERSEC;
239+
pub const SO_PASSSEC = c.SO_PASSSEC;
240+
pub const SO_MARK = c.SO_MARK;
241+
pub const SO_PROTOCOL = c.SO_PROTOCOL;
242+
pub const SO_DOMAIN = c.SO_DOMAIN;
243+
pub const SO_RXQ_OVFL = c.SO_RXQ_OVFL;
244+
pub const SO_WIFI_STATUS = c.SO_WIFI_STATUS;
245+
pub const SCM_WIFI_STATUS = c.SCM_WIFI_STATUS;
246+
pub const SO_PEEK_OFF = c.SO_PEEK_OFF;
193247

194248
// not tested
195-
pub const SO_TIMESTAMP = SO_TIMESTAMP;
196-
pub const SO_TIMESTAMPNS = SO_TIMESTAMPNS;
197-
pub const SO_TIMESTAMPING = SO_TIMESTAMPING;
198-
pub const SO_RCVTIMEO = SO_RCVTIMEO;
199-
pub const SO_SNDTIMEO = SO_SNDTIMEO;
249+
pub const SO_TIMESTAMP = c.SO_TIMESTAMP;
250+
pub const SO_TIMESTAMPNS = c.SO_TIMESTAMPNS;
251+
pub const SO_TIMESTAMPING = c.SO_TIMESTAMPING;
252+
pub const SO_RCVTIMEO = c.SO_RCVTIMEO;
253+
pub const SO_SNDTIMEO = c.SO_SNDTIMEO;

0 commit comments

Comments
 (0)