authorgravatar for hemisputnik@proton.mehemisputnik <hemisputnik@proton.me> 2026-07-22 09:06:26+03:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2026-10-01 10:55:12+02:00
log20355494085a6eb59b73816038a5d0c56b5492c6
tree07234e26640c2f1626046fb5853d199e8af45a9a
parent8909d25b365de94d4b37c613ce3276634765a86b
signature Commit is signed but in an unrecognized format.

std.Io.net: improve reception of control data

A couple of changes to improve reception of control data when using the datagram API. Instead of having a separate control buffer per received message, there's one big buffer that all messages share (like the data buffer). This means that now IncomingMessage has no user-initialised fields, and can be initialised with undefined (which means that .init is now deprecated). Also, instead of taking a pointer to mutable IncomingMessage, netReceiveOne* functions simply return a IncomingMessage.

5 files changed, 106 insertions(+), 23 deletions(-)

lib/std/Io.zig+1
...@@ -346,6 +346,7 @@ pub const Operation = union(enum) {...@@ -346,6 +346,7 @@ pub const Operation = union(enum) {
346 socket_handle: net.Socket.Handle,346 socket_handle: net.Socket.Handle,
347 message_buffer: []net.IncomingMessage,347 message_buffer: []net.IncomingMessage,
348 data_buffer: []u8,348 data_buffer: []u8,
349 control_buffer: []u8 = &.{},
349 flags: net.ReceiveFlags,350 flags: net.ReceiveFlags,
350351
351 pub const Error = error{352 pub const Error = error{
lib/std/Io/Kqueue.zig+2
...@@ -1183,6 +1183,7 @@ fn netReceive(...@@ -1183,6 +1183,7 @@ fn netReceive(
1183 handle: net.Socket.Handle,1183 handle: net.Socket.Handle,
1184 message_buffer: []net.IncomingMessage,1184 message_buffer: []net.IncomingMessage,
1185 data_buffer: []u8,1185 data_buffer: []u8,
1186 control_buffer: []u8,
1186 flags: net.ReceiveFlags,1187 flags: net.ReceiveFlags,
1187 timeout: Io.Timeout,1188 timeout: Io.Timeout,
1188) struct { ?net.Socket.ReceiveTimeoutError, usize } {1189) struct { ?net.Socket.ReceiveTimeoutError, usize } {
...@@ -1191,6 +1192,7 @@ fn netReceive(...@@ -1191,6 +1192,7 @@ fn netReceive(
1191 _ = handle;1192 _ = handle;
1192 _ = message_buffer;1193 _ = message_buffer;
1193 _ = data_buffer;1194 _ = data_buffer;
1195 _ = control_buffer;
1194 _ = flags;1196 _ = flags;
1195 _ = timeout;1197 _ = timeout;
1196 @panic("TODO");1198 @panic("TODO");
lib/std/Io/Threaded.zig+18-8
...@@ -2555,8 +2555,8 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper...@@ -2555,8 +2555,8 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper
2555 .device_io_control => |*o| return .{ .device_io_control = try deviceIoControl(o) },2555 .device_io_control => |*o| return .{ .device_io_control = try deviceIoControl(o) },
2556 .net_receive => |*o| return .{ .net_receive = o: {2556 .net_receive => |*o| return .{ .net_receive = o: {
2557 if (!have_networking) break :o .{ error.NetworkDown, 0 };2557 if (!have_networking) break :o .{ error.NetworkDown, 0 };
2558 if (is_windows) break :o netReceiveWindows(t, o.socket_handle, o.message_buffer, o.data_buffer, o.flags);2558 if (is_windows) break :o netReceiveWindows(t, o.socket_handle, o.message_buffer, o.data_buffer, o.control_buffer, o.flags);
2559 netReceivePosix(o.socket_handle, &o.message_buffer[0], o.data_buffer, o.flags, false) catch |err| switch (err) {2559 netReceiveOnePosix(o.socket_handle, &o.message_buffer[0], o.data_buffer, o.control_buffer, o.flags, false) catch |err| switch (err) {
2560 error.Canceled => |e| return e,2560 error.Canceled => |e| return e,
2561 error.WouldBlock => unreachable,2561 error.WouldBlock => unreachable,
2562 else => |e| break :o .{ e, 0 },2562 else => |e| break :o .{ e, 0 },
...@@ -2825,9 +2825,11 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout...@@ -2825,9 +2825,11 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout
2825 .device_io_control => |o| try poll_storage.add(o.file.handle, posix.POLL.IN | posix.POLL.OUT | posix.POLL.ERR),2825 .device_io_control => |o| try poll_storage.add(o.file.handle, posix.POLL.IN | posix.POLL.OUT | posix.POLL.ERR),
2826 .net_receive => |*o| nb: {2826 .net_receive => |*o| nb: {
2827 var data_i: usize = 0;2827 var data_i: usize = 0;
2828 var control_i: usize = 0;
2828 const result: Io.Operation.Result = .{ .net_receive = for (o.message_buffer, 0..) |*msg, msg_i| {2829 const result: Io.Operation.Result = .{ .net_receive = for (o.message_buffer, 0..) |*msg, msg_i| {
2829 const remaining_data_buffer = o.data_buffer[data_i..];2830 const remaining_data_buffer = o.data_buffer[data_i..];
2830 netReceivePosix(o.socket_handle, msg, remaining_data_buffer, o.flags, true) catch |err| switch (err) {2831 const remaining_control_buffer = o.control_buffer[control_i..];
2832 netReceiveOnePosix(o.socket_handle, msg, remaining_data_buffer, remaining_control_buffer, o.flags, true) catch |err| switch (err) {
2831 error.Canceled => |e| return e,2833 error.Canceled => |e| return e,
2832 error.WouldBlock => {2834 error.WouldBlock => {
2833 if (msg_i != 0) break .{ null, msg_i };2835 if (msg_i != 0) break .{ null, msg_i };
...@@ -2837,6 +2839,7 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout...@@ -2837,6 +2839,7 @@ fn batchAwaitConcurrent(userdata: ?*anyopaque, b: *Io.Batch, timeout: Io.Timeout
2837 else => |e| break .{ e, 0 },2839 else => |e| break .{ e, 0 },
2838 };2840 };
2839 data_i += msg.data.len;2841 data_i += msg.data.len;
2842 control_i += msg.control.len;
2840 } else .{ null, o.message_buffer.len } };2843 } else .{ null, o.message_buffer.len } };
2841 switch (b.completed.tail) {2844 switch (b.completed.tail) {
2842 .none => b.completed.head = index,2845 .none => b.completed.head = index,
...@@ -3279,7 +3282,7 @@ fn batchDrainSubmittedWindows(t: *Threaded, b: *Io.Batch, concurrency: bool) (Io...@@ -3279,7 +3282,7 @@ fn batchDrainSubmittedWindows(t: *Threaded, b: *Io.Batch, concurrency: bool) (Io
3279 // TODO integrate with overlapped I/O or equivalent to avoid this error3282 // TODO integrate with overlapped I/O or equivalent to avoid this error
3280 if (concurrency) return error.ConcurrencyUnavailable;3283 if (concurrency) return error.ConcurrencyUnavailable;
3281 batchCompleteBlockingWindows(b, operation_userdata, .{3284 batchCompleteBlockingWindows(b, operation_userdata, .{
3282 .net_receive = netReceiveWindows(t, o.socket_handle, o.message_buffer, o.data_buffer, o.flags),3285 .net_receive = netReceiveWindows(t, o.socket_handle, o.message_buffer, o.data_buffer, o.control_buffer, o.flags),
3283 });3286 });
3284 },3287 },
3285 .net_send => |*o| {3288 .net_send => |*o| {
...@@ -13212,10 +13215,11 @@ fn netSendManyPosix(...@@ -13212,10 +13215,11 @@ fn netSendManyPosix(
13212 }13215 }
13213}13216}
1321413217
13215fn netReceivePosix(13218fn netReceiveOnePosix(
13216 socket_handle: net.Socket.Handle,13219 socket_handle: net.Socket.Handle,
13217 message: *net.IncomingMessage,13220 message: *net.IncomingMessage,
13218 data_buffer: []u8,13221 data_buffer: []u8,
13222 control_buffer: []u8,
13219 flags: net.ReceiveFlags,13223 flags: net.ReceiveFlags,
13220 nonblocking: bool,13224 nonblocking: bool,
13221) (net.Socket.ReceiveError || error{WouldBlock})!void {13225) (net.Socket.ReceiveError || error{WouldBlock})!void {
...@@ -13238,22 +13242,24 @@ fn netReceivePosix(...@@ -13238,22 +13242,24 @@ fn netReceivePosix(
13238 .namelen = @sizeOf(PosixAddress),13242 .namelen = @sizeOf(PosixAddress),
13239 .iov = (&iov)[0..1],13243 .iov = (&iov)[0..1],
13240 .iovlen = 1,13244 .iovlen = 1,
13241 .control = message.control.ptr,13245 .control = control_buffer.ptr,
13242 .controllen = @intCast(message.control.len),13246 .controllen = @intCast(control_buffer.len),
13243 .flags = 0,13247 .flags = 0,
13244 };13248 };
1324513249
13246 const syscall = try Syscall.start();13250 const syscall = try Syscall.start();
13247 while (true) {13251 while (true) {
13248 const rc = posix.system.recvmsg(socket_handle, &msg, posix_flags);13252 const rc = posix.system.recvmsg(socket_handle, &msg, posix_flags);
13253 const rc_control = msg.controllen;
13249 switch (posix.errno(rc)) {13254 switch (posix.errno(rc)) {
13250 .SUCCESS => {13255 .SUCCESS => {
13251 syscall.finish();13256 syscall.finish();
13252 const data = data_buffer[0..@intCast(rc)];13257 const data = data_buffer[0..@intCast(rc)];
13258 const control = control_buffer[0..@intCast(rc_control)];
13253 message.* = .{13259 message.* = .{
13254 .from = addressFromPosix(&storage),13260 .from = addressFromPosix(&storage),
13255 .data = data,13261 .data = data,
13256 .control = if (msg.control) |ptr| @as([*]u8, @ptrCast(ptr))[0..msg.controllen] else message.control,13262 .control = control,
13257 .flags = .{13263 .flags = .{
13258 .eor = (msg.flags & posix.MSG.EOR) != 0,13264 .eor = (msg.flags & posix.MSG.EOR) != 0,
13259 .trunc = (msg.flags & posix.MSG.TRUNC) != 0,13265 .trunc = (msg.flags & posix.MSG.TRUNC) != 0,
...@@ -13294,8 +13300,12 @@ fn netReceiveWindows(...@@ -13294,8 +13300,12 @@ fn netReceiveWindows(
13294 socket_handle: net.Socket.Handle,13300 socket_handle: net.Socket.Handle,
13295 message_buffer: []net.IncomingMessage,13301 message_buffer: []net.IncomingMessage,
13296 data_buffer: []u8,13302 data_buffer: []u8,
13303 control_buffer: []u8,
13297 flags: net.ReceiveFlags,13304 flags: net.ReceiveFlags,
13298) struct { ?net.Socket.ReceiveError, usize } {13305) struct { ?net.Socket.ReceiveError, usize } {
13306 // Windows doesn't have the concept of control/ancillary data.
13307 _ = control_buffer;
13308
13299 t.netReceiveOneWindows(socket_handle, &message_buffer[0], data_buffer, flags) catch |err|13309 t.netReceiveOneWindows(socket_handle, &message_buffer[0], data_buffer, flags) catch |err|
13300 return .{ err, 0 };13310 return .{ err, 0 };
13301 return .{ null, 1 };13311 return .{ null, 1 };
lib/std/Io/Uring.zig+9-4
...@@ -2095,7 +2095,7 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper...@@ -2095,7 +2095,7 @@ fn operate(userdata: ?*anyopaque, operation: Io.Operation) Io.Cancelable!Io.Oper
2095 },2095 },
2096 .net_receive => |o| .{2096 .net_receive => |o| .{
2097 .net_receive = r: {2097 .net_receive = r: {
2098 const opt_err, const n = ev.netReceive(&maybe_sync.cancel_region, o.socket_handle, o.message_buffer, o.data_buffer, o.flags);2098 const opt_err, const n = ev.netReceive(&maybe_sync.cancel_region, o.socket_handle, o.message_buffer, o.data_buffer, o.control_buffer, o.flags);
2099 break :r .{2099 break :r .{
2100 if (opt_err) |err| switch (err) {2100 if (opt_err) |err| switch (err) {
2101 error.Canceled => |e| return e,2101 error.Canceled => |e| return e,
...@@ -5075,15 +5075,18 @@ fn netReceive(...@@ -5075,15 +5075,18 @@ fn netReceive(
5075 handle: net.Socket.Handle,5075 handle: net.Socket.Handle,
5076 message_buffer: []net.IncomingMessage,5076 message_buffer: []net.IncomingMessage,
5077 data_buffer: []u8,5077 data_buffer: []u8,
5078 control_buffer: []u8,
5078 flags: net.ReceiveFlags,5079 flags: net.ReceiveFlags,
5079) struct { ?net.Socket.ReceiveError, usize } {5080) struct { ?net.Socket.ReceiveError, usize } {
5080 var message_i: usize = 0;5081 var message_i: usize = 0;
5081 var data_i: usize = 0;5082 var data_i: usize = 0;
5083 var control_i: usize = 0;
50825084
5083 while (true) {5085 while (true) {
5084 if (message_buffer.len - message_i == 0) return .{ null, message_i };5086 if (message_buffer.len - message_i == 0) return .{ null, message_i };
5085 const message = &message_buffer[message_i];5087 const message = &message_buffer[message_i];
5086 const remaining_data_buffer = data_buffer[data_i..];5088 const remaining_data_buffer = data_buffer[data_i..];
5089 const remaining_control_buffer = control_buffer[control_i..];
5087 var storage: PosixAddress = undefined;5090 var storage: PosixAddress = undefined;
5088 var iov: iovec = .{ .base = remaining_data_buffer.ptr, .len = remaining_data_buffer.len };5091 var iov: iovec = .{ .base = remaining_data_buffer.ptr, .len = remaining_data_buffer.len };
5089 var msg: linux.msghdr = .{5092 var msg: linux.msghdr = .{
...@@ -5091,8 +5094,8 @@ fn netReceive(...@@ -5091,8 +5094,8 @@ fn netReceive(
5091 .namelen = @sizeOf(PosixAddress),5094 .namelen = @sizeOf(PosixAddress),
5092 .iov = (&iov)[0..1],5095 .iov = (&iov)[0..1],
5093 .iovlen = 1,5096 .iovlen = 1,
5094 .control = message.control.ptr,5097 .control = remaining_control_buffer.ptr,
5095 .controllen = @intCast(message.control.len),5098 .controllen = @intCast(remaining_control_buffer.len),
5096 .flags = undefined,5099 .flags = undefined,
5097 };5100 };
50985101
...@@ -5121,11 +5124,13 @@ fn netReceive(...@@ -5121,11 +5124,13 @@ fn netReceive(
5121 switch (completion.errno()) {5124 switch (completion.errno()) {
5122 .SUCCESS => {5125 .SUCCESS => {
5123 const data = remaining_data_buffer[0..@intCast(completion.result)];5126 const data = remaining_data_buffer[0..@intCast(completion.result)];
5127 const control = remaining_control_buffer[0..@intCast(msg.controllen)];
5124 data_i += data.len;5128 data_i += data.len;
5129 control_i += @intCast(msg.controllen);
5125 message.* = .{5130 message.* = .{
5126 .from = addressFromPosix(&storage),5131 .from = addressFromPosix(&storage),
5127 .data = data,5132 .data = data,
5128 .control = if (msg.control) |ptr| @as([*]u8, @ptrCast(ptr))[0..msg.controllen] else message.control,5133 .control = control,
5129 .flags = .{5134 .flags = .{
5130 .eor = msg.flags & linux.MSG.EOR != 0,5135 .eor = msg.flags & linux.MSG.EOR != 0,
5131 .trunc = msg.flags & linux.MSG.TRUNC != 0,5136 .trunc = msg.flags & linux.MSG.TRUNC != 0,
lib/std/Io/net.zig+76-11
...@@ -924,22 +924,20 @@ pub const ReceiveFlags = packed struct(u8) {...@@ -924,22 +924,20 @@ pub const ReceiveFlags = packed struct(u8) {
924 _: u5 = 0,924 _: u5 = 0,
925};925};
926926
927/// Fields are populated by receive functions.
927pub const IncomingMessage = struct {928pub const IncomingMessage = struct {
928 /// Populated by receive functions.
929 from: IpAddress,929 from: IpAddress,
930 /// Populated by receive functions, points into the caller-supplied buffer.930 /// Points into caller-supplied buffer.
931 data: []u8,931 data: []u8,
932 /// Supplied by caller before calling receive functions; mutated by receive932 /// Points into caller-supplied buffer.
933 /// functions.
934 control: []u8,933 control: []u8,
935 /// Populated by receive functions.
936 flags: Flags,934 flags: Flags,
937935
938 /// Useful for initializing before calling `receiveManyTimeout`.936 /// Deprecated. Initialize with `undefined`.
939 pub const init: IncomingMessage = .{937 pub const init: IncomingMessage = .{
940 .from = undefined,938 .from = undefined,
941 .data = undefined,939 .data = undefined,
942 .control = &.{},940 .control = undefined,
943 .flags = undefined,941 .flags = undefined,
944 };942 };
945943
...@@ -1162,13 +1160,30 @@ pub const Socket = struct {...@@ -1162,13 +1160,30 @@ pub const Socket = struct {
1162 /// Waits for data. Connectionless.1160 /// Waits for data. Connectionless.
1163 ///1161 ///
1164 /// See also:1162 /// See also:
1163 /// * `receiveWithControl`
1165 /// * `receiveTimeout`1164 /// * `receiveTimeout`
1165 /// * `receiveWithControlTimeout`
1166 /// * `receiveManyTimeout`
1167 /// * `receiveManyWithControlTimeout`
1166 pub fn receive(s: *const Socket, io: Io, buffer: []u8) ReceiveError!IncomingMessage {1168 pub fn receive(s: *const Socket, io: Io, buffer: []u8) ReceiveError!IncomingMessage {
1167 var message: IncomingMessage = .init;1169 return s.receiveWithControl(io, buffer, &.{});
1170 }
1171
1172 /// Waits for data, allowing the reception of control data. Connectionless.
1173 ///
1174 /// See also:
1175 /// * `receive`
1176 /// * `receiveTimeout`
1177 /// * `receiveWithControlTimeout`
1178 /// * `receiveManyTimeout`
1179 /// * `receiveManyWithControlTimeout`
1180 pub fn receiveWithControl(s: *const Socket, io: Io, buffer: []u8, control: []u8) ReceiveError!IncomingMessage {
1181 var message: IncomingMessage = undefined;
1168 const maybe_err, const count = (try io.operate(.{ .net_receive = .{1182 const maybe_err, const count = (try io.operate(.{ .net_receive = .{
1169 .socket_handle = s.handle,1183 .socket_handle = s.handle,
1170 .message_buffer = (&message)[0..1],1184 .message_buffer = (&message)[0..1],
1171 .data_buffer = buffer,1185 .data_buffer = buffer,
1186 .control_buffer = control,
1172 .flags = .{},1187 .flags = .{},
1173 } })).net_receive;1188 } })).net_receive;
1174 if (maybe_err) |err| return err;1189 if (maybe_err) |err| return err;
...@@ -1184,18 +1199,42 @@ pub const Socket = struct {...@@ -1184,18 +1199,42 @@ pub const Socket = struct {
1184 ///1199 ///
1185 /// See also:1200 /// See also:
1186 /// * `receive`1201 /// * `receive`
1202 /// * `receiveWithControl`
1203 /// * `receiveWithControlTimeout`
1187 /// * `receiveManyTimeout`1204 /// * `receiveManyTimeout`
1205 /// * `receiveManyWithControlTimeout`
1188 pub fn receiveTimeout(1206 pub fn receiveTimeout(
1189 s: *const Socket,1207 s: *const Socket,
1190 io: Io,1208 io: Io,
1191 buffer: []u8,1209 buffer: []u8,
1192 timeout: Io.Timeout,1210 timeout: Io.Timeout,
1193 ) ReceiveTimeoutError!IncomingMessage {1211 ) ReceiveTimeoutError!IncomingMessage {
1194 var message: IncomingMessage = .init;1212 return s.receiveWithControlTimeout(io, buffer, &.{}, timeout);
1213 }
1214
1215 /// Waits for data, allowing the reception of control data. Connectionless.
1216 ///
1217 /// Returns `error.Timeout` if no message arrives early enough.
1218 ///
1219 /// See also:
1220 /// * `receive`
1221 /// * `receiveWithControl`
1222 /// * `receiveTimeout`
1223 /// * `receiveManyTimeout`
1224 /// * `receiveManyWithControlTimeout`
1225 pub fn receiveWithControlTimeout(
1226 s: *const Socket,
1227 io: Io,
1228 buffer: []u8,
1229 control: []u8,
1230 timeout: Io.Timeout,
1231 ) ReceiveTimeoutError!IncomingMessage {
1232 var message: IncomingMessage = undefined;
1195 const maybe_err, const count = (try io.operateTimeout(.{ .net_receive = .{1233 const maybe_err, const count = (try io.operateTimeout(.{ .net_receive = .{
1196 .socket_handle = s.handle,1234 .socket_handle = s.handle,
1197 .message_buffer = (&message)[0..1],1235 .message_buffer = (&message)[0..1],
1198 .data_buffer = buffer,1236 .data_buffer = buffer,
1237 .control_buffer = control,
1199 .flags = .{},1238 .flags = .{},
1200 } }, timeout)).net_receive;1239 } }, timeout)).net_receive;
1201 if (maybe_err) |err| return err;1240 if (maybe_err) |err| return err;
...@@ -1211,21 +1250,47 @@ pub const Socket = struct {...@@ -1211,21 +1250,47 @@ pub const Socket = struct {
1211 ///1250 ///
1212 /// See also:1251 /// See also:
1213 /// * `receive`1252 /// * `receive`
1253 /// * `receiveWithControl`
1214 /// * `receiveTimeout`1254 /// * `receiveTimeout`
1255 /// * `receiveWithControlTimeout`
1256 /// * `receiveManyWithControlTimeout`
1215 pub fn receiveManyTimeout(1257 pub fn receiveManyTimeout(
1216 s: *const Socket,1258 s: *const Socket,
1217 io: Io,1259 io: Io,
1218 /// Function assumes each element has initialized `control` field.
1219 /// Initializing with `IncomingMessage.init` may be helpful.
1220 message_buffer: []IncomingMessage,1260 message_buffer: []IncomingMessage,
1221 data_buffer: []u8,1261 data_buffer: []u8,
1222 flags: ReceiveFlags,1262 flags: ReceiveFlags,
1223 timeout: Io.Timeout,1263 timeout: Io.Timeout,
1264 ) struct { ?ReceiveTimeoutError, usize } {
1265 return s.receiveManyWithControlTimeout(io, message_buffer, data_buffer, &.{}, flags, timeout);
1266 }
1267
1268 /// Waits until at least one message is delivered, possibly returning more
1269 /// than one message. Allows reception of control data. Connectionless.
1270 ///
1271 /// Returns number of messages received, or `error.Timeout` if no message
1272 /// arrives early enough.
1273 ///
1274 /// See also:
1275 /// * `receive`
1276 /// * `receiveWithControl`
1277 /// * `receiveTimeout`
1278 /// * `receiveWithControlTimeout`
1279 /// * `receiveManyTimeout`
1280 pub fn receiveManyWithControlTimeout(
1281 s: *const Socket,
1282 io: Io,
1283 message_buffer: []IncomingMessage,
1284 data_buffer: []u8,
1285 control_buffer: []u8,
1286 flags: ReceiveFlags,
1287 timeout: Io.Timeout,
1224 ) struct { ?ReceiveTimeoutError, usize } {1288 ) struct { ?ReceiveTimeoutError, usize } {
1225 const result = io.operateTimeout(.{ .net_receive = .{1289 const result = io.operateTimeout(.{ .net_receive = .{
1226 .socket_handle = s.handle,1290 .socket_handle = s.handle,
1227 .message_buffer = message_buffer,1291 .message_buffer = message_buffer,
1228 .data_buffer = data_buffer,1292 .data_buffer = data_buffer,
1293 .control_buffer = control_buffer,
1229 .flags = flags,1294 .flags = flags,
1230 } }, timeout) catch |err| return .{ err, 0 };1295 } }, timeout) catch |err| return .{ err, 0 };
1231 return result.net_receive;1296 return result.net_receive;