mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
97 lines
2.9 KiB
C
97 lines
2.9 KiB
C
module std::net @if(os::SUPPORTS_INET);
|
|
import std::io;
|
|
import libc;
|
|
|
|
struct Socket
|
|
{
|
|
inline Stream stream;
|
|
NativeSocket sock;
|
|
Socklen_t ai_addrlen;
|
|
// TODO proper way to get the size of sockaddr_storage
|
|
// https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms740504(v=vs.85)
|
|
char[128] ai_addr_storage;
|
|
}
|
|
|
|
macro void @loop_over_ai(AddrInfo* ai; @body(NativeSocket fd, AddrInfo* ai))
|
|
{
|
|
while (ai)
|
|
{
|
|
NativeSocket sockfd = os::socket(ai.ai_family, ai.ai_socktype, ai.ai_protocol);
|
|
if (sockfd > 0)
|
|
{
|
|
@body(sockfd, ai);
|
|
}
|
|
ai = ai.ai_next;
|
|
}
|
|
}
|
|
|
|
macro Socket new_socket(fd, ai)
|
|
{
|
|
Socket sock = { .stream.fns = &SOCKETSTREAM_INTERFACE, .sock = fd, .ai_addrlen = ai.ai_addrlen };
|
|
assert(sock.ai_addr_storage.len >= ai.ai_addrlen, "storage %d < addrlen %d", sock.ai_addr_storage.len, ai.ai_addrlen);
|
|
mem::copy(&sock.ai_addr_storage, (void*)ai.ai_addr, ai.ai_addrlen);
|
|
return sock;
|
|
}
|
|
|
|
enum SocketOption : char (CInt value)
|
|
{
|
|
REUSEADDR (os::SO_REUSEADDR),
|
|
REUSEPORT (os::SO_REUSEPORT) @if(!env::WIN32),
|
|
KEEPALIVE (os::SO_KEEPALIVE),
|
|
BROADCAST (os::SO_BROADCAST),
|
|
OOBINLINE (os::SO_OOBINLINE),
|
|
DONTROUTE (os::SO_DONTROUTE),
|
|
}
|
|
|
|
const StreamInterface SOCKETSTREAM_INTERFACE = {
|
|
.read_fn = (ReadStreamFn)&Socket.read,
|
|
.write_fn = (WriteStreamFn)&Socket.write,
|
|
.close_fn = (CloseStreamFn)&Socket.close,
|
|
};
|
|
|
|
fn bool! Socket.get_broadcast(&self) => self.get_option(BROADCAST);
|
|
fn bool! Socket.get_keepalive(&self) => self.get_option(KEEPALIVE);
|
|
fn bool! Socket.get_reuseaddr(&self) => self.get_option(REUSEADDR);
|
|
fn bool! Socket.get_dontroute(&self) => self.get_option(DONTROUTE);
|
|
fn bool! Socket.get_oobinline(&self) => self.get_option(OOBINLINE);
|
|
|
|
fn void! Socket.set_broadcast(&self, bool value) => self.set_option(BROADCAST, value);
|
|
fn void! Socket.set_keepalive(&self, bool value) => self.set_option(KEEPALIVE, value);
|
|
fn void! Socket.set_reuseaddr(&self, bool value) => self.set_option(REUSEADDR, value);
|
|
fn void! Socket.set_dontroute(&self, bool value) => self.set_option(DONTROUTE, value);
|
|
fn void! Socket.set_oobinline(&self, bool value) => self.set_option(OOBINLINE, value);
|
|
|
|
fn void! Socket.set_option(&self, SocketOption option, bool value)
|
|
{
|
|
CInt flag = (CInt)value;
|
|
int errcode = os::setsockopt(self.sock, os::SOL_SOCKET, option.value, &flag, CInt.sizeof);
|
|
if (errcode != 0) return NetError.SOCKOPT_FAILED?;
|
|
}
|
|
|
|
fn bool! Socket.get_option(&self, SocketOption option)
|
|
{
|
|
CInt flag;
|
|
int errcode = os::setsockopt(self.sock, os::SOL_SOCKET, option.value, &flag, CInt.sizeof);
|
|
if (errcode != 0) return NetError.SOCKOPT_FAILED?;
|
|
return (bool)flag;
|
|
}
|
|
|
|
fn usz! Socket.read(&self, char[] bytes)
|
|
{
|
|
isz n = libc::read((Fd)self.sock, bytes.ptr, bytes.len);
|
|
if (n < 0) return NetError.READ_FAILED?;
|
|
return (usz)n;
|
|
}
|
|
|
|
fn usz! Socket.write(&self, char[] bytes)
|
|
{
|
|
isz n = libc::write((Fd)self.sock, bytes.ptr, bytes.len);
|
|
if (n < 0) return NetError.WRITE_FAILED?;
|
|
return (usz)n;
|
|
}
|
|
|
|
fn void! Socket.close(&self) @inline
|
|
{
|
|
self.sock.close()!;
|
|
}
|