6.94. kink/socket/TCP_SERVER

Provides listening sockets of TCP/IP, or stream based Unix Domain Socket.

Example

The following program spawns a TCP/IP server and a client. The server sets socket options SO_REUSEADDR and SO_RCVBUF. The client sends bytes [1, 2, 3] to the server.

:TCP.require_from('kink/socket/')
:TCP_SERVER.require_from('kink/socket/')
:IP.require_from('kink/socket/')
:IP_PORT.require_from('kink/socket/')
:THREAD.require_from('kink/thread/')
:BIN.require_from('kink/')
:CONTROL.require_from('kink/')

:spawn_client <- {(:Server_addr)
  THREAD.spawn_io{
    CONTROL.with_finally{(:finally)
      :Tcp = TCP.open
      finally{ Tcp.close }

      Tcp.connect(Server_addr)
      :Out = Tcp.output
      finally{ Out.close }

      Out.write(BIN.of(1 2 3))
    }
  }
}

CONTROL.with_finally{(:finally)
  :Server = TCP_SERVER.open
  finally{ Server.close }

  Server.so_reuseaddr <- true
  Server.so_rcvbuf <- 1024
  stdout.print_line(Server.so_reuseaddr.load.repr) # => true
  stdout.print_line(Server.so_rcvbuf.load.repr)    # => 1152

  Server.bind_listen(IP_PORT.new(IP.for_hostname('::1') 0))
  :Server_addr = Server.local_address
  spawn_client(Server_addr)

  :Tcp = Server.accept
  finally{ Tcp.close }
  :In = Tcp.input
  finally{ In.close }

  :Bin = In.read_all
  stdout.print_line(Bin.repr) # => (bin 0x01 0x02 0x03)
}

6.94.1. type tcp_server

A `tcp_server` is a listening socket of TCP/IP, or stream based Unix Domain Socket.

6.94.1.1. Serv.bind_listen(Local ...[$config_fun={}])

`bind_listen` binds the local address to the listening socket, and changes the socket to listening mode.

Config methods:

• C.backlog(Backlog): default = the runtime default

• C.on_success($success): default = {}

• C.on_error($error): default = {(:Exc) Exc.raise }

If the socket is changed to listening mode, `bind_listen` tail-calls $success with no arg.

If an IO error occurs, `bind_listen` tail-calls $error with an `exception`.

`Backlog` is used as a preferred maximum number of connections which are established but not accepted.

Preconditions

`Local` must be a `socket_address` whose protocol family is acceptable by the socket.

`Backlog` must be a positive integer `num`.

$success must be a thunk.

$error must be a function which takes an `exception`.

6.94.1.2. Serv.accept(...[$config={}])

`accept` method accepts an incoming connection.

Config methods:

• C.on_success($success): default = VAL.identity

• C.on_error($error): default = {(:Exc) Exc.raise }

• C.on_cancelled($cancelled): default = a function which raises an exception

`accept` method waits until a connection becomes established, an IO error occurs, or it is cancelled.

If a connection is established, `accept` tail-calls $success with a `tcp` value of the connecting socket.

If an IO error occurs, `accept` tail-calls $error with an `exception`.

If `accept` is cancelled, `accept` tail-calls $cancelled with no arg.

Precondition

The socket must be in listening mode.

$success must be a function which takes a `tcp`.

$error must be a function which takes an `exception`.

$cancelled must be a thunk.

6.94.1.3. Serv.cancel_accept

`cancel_accept` cancels the current or the next `accept` operation of this listening socket.

If no other thread is blocked in `accept` operation, the next invocation of `accept` will be cancelled.

If a single thread is blocked in `accept` operation, the invocation of `accept` will be cancelled.

If multiple threads are blocked in `accept` operation, one of them will be cancelled.

6.94.1.4. Serv.close(...[$config={}])

`close` closes the listening socket.

Config methods:

• C.on_success($success): default = {}

• C.on_error($error): default = {(:Exc) Exc.raise }

If the socket is closed successfully, `close` tail-calls $success with no arg.

If an IO error occurs, `close` tail-calls $error with an `exception`.

Preconditions

$success must be a thunk.

$error must be a function which takes an `exception`.

6.94.1.5. Serv.local_address(...[$config={}])

`local_address` retrieves the `socket_address` of the local address of the listening socket.

Config methods:

• C.on_success($success): default = VAL.identity

• C.on_error($error): default = {(:Exc) Exc.raise }

If the local address is available, `local_address` tail-calls $success with the `socket_address`.

If an IO error occurs, `local_address` tail-calls $error with an `exception`.

Preconditions

$success must be a function which takes a `socket_address`.

$error must be a function which takes an `exception`.

6.94.1.6. Serv.so_reuseaddr

`so_reuseaddr` returns a `ref` of a `bool` of SO_REUSEADDR option.

For usage of socket options, see the example program at the beginning of this module.

Precondition

The protocol family must be ipv4 or ipv6.

6.94.1.7. Serv.so_rcvbuf

`so_rcvbuf` returns a `ref` of a non-negative integer `num` of SO_RCVBUF option.

For usage of socket options, see the example program at the beginning of this module.

6.94.2. TCP_SERVER.open(...[Protocol_family=PROTOCOL_FAMILY.ipv6 $config={}])

`open` method makes a new listening socket.

Config methods:

• C.on_success($success): default = VAL.identity

• C.on_error($error): default = {(:Exc) Exc.raise }

• C.on_unsupported($unsupported): default = a function which tail-calls $error with an `exception`

If a listening socket is created, `open` tail-calls $success with a `tcp_server` of the listening socket.

If an IO error occurs, `open` tail-calls $error with an `exception`.

If the runtime does not support `Protocol_family`, `open` tail-calls $unsupported with no arg.

Preconditions

`Protocol_family` must be a `protocol_family`.

$success must be a function which takes a `tcp_server`.

$error must be a function which takes an `exception`.

6.94.3. TCP_SERVER.is?(Val)

`is?` method returns whether `Val` is a tcp_server.