Thanks for starting hare-icmp! I fixed some small issues and adapted to recent changes in the stdlib. This allowed me to create a stupid, but working, "ping" tool (also included). My next goal would be IPv6 support. Let me know what you think! Conrad Hoffmann (6): Reformat according to official style guide test: adapt to memio/bufio changes in stdlib test: properly initialize structs Fix checksum calculation and test it Fix memory leak Add a _very_ basic ping utility cmd/ping/main.ha | 78 +++++++++ net/icmp/+test.ha | 321 ++++++++++++++++++++----------------- net/icmp/README | 13 +- net/icmp/message.ha | 377 ++++++++++++++++++++++---------------------- 4 files changed, 449 insertions(+), 340 deletions(-) create mode 100644 cmd/ping/main.ha -- 2.41.0
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~blainsmith/public-inbox/patches/43568/mbox | git am -3Learn more about email & git
Use tabs for indentation, break README lines at 80 characters. See https://harelang.org/style/#a-general-conventions Signed-off-by: Conrad Hoffmann <ch@bitfehler.net> --- net/icmp/+test.ha | 288 +++++++++++++++++----------------- net/icmp/README | 13 +- net/icmp/message.ha | 374 ++++++++++++++++++++++---------------------- 3 files changed, 339 insertions(+), 336 deletions(-) diff --git a/net/icmp/+test.ha b/net/icmp/+test.ha index 5c15ddf..690b426 100644 --- a/net/icmp/+test.ha +++ b/net/icmp/+test.ha @@ -3,159 +3,159 @@ use bytes; use io; @test fn encode_decode_echo() void = { - let data: []u8 = alloc(['h', 'e', 'l', 'l', 'o']); - - let inmsg = message { - proto = IP_V4, - code = 10, - checksum = 0, - body = echo { - id = 13, - seq = 200, - data = data, - }, - }; - - let outbuf = bufio::dynamic(io::mode::RDWR); - let encsz = encode(&outbuf, &inmsg)!; - assert(encsz == 13); - - let msg = bufio::buffer(&outbuf); - - let outmsg = message {...}; - let inbuf = bufio::dynamic_from(msg, io::mode::RDWR); - let decsz = decode(&outmsg, &inbuf)! as size; - assert(decsz == 13); - - assert(inmsg.proto == outmsg.proto); - assert(inmsg.code == outmsg.code); - assert(inmsg.checksum == outmsg.checksum); - - let inbody = inmsg.body as echo; - let outbody = outmsg.body as echo; - - assert(inbody.id == outbody.id); - assert(inbody.seq == outbody.seq); - assert(bytes::equal(inbody.data, outbody.data)); + let data: []u8 = alloc(['h', 'e', 'l', 'l', 'o']); + + let inmsg = message { + proto = IP_V4, + code = 10, + checksum = 0, + body = echo { + id = 13, + seq = 200, + data = data, + }, + }; + + let outbuf = bufio::dynamic(io::mode::RDWR); + let encsz = encode(&outbuf, &inmsg)!; + assert(encsz == 13); + + let msg = bufio::buffer(&outbuf); + + let outmsg = message {...}; + let inbuf = bufio::dynamic_from(msg, io::mode::RDWR); + let decsz = decode(&outmsg, &inbuf)! as size; + assert(decsz == 13); + + assert(inmsg.proto == outmsg.proto); + assert(inmsg.code == outmsg.code); + assert(inmsg.checksum == outmsg.checksum); + + let inbody = inmsg.body as echo; + let outbody = outmsg.body as echo; + + assert(inbody.id == outbody.id); + assert(inbody.seq == outbody.seq); + assert(bytes::equal(inbody.data, outbody.data)); }; @test fn encode_decode_reply() void = { - let data: []u8 = alloc(['h', 'e', 'l', 'l', 'o']); - - let inmsg = message { - proto = IP_V4, - code = 10, - checksum = 0, - body = reply { - id = 13, - seq = 200, - data = data, - }, - }; - - let outbuf = bufio::dynamic(io::mode::RDWR); - let encsz = encode(&outbuf, &inmsg)!; - assert(encsz == 13); - - let msg = bufio::buffer(&outbuf); - - let outmsg = message {...}; - let inbuf = bufio::dynamic_from(msg, io::mode::RDWR); - let decsz = decode(&outmsg, &inbuf)! as size; - assert(decsz == 13); - - assert(inmsg.proto == outmsg.proto); - assert(inmsg.code == outmsg.code); - assert(inmsg.checksum == outmsg.checksum); - - let inbody = inmsg.body as reply; - let outbody = outmsg.body as reply; - - assert(inbody.id == outbody.id); - assert(inbody.seq == outbody.seq); - assert(bytes::equal(inbody.data, outbody.data)); + let data: []u8 = alloc(['h', 'e', 'l', 'l', 'o']); + + let inmsg = message { + proto = IP_V4, + code = 10, + checksum = 0, + body = reply { + id = 13, + seq = 200, + data = data, + }, + }; + + let outbuf = bufio::dynamic(io::mode::RDWR); + let encsz = encode(&outbuf, &inmsg)!; + assert(encsz == 13); + + let msg = bufio::buffer(&outbuf); + + let outmsg = message {...}; + let inbuf = bufio::dynamic_from(msg, io::mode::RDWR); + let decsz = decode(&outmsg, &inbuf)! as size; + assert(decsz == 13); + + assert(inmsg.proto == outmsg.proto); + assert(inmsg.code == outmsg.code); + assert(inmsg.checksum == outmsg.checksum); + + let inbody = inmsg.body as reply; + let outbody = outmsg.body as reply; + + assert(inbody.id == outbody.id); + assert(inbody.seq == outbody.seq); + assert(bytes::equal(inbody.data, outbody.data)); }; @test fn encode_decode_destination_unreachable() void = { - let inmsg = message { - proto = IP_V4, - code = 10, - checksum = 0, - body = destination_unreachable { - ..., - }, - }; - - let outbuf = bufio::dynamic(io::mode::RDWR); - let encsz = encode(&outbuf, &inmsg)!; - assert(encsz == 4); - - let msg = bufio::buffer(&outbuf); - - let outmsg = message {...}; - let inbuf = bufio::dynamic_from(msg, io::mode::RDWR); - let decsz = decode(&outmsg, &inbuf)! as size; - assert(decsz == 4); - - assert(inmsg.proto == outmsg.proto); - assert(inmsg.code == outmsg.code); - assert(inmsg.checksum == outmsg.checksum); + let inmsg = message { + proto = IP_V4, + code = 10, + checksum = 0, + body = destination_unreachable { + ..., + }, + }; + + let outbuf = bufio::dynamic(io::mode::RDWR); + let encsz = encode(&outbuf, &inmsg)!; + assert(encsz == 4); + + let msg = bufio::buffer(&outbuf); + + let outmsg = message {...}; + let inbuf = bufio::dynamic_from(msg, io::mode::RDWR); + let decsz = decode(&outmsg, &inbuf)! as size; + assert(decsz == 4); + + assert(inmsg.proto == outmsg.proto); + assert(inmsg.code == outmsg.code); + assert(inmsg.checksum == outmsg.checksum); }; @test fn encode_decode_time_exeeded() void = { - let inmsg = message { - proto = IP_V4, - code = 10, - checksum = 0, - body = time_exeeded { - ..., - }, - }; - - let outbuf = bufio::dynamic(io::mode::RDWR); - let encsz = encode(&outbuf, &inmsg)!; - assert(encsz == 4); - - let msg = bufio::buffer(&outbuf); - - let outmsg = message {...}; - let inbuf = bufio::dynamic_from(msg, io::mode::RDWR); - let decsz = decode(&outmsg, &inbuf)! as size; - assert(decsz == 4); - - assert(inmsg.proto == outmsg.proto); - assert(inmsg.code == outmsg.code); - assert(inmsg.checksum == outmsg.checksum); + let inmsg = message { + proto = IP_V4, + code = 10, + checksum = 0, + body = time_exeeded { + ..., + }, + }; + + let outbuf = bufio::dynamic(io::mode::RDWR); + let encsz = encode(&outbuf, &inmsg)!; + assert(encsz == 4); + + let msg = bufio::buffer(&outbuf); + + let outmsg = message {...}; + let inbuf = bufio::dynamic_from(msg, io::mode::RDWR); + let decsz = decode(&outmsg, &inbuf)! as size; + assert(decsz == 4); + + assert(inmsg.proto == outmsg.proto); + assert(inmsg.code == outmsg.code); + assert(inmsg.checksum == outmsg.checksum); }; @test fn encode_decode_parameter_problem() void = { - let inmsg = message { - proto = IP_V4, - code = 10, - checksum = 0, - body = parameter_problem { - pointer = 13, - ..., - }, - }; - - let outbuf = bufio::dynamic(io::mode::RDWR); - let encsz = encode(&outbuf, &inmsg)!; - assert(encsz == 6); - - let msg = bufio::buffer(&outbuf); - - let outmsg = message {...}; - let inbuf = bufio::dynamic_from(msg, io::mode::RDWR); - let decsz = decode(&outmsg, &inbuf)! as size; - assert(decsz == 6); - - assert(inmsg.proto == outmsg.proto); - assert(inmsg.code == outmsg.code); - assert(inmsg.checksum == outmsg.checksum); - - let inbody = inmsg.body as parameter_problem; - let outbody = outmsg.body as parameter_problem; - - assert(inbody.pointer == outbody.pointer); -}; \ No newline at end of file + let inmsg = message { + proto = IP_V4, + code = 10, + checksum = 0, + body = parameter_problem { + pointer = 13, + ..., + }, + }; + + let outbuf = bufio::dynamic(io::mode::RDWR); + let encsz = encode(&outbuf, &inmsg)!; + assert(encsz == 6); + + let msg = bufio::buffer(&outbuf); + + let outmsg = message {...}; + let inbuf = bufio::dynamic_from(msg, io::mode::RDWR); + let decsz = decode(&outmsg, &inbuf)! as size; + assert(decsz == 6); + + assert(inmsg.proto == outmsg.proto); + assert(inmsg.code == outmsg.code); + assert(inmsg.checksum == outmsg.checksum); + + let inbody = inmsg.body as parameter_problem; + let outbody = outmsg.body as parameter_problem; + + assert(inbody.pointer == outbody.pointer); +}; diff --git a/net/icmp/README b/net/icmp/README index 8ac9849..717807e 100644 --- a/net/icmp/README +++ b/net/icmp/README @@ -1,9 +1,12 @@ -The icmp module provides basic functions for the manipulation of messages used in the Internet Control Message Protocols, ICMPv4 and ICMPv6. This can be used in conjunction with [[net]] to send and -receive ICMP packets. +The icmp module provides basic functions for the manipulation of messages used +in the Internet Control Message Protocols, ICMPv4 and ICMPv6. This can be used +in conjunction with [[net]] to send and receive ICMP packets. -ICMPv4 and ICMPv6 are defined in RFC 792 and RFC 4443. Additional support for the following are planned: +ICMPv4 and ICMPv6 are defined in RFC 792 and RFC 4443. Additional support for +the following are planned: - Multi-part message support for ICMP as defined in RFC 4884. - ICMP extensions for MPLS as defined in RFC 4950. -- ICMP extensions for interface and next-hop identification as defined in RFC 5837. -- PROBE: A utility for probing interfaces as defined in RFC 8335. \ No newline at end of file +- ICMP extensions for interface and next-hop identification as defined in RFC + 5837. +- PROBE: A utility for probing interfaces as defined in RFC 8335. diff --git a/net/icmp/message.ha b/net/icmp/message.ha index ea55941..cbeefeb 100644 --- a/net/icmp/message.ha +++ b/net/icmp/message.ha @@ -11,234 +11,234 @@ export type body = (raw | echo | reply | destination_unreachable | time_exeeded // A complete ICMP message export type message = struct { - proto: proto, - code: int, - checksum: int, - body: body, + proto: proto, + code: int, + checksum: int, + body: body, }; // A raw [[body]] of data in an ICMP message export type raw = struct { - data: []u8, + data: []u8, }; // An echo request message [[body]] export type echo = struct { - id: int, - seq: int, - data: []u8, + id: int, + seq: int, + data: []u8, }; // An echo reply message [[body]] export type reply = struct { - id: int, - seq: int, - data: []u8, + id: int, + seq: int, + data: []u8, }; // A destination unreachable reply message [[body]] export type destination_unreachable = struct { - data: []u8, + data: []u8, }; // A time exceeded reply message [[body]] export type time_exeeded = struct { - data: []u8, + data: []u8, }; // A parameter problem reply message [[body]] export type parameter_problem = struct { - pointer: uintptr, - data: []u8, + pointer: uintptr, + data: []u8, }; fn checksum(msg: []u8) u16 = { - let cov: size = len(msg) - 1z; + let cov: size = len(msg) - 1z; - let s: u32 = 0; - for (let i = 0z; i < cov; i += 1) { - s += ((msg[i + 1]: u32) << 8) | msg[i]: u32; - }; + let s: u32 = 0; + for (let i = 0z; i < cov; i += 1) { + s += ((msg[i + 1]: u32) << 8) | msg[i]: u32; + }; - if (cov & 1 == 0) { - s += msg[cov]: u32; - }; + if (cov & 1 == 0) { + s += msg[cov]: u32; + }; - s = (s >> 16) + (s & 0xffff); + s = (s >> 16) + (s & 0xffff); - s = s + (s >> 16); + s = s + (s >> 16); - s ^= s: u16; + s ^= s: u16; - return s: u16; + return s: u16; }; // Encodes a [[message]] into the [[io::handle]] provided export fn encode(out: io::handle, in: *message) (size | io::error) = { - let msg: []u8 = []; - let sz = 0z; - - match (in.body) { - case let m: echo => - msg = alloc([ - V4_ECHO: u8, in.code: u8, - 0, 0, // checksum - 0, 0, // id - 0, 0, // seq - ]); - - endian::beputu16(msg[4..6], m.id: u16); - endian::beputu16(msg[6..8], m.seq: u16); - - append(msg, m.data...); - - let cs = checksum(msg); - in.checksum = cs: int; - endian::beputu16(msg[2..4], cs); - case let m: reply => - msg = alloc([ - V4_ECHO_REPLY: u8, in.code: u8, - 0, 0, // checksum - 0, 0, // id - 0, 0, // seq - ]); - - endian::beputu16(msg[4..6], m.id: u16); - endian::beputu16(msg[6..8], m.seq: u16); - - append(msg, m.data...); - - let cs = checksum(msg); - in.checksum = cs: int; - endian::beputu16(msg[2..4], cs); - case let m: destination_unreachable => - msg = alloc([ - V4_DESTINATION_UNREACHABLE: u8, in.code: u8, - 0, 0, // checksum - ]); - - let cs = checksum(msg); - in.checksum = cs: int; - endian::beputu16(msg[2..4], cs); - case let m: time_exeeded => - msg = alloc([ - V4_TIME_EXCEEDED: u8, in.code: u8, - 0, 0, // checksum - ]); - - let cs = checksum(msg); - in.checksum = cs: int; - endian::beputu16(msg[2..4], cs); - case let m: parameter_problem => - msg = alloc([ - V4_PARAMETER_PROBLEM: u8, in.code: u8, - 0, 0, // checksum - 0, 0, // pointer - ]); - - endian::beputu16(msg[4..6], m.pointer: u16); - - let cs = checksum(msg); - in.checksum = cs: int; - endian::beputu16(msg[2..4], cs); - }; - - return io::write(out, msg)?; + let msg: []u8 = []; + let sz = 0z; + + match (in.body) { + case let m: echo => + msg = alloc([ + V4_ECHO: u8, in.code: u8, + 0, 0, // checksum + 0, 0, // id + 0, 0, // seq + ]); + + endian::beputu16(msg[4..6], m.id: u16); + endian::beputu16(msg[6..8], m.seq: u16); + + append(msg, m.data...); + + let cs = checksum(msg); + in.checksum = cs: int; + endian::beputu16(msg[2..4], cs); + case let m: reply => + msg = alloc([ + V4_ECHO_REPLY: u8, in.code: u8, + 0, 0, // checksum + 0, 0, // id + 0, 0, // seq + ]); + + endian::beputu16(msg[4..6], m.id: u16); + endian::beputu16(msg[6..8], m.seq: u16); + + append(msg, m.data...); + + let cs = checksum(msg); + in.checksum = cs: int; + endian::beputu16(msg[2..4], cs); + case let m: destination_unreachable => + msg = alloc([ + V4_DESTINATION_UNREACHABLE: u8, in.code: u8, + 0, 0, // checksum + ]); + + let cs = checksum(msg); + in.checksum = cs: int; + endian::beputu16(msg[2..4], cs); + case let m: time_exeeded => + msg = alloc([ + V4_TIME_EXCEEDED: u8, in.code: u8, + 0, 0, // checksum + ]); + + let cs = checksum(msg); + in.checksum = cs: int; + endian::beputu16(msg[2..4], cs); + case let m: parameter_problem => + msg = alloc([ + V4_PARAMETER_PROBLEM: u8, in.code: u8, + 0, 0, // checksum + 0, 0, // pointer + ]); + + endian::beputu16(msg[4..6], m.pointer: u16); + + let cs = checksum(msg); + in.checksum = cs: int; + endian::beputu16(msg[2..4], cs); + }; + + return io::write(out, msg)?; }; // Decodes from the [[io::handle]] into a [[message]] export fn decode(out: *message, in: io::handle) (size | io::EOF | io::error) = { - let msg: [1500]u8 = [0...]; - let sz = 0z; + let msg: [1500]u8 = [0...]; + let sz = 0z; - sz = match(io::read(in, msg)?) { - case let s: size => - yield s; - case io::EOF => + sz = match(io::read(in, msg)?) { + case let s: size => + yield s; + case io::EOF => return io::EOF; - }; - - switch (msg[0]: msgtype) { - case V4_ECHO, V6_ECHO_REQUEST => - out.proto = IP_V4; - out.code = msg[1]: int; - out.checksum = endian::begetu16(msg[2..4]): int; - - let body = echo { - id = endian::begetu16(msg[4..6]): int, - seq = endian::begetu16(msg[6..8]): int, - ..., - }; - append(body.data, msg[8..sz]...); - - out.body = body; - case V4_ECHO_REPLY, V6_ECHO_REPLY => - out.proto = IP_V4; - out.code = msg[1]: int; - out.checksum = endian::begetu16(msg[2..4]): int; - - let body = reply { - id = endian::begetu16(msg[4..6]): int, - seq = endian::begetu16(msg[6..8]): int, - ..., - }; - append(body.data, msg[8..sz]...); - - out.body = body; - case V4_DESTINATION_UNREACHABLE, V6_DESTINATION_UNREACHABLE => - out.proto = IP_V4; - out.code = msg[1]: int; - out.checksum = endian::begetu16(msg[2..4]): int; - - let body = destination_unreachable { - ..., - }; - if (sz > 4) { - append(body.data, msg[5..sz]...); - }; - - out.body = body; - case V4_TIME_EXCEEDED, V6_TIME_EXCEEDED => - out.proto = IP_V4; - out.code = msg[1]: int; - out.checksum = endian::begetu16(msg[2..4]): int; - - let body = time_exeeded { - ..., - }; - if (sz > 4) { - append(body.data, msg[5..sz]...); - }; - - out.body = body; - case V4_PARAMETER_PROBLEM, V6_PARAMETER_PROBLEM => - out.proto = IP_V4; - out.code = msg[1]: int; - out.checksum = endian::begetu16(msg[2..4]): int; - - let body = parameter_problem { - pointer = endian::begetu16(msg[4..6]): uintptr, - ..., - }; - if (sz > 6) { - append(body.data, msg[7..sz]...); - }; - - out.body = body; - case => - out.proto = IP_V4; - out.code = msg[1]: int; - out.checksum = endian::begetu16(msg[2..4]): int; - - let body = raw { - ..., - }; - if (sz > 4) { - append(body.data, msg[5..sz]...); - }; - - out.body = body; - }; - - return sz; + }; + + switch (msg[0]: msgtype) { + case V4_ECHO, V6_ECHO_REQUEST => + out.proto = IP_V4; + out.code = msg[1]: int; + out.checksum = endian::begetu16(msg[2..4]): int; + + let body = echo { + id = endian::begetu16(msg[4..6]): int, + seq = endian::begetu16(msg[6..8]): int, + ..., + }; + append(body.data, msg[8..sz]...); + + out.body = body; + case V4_ECHO_REPLY, V6_ECHO_REPLY => + out.proto = IP_V4; + out.code = msg[1]: int; + out.checksum = endian::begetu16(msg[2..4]): int; + + let body = reply { + id = endian::begetu16(msg[4..6]): int, + seq = endian::begetu16(msg[6..8]): int, + ..., + }; + append(body.data, msg[8..sz]...); + + out.body = body; + case V4_DESTINATION_UNREACHABLE, V6_DESTINATION_UNREACHABLE => + out.proto = IP_V4; + out.code = msg[1]: int; + out.checksum = endian::begetu16(msg[2..4]): int; + + let body = destination_unreachable { + ..., + }; + if (sz > 4) { + append(body.data, msg[5..sz]...); + }; + + out.body = body; + case V4_TIME_EXCEEDED, V6_TIME_EXCEEDED => + out.proto = IP_V4; + out.code = msg[1]: int; + out.checksum = endian::begetu16(msg[2..4]): int; + + let body = time_exeeded { + ..., + }; + if (sz > 4) { + append(body.data, msg[5..sz]...); + }; + + out.body = body; + case V4_PARAMETER_PROBLEM, V6_PARAMETER_PROBLEM => + out.proto = IP_V4; + out.code = msg[1]: int; + out.checksum = endian::begetu16(msg[2..4]): int; + + let body = parameter_problem { + pointer = endian::begetu16(msg[4..6]): uintptr, + ..., + }; + if (sz > 6) { + append(body.data, msg[7..sz]...); + }; + + out.body = body; + case => + out.proto = IP_V4; + out.code = msg[1]: int; + out.checksum = endian::begetu16(msg[2..4]): int; + + let body = raw { + ..., + }; + if (sz > 4) { + append(body.data, msg[5..sz]...); + }; + + out.body = body; + }; + + return sz; }; -- 2.41.0
See https://git.sr.ht/~sircmpwn/hare/commit/ed762a2 Signed-off-by: Conrad Hoffmann <ch@bitfehler.net> --- net/icmp/+test.ha | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/net/icmp/+test.ha b/net/icmp/+test.ha index 690b426..c2a275a 100644 --- a/net/icmp/+test.ha +++ b/net/icmp/+test.ha @@ -1,6 +1,5 @@ -use bufio; +use memio; use bytes; -use io; @test fn encode_decode_echo() void = { let data: []u8 = alloc(['h', 'e', 'l', 'l', 'o']); @@ -16,14 +15,14 @@ use io; }, }; - let outbuf = bufio::dynamic(io::mode::RDWR); + let outbuf = memio::dynamic(); let encsz = encode(&outbuf, &inmsg)!; assert(encsz == 13); - let msg = bufio::buffer(&outbuf); + let msg = memio::buffer(&outbuf); let outmsg = message {...}; - let inbuf = bufio::dynamic_from(msg, io::mode::RDWR); + let inbuf = memio::dynamic_from(msg); let decsz = decode(&outmsg, &inbuf)! as size; assert(decsz == 13); @@ -53,14 +52,14 @@ use io; }, }; - let outbuf = bufio::dynamic(io::mode::RDWR); + let outbuf = memio::dynamic(); let encsz = encode(&outbuf, &inmsg)!; assert(encsz == 13); - let msg = bufio::buffer(&outbuf); + let msg = memio::buffer(&outbuf); let outmsg = message {...}; - let inbuf = bufio::dynamic_from(msg, io::mode::RDWR); + let inbuf = memio::dynamic_from(msg); let decsz = decode(&outmsg, &inbuf)! as size; assert(decsz == 13); @@ -86,14 +85,14 @@ use io; }, }; - let outbuf = bufio::dynamic(io::mode::RDWR); + let outbuf = memio::dynamic(); let encsz = encode(&outbuf, &inmsg)!; assert(encsz == 4); - let msg = bufio::buffer(&outbuf); + let msg = memio::buffer(&outbuf); let outmsg = message {...}; - let inbuf = bufio::dynamic_from(msg, io::mode::RDWR); + let inbuf = memio::dynamic_from(msg); let decsz = decode(&outmsg, &inbuf)! as size; assert(decsz == 4); @@ -112,14 +111,14 @@ use io; }, }; - let outbuf = bufio::dynamic(io::mode::RDWR); + let outbuf = memio::dynamic(); let encsz = encode(&outbuf, &inmsg)!; assert(encsz == 4); - let msg = bufio::buffer(&outbuf); + let msg = memio::buffer(&outbuf); let outmsg = message {...}; - let inbuf = bufio::dynamic_from(msg, io::mode::RDWR); + let inbuf = memio::dynamic_from(msg); let decsz = decode(&outmsg, &inbuf)! as size; assert(decsz == 4); @@ -139,14 +138,14 @@ use io; }, }; - let outbuf = bufio::dynamic(io::mode::RDWR); + let outbuf = memio::dynamic(); let encsz = encode(&outbuf, &inmsg)!; assert(encsz == 6); - let msg = bufio::buffer(&outbuf); + let msg = memio::buffer(&outbuf); let outmsg = message {...}; - let inbuf = bufio::dynamic_from(msg, io::mode::RDWR); + let inbuf = memio::dynamic_from(msg); let decsz = decode(&outmsg, &inbuf)! as size; assert(decsz == 6); -- 2.41.0
Not sure this still makes for a good API like this, but just make it compile for now. Signed-off-by: Conrad Hoffmann <ch@bitfehler.net> --- net/icmp/+test.ha | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/net/icmp/+test.ha b/net/icmp/+test.ha index c2a275a..fe79d92 100644 --- a/net/icmp/+test.ha +++ b/net/icmp/+test.ha @@ -21,7 +21,12 @@ use bytes; let msg = memio::buffer(&outbuf); - let outmsg = message {...}; + let outmsg = message { + body = echo { + ... + }, + ... + }; let inbuf = memio::dynamic_from(msg); let decsz = decode(&outmsg, &inbuf)! as size; assert(decsz == 13); @@ -58,7 +63,12 @@ use bytes; let msg = memio::buffer(&outbuf); - let outmsg = message {...}; + let outmsg = message { + body = reply { + ... + }, + ... + }; let inbuf = memio::dynamic_from(msg); let decsz = decode(&outmsg, &inbuf)! as size; assert(decsz == 13); @@ -91,7 +101,12 @@ use bytes; let msg = memio::buffer(&outbuf); - let outmsg = message {...}; + let outmsg = message { + body = destination_unreachable { + ... + }, + ... + }; let inbuf = memio::dynamic_from(msg); let decsz = decode(&outmsg, &inbuf)! as size; assert(decsz == 4); @@ -117,7 +132,12 @@ use bytes; let msg = memio::buffer(&outbuf); - let outmsg = message {...}; + let outmsg = message { + body = time_exeeded { + ... + }, + ... + }; let inbuf = memio::dynamic_from(msg); let decsz = decode(&outmsg, &inbuf)! as size; assert(decsz == 4); @@ -144,7 +164,12 @@ use bytes; let msg = memio::buffer(&outbuf); - let outmsg = message {...}; + let outmsg = message { + body = parameter_problem { + ... + }, + ... + }; let inbuf = memio::dynamic_from(msg); let decsz = decode(&outmsg, &inbuf)! as size; assert(decsz == 6); -- 2.41.0
Signed-off-by: Conrad Hoffmann <ch@bitfehler.net> --- net/icmp/+test.ha | 5 +++++ net/icmp/message.ha | 14 ++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/net/icmp/+test.ha b/net/icmp/+test.ha index fe79d92..0d4a5b6 100644 --- a/net/icmp/+test.ha +++ b/net/icmp/+test.ha @@ -18,6 +18,7 @@ use bytes; let outbuf = memio::dynamic(); let encsz = encode(&outbuf, &inmsg)!; assert(encsz == 13); + assert(inmsg.checksum == 8672); let msg = memio::buffer(&outbuf); @@ -60,6 +61,7 @@ use bytes; let outbuf = memio::dynamic(); let encsz = encode(&outbuf, &inmsg)!; assert(encsz == 13); + assert(inmsg.checksum == 10720); let msg = memio::buffer(&outbuf); @@ -98,6 +100,7 @@ use bytes; let outbuf = memio::dynamic(); let encsz = encode(&outbuf, &inmsg)!; assert(encsz == 4); + assert(inmsg.checksum == 64757); let msg = memio::buffer(&outbuf); @@ -129,6 +132,7 @@ use bytes; let outbuf = memio::dynamic(); let encsz = encode(&outbuf, &inmsg)!; assert(encsz == 4); + assert(inmsg.checksum == 62709); let msg = memio::buffer(&outbuf); @@ -161,6 +165,7 @@ use bytes; let outbuf = memio::dynamic(); let encsz = encode(&outbuf, &inmsg)!; assert(encsz == 6); + assert(inmsg.checksum == 62440); let msg = memio::buffer(&outbuf); diff --git a/net/icmp/message.ha b/net/icmp/message.ha index cbeefeb..9e2c91f 100644 --- a/net/icmp/message.ha +++ b/net/icmp/message.ha @@ -56,21 +56,19 @@ fn checksum(msg: []u8) u16 = { let cov: size = len(msg) - 1z; let s: u32 = 0; - for (let i = 0z; i < cov; i += 1) { - s += ((msg[i + 1]: u32) << 8) | msg[i]: u32; + for (let i = 0z; i < cov; i += 2) { + s += ((msg[i]: u32) << 8) + msg[i + 1]: u32; }; if (cov & 1 == 0) { s += msg[cov]: u32; }; - s = (s >> 16) + (s & 0xffff); - - s = s + (s >> 16); - - s ^= s: u16; + for ((s >> 16) != 0) { + s = (s >> 16) + (s & 0xffff); + }; - return s: u16; + return ~s: u16; }; // Encodes a [[message]] into the [[io::handle]] provided -- 2.41.0
Signed-off-by: Conrad Hoffmann <ch@bitfehler.net> --- net/icmp/message.ha | 1 + 1 file changed, 1 insertion(+) diff --git a/net/icmp/message.ha b/net/icmp/message.ha index 9e2c91f..6d91b24 100644 --- a/net/icmp/message.ha +++ b/net/icmp/message.ha @@ -74,6 +74,7 @@ fn checksum(msg: []u8) u16 = { // Encodes a [[message]] into the [[io::handle]] provided export fn encode(out: io::handle, in: *message) (size | io::error) = { let msg: []u8 = []; + defer free(msg); let sz = 0z; match (in.body) { -- 2.41.0
Currently IPv4 only, for various reasons. Signed-off-by: Conrad Hoffmann <ch@bitfehler.net> --- cmd/ping/main.ha | 78 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 cmd/ping/main.ha diff --git a/cmd/ping/main.ha b/cmd/ping/main.ha new file mode 100644 index 0000000..d992a5d --- /dev/null +++ b/cmd/ping/main.ha @@ -0,0 +1,78 @@ +use fmt; +use getopt; +use io; +use memio; +use net::icmp; +use net::ip; +use os; +use rt; + +export fn main() void = { + + const cmd = getopt::parse(os::args, + "send ICMP echo requests", + "address", + ); + defer getopt::finish(&cmd); + + if (len(cmd.args) != 1) { + fmt::fatal("Must specify exactly one target address"); + }; + let addr = ip::parse(cmd.args[0])!; + let (icmp_proto, domain, proto) = match (addr) { + case ip::addr4 => + yield (icmp::IP_V4, rt::AF_INET, rt::IPPROTO_ICMP); + case ip::addr6 => + // TODO imcp::encode does not handle v6 atm + // TODO rt is missing IPPROTO_ICMP6 + //yield (icmp::IP_V6, rt::AF_INET6, 58); + fmt::fatal("Error: IPv6 is currently not supported!"); + }; + + static let buf: [512]u8 = [0...]; + + let s = match (rt::socket(domain: int, rt::SOCK_DGRAM, proto)) { + case let s: int => + yield s; + case let err: rt::errno => + fmt::fatalf("Failed to create socket: {}", rt::strerror(err)); + }; + defer io::close(s)!; + + // This would be nice, but rt currently doesn't know about SO_RCVTIMEO + //let timeout = rt::timeval { + // tv_sec = 2, + // tv_usec = 0, + //}; + //let i = rt::setsockopt(s, rt::SOL_SOCKET, rt::SO_RCVTIMEO, &timeout: *void, size(rt::timeval))!; + + let echo = icmp::echo { + id = 1234, + seq = 1, + data = ['1': u8, '2': u8, '3': u8, '4': u8, '5': u8], + }; + + let inmsg = icmp::message { + proto = proto, + code = 0, + checksum = 0, + body = echo, + }; + + let outbuf = memio::fixed(buf[..]); + let encsz = icmp::encode(&outbuf, &inmsg)!; + let sa = ip::to_native(addr, 0); + let data = memio::buffer(&outbuf); + let addrsz = size(rt::sockaddr): u32; + let sz = rt::sendto(s, data: *[*]u8, encsz, 0, &sa, addrsz); + match (sz) { + case let err: rt::errno => + fmt::fatalf("sendto: {}", rt::strerror(err)); + case let s: size => + yield s; + }; + + sz = rt::recvfrom(s, &buf: *[*]u8, 512, 0, &sa, &addrsz)!; + let (from, port) = ip::from_native(sa); + fmt::printfln("Received response from {}", ip::string(from))!; +}; -- 2.41.0