sys_socket.odin 15 KB

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