Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/socket/ffi.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ fn check_socket_err(sock : Int) -> Unit raise {
}
}

///|
extern "C" fn enable_keepalive_ffi(
sock : Int,
keep_idle : Int,
keep_count : Int,
keep_intv : Int
) -> Int = "moonbitlang_async_enable_keepalive"

///|
#borrow(buf, addr_buf)
extern "C" fn recvfrom_ffi(
Expand Down
34 changes: 34 additions & 0 deletions src/socket/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <stdint.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <stdio.h>
#include <fcntl.h>
#include <moonbit.h>
Expand Down Expand Up @@ -98,6 +99,39 @@ int moonbitlang_async_getsockerr(int sockfd) {
return err;
}

int moonbitlang_async_enable_keepalive(
int sock,
int keep_idle,
int keep_cnt,
int keep_intvl
) {
int value = 1;
if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &value, sizeof(int)) < 0)
return -1;

if (keep_cnt > 0) {
if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keep_cnt, sizeof(int)) < 0)
return -1;
}

if (keep_idle > 0) {
#ifdef __MACH__
if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPALIVE, &keep_idle, sizeof(int)) < 0)
return -1;
#elifdef __linux__
if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keep_idle, sizeof(int)) < 0)
return -1;
#endif
}

if (keep_intvl > 0) {
if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keep_intvl, sizeof(int)) < 0)
return -1;
}

return 0;
}

void *moonbitlang_async_make_ip_addr(uint32_t ip, int port) {
struct sockaddr_in *addr = (struct sockaddr_in*)moonbit_make_bytes(
sizeof(struct sockaddr_in),
Expand Down
1 change: 1 addition & 0 deletions src/socket/socket.mbti
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ async fn TCP::accept(Self) -> (Self, Addr) raise
fn TCP::bind(Self, Addr) -> Unit raise
fn TCP::close(Self) -> Unit
async fn TCP::connect(Self, Addr) -> Unit raise
fn TCP::enable_keepalive(Self, idle_before_keep_alive~ : Int = .., keep_alive_count~ : Int = .., keep_alive_interval~ : Int = ..) -> Unit raise
fn TCP::listen(Self) -> Unit raise
fn TCP::new() -> Self
async fn TCP::recv(Self, FixedArray[Byte], offset~ : Int = .., max_len? : Int) -> Int raise
Expand Down
25 changes: 25 additions & 0 deletions src/socket/tcp.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,31 @@ pub fn TCP::listen(self : TCP) -> Unit raise {
}
}

///|
/// Enable TCP keep alive on the socket.
///
/// `idle_before_keep_alive` is the duration of idle time in seconds to wait
/// before sending the first keep alive probe.
///
/// `keep_alive_count` is the number of keep alive probe to try
/// before closing the connection.
///
/// `keep_alive_interval` is the time in seconds between two keep alive probes.
pub fn TCP::enable_keepalive(
self : TCP,
idle_before_keep_alive~ : Int = -1,
keep_alive_count~ : Int = -1,
keep_alive_interval~ : Int = -1
) -> Unit raise {
let TCP(sock) = self
let ret = enable_keepalive_ffi(
sock, idle_before_keep_alive, keep_alive_count, keep_alive_interval,
)
if ret < 0 {
@os_error.check_errno()
}
}

///|
/// Accept a new connection on a listening socket using `accept(2)` system call.
/// A new socket representing the accepted connection
Expand Down
Loading