| author | |
| committer | |
| log | 20355494085a6eb59b73816038a5d0c56b5492c6 |
| tree | 07234e26640c2f1626046fb5853d199e8af45a9a |
| parent | 8909d25b365de94d4b37c613ce3276634765a86b |
| signature | Commit is signed but in an unrecognized format. |
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, |
| 350 | 351 | ||
| 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 error | 3282 | // 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 | } |
| 13214 | 13217 | ||
| 13215 | fn netReceivePosix( | 13218 | fn 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 | }; |
| 13245 | 13249 | ||
| 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; | ||
| 5082 | 5084 | ||
| 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 | }; |
| 5098 | 5101 | ||
| ... | @@ -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 | }; |
| 926 | 926 | ||
| 927 | /// Fields are populated by receive functions. | ||
| 927 | pub const IncomingMessage = struct { | 928 | pub 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 receive | 932 | /// Points into caller-supplied buffer. |
| 933 | /// functions. | ||
| 934 | control: []u8, | 933 | control: []u8, |
| 935 | /// Populated by receive functions. | ||
| 936 | flags: Flags, | 934 | flags: Flags, |
| 937 | 935 | ||
| 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 | }; |
| 945 | 943 | ||
| ... | @@ -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; |