| ... | @@ -10,8 +10,13 @@ const net = @This(); | ... | @@ -10,8 +10,13 @@ const net = @This(); |
| 10 | const mem = std.mem; | 10 | const mem = std.mem; |
| 11 | const os = std.os; | 11 | const os = std.os; |
| 12 | const fs = std.fs; | 12 | const fs = std.fs; |
| | 13 | const io = std.io; |
| 13 | | 14 | |
| 14 | pub const has_unix_sockets = @hasDecl(os, "sockaddr_un"); | 15 | // Windows 10 added support for unix sockets in build 17063, redstone 4 is the |
| | 16 | // first release to support them. |
| | 17 | pub const has_unix_sockets = @hasDecl(os, "sockaddr_un") and |
| | 18 | (builtin.os.tag != .windows or |
| | 19 | std.Target.current.os.version_range.windows.isAtLeast(.win10_rs4) orelse false); |
| 15 | | 20 | |
| 16 | pub const Address = extern union { | 21 | pub const Address = extern union { |
| 17 | any: os.sockaddr, | 22 | any: os.sockaddr, |
| ... | @@ -596,7 +601,7 @@ pub const Ip6Address = extern struct { | ... | @@ -596,7 +601,7 @@ pub const Ip6Address = extern struct { |
| 596 | } | 601 | } |
| 597 | }; | 602 | }; |
| 598 | | 603 | |
| 599 | pub fn connectUnixSocket(path: []const u8) !fs.File { | 604 | pub fn connectUnixSocket(path: []const u8) !Stream { |
| 600 | const opt_non_block = if (std.io.is_async) os.SOCK_NONBLOCK else 0; | 605 | const opt_non_block = if (std.io.is_async) os.SOCK_NONBLOCK else 0; |
| 601 | const sockfd = try os.socket( | 606 | const sockfd = try os.socket( |
| 602 | os.AF_UNIX, | 607 | os.AF_UNIX, |
| ... | @@ -614,7 +619,7 @@ pub fn connectUnixSocket(path: []const u8) !fs.File { | ... | @@ -614,7 +619,7 @@ pub fn connectUnixSocket(path: []const u8) !fs.File { |
| 614 | try os.connect(sockfd, &addr.any, addr.getOsSockLen()); | 619 | try os.connect(sockfd, &addr.any, addr.getOsSockLen()); |
| 615 | } | 620 | } |
| 616 | | 621 | |
| 617 | return fs.File{ | 622 | return Stream{ |
| 618 | .handle = sockfd, | 623 | .handle = sockfd, |
| 619 | }; | 624 | }; |
| 620 | } | 625 | } |
| ... | @@ -648,7 +653,7 @@ pub const AddressList = struct { | ... | @@ -648,7 +653,7 @@ pub const AddressList = struct { |
| 648 | }; | 653 | }; |
| 649 | | 654 | |
| 650 | /// All memory allocated with `allocator` will be freed before this function returns. | 655 | /// All memory allocated with `allocator` will be freed before this function returns. |
| 651 | pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) !fs.File { | 656 | pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) !Stream { |
| 652 | const list = try getAddressList(allocator, name, port); | 657 | const list = try getAddressList(allocator, name, port); |
| 653 | defer list.deinit(); | 658 | defer list.deinit(); |
| 654 | | 659 | |
| ... | @@ -665,7 +670,7 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) | ... | @@ -665,7 +670,7 @@ pub fn tcpConnectToHost(allocator: *mem.Allocator, name: []const u8, port: u16) |
| 665 | return std.os.ConnectError.ConnectionRefused; | 670 | return std.os.ConnectError.ConnectionRefused; |
| 666 | } | 671 | } |
| 667 | | 672 | |
| 668 | pub fn tcpConnectToAddress(address: Address) !fs.File { | 673 | pub fn tcpConnectToAddress(address: Address) !Stream { |
| 669 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; | 674 | const nonblock = if (std.io.is_async) os.SOCK_NONBLOCK else 0; |
| 670 | const sock_flags = os.SOCK_STREAM | nonblock | | 675 | const sock_flags = os.SOCK_STREAM | nonblock | |
| 671 | (if (builtin.os.tag == .windows) 0 else os.SOCK_CLOEXEC); | 676 | (if (builtin.os.tag == .windows) 0 else os.SOCK_CLOEXEC); |
| ... | @@ -679,7 +684,7 @@ pub fn tcpConnectToAddress(address: Address) !fs.File { | ... | @@ -679,7 +684,7 @@ pub fn tcpConnectToAddress(address: Address) !fs.File { |
| 679 | try os.connect(sockfd, &address.any, address.getOsSockLen()); | 684 | try os.connect(sockfd, &address.any, address.getOsSockLen()); |
| 680 | } | 685 | } |
| 681 | | 686 | |
| 682 | return fs.File{ .handle = sockfd }; | 687 | return Stream{ .handle = sockfd }; |
| 683 | } | 688 | } |
| 684 | | 689 | |
| 685 | /// Call `AddressList.deinit` on the result. | 690 | /// Call `AddressList.deinit` on the result. |
| ... | @@ -1580,6 +1585,55 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8) | ... | @@ -1580,6 +1585,55 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8) |
| 1580 | } | 1585 | } |
| 1581 | } | 1586 | } |
| 1582 | | 1587 | |
| | 1588 | pub const Stream = struct { |
| | 1589 | // Underlying socket descriptor. |
| | 1590 | // Note that on some platforms this may not be interchangeable with a |
| | 1591 | // regular files descriptor. |
| | 1592 | handle: os.socket_t, |
| | 1593 | |
| | 1594 | pub fn close(self: Stream) void { |
| | 1595 | os.closeSocket(self.handle); |
| | 1596 | } |
| | 1597 | |
| | 1598 | pub const ReadError = os.ReadError; |
| | 1599 | pub const WriteError = os.WriteError; |
| | 1600 | |
| | 1601 | pub const Reader = io.Reader(Stream, ReadError, read); |
| | 1602 | pub const Writer = io.Writer(Stream, WriteError, write); |
| | 1603 | |
| | 1604 | pub fn reader(self: Stream) Reader { |
| | 1605 | return .{ .context = self }; |
| | 1606 | } |
| | 1607 | |
| | 1608 | pub fn writer(self: Stream) Writer { |
| | 1609 | return .{ .context = self }; |
| | 1610 | } |
| | 1611 | |
| | 1612 | pub fn read(self: Stream, buffer: []u8) ReadError!usize { |
| | 1613 | if (std.Target.current.os.tag == .windows) { |
| | 1614 | return os.windows.ReadFile(self.handle, buffer, null, io.default_mode); |
| | 1615 | } |
| | 1616 | |
| | 1617 | if (std.io.is_async) { |
| | 1618 | return std.event.Loop.instance.?.read(self.handle, buffer, false); |
| | 1619 | } else { |
| | 1620 | return os.read(self.handle, buffer); |
| | 1621 | } |
| | 1622 | } |
| | 1623 | |
| | 1624 | pub fn write(self: Stream, buffer: []const u8) WriteError!usize { |
| | 1625 | if (std.Target.current.os.tag == .windows) { |
| | 1626 | return os.windows.WriteFile(self.handle, buffer, null, io.default_mode); |
| | 1627 | } |
| | 1628 | |
| | 1629 | if (std.io.is_async) { |
| | 1630 | return std.event.Loop.instance.?.write(self.handle, buffer, false); |
| | 1631 | } else { |
| | 1632 | return os.write(self.handle, buffer); |
| | 1633 | } |
| | 1634 | } |
| | 1635 | }; |
| | 1636 | |
| 1583 | pub const StreamServer = struct { | 1637 | pub const StreamServer = struct { |
| 1584 | /// Copied from `Options` on `init`. | 1638 | /// Copied from `Options` on `init`. |
| 1585 | kernel_backlog: u31, | 1639 | kernel_backlog: u31, |
| ... | @@ -1686,7 +1740,7 @@ pub const StreamServer = struct { | ... | @@ -1686,7 +1740,7 @@ pub const StreamServer = struct { |
| 1686 | } || os.UnexpectedError; | 1740 | } || os.UnexpectedError; |
| 1687 | | 1741 | |
| 1688 | pub const Connection = struct { | 1742 | pub const Connection = struct { |
| 1689 | file: fs.File, | 1743 | stream: Stream, |
| 1690 | address: Address, | 1744 | address: Address, |
| 1691 | }; | 1745 | }; |
| 1692 | | 1746 | |
| ... | @@ -1705,7 +1759,7 @@ pub const StreamServer = struct { | ... | @@ -1705,7 +1759,7 @@ pub const StreamServer = struct { |
| 1705 | | 1759 | |
| 1706 | if (accept_result) |fd| { | 1760 | if (accept_result) |fd| { |
| 1707 | return Connection{ | 1761 | return Connection{ |
| 1708 | .file = fs.File{ .handle = fd }, | 1762 | .stream = Stream{ .handle = fd }, |
| 1709 | .address = accepted_addr, | 1763 | .address = accepted_addr, |
| 1710 | }; | 1764 | }; |
| 1711 | } else |err| switch (err) { | 1765 | } else |err| switch (err) { |