mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-04 06:38:47 +00:00
posix: add package
This commit is contained in:
@@ -0,0 +1,491 @@
|
||||
package posix
|
||||
|
||||
import "core:c"
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
foreign import libc "system:c"
|
||||
}
|
||||
|
||||
// sys/socket.h - main sockets header
|
||||
|
||||
#assert(Protocol.IP == Protocol(0), "socket() assumes this")
|
||||
|
||||
foreign libc {
|
||||
/*
|
||||
Creates a socket.
|
||||
|
||||
Returns: -1 (setting errno) on failure, file descriptor of socket otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html ]]
|
||||
*/
|
||||
@(link_name=LSOCKET)
|
||||
socket :: proc(domain: AF, type: Sock, protocol: Protocol = .IP) -> FD ---
|
||||
|
||||
/*
|
||||
Extracts the first connection on the queue of pending connections.
|
||||
|
||||
Blocks (if not O_NONBLOCK) if there is no pending connection.
|
||||
|
||||
Returns: -1 (setting errno) on failure, file descriptor of accepted socket otherwise
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html ]]
|
||||
*/
|
||||
accept :: proc(socket: FD, address: ^sockaddr, address_len: ^socklen_t) -> FD ---
|
||||
|
||||
/*
|
||||
Assigns a local socket address to the socket.
|
||||
|
||||
Example:
|
||||
sfd := posix.socket(.UNIX, .STREAM)
|
||||
if sfd == -1 {
|
||||
/* Handle error */
|
||||
}
|
||||
|
||||
addr: posix.sockaddr_un
|
||||
addr.sun_family = .UNIX
|
||||
copy(addr.sun_path[:], "/somepath\x00")
|
||||
|
||||
if posix.bind(sfd, (^posix.sockaddr)(&addr), size_of(addr)) != .OK {
|
||||
/* Handle error */
|
||||
}
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html ]]
|
||||
*/
|
||||
bind :: proc(socket: FD, address: ^sockaddr, address_len: socklen_t) -> result ---
|
||||
|
||||
/*
|
||||
Attempt to make a connection.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html ]]
|
||||
*/
|
||||
connect :: proc(socket: FD, address: ^sockaddr, address_len: socklen_t) -> result ---
|
||||
|
||||
/*
|
||||
Get the peer address of the specified socket.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html ]]
|
||||
*/
|
||||
getpeername :: proc(socket: FD, address: ^sockaddr, address_len: ^socklen_t) -> result ---
|
||||
|
||||
/*
|
||||
Get the socket name.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html ]]
|
||||
*/
|
||||
getsockname :: proc(socket: FD, address: ^sockaddr, address_len: ^socklen_t) -> result ---
|
||||
|
||||
/*
|
||||
Retrieves the value for the option specified by option_name.
|
||||
|
||||
level: either `c.int(posix.Protocol(...))` to specify a protocol level or `posix.SOL_SOCKET`
|
||||
to specify the socket local level.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html ]]
|
||||
*/
|
||||
getsockopt :: proc(
|
||||
socket: FD,
|
||||
level: c.int,
|
||||
option_name: Sock_Option,
|
||||
option_value: rawptr,
|
||||
option_len: ^socklen_t,
|
||||
) -> result ---
|
||||
|
||||
/*
|
||||
Sets the specified option.
|
||||
|
||||
level: either `c.int(posix.Protocol(...))` to specify a protocol level or `posix.SOL_SOCKET`
|
||||
to specify the socket local level.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html ]]
|
||||
*/
|
||||
setsockopt :: proc(
|
||||
socket: FD,
|
||||
level: c.int,
|
||||
option_name: Sock_Option,
|
||||
option_value: rawptr,
|
||||
option_len: socklen_t,
|
||||
) -> result ---
|
||||
|
||||
/*
|
||||
Mark the socket as a socket accepting connections.
|
||||
|
||||
backlog provides a hint to limit the number of connections on the listen queue.
|
||||
Implementation may silently reduce the backlog, additionally `SOMAXCONN` specifies the maximum
|
||||
an implementation has to support.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html ]]
|
||||
*/
|
||||
listen :: proc(socket: FD, backlog: c.int) -> result ---
|
||||
|
||||
/*
|
||||
Receives a message from a socket.
|
||||
|
||||
Blocks (besides with O_NONBLOCK) if there is nothing to receive.
|
||||
|
||||
Returns: 0 when the peer shutdown with no more messages, -1 (setting errno) on failure, the amount of bytes received on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html ]]
|
||||
*/
|
||||
recv :: proc(socket: FD, buffer: rawptr, length: c.size_t, flags: Msg_Flags) -> c.ssize_t ---
|
||||
|
||||
/*
|
||||
Receives a message from a socket.
|
||||
|
||||
Equivalent to recv() but retrieves the source address too.
|
||||
|
||||
Returns: 0 when the peer shutdown with no more messages, -1 (setting errno) on failure, the amount of bytes received on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html ]]
|
||||
*/
|
||||
recvfrom :: proc(
|
||||
socket: FD,
|
||||
buffer: rawptr,
|
||||
length: c.size_t,
|
||||
flags: Msg_Flags,
|
||||
address: ^sockaddr,
|
||||
address_len: ^socklen_t,
|
||||
) -> c.ssize_t ---
|
||||
|
||||
/*
|
||||
Receives a message from a socket.
|
||||
|
||||
Returns: 0 when the peer shutdown with no more messages, -1 (setting errno) on failure, the amount of bytes received on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html ]]
|
||||
*/
|
||||
recvmsg :: proc(socket: FD, message: ^msghdr, flags: Msg_Flags) -> c.ssize_t ---
|
||||
|
||||
/*
|
||||
Sends a message on a socket.
|
||||
|
||||
Returns: -1 (setting errno) on failure, the amount of bytes received on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html ]]
|
||||
*/
|
||||
send :: proc(socket: FD, buffer: rawptr, length: c.size_t, flags: Msg_Flags) -> c.ssize_t ---
|
||||
|
||||
/*
|
||||
Sends a message on a socket.
|
||||
|
||||
Returns: -1 (setting errno) on failure, the amount of bytes received on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html ]]
|
||||
*/
|
||||
sendmsg :: proc(socket: FD, message: ^msghdr, flags: Msg_Flags) -> c.ssize_t ---
|
||||
|
||||
/*
|
||||
Sends a message on a socket.
|
||||
|
||||
If the socket is connectionless, the dest_addr is used to send to.
|
||||
|
||||
Returns: -1 (setting errno) on failure, the amount of bytes received on success
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html ]]
|
||||
*/
|
||||
sendto :: proc(
|
||||
socket: FD,
|
||||
message: rawptr,
|
||||
length: c.size_t,
|
||||
flags: Msg_Flags,
|
||||
dest_addr: ^sockaddr,
|
||||
dest_len: socklen_t,
|
||||
) -> c.ssize_t ---
|
||||
|
||||
/*
|
||||
Shuts down a socket end or both.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html ]]
|
||||
*/
|
||||
shutdown :: proc(socket: FD, how: Shut) -> result ---
|
||||
|
||||
/*
|
||||
Determine wheter a socket is at the out-of-band mark.
|
||||
|
||||
Returns: -1 (setting errno) on failure, 0 if not at the mark, 1 if it is
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sockatmark.html ]]
|
||||
*/
|
||||
sockatmark :: proc(socket: FD) -> c.int ---
|
||||
|
||||
/*
|
||||
Create a pair of connected sockets.
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html ]]
|
||||
*/
|
||||
socketpair :: proc(domain: AF, type: Sock, protocol: Protocol, socket_vector: ^[2]FD) -> result ---
|
||||
}
|
||||
|
||||
AF_UNSPEC :: 0
|
||||
|
||||
AF :: enum c.int {
|
||||
// Unspecified.
|
||||
UNSPEC = AF_UNSPEC,
|
||||
// Internet domain sockets for use with IPv4 addresses.
|
||||
INET = AF_INET,
|
||||
// Internet domain sockets for use with IPv6 addresses.
|
||||
INET6 = AF_INET6,
|
||||
// UNIX domain sockets.
|
||||
UNIX = AF_UNIX,
|
||||
}
|
||||
|
||||
sa_family_t :: enum _sa_family_t {
|
||||
// Unspecified.
|
||||
UNSPEC = AF_UNSPEC,
|
||||
// Internet domain sockets for use with IPv4 addresses.
|
||||
INET = AF_INET,
|
||||
// Internet domain sockets for use with IPv6 addresses.
|
||||
INET6 = AF_INET6,
|
||||
// UNIX domain sockets.
|
||||
UNIX = AF_UNIX,
|
||||
}
|
||||
|
||||
Sock :: enum c.int {
|
||||
// Datagram socket.
|
||||
DGRAM = SOCK_DGRAM,
|
||||
// Raw Protocol Interface.
|
||||
RAW = SOCK_RAW,
|
||||
// Sequenced-packet socket.
|
||||
SEQPACKET = SOCK_SEQPACKET,
|
||||
// Byte-stream socket.
|
||||
STREAM = SOCK_STREAM,
|
||||
}
|
||||
|
||||
Shut :: enum c.int {
|
||||
// Disables further receive operations.
|
||||
RD = SHUT_RD,
|
||||
// Disables further send and receive operations.
|
||||
RDWR = SHUT_RDWR,
|
||||
// Disables further send operations.
|
||||
WR = SHUT_WR,
|
||||
}
|
||||
|
||||
Msg_Flag_Bits :: enum c.int {
|
||||
// Control data truncated.
|
||||
CTRUNC = log2(MSG_CTRUNC),
|
||||
// Send without using routing table.
|
||||
DONTROUTE = log2(MSG_DONTROUTE),
|
||||
// Terminates a record (if supported by protocol).
|
||||
EOR = log2(MSG_EOR),
|
||||
// Out-of-band data.
|
||||
OOB = log2(MSG_OOB),
|
||||
// No SIGPIPE is generated when an attempt to send is made on a stream-oriented socket that is
|
||||
// no longer connected.
|
||||
NOSIGNAL = log2(MSG_NOSIGNAL),
|
||||
// Leave received data in queue.
|
||||
PEEK = log2(MSG_PEEK),
|
||||
// Normal data truncated.
|
||||
TRUNC = log2(MSG_TRUNC),
|
||||
// Attempt to fill the read buffer.
|
||||
WAITALL = log2(MSG_WAITALL),
|
||||
}
|
||||
Msg_Flags :: bit_set[Msg_Flag_Bits; c.int]
|
||||
|
||||
Sock_Option :: enum c.int {
|
||||
// Transmission of broadcast message is supported.
|
||||
BROADCAST = SO_BROADCAST,
|
||||
// Debugging information is being recorded.
|
||||
DEBUG = SO_DEBUG,
|
||||
// Bypass normal routing.
|
||||
DONTROUTE = SO_DONTROUTE,
|
||||
// Socket error status.
|
||||
ERROR = SO_ERROR,
|
||||
// Connections are kept alive with periodic messages.
|
||||
KEEPALIVE = SO_KEEPALIVE,
|
||||
// Socket lingers on close.
|
||||
LINGER = SO_LINGER,
|
||||
// Out-of-band data is transmitted in line.
|
||||
OOBINLINE = SO_OOBINLINE,
|
||||
// Receive buffer size.
|
||||
RCVBUF = SO_RCVBUF,
|
||||
// Receive low water mark.
|
||||
RCVLOWAT = SO_RCVLOWAT,
|
||||
// Receive timeout.
|
||||
RCVTIMEO = SO_RCVTIMEO,
|
||||
// Reuse of local addresses is supported.
|
||||
REUSEADDR = SO_REUSEADDR,
|
||||
// Send buffer size.
|
||||
SNDBUF = SO_SNDBUF,
|
||||
// Send low water mark.
|
||||
SNDLOWAT = SO_SNDLOWAT,
|
||||
// Send timeout.
|
||||
SNDTIMEO = SO_SNDTIMEO,
|
||||
// Socket type.
|
||||
TYPE = SO_TYPE,
|
||||
}
|
||||
|
||||
when ODIN_OS == .NetBSD {
|
||||
@(private) LSOCKET :: "__socket30"
|
||||
} else {
|
||||
@(private) LSOCKET :: "socket"
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
|
||||
socklen_t :: distinct c.uint
|
||||
|
||||
_sa_family_t :: distinct c.uint8_t
|
||||
|
||||
sockaddr :: struct {
|
||||
sa_len: c.uint8_t, /* total length */
|
||||
sa_family: sa_family_t, /* [PSX] address family */
|
||||
sa_data: [14]c.char, /* [PSX] socket address */
|
||||
}
|
||||
|
||||
|
||||
when ODIN_OS == .OpenBSD {
|
||||
@(private)
|
||||
_SS_PAD1SIZE :: 6
|
||||
@(private)
|
||||
_SS_PAD2SIZE :: 240
|
||||
} else {
|
||||
@(private)
|
||||
_SS_MAXSIZE :: 128
|
||||
@(private)
|
||||
_SS_ALIGNSIZE :: size_of(c.int64_t)
|
||||
@(private)
|
||||
_SS_PAD1SIZE :: _SS_ALIGNSIZE - size_of(c.uint8_t) - size_of(sa_family_t)
|
||||
@(private)
|
||||
_SS_PAD2SIZE :: _SS_MAXSIZE - size_of(c.uint8_t) - size_of(sa_family_t) - _SS_PAD1SIZE - _SS_ALIGNSIZE
|
||||
}
|
||||
|
||||
sockaddr_storage :: struct {
|
||||
ss_len: c.uint8_t, /* address length */
|
||||
ss_family: sa_family_t, /* [PSX] address family */
|
||||
__ss_pad1: [_SS_PAD1SIZE]c.char,
|
||||
__ss_align: c.int64_t, /* force structure storage alignment */
|
||||
__ss_pad2: [_SS_PAD2SIZE]c.char,
|
||||
}
|
||||
|
||||
msghdr :: struct {
|
||||
msg_name: rawptr, /* [PSX] optional address */
|
||||
msg_namelen: socklen_t, /* [PSX] size of address */
|
||||
msg_iov: [^]iovec, /* [PSX] scatter/gather array */
|
||||
msg_iovlen: c.int, /* [PSX] members in msg_iov */
|
||||
msg_control: rawptr, /* [PSX] ancillary data */
|
||||
msg_controllen: socklen_t, /* [PSX] ancillary data buffer length */
|
||||
msg_flags: Msg_Flags, /* [PSX] flags on received message */
|
||||
}
|
||||
|
||||
cmsghdr :: struct {
|
||||
cmsg_len: socklen_t, /* [PSX] data byte count, including cmsghdr */
|
||||
cmsg_level: c.int, /* [PSX] originating protocol */
|
||||
cmsg_type: c.int, /* [PSX] protocol-specific type */
|
||||
}
|
||||
|
||||
SCM_RIGHTS :: 0x01
|
||||
|
||||
@(private)
|
||||
__ALIGN32 :: #force_inline proc "contextless" (p: uintptr) -> uintptr {
|
||||
__ALIGNBYTES32 :: size_of(c.uint32_t) - 1
|
||||
return (p + __ALIGNBYTES32) &~ __ALIGNBYTES32
|
||||
}
|
||||
|
||||
// Returns a pointer to the data array.
|
||||
CMSG_DATA :: #force_inline proc "contextless" (cmsg: ^cmsghdr) -> [^]c.uchar {
|
||||
return ([^]c.uchar)(uintptr(cmsg) + __ALIGN32(size_of(cmsghdr)))
|
||||
}
|
||||
|
||||
// Returns a pointer to the next cmsghdr or nil.
|
||||
CMSG_NXTHDR :: #force_inline proc "contextless" (mhdr: ^msghdr, cmsg: ^cmsghdr) -> ^cmsghdr {
|
||||
if cmsg == nil {
|
||||
return CMSG_FIRSTHDR(mhdr)
|
||||
}
|
||||
|
||||
ptr := uintptr(cmsg) + __ALIGN32(uintptr(cmsg.cmsg_len))
|
||||
if ptr + __ALIGN32(size_of(cmsghdr)) > uintptr(mhdr.msg_control) + uintptr(mhdr.msg_controllen) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return (^cmsghdr)(ptr)
|
||||
}
|
||||
|
||||
// Returns a pointer to the first cmsghdr or nil.
|
||||
CMSG_FIRSTHDR :: #force_inline proc "contextless" (mhdr: ^msghdr) -> ^cmsghdr {
|
||||
if mhdr.msg_controllen >= size_of(cmsghdr) {
|
||||
return (^cmsghdr)(mhdr.msg_control)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
linger :: struct {
|
||||
l_onoff: c.int, /* [PSX] indicates whether linger option is enabled */
|
||||
l_linger: c.int, /* [PSX] linger time in seconds */
|
||||
}
|
||||
|
||||
SOCK_DGRAM :: 2
|
||||
SOCK_RAW :: 3
|
||||
SOCK_SEQPACKET :: 5
|
||||
SOCK_STREAM :: 1
|
||||
|
||||
// Options to be accessed at socket level, not protocol level.
|
||||
SOL_SOCKET :: 0xffff
|
||||
|
||||
SO_ACCEPTCONN :: 0x0002
|
||||
SO_BROADCAST :: 0x0020
|
||||
SO_DEBUG :: 0x0001
|
||||
SO_DONTROUTE :: 0x0010
|
||||
SO_ERROR :: 0x1007
|
||||
SO_KEEPALIVE :: 0x0008
|
||||
SO_OOBINLINE :: 0x0100
|
||||
SO_RCVBUF :: 0x1002
|
||||
SO_RCVLOWAT :: 0x1004
|
||||
SO_REUSEADDR :: 0x0004
|
||||
SO_SNDBUF :: 0x1001
|
||||
SO_SNDLOWAT :: 0x1003
|
||||
SO_TYPE :: 0x1008
|
||||
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD {
|
||||
SO_LINGER :: 0x1080
|
||||
SO_RCVTIMEO :: 0x1006
|
||||
SO_SNDTIMEO :: 0x1005
|
||||
} else when ODIN_OS == .NetBSD {
|
||||
SO_LINGER :: 0x0080
|
||||
SO_RCVTIMEO :: 0x100c
|
||||
SO_SNDTIMEO :: 0x100b
|
||||
} else when ODIN_OS == .OpenBSD {
|
||||
SO_LINGER :: 0x0080
|
||||
SO_RCVTIMEO :: 0x1006
|
||||
SO_SNDTIMEO :: 0x1005
|
||||
}
|
||||
|
||||
// The maximum backlog queue length for listen().
|
||||
SOMAXCONN :: 128
|
||||
|
||||
MSG_CTRUNC :: 0x20
|
||||
MSG_DONTROUTE :: 0x4
|
||||
MSG_EOR :: 0x8
|
||||
MSG_OOB :: 0x1
|
||||
MSG_PEEK :: 0x2
|
||||
MSG_TRUNC :: 0x10
|
||||
MSG_WAITALL :: 0x40
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
MSG_NOSIGNAL :: 0x80000
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
MSG_NOSIGNAL :: 0x00020000
|
||||
} else when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
MSG_NOSIGNAL :: 0x0400
|
||||
}
|
||||
|
||||
AF_INET :: 2
|
||||
AF_UNIX :: 1
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
AF_INET6 :: 30
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
AF_INET6 :: 28
|
||||
} else when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
|
||||
AF_INET6 :: 24
|
||||
}
|
||||
|
||||
SHUT_RD :: 0
|
||||
SHUT_RDWR :: 2
|
||||
SHUT_WR :: 1
|
||||
|
||||
} else {
|
||||
#panic("posix is unimplemented for the current target")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user