sys_socket.odin 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. package posix
  2. import "core:c"
  3. when ODIN_OS == .Darwin {
  4. foreign import libc "system:System.framework"
  5. } else {
  6. foreign import libc "system:c"
  7. }
  8. // sys/socket.h - main sockets header
  9. #assert(Protocol.IP == Protocol(0), "socket() assumes this")
  10. foreign libc {
  11. /*
  12. Creates a socket.
  13. Returns: -1 (setting errno) on failure, file descriptor of socket otherwise
  14. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html ]]
  15. */
  16. @(link_name=LSOCKET)
  17. socket :: proc(domain: AF, type: Sock, protocol: Protocol = .IP) -> FD ---
  18. /*
  19. Extracts the first connection on the queue of pending connections.
  20. Blocks (if not O_NONBLOCK) if there is no pending connection.
  21. Returns: -1 (setting errno) on failure, file descriptor of accepted socket otherwise
  22. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html ]]
  23. */
  24. accept :: proc(socket: FD, address: ^sockaddr, address_len: ^socklen_t) -> FD ---
  25. /*
  26. Assigns a local socket address to the socket.
  27. Example:
  28. sfd := posix.socket(.UNIX, .STREAM)
  29. if sfd == -1 {
  30. /* Handle error */
  31. }
  32. addr: posix.sockaddr_un
  33. addr.sun_family = .UNIX
  34. copy(addr.sun_path[:], "/somepath\x00")
  35. if posix.bind(sfd, (^posix.sockaddr)(&addr), size_of(addr)) != .OK {
  36. /* Handle error */
  37. }
  38. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html ]]
  39. */
  40. bind :: proc(socket: FD, address: ^sockaddr, address_len: socklen_t) -> result ---
  41. /*
  42. Attempt to make a connection.
  43. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html ]]
  44. */
  45. connect :: proc(socket: FD, address: ^sockaddr, address_len: socklen_t) -> result ---
  46. /*
  47. Get the peer address of the specified socket.
  48. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html ]]
  49. */
  50. getpeername :: proc(socket: FD, address: ^sockaddr, address_len: ^socklen_t) -> result ---
  51. /*
  52. Get the socket name.
  53. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html ]]
  54. */
  55. getsockname :: proc(socket: FD, address: ^sockaddr, address_len: ^socklen_t) -> result ---
  56. /*
  57. Retrieves the value for the option specified by option_name.
  58. level: either `c.int(posix.Protocol(...))` to specify a protocol level or `posix.SOL_SOCKET`
  59. to specify the socket local level.
  60. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html ]]
  61. */
  62. getsockopt :: proc(
  63. socket: FD,
  64. level: c.int,
  65. option_name: Sock_Option,
  66. option_value: rawptr,
  67. option_len: ^socklen_t,
  68. ) -> result ---
  69. /*
  70. Sets the specified option.
  71. level: either `c.int(posix.Protocol(...))` to specify a protocol level or `posix.SOL_SOCKET`
  72. to specify the socket local level.
  73. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html ]]
  74. */
  75. setsockopt :: proc(
  76. socket: FD,
  77. level: c.int,
  78. option_name: Sock_Option,
  79. option_value: rawptr,
  80. option_len: socklen_t,
  81. ) -> result ---
  82. /*
  83. Mark the socket as a socket accepting connections.
  84. backlog provides a hint to limit the number of connections on the listen queue.
  85. Implementation may silently reduce the backlog, additionally `SOMAXCONN` specifies the maximum
  86. an implementation has to support.
  87. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html ]]
  88. */
  89. listen :: proc(socket: FD, backlog: c.int) -> result ---
  90. /*
  91. Receives a message from a socket.
  92. Blocks (besides with O_NONBLOCK) if there is nothing to receive.
  93. Returns: 0 when the peer shutdown with no more messages, -1 (setting errno) on failure, the amount of bytes received on success
  94. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html ]]
  95. */
  96. recv :: proc(socket: FD, buffer: rawptr, length: c.size_t, flags: Msg_Flags) -> c.ssize_t ---
  97. /*
  98. Receives a message from a socket.
  99. Equivalent to recv() but retrieves the source address too.
  100. Returns: 0 when the peer shutdown with no more messages, -1 (setting errno) on failure, the amount of bytes received on success
  101. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html ]]
  102. */
  103. recvfrom :: proc(
  104. socket: FD,
  105. buffer: rawptr,
  106. length: c.size_t,
  107. flags: Msg_Flags,
  108. address: ^sockaddr,
  109. address_len: ^socklen_t,
  110. ) -> c.ssize_t ---
  111. /*
  112. Receives a message from a socket.
  113. Returns: 0 when the peer shutdown with no more messages, -1 (setting errno) on failure, the amount of bytes received on success
  114. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html ]]
  115. */
  116. recvmsg :: proc(socket: FD, message: ^msghdr, flags: Msg_Flags) -> c.ssize_t ---
  117. /*
  118. Sends a message on a socket.
  119. Returns: -1 (setting errno) on failure, the amount of bytes received on success
  120. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html ]]
  121. */
  122. send :: proc(socket: FD, buffer: rawptr, length: c.size_t, flags: Msg_Flags) -> c.ssize_t ---
  123. /*
  124. Sends a message on a socket.
  125. Returns: -1 (setting errno) on failure, the amount of bytes received on success
  126. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html ]]
  127. */
  128. sendmsg :: proc(socket: FD, message: ^msghdr, flags: Msg_Flags) -> c.ssize_t ---
  129. /*
  130. Sends a message on a socket.
  131. If the socket is connectionless, the dest_addr is used to send to.
  132. Returns: -1 (setting errno) on failure, the amount of bytes received on success
  133. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html ]]
  134. */
  135. sendto :: proc(
  136. socket: FD,
  137. message: rawptr,
  138. length: c.size_t,
  139. flags: Msg_Flags,
  140. dest_addr: ^sockaddr,
  141. dest_len: socklen_t,
  142. ) -> c.ssize_t ---
  143. /*
  144. Shuts down a socket end or both.
  145. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html ]]
  146. */
  147. shutdown :: proc(socket: FD, how: Shut) -> result ---
  148. /*
  149. Determine wheter a socket is at the out-of-band mark.
  150. Returns: -1 (setting errno) on failure, 0 if not at the mark, 1 if it is
  151. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sockatmark.html ]]
  152. */
  153. sockatmark :: proc(socket: FD) -> c.int ---
  154. /*
  155. Create a pair of connected sockets.
  156. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html ]]
  157. */
  158. socketpair :: proc(domain: AF, type: Sock, protocol: Protocol, socket_vector: ^[2]FD) -> result ---
  159. }
  160. AF_UNSPEC :: 0
  161. AF :: enum c.int {
  162. // Unspecified.
  163. UNSPEC = AF_UNSPEC,
  164. // Internet domain sockets for use with IPv4 addresses.
  165. INET = AF_INET,
  166. // Internet domain sockets for use with IPv6 addresses.
  167. INET6 = AF_INET6,
  168. // UNIX domain sockets.
  169. UNIX = AF_UNIX,
  170. }
  171. sa_family_t :: enum _sa_family_t {
  172. // Unspecified.
  173. UNSPEC = AF_UNSPEC,
  174. // Internet domain sockets for use with IPv4 addresses.
  175. INET = AF_INET,
  176. // Internet domain sockets for use with IPv6 addresses.
  177. INET6 = AF_INET6,
  178. // UNIX domain sockets.
  179. UNIX = AF_UNIX,
  180. }
  181. Sock :: enum c.int {
  182. // Datagram socket.
  183. DGRAM = SOCK_DGRAM,
  184. // Raw Protocol Interface.
  185. RAW = SOCK_RAW,
  186. // Sequenced-packet socket.
  187. SEQPACKET = SOCK_SEQPACKET,
  188. // Byte-stream socket.
  189. STREAM = SOCK_STREAM,
  190. }
  191. Shut :: enum c.int {
  192. // Disables further receive operations.
  193. RD = SHUT_RD,
  194. // Disables further send and receive operations.
  195. RDWR = SHUT_RDWR,
  196. // Disables further send operations.
  197. WR = SHUT_WR,
  198. }
  199. Msg_Flag_Bits :: enum c.int {
  200. // Control data truncated.
  201. CTRUNC = log2(MSG_CTRUNC),
  202. // Send without using routing table.
  203. DONTROUTE = log2(MSG_DONTROUTE),
  204. // Terminates a record (if supported by protocol).
  205. EOR = log2(MSG_EOR),
  206. // Out-of-band data.
  207. OOB = log2(MSG_OOB),
  208. // No SIGPIPE is generated when an attempt to send is made on a stream-oriented socket that is
  209. // no longer connected.
  210. NOSIGNAL = log2(MSG_NOSIGNAL),
  211. // Leave received data in queue.
  212. PEEK = log2(MSG_PEEK),
  213. // Normal data truncated.
  214. TRUNC = log2(MSG_TRUNC),
  215. // Attempt to fill the read buffer.
  216. WAITALL = log2(MSG_WAITALL),
  217. }
  218. Msg_Flags :: bit_set[Msg_Flag_Bits; c.int]
  219. Sock_Option :: enum c.int {
  220. // Transmission of broadcast message is supported.
  221. BROADCAST = SO_BROADCAST,
  222. // Debugging information is being recorded.
  223. DEBUG = SO_DEBUG,
  224. // Bypass normal routing.
  225. DONTROUTE = SO_DONTROUTE,
  226. // Socket error status.
  227. ERROR = SO_ERROR,
  228. // Connections are kept alive with periodic messages.
  229. KEEPALIVE = SO_KEEPALIVE,
  230. // Socket lingers on close.
  231. LINGER = SO_LINGER,
  232. // Out-of-band data is transmitted in line.
  233. OOBINLINE = SO_OOBINLINE,
  234. // Receive buffer size.
  235. RCVBUF = SO_RCVBUF,
  236. // Receive low water mark.
  237. RCVLOWAT = SO_RCVLOWAT,
  238. // Receive timeout.
  239. RCVTIMEO = SO_RCVTIMEO,
  240. // Reuse of local addresses is supported.
  241. REUSEADDR = SO_REUSEADDR,
  242. // Send buffer size.
  243. SNDBUF = SO_SNDBUF,
  244. // Send low water mark.
  245. SNDLOWAT = SO_SNDLOWAT,
  246. // Send timeout.
  247. SNDTIMEO = SO_SNDTIMEO,
  248. // Socket type.
  249. TYPE = SO_TYPE,
  250. }
  251. when ODIN_OS == .NetBSD {
  252. @(private) LSOCKET :: "__socket30"
  253. } else {
  254. @(private) LSOCKET :: "socket"
  255. }
  256. when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
  257. socklen_t :: distinct c.uint
  258. _sa_family_t :: distinct c.uint8_t
  259. sockaddr :: struct {
  260. sa_len: c.uint8_t, /* total length */
  261. sa_family: sa_family_t, /* [PSX] address family */
  262. sa_data: [14]c.char, /* [PSX] socket address */
  263. }
  264. when ODIN_OS == .OpenBSD {
  265. @(private)
  266. _SS_PAD1SIZE :: 6
  267. @(private)
  268. _SS_PAD2SIZE :: 240
  269. } else {
  270. @(private)
  271. _SS_MAXSIZE :: 128
  272. @(private)
  273. _SS_ALIGNSIZE :: size_of(c.int64_t)
  274. @(private)
  275. _SS_PAD1SIZE :: _SS_ALIGNSIZE - size_of(c.uint8_t) - size_of(sa_family_t)
  276. @(private)
  277. _SS_PAD2SIZE :: _SS_MAXSIZE - size_of(c.uint8_t) - size_of(sa_family_t) - _SS_PAD1SIZE - _SS_ALIGNSIZE
  278. }
  279. sockaddr_storage :: struct {
  280. ss_len: c.uint8_t, /* address length */
  281. ss_family: sa_family_t, /* [PSX] address family */
  282. __ss_pad1: [_SS_PAD1SIZE]c.char,
  283. __ss_align: c.int64_t, /* force structure storage alignment */
  284. __ss_pad2: [_SS_PAD2SIZE]c.char,
  285. }
  286. msghdr :: struct {
  287. msg_name: rawptr, /* [PSX] optional address */
  288. msg_namelen: socklen_t, /* [PSX] size of address */
  289. msg_iov: [^]iovec, /* [PSX] scatter/gather array */
  290. msg_iovlen: c.int, /* [PSX] members in msg_iov */
  291. msg_control: rawptr, /* [PSX] ancillary data */
  292. msg_controllen: socklen_t, /* [PSX] ancillary data buffer length */
  293. msg_flags: Msg_Flags, /* [PSX] flags on received message */
  294. }
  295. cmsghdr :: struct {
  296. cmsg_len: socklen_t, /* [PSX] data byte count, including cmsghdr */
  297. cmsg_level: c.int, /* [PSX] originating protocol */
  298. cmsg_type: c.int, /* [PSX] protocol-specific type */
  299. }
  300. SCM_RIGHTS :: 0x01
  301. @(private)
  302. __ALIGN32 :: #force_inline proc "contextless" (p: uintptr) -> uintptr {
  303. __ALIGNBYTES32 :: size_of(c.uint32_t) - 1
  304. return (p + __ALIGNBYTES32) &~ __ALIGNBYTES32
  305. }
  306. // Returns a pointer to the data array.
  307. CMSG_DATA :: #force_inline proc "contextless" (cmsg: ^cmsghdr) -> [^]c.uchar {
  308. return ([^]c.uchar)(uintptr(cmsg) + __ALIGN32(size_of(cmsghdr)))
  309. }
  310. // Returns a pointer to the next cmsghdr or nil.
  311. CMSG_NXTHDR :: #force_inline proc "contextless" (mhdr: ^msghdr, cmsg: ^cmsghdr) -> ^cmsghdr {
  312. if cmsg == nil {
  313. return CMSG_FIRSTHDR(mhdr)
  314. }
  315. ptr := uintptr(cmsg) + __ALIGN32(uintptr(cmsg.cmsg_len))
  316. if ptr + __ALIGN32(size_of(cmsghdr)) > uintptr(mhdr.msg_control) + uintptr(mhdr.msg_controllen) {
  317. return nil
  318. }
  319. return (^cmsghdr)(ptr)
  320. }
  321. // Returns a pointer to the first cmsghdr or nil.
  322. CMSG_FIRSTHDR :: #force_inline proc "contextless" (mhdr: ^msghdr) -> ^cmsghdr {
  323. if mhdr.msg_controllen >= size_of(cmsghdr) {
  324. return (^cmsghdr)(mhdr.msg_control)
  325. }
  326. return nil
  327. }
  328. linger :: struct {
  329. l_onoff: c.int, /* [PSX] indicates whether linger option is enabled */
  330. l_linger: c.int, /* [PSX] linger time in seconds */
  331. }
  332. SOCK_DGRAM :: 2
  333. SOCK_RAW :: 3
  334. SOCK_SEQPACKET :: 5
  335. SOCK_STREAM :: 1
  336. // Options to be accessed at socket level, not protocol level.
  337. SOL_SOCKET :: 0xffff
  338. SO_ACCEPTCONN :: 0x0002
  339. SO_BROADCAST :: 0x0020
  340. SO_DEBUG :: 0x0001
  341. SO_DONTROUTE :: 0x0010
  342. SO_ERROR :: 0x1007
  343. SO_KEEPALIVE :: 0x0008
  344. SO_OOBINLINE :: 0x0100
  345. SO_RCVBUF :: 0x1002
  346. SO_RCVLOWAT :: 0x1004
  347. SO_REUSEADDR :: 0x0004
  348. SO_SNDBUF :: 0x1001
  349. SO_SNDLOWAT :: 0x1003
  350. SO_TYPE :: 0x1008
  351. when ODIN_OS == .Darwin {
  352. SO_LINGER :: 0x1080
  353. SO_RCVTIMEO :: 0x1006
  354. SO_SNDTIMEO :: 0x1005
  355. } else when ODIN_OS == .FreeBSD {
  356. SO_LINGER :: 0x0080
  357. SO_RCVTIMEO :: 0x1006
  358. SO_SNDTIMEO :: 0x1005
  359. } else when ODIN_OS == .NetBSD {
  360. SO_LINGER :: 0x0080
  361. SO_RCVTIMEO :: 0x100c
  362. SO_SNDTIMEO :: 0x100b
  363. } else when ODIN_OS == .OpenBSD {
  364. SO_LINGER :: 0x0080
  365. SO_RCVTIMEO :: 0x1006
  366. SO_SNDTIMEO :: 0x1005
  367. }
  368. // The maximum backlog queue length for listen().
  369. SOMAXCONN :: 128
  370. MSG_CTRUNC :: 0x20
  371. MSG_DONTROUTE :: 0x4
  372. MSG_EOR :: 0x8
  373. MSG_OOB :: 0x1
  374. MSG_PEEK :: 0x2
  375. MSG_TRUNC :: 0x10
  376. MSG_WAITALL :: 0x40
  377. when ODIN_OS == .Darwin {
  378. MSG_NOSIGNAL :: 0x80000
  379. } else when ODIN_OS == .FreeBSD {
  380. MSG_NOSIGNAL :: 0x00020000
  381. } else when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
  382. MSG_NOSIGNAL :: 0x0400
  383. }
  384. AF_INET :: 2
  385. AF_UNIX :: 1
  386. when ODIN_OS == .Darwin {
  387. AF_INET6 :: 30
  388. } else when ODIN_OS == .FreeBSD {
  389. AF_INET6 :: 28
  390. } else when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD {
  391. AF_INET6 :: 24
  392. }
  393. SHUT_RD :: 0
  394. SHUT_RDWR :: 2
  395. SHUT_WR :: 1
  396. } else {
  397. #panic("posix is unimplemented for the current target")
  398. }