Up

module Tcp

: sig
#
type 'a where_to_connect constraint 'a = [<
| Import.Socket.Address.t
]

Tcp supports connection to inet sockets and unix sockets. These are two different types. We use 'a where_to_connect to specify a socket to connect to, where the 'a identifies the type of socket.

#
val to_host_and_port : ?via_local_interface:Import.Unix.Inet_addr.t -> string -> int -> Import.Socket.Address.Inet.t where_to_connect
#
val to_inet_address : ?via_local_interface:Import.Unix.Inet_addr.t -> Import.Socket.Address.Inet.t -> Import.Socket.Address.Inet.t where_to_connect
#
val to_file : string -> Import.Socket.Address.Unix.t where_to_connect
#
val to_unix_address : Import.Socket.Address.Unix.t -> Import.Socket.Address.Unix.t where_to_connect
#
type 'a with_connect_options = ?buffer_age_limit:[
| `At_most of Core.Std.Time.Span.t
| `Unlimited
] -> ?interrupt:unit Import.Deferred.t -> ?reader_buffer_size:int -> ?timeout:Core.Std.Time.Span.t -> 'a
#
val with_connection : ('addr where_to_connect -> (([
| `Active
], 'addr) Import.Socket.t -> Import.Reader.t -> Import.Writer.t -> 'a Import.Deferred.t) -> 'a Import.Deferred.t) with_connect_options

with_connection ~host ~port f looks up host from a string (using DNS as needed), connects, then calls f, passing the connected socket and a reader and writer for it. When the deferred returned by f is determined, or any exception is thrown, the socket, reader and writer are closed. The return deferred is fulfilled after f has finished processing and the file descriptor for the socket is closed. If interrupt is supplied then the connection attempt will be aborted if interrupt is fulfilled before the connection has been established. Similarly, all connection attempts have a timeout (default 30s), that can be overridden with timeout.

It is fine for f to ignore the supplied socket and just use the reader and writer. The socket is there to make it convenient to call Socket functions.

#
val connect_sock : 'addr where_to_connect -> ([
| `Active
], 'addr) Import.Socket.t Import.Deferred.t

connect_sock ~host ~port opens a TCP connection to the specified hostname and port, returning the socket.

Any errors in the connection will be reported to the monitor that was current when connect was called.

#
val connect : ('addr where_to_connect -> (([
| `Active
], 'addr) Import.Socket.t * Import.Reader.t * Import.Writer.t) Import.Deferred.t) with_connect_options

connect ~host ~port is a convenience wrapper around connect_sock that returns the socket, and a reader and writer for the socket. The reader and writer share a file descriptor, and so closing one will affect the other. In particular, closing the reader before closing the writer will cause the writer to subsequently raise an exception when it attempts to flush internally-buffered bytes to the OS, due to a closed fd. You should close the Writer first to avoid this problem.

If possible, use with_connection, which automatically handles closing.

It is fine to ignore the returned socket and just use the reader and writer. The socket is there to make it convenient to call Socket functions.

#
module Where_to_listen : sig

A Where_to_listen describes the socket that a tcp server should listen on.

#
type ('address, 'listening_on) t constraint 'address = [<
| Import.Socket.Address.t
]
#
type inet = (Import.Socket.Address.Inet.t, int) t
#
type unix = (Import.Socket.Address.Unix.t, string) t
#
val create : socket_type:'address Import.Socket.Type.t -> address:'address -> listening_on:('address -> 'listening_on) -> ('address, 'listening_on) t
#
val sexp_of_t : ('address -> Sexplib.Sexp.t) -> ('listening_on -> Sexplib.Sexp.t) -> ('address, 'listening_on) t -> Sexplib.Sexp.t
#
val sexp_of_inet : inet -> Sexplib.Sexp.t
#
val sexp_of_unix : unix -> Sexplib.Sexp.t
end
#
val on_port : int -> Where_to_listen.inet
#
val on_port_chosen_by_os : Where_to_listen.inet
#
val on_file : string -> Where_to_listen.unix
#
module Server : sig

A Server.t represents a TCP server listening on a socket.

#
type ('address, 'listening_on) t constraint 'address = [<
| Import.Socket.Address.t
]
#
type inet = (Import.Socket.Address.Inet.t, int) t
#
type unix = (Import.Socket.Address.Unix.t, string) t
#
val invariant : (_, _) t -> unit
#
val listening_on : (_, 'listening_on) t -> 'listening_on
#
val close : (_, _) t -> unit Import.Deferred.t

close t starts closing the listening socket, and returns a deferred that becomes determined after Fd.close_finished fd on the socket's fd. It is guaranteed that t's client handler will never be called after close t. It is ok to call close multiple times on the same t; calls subsequent to the initial call will have no effect, but will return the same deferred as the original call.

close_finished becomes determined after Fd.close_finished fd on the socket's fd, i.e. the same deferred that close returns. close_finished differs from close in that it does not have the side effect of initiating a close.

is_closed t returns true iff close t has been called.

#
val close_finished : (_, _) t -> unit Import.Deferred.t
#
val is_closed : (_, _) t -> bool
#
val create : ?max_connections:int -> ?max_pending_connections:int -> ?buffer_age_limit:Import.Writer.buffer_age_limit -> ?on_handler_error:[
| `Raise
| `Ignore
| `Call of 'address -> exn -> unit
] -> ('address, 'listening_on) Where_to_listen.t -> ('address -> Import.Reader.t -> Import.Writer.t -> unit Import.Deferred.t) -> ('address, 'listening_on) t Import.Deferred.t

create where_to_listen handler starts a server listening to a socket as specified by where_to_listen. It returns a server once the socket is ready to accept connections. The server calls handler (address, reader, writer) for each client that connects. If the deferred returned by handler is ever determined, or handler raises an exception, then reader and writer are closed.

max_pending_connections is the maximum number of clients that can have a connection pending, as with Unix.Socket.listen. Additional connections will be rejected.

max_connections is the maximum number of clients that can be connected simultaneously. The server will not call accept unless the number of clients is less than max_connections, although of course potential clients can have a connection pending.

buffer_age_limit passes on to the underlying writer option of the same name.

on_handler_error determines what happens if the handler throws an exception. The default is `Raise. If an exception is raised by on_handler_error (either explicitely via `Raise, or in the closure passed to `Call) no further connections will be accepted.

The server will stop accepting and close the listening socket when an error handler raises (either via `Raise or `Call f where f raises), or if close is called.

#
val listening_socket : ('address, _) t -> ([
| `Passive
], 'address) Import.Socket.t

listening_socket t accesses the listening socket, which should be used with care. An anticipated use is with Udp.bind_to_interface_exn. Accepting connections on the socket directly will circumvent max_connections and on_handler_error, however, and is not recommended.

end
end