%{#
#include "libc/sys/CATS/socket.cats"
%} 
staload SA = "libc/sys/SATS/sockaddr.sats"
typedef sa_family_t = $SA.sa_family_t
stadef socklen_t = $SA.socklen_t
stadef sockaddr_struct = $SA.sockaddr_struct
abst@ype socktype_t = int
macdef SOCK_STREAM = $extval (socktype_t, "SOCK_STREAM")
macdef SOCK_DGRAM = $extval (socktype_t, "SOCK_DGRAM")
macdef SOCK_RAW = $extval (socktype_t, "SOCK_RAW")
macdef SOCK_RDM = $extval (socktype_t, "SOCK_RDM")
macdef SOCK_PACKET = $extval (socktype_t, "SOCK_PACKET")
macdef SOCK_SEQPACKET = $extval (socktype_t, "SOCK_SEQPACKET")
macdef SOCK_DCCP = $extval (socktype_t, "SOCK_DCCP")
abst@ype socktypeflag_t = int
macdef SOCK_CLOEXEC = $extval (socktypeflag_t, "SOCK_CLOEXEC")
macdef SOCK_NONBLOCK = $extval (socktypeflag_t, "SOCK_NONBLOCK")
fun lor_socktype_socktypeflag
  (t: socktype_t, f: socktypeflag_t):<> socktype_t = "atspre_lor_uint_uint"
overload lor with lor_socktype_socktypeflag
abst@ype sockprot_t = int
datasort status = init | bind | listen | conn
absview socket_v (int, status)
fun socket_family_type_err
  (af: sa_family_t, t: socktype_t)
  : [fd:int] (option_v (socket_v (fd, init), fd >= 0) | int fd)
  = "atslib_socket_family_type_err"
fun socket_family_type_exn
  (af: sa_family_t, t: socktype_t): [fd:nat] (socket_v (fd, init) | int fd)
dataview connect_v (fd: int, int) =
  | connect_v_succ (fd,  0) of socket_v (fd, conn)
  | connect_v_fail (fd, ~1) of socket_v (fd, init)
fun connect_err
  {fd:int} {n:int} (
    pfskt: socket_v (fd, init)
  | fd: int fd
  , servaddr: &sockaddr_struct(n), salen: socklen_t(n)
  ) : [i:int | i <= 0] (connect_v (fd, i) | int i)
  = "#atslib_connect_err"
dataview bind_v (fd:int, int) = 
  | bind_v_fail (fd, ~1) of socket_v (fd, init)
  | bind_v_succ (fd,  0) of socket_v (fd, bind)
fun bind_err
  {fd:int} {n:int} (
    pfskt: socket_v (fd, init)
  | fd: int fd
  , servaddr: &sockaddr_struct(n), salen: socklen_t(n)
  ) : [i:int] (bind_v (fd, i) | int i) = "#atslib_bind_err"
macdef SOMAXCONN = $extval (Pos, "SOMAXCONN")
dataview listen_v (fd:int, int) = 
  | listen_v_fail (fd, ~1) of socket_v (fd, bind) 
  | listen_v_succ (fd,  0) of socket_v (fd, listen)
fun listen_err {fd:int}
  (pfskt: socket_v (fd, bind) | fd: int fd, backlog: Pos)
  : [i:int] (listen_v (fd, i) | int i)
  = "atslib_listen_err"
fun listen_exn {fd:int} (
    pfskt: !socket_v (fd, bind) >> socket_v (fd, listen)
  | fd: int fd, backlog: Pos   ) : void
dataview
accept_v (fd:int, int) =
  | accept_v_fail (fd, ~1) of ()
  | {cfd:nat} accept_v_succ (fd, cfd) of socket_v (cfd, conn)
fun accept_err
  {sfd:int} {n:int} (
  pfskt: !socket_v (sfd, listen)
| sfd: int sfd
, sa: &sockaddr_struct(n)? >> opt (sockaddr_struct(n), cfd >= 0)
, salen: &socklen_t(n) >> socklen_t(n1)
) : #[cfd:int;n1:nat] (accept_v (sfd, cfd) | int cfd)
  = "#atslib_accept_err"
fun accept_null_err {sfd:int}
  (pfskt: !socket_v (sfd, listen) | sfd: int sfd)
  : [cfd:int] (option_v (socket_v (cfd, conn), cfd >= 0) | int cfd)
  = "atslib_accept_null_err"
fun accept_null_exn {sfd:int} (
  pfskt: !socket_v (sfd, listen) | sfd: int sfd
) : [cfd:nat] (socket_v (cfd, conn) | int cfd) 
fun socket_close_err
  {fd:int} {s:status} (
  pfskt: socket_v (fd, s) | fd: int fd
) : [i:int | i <= 0] (option_v (socket_v (fd, s), i < 0) | int i)
  = "#atslib_socket_close_err" 
fun socket_close_exn {fd:int} {s:status}
  (pfskt: socket_v (fd, s) | fd: int fd): void
abst@ype shutkind_t = int
macdef SHUT_RD = $extval (shutkind_t, "SHUT_RD")
macdef SHUT_WR = $extval (shutkind_t, "SHUT_WR")
macdef SHUT_RDWR = $extval (shutkind_t, "SHUT_RDWR")
fun shutdown_err   {fd:int}   (pfskt: socket_v (fd, conn) | fd: int fd, how: shutkind_t)
  : [i:int | i <= 0] (option_v (socket_v (fd, conn), i < 0) | int i)
  = "#atslib_shutdown_err"
fun shutdown_exn   {fd:int}   (pfskt: socket_v (fd, conn) | fd: int fd, how: shutkind_t): void
fun socket_read_err {fd:int} {n,sz:nat | n <= sz} (
    pfskt: !socket_v (fd, conn) | fd: int fd, buf: &bytes sz, ntotal: size_t n
  ) : ssizeBtw(~1, n+1) = "#atslib_socket_read_err" fun socket_read_exn {fd:int} {n,sz:nat | n <= sz} (
    pfskt: !socket_v (fd, conn) | fd: int fd, buf: &bytes sz, ntotal: size_t n
  ) : sizeLte n
fun socket_write_err {fd:int} {n,sz:nat | n <= sz} (
    pfskt: !socket_v (fd, conn) | fd: int fd, buf: &bytes sz, ntotal: size_t n
  ) : ssizeBtw(~1, n+1) = "#atslib_socket_write_err" 
fun socket_read_all_err {fd:int} {n,sz:nat | n <= sz} (
    pfskt: !socket_v (fd, conn) | fd: int fd, buf: &bytes sz, ntotal: size_t n
  ) : ssizeBtw (~1, n+1) = "#atslib_socket_read_all_err" 
fun socket_write_all_err {fd:int} {n,sz:nat | n <= sz} (
    pfskt: !socket_v (fd, conn) | fd: int fd, buf: &bytes sz, ntotal: size_t n
  ) : ssizeBtw(~1, n+1) = "#atslib_socket_write_all_err" fun socket_write_all_exn {fd:int} {n,sz:nat | n <= sz} (
    pfskt: !socket_v (fd, conn) | fd: int fd, buf: &bytes sz, ntotal: size_t n
  ) : void   = "atslib_socket_write_all_exn"
fun socket_write_substring
  {fd:int} {n:int}
  {st,ln:nat | st+ln <= n} (
    pf_sock: !socket_v (fd, conn)
  | fd: int fd, str: string n, st: size_t st, ln: size_t ln
  ) : void 
dataview socket_fdopen_v
  (fd: int, m: file_mode, addr) =
  | socket_fdopen_v_fail (fd, m, null) of socket_v (fd, conn)
  | {l:agz} socket_fdopen_v_succ (fd, m, l) of FILE m @ l
fun socket_fdopen_err {fd:int} {m:file_mode}
  (pf: socket_v (fd, conn) | fd: int fd, m: file_mode m)
  : [l:addr] (socket_fdopen_v (fd, m, l) | ptr l) = "#atslib_socket_fdopen_err"
fun setsockopt {a:t@ype} {fd:nat}
  (fd: int fd, level: int, option: int, value: &a, valen: sizeof_t a): int
  = "atslib_setsockopt" 
fun getsockopt_err {a:t@ype} {fd:nat} (
    fd: int fd
  , level: int, option: int
  , value: &a? >> opt (a, i==0), valen: sizeof_t a
  ) : #[i:int | i <= 0] int i = "atslib_getsockopt_err" 
fun sockatmark {fd:nat} (fd: int fd): int = "#atslib_sockatmark"