package async_extra

  1. Overview
  2. Docs
Legend:
Library
Module
Module type
Parameter
Class
Class type

Repeater is used in the cases where we want to inspect and possible alter the flow between a client and a server without having to change either the client or the server or the protocol between them. It is written with efficiency in mind which dictated some design decisions.

Repeater is created to act on behalf of a particular server. When a client connects to the repeater, the repeater in turns makes a connection to the server. From the client point of view it looks like it connected to the actual server. Similarly the server thinks that it got a connection from the client. Repeater maintains this pair of connections internally and transfers messages between them, or issues messages itself, all based on application provided callbacks.

Repeater sends its name using credentials field of the Hello message, so it is possible for the server or the client to know that the connection is being routed through a repeater. That might be useful in certain cases.

In order to avoid conversions between types, and to be able to just pass the bytes through, repeater requires that both To_server_msg and To_client_msg use a single version (i.e. low_version = prod_version = test_version). This restriction is not strictly necessary but makes code simpler. It is possible that this will be changed in the future

Parameters

module Server_name : Name
module Client_name : Name
module Mode : Mode

Signature

type t
val create : ?is_client_ip_authorized:(string -> bool) -> is_client_allowed:(Client_name.t -> bool) -> repeater_name:string -> listen_port:int -> server_ip:string -> server_port:int -> server_name:Server_name.t -> t Async_kernel.Deferred.t
type ('state, 'send, 'recv) filter = 'recv -> state:'state -> client_name:Client_name.t -> server_name:Server_name.t -> ('send, 'recv) Repeater_hook_result.t
val start : t -> on_connect:(Client_name.t -> 'state Core.Or_error.t) -> to_server_msg_filter:('state, To_client_msg.t, To_server_msg.t) filter -> to_client_msg_filter:('state, To_server_msg.t, To_client_msg.t) filter -> on_error: (client_name:Client_name.t -> server_name:Server_name.t -> state:'state -> [ `repeater_to_client | `repeater_to_server ] -> Repeater_error.t -> unit) -> on_connecting_error: (client_name:Client_name.t -> server_name:Server_name.t -> Core.Error.t -> unit) -> unit

start t ~on_connect ~to_server_msg_filter ~to_client_msg_filter ~on_error starts listening for connections from clients. For each incoming connection, repeater will create a connection to the actual server. The filter callbacks will be used to decide how to alter the message flow. Assumption is that majority of callback call will result in Pass_on, that is the application will inspect the message, alter its internal state and allow the message to go through unaltered. The repeater code is optimized for this case.

It is important for the application to handle on_error events, especially disconnects. If one connection goes down, the repeater code will not disconnect the other side. This allows the application to do any necessary cleanup and possibly send messages to the other side. Eventually, application should call close_connection_from_client which makes sure that both sides are disconnected. Until then, a new connection pair between the same client and the server cannot be established. Any messages intended for the disconnected side will be dropped.

on_connect is called when a client establishes connection to the repeater. If it returns an Error, then the connection is terminated. Otherwise, the returned connection state will be passed to other callbacks during message processing. This can be used by the application to avoid looking up state based on client or server names.

Any exceptions raised by callbacks will stop the receive message loop on that side, and will be propagated to the monitor that called start.

val send_to_all_clients : t -> To_client_msg.t -> unit
val send_from_all_clients : t -> To_server_msg.t -> unit
val send_to_server_from : t -> Client_name.t -> To_server_msg.t -> unit
val active_clients : t -> Client_name.t list
val close_connection_from_client : t -> Client_name.t -> unit

Closes both the connection from the client to the repeater and the one from the repeater to the server.

val drop_new_clients : t -> unit
val accept_new_clients : t -> unit
val shutdown : t -> unit Async_kernel.Deferred.t