| author | |
| committer | |
| log | bdf463bee2becd84b83bb9d66725420e03680df8 |
| tree | c0a51d328eb42e28ec9315171c0f58d1f803bdc8 |
| parent | 07cc4077fba5701ef582e17c795f9f5214915179 |
5 files changed, 302 insertions(+), 56 deletions(-)
lib/std/Io.zig+8-3| ... | @@ -660,7 +660,7 @@ pub const VTable = struct { | ... | @@ -660,7 +660,7 @@ pub const VTable = struct { |
| 660 | 660 | ||
| 661 | listen: *const fn (?*anyopaque, address: net.IpAddress, options: net.ListenOptions) net.ListenError!net.Server, | 661 | listen: *const fn (?*anyopaque, address: net.IpAddress, options: net.ListenOptions) net.ListenError!net.Server, |
| 662 | accept: *const fn (?*anyopaque, server: *net.Server) net.Server.AcceptError!net.Server.Connection, | 662 | accept: *const fn (?*anyopaque, server: *net.Server) net.Server.AcceptError!net.Server.Connection, |
| 663 | netRead: *const fn (?*anyopaque, src: net.Stream, dest: *Io.Writer, limit: Io.Limit) net.Stream.Reader.Error!usize, | 663 | netRead: *const fn (?*anyopaque, src: net.Stream, data: [][]u8) net.Stream.Reader.Error!usize, |
| 664 | netWrite: *const fn (?*anyopaque, dest: net.Stream, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize, | 664 | netWrite: *const fn (?*anyopaque, dest: net.Stream, header: []const u8, data: []const []const u8, splat: usize) net.Stream.Writer.Error!usize, |
| 665 | netClose: *const fn (?*anyopaque, stream: net.Stream) void, | 665 | netClose: *const fn (?*anyopaque, stream: net.Stream) void, |
| 666 | }; | 666 | }; |
| ... | @@ -760,6 +760,11 @@ pub const File = struct { | ... | @@ -760,6 +760,11 @@ pub const File = struct { |
| 760 | } | 760 | } |
| 761 | return index; | 761 | return index; |
| 762 | } | 762 | } |
| 763 | |||
| 764 | pub fn openAbsolute(io: Io, absolute_path: []const u8, flags: OpenFlags) OpenError { | ||
| 765 | assert(std.fs.path.isAbsolute(absolute_path)); | ||
| 766 | return Dir.cwd().openFile(io, absolute_path, flags); | ||
| 767 | } | ||
| 763 | }; | 768 | }; |
| 764 | 769 | ||
| 765 | pub const Timestamp = enum(i96) { | 770 | pub const Timestamp = enum(i96) { |
| ... | @@ -1205,7 +1210,7 @@ pub fn asyncConcurrent( | ... | @@ -1205,7 +1210,7 @@ pub fn asyncConcurrent( |
| 1205 | const Args = @TypeOf(args); | 1210 | const Args = @TypeOf(args); |
| 1206 | const TypeErased = struct { | 1211 | const TypeErased = struct { |
| 1207 | fn start(context: *const anyopaque, result: *anyopaque) void { | 1212 | fn start(context: *const anyopaque, result: *anyopaque) void { |
| 1208 | const args_casted: *const Args = @alignCast(@ptrCast(context)); | 1213 | const args_casted: *const Args = @ptrCast(@alignCast(context)); |
| 1209 | const result_casted: *Result = @ptrCast(@alignCast(result)); | 1214 | const result_casted: *Result = @ptrCast(@alignCast(result)); |
| 1210 | result_casted.* = @call(.auto, function, args_casted.*); | 1215 | result_casted.* = @call(.auto, function, args_casted.*); |
| 1211 | } | 1216 | } |
| ... | @@ -1234,7 +1239,7 @@ pub fn asyncDetached(io: Io, function: anytype, args: std.meta.ArgsTuple(@TypeOf | ... | @@ -1234,7 +1239,7 @@ pub fn asyncDetached(io: Io, function: anytype, args: std.meta.ArgsTuple(@TypeOf |
| 1234 | const Args = @TypeOf(args); | 1239 | const Args = @TypeOf(args); |
| 1235 | const TypeErased = struct { | 1240 | const TypeErased = struct { |
| 1236 | fn start(context: *const anyopaque) void { | 1241 | fn start(context: *const anyopaque) void { |
| 1237 | const args_casted: *const Args = @alignCast(@ptrCast(context)); | 1242 | const args_casted: *const Args = @ptrCast(@alignCast(context)); |
| 1238 | @call(.auto, function, args_casted.*); | 1243 | @call(.auto, function, args_casted.*); |
| 1239 | } | 1244 | } |
| 1240 | }; | 1245 | }; |
lib/std/Io/ThreadPool.zig+34-31| ... | @@ -233,7 +233,7 @@ fn async( | ... | @@ -233,7 +233,7 @@ fn async( |
| 233 | start(context.ptr, result.ptr); | 233 | start(context.ptr, result.ptr); |
| 234 | return null; | 234 | return null; |
| 235 | } | 235 | } |
| 236 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 236 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 237 | const cpu_count = pool.cpu_count catch { | 237 | const cpu_count = pool.cpu_count catch { |
| 238 | return asyncConcurrent(userdata, result.len, result_alignment, context, context_alignment, start) catch { | 238 | return asyncConcurrent(userdata, result.len, result_alignment, context, context_alignment, start) catch { |
| 239 | start(context.ptr, result.ptr); | 239 | start(context.ptr, result.ptr); |
| ... | @@ -244,7 +244,7 @@ fn async( | ... | @@ -244,7 +244,7 @@ fn async( |
| 244 | const context_offset = context_alignment.forward(@sizeOf(AsyncClosure)); | 244 | const context_offset = context_alignment.forward(@sizeOf(AsyncClosure)); |
| 245 | const result_offset = result_alignment.forward(context_offset + context.len); | 245 | const result_offset = result_alignment.forward(context_offset + context.len); |
| 246 | const n = result_offset + result.len; | 246 | const n = result_offset + result.len; |
| 247 | const closure: *AsyncClosure = @alignCast(@ptrCast(gpa.alignedAlloc(u8, .of(AsyncClosure), n) catch { | 247 | const closure: *AsyncClosure = @ptrCast(@alignCast(gpa.alignedAlloc(u8, .of(AsyncClosure), n) catch { |
| 248 | start(context.ptr, result.ptr); | 248 | start(context.ptr, result.ptr); |
| 249 | return null; | 249 | return null; |
| 250 | })); | 250 | })); |
| ... | @@ -309,13 +309,13 @@ fn asyncConcurrent( | ... | @@ -309,13 +309,13 @@ fn asyncConcurrent( |
| 309 | ) error{OutOfMemory}!*Io.AnyFuture { | 309 | ) error{OutOfMemory}!*Io.AnyFuture { |
| 310 | if (builtin.single_threaded) unreachable; | 310 | if (builtin.single_threaded) unreachable; |
| 311 | 311 | ||
| 312 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 312 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 313 | const cpu_count = pool.cpu_count catch 1; | 313 | const cpu_count = pool.cpu_count catch 1; |
| 314 | const gpa = pool.allocator; | 314 | const gpa = pool.allocator; |
| 315 | const context_offset = context_alignment.forward(@sizeOf(AsyncClosure)); | 315 | const context_offset = context_alignment.forward(@sizeOf(AsyncClosure)); |
| 316 | const result_offset = result_alignment.forward(context_offset + context.len); | 316 | const result_offset = result_alignment.forward(context_offset + context.len); |
| 317 | const n = result_offset + result_len; | 317 | const n = result_offset + result_len; |
| 318 | const closure: *AsyncClosure = @alignCast(@ptrCast(try gpa.alignedAlloc(u8, .of(AsyncClosure), n))); | 318 | const closure: *AsyncClosure = @ptrCast(@alignCast(try gpa.alignedAlloc(u8, .of(AsyncClosure), n))); |
| 319 | 319 | ||
| 320 | closure.* = .{ | 320 | closure.* = .{ |
| 321 | .func = start, | 321 | .func = start, |
| ... | @@ -399,11 +399,11 @@ fn asyncDetached( | ... | @@ -399,11 +399,11 @@ fn asyncDetached( |
| 399 | start: *const fn (context: *const anyopaque) void, | 399 | start: *const fn (context: *const anyopaque) void, |
| 400 | ) void { | 400 | ) void { |
| 401 | if (builtin.single_threaded) return start(context.ptr); | 401 | if (builtin.single_threaded) return start(context.ptr); |
| 402 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 402 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 403 | const cpu_count = pool.cpu_count catch 1; | 403 | const cpu_count = pool.cpu_count catch 1; |
| 404 | const gpa = pool.allocator; | 404 | const gpa = pool.allocator; |
| 405 | const n = DetachedClosure.contextEnd(context_alignment, context.len); | 405 | const n = DetachedClosure.contextEnd(context_alignment, context.len); |
| 406 | const closure: *DetachedClosure = @alignCast(@ptrCast(gpa.alignedAlloc(u8, .of(DetachedClosure), n) catch { | 406 | const closure: *DetachedClosure = @ptrCast(@alignCast(gpa.alignedAlloc(u8, .of(DetachedClosure), n) catch { |
| 407 | return start(context.ptr); | 407 | return start(context.ptr); |
| 408 | })); | 408 | })); |
| 409 | closure.* = .{ | 409 | closure.* = .{ |
| ... | @@ -451,7 +451,7 @@ fn await( | ... | @@ -451,7 +451,7 @@ fn await( |
| 451 | result_alignment: std.mem.Alignment, | 451 | result_alignment: std.mem.Alignment, |
| 452 | ) void { | 452 | ) void { |
| 453 | _ = result_alignment; | 453 | _ = result_alignment; |
| 454 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 454 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 455 | const closure: *AsyncClosure = @ptrCast(@alignCast(any_future)); | 455 | const closure: *AsyncClosure = @ptrCast(@alignCast(any_future)); |
| 456 | closure.waitAndFree(pool.allocator, result); | 456 | closure.waitAndFree(pool.allocator, result); |
| 457 | } | 457 | } |
| ... | @@ -463,7 +463,7 @@ fn cancel( | ... | @@ -463,7 +463,7 @@ fn cancel( |
| 463 | result_alignment: std.mem.Alignment, | 463 | result_alignment: std.mem.Alignment, |
| 464 | ) void { | 464 | ) void { |
| 465 | _ = result_alignment; | 465 | _ = result_alignment; |
| 466 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 466 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 467 | const closure: *AsyncClosure = @ptrCast(@alignCast(any_future)); | 467 | const closure: *AsyncClosure = @ptrCast(@alignCast(any_future)); |
| 468 | switch (@atomicRmw( | 468 | switch (@atomicRmw( |
| 469 | std.Thread.Id, | 469 | std.Thread.Id, |
| ... | @@ -486,7 +486,7 @@ fn cancel( | ... | @@ -486,7 +486,7 @@ fn cancel( |
| 486 | } | 486 | } |
| 487 | 487 | ||
| 488 | fn cancelRequested(userdata: ?*anyopaque) bool { | 488 | fn cancelRequested(userdata: ?*anyopaque) bool { |
| 489 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 489 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 490 | _ = pool; | 490 | _ = pool; |
| 491 | const closure = current_closure orelse return false; | 491 | const closure = current_closure orelse return false; |
| 492 | return @atomicLoad(std.Thread.Id, &closure.cancel_tid, .acquire) == AsyncClosure.canceling_tid; | 492 | return @atomicLoad(std.Thread.Id, &closure.cancel_tid, .acquire) == AsyncClosure.canceling_tid; |
| ... | @@ -520,7 +520,7 @@ fn mutexUnlock(userdata: ?*anyopaque, prev_state: Io.Mutex.State, mutex: *Io.Mut | ... | @@ -520,7 +520,7 @@ fn mutexUnlock(userdata: ?*anyopaque, prev_state: Io.Mutex.State, mutex: *Io.Mut |
| 520 | } | 520 | } |
| 521 | 521 | ||
| 522 | fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) Io.Cancelable!void { | 522 | fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) Io.Cancelable!void { |
| 523 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 523 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 524 | comptime assert(@TypeOf(cond.state) == u64); | 524 | comptime assert(@TypeOf(cond.state) == u64); |
| 525 | const ints: *[2]std.atomic.Value(u32) = @ptrCast(&cond.state); | 525 | const ints: *[2]std.atomic.Value(u32) = @ptrCast(&cond.state); |
| 526 | const cond_state = &ints[0]; | 526 | const cond_state = &ints[0]; |
| ... | @@ -567,7 +567,7 @@ fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) I | ... | @@ -567,7 +567,7 @@ fn conditionWait(userdata: ?*anyopaque, cond: *Io.Condition, mutex: *Io.Mutex) I |
| 567 | } | 567 | } |
| 568 | 568 | ||
| 569 | fn conditionWake(userdata: ?*anyopaque, cond: *Io.Condition, wake: Io.Condition.Wake) void { | 569 | fn conditionWake(userdata: ?*anyopaque, cond: *Io.Condition, wake: Io.Condition.Wake) void { |
| 570 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 570 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 571 | _ = pool; | 571 | _ = pool; |
| 572 | comptime assert(@TypeOf(cond.state) == u64); | 572 | comptime assert(@TypeOf(cond.state) == u64); |
| 573 | const ints: *[2]std.atomic.Value(u32) = @ptrCast(&cond.state); | 573 | const ints: *[2]std.atomic.Value(u32) = @ptrCast(&cond.state); |
| ... | @@ -624,7 +624,7 @@ fn createFile( | ... | @@ -624,7 +624,7 @@ fn createFile( |
| 624 | sub_path: []const u8, | 624 | sub_path: []const u8, |
| 625 | flags: Io.File.CreateFlags, | 625 | flags: Io.File.CreateFlags, |
| 626 | ) Io.File.OpenError!Io.File { | 626 | ) Io.File.OpenError!Io.File { |
| 627 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 627 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 628 | try pool.checkCancel(); | 628 | try pool.checkCancel(); |
| 629 | const fs_dir: std.fs.Dir = .{ .fd = dir.handle }; | 629 | const fs_dir: std.fs.Dir = .{ .fd = dir.handle }; |
| 630 | const fs_file = try fs_dir.createFile(sub_path, flags); | 630 | const fs_file = try fs_dir.createFile(sub_path, flags); |
| ... | @@ -637,7 +637,7 @@ fn openFile( | ... | @@ -637,7 +637,7 @@ fn openFile( |
| 637 | sub_path: []const u8, | 637 | sub_path: []const u8, |
| 638 | flags: Io.File.OpenFlags, | 638 | flags: Io.File.OpenFlags, |
| 639 | ) Io.File.OpenError!Io.File { | 639 | ) Io.File.OpenError!Io.File { |
| 640 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 640 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 641 | try pool.checkCancel(); | 641 | try pool.checkCancel(); |
| 642 | const fs_dir: std.fs.Dir = .{ .fd = dir.handle }; | 642 | const fs_dir: std.fs.Dir = .{ .fd = dir.handle }; |
| 643 | const fs_file = try fs_dir.openFile(sub_path, flags); | 643 | const fs_file = try fs_dir.openFile(sub_path, flags); |
| ... | @@ -645,14 +645,14 @@ fn openFile( | ... | @@ -645,14 +645,14 @@ fn openFile( |
| 645 | } | 645 | } |
| 646 | 646 | ||
| 647 | fn closeFile(userdata: ?*anyopaque, file: Io.File) void { | 647 | fn closeFile(userdata: ?*anyopaque, file: Io.File) void { |
| 648 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 648 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 649 | _ = pool; | 649 | _ = pool; |
| 650 | const fs_file: std.fs.File = .{ .handle = file.handle }; | 650 | const fs_file: std.fs.File = .{ .handle = file.handle }; |
| 651 | return fs_file.close(); | 651 | return fs_file.close(); |
| 652 | } | 652 | } |
| 653 | 653 | ||
| 654 | fn pread(userdata: ?*anyopaque, file: Io.File, buffer: []u8, offset: posix.off_t) Io.File.PReadError!usize { | 654 | fn pread(userdata: ?*anyopaque, file: Io.File, buffer: []u8, offset: posix.off_t) Io.File.PReadError!usize { |
| 655 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 655 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 656 | try pool.checkCancel(); | 656 | try pool.checkCancel(); |
| 657 | const fs_file: std.fs.File = .{ .handle = file.handle }; | 657 | const fs_file: std.fs.File = .{ .handle = file.handle }; |
| 658 | return switch (offset) { | 658 | return switch (offset) { |
| ... | @@ -662,7 +662,7 @@ fn pread(userdata: ?*anyopaque, file: Io.File, buffer: []u8, offset: posix.off_t | ... | @@ -662,7 +662,7 @@ fn pread(userdata: ?*anyopaque, file: Io.File, buffer: []u8, offset: posix.off_t |
| 662 | } | 662 | } |
| 663 | 663 | ||
| 664 | fn pwrite(userdata: ?*anyopaque, file: Io.File, buffer: []const u8, offset: posix.off_t) Io.File.PWriteError!usize { | 664 | fn pwrite(userdata: ?*anyopaque, file: Io.File, buffer: []const u8, offset: posix.off_t) Io.File.PWriteError!usize { |
| 665 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 665 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 666 | try pool.checkCancel(); | 666 | try pool.checkCancel(); |
| 667 | const fs_file: std.fs.File = .{ .handle = file.handle }; | 667 | const fs_file: std.fs.File = .{ .handle = file.handle }; |
| 668 | return switch (offset) { | 668 | return switch (offset) { |
| ... | @@ -672,14 +672,14 @@ fn pwrite(userdata: ?*anyopaque, file: Io.File, buffer: []const u8, offset: posi | ... | @@ -672,14 +672,14 @@ fn pwrite(userdata: ?*anyopaque, file: Io.File, buffer: []const u8, offset: posi |
| 672 | } | 672 | } |
| 673 | 673 | ||
| 674 | fn now(userdata: ?*anyopaque, clockid: posix.clockid_t) Io.ClockGetTimeError!Io.Timestamp { | 674 | fn now(userdata: ?*anyopaque, clockid: posix.clockid_t) Io.ClockGetTimeError!Io.Timestamp { |
| 675 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 675 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 676 | try pool.checkCancel(); | 676 | try pool.checkCancel(); |
| 677 | const timespec = try posix.clock_gettime(clockid); | 677 | const timespec = try posix.clock_gettime(clockid); |
| 678 | return @enumFromInt(@as(i128, timespec.sec) * std.time.ns_per_s + timespec.nsec); | 678 | return @enumFromInt(@as(i128, timespec.sec) * std.time.ns_per_s + timespec.nsec); |
| 679 | } | 679 | } |
| 680 | 680 | ||
| 681 | fn sleep(userdata: ?*anyopaque, clockid: posix.clockid_t, deadline: Io.Deadline) Io.SleepError!void { | 681 | fn sleep(userdata: ?*anyopaque, clockid: posix.clockid_t, deadline: Io.Deadline) Io.SleepError!void { |
| 682 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 682 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 683 | const deadline_nanoseconds: i96 = switch (deadline) { | 683 | const deadline_nanoseconds: i96 = switch (deadline) { |
| 684 | .duration => |duration| duration.nanoseconds, | 684 | .duration => |duration| duration.nanoseconds, |
| 685 | .timestamp => |timestamp| @intFromEnum(timestamp), | 685 | .timestamp => |timestamp| @intFromEnum(timestamp), |
| ... | @@ -704,7 +704,7 @@ fn sleep(userdata: ?*anyopaque, clockid: posix.clockid_t, deadline: Io.Deadline) | ... | @@ -704,7 +704,7 @@ fn sleep(userdata: ?*anyopaque, clockid: posix.clockid_t, deadline: Io.Deadline) |
| 704 | } | 704 | } |
| 705 | 705 | ||
| 706 | fn select(userdata: ?*anyopaque, futures: []const *Io.AnyFuture) usize { | 706 | fn select(userdata: ?*anyopaque, futures: []const *Io.AnyFuture) usize { |
| 707 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 707 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 708 | _ = pool; | 708 | _ = pool; |
| 709 | 709 | ||
| 710 | var reset_event: std.Thread.ResetEvent = .{}; | 710 | var reset_event: std.Thread.ResetEvent = .{}; |
| ... | @@ -736,7 +736,7 @@ fn select(userdata: ?*anyopaque, futures: []const *Io.AnyFuture) usize { | ... | @@ -736,7 +736,7 @@ fn select(userdata: ?*anyopaque, futures: []const *Io.AnyFuture) usize { |
| 736 | } | 736 | } |
| 737 | 737 | ||
| 738 | fn listen(userdata: ?*anyopaque, address: Io.net.IpAddress, options: Io.net.ListenOptions) Io.net.ListenError!Io.net.Server { | 738 | fn listen(userdata: ?*anyopaque, address: Io.net.IpAddress, options: Io.net.ListenOptions) Io.net.ListenError!Io.net.Server { |
| 739 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 739 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 740 | try pool.checkCancel(); | 740 | try pool.checkCancel(); |
| 741 | 741 | ||
| 742 | const nonblock: u32 = if (options.force_nonblocking) posix.SOCK.NONBLOCK else 0; | 742 | const nonblock: u32 = if (options.force_nonblocking) posix.SOCK.NONBLOCK else 0; |
| ... | @@ -776,7 +776,7 @@ fn listen(userdata: ?*anyopaque, address: Io.net.IpAddress, options: Io.net.List | ... | @@ -776,7 +776,7 @@ fn listen(userdata: ?*anyopaque, address: Io.net.IpAddress, options: Io.net.List |
| 776 | } | 776 | } |
| 777 | 777 | ||
| 778 | fn accept(userdata: ?*anyopaque, server: *Io.net.Server) Io.net.Server.AcceptError!Io.net.Server.Connection { | 778 | fn accept(userdata: ?*anyopaque, server: *Io.net.Server) Io.net.Server.AcceptError!Io.net.Server.Connection { |
| 779 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 779 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 780 | try pool.checkCancel(); | 780 | try pool.checkCancel(); |
| 781 | 781 | ||
| 782 | var storage: PosixAddress = undefined; | 782 | var storage: PosixAddress = undefined; |
| ... | @@ -788,17 +788,20 @@ fn accept(userdata: ?*anyopaque, server: *Io.net.Server) Io.net.Server.AcceptErr | ... | @@ -788,17 +788,20 @@ fn accept(userdata: ?*anyopaque, server: *Io.net.Server) Io.net.Server.AcceptErr |
| 788 | }; | 788 | }; |
| 789 | } | 789 | } |
| 790 | 790 | ||
| 791 | fn netReadPosix( | 791 | fn netReadPosix(userdata: ?*anyopaque, stream: Io.net.Stream, data: [][]u8) Io.net.Stream.Reader.Error!usize { |
| 792 | userdata: ?*anyopaque, | 792 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 793 | stream: Io.net.Stream, | ||
| 794 | w: *Io.Writer, | ||
| 795 | limit: Io.Limit, | ||
| 796 | ) Io.net.Stream.Reader.Error!usize { | ||
| 797 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | ||
| 798 | try pool.checkCancel(); | 793 | try pool.checkCancel(); |
| 799 | 794 | ||
| 800 | var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined; | 795 | var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined; |
| 801 | const dest = try w.writableVectorPosix(&iovecs_buffer, limit); | 796 | var i: usize = 0; |
| 797 | for (data) |buf| { | ||
| 798 | if (iovecs_buffer.len - i == 0) break; | ||
| 799 | if (buf.len != 0) { | ||
| 800 | iovecs_buffer[i] = .{ .base = buf.ptr, .len = buf.len }; | ||
| 801 | i += 1; | ||
| 802 | } | ||
| 803 | } | ||
| 804 | const dest = iovecs_buffer[0..i]; | ||
| 802 | assert(dest[0].len > 0); | 805 | assert(dest[0].len > 0); |
| 803 | const n = try posix.readv(stream.handle, dest); | 806 | const n = try posix.readv(stream.handle, dest); |
| 804 | if (n == 0) return error.EndOfStream; | 807 | if (n == 0) return error.EndOfStream; |
| ... | @@ -812,7 +815,7 @@ fn netWritePosix( | ... | @@ -812,7 +815,7 @@ fn netWritePosix( |
| 812 | data: []const []const u8, | 815 | data: []const []const u8, |
| 813 | splat: usize, | 816 | splat: usize, |
| 814 | ) Io.net.Stream.Writer.Error!usize { | 817 | ) Io.net.Stream.Writer.Error!usize { |
| 815 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 818 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 816 | try pool.checkCancel(); | 819 | try pool.checkCancel(); |
| 817 | 820 | ||
| 818 | var iovecs: [max_iovecs_len]posix.iovec_const = undefined; | 821 | var iovecs: [max_iovecs_len]posix.iovec_const = undefined; |
| ... | @@ -866,7 +869,7 @@ fn addBuf(v: []posix.iovec_const, i: *@FieldType(posix.msghdr_const, "iovlen"), | ... | @@ -866,7 +869,7 @@ fn addBuf(v: []posix.iovec_const, i: *@FieldType(posix.msghdr_const, "iovlen"), |
| 866 | } | 869 | } |
| 867 | 870 | ||
| 868 | fn netClose(userdata: ?*anyopaque, stream: Io.net.Stream) void { | 871 | fn netClose(userdata: ?*anyopaque, stream: Io.net.Stream) void { |
| 869 | const pool: *Pool = @alignCast(@ptrCast(userdata)); | 872 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 870 | _ = pool; | 873 | _ = pool; |
| 871 | const net_stream: std.net.Stream = .{ .handle = stream.handle }; | 874 | const net_stream: std.net.Stream = .{ .handle = stream.handle }; |
| 872 | return net_stream.close(); | 875 | return net_stream.close(); |
lib/std/Io/net.zig+244-2| ... | @@ -2,6 +2,7 @@ const builtin = @import("builtin"); | ... | @@ -2,6 +2,7 @@ const builtin = @import("builtin"); |
| 2 | const native_os = builtin.os.tag; | 2 | const native_os = builtin.os.tag; |
| 3 | const std = @import("../std.zig"); | 3 | const std = @import("../std.zig"); |
| 4 | const Io = std.Io; | 4 | const Io = std.Io; |
| 5 | const assert = std.debug.assert; | ||
| 5 | 6 | ||
| 6 | pub const ListenError = std.net.Address.ListenError || Io.Cancelable; | 7 | pub const ListenError = std.net.Address.ListenError || Io.Cancelable; |
| 7 | 8 | ||
| ... | @@ -16,10 +17,233 @@ pub const ListenOptions = struct { | ... | @@ -16,10 +17,233 @@ pub const ListenOptions = struct { |
| 16 | force_nonblocking: bool = false, | 17 | force_nonblocking: bool = false, |
| 17 | }; | 18 | }; |
| 18 | 19 | ||
| 20 | /// An already-validated host name. | ||
| 21 | pub const HostName = struct { | ||
| 22 | /// Externally managed memory. Already checked to be within `max_len`. | ||
| 23 | bytes: []const u8, | ||
| 24 | |||
| 25 | pub const max_len = 255; | ||
| 26 | |||
| 27 | pub const InitError = error{ | ||
| 28 | NameTooLong, | ||
| 29 | InvalidHostName, | ||
| 30 | }; | ||
| 31 | |||
| 32 | pub fn init(bytes: []const u8) InitError!HostName { | ||
| 33 | if (bytes.len > max_len) return error.NameTooLong; | ||
| 34 | if (!std.unicode.utf8ValidateSlice(bytes)) return error.InvalidHostName; | ||
| 35 | for (bytes) |byte| { | ||
| 36 | if (!std.ascii.isAscii(byte) or byte == '.' or byte == '-' or std.ascii.isAlphanumeric(byte)) { | ||
| 37 | continue; | ||
| 38 | } | ||
| 39 | return error.InvalidHostName; | ||
| 40 | } | ||
| 41 | return .{ .bytes = bytes }; | ||
| 42 | } | ||
| 43 | |||
| 44 | pub const LookupOptions = struct { | ||
| 45 | port: u16, | ||
| 46 | /// Must have at least length 2. | ||
| 47 | addresses_buffer: []IpAddress, | ||
| 48 | /// If a buffer of at least `max_len` is not provided, `lookup` may | ||
| 49 | /// return successfully with zero-length `LookupResult.canonical_name_len`. | ||
| 50 | /// | ||
| 51 | /// Suggestion: if not interested in canonical name, pass an empty buffer; | ||
| 52 | /// otherwise pass a buffer of size `max_len`. | ||
| 53 | canonical_name_buffer: []u8, | ||
| 54 | /// `null` means either. | ||
| 55 | family: ?IpAddress.Tag = null, | ||
| 56 | }; | ||
| 57 | |||
| 58 | pub const LookupError = Io.Cancelable || error{}; | ||
| 59 | |||
| 60 | pub const LookupResult = struct { | ||
| 61 | /// How many `LookupOptions.addresses_buffer` elements are populated. | ||
| 62 | addresses_len: usize, | ||
| 63 | /// Length zero means no canonical name returned. | ||
| 64 | canonical_name_len: usize, | ||
| 65 | }; | ||
| 66 | |||
| 67 | pub fn lookup(host_name: HostName, io: Io, options: LookupOptions) LookupError!LookupResult { | ||
| 68 | const name = host_name.bytes; | ||
| 69 | assert(name.len <= max_len); | ||
| 70 | assert(options.addresses_buffer.len >= 2); | ||
| 71 | |||
| 72 | if (native_os == .windows) @compileError("TODO"); | ||
| 73 | if (builtin.link_libc) @compileError("TODO"); | ||
| 74 | if (native_os == .linux) { | ||
| 75 | if (options.family != .ip6) { | ||
| 76 | if (IpAddress.parseIp4(name, options.port)) |addr| { | ||
| 77 | options.addresses_buffer[0] = addr; | ||
| 78 | return .{ .addresses_len = 1, .canonical_name_len = 0 }; | ||
| 79 | } else |_| {} | ||
| 80 | } | ||
| 81 | if (options.family != .ip4) { | ||
| 82 | if (IpAddress.parseIp6(name, options.port)) |addr| { | ||
| 83 | options.addresses_buffer[0] = addr; | ||
| 84 | return .{ .addresses_len = 1, .canonical_name_len = 0 }; | ||
| 85 | } else |_| {} | ||
| 86 | } | ||
| 87 | { | ||
| 88 | const result = try lookupHosts(io, options); | ||
| 89 | if (result.addresses_len > 0) return sortLookupResults(options, result); | ||
| 90 | } | ||
| 91 | { | ||
| 92 | // RFC 6761 Section 6.3.3 | ||
| 93 | // Name resolution APIs and libraries SHOULD recognize | ||
| 94 | // localhost names as special and SHOULD always return the IP | ||
| 95 | // loopback address for address queries and negative responses | ||
| 96 | // for all other query types. | ||
| 97 | |||
| 98 | // Check for equal to "localhost(.)" or ends in ".localhost(.)" | ||
| 99 | const localhost = if (name[name.len - 1] == '.') "localhost." else "localhost"; | ||
| 100 | if (std.mem.endsWith(u8, name, localhost) and | ||
| 101 | (name.len == localhost.len or name[name.len - localhost.len] == '.')) | ||
| 102 | { | ||
| 103 | var i: usize = 0; | ||
| 104 | if (options.family != .ip6) { | ||
| 105 | options.addresses_buffer[i] = .{ .ip4 = .localhost(options.port) }; | ||
| 106 | i += 1; | ||
| 107 | } | ||
| 108 | if (options.family != .ip4) { | ||
| 109 | options.addresses_buffer[i] = .{ .ip6 = .localhost(options.port) }; | ||
| 110 | i += 1; | ||
| 111 | } | ||
| 112 | const canon_name = "localhost"; | ||
| 113 | options.canonical_name_buffer[0..canon_name.len].* = canon_name.*; | ||
| 114 | return sortLookupResults(options, .{ .addresses_len = i, .canonical_name_len = canon_name.len }); | ||
| 115 | } | ||
| 116 | } | ||
| 117 | { | ||
| 118 | const result = try lookupDns(io, options); | ||
| 119 | if (result.addresses_len > 0) return sortLookupResults(options, result); | ||
| 120 | } | ||
| 121 | return error.UnknownHostName; | ||
| 122 | } | ||
| 123 | @compileError("unimplemented"); | ||
| 124 | } | ||
| 125 | |||
| 126 | fn sortLookupResults(options: LookupOptions, result: LookupResult) !LookupResult { | ||
| 127 | _ = options; | ||
| 128 | _ = result; | ||
| 129 | @panic("TODO"); | ||
| 130 | } | ||
| 131 | |||
| 132 | fn lookupDns(io: Io, options: LookupOptions) !LookupResult { | ||
| 133 | _ = io; | ||
| 134 | _ = options; | ||
| 135 | @panic("TODO"); | ||
| 136 | } | ||
| 137 | |||
| 138 | fn lookupHosts(io: Io, options: LookupOptions) !LookupResult { | ||
| 139 | const file = Io.File.openFileAbsoluteZ(io, "/etc/hosts", .{}) catch |err| switch (err) { | ||
| 140 | error.FileNotFound, | ||
| 141 | error.NotDir, | ||
| 142 | error.AccessDenied, | ||
| 143 | => return, | ||
| 144 | else => |e| return e, | ||
| 145 | }; | ||
| 146 | defer file.close(); | ||
| 147 | |||
| 148 | var line_buf: [512]u8 = undefined; | ||
| 149 | var file_reader = file.reader(io, &line_buf); | ||
| 150 | return lookupHostsReader(options, &file_reader.interface) catch |err| switch (err) { | ||
| 151 | error.OutOfMemory => return error.OutOfMemory, | ||
| 152 | error.ReadFailed => return file_reader.err.?, | ||
| 153 | }; | ||
| 154 | } | ||
| 155 | |||
| 156 | fn lookupHostsReader(options: LookupOptions, reader: *Io.Reader) error{ReadFailed}!LookupResult { | ||
| 157 | var addresses_len: usize = 0; | ||
| 158 | var canonical_name_len: usize = 0; | ||
| 159 | while (true) { | ||
| 160 | const line = reader.takeDelimiterExclusive('\n') catch |err| switch (err) { | ||
| 161 | error.StreamTooLong => { | ||
| 162 | // Skip lines that are too long. | ||
| 163 | _ = reader.discardDelimiterInclusive('\n') catch |e| switch (e) { | ||
| 164 | error.EndOfStream => break, | ||
| 165 | error.ReadFailed => return error.ReadFailed, | ||
| 166 | }; | ||
| 167 | continue; | ||
| 168 | }, | ||
| 169 | error.ReadFailed => return error.ReadFailed, | ||
| 170 | error.EndOfStream => break, | ||
| 171 | }; | ||
| 172 | var split_it = std.mem.splitScalar(u8, line, '#'); | ||
| 173 | const no_comment_line = split_it.first(); | ||
| 174 | |||
| 175 | var line_it = std.mem.tokenizeAny(u8, no_comment_line, " \t"); | ||
| 176 | const ip_text = line_it.next() orelse continue; | ||
| 177 | var first_name_text: ?[]const u8 = null; | ||
| 178 | while (line_it.next()) |name_text| { | ||
| 179 | if (std.mem.eql(u8, name_text, options.name)) { | ||
| 180 | if (first_name_text == null) first_name_text = name_text; | ||
| 181 | break; | ||
| 182 | } | ||
| 183 | } else continue; | ||
| 184 | |||
| 185 | if (canonical_name_len == 0) { | ||
| 186 | if (HostName.init(first_name_text)) |name_text| { | ||
| 187 | if (name_text.len <= options.canonical_name_buffer.len) { | ||
| 188 | @memcpy(options.canonical_name_buffer[0..name_text.len], name_text); | ||
| 189 | canonical_name_len = name_text.len; | ||
| 190 | } | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | if (options.family != .ip6) { | ||
| 195 | if (IpAddress.parseIp4(ip_text, options.port)) |addr| { | ||
| 196 | options.addresses_buffer[addresses_len] = addr; | ||
| 197 | addresses_len += 1; | ||
| 198 | if (options.addresses_buffer.len - addresses_len == 0) return .{ | ||
| 199 | .addresses_len = addresses_len, | ||
| 200 | .canonical_name_len = canonical_name_len, | ||
| 201 | }; | ||
| 202 | } else |_| {} | ||
| 203 | } | ||
| 204 | if (options.family != .ip4) { | ||
| 205 | if (IpAddress.parseIp6(ip_text, options.port)) |addr| { | ||
| 206 | options.addresses_buffer[addresses_len] = addr; | ||
| 207 | addresses_len += 1; | ||
| 208 | if (options.addresses_buffer.len - addresses_len == 0) return .{ | ||
| 209 | .addresses_len = addresses_len, | ||
| 210 | .canonical_name_len = canonical_name_len, | ||
| 211 | }; | ||
| 212 | } else |_| {} | ||
| 213 | } | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | pub const ConnectTcpError = LookupError || IpAddress.ConnectTcpError; | ||
| 218 | |||
| 219 | pub fn connectTcp(host_name: HostName, io: Io, port: u16) ConnectTcpError!Stream { | ||
| 220 | var addresses_buffer: [32]IpAddress = undefined; | ||
| 221 | |||
| 222 | const results = try lookup(host_name, .{ | ||
| 223 | .port = port, | ||
| 224 | .addresses_buffer = &addresses_buffer, | ||
| 225 | .canonical_name_buffer = &.{}, | ||
| 226 | }); | ||
| 227 | const addresses = addresses_buffer[0..results.addresses_len]; | ||
| 228 | |||
| 229 | if (addresses.len == 0) return error.UnknownHostName; | ||
| 230 | |||
| 231 | for (addresses) |addr| { | ||
| 232 | return addr.connectTcp(io) catch |err| switch (err) { | ||
| 233 | error.ConnectionRefused => continue, | ||
| 234 | else => |e| return e, | ||
| 235 | }; | ||
| 236 | } | ||
| 237 | return error.ConnectionRefused; | ||
| 238 | } | ||
| 239 | }; | ||
| 240 | |||
| 19 | pub const IpAddress = union(enum) { | 241 | pub const IpAddress = union(enum) { |
| 20 | ip4: Ip4Address, | 242 | ip4: Ip4Address, |
| 21 | ip6: Ip6Address, | 243 | ip6: Ip6Address, |
| 22 | 244 | ||
| 245 | pub const Tag = @typeInfo(IpAddress).@"union".tag_type.?; | ||
| 246 | |||
| 23 | /// Parse the given IP address string into an `IpAddress` value. | 247 | /// Parse the given IP address string into an `IpAddress` value. |
| 24 | pub fn parse(name: []const u8, port: u16) !IpAddress { | 248 | pub fn parse(name: []const u8, port: u16) !IpAddress { |
| 25 | if (parseIp4(name, port)) |ip4| return ip4 else |err| switch (err) { | 249 | if (parseIp4(name, port)) |ip4| return ip4 else |err| switch (err) { |
| ... | @@ -94,6 +318,13 @@ pub const Ip4Address = struct { | ... | @@ -94,6 +318,13 @@ pub const Ip4Address = struct { |
| 94 | bytes: [4]u8, | 318 | bytes: [4]u8, |
| 95 | port: u16, | 319 | port: u16, |
| 96 | 320 | ||
| 321 | pub fn localhost(port: u16) Ip4Address { | ||
| 322 | return .{ | ||
| 323 | .bytes = .{ 127, 0, 0, 1 }, | ||
| 324 | .port = port, | ||
| 325 | }; | ||
| 326 | } | ||
| 327 | |||
| 97 | pub const ParseError = error{ | 328 | pub const ParseError = error{ |
| 98 | Overflow, | 329 | Overflow, |
| 99 | InvalidEnd, | 330 | InvalidEnd, |
| ... | @@ -373,7 +604,10 @@ pub const Stream = struct { | ... | @@ -373,7 +604,10 @@ pub const Stream = struct { |
| 373 | pub fn init(stream: Stream, buffer: []u8) Reader { | 604 | pub fn init(stream: Stream, buffer: []u8) Reader { |
| 374 | return .{ | 605 | return .{ |
| 375 | .interface = .{ | 606 | .interface = .{ |
| 376 | .vtable = &.{ .stream = streamImpl }, | 607 | .vtable = &.{ |
| 608 | .stream = streamImpl, | ||
| 609 | .readVec = readVec, | ||
| 610 | }, | ||
| 377 | .buffer = buffer, | 611 | .buffer = buffer, |
| 378 | .seek = 0, | 612 | .seek = 0, |
| 379 | .end = 0, | 613 | .end = 0, |
| ... | @@ -384,9 +618,17 @@ pub const Stream = struct { | ... | @@ -384,9 +618,17 @@ pub const Stream = struct { |
| 384 | } | 618 | } |
| 385 | 619 | ||
| 386 | fn streamImpl(io_r: *Io.Reader, io_w: *Io.Writer, limit: Io.Limit) Io.Reader.StreamError!usize { | 620 | fn streamImpl(io_r: *Io.Reader, io_w: *Io.Writer, limit: Io.Limit) Io.Reader.StreamError!usize { |
| 621 | const dest = limit.slice(try io_w.writableSliceGreedy(1)); | ||
| 622 | var data: [1][]u8 = .{dest}; | ||
| 623 | const n = try readVec(io_r, &data); | ||
| 624 | io_w.advance(n); | ||
| 625 | return n; | ||
| 626 | } | ||
| 627 | |||
| 628 | fn readVec(io_r: *Reader, data: [][]u8) Io.Reader.Error!usize { | ||
| 387 | const r: *Reader = @alignCast(@fieldParentPtr("interface", io_r)); | 629 | const r: *Reader = @alignCast(@fieldParentPtr("interface", io_r)); |
| 388 | const io = r.io; | 630 | const io = r.io; |
| 389 | return io.vtable.netRead(io.vtable.userdata, r.stream, io_w, limit); | 631 | return io.vtable.netReadVec(io.vtable.userdata, r.stream, io_r, data); |
| 390 | } | 632 | } |
| 391 | }; | 633 | }; |
| 392 | 634 |
lib/std/http/Client.zig+14-11| ... | @@ -9,10 +9,10 @@ const builtin = @import("builtin"); | ... | @@ -9,10 +9,10 @@ const builtin = @import("builtin"); |
| 9 | const testing = std.testing; | 9 | const testing = std.testing; |
| 10 | const http = std.http; | 10 | const http = std.http; |
| 11 | const mem = std.mem; | 11 | const mem = std.mem; |
| 12 | const net = std.net; | ||
| 13 | const Uri = std.Uri; | 12 | const Uri = std.Uri; |
| 14 | const Allocator = mem.Allocator; | 13 | const Allocator = mem.Allocator; |
| 15 | const assert = std.debug.assert; | 14 | const assert = std.debug.assert; |
| 15 | const Io = std.Io; | ||
| 16 | const Writer = std.Io.Writer; | 16 | const Writer = std.Io.Writer; |
| 17 | const Reader = std.Io.Reader; | 17 | const Reader = std.Io.Reader; |
| 18 | 18 | ||
| ... | @@ -22,6 +22,8 @@ pub const disable_tls = std.options.http_disable_tls; | ... | @@ -22,6 +22,8 @@ pub const disable_tls = std.options.http_disable_tls; |
| 22 | 22 | ||
| 23 | /// Used for all client allocations. Must be thread-safe. | 23 | /// Used for all client allocations. Must be thread-safe. |
| 24 | allocator: Allocator, | 24 | allocator: Allocator, |
| 25 | /// Used for opening TCP connections. | ||
| 26 | io: Io, | ||
| 25 | 27 | ||
| 26 | ca_bundle: if (disable_tls) void else std.crypto.Certificate.Bundle = if (disable_tls) {} else .{}, | 28 | ca_bundle: if (disable_tls) void else std.crypto.Certificate.Bundle = if (disable_tls) {} else .{}, |
| 27 | ca_bundle_mutex: std.Thread.Mutex = .{}, | 29 | ca_bundle_mutex: std.Thread.Mutex = .{}, |
| ... | @@ -225,8 +227,8 @@ pub const Protocol = enum { | ... | @@ -225,8 +227,8 @@ pub const Protocol = enum { |
| 225 | 227 | ||
| 226 | pub const Connection = struct { | 228 | pub const Connection = struct { |
| 227 | client: *Client, | 229 | client: *Client, |
| 228 | stream_writer: net.Stream.Writer, | 230 | stream_writer: Io.net.Stream.Writer, |
| 229 | stream_reader: net.Stream.Reader, | 231 | stream_reader: Io.net.Stream.Reader, |
| 230 | /// Entry in `ConnectionPool.used` or `ConnectionPool.free`. | 232 | /// Entry in `ConnectionPool.used` or `ConnectionPool.free`. |
| 231 | pool_node: std.DoublyLinkedList.Node, | 233 | pool_node: std.DoublyLinkedList.Node, |
| 232 | port: u16, | 234 | port: u16, |
| ... | @@ -242,7 +244,7 @@ pub const Connection = struct { | ... | @@ -242,7 +244,7 @@ pub const Connection = struct { |
| 242 | client: *Client, | 244 | client: *Client, |
| 243 | remote_host: []const u8, | 245 | remote_host: []const u8, |
| 244 | port: u16, | 246 | port: u16, |
| 245 | stream: net.Stream, | 247 | stream: Io.net.Stream, |
| 246 | ) error{OutOfMemory}!*Plain { | 248 | ) error{OutOfMemory}!*Plain { |
| 247 | const gpa = client.allocator; | 249 | const gpa = client.allocator; |
| 248 | const alloc_len = allocLen(client, remote_host.len); | 250 | const alloc_len = allocLen(client, remote_host.len); |
| ... | @@ -295,7 +297,7 @@ pub const Connection = struct { | ... | @@ -295,7 +297,7 @@ pub const Connection = struct { |
| 295 | client: *Client, | 297 | client: *Client, |
| 296 | remote_host: []const u8, | 298 | remote_host: []const u8, |
| 297 | port: u16, | 299 | port: u16, |
| 298 | stream: net.Stream, | 300 | stream: Io.net.Stream, |
| 299 | ) error{ OutOfMemory, TlsInitializationFailed }!*Tls { | 301 | ) error{ OutOfMemory, TlsInitializationFailed }!*Tls { |
| 300 | const gpa = client.allocator; | 302 | const gpa = client.allocator; |
| 301 | const alloc_len = allocLen(client, remote_host.len); | 303 | const alloc_len = allocLen(client, remote_host.len); |
| ... | @@ -363,7 +365,7 @@ pub const Connection = struct { | ... | @@ -363,7 +365,7 @@ pub const Connection = struct { |
| 363 | } | 365 | } |
| 364 | }; | 366 | }; |
| 365 | 367 | ||
| 366 | pub const ReadError = std.crypto.tls.Client.ReadError || std.net.Stream.ReadError; | 368 | pub const ReadError = std.crypto.tls.Client.ReadError || Io.net.Stream.ReadError; |
| 367 | 369 | ||
| 368 | pub fn getReadError(c: *const Connection) ?ReadError { | 370 | pub fn getReadError(c: *const Connection) ?ReadError { |
| 369 | return switch (c.protocol) { | 371 | return switch (c.protocol) { |
| ... | @@ -378,8 +380,8 @@ pub const Connection = struct { | ... | @@ -378,8 +380,8 @@ pub const Connection = struct { |
| 378 | }; | 380 | }; |
| 379 | } | 381 | } |
| 380 | 382 | ||
| 381 | fn getStream(c: *Connection) net.Stream { | 383 | fn getStream(c: *Connection) Io.net.Stream { |
| 382 | return c.stream_reader.getStream(); | 384 | return c.stream_reader.stream; |
| 383 | } | 385 | } |
| 384 | 386 | ||
| 385 | pub fn host(c: *Connection) []u8 { | 387 | pub fn host(c: *Connection) []u8 { |
| ... | @@ -1409,7 +1411,7 @@ pub fn connectTcp( | ... | @@ -1409,7 +1411,7 @@ pub fn connectTcp( |
| 1409 | } | 1411 | } |
| 1410 | 1412 | ||
| 1411 | pub const ConnectTcpOptions = struct { | 1413 | pub const ConnectTcpOptions = struct { |
| 1412 | host: []const u8, | 1414 | host: Io.net.HostName, |
| 1413 | port: u16, | 1415 | port: u16, |
| 1414 | protocol: Protocol, | 1416 | protocol: Protocol, |
| 1415 | 1417 | ||
| ... | @@ -1418,7 +1420,7 @@ pub const ConnectTcpOptions = struct { | ... | @@ -1418,7 +1420,7 @@ pub const ConnectTcpOptions = struct { |
| 1418 | }; | 1420 | }; |
| 1419 | 1421 | ||
| 1420 | pub fn connectTcpOptions(client: *Client, options: ConnectTcpOptions) ConnectTcpError!*Connection { | 1422 | pub fn connectTcpOptions(client: *Client, options: ConnectTcpOptions) ConnectTcpError!*Connection { |
| 1421 | const host = options.host; | 1423 | const host = options.host_name; |
| 1422 | const port = options.port; | 1424 | const port = options.port; |
| 1423 | const protocol = options.protocol; | 1425 | const protocol = options.protocol; |
| 1424 | 1426 | ||
| ... | @@ -1431,7 +1433,7 @@ pub fn connectTcpOptions(client: *Client, options: ConnectTcpOptions) ConnectTcp | ... | @@ -1431,7 +1433,7 @@ pub fn connectTcpOptions(client: *Client, options: ConnectTcpOptions) ConnectTcp |
| 1431 | .protocol = protocol, | 1433 | .protocol = protocol, |
| 1432 | })) |conn| return conn; | 1434 | })) |conn| return conn; |
| 1433 | 1435 | ||
| 1434 | const stream = net.tcpConnectToHost(client.allocator, host, port) catch |err| switch (err) { | 1436 | const stream = host.connectTcp(client.io, port) catch |err| switch (err) { |
| 1435 | error.ConnectionRefused => return error.ConnectionRefused, | 1437 | error.ConnectionRefused => return error.ConnectionRefused, |
| 1436 | error.NetworkUnreachable => return error.NetworkUnreachable, | 1438 | error.NetworkUnreachable => return error.NetworkUnreachable, |
| 1437 | error.ConnectionTimedOut => return error.ConnectionTimedOut, | 1439 | error.ConnectionTimedOut => return error.ConnectionTimedOut, |
| ... | @@ -1440,6 +1442,7 @@ pub fn connectTcpOptions(client: *Client, options: ConnectTcpOptions) ConnectTcp | ... | @@ -1440,6 +1442,7 @@ pub fn connectTcpOptions(client: *Client, options: ConnectTcpOptions) ConnectTcp |
| 1440 | error.NameServerFailure => return error.NameServerFailure, | 1442 | error.NameServerFailure => return error.NameServerFailure, |
| 1441 | error.UnknownHostName => return error.UnknownHostName, | 1443 | error.UnknownHostName => return error.UnknownHostName, |
| 1442 | error.HostLacksNetworkAddresses => return error.HostLacksNetworkAddresses, | 1444 | error.HostLacksNetworkAddresses => return error.HostLacksNetworkAddresses, |
| 1445 | error.Canceled => return error.Canceled, | ||
| 1443 | else => return error.UnexpectedConnectFailure, | 1446 | else => return error.UnexpectedConnectFailure, |
| 1444 | }; | 1447 | }; |
| 1445 | errdefer stream.close(); | 1448 | errdefer stream.close(); |
lib/std/net.zig+2-9| ... | @@ -1461,15 +1461,8 @@ test parseHosts { | ... | @@ -1461,15 +1461,8 @@ test parseHosts { |
| 1461 | try std.testing.expectFmt("127.0.0.2:1234", "{f}", .{addrs.items[0].addr}); | 1461 | try std.testing.expectFmt("127.0.0.2:1234", "{f}", .{addrs.items[0].addr}); |
| 1462 | } | 1462 | } |
| 1463 | 1463 | ||
| 1464 | pub fn isValidHostName(hostname: []const u8) bool { | 1464 | pub fn isValidHostName(bytes: []const u8) bool { |
| 1465 | if (hostname.len >= 254) return false; | 1465 | _ = std.Io.net.HostName.init(bytes) catch return false; |
| 1466 | if (!std.unicode.utf8ValidateSlice(hostname)) return false; | ||
| 1467 | for (hostname) |byte| { | ||
| 1468 | if (!std.ascii.isAscii(byte) or byte == '.' or byte == '-' or std.ascii.isAlphanumeric(byte)) { | ||
| 1469 | continue; | ||
| 1470 | } | ||
| 1471 | return false; | ||
| 1472 | } | ||
| 1473 | return true; | 1466 | return true; |
| 1474 | } | 1467 | } |
| 1475 | 1468 |