123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572 |
- #+build linux, darwin, netbsd, openbsd, freebsd
- 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")
- /*
- unlink the socket before binding in case
- of previous runs not cleaning up the socket
- */
- posix.unlink("/somepath")
- 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 || ODIN_OS == .Linux {
- socklen_t :: distinct c.uint
- when ODIN_OS == .Linux {
- _sa_family_t :: distinct c.ushort
- sockaddr :: struct {
- sa_family: sa_family_t, /* [PSX] address family */
- sa_data: [14]c.char, /* [PSX] socket address */
- }
- } else {
- _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 when ODIN_OS == .Linux {
- @(private)
- _SS_SIZE :: 128
- @(private)
- _SS_PADSIZE :: _SS_SIZE - size_of(c.uint16_t) - size_of(c.uint64_t)
- } 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
- }
- when ODIN_OS == .Linux {
- sockaddr_storage :: struct {
- ss_family: sa_family_t, /* [PSX] address family */
- __ss_padding: [_SS_PADSIZE]c.char,
- __ss_align: c.uint64_t, /* force structure storage alignment */
- }
- 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.size_t, /* [PSX] members in msg_iov */
- msg_control: rawptr, /* [PSX] ancillary data */
- msg_controllen: c.size_t, /* [PSX] ancillary data buffer length */
- msg_flags: Msg_Flags, /* [PSX] flags on received message */
- }
- cmsghdr :: struct {
- cmsg_len: c.size_t, /* [PSX] data byte count, including cmsghdr */
- cmsg_level: c.int, /* [PSX] originating protocol */
- cmsg_type: c.int, /* [PSX] protocol-specific type */
- }
- } else {
- 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.
- when ODIN_OS == .Linux {
- SOL_SOCKET :: 1
- SO_ACCEPTCONN :: 30
- SO_BROADCAST :: 6
- SO_DEBUG :: 1
- SO_DONTROUTE :: 5
- SO_ERROR :: 4
- SO_KEEPALIVE :: 9
- SO_OOBINLINE :: 10
- SO_RCVBUF :: 8
- SO_RCVLOWAT :: 18
- SO_REUSEADDR :: 2
- SO_SNDBUF :: 7
- SO_SNDLOWAT :: 19
- SO_TYPE :: 3
- SO_LINGER :: 13
- SO_RCVTIMEO :: 66
- SO_SNDTIMEO :: 67
- } else {
- 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 {
- SO_LINGER :: 0x1080
- SO_RCVTIMEO :: 0x1006
- SO_SNDTIMEO :: 0x1005
- } else when ODIN_OS == .FreeBSD {
- SO_LINGER :: 0x0080
- 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
- when ODIN_OS == .Linux {
- MSG_CTRUNC :: 0x008
- MSG_DONTROUTE :: 0x004
- MSG_EOR :: 0x080
- MSG_OOB :: 0x001
- MSG_PEEK :: 0x002
- MSG_TRUNC :: 0x020
- MSG_WAITALL :: 0x100
- MSG_NOSIGNAL :: 0x4000
- } else {
- 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
- } else when ODIN_OS == .Linux {
- AF_INET6 :: 10
- }
- SHUT_RD :: 0
- SHUT_RDWR :: 2
- SHUT_WR :: 1
- }
|