sys_socket.odin 15 KB

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