dcsctp: Add public API

Clients will use this API for all their interactions with this library.
It's made into an interface (of which there will only be a single
implementation) simply for documentation purposes. But that also allows
clients to mock the library if wanted or to have a thread-safe wrapper,
as the library itself is not thread-safe, while keeping the same
interface.

Bug: webrtc:12614
Change-Id: I346af9916e26487da040c01825c2547aa7a5d0b7
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/213348
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Tommi <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33648}
diff --git a/net/dcsctp/public/BUILD.gn b/net/dcsctp/public/BUILD.gn
index 0bfab84..8a7e26e 100644
--- a/net/dcsctp/public/BUILD.gn
+++ b/net/dcsctp/public/BUILD.gn
@@ -14,7 +14,25 @@
 
 rtc_source_set("types") {
   deps = [ ":strong_alias" ]
-  sources = [ "types.h" ]
+  sources = [
+    "dcsctp_message.h",
+    "dcsctp_options.h",
+    "types.h",
+  ]
+}
+
+rtc_source_set("socket") {
+  deps = [
+    "//api:array_view",
+    "//rtc_base",
+    "//rtc_base:checks",
+    "//rtc_base:rtc_base_approved",
+  ]
+  sources = [
+    "dcsctp_socket.h",
+    "packet_observer.h",
+    "timeout.h",
+  ]
 }
 
 if (rtc_include_tests) {
diff --git a/net/dcsctp/public/dcsctp_message.h b/net/dcsctp/public/dcsctp_message.h
new file mode 100644
index 0000000..38e6763
--- /dev/null
+++ b/net/dcsctp/public/dcsctp_message.h
@@ -0,0 +1,54 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PUBLIC_DCSCTP_MESSAGE_H_
+#define NET_DCSCTP_PUBLIC_DCSCTP_MESSAGE_H_
+
+#include <cstdint>
+#include <utility>
+#include <vector>
+
+#include "api/array_view.h"
+#include "net/dcsctp/public/types.h"
+
+namespace dcsctp {
+
+// An SCTP message is a group of bytes sent and received as a whole on a
+// specified stream identifier (`stream_id`), and with a payload protocol
+// identifier (`ppid`).
+class DcSctpMessage {
+ public:
+  DcSctpMessage(StreamID stream_id, PPID ppid, std::vector<uint8_t> payload)
+      : stream_id_(stream_id), ppid_(ppid), payload_(std::move(payload)) {}
+
+  DcSctpMessage(DcSctpMessage&& other) = default;
+  DcSctpMessage& operator=(DcSctpMessage&& other) = default;
+  DcSctpMessage(const DcSctpMessage&) = delete;
+  DcSctpMessage& operator=(const DcSctpMessage&) = delete;
+
+  // The stream identifier to which the message is sent.
+  StreamID stream_id() const { return stream_id_; }
+
+  // The payload protocol identifier (ppid) associated with the message.
+  PPID ppid() const { return ppid_; }
+
+  // The payload of the message.
+  rtc::ArrayView<const uint8_t> payload() const { return payload_; }
+
+  // When destructing the message, extracts the payload.
+  std::vector<uint8_t> ReleasePayload() && { return std::move(payload_); }
+
+ private:
+  StreamID stream_id_;
+  PPID ppid_;
+  std::vector<uint8_t> payload_;
+};
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PUBLIC_DCSCTP_MESSAGE_H_
diff --git a/net/dcsctp/public/dcsctp_options.h b/net/dcsctp/public/dcsctp_options.h
new file mode 100644
index 0000000..acc237a
--- /dev/null
+++ b/net/dcsctp/public/dcsctp_options.h
@@ -0,0 +1,122 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PUBLIC_DCSCTP_OPTIONS_H_
+#define NET_DCSCTP_PUBLIC_DCSCTP_OPTIONS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "net/dcsctp/public/types.h"
+
+namespace dcsctp {
+struct DcSctpOptions {
+  // The largest safe SCTP packet. Starting from the minimum guaranteed MTU
+  // value of 1280 for IPv6 (which may not support fragmentation), take off 85
+  // bytes for DTLS/TURN/TCP/IP and ciphertext overhead.
+  //
+  // Additionally, it's possible that TURN adds an additional 4 bytes of
+  // overhead after a channel has been established, so an additional 4 bytes is
+  // subtracted
+  //
+  // 1280 IPV6 MTU
+  //  -40 IPV6 header
+  //   -8 UDP
+  //  -24 GCM Cipher
+  //  -13 DTLS record header
+  //   -4 TURN ChannelData
+  // = 1191 bytes.
+  static constexpr size_t kMaxSafeMTUSize = 1191;
+
+  // The local port for which the socket is supposed to be bound to. Incoming
+  // packets will be verified that they are sent to this port number and all
+  // outgoing packets will have this port number as source port.
+  int local_port = 5000;
+
+  // The remote port to send packets to. All outgoing packets will have this
+  // port number as destination port.
+  int remote_port = 5000;
+
+  // Maximum SCTP packet size. The library will limit the size of generated
+  // packets to be less than or equal to this number. This does not include any
+  // overhead of DTLS, TURN, UDP or IP headers.
+  size_t mtu = kMaxSafeMTUSize;
+
+  // Maximum received window buffer size. This should be a bit larger than the
+  // largest sized message you want to be able to receive. This essentially
+  // limits the memory usage on the receive side. Note that memory is allocated
+  // dynamically, and this represents the maximum amount of buffered data. The
+  // actual memory usage of the library will be smaller in normal operation, and
+  // will be larger than this due to other allocations and overhead if the
+  // buffer is fully utilized.
+  size_t max_receiver_window_buffer_size = 5 * 1024 * 1024;
+
+  // Maximum send buffer size. It will not be possible to queue more data than
+  // this before sending it.
+  size_t max_send_buffer_size = 2 * 1024 * 1024;
+
+  // Initial RTO value.
+  DurationMs rto_initial = DurationMs(500);
+
+  // Maximum RTO value.
+  DurationMs rto_max = DurationMs(800);
+
+  // Minimum RTO value.
+  DurationMs rto_min = DurationMs(120);
+
+  // T1-init timeout.
+  DurationMs t1_init_timeout = DurationMs(1000);
+
+  // T1-cookie timeout.
+  DurationMs t1_cookie_timeout = DurationMs(1000);
+
+  // T2-shutdown timeout.
+  DurationMs t2_shutdown_timeout = DurationMs(1000);
+
+  // Hearbeat interval (on idle connections only).
+  DurationMs heartbeat_interval = DurationMs(30'000);
+
+  // The maximum time when a SACK will be sent from the arrival of an
+  // unacknowledged packet. Whatever is smallest of RTO/2 and this will be used.
+  DurationMs delayed_ack_max_timeout = DurationMs(200);
+
+  // Do slow start as TCP - double cwnd instead of increasing it by MTU.
+  bool slow_start_tcp_style = true;
+
+  // The initial congestion window size, in number of MTUs.
+  // See https://tools.ietf.org/html/rfc4960#section-7.2.1 which defaults at ~3
+  // and https://research.google/pubs/pub36640/ which argues for at least ten
+  // segments.
+  size_t cwnd_mtus_initial = 10;
+
+  // The minimum congestion window size, in number of MTUs.
+  // See https://tools.ietf.org/html/rfc4960#section-7.2.3.
+  size_t cwnd_mtus_min = 4;
+
+  // Maximum Data Retransmit Attempts (per DATA chunk).
+  int max_retransmissions = 10;
+
+  // Max.Init.Retransmits (https://tools.ietf.org/html/rfc4960#section-15)
+  int max_init_retransmits = 8;
+
+  // RFC3758 Partial Reliability Extension
+  bool enable_partial_reliability = true;
+
+  // RFC8260 Stream Schedulers and User Message Interleaving
+  bool enable_message_interleaving = false;
+
+  // If RTO should be added to heartbeat_interval
+  bool heartbeat_interval_include_rtt = true;
+
+  // Disables SCTP packet crc32 verification. Useful when running with fuzzers.
+  bool disable_checksum_verification = false;
+};
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PUBLIC_DCSCTP_OPTIONS_H_
diff --git a/net/dcsctp/public/dcsctp_socket.h b/net/dcsctp/public/dcsctp_socket.h
new file mode 100644
index 0000000..e7f2134
--- /dev/null
+++ b/net/dcsctp/public/dcsctp_socket.h
@@ -0,0 +1,278 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PUBLIC_DCSCTP_SOCKET_H_
+#define NET_DCSCTP_PUBLIC_DCSCTP_SOCKET_H_
+
+#include <cstdint>
+#include <memory>
+#include <utility>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/public/dcsctp_message.h"
+#include "net/dcsctp/public/packet_observer.h"
+#include "net/dcsctp/public/timeout.h"
+#include "net/dcsctp/public/types.h"
+
+namespace dcsctp {
+
+// Send options for sending messages
+struct SendOptions {
+  // If the message should be sent with unordered message delivery.
+  IsUnordered unordered = IsUnordered(false);
+
+  // If set, will discard messages that haven't been correctly sent and
+  // received before the lifetime has expired. This is only available if the
+  // peer supports Partial Reliability Extension (RFC3758).
+  absl::optional<DurationMs> lifetime = absl::nullopt;
+
+  // If set, limits the number of retransmissions. This is only available
+  // if the peer supports Partial Reliability Extension (RFC3758).
+  absl::optional<size_t> max_retransmissions = absl::nullopt;
+};
+
+enum class ErrorKind {
+  // Indicates that no error has occurred. This will never be the case when
+  // `OnError` or `OnAborted` is called.
+  kNoError,
+  // There have been too many retries or timeouts, and the library has given up.
+  kTooManyRetries,
+  // A command was received that is only possible to execute when the socket is
+  // connected, which it is not.
+  kNotConnected,
+  // Parsing of the command or its parameters failed.
+  kParseFailed,
+  // Commands are received in the wrong sequence, which indicates a
+  // synchronisation mismatch between the peers.
+  kWrongSequence,
+  // The peer has reported an issue using ERROR or ABORT command.
+  kPeerReported,
+  // The peer has performed a protocol violation.
+  kProtocolViolation,
+  // The receive or send buffers have been exhausted.
+  kResourceExhaustion,
+};
+
+inline constexpr absl::string_view ToString(ErrorKind error) {
+  switch (error) {
+    case ErrorKind::kNoError:
+      return "NO_ERROR";
+    case ErrorKind::kTooManyRetries:
+      return "TOO_MANY_RETRIES";
+    case ErrorKind::kNotConnected:
+      return "NOT_CONNECTED";
+    case ErrorKind::kParseFailed:
+      return "PARSE_FAILED";
+    case ErrorKind::kWrongSequence:
+      return "WRONG_SEQUENCE";
+    case ErrorKind::kPeerReported:
+      return "PEER_REPORTED";
+    case ErrorKind::kProtocolViolation:
+      return "PROTOCOL_VIOLATION";
+    case ErrorKind::kResourceExhaustion:
+      return "RESOURCE_EXHAUSTION";
+  }
+}
+
+// Return value of SupportsStreamReset.
+enum class StreamResetSupport {
+  // If the connection is not yet established, this will be returned.
+  kUnknown,
+  // Indicates that Stream Reset is supported by the peer.
+  kSupported,
+  // Indicates that Stream Reset is not supported by the peer.
+  kNotSupported,
+};
+
+// Callbacks that the DcSctpSocket will be done synchronously to the owning
+// client. It is allowed to call back into the library from callbacks that start
+// with "On". It has been explicitly documented when it's not allowed to call
+// back into this library from within a callback.
+//
+// Theses callbacks are only synchronously triggered as a result of the client
+// calling a public method in `DcSctpSocketInterface`.
+class DcSctpSocketCallbacks {
+ public:
+  virtual ~DcSctpSocketCallbacks() = default;
+
+  // Called when the library wants the packet serialized as `data` to be sent.
+  //
+  // Note that it's NOT ALLOWED to call into this library from within this
+  // callback.
+  virtual void SendPacket(rtc::ArrayView<const uint8_t> data) = 0;
+
+  // Called when the library wants to create a Timeout. The callback must return
+  // an object that implements that interface.
+  //
+  // Note that it's NOT ALLOWED to call into this library from within this
+  // callback.
+  virtual std::unique_ptr<Timeout> CreateTimeout() = 0;
+
+  // Returns the current time in milliseconds (from any epoch).
+  //
+  // Note that it's NOT ALLOWED to call into this library from within this
+  // callback.
+  virtual TimeMs TimeMillis() = 0;
+
+  // Called when the library needs a random number uniformly distributed between
+  // `low` (inclusive) and `high` (exclusive). The random number used by the
+  // library are not used for cryptographic purposes there are no requirements
+  // on a secure random number generator.
+  //
+  // Note that it's NOT ALLOWED to call into this library from within this
+  // callback.
+  virtual uint32_t GetRandomInt(uint32_t low, uint32_t high) = 0;
+
+  // Triggered when the outgoing message buffer is empty, meaning that there are
+  // no more queued messages, but there can still be packets in-flight or to be
+  // retransmitted. (in contrast to SCTP_SENDER_DRY_EVENT).
+  // TODO(boivie): This is currently only used in benchmarks to have a steady
+  // flow of packets to send
+  //
+  // Note that it's NOT ALLOWED to call into this library from within this
+  // callback.
+  virtual void NotifyOutgoingMessageBufferEmpty() = 0;
+
+  // Called when the library has received an SCTP message in full and delivers
+  // it to the upper layer.
+  //
+  // It is allowed to call into this library from within this callback.
+  virtual void OnMessageReceived(DcSctpMessage message) = 0;
+
+  // Triggered when an non-fatal error is reported by either this library or
+  // from the other peer (by sending an ERROR command). These should be logged,
+  // but no other action need to be taken as the association is still viable.
+  //
+  // It is allowed to call into this library from within this callback.
+  virtual void OnError(ErrorKind error, absl::string_view message) = 0;
+
+  // Triggered when the socket has aborted - either as decided by this socket
+  // due to e.g. too many retransmission attempts, or by the peer when
+  // receiving an ABORT command. No other callbacks will be done after this
+  // callback, unless reconnecting.
+  //
+  // It is allowed to call into this library from within this callback.
+  virtual void OnAborted(ErrorKind error, absl::string_view message) = 0;
+
+  // Called when calling `Connect` succeeds, but also for incoming successful
+  // connection attempts.
+  //
+  // It is allowed to call into this library from within this callback.
+  virtual void OnConnected() = 0;
+
+  // Called when the socket is closed in a controlled way. No other
+  // callbacks will be done after this callback, unless reconnecting.
+  //
+  // It is allowed to call into this library from within this callback.
+  virtual void OnClosed() = 0;
+
+  // On connection restarted (by peer). This is just a notification, and the
+  // association is expected to work fine after this call, but there could have
+  // been packet loss as a result of restarting the association.
+  //
+  // It is allowed to call into this library from within this callback.
+  virtual void OnConnectionRestarted() = 0;
+
+  // Indicates that a stream reset request has failed.
+  //
+  // It is allowed to call into this library from within this callback.
+  virtual void OnStreamsResetFailed(
+      rtc::ArrayView<const StreamID> outgoing_streams,
+      absl::string_view reason) = 0;
+
+  // Indicates that a stream reset request has been performed.
+  //
+  // It is allowed to call into this library from within this callback.
+  virtual void OnStreamsResetPerformed(
+      rtc::ArrayView<const StreamID> outgoing_streams) = 0;
+
+  // When a peer has reset some of its outgoing streams, this will be called. An
+  // empty list indicates that all streams have been reset.
+  //
+  // It is allowed to call into this library from within this callback.
+  virtual void OnIncomingStreamsReset(
+      rtc::ArrayView<const StreamID> incoming_streams) = 0;
+
+  // If an outgoing message has expired before being completely sent.
+  // TODO(boivie) Add some kind of message identifier.
+  // TODO(boivie) Add callbacks for OnMessageSent and OnSentMessageAcked
+  //
+  // It is allowed to call into this library from within this callback.
+  virtual void OnSentMessageExpired(StreamID stream_id,
+                                    PPID ppid,
+                                    bool unsent) = 0;
+};
+
+// The DcSctpSocket implementation implements the following interface.
+class DcSctpSocketInterface {
+ public:
+  virtual ~DcSctpSocketInterface() = default;
+
+  // To be called when an incoming SCTP packet is to be processed.
+  virtual void ReceivePacket(rtc::ArrayView<const uint8_t> data) = 0;
+
+  // To be called when a timeout has expired. The `timeout_id` is provided
+  // when the timeout was initiated.
+  virtual void HandleTimeout(TimeoutID timeout_id) = 0;
+
+  // Connects the socket. This is an asynchronous operation, and
+  // `DcSctpSocketCallbacks::OnConnected` will be called on success.
+  virtual void Connect() = 0;
+
+  // Gracefully shutdowns the socket and sends all outstanding data. This is an
+  // asynchronous operation and `DcSctpSocketCallbacks::OnClosed` will be called
+  // on success.
+  virtual void Shutdown() = 0;
+
+  // Closes the connection non-gracefully. Will send ABORT if the connection is
+  // not already closed. No callbacks will be made after Close() has returned.
+  virtual void Close() = 0;
+
+  // Resetting streams is an asynchronous operation and the results will
+  // be notified using `DcSctpSocketCallbacks::OnStreamsResetDone()` on success
+  // and `DcSctpSocketCallbacks::OnStreamsResetFailed()` on failure. Note that
+  // only outgoing streams can be reset.
+  //
+  // When it's known that the peer has reset its own outgoing streams,
+  // `DcSctpSocketCallbacks::OnIncomingStreamReset` is called.
+  //
+  // Note that resetting a stream will also remove all queued messages on those
+  // streams, but will ensure that the currently sent message (if any) is fully
+  // sent before closing the stream.
+  //
+  // Resetting streams can only be done on an established association that
+  // supports stream resetting. Calling this method on e.g. a closed association
+  // or streams that don't support resetting will not perform any operation.
+  virtual void ResetStreams(
+      rtc::ArrayView<const StreamID> outgoing_streams) = 0;
+
+  // Indicates if the peer supports resetting streams (RFC6525). Please note
+  // that the connection must be established for support to be known.
+  virtual StreamResetSupport SupportsStreamReset() const = 0;
+
+  // Sends the message `message` using the provided send options.
+  // Sending a message is an asynchrous operation, and the `OnError` callback
+  // may be invoked to indicate any errors in sending the message.
+  //
+  // The association does not have to be established before calling this method.
+  // If it's called before there is an established association, the message will
+  // be queued.
+  void Send(DcSctpMessage message, const SendOptions& send_options = {}) {
+    SendMessage(std::move(message), send_options);
+  }
+
+ private:
+  virtual void SendMessage(DcSctpMessage message,
+                           const SendOptions& send_options) = 0;
+};
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PUBLIC_DCSCTP_SOCKET_H_
diff --git a/net/dcsctp/public/packet_observer.h b/net/dcsctp/public/packet_observer.h
new file mode 100644
index 0000000..fe75678
--- /dev/null
+++ b/net/dcsctp/public/packet_observer.h
@@ -0,0 +1,37 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PUBLIC_PACKET_OBSERVER_H_
+#define NET_DCSCTP_PUBLIC_PACKET_OBSERVER_H_
+
+#include <stdint.h>
+
+#include "api/array_view.h"
+#include "net/dcsctp/public/types.h"
+
+namespace dcsctp {
+
+// A PacketObserver can be attached to a socket and will be called for
+// all sent and received packets.
+class PacketObserver {
+ public:
+  virtual ~PacketObserver() = default;
+  // Called when a packet is sent, with the current time (in milliseconds) as
+  // `now`, and the packet payload as `payload`.
+  virtual void OnSentPacket(TimeMs now,
+                            rtc::ArrayView<const uint8_t> payload) = 0;
+
+  // Called when a packet is received, with the current time (in milliseconds)
+  // as `now`, and the packet payload as `payload`.
+  virtual void OnReceivedPacket(TimeMs now,
+                                rtc::ArrayView<const uint8_t> payload) = 0;
+};
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PUBLIC_PACKET_OBSERVER_H_
diff --git a/net/dcsctp/public/timeout.h b/net/dcsctp/public/timeout.h
new file mode 100644
index 0000000..64ba351
--- /dev/null
+++ b/net/dcsctp/public/timeout.h
@@ -0,0 +1,53 @@
+/*
+ *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+#ifndef NET_DCSCTP_PUBLIC_TIMEOUT_H_
+#define NET_DCSCTP_PUBLIC_TIMEOUT_H_
+
+#include <cstdint>
+
+#include "net/dcsctp/public/types.h"
+
+namespace dcsctp {
+
+// A very simple timeout that can be started and stopped. When started,
+// it will be given a unique `timeout_id` which should be provided to
+// `DcSctpSocket::HandleTimeout` when it expires.
+class Timeout {
+ public:
+  virtual ~Timeout() = default;
+
+  // Called to start time timeout, with the duration in milliseconds as
+  // `duration` and with the timeout identifier as `timeout_id`, which - if
+  // the timeout expires - shall be provided to `DcSctpSocket::HandleTimeout`.
+  //
+  // `Start` and `Stop` will always be called in pairs. In other words will
+  // ´Start` never be called twice, without a call to `Stop` in between.
+  virtual void Start(DurationMs duration, TimeoutID timeout_id) = 0;
+
+  // Called to stop the running timeout.
+  //
+  // `Start` and `Stop` will always be called in pairs. In other words will
+  // ´Start` never be called twice, without a call to `Stop` in between.
+  //
+  // `Stop` will always be called prior to releasing this object.
+  virtual void Stop() = 0;
+
+  // Called to restart an already running timeout, with the `duration` and
+  // `timeout_id` parameters as described in `Start`. This can be overridden by
+  // the implementation to restart it more efficiently.
+  virtual void Restart(DurationMs duration, TimeoutID timeout_id) {
+    Stop();
+    Start(duration, timeout_id);
+  }
+};
+
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_PUBLIC_TIMEOUT_H_
diff --git a/net/dcsctp/public/types.h b/net/dcsctp/public/types.h
index 16c3e28..31c3f94 100644
--- a/net/dcsctp/public/types.h
+++ b/net/dcsctp/public/types.h
@@ -28,6 +28,12 @@
 // other messages on the same stream.
 using IsUnordered = StrongAlias<class IsUnorderedTag, bool>;
 
+// Duration, as milliseconds. Overflows after 24 days.
+using DurationMs = StrongAlias<class DurationMsTag, int32_t>;
+
+// Current time, in milliseconds since a client-defined epoch.´
+using TimeMs = StrongAlias<class TimeMsTag, int64_t>;
+
 }  // namespace dcsctp
 
 #endif  // NET_DCSCTP_PUBLIC_TYPES_H_