Module Async_udp
A grab-bag of performance-oriented, UDP-oriented network tools. These provide some convenience, but they are more complex than basic applications require.
Defaults are chosen for typical UDP applications. Buffering is via Iobuf conventions, where a typical packet-handling loop iteration is read -> flip_lo -> process -> reset.
While these functions are oriented toward UDP, they work with any files that satisfy Fd.supports_nonblock.
For zero-copy Bigstring.t transfers, we must ensure no buffering between the receive loop and caller. So an interface like Tcp.connect, with something like (Bigstring.t * Socket.Address.Inet.t) Pipe.Reader.t, won't work. Instead, we use synchronous callbacks.
type write_buffer= (Core.read_write, Iobuf.seek) Iobuf.t
val default_capacity : intThe default buffer capacity for UDP-oriented buffers is 1472, determined as the typical Ethernet MTU (1500 octets) less the typical UDP header length (28). Using buffers of this size, one avoids accidentally creating messages that will be dropped on send because they exceed the MTU, and can receive the largest corresponding UDP message.
While this number is merely typical and not guaranteed to work in all cases, defining it in one place makes it easy to share and change. For example, another MTU in common use is 9000 for Jumbo frames, so the value of
default_capacitymight change to 8972 in the future.
module Config : sig ... endA typical receive loop implicitly calls
Iobuf.flip_lobefore calling its callback to prepare a packet buffer for reading by the callback andIobuf.resetafterward to prepare for the next iteration.
val sendto_sync : unit -> (Async.Fd.t -> ([> Core.read ], Iobuf.seek) Iobuf.t -> Async.Socket.Address.Inet.t -> Async.Unix.Syscall_result.Unit.t) Core.Or_error.tsendto_sync sock buf addrdoes not try again ifsockis not ready to write. Instead, it returnsEWOULDBLOCKimmediately.Short writes are distinguished by
bufnot being empty afterward.See also
Iobuf.sendto_nonblocking_no_sigpipe andBigstring.sendto_nonblocking_no_sigpipe.- raises Failure
on internal errors but return
Unix.errorviaUnix.Syscall_result.Unit.trather than raisingUnix_error.
val send_sync : unit -> (Async.Fd.t -> ([> Core.read ], Iobuf.seek) Iobuf.t -> Async.Unix.Syscall_result.Unit.t) Core.Or_error.tsend_sync sock bufhas identical semantics tosendto_sync, but is intended for connected UDP sockets (and therefore does not require a "to" address).See also
Iobuf.send_nonblocking_no_sigpipe andBigstring.send_nonblocking_no_sigpipe.- raises Failure
on internal errors but return
Unix.errorviaUnix.Syscall_result.Unit.trather than raisingUnix_error.
val sendto : unit -> (Async.Fd.t -> ([> Core.read ], Iobuf.seek) Iobuf.t -> Async.Socket.Address.Inet.t -> unit Async.Deferred.t) Core.Or_error.tsendto sock buf addrretries ifsockis not ready to write.- raises Unix_error
in the case of Unix output errors and
Failureon internal errors.
val send : unit -> (Async.Fd.t -> ([> Core.read ], Iobuf.seek) Iobuf.t -> unit Async.Deferred.t) Core.Or_error.tsend sock bufretries ifsockis not ready to write.- raises Unix_error
in the case of Unix output errors and
Failureon internal errors.
val bind : ?ifname:string -> ?source:Async.Unix.Inet_addr.t -> ?reuseaddr:bool -> Async.Socket.Address.Inet.t -> ([ `Bound ], Async.Socket.Address.Inet.t) Async.Socket.tbind ?ifname ?source addresscreates a socket bound to address, and ifaddressis multicast address,- joins the multicast group.
- if
ifnameis specified, joins the multicast group on ifname. - if
sourceis specified, joins the multicast group with source.
val bind_any : unit -> ([ `Bound ], Async.Socket.Address.Inet.t) Async.Socket.t
module Loop_result : sig ... endval recvfrom_loop : ?config:Config.t -> Async.Fd.t -> (write_buffer -> Async.Socket.Address.Inet.t -> unit) -> Loop_result.t Async.Deferred.tLoops, including
recvfrom_loop, terminate normally when the socket is closed.
val recvfrom_loop_with_buffer_replacement : ?config:Config.t -> Async.Fd.t -> (write_buffer -> Async.Socket.Address.Inet.t -> write_buffer) -> Loop_result.t Async.Deferred.trecvfrom_loop_with_buffer_replacement callbackcallscallbacksynchronously on each message received.callbackreturns the packet buffer for subsequent iterations, so it can replace the initial packet buffer when necessary. This enables immediate buffer reuse in the common case and fallback to allocation if we want to save the packet buffer for asynchronous processing.
val read_loop : ?config:Config.t -> Async.Fd.t -> (write_buffer -> unit) -> Loop_result.t Async.Deferred.tval read_loop_with_buffer_replacement : ?config:Config.t -> Async.Fd.t -> (write_buffer -> write_buffer) -> Loop_result.t Async.Deferred.tval recvmmsg_loop : (?config:Config.t -> ?max_count:int -> ?on_wouldblock:(unit -> unit) -> Async.Fd.t -> (write_buffer array -> count:int -> unit) -> Loop_result.t Async.Deferred.t) Core.Or_error.trecvmmsg_loop ~socket callbackiteratively receives up tomax_countpackets at a time onsocketand passes them tocallback. Each packet is up toIobuf.capacitybytes.callback bufs ~countprocessescountpackets synchronously.Config.init configis used as a prototype forbufsand as one of the elements.
module Ready_iter : sig ... endval custom_on_readable_loop : ?config:Config.t -> Async.Fd.t -> syscall_name:string -> f:(Core.Unix.File_descr.t -> Ready_iter.t) -> Loop_result.t Async.Deferred.tIf you need a custom read operation on an FD that we don't provide, use this to turn it into a loop with the same features as our other APIs.