| ... | ... | @@ -1431,8 +1431,8 @@ fn netReceive( |
| 1431 | 1431 | // the split vectors though because reducing the buffer size might make |
| 1432 | 1432 | // some messages unreceivable. |
| 1433 | 1433 | |
| 1434 | | // So the strategy instead is to use poll with timeout and then non-blocking |
| 1435 | | // recvmsg calls. |
| 1434 | // So the strategy instead is to use non-blocking recvmsg calls, calling |
| 1435 | // poll() with timeout if the first one returns EAGAIN. |
| 1436 | 1436 | const posix_flags: u32 = |
| 1437 | 1437 | @as(u32, if (flags.oob) posix.MSG.OOB else 0) | |
| 1438 | 1438 | @as(u32, if (flags.peek) posix.MSG.PEEK else 0) | |
| ... | ... | @@ -1449,93 +1449,92 @@ fn netReceive( |
| 1449 | 1449 | var message_i: usize = 0; |
| 1450 | 1450 | var data_i: usize = 0; |
| 1451 | 1451 | |
| 1452 | | // TODO: recvmsg first, then poll if EAGAIN. saves syscall in case the messages are already queued. |
| 1453 | | |
| 1454 | 1452 | const deadline = timeout.toDeadline(pool.io()) catch |err| return .{ err, message_i }; |
| 1455 | 1453 | |
| 1456 | | poll: while (true) { |
| 1454 | recv: while (true) { |
| 1457 | 1455 | pool.checkCancel() catch |err| return .{ err, message_i }; |
| 1458 | 1456 | |
| 1459 | | if (message_i > 0 or message_buffer.len - message_i == 0) return .{ null, message_i }; |
| 1460 | | |
| 1461 | | const max_poll_ms = std.math.maxInt(u31); |
| 1462 | | const timeout_ms: u31 = if (deadline) |d| t: { |
| 1463 | | const duration = d.durationFromNow(pool.io()) catch |err| return .{ err, message_i }; |
| 1464 | | if (duration.nanoseconds <= 0) return .{ error.Timeout, message_i }; |
| 1465 | | break :t @intCast(@min(max_poll_ms, duration.toMilliseconds())); |
| 1466 | | } else max_poll_ms; |
| 1457 | if (message_buffer.len - message_i == 0) return .{ null, message_i }; |
| 1458 | const message = &message_buffer[message_i]; |
| 1459 | const remaining_data_buffer = data_buffer[data_i..]; |
| 1460 | var storage: PosixAddress = undefined; |
| 1461 | var iov: posix.iovec = .{ .base = remaining_data_buffer.ptr, .len = remaining_data_buffer.len }; |
| 1462 | var msg: posix.msghdr = .{ |
| 1463 | .name = &storage.any, |
| 1464 | .namelen = @sizeOf(PosixAddress), |
| 1465 | .iov = (&iov)[0..1], |
| 1466 | .iovlen = 1, |
| 1467 | .control = message.control.ptr, |
| 1468 | .controllen = message.control.len, |
| 1469 | .flags = undefined, |
| 1470 | }; |
| 1467 | 1471 | |
| 1468 | | const poll_rc = posix.system.poll(&poll_fds, poll_fds.len, timeout_ms); |
| 1469 | | switch (posix.errno(poll_rc)) { |
| 1472 | const recv_rc = posix.system.recvmsg(handle, &msg, posix_flags); |
| 1473 | switch (posix.errno(recv_rc)) { |
| 1470 | 1474 | .SUCCESS => { |
| 1471 | | if (poll_rc == 0) { |
| 1472 | | // Possibly spurious timeout. |
| 1473 | | if (deadline == null) continue; |
| 1474 | | return .{ error.Timeout, message_i }; |
| 1475 | | } |
| 1476 | | |
| 1477 | | // Proceed to recvmsg. |
| 1478 | | while (true) { |
| 1479 | | pool.checkCancel() catch |err| return .{ err, message_i }; |
| 1480 | | |
| 1481 | | const message = &message_buffer[message_i]; |
| 1482 | | const remaining_data_buffer = data_buffer[data_i..]; |
| 1483 | | var storage: PosixAddress = undefined; |
| 1484 | | var iov: posix.iovec = .{ .base = remaining_data_buffer.ptr, .len = remaining_data_buffer.len }; |
| 1485 | | var msg: posix.msghdr = .{ |
| 1486 | | .name = &storage.any, |
| 1487 | | .namelen = @sizeOf(PosixAddress), |
| 1488 | | .iov = (&iov)[0..1], |
| 1489 | | .iovlen = 1, |
| 1490 | | .control = message.control.ptr, |
| 1491 | | .controllen = message.control.len, |
| 1492 | | .flags = undefined, |
| 1493 | | }; |
| 1494 | | |
| 1495 | | const rc = posix.system.recvmsg(handle, &msg, posix_flags); |
| 1496 | | switch (posix.errno(rc)) { |
| 1497 | | .SUCCESS => { |
| 1498 | | const data = remaining_data_buffer[0..@intCast(rc)]; |
| 1499 | | data_i += data.len; |
| 1500 | | message.* = .{ |
| 1501 | | .from = addressFromPosix(&storage), |
| 1502 | | .data = data, |
| 1503 | | .control = if (msg.control) |ptr| @as([*]u8, @ptrCast(ptr))[0..msg.controllen] else message.control, |
| 1504 | | .flags = .{ |
| 1505 | | .eor = (msg.flags & posix.MSG.EOR) != 0, |
| 1506 | | .trunc = (msg.flags & posix.MSG.TRUNC) != 0, |
| 1507 | | .ctrunc = (msg.flags & posix.MSG.CTRUNC) != 0, |
| 1508 | | .oob = (msg.flags & posix.MSG.OOB) != 0, |
| 1509 | | .errqueue = (msg.flags & posix.MSG.ERRQUEUE) != 0, |
| 1510 | | }, |
| 1511 | | }; |
| 1512 | | message_i += 1; |
| 1513 | | continue; |
| 1514 | | }, |
| 1515 | | .AGAIN => continue :poll, |
| 1516 | | .BADF => |err| return .{ errnoBug(err), message_i }, |
| 1517 | | .NFILE => return .{ error.SystemFdQuotaExceeded, message_i }, |
| 1518 | | .MFILE => return .{ error.ProcessFdQuotaExceeded, message_i }, |
| 1519 | | .INTR => continue, |
| 1520 | | .FAULT => |err| return .{ errnoBug(err), message_i }, |
| 1521 | | .INVAL => |err| return .{ errnoBug(err), message_i }, |
| 1522 | | .NOBUFS => return .{ error.SystemResources, message_i }, |
| 1523 | | .NOMEM => return .{ error.SystemResources, message_i }, |
| 1524 | | .NOTCONN => return .{ error.SocketUnconnected, message_i }, |
| 1525 | | .NOTSOCK => |err| return .{ errnoBug(err), message_i }, |
| 1526 | | .MSGSIZE => return .{ error.MessageOversize, message_i }, |
| 1527 | | .PIPE => return .{ error.SocketUnconnected, message_i }, |
| 1528 | | .OPNOTSUPP => |err| return .{ errnoBug(err), message_i }, |
| 1529 | | .CONNRESET => return .{ error.ConnectionResetByPeer, message_i }, |
| 1530 | | .NETDOWN => return .{ error.NetworkDown, message_i }, |
| 1531 | | else => |err| return .{ posix.unexpectedErrno(err), message_i }, |
| 1532 | | } |
| 1475 | const data = remaining_data_buffer[0..@intCast(recv_rc)]; |
| 1476 | data_i += data.len; |
| 1477 | message.* = .{ |
| 1478 | .from = addressFromPosix(&storage), |
| 1479 | .data = data, |
| 1480 | .control = if (msg.control) |ptr| @as([*]u8, @ptrCast(ptr))[0..msg.controllen] else message.control, |
| 1481 | .flags = .{ |
| 1482 | .eor = (msg.flags & posix.MSG.EOR) != 0, |
| 1483 | .trunc = (msg.flags & posix.MSG.TRUNC) != 0, |
| 1484 | .ctrunc = (msg.flags & posix.MSG.CTRUNC) != 0, |
| 1485 | .oob = (msg.flags & posix.MSG.OOB) != 0, |
| 1486 | .errqueue = (msg.flags & posix.MSG.ERRQUEUE) != 0, |
| 1487 | }, |
| 1488 | }; |
| 1489 | message_i += 1; |
| 1490 | continue; |
| 1491 | }, |
| 1492 | .AGAIN => while (true) { |
| 1493 | pool.checkCancel() catch |err| return .{ err, message_i }; |
| 1494 | if (message_i != 0) return .{ null, message_i }; |
| 1495 | |
| 1496 | const max_poll_ms = std.math.maxInt(u31); |
| 1497 | const timeout_ms: u31 = if (deadline) |d| t: { |
| 1498 | const duration = d.durationFromNow(pool.io()) catch |err| return .{ err, message_i }; |
| 1499 | if (duration.nanoseconds <= 0) return .{ error.Timeout, message_i }; |
| 1500 | break :t @intCast(@min(max_poll_ms, duration.toMilliseconds())); |
| 1501 | } else max_poll_ms; |
| 1502 | |
| 1503 | const poll_rc = posix.system.poll(&poll_fds, poll_fds.len, timeout_ms); |
| 1504 | switch (posix.errno(poll_rc)) { |
| 1505 | .SUCCESS => { |
| 1506 | if (poll_rc == 0) { |
| 1507 | // Although spurious timeouts are OK, when no deadline |
| 1508 | // is passed we must not return `error.Timeout`. |
| 1509 | if (deadline == null) continue; |
| 1510 | return .{ error.Timeout, message_i }; |
| 1511 | } |
| 1512 | continue :recv; |
| 1513 | }, |
| 1514 | .INTR => continue, |
| 1515 | |
| 1516 | .FAULT => |err| return .{ errnoBug(err), message_i }, |
| 1517 | .INVAL => |err| return .{ errnoBug(err), message_i }, |
| 1518 | .NOMEM => return .{ error.SystemResources, message_i }, |
| 1519 | else => |err| return .{ posix.unexpectedErrno(err), message_i }, |
| 1533 | 1520 | } |
| 1534 | 1521 | }, |
| 1535 | 1522 | .INTR => continue, |
| 1523 | |
| 1524 | .BADF => |err| return .{ errnoBug(err), message_i }, |
| 1525 | .NFILE => return .{ error.SystemFdQuotaExceeded, message_i }, |
| 1526 | .MFILE => return .{ error.ProcessFdQuotaExceeded, message_i }, |
| 1536 | 1527 | .FAULT => |err| return .{ errnoBug(err), message_i }, |
| 1537 | 1528 | .INVAL => |err| return .{ errnoBug(err), message_i }, |
| 1529 | .NOBUFS => return .{ error.SystemResources, message_i }, |
| 1538 | 1530 | .NOMEM => return .{ error.SystemResources, message_i }, |
| 1531 | .NOTCONN => return .{ error.SocketUnconnected, message_i }, |
| 1532 | .NOTSOCK => |err| return .{ errnoBug(err), message_i }, |
| 1533 | .MSGSIZE => return .{ error.MessageOversize, message_i }, |
| 1534 | .PIPE => return .{ error.SocketUnconnected, message_i }, |
| 1535 | .OPNOTSUPP => |err| return .{ errnoBug(err), message_i }, |
| 1536 | .CONNRESET => return .{ error.ConnectionResetByPeer, message_i }, |
| 1537 | .NETDOWN => return .{ error.NetworkDown, message_i }, |
| 1539 | 1538 | else => |err| return .{ posix.unexpectedErrno(err), message_i }, |
| 1540 | 1539 | } |
| 1541 | 1540 | } |