nbio/tcp-echo

Code

main.odin ¶
74 linesSource

1/*
2This example shows a simple TCP server that echos back anything it receives.
3
4Better error handling and closing/freeing connections are left for the reader.
5
6You can run this with the netcat utility as the client like so: `nc 127.0.0.1 1234`.
7*/
8package main
9
10import "core:container/xar"
11import "core:fmt"
12import "core:nbio"
13
14Server :: struct {
15	socket:      nbio.TCP_Socket,
16	// Xar is used in favor of `[dynamic]Connection` so pointers are stable.
17	connections: xar.Array(Connection, 4),
18}
19
20Connection :: struct {
21	server: ^Server,
22	sock:   nbio.TCP_Socket,
23	buf:    [50]byte,
24}
25
26main :: proc() {
27	err := nbio.acquire_thread_event_loop()
28	fmt.assertf(err == nil, "Could not initialize nbio: %v", err)
29	defer nbio.release_thread_event_loop()
30
31	server: Server
32
33	socket, listen_err := nbio.listen_tcp({nbio.IP4_Any, 1234})
34	fmt.assertf(listen_err == nil, "Error listening on localhost:1234: %v", listen_err)
35	server.socket = socket
36
37	nbio.accept_poly(socket, &server, on_accept)
38
39	rerr := nbio.run()
40	fmt.assertf(rerr == nil, "Server stopped with error: %v", rerr)
41}
42
43on_accept :: proc(op: ^nbio.Operation, server: ^Server) {
44	fmt.assertf(op.accept.err == nil, "Error accepting a connection: %v", op.accept.err)
45
46	// Register a new accept for the next client.
47	nbio.accept_poly(server.socket, server, on_accept)
48
49	connection, alloc_err := xar.push_back_elem_and_get_ptr(&server.connections, Connection{
50		server = server,
51		sock   = op.accept.client,
52	})
53	assert(alloc_err == nil)
54
55	nbio.recv_poly(op.accept.client, {connection.buf[:]}, connection, on_recv)
56}
57
58on_recv :: proc(op: ^nbio.Operation, connection: ^Connection) {
59	fmt.assertf(op.recv.err == nil, "Error receiving from client: %v", op.recv.err)
60	if op.recv.received == 0 {
61		// NOTE: leaking `connection`.
62		nbio.close(connection.sock)
63		return
64	}
65
66	nbio.send_poly(connection.sock, {connection.buf[:op.recv.received]}, connection, on_sent)
67}
68
69on_sent :: proc(op: ^nbio.Operation, connection: ^Connection) {
70	fmt.assertf(op.send.err == nil, "Error sending to client: %v", op.send.err)
71
72	// Accept the next message, to then ultimately echo back again.
73	nbio.recv_poly(connection.sock, {connection.buf[:]}, connection, on_recv)
74}

Declarations Used 14