| 1 | import net |
| 2 | import time |
| 3 | |
| 4 | fn echo_server(mut c net.UdpConn) { |
| 5 | mut count := 0 |
| 6 | for { |
| 7 | eprintln('> echo_server loop count: ${count}') |
| 8 | mut buf := []u8{len: 100} |
| 9 | read, addr := c.read(mut buf) or { continue } |
| 10 | eprintln('Server got addr ${addr}, read: ${read} | buf: ${buf}') |
| 11 | c.write_to(addr, buf[..read]) or { |
| 12 | println('Server: connection dropped') |
| 13 | return |
| 14 | } |
| 15 | count++ |
| 16 | // Normally, after responding, the test will end, but there are sometimes cases, |
| 17 | // when the echo_server continued looping, printing messages constantly. |
| 18 | // The sleep here, is a small precaution against spamming the CI with log messages, |
| 19 | // when there are network problems, and it allows easier root cause diagnostic, when |
| 20 | // they do happen: |
| 21 | time.sleep(1000 * time.millisecond) |
| 22 | } |
| 23 | } |
| 24 | |
| 25 | const server_addr = '127.0.0.1:40003' |
| 26 | |
| 27 | fn echo() ! { |
| 28 | mut c := net.dial_udp(server_addr) or { panic('could not net.dial_udp: ${err}') } |
| 29 | defer { |
| 30 | c.close() or {} |
| 31 | } |
| 32 | data := 'Hello from vlib/net!' |
| 33 | |
| 34 | c.write_string(data) or { panic('could not write_string: ${err}') } |
| 35 | |
| 36 | mut buf := []u8{len: 100, init: 0} |
| 37 | read, addr := c.read(mut buf) or { panic('could not read: ${err}') } |
| 38 | |
| 39 | assert read == data.len |
| 40 | println('Got address ${addr}') |
| 41 | // Can't test this here because loopback addresses |
| 42 | // are mapped to other addresses |
| 43 | // assert addr.str() == '127.0.0.1:30001' |
| 44 | |
| 45 | for i := 0; i < read; i++ { |
| 46 | assert buf[i] == data[i] |
| 47 | } |
| 48 | |
| 49 | println('Got "${buf.bytestr()}"') |
| 50 | |
| 51 | c.close()! |
| 52 | } |
| 53 | |
| 54 | fn test_udp() { |
| 55 | mut l := net.listen_udp(server_addr) or { panic('could not listen_udp: ${err}') } |
| 56 | |
| 57 | spawn echo_server(mut l) |
| 58 | echo() or { panic('could not echo: ${err}') } |
| 59 | |
| 60 | l.close() or {} |
| 61 | } |
| 62 | |
| 63 | fn udp_write_after_delay(addr string, delay time.Duration, payload string, done chan bool) { |
| 64 | time.sleep(delay) |
| 65 | mut conn := net.dial_udp(addr) or { panic(err) } |
| 66 | defer { |
| 67 | conn.close() or {} |
| 68 | } |
| 69 | conn.write_string(payload) or { panic(err) } |
| 70 | done <- true |
| 71 | } |
| 72 | |
| 73 | fn test_udp_read_timeout_is_honored_for_blocking_reads() ! { |
| 74 | mut listener := net.listen_udp('127.0.0.1:0')! |
| 75 | defer { |
| 76 | listener.close() or {} |
| 77 | } |
| 78 | addr := listener.sock.address()!.str() |
| 79 | delay := 200 * time.millisecond |
| 80 | timeout := 20 * time.millisecond |
| 81 | payload := 'late udp packet' |
| 82 | done := chan bool{cap: 1} |
| 83 | |
| 84 | spawn udp_write_after_delay(addr, delay, payload, done) |
| 85 | listener.set_read_timeout(timeout) |
| 86 | |
| 87 | mut buf := []u8{len: payload.len} |
| 88 | if _, _ := listener.read(mut buf) { |
| 89 | assert false, 'expected udp read timeout before delayed packet arrived' |
| 90 | } else { |
| 91 | assert err.code() == net.err_timed_out_code |
| 92 | } |
| 93 | |
| 94 | _ = <-done |
| 95 | listener.set_read_timeout(time.second) |
| 96 | read, _ := listener.read(mut buf)! |
| 97 | assert read == payload.len |
| 98 | assert buf[..read].bytestr() == payload |
| 99 | } |
| 100 | |
| 101 | fn test_udp_multicast_ipv4_socket_options() ! { |
| 102 | mut listener := net.listen_udp('0.0.0.0:0')! |
| 103 | defer { |
| 104 | listener.close() or {} |
| 105 | } |
| 106 | |
| 107 | listener.join_multicast_group('224.0.0.1', '0.0.0.0')! |
| 108 | listener.leave_multicast_group('224.0.0.1', '0.0.0.0')! |
| 109 | listener.set_multicast_ttl(2)! |
| 110 | listener.set_multicast_loop(true)! |
| 111 | listener.set_multicast_loop(false)! |
| 112 | listener.set_multicast_interface('0.0.0.0')! |
| 113 | } |
| 114 | |
| 115 | fn test_udp_multicast_validates_inputs() ! { |
| 116 | mut listener := net.listen_udp('0.0.0.0:0')! |
| 117 | defer { |
| 118 | listener.close() or {} |
| 119 | } |
| 120 | |
| 121 | mut ttl_failed := false |
| 122 | listener.set_multicast_ttl(-1) or { |
| 123 | ttl_failed = true |
| 124 | assert err.msg().contains('multicast ttl') |
| 125 | } |
| 126 | assert ttl_failed |
| 127 | |
| 128 | mut non_multicast_failed := false |
| 129 | listener.join_multicast_group('127.0.0.1', '') or { |
| 130 | non_multicast_failed = true |
| 131 | assert err.msg().contains('not an ipv4 multicast address') |
| 132 | } |
| 133 | assert non_multicast_failed |
| 134 | |
| 135 | mut iface_failed := false |
| 136 | listener.set_multicast_interface('not-an-ip') or { |
| 137 | iface_failed = true |
| 138 | assert err.msg().contains('ipv4 multicast interface') |
| 139 | } |
| 140 | assert iface_failed |
| 141 | } |
| 142 | |