authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-10 15:00:59-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-10 15:00:59-07:00
log22888ca5246acb7dc7afac602488b17f01790bfb
tree8f3dbf24b6a65a65b084dc7e19d7e413e4897bbe
parentd92ae20f459c3ac491a0f5ef8aa42e8ac37634c8

some work in progress networking code

also, casting to or from a u8 slice makes a function impure

6 files changed, 346 insertions(+), 21 deletions(-)

src/analyze.cpp+1
......@@ -4260,6 +4260,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
42604260 (wanted_type->data.structure.fields[0].type_entry->data.pointer.is_const ||
42614261 !actual_type->data.structure.fields[0].type_entry->data.pointer.is_const))
42624262 {
4263 mark_impure_fn(context);
42634264 return resolve_cast(g, context, node, expr_node, wanted_type, CastOpResizeSlice, true);
42644265 }
42654266
std/hash_map.zig+6
......@@ -6,6 +6,12 @@ const Allocator = mem.Allocator;
66const want_modification_safety = !@compile_var("is_release");
77const debug_u32 = if (want_modification_safety) u32 else void;
88
9/*
10pub fn HashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)->bool) {
11 SmallHashMap(K, V, hash, eql, 8);
12}
13*/
14
915pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)->bool, STATIC_SIZE: isize) {
1016 entries: []Entry,
1117 size: isize,
std/index.zig-1
......@@ -12,4 +12,3 @@ pub const mem = @import("mem.zig");
1212pub fn assert(b: bool) {
1313 if (!b) unreachable{}
1414}
15
std/linux.zig+56-11
......@@ -312,13 +312,10 @@ fn restore_signals(set: &sigset_t) {
312312}
313313
314314
315pub type sa_family_t = u16;
316pub type socklen_t = u32;
317pub type in_addr_t = u32;
318
319export struct in_addr {
320 s_addr: in_addr_t,
321}
315pub const sa_family_t = u16;
316pub const socklen_t = u32;
317pub const in_addr = u32;
318pub const in6_addr = [16]u8;
322319
323320export struct sockaddr {
324321 family: sa_family_t,
......@@ -341,15 +338,33 @@ export struct sockaddr_in6 {
341338 scope_id: u32,
342339}
343340
344export struct in6_addr {
345 addr: [16]u8,
346}
347
348341export struct iovec {
349342 iov_base: &u8,
350343 iov_len: usize,
351344}
352345
346/*
347const IF_NAMESIZE = 16;
348
349export struct ifreq {
350 ifrn_name: [IF_NAMESIZE]u8,
351 union {
352 ifru_addr: sockaddr,
353 ifru_dstaddr: sockaddr,
354 ifru_broadaddr: sockaddr,
355 ifru_netmask: sockaddr,
356 ifru_hwaddr: sockaddr,
357 ifru_flags: i16,
358 ifru_ivalue: i32,
359 ifru_mtu: i32,
360 ifru_map: ifmap,
361 ifru_slave: [IF_NAMESIZE]u8,
362 ifru_newname: [IF_NAMESIZE]u8,
363 ifru_data: &u8,
364 } ifr_ifru;
365}
366*/
367
353368pub fn getsockname(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) -> isize {
354369 arch.syscall3(arch.SYS_getsockname, fd, isize(addr), isize(len))
355370}
......@@ -415,3 +430,33 @@ pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) -> i
415430pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags: i32) -> isize {
416431 arch.syscall4(arch.SYS_accept4, fd, isize(addr), isize(len), flags)
417432}
433
434/*
435pub error NameTooLong;
436pub error SystemResources;
437pub error Io;
438
439pub fn if_nametoindex(name: []u8) -> %u32 {
440 var ifr: ifreq = undefined;
441
442 if (name.len >= ifr.ifr_name.len) {
443 return error.NameTooLong;
444 }
445
446 const socket_ret = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
447 const socket_err = get_errno(socket_ret);
448 if (socket_err > 0) {
449 return error.SystemResources;
450 }
451 const socket_fd = i32(socket_ret);
452 @memcpy(&ifr.ifr_name[0], &name[0], name.len);
453 ifr.ifr_name[name.len] = 0;
454 const ioctl_ret = ioctl(socket_fd, SIOCGIFINDEX, &ifr);
455 close(socket_fd);
456 const ioctl_err = get_errno(ioctl_ret);
457 if (ioctl_err > 0) {
458 return error.Io;
459 }
460 return ifr.ifr_ifindex;
461}
462*/
std/list.zig+2-2
......@@ -3,8 +3,8 @@ const mem = @import("mem.zig");
33const Allocator = mem.Allocator;
44
55/*
6fn List(T: type) -> type {
7 List(T, 8)
6pub fn List(T: type) -> type {
7 SmallList(T, 8)
88}
99*/
1010
std/net.zig+281-7
......@@ -1,9 +1,11 @@
11const linux = @import("linux.zig");
22const errno = @import("errno.zig");
3const assert = @import("index.zig").assert;
34
45pub error SigInterrupt;
56pub error Unexpected;
67pub error Io;
8pub error TimedOut;
79
810struct Connection {
911 socket_fd: i32,
......@@ -20,17 +22,37 @@ struct Connection {
2022}
2123
2224struct Address {
23 addr: linux.sockaddr,
25 family: u16,
26 scope_id: u32,
27 addr: [16]u8,
28 sort_key: i32,
2429}
2530
2631pub fn lookup(hostname: []const u8, out_addrs: []Address) -> %[]Address {
32 if (hostname.len == 0) {
33
34/*
35 if (family != AF_INET6)
36 buf[cnt++] = (struct address){ .family = AF_INET, .addr = { 127,0,0,1 } };
37 if (family != AF_INET)
38 buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } };
39 */
40 unreachable{} // TODO
41 }
42
43 switch (parse_ip_literal(hostname)) {
44 Ok => |addr| {
45 out_addrs[0] = addr;
46 return out_addrs[0...1];
47 },
48 else => {},
49 };
50
2751 unreachable{} // TODO
2852}
2953
3054pub fn connect_addr(addr: &Address, port: u16) -> %Connection {
31 addr.addr.port = port;
32
33 const socket_ret = linux.socket(linux.PF_INET, linux.SOCK_STREAM, linux.PROTO_tcp);
55 const socket_ret = linux.socket(addr.family, linux.SOCK_STREAM, linux.PROTO_tcp);
3456 const socket_err = linux.get_errno(socket_ret);
3557 if (socket_err > 0) {
3658 // TODO figure out possible errors from socket()
......@@ -38,10 +60,33 @@ pub fn connect_addr(addr: &Address, port: u16) -> %Connection {
3860 }
3961 const socket_fd = i32(socket_ret);
4062
41 const connect_err = linux.get_errno(linux.connect(socket_fd, &addr.addr, @sizeof(linux.sockaddr)));
63 const connect_ret = if (addr.family == linux.AF_INET) {
64 var os_addr: linux.sockaddr_in = undefined;
65 os_addr.family = addr.family;
66 os_addr.port = host_to_be(u16)(port);
67 @memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4);
68 @memset(&os_addr.zero, 0, @sizeof(@typeof(os_addr.zero)));
69 linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeof(linux.sockaddr_in))
70 } else if (addr.family == linux.AF_INET6) {
71 var os_addr: linux.sockaddr_in6 = undefined;
72 os_addr.family = addr.family;
73 os_addr.port = host_to_be(u16)(port);
74 os_addr.flowinfo = 0;
75 os_addr.scope_id = addr.scope_id;
76 @memcpy(&os_addr.addr[0], &addr.addr[0], 16);
77 linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeof(linux.sockaddr_in6))
78 } else {
79 unreachable{}
80 };
81 const connect_err = linux.get_errno(connect_ret);
4282 if (connect_err > 0) {
43 // TODO figure out possible errors from connect()
44 return error.Unexpected;
83 switch (connect_err) {
84 errno.ETIMEDOUT => return error.TimedOut,
85 else => {
86 // TODO figure out possible errors from connect()
87 return error.Unexpected;
88 },
89 }
4590 }
4691
4792 return Connection {
......@@ -56,3 +101,232 @@ pub fn connect(hostname: []const u8, port: u16) -> %Connection {
56101
57102 return connect_addr(main_addr, port);
58103}
104
105pub error InvalidIpLiteral;
106
107pub fn parse_ip_literal(buf: []const u8) -> %Address {
108 switch (parse_ip4(buf)) {
109 Ok => |ip4| {
110 var result: Address = undefined;
111 @memcpy(&result.addr[0], (&u8)(&ip4), @sizeof(u32));
112 result.family = linux.AF_INET;
113 result.scope_id = 0;
114 return result;
115 },
116 else => {},
117 }
118 switch (parse_ip6(buf)) {
119 Ok => |addr| {
120 return addr;
121 },
122 else => {},
123 }
124
125 return error.InvalidIpLiteral;
126}
127
128fn hex_digit(c: u8) -> u8 {
129 // TODO use switch with range
130 if ('0' <= c && c <= '9') {
131 c - '0'
132 } else if ('A' <= c && c <= 'Z') {
133 c - 'A' + 10
134 } else if ('a' <= c && c <= 'z') {
135 c - 'a' + 10
136 } else {
137 @max_value(u8)
138 }
139}
140
141error InvalidChar;
142error Overflow;
143error JunkAtEnd;
144error Incomplete;
145
146#static_eval_enable(false)
147fn parse_ip6(buf: []const u8) -> %Address {
148 var result: Address = undefined;
149 result.family = linux.AF_INET6;
150 result.scope_id = 0;
151 const ip_slice = result.addr[0...];
152
153 var x: u16 = 0;
154 var saw_any_digits = false;
155 var index: u8 = 0;
156 var scope_id = false;
157 for (buf) |c| {
158 if (scope_id) {
159 if (c >= '0' && c <= '9') {
160 const digit = c - '0';
161 if (@mul_with_overflow(u32, result.scope_id, 10, &result.scope_id)) {
162 return error.Overflow;
163 }
164 if (@add_with_overflow(u32, result.scope_id, digit, &result.scope_id)) {
165 return error.Overflow;
166 }
167 } else {
168 return error.InvalidChar;
169 }
170 } else if (c == ':') {
171 if (!saw_any_digits) {
172 return error.InvalidChar;
173 }
174 if (index == 14) {
175 return error.JunkAtEnd;
176 }
177 ip_slice[index] = @truncate(u8, x >> 8);
178 index += 1;
179 ip_slice[index] = @truncate(u8, x);
180 index += 1;
181
182 x = 0;
183 saw_any_digits = false;
184 } else if (c == '%') {
185 if (!saw_any_digits) {
186 return error.InvalidChar;
187 }
188 if (index == 14) {
189 ip_slice[index] = @truncate(u8, x >> 8);
190 index += 1;
191 ip_slice[index] = @truncate(u8, x);
192 index += 1;
193 }
194 scope_id = true;
195 saw_any_digits = false;
196 } else {
197 const digit = hex_digit(c);
198 if (digit == @max_value(u8)) {
199 return error.InvalidChar;
200 }
201 if (@mul_with_overflow(u16, x, 16, &x)) {
202 return error.Overflow;
203 }
204 if (@add_with_overflow(u16, x, digit, &x)) {
205 return error.Overflow;
206 }
207 saw_any_digits = true;
208 }
209 }
210
211 if (!saw_any_digits) {
212 return error.Incomplete;
213 }
214
215 /*
216 if (p) {
217 if (isdigit(*++p)) scopeid = strtoull(p, &z, 10);
218 else z = p-1;
219 if (*z) {
220 if (!IN6_IS_ADDR_LINKLOCAL(&a6) &&
221 !IN6_IS_ADDR_MC_LINKLOCAL(&a6))
222 return EAI_NONAME;
223 scopeid = if_nametoindex(p);
224 if (!scopeid) return EAI_NONAME;
225 }
226 if (scopeid > UINT_MAX) return EAI_NONAME;
227 }
228 */
229
230 if (scope_id) {
231 return result;
232 }
233
234 if (index == 14) {
235 ip_slice[14] = @truncate(u8, x >> 8);
236 ip_slice[15] = @truncate(u8, x);
237 return result;
238 }
239
240 return error.Incomplete;
241}
242
243fn parse_ip4(buf: []const u8) -> %u32 {
244 var result: u32 = undefined;
245 const out_ptr = ([]u8)((&result)[0...1]);
246
247 var x: u8 = 0;
248 var index: u8 = 0;
249 var saw_any_digits = false;
250 for (buf) |c| {
251 if (c == '.') {
252 if (!saw_any_digits) {
253 return error.InvalidChar;
254 }
255 if (index == 3) {
256 return error.JunkAtEnd;
257 }
258 out_ptr[index] = x;
259 index += 1;
260 x = 0;
261 saw_any_digits = false;
262 } else if (c >= '0' && c <= '9') {
263 saw_any_digits = true;
264 const digit = c - '0';
265 if (@mul_with_overflow(u8, x, 10, &x)) {
266 return error.Overflow;
267 }
268 if (@add_with_overflow(u8, x, digit, &x)) {
269 return error.Overflow;
270 }
271 } else {
272 return error.InvalidChar;
273 }
274 }
275 if (index == 3 && saw_any_digits) {
276 out_ptr[index] = x;
277 return result;
278 }
279
280 return error.Incomplete;
281}
282
283
284#attribute("test")
285fn test_parse_ip4() {
286 assert(%%parse_ip4("127.0.0.1") == be_to_host(u32)(0x7f000001));
287 switch (parse_ip4("256.0.0.1")) { Overflow => {}, else => unreachable {}, }
288 switch (parse_ip4("x.0.0.1")) { InvalidChar => {}, else => unreachable {}, }
289 switch (parse_ip4("127.0.0.1.1")) { JunkAtEnd => {}, else => unreachable {}, }
290 switch (parse_ip4("127.0.0.")) { Incomplete => {}, else => unreachable {}, }
291 switch (parse_ip4("100..0.1")) { InvalidChar => {}, else => unreachable {}, }
292}
293
294#attribute("test")
295fn test_parse_ip6() {
296 {
297 const addr = %%parse_ip6("FF01:0:0:0:0:0:0:FB");
298 assert(addr.addr[0] == 0xff);
299 assert(addr.addr[1] == 0x01);
300 assert(addr.addr[2] == 0x00);
301 }
302}
303
304#attribute("test")
305fn test_lookup_simple_ip() {
306 {
307 var addrs_buf: [5]Address = undefined;
308 const addrs = %%lookup("192.168.1.1", addrs_buf);
309 assert(addrs.len == 1);
310 const addr = addrs[0];
311 assert(addr.family == linux.AF_INET);
312 assert(addr.addr[0] == 192);
313 assert(addr.addr[1] == 168);
314 assert(addr.addr[2] == 1);
315 assert(addr.addr[3] == 1);
316 }
317}
318
319const be_to_host = host_to_be;
320fn host_to_be(T: type)(x: T) -> T {
321 if (@compile_var("is_big_endian")) x else endian_swap(T)(x)
322}
323
324fn endian_swap(T: type)(x: T) -> T {
325 const x_slice = ([]u8)((&const x)[0...1]);
326 var result: T = undefined;
327 const result_slice = ([]u8)((&result)[0...1]);
328 for (result_slice) |*b, i| {
329 *b = x_slice[@sizeof(T) - i - 1];
330 }
331 return result;
332}