aboutsummaryrefslogtreecommitdiff
path: root/std/net.zig
diff options
context:
space:
mode:
Diffstat (limited to 'std/net.zig')
-rw-r--r--std/net.zig283
1 files changed, 121 insertions, 162 deletions
diff --git a/std/net.zig b/std/net.zig
index 1140b6449b..8e1b8d97b2 100644
--- a/std/net.zig
+++ b/std/net.zig
@@ -1,143 +1,120 @@
const std = @import("index.zig");
-const linux = std.os.linux;
+const builtin = @import("builtin");
const assert = std.debug.assert;
-const endian = std.endian;
+const net = this;
+const posix = std.os.posix;
+const mem = std.mem;
-// TODO don't trust this file, it bit rotted. start over
-
-const Connection = struct {
- socket_fd: i32,
-
- pub fn send(c: Connection, buf: []const u8) !usize {
- const send_ret = linux.sendto(c.socket_fd, buf.ptr, buf.len, 0, null, 0);
- const send_err = linux.getErrno(send_ret);
- switch (send_err) {
- 0 => return send_ret,
- linux.EINVAL => unreachable,
- linux.EFAULT => unreachable,
- linux.ECONNRESET => return error.ConnectionReset,
- linux.EINTR => return error.SigInterrupt,
- // TODO there are more possible errors
- else => return error.Unexpected,
- }
- }
-
- pub fn recv(c: Connection, buf: []u8) ![]u8 {
- const recv_ret = linux.recvfrom(c.socket_fd, buf.ptr, buf.len, 0, null, null);
- const recv_err = linux.getErrno(recv_ret);
- switch (recv_err) {
- 0 => return buf[0..recv_ret],
- linux.EINVAL => unreachable,
- linux.EFAULT => unreachable,
- linux.ENOTSOCK => return error.NotSocket,
- linux.EINTR => return error.SigInterrupt,
- linux.ENOMEM => return error.OutOfMemory,
- linux.ECONNREFUSED => return error.ConnectionRefused,
- linux.EBADF => return error.BadFd,
- // TODO more error values
- else => return error.Unexpected,
- }
- }
-
- pub fn close(c: Connection) !void {
- switch (linux.getErrno(linux.close(c.socket_fd))) {
- 0 => return,
- linux.EBADF => unreachable,
- linux.EINTR => return error.SigInterrupt,
- linux.EIO => return error.Io,
- else => return error.Unexpected,
- }
- }
+pub const TmpWinAddr = struct {
+ family: u8,
+ data: [14]u8,
};
-const Address = struct {
- family: u16,
- scope_id: u32,
- addr: [16]u8,
- sort_key: i32,
+pub const OsAddress = switch (builtin.os) {
+ builtin.Os.windows => TmpWinAddr,
+ else => posix.sockaddr,
};
-pub fn lookup(hostname: []const u8, out_addrs: []Address) ![]Address {
- if (hostname.len == 0) {
-
- unreachable; // TODO
+pub const Address = struct {
+ os_addr: OsAddress,
+
+ pub fn initIp4(ip4: u32, port: u16) Address {
+ return Address {
+ .os_addr = posix.sockaddr {
+ .in = posix.sockaddr_in {
+ .family = posix.AF_INET,
+ .port = std.mem.endianSwapIfLe(u16, port),
+ .addr = ip4,
+ .zero = []u8{0} ** 8,
+ },
+ },
+ };
}
- unreachable; // TODO
-}
+ pub fn initIp6(ip6: &const Ip6Addr, port: u16) Address {
+ return Address {
+ .family = posix.AF_INET6,
+ .os_addr = posix.sockaddr {
+ .in6 = posix.sockaddr_in6 {
+ .family = posix.AF_INET6,
+ .port = std.mem.endianSwapIfLe(u16, port),
+ .flowinfo = 0,
+ .addr = ip6.addr,
+ .scope_id = ip6.scope_id,
+ },
+ },
+ };
+ }
-pub fn connectAddr(addr: &Address, port: u16) !Connection {
- const socket_ret = linux.socket(addr.family, linux.SOCK_STREAM, linux.PROTO_tcp);
- const socket_err = linux.getErrno(socket_ret);
- if (socket_err > 0) {
- // TODO figure out possible errors from socket()
- return error.Unexpected;
+ pub fn initPosix(addr: &const posix.sockaddr) Address {
+ return Address {
+ .os_addr = *addr,
+ };
}
- const socket_fd = i32(socket_ret);
- const connect_ret = if (addr.family == linux.AF_INET) x: {
- var os_addr: linux.sockaddr_in = undefined;
- os_addr.family = addr.family;
- os_addr.port = endian.swapIfLe(u16, port);
- @memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4);
- @memset(&os_addr.zero[0], 0, @sizeOf(@typeOf(os_addr.zero)));
- break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in));
- } else if (addr.family == linux.AF_INET6) x: {
- var os_addr: linux.sockaddr_in6 = undefined;
- os_addr.family = addr.family;
- os_addr.port = endian.swapIfLe(u16, port);
- os_addr.flowinfo = 0;
- os_addr.scope_id = addr.scope_id;
- @memcpy(&os_addr.addr[0], &addr.addr[0], 16);
- break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in6));
- } else {
- unreachable;
- };
- const connect_err = linux.getErrno(connect_ret);
- if (connect_err > 0) {
- switch (connect_err) {
- linux.ETIMEDOUT => return error.TimedOut,
- else => {
- // TODO figure out possible errors from connect()
- return error.Unexpected;
+ pub fn format(self: &const Address, out_stream: var) !void {
+ switch (self.os_addr.in.family) {
+ posix.AF_INET => {
+ const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in.port);
+ const bytes = ([]const u8)((&self.os_addr.in.addr)[0..1]);
+ try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port);
+ },
+ posix.AF_INET6 => {
+ const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in6.port);
+ try out_stream.print("[TODO render ip6 address]:{}", native_endian_port);
},
+ else => try out_stream.write("(unrecognized address family)"),
}
}
+};
- return Connection {
- .socket_fd = socket_fd,
- };
-}
-
-pub fn connect(hostname: []const u8, port: u16) !Connection {
- var addrs_buf: [1]Address = undefined;
- const addrs_slice = try lookup(hostname, addrs_buf[0..]);
- const main_addr = &addrs_slice[0];
-
- return connectAddr(main_addr, port);
-}
+pub fn parseIp4(buf: []const u8) !u32 {
+ var result: u32 = undefined;
+ const out_ptr = ([]u8)((&result)[0..1]);
-pub fn parseIpLiteral(buf: []const u8) !Address {
+ var x: u8 = 0;
+ var index: u8 = 0;
+ var saw_any_digits = false;
+ for (buf) |c| {
+ if (c == '.') {
+ if (!saw_any_digits) {
+ return error.InvalidCharacter;
+ }
+ if (index == 3) {
+ return error.InvalidEnd;
+ }
+ out_ptr[index] = x;
+ index += 1;
+ x = 0;
+ saw_any_digits = false;
+ } else if (c >= '0' and c <= '9') {
+ saw_any_digits = true;
+ const digit = c - '0';
+ if (@mulWithOverflow(u8, x, 10, &x)) {
+ return error.Overflow;
+ }
+ if (@addWithOverflow(u8, x, digit, &x)) {
+ return error.Overflow;
+ }
+ } else {
+ return error.InvalidCharacter;
+ }
+ }
+ if (index == 3 and saw_any_digits) {
+ out_ptr[index] = x;
+ return result;
+ }
- return error.InvalidIpLiteral;
+ return error.Incomplete;
}
-fn hexDigit(c: u8) u8 {
- // TODO use switch with range
- if ('0' <= c and c <= '9') {
- return c - '0';
- } else if ('A' <= c and c <= 'Z') {
- return c - 'A' + 10;
- } else if ('a' <= c and c <= 'z') {
- return c - 'a' + 10;
- } else {
- return @maxValue(u8);
- }
-}
+pub const Ip6Addr = struct {
+ scope_id: u32,
+ addr: [16]u8,
+};
-fn parseIp6(buf: []const u8) !Address {
- var result: Address = undefined;
- result.family = linux.AF_INET6;
+pub fn parseIp6(buf: []const u8) !Ip6Addr {
+ var result: Ip6Addr = undefined;
result.scope_id = 0;
const ip_slice = result.addr[0..];
@@ -156,14 +133,14 @@ fn parseIp6(buf: []const u8) !Address {
return error.Overflow;
}
} else {
- return error.InvalidChar;
+ return error.InvalidCharacter;
}
} else if (c == ':') {
if (!saw_any_digits) {
- return error.InvalidChar;
+ return error.InvalidCharacter;
}
if (index == 14) {
- return error.JunkAtEnd;
+ return error.InvalidEnd;
}
ip_slice[index] = @truncate(u8, x >> 8);
index += 1;
@@ -174,7 +151,7 @@ fn parseIp6(buf: []const u8) !Address {
saw_any_digits = false;
} else if (c == '%') {
if (!saw_any_digits) {
- return error.InvalidChar;
+ return error.InvalidCharacter;
}
if (index == 14) {
ip_slice[index] = @truncate(u8, x >> 8);
@@ -185,10 +162,7 @@ fn parseIp6(buf: []const u8) !Address {
scope_id = true;
saw_any_digits = false;
} else {
- const digit = hexDigit(c);
- if (digit == @maxValue(u8)) {
- return error.InvalidChar;
- }
+ const digit = try std.fmt.charToDigit(c, 16);
if (@mulWithOverflow(u16, x, 16, &x)) {
return error.Overflow;
}
@@ -216,42 +190,27 @@ fn parseIp6(buf: []const u8) !Address {
return error.Incomplete;
}
-fn parseIp4(buf: []const u8) !u32 {
- var result: u32 = undefined;
- const out_ptr = ([]u8)((&result)[0..1]);
+test "std.net.parseIp4" {
+ assert((try parseIp4("127.0.0.1")) == std.mem.endianSwapIfLe(u32, 0x7f000001));
- var x: u8 = 0;
- var index: u8 = 0;
- var saw_any_digits = false;
- for (buf) |c| {
- if (c == '.') {
- if (!saw_any_digits) {
- return error.InvalidChar;
- }
- if (index == 3) {
- return error.JunkAtEnd;
- }
- out_ptr[index] = x;
- index += 1;
- x = 0;
- saw_any_digits = false;
- } else if (c >= '0' and c <= '9') {
- saw_any_digits = true;
- const digit = c - '0';
- if (@mulWithOverflow(u8, x, 10, &x)) {
- return error.Overflow;
- }
- if (@addWithOverflow(u8, x, digit, &x)) {
- return error.Overflow;
- }
- } else {
- return error.InvalidChar;
- }
- }
- if (index == 3 and saw_any_digits) {
- out_ptr[index] = x;
- return result;
+ testParseIp4Fail("256.0.0.1", error.Overflow);
+ testParseIp4Fail("x.0.0.1", error.InvalidCharacter);
+ testParseIp4Fail("127.0.0.1.1", error.InvalidEnd);
+ testParseIp4Fail("127.0.0.", error.Incomplete);
+ testParseIp4Fail("100..0.1", error.InvalidCharacter);
+}
+
+fn testParseIp4Fail(buf: []const u8, expected_err: error) void {
+ if (parseIp4(buf)) |_| {
+ @panic("expected error");
+ } else |e| {
+ assert(e == expected_err);
}
+}
- return error.Incomplete;
+test "std.net.parseIp6" {
+ const addr = try parseIp6("FF01:0:0:0:0:0:0:FB");
+ assert(addr.addr[0] == 0xff);
+ assert(addr.addr[1] == 0x01);
+ assert(addr.addr[2] == 0x00);
}