| 1 | module main |
| 2 | |
| 3 | import net |
| 4 | import time |
| 5 | |
| 6 | const xport = 15523 |
| 7 | |
| 8 | struct Context { |
| 9 | mut: |
| 10 | ok_client_dials int |
| 11 | fail_client_dials int |
| 12 | |
| 13 | ok_client_close int |
| 14 | fail_client_close int |
| 15 | |
| 16 | ok_server_accepts int |
| 17 | fail_server_accepts int |
| 18 | |
| 19 | ok_server_close int |
| 20 | fail_server_close int |
| 21 | |
| 22 | received []int |
| 23 | } |
| 24 | |
| 25 | fn elog(msg string) { |
| 26 | eprintln('${time.now().format_ss_micro()} | ${msg}') |
| 27 | } |
| 28 | |
| 29 | fn receive_data(mut con net.TcpConn, shared ctx Context) { |
| 30 | mut buf := []u8{len: 5} |
| 31 | for { |
| 32 | bytes := con.read(mut buf) or { -1 } |
| 33 | if bytes < 0 { |
| 34 | break |
| 35 | } |
| 36 | if bytes > 0 { |
| 37 | lock ctx { |
| 38 | ctx.received << buf[0] |
| 39 | } |
| 40 | } |
| 41 | } |
| 42 | con.close() or { |
| 43 | lock ctx { |
| 44 | ctx.fail_server_close++ |
| 45 | } |
| 46 | return |
| 47 | } |
| 48 | lock ctx { |
| 49 | ctx.ok_server_close++ |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | fn start_server(schannel chan int, shared ctx Context) { |
| 54 | elog('server: start_server') |
| 55 | mut tcp_listener := net.listen_tcp(net.AddrFamily.ip, ':${xport}') or { |
| 56 | elog('server: start server error ${err}') |
| 57 | return |
| 58 | } |
| 59 | elog('server: server started listening at port :${xport}') |
| 60 | schannel <- 0 |
| 61 | |
| 62 | for { |
| 63 | mut tcp_con := tcp_listener.accept() or { |
| 64 | elog('server: accept error: ${err}') |
| 65 | lock ctx { |
| 66 | ctx.fail_server_accepts++ |
| 67 | } |
| 68 | continue |
| 69 | } |
| 70 | spawn receive_data(mut tcp_con, shared ctx) |
| 71 | lock ctx { |
| 72 | ctx.ok_server_accepts++ |
| 73 | } |
| 74 | elog('server: new tcp connection con.sock.handle: ${tcp_con.sock.handle}') |
| 75 | continue |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | fn start_client(i int, shared ctx Context) { |
| 80 | elog('client [${i}]: start') |
| 81 | mut tcp_con := net.dial_tcp('127.0.0.1:${xport}') or { |
| 82 | elog('client [${i}]: net.dial_tcp err ${err}') |
| 83 | lock ctx { |
| 84 | ctx.fail_client_dials++ |
| 85 | } |
| 86 | return |
| 87 | } |
| 88 | lock ctx { |
| 89 | ctx.ok_client_dials++ |
| 90 | } |
| 91 | elog('client [${i}]: conn is connected, con.sock.handle: ${tcp_con.sock.handle}') |
| 92 | tcp_con.write([u8(i)]) or { elog('client [${i}]: write failed, err: ${err}') } |
| 93 | time.sleep(1 * time.second) |
| 94 | elog('client [${i}]: closing connection...') |
| 95 | tcp_con.close() or { |
| 96 | elog('client [${i}]: close failed, err: ${err}') |
| 97 | lock ctx { |
| 98 | ctx.fail_client_close++ |
| 99 | } |
| 100 | return |
| 101 | } |
| 102 | lock ctx { |
| 103 | ctx.ok_client_close++ |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | fn test_tcp_self_dialing() { |
| 108 | elog('>>> start') |
| 109 | start_time := time.now() |
| 110 | shared ctx := &Context{} |
| 111 | mut server_channel := chan int{cap: 1} |
| 112 | spawn start_server(server_channel, shared ctx) |
| 113 | svalue := <-server_channel |
| 114 | elog('>>> server was started: ${svalue}. Starting clients:') |
| 115 | for i := int(0); i < 20; i++ { |
| 116 | spawn start_client(i, shared ctx) |
| 117 | elog('>>> started client ${i}') |
| 118 | // time.sleep(2 * time.millisecond) |
| 119 | } |
| 120 | max_dt := 5 * time.second |
| 121 | for { |
| 122 | t := time.now() |
| 123 | dt := t - start_time |
| 124 | if dt > max_dt { |
| 125 | elog('>>> exiting after ${dt.milliseconds()} ms ...') |
| 126 | lock ctx { |
| 127 | // TODO: fix `dump(ctx)`, when `shared ctx := Type{}` |
| 128 | final_value_for_ctx := ctx // make a value copy as a temporary workaround. TODO: remove when dump(ctx) works. |
| 129 | dump(final_value_for_ctx) |
| 130 | assert ctx.fail_client_dials < 2, 'allowed failed client dials, from ${ctx.ok_server_accepts} connections' |
| 131 | assert ctx.received.len > ctx.ok_server_accepts / 2, 'at least half the clients sent some data, that was later received by the server' |
| 132 | } |
| 133 | elog('>>> goodbye') |
| 134 | exit(0) |
| 135 | } |
| 136 | time.sleep(10 * time.millisecond) |
| 137 | } |
| 138 | } |
| 139 | |