Skip to content

Commit edb1663

Browse files
committed
std.os: add support for socketpair
1 parent 42389cb commit edb1663

File tree

6 files changed

+95
-7
lines changed

6 files changed

+95
-7
lines changed

lib/std/c.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ pub usingnamespace switch (builtin.os.tag) {
7777
pub extern "c" fn sigfillset(set: ?*c.sigset_t) void;
7878
pub extern "c" fn sigwait(set: ?*c.sigset_t, sig: ?*c_int) c_int;
7979

80-
pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
80+
pub extern "c" fn socket(domain: c_int, sock_type: c_int, protocol: c_int) c_int;
8181

8282
pub extern "c" fn stat(noalias path: [*:0]const u8, noalias buf: *c.Stat) c_int;
8383

@@ -185,7 +185,7 @@ pub extern "c" fn uname(buf: *c.utsname) c_int;
185185
pub extern "c" fn gethostname(name: [*]u8, len: usize) c_int;
186186
pub extern "c" fn shutdown(socket: c.fd_t, how: c_int) c_int;
187187
pub extern "c" fn bind(socket: c.fd_t, address: ?*const c.sockaddr, address_len: c.socklen_t) c_int;
188-
pub extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint, sv: *[2]c.fd_t) c_int;
188+
pub extern "c" fn socketpair(domain: c_int, sock_type: c_int, protocol: c_int, sv: *[2]c.fd_t) c_int;
189189
pub extern "c" fn listen(sockfd: c.fd_t, backlog: c_uint) c_int;
190190
pub extern "c" fn getsockname(sockfd: c.fd_t, noalias addr: *c.sockaddr, noalias addrlen: *c.socklen_t) c_int;
191191
pub extern "c" fn getpeername(sockfd: c.fd_t, noalias addr: *c.sockaddr, noalias addrlen: *c.socklen_t) c_int;

lib/std/net.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1928,7 +1928,7 @@ pub const StreamServer = struct {
19281928
pub fn listen(self: *StreamServer, address: Address) !void {
19291929
const nonblock = if (std.io.is_async) os.SOCK.NONBLOCK else 0;
19301930
const sock_flags = os.SOCK.STREAM | os.SOCK.CLOEXEC | nonblock;
1931-
var use_sock_flags: u32 = sock_flags;
1931+
var use_sock_flags: i32 = sock_flags;
19321932
if (self.force_nonblocking) use_sock_flags |= os.SOCK.NONBLOCK;
19331933
const proto = if (address.any.family == os.AF.UNIX) @as(u32, 0) else os.IPPROTO.TCP;
19341934

lib/std/os.zig

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3377,7 +3377,7 @@ pub const SocketError = error{
33773377
SocketTypeNotSupported,
33783378
} || UnexpectedError;
33793379

3380-
pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!socket_t {
3380+
pub fn socket(domain: i32, socket_type: i32, protocol: i32) SocketError!socket_t {
33813381
if (builtin.os.tag == .windows) {
33823382
// NOTE: windows translates the SOCK.NONBLOCK/SOCK.CLOEXEC flags into
33833383
// windows-analagous operations
@@ -6671,7 +6671,8 @@ pub fn recvfrom(
66716671
addrlen: ?*socklen_t,
66726672
) RecvFromError!usize {
66736673
while (true) {
6674-
const rc = system.recvfrom(sockfd, buf.ptr, buf.len, flags, src_addr, addrlen);
6674+
const sys = if (builtin.os.tag == .windows) windows else system;
6675+
const rc = sys.recvfrom(sockfd, buf.ptr, buf.len, flags, src_addr, addrlen);
66756676
if (builtin.os.tag == .windows) {
66766677
if (rc == windows.ws2_32.SOCKET_ERROR) {
66776678
switch (windows.ws2_32.WSAGetLastError()) {
@@ -7393,3 +7394,29 @@ pub fn ptrace(request: u32, pid: pid_t, addr: usize, signal: usize) PtraceError!
73937394
}
73947395

73957396
const lfs64_abi = builtin.os.tag == .linux and builtin.link_libc and builtin.abi.isGnu();
7397+
7398+
const SocketpairError = SocketError || error{OperationNotSupported};
7399+
7400+
/// On platforms not supporting socketpair (Windows), socketpair is emulated.
7401+
/// On Windows, only `AF_UNIX` and `SOCK_STREAM` are supported.
7402+
pub fn socketpair(domain: i32, sock_type: i32, protocol: i32) SocketpairError![2]socket_t {
7403+
var pair: [2]socket_t = undefined;
7404+
7405+
if (builtin.os.tag == .windows) {
7406+
@compileError("socketpair is unsupported on Windows");
7407+
}
7408+
7409+
return switch (system.getErrno(system.socketpair(domain, sock_type, protocol, &pair))) {
7410+
E.SUCCESS => pair,
7411+
E.AFNOSUPPORT => error.AddressFamilyNotSupported,
7412+
E.MFILE => error.ProcessFdQuotaExceeded,
7413+
E.NFILE => error.SystemFdQuotaExceeded,
7414+
E.OPNOTSUPP => error.OperationNotSupported,
7415+
E.PROTONOSUPPORT => error.ProtocolNotSupported,
7416+
E.PROTOTYPE => error.SocketTypeNotSupported,
7417+
E.NOBUFS => error.SystemResources,
7418+
E.NOMEM => error.SystemResources,
7419+
E.FAULT => unreachable, // we own `pair`
7420+
else => error.Unexpected,
7421+
};
7422+
}

lib/std/os/linux.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1268,11 +1268,11 @@ pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) us
12681268
return syscall3(.getpeername, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(addr), @intFromPtr(len));
12691269
}
12701270

1271-
pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
1271+
pub fn socket(domain: i32, socket_type: i32, protocol: i32) usize {
12721272
if (native_arch == .x86) {
12731273
return socketcall(SC.socket, &[3]usize{ domain, socket_type, protocol });
12741274
}
1275-
return syscall3(.socket, domain, socket_type, protocol);
1275+
return syscall3(.socket, @intCast(domain), @intCast(socket_type), @intCast(protocol));
12761276
}
12771277

12781278
pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize {

lib/std/os/test.zig

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,3 +1230,62 @@ test "fchmodat smoke test" {
12301230
const st = try os.fstatat(tmp.dir.fd, "foo.txt", 0);
12311231
try expectEqual(@as(os.mode_t, 0o755), st.mode & 0b111_111_111);
12321232
}
1233+
1234+
fn writeSocketTest(socket: os.socket_t, err: *?anyerror) void {
1235+
const buf = "Hello, World!";
1236+
var i: usize = 0;
1237+
while (i < buf.len) {
1238+
const nb_sent = std.os.send(socket, buf[i..], 0) catch |e| {
1239+
err.* = e;
1240+
return;
1241+
};
1242+
i += nb_sent;
1243+
}
1244+
}
1245+
1246+
fn readSocketTest(socket: os.socket_t, err: *?anyerror) void {
1247+
var buf: [13]u8 = undefined;
1248+
var i: usize = 0;
1249+
1250+
while (i < buf.len) {
1251+
const nb_recved = std.os.recv(socket, buf[i..], 0) catch |e| {
1252+
err.* = e;
1253+
return;
1254+
};
1255+
i += nb_recved;
1256+
}
1257+
1258+
testing.expectEqualSlices(u8, &buf, "Hello, World!") catch |e| {
1259+
err.* = e;
1260+
};
1261+
}
1262+
1263+
test "socketpair" {
1264+
if (builtin.single_threaded) return error.SkipZigTest;
1265+
1266+
const pair = try os.socketpair(os.AF.UNIX, os.SOCK.STREAM, 0);
1267+
defer os.close(pair[0]);
1268+
defer os.close(pair[1]);
1269+
1270+
const ally = testing.allocator;
1271+
1272+
var wr_err: ?anyerror = null;
1273+
const writer = try std.Thread.spawn(
1274+
.{ .allocator = ally },
1275+
writeSocketTest,
1276+
.{ pair[0], &wr_err },
1277+
);
1278+
1279+
var rd_err: ?anyerror = null;
1280+
const reader = try std.Thread.spawn(
1281+
.{ .allocator = ally },
1282+
readSocketTest,
1283+
.{ pair[1], &rd_err },
1284+
);
1285+
1286+
writer.join();
1287+
if (wr_err) |e| return e;
1288+
1289+
reader.join();
1290+
if (rd_err) |e| return e;
1291+
}

lib/std/os/windows/kernel32.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,3 +451,5 @@ pub extern "kernel32" fn RegOpenKeyExW(
451451
) callconv(WINAPI) LSTATUS;
452452

453453
pub extern "kernel32" fn GetPhysicallyInstalledSystemMemory(TotalMemoryInKilobytes: *ULONGLONG) BOOL;
454+
455+
pub extern "kernel32" fn GetTempPathA(nBufferLength: DWORD, lpBuffer: LPSTR) callconv(WINAPI) DWORD;

0 commit comments

Comments
 (0)