Skip to content

Commit f57e52b

Browse files
committed
Start working TCP server
1 parent c7272cf commit f57e52b

File tree

2 files changed

+130
-0
lines changed

2 files changed

+130
-0
lines changed

libraries/common/io/network.effekt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@ def close(handle: Connection): Unit / Exception[IOError] = {
2121
internal::checkResult(internal::close(handle)); ()
2222
}
2323

24+
/// A tcp listener. Should not be inspected.
25+
type Listener = Int
26+
27+
def listen(host: String, port: Int, backlog: Int): Listener / Exception[IOError] =
28+
internal::checkResult(internal::listen(host, port, backlog))
29+
30+
def accept(listener: Listener): Connection / Exception[IOError] =
31+
internal::checkResult(internal::accept(listener))
32+
33+
def close_listener(listener: Listener): Unit / Exception[IOError] = {
34+
internal::checkResult(internal::close_listener(listener)); ()
35+
}
2436

2537
namespace internal {
2638

@@ -29,6 +41,9 @@ namespace internal {
2941
declare void @c_tcp_read(%Int, %Pos, %Int, %Int, %Stack)
3042
declare void @c_tcp_write(%Int, %Pos, %Int, %Int, %Stack)
3143
declare void @c_tcp_close(%Int, %Stack)
44+
declare void @c_tcp_listen(%Pos, %Int, %Int, %Stack)
45+
declare void @c_tcp_accept(%Int, %Stack)
46+
declare void @c_tcp_close_listener(%Int, %Stack)
3247
"""
3348

3449
extern async def connect(host: String, port: Int): Int =
@@ -55,6 +70,24 @@ namespace internal {
5570
ret void
5671
"""
5772

73+
extern async def listen(host: String, port: Int, backlog: Int): Int =
74+
llvm """
75+
call void @c_tcp_listen(%Pos ${host}, %Int ${port}, %Int ${backlog}, %Stack %stack)
76+
ret void
77+
"""
78+
79+
extern async def accept(listener: Int): Int =
80+
llvm """
81+
call void @c_tcp_accept(%Int ${listener}, %Stack %stack)
82+
ret void
83+
"""
84+
85+
extern async def close_listener(handle: Int): Int =
86+
llvm """
87+
call void @c_tcp_close_listener(%Int ${handle}, %Stack %stack)
88+
ret void
89+
"""
90+
5891
}
5992

6093

libraries/llvm/io.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ void c_tcp_write(Int handle, struct Pos buffer, Int offset, Int size, Stack stac
305305
void c_tcp_close_cb(uv_handle_t* handle) {
306306
Stack stack = (Stack)handle->data;
307307
free(handle);
308+
// TODO resume_Pos Unit
308309
resume_Int(stack, 0);
309310
}
310311

@@ -314,6 +315,102 @@ void c_tcp_close(Int handle, Stack stack) {
314315
uv_close(uv_handle, c_tcp_close_cb);
315316
}
316317

318+
void c_tcp_listen(String host, Int port, Int backlog, Stack stack) {
319+
// TODO make non-async
320+
char* host_str = c_bytearray_into_nullterminated_string(host);
321+
erasePositive(host);
322+
323+
uv_tcp_t* tcp_handle = malloc(sizeof(uv_tcp_t));
324+
int result = uv_tcp_init(uv_default_loop(), tcp_handle);
325+
326+
if (result < 0) {
327+
free(tcp_handle);
328+
free(host_str);
329+
resume_Int(stack, result);
330+
return;
331+
}
332+
333+
struct sockaddr_in addr;
334+
result = uv_ip4_addr(host_str, port, &addr);
335+
free(host_str);
336+
337+
if (result < 0) {
338+
free(tcp_handle);
339+
resume_Int(stack, result);
340+
return;
341+
}
342+
343+
result = uv_tcp_bind(tcp_handle, (const struct sockaddr*)&addr, 0);
344+
if (result < 0) {
345+
free(tcp_handle);
346+
resume_Int(stack, result);
347+
return;
348+
}
349+
350+
result = uv_listen((uv_stream_t*)tcp_handle, backlog, NULL);
351+
if (result < 0) {
352+
free(tcp_handle);
353+
resume_Int(stack, result);
354+
return;
355+
}
356+
357+
resume_Int(stack, (int64_t)tcp_handle);
358+
}
359+
360+
void c_tcp_accept_cb(uv_stream_t* server, int status) {
361+
Stack stack = (Stack)server->data;
362+
363+
if (status < 0) {
364+
resume_Int(stack, status);
365+
return;
366+
}
367+
368+
uv_tcp_t* client = malloc(sizeof(uv_tcp_t));
369+
int result = uv_tcp_init(uv_default_loop(), client);
370+
371+
if (result < 0) {
372+
free(client);
373+
// TODO share stack?
374+
resume_Int(stack, result);
375+
return;
376+
}
377+
378+
result = uv_accept(server, (uv_stream_t*)client);
379+
if (result < 0) {
380+
uv_close((uv_handle_t*)client, NULL);
381+
free(client);
382+
// TODO share stack?
383+
resume_Int(stack, result);
384+
return;
385+
}
386+
387+
// TODO share resumption
388+
// shareStack(stack);
389+
resume_Int(stack, (int64_t)client);
390+
}
391+
392+
void c_tcp_accept(Int server_handle, Stack stack) {
393+
uv_stream_t* server = (uv_stream_t*)server_handle;
394+
server->data = stack; // Store stack for multiple resumes
395+
396+
int result = uv_listen(server, 0, c_tcp_accept_cb);
397+
if (result < 0) {
398+
resume_Int(stack, result);
399+
}
400+
}
401+
402+
void c_tcp_close_listener(Int handle, Stack stack) {
403+
uv_handle_t* uv_handle = (uv_handle_t*)handle;
404+
405+
Stack registered_stack = (Stack)uv_handle->data;
406+
if (registered_stack) {
407+
eraseStack(registered_stack);
408+
}
409+
410+
uv_handle->data = stack;
411+
uv_close(uv_handle, c_tcp_close_cb);
412+
}
413+
317414

318415
/**
319416
* Maps the libuv error code to a stable (platform independent) numeric value.

0 commit comments

Comments
 (0)