-
Notifications
You must be signed in to change notification settings - Fork 10
/
tcp-echo-client-coro.nelua
119 lines (105 loc) · 3.29 KB
/
tcp-echo-client-coro.nelua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
## pragmas.nogc = true
require 'uv'
require 'coroutine'
local loop: uv_loop_t
-- Asynchronous write.
local function uv_write_async(stream: *uv_stream_t, message: string)
local buf = uv_buf_init(message.data, message.size)
local write_req: uv_write_t
-- Request write.
uv_write(&write_req, stream, &buf, 1, function(req: *uv_write_t, status: cint)
-- Resume the coroutine with the write result.
local co = (@coroutine)(uv_handle_get_data((@*uv_handle_t)(req.handle)))
coroutine.resume(co, status)
end)
-- Wait write request to complete.
coroutine.yield()
local status: cint
coroutine.pop(coroutine.running(), &status)
return status
end
-- Asynchronous TCP connect.
local function uv_tcp_connect_async(tcp: *uv_tcp_t, addr: *sockaddr): (cint, *uv_stream_t)
local connect: uv_connect_t
-- Request connect.
uv_tcp_connect(&connect, tcp, addr, function(req: *uv_connect_t, status: cint)
-- Resume the coroutine with the connect result.
local co = (@coroutine)(uv_handle_get_data((@*uv_handle_t)(req.handle)))
coroutine.resume(co, status)
end)
-- Wait connect request to complete.
coroutine.yield()
local status: cint
coroutine.pop(coroutine.running(), &status)
return status, connect.handle
end
-- Asynchronous read.
local function uv_tcp_read_async(stream: *uv_stream_t): (cint, string)
-- Request read.
uv_read_start(stream,
function(handle: *uv_handle_t, suggested_size: csize, buf: *uv_buf_t)
local readbuf: [1024]cchar <static>
buf.base = &readbuf
buf.len = #readbuf
end,
function(client: *uv_stream_t, nread: clong, buf: *uv_buf_t)
-- Resume the coroutine with the read result.
local co = (@coroutine)(uv_handle_get_data((@*uv_handle_t)(client)))
coroutine.resume(co, nread, buf)
end)
-- Wait the read request to complete.
coroutine.yield()
local buf: *uv_buf_t, nread: clong
coroutine.pop(coroutine.running(), &nread, &buf)
if nread < 0 then
return nread, (@string){}
end
return 0, (@string){data=buf.base, size=buf.len}
end
local function client_request()
-- Initialize TCP.
local client: uv_tcp_t
if uv_tcp_init(&loop, &client) ~= 0 then
error 'failed to init tcp client'
end
uv_handle_set_data((@*uv_handle_t)(&client), coroutine.running())
-- Initialize destination IPv4 address to connect to.
local addr: sockaddr_in
if uv_ip4_addr('127.0.0.1'_cstring, 7000, &addr) ~= 0 then
error 'failed to create ip4 addr'
end
-- Connect.
local status, stream = uv_tcp_connect_async(&client, (@*sockaddr)(&addr))
if status ~= 0 then
error 'connection failed'
end
print('connected')
-- Write a message.
local message = 'hello'
status = uv_write_async(stream, message)
if status ~= 0 then
error 'write failed'
end
print('sent:')
print(message)
-- Read a message.
local status, received_message = uv_tcp_read_async(stream)
if status ~= 0 then
error 'read error'
end
print('received:')
print(received_message)
-- Everything completed, lets end the UV loop.
uv_stop(&loop)
end
-- Initialize UV
if uv_loop_init(&loop) ~= 0 then
error 'failed to init loop'
end
-- Create the client request coroutine and begin it.
local co: coroutine = coroutine.spawn(client_request)
-- Main loop
uv_run(&loop, UV_RUN_DEFAULT)
-- Cleanups.
coroutine.destroy(co)
uv_loop_close(&loop)