socket.odin 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. // +build windows, linux, darwin, freebsd
  2. package net
  3. /*
  4. Package net implements cross-platform Berkeley Sockets, DNS resolution and associated procedures.
  5. For other protocols and their features, see subdirectories of this package.
  6. */
  7. /*
  8. Copyright 2022-2023 Tetralux <[email protected]>
  9. Copyright 2022-2023 Colin Davidson <[email protected]>
  10. Copyright 2022-2023 Jeroen van Rijn <[email protected]>.
  11. Copyright 2024 Feoramund <[email protected]>.
  12. Made available under Odin's BSD-3 license.
  13. List of contributors:
  14. Tetralux: Initial implementation
  15. Colin Davidson: Linux platform code, OSX platform code, Odin-native DNS resolver
  16. Jeroen van Rijn: Cross platform unification, code style, documentation
  17. Feoramund: FreeBSD platform code
  18. */
  19. any_socket_to_socket :: proc "contextless" (socket: Any_Socket) -> Socket {
  20. switch s in socket {
  21. case TCP_Socket: return Socket(s)
  22. case UDP_Socket: return Socket(s)
  23. case:
  24. // TODO(tetra): Bluetooth, Raw
  25. return Socket({})
  26. }
  27. }
  28. /*
  29. Expects both hostname and port to be present in the `hostname_and_port` parameter, either as:
  30. `a.host.name:9999`, or as `1.2.3.4:9999`, or IP6 equivalent.
  31. Calls `parse_hostname_or_endpoint` and `resolve`, then `dial_tcp_from_endpoint`.
  32. */
  33. dial_tcp_from_hostname_and_port_string :: proc(hostname_and_port: string, options := default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) {
  34. target := parse_hostname_or_endpoint(hostname_and_port) or_return
  35. switch t in target {
  36. case Endpoint:
  37. return dial_tcp_from_endpoint(t, options)
  38. case Host:
  39. if t.port == 0 {
  40. return 0, .Port_Required
  41. }
  42. ep4, ep6 := resolve(t.hostname) or_return
  43. ep := ep4 if ep4.address != nil else ep6 // NOTE(tetra): We don't know what family the server uses, so we just default to IP4.
  44. ep.port = t.port
  45. return dial_tcp_from_endpoint(ep, options)
  46. }
  47. unreachable()
  48. }
  49. /*
  50. Expects the `hostname` as a string and `port` as a `int`.
  51. `parse_hostname_or_endpoint` is called and the `hostname` will be resolved into an IP.
  52. If a `hostname` of form `a.host.name:9999` is given, the port will be ignored in favor of the explicit `port` param.
  53. */
  54. dial_tcp_from_hostname_with_port_override :: proc(hostname: string, port: int, options := default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) {
  55. target := parse_hostname_or_endpoint(hostname) or_return
  56. switch t in target {
  57. case Endpoint:
  58. return dial_tcp_from_endpoint({t.address, port}, options)
  59. case Host:
  60. if port == 0 {
  61. return 0, .Port_Required
  62. }
  63. ep4, ep6 := resolve(t.hostname) or_return
  64. ep := ep4 if ep4.address != nil else ep6 // NOTE(tetra): We don't know what family the server uses, so we just default to IP4.
  65. ep.port = port
  66. return dial_tcp_from_endpoint(ep, options)
  67. }
  68. unreachable()
  69. }
  70. // Dial from an Address
  71. dial_tcp_from_address_and_port :: proc(address: Address, port: int, options := default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) {
  72. return dial_tcp_from_endpoint({address, port}, options)
  73. }
  74. dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) {
  75. return _dial_tcp_from_endpoint(endpoint, options)
  76. }
  77. dial_tcp :: proc{
  78. dial_tcp_from_endpoint,
  79. dial_tcp_from_address_and_port,
  80. dial_tcp_from_hostname_and_port_string,
  81. dial_tcp_from_hostname_with_port_override,
  82. }
  83. create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Network_Error) {
  84. return _create_socket(family, protocol)
  85. }
  86. bind :: proc(socket: Any_Socket, ep: Endpoint) -> (err: Network_Error) {
  87. return _bind(socket, ep)
  88. }
  89. /*
  90. This type of socket becomes bound when you try to send data.
  91. It is likely what you want if you want to send data unsolicited.
  92. This is like a client TCP socket, except that it can send data to any remote endpoint without needing to establish a connection first.
  93. */
  94. make_unbound_udp_socket :: proc(family: Address_Family) -> (socket: UDP_Socket, err: Network_Error) {
  95. sock := create_socket(family, .UDP) or_return
  96. socket = sock.(UDP_Socket)
  97. return
  98. }
  99. /*
  100. This type of socket is bound immediately, which enables it to receive data on the port.
  101. Since it's UDP, it's also able to send data without receiving any first.
  102. This is like a listening TCP socket, except that data packets can be sent and received without needing to establish a connection first.
  103. The `bound_address` is the address of the network interface that you want to use, or a loopback address if you don't care which to use.
  104. */
  105. make_bound_udp_socket :: proc(bound_address: Address, port: int) -> (socket: UDP_Socket, err: Network_Error) {
  106. if bound_address == nil {
  107. return {}, .Bad_Address
  108. }
  109. socket = make_unbound_udp_socket(family_from_address(bound_address)) or_return
  110. bind(socket, {bound_address, port}) or_return
  111. return
  112. }
  113. listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (socket: TCP_Socket, err: Network_Error) {
  114. assert(backlog > 0 && backlog < int(max(i32)))
  115. return _listen_tcp(interface_endpoint, backlog)
  116. }
  117. accept_tcp :: proc(socket: TCP_Socket, options := default_tcp_options) -> (client: TCP_Socket, source: Endpoint, err: Network_Error) {
  118. return _accept_tcp(socket, options)
  119. }
  120. close :: proc(socket: Any_Socket) {
  121. _close(socket)
  122. }
  123. recv_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_read: int, err: Network_Error) {
  124. return _recv_tcp(socket, buf)
  125. }
  126. recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endpoint: Endpoint, err: Network_Error) {
  127. return _recv_udp(socket, buf)
  128. }
  129. /*
  130. Receive data from into a buffer from any socket.
  131. Note: `remote_endpoint` parameter is non-nil only if the socket type is UDP. On TCP sockets it
  132. will always return `nil`.
  133. */
  134. recv_any :: proc(socket: Any_Socket, buf: []byte) -> (
  135. bytes_read: int,
  136. remote_endpoint: Maybe(Endpoint),
  137. err: Network_Error,
  138. ) {
  139. switch socktype in socket {
  140. case TCP_Socket:
  141. bytes_read, err = recv_tcp(socktype, buf)
  142. return
  143. case UDP_Socket:
  144. return recv_udp(socktype, buf)
  145. case: panic("Not supported")
  146. }
  147. }
  148. recv :: proc{recv_tcp, recv_udp, recv_any}
  149. /*
  150. Repeatedly sends data until the entire buffer is sent.
  151. If a send fails before all data is sent, returns the amount sent up to that point.
  152. */
  153. send_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_written: int, err: Network_Error) {
  154. return _send_tcp(socket, buf)
  155. }
  156. /*
  157. Sends a single UDP datagram packet.
  158. Datagrams are limited in size; attempting to send more than this limit at once will result in a Message_Too_Long error.
  159. UDP packets are not guarenteed to be received in order.
  160. */
  161. send_udp :: proc(socket: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: int, err: Network_Error) {
  162. return _send_udp(socket, buf, to)
  163. }
  164. send_any :: proc(socket: Any_Socket, buf: []byte, to: Maybe(Endpoint) = nil) -> (
  165. bytes_written: int,
  166. err: Network_Error,
  167. ) {
  168. switch socktype in socket {
  169. case TCP_Socket:
  170. return send_tcp(socktype, buf)
  171. case UDP_Socket:
  172. return send_udp(socktype, buf, to.(Endpoint))
  173. case: panic("Not supported")
  174. }
  175. }
  176. send :: proc{send_tcp, send_udp, send_any}
  177. shutdown :: proc(socket: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) {
  178. return _shutdown(socket, manner)
  179. }
  180. set_option :: proc(socket: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Network_Error {
  181. return _set_option(socket, option, value, loc)
  182. }
  183. set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) {
  184. return _set_blocking(socket, should_block)
  185. }