Fuzion Logo
fuzion-lang.dev — The Fuzion Language Portal
JavaScript seems to be disabled. Functionality is limited.

fuzion/sys/net.fz


# This file is part of the Fuzion language implementation.
#
# The Fuzion language implementation is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, version 3 of the License.
#
# The Fuzion language implementation is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License along with The
# Fuzion language implementation.  If not, see <https://www.gnu.org/licenses/>.


# -----------------------------------------------------------------------
#
#  Tokiwa Software GmbH, Germany
#
#  Source code of Fuzion standard library feature fuzion.sys.net0
#
# -----------------------------------------------------------------------

# groups networking related features
#
# internally this builds on:
# - java: nio
#   - why not java.net.Socket etc.?: this is only suitable for blocking I/O
#   - why not nio2?                : nio2 is basically the same as nio but asynchronous.
#                                    I.e. read/write return Futures.
# - c/posix: posix-sockets
# - c/win: winsock2
#
# sources of inspiration:
# - https://github.com/tezc/sc/
# - https://github.com/jart/cosmopolitan
# - https://learn.microsoft.com/en-us/windows/win32/winsock/complete-server-code
# - https://learn.microsoft.com/en-us/windows/win32/winsock/complete-client-code
#
# NYI: use error codes coming from backend
#
module net is

  # bind a name to a newly created socket, wrapper for fzE_bind native
  #
  module bind    (family, socket_type, protocol i32, host String, port u16) outcome i32 =>
    arr := fuzion.sys.internal_array_init i32 1
    r := fzE_bind family socket_type protocol (fuzion.sys.c_string host) (fuzion.sys.c_string port.as_string) arr.data = 0
    if r
      arr[0]
    else
      error "net.bind failed (host=$host, port=$port), error number: $fzE_last_error"


  # accept a new connection for given socket descriptor, wrapper for accept native.
  # returns an error or a new descriptor.
  module accept(sd i32) outcome i32 =>
    desc := fzE_accept sd
    if desc != -1 then desc
    else error "net.accept failed, error number: $fzE_last_error"


  # open and connect a client socket
  #
  module connect(family, socket_type, protocol i32, host String, port u16) outcome i32 =>
    arr := fuzion.sys.internal_array_init i32 1
    res := fzE_connect family socket_type protocol (fuzion.sys.c_string host) (fuzion.sys.c_string port.as_string) arr.data = 0
    if res
      arr[0]
    else
      error "net.connect failed (host=$host, port=$port), error number: {arr[0]}"


  # read a maximum of max_bytes from descriptor, wrapper for read native
  # may block if descriptor is set to blocking.
  #
  module read(descriptor i32, max_bytes i64) outcome (array u8) =>
    buff := fuzion.sys.internal_array_init u8 max_bytes.as_i32
    res := fzE_socket_read descriptor buff.data max_bytes
    if res >= 0
      if res.as_i64 = max_bytes
        buff.as_array
      else
        # NYI: UNDER DEVELOPMENT: there should be a way to use a slice of internal_array to init array
        array u8 res (idx -> buff[idx])
    else
      error "error reading from socket: $fzE_last_error"


  # write data to descriptor, wrapper for write native
  # may block if descriptor is set to blocking.
  #
  module write(descriptor i32, data array u8) outcome unit =>
    res := fzE_socket_write descriptor data.internal_array.data data.length.as_i64
    if res = -1 then error "error writing to socket: $fzE_last_error" else unit


  # close socket descriptor
  module close(sd i32) outcome unit =>
    res := fzE_close sd
    if res = -1 then error "error: $res" else unit


  # set descriptor to blocking / none blocking mode.
  module set_blocking(sd i32, blocking bool) outcome unit =>
    res := if blocking then fzE_set_blocking sd 0 else fzE_set_blocking sd 1
    if res = 0 then unit else error "error setting socket to {blocking ? "blocking" : "nonblocking"} mode: $fzE_last_error"


  # get a socket's peer's ip address
  #
  # takes a socket descriptor number
  # returns the IP address, as a list of bytes
  #
  # not useful for UDP sockets (information not necessarily available)
  #
  module get_peer_address(sockfd i32) outcome (Sequence u8) =>
    iarr := fuzion.sys.internal_array_init u8 16
    l := fzE_get_peer_address sockfd iarr.data
    iarr.as_array.take l

last changed: 2025-07-10