chromium/services/network/public/mojom/udp_socket.mojom

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

module network.mojom;

import "mojo/public/mojom/base/read_only_buffer.mojom";
import "services/network/public/mojom/ip_address.mojom";
import "services/network/public/mojom/ip_endpoint.mojom";
import "services/network/public/mojom/optional_bool.mojom";
import "services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom";

// Represents options that consumers can set when requesting a UDPSocket
// interface pointer.
struct UDPSocketOptions {
  // If true, this enables SO_REUSEADDR on the underlying socket.
  bool allow_address_reuse = false;

  // If true, allows sending and receiving packets to and from broadcast
  // addresses. It's recommended this be used instead of SetBroadcast(), as
  // Bind() may fail on some platforms when reusing a UDP port and broadcast
  // is not enabled when the socket is created.
  bool allow_broadcast = false;

  // If true, allows the socket to share the local address to which the socket
  // will be bound with other processes and attempts to allow all such sockets
  // to receive the same multicast messages.
  //
  // For best cross-platform results in allowing the messages to be shared, all
  // sockets sharing the same address should join the same multicast group (via
  // UDPSocket::JoinGroup()) and set the same |multicast_interface|. Also, the
  // socket should bind to the specific multicast group address rather than a
  // wildcard address (e.g. 0.0.0.0) on platforms where doing so is allowed.
  bool allow_address_sharing_for_multicast = false;

  // Sets interface to use for multicast. Default value is 0, in which case the
  // default interface is used.
  uint32 multicast_interface = 0;

  // Sets the time-to-live option for UDP packets sent to the multicast
  // group address. The default value of this option is 1. Cannot be more than
  // 255.
  uint32 multicast_time_to_live = 1;

  // Sets the loopback flag for UDP socket. If this flag is true and the socket
  // joins a group through JoinGroup(), the socket will receive packets sent to
  // the joined group from itself. The default value of this option is true.
  //
  // Note: the behavior of |SetMulticastLoopbackMode| is slightly
  // different between Windows and Unix-like systems. The inconsistency only
  // happens when there are more than one applications on the same host
  // joined to the same multicast group while having different settings on
  // multicast loopback mode. On Windows, the applications with loopback off
  // will not RECEIVE the loopback packets; while on Unix-like systems, the
  // applications with loopback off will not SEND the loopback packets to
  // other applications on the same host. See MSDN: http://goo.gl/6vqbj
  bool multicast_loopback_mode = true;

  // Sets the OS send buffer size (in bytes) for the socket. This is the
  // SO_SNDBUF socket option. This socket option matters less for UDP socket (as
  // compared to TCP), because in theory all UDP data written to the kernel
  // should directly go out to the network. The kernel usually doesn't need to
  // buffer send data. Default value is 0, in which case, OS's default value
  // will be used.
  int32 send_buffer_size = 0;

  // Sets the OS receive buffer size (in bytes) for the socket. This is the
  // SO_RCVBUF socket option. The kernel allocates this much to hold the data
  // arriving into this socket between the time when data arrives over the
  // network and when it is read by UDPSocketListener. If buffer is full,
  // new packets will be discarded. Default value is 0, in which case, OS's
  // default value will be used.
  int32 receive_buffer_size = 0;

  // Sets IPV6_V6ONLY on the socket to enable/disable dual stack mode.
  // |true| restricts incoming connections to IPv6 only; |false| allows both
  // IPv4/IPv6 connections. Leaving this value unset results in platform default
  // being applied (|true| on Windows, |false| on Posix).
  OptionalBool ipv6_only;
};

// UDPSocket is an interface that exposes UDP socket functionalities.
// UDPSocketListener is an interface that allows consumers to consume data
// received by the UDPSocket. The typical flow of using the interfaces is:
// - Acquire a UDPSocket interface pointer and optionally supply a non-null
//   UDPSocketListenerPtr. If consumers are not interested in received data, a
//   null UDPSocketListenerPtr is acceptable.
// - Use either Bind() or Connect() before datagrams can be sent or received.
// - (optional) Invoke setters (e.g. SetBroadcast()).
// - Send / request to receive datagrams. Received datagrams will be delivered
//   to the bound listener's OnReceived() call.
// - Close the socket by destroying the interface pointer.
interface UDPSocket {
  // Binds the address/port for this socket to |local_addr|. Caller can use port
  // 0 to let the OS pick an available port. If |socket_options| is not null,
  // configures the socket with the options before binding the socket.
  // Returns net::OK and the real local address used on success and a negative
  // net error code on failure.
  Bind(IPEndPoint local_addr, UDPSocketOptions? socket_options)
      => (int32 result, IPEndPoint? local_addr_out);

  // Connects the socket to |remote_addr|. This automatically binds the socket
  // to an available local port, so this cannot be used with Bind().
  // If |socket_options| is not null, configures the socket with the options
  // before connecting the socket.
  // The address family of the local socket will be of the same
  // AddressFamily as |remote_addr|. Returns net::OK and the local address of
  // socket on success. Subsequent packets received will be from |remote_addr|.
  // Returns a negative net error code on failure.
  Connect(IPEndPoint remote_addr, UDPSocketOptions? socket_options) =>
      (int32 result, IPEndPoint? local_addr_out);

  // Allows or disallows sending and receiving packets to and from broadcast
  // addresses. Returns a net error code. Should only be called after Bind().
  SetBroadcast(bool broadcast) => (int32 result);

  // Sets the OS send buffer size (in bytes) for the socket. Overwrites any
  // previously set value. Returns a net error code.
  // See |UDPSocketOptions::send_buffer_size| for more information.
  SetSendBufferSize(int32 send_buffer_size) => (int32 result);

  // Sets the OS receive buffer size (in bytes) for the socket. Overwrites any
  // previously set value. Returns a net error code.
  // See |UDPSocketOptions::receive_buffer_size| for more information.
  SetReceiveBufferSize(int32 receive_buffer_size) => (int32 result);

  // Joins a multicast group. |group_address| is the group address to join,
  // could be either an IPv4 or IPv6 address. Returns a net error code.
  // See RFC 1112 for details on multicast.
  JoinGroup(IPAddress group_address) => (int32 result);

  // Leaves the multicast group. |group_address| is the group address to leave,
  // could be either an IPv4 or IPv6 address. If the socket hasn't joined the
  // group, this call will be ignored. It's optional to leave the multicast
  // group before destroying the socket. Returns a net error code.
  LeaveGroup(IPAddress group_address) => (int32 result);

  // Notifies that the listener is ready to accept |number| of datagrams.
  // Correspondingly, OnReceived() of the UDPSocketListener interface will be
  // called |number| times (errors also count), unless the connection is closed
  // before that. The implementation may return net::ERR_INSUFFICIENT_RESOURCES
  // in an OnReceived() callback if the service doesn't have enough resource to
  // complete the operation. For example, if the implementation queues the
  // requests internally, net::ERR_INSUFFICIENT_RESOURCES can be returned if the
  // queue doesn't have any space to accept new ReceiveMore().
  //
  // It is allowed to call this method again before the previous request is
  // completely satisfied. For example:
  //   service->ReceiveMore(3);
  //   ...
  //   // OnReceived() is called.
  //   // OnReceived() is called.
  //   ...
  //   service->ReceiveMore(3);
  //   // The client expects 4 more calls to OnReceived().
  //
  // Please note that how ReceiveMore() is used will affect performance
  // significantly. For example:
  //   // Approach 1:
  //   service->ReceiveMore(3);
  //   // OnReceived() is called.
  //   // OnReceived() is called.
  //   // OnReceived() is called.
  //
  //   // Approach 2:
  //   service->ReceiveMore(1);
  //   // OnReceived() is called.
  //   service->ReceiveMore(1);
  //   // OnReceived() is called.
  //   service->ReceiveMore(1);
  //   // OnReceived() is called.
  //
  // It is very likely that approach 1 will perform better than approach 2,
  // because in approach 2 getting every datagram takes at least the time of a
  // round trip to the service side. Default buffer size of 64KiB will be
  // allocated to receive each datagram.
  ReceiveMore(uint32 num_additional_datagrams);

  // Same as ReceiveMore(), but with an ability to set the buffer size used for
  // receiving each datagram. Note that |buffer_size| is the application-side
  // buffer which is different from UDPSocketOptions::receive_buffer_size which
  // is the OS-side buffer. |buffer_size| larger than 64KiB will be capped at
  // 64KiB as the limit on data length of a IPv4 UDP packet is 65,507 and 65,535
  // for IPv6.
  ReceiveMoreWithBufferSize(
      uint32 num_additional_datagrams, uint32 buffer_size);

  // Sends data to a particular destination, |dest_addr|. Should only be used
  // after Bind(). There is currently no limit on the size of |data|, other
  // than the restrictions on datagram size specified in the IP layer (e.g.
  // 65507 bytes for IPv4) . Consumers need to be aware that sending data in
  // larger chunks will result in higher memory usage. Upon successfully handing
  // the data to the OS, |result| is net::OK. On failure, it is a network error
  // code, including (but not limited to):
  // - net::ERR_INSUFFICIENT_RESOURCES: The service doesn't have
  //   sufficient resource to complete the operation. When this happens, the
  //   requests will be failed quickly (which might happen before the completion
  //   of requests that were sent earlier).
  SendTo(IPEndPoint dest_addr,
         mojo_base.mojom.ReadOnlyBuffer data,
         MutableNetworkTrafficAnnotationTag traffic_annotation)
      => (int32 result);

  // Same as SendTo(), except this method sends data to the destination
  // specified in an earlier Connect(). This method should only be called after
  // a successful Connect().
  Send(mojo_base.mojom.ReadOnlyBuffer data,
       MutableNetworkTrafficAnnotationTag traffic_annotation)
      => (int32 result);

  // Closes the socket. Connect() or Bind() can be used after Close().
  Close();
};

// An interface the consumers of UDPSocket can implement to listen for incoming
// packets. This interface is to be used together when requesting a UDPSocket.
interface UDPSocketListener {
  // Invoked when data is received.
  // - When UDPSocket is used with Bind():
  //   On success, |result| is net::OK. |src_addr| indicates the address of the
  //   sender. |data| contains the received data.
  //   On failure, |result| is a negative network error code. |data| is null.
  //   |src_addr| might be null.
  // - When UDPSocket is used with Connect():
  //   |src_addr| is always null. Data are always received from the remote
  //   address specified in Connect().
  //   On success, |result| is net::OK. |data| contains the received data.
  //   On failure, |result| is a negative network error code. |data| is null.
  //
  // Note that in both cases, |data| can be an empty buffer when |result| is
  // net::OK, which indicates a zero-byte payload.
  OnReceived(int32 result,
             IPEndPoint? src_addr,
             mojo_base.mojom.ReadOnlyBuffer? data);
};