summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/net/dcsctp/public/dcsctp_socket.h
blob: 3cfb8052f831938d1ff2f89c53793cd951fd6f4c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
/*
 *  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 "api/task_queue/task_queue_base.h"
#include "net/dcsctp/public/dcsctp_handover_state.h"
#include "net/dcsctp/public/dcsctp_message.h"
#include "net/dcsctp/public/dcsctp_options.h"
#include "net/dcsctp/public/packet_observer.h"
#include "net/dcsctp/public/timeout.h"
#include "net/dcsctp/public/types.h"

namespace dcsctp {

// The socket/association state
enum class SocketState {
  // The socket is closed.
  kClosed,
  // The socket has initiated a connection, which is not yet established. Note
  // that for incoming connections and for reconnections when the socket is
  // already connected, the socket will not transition to this state.
  kConnecting,
  // The socket is connected, and the connection is established.
  kConnected,
  // The socket is shutting down, and the connection is not yet closed.
  kShuttingDown,
};

// 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;

  // If set, will generate lifecycle events for this message. See e.g.
  // `DcSctpSocketCallbacks::OnLifecycleMessageFullySent`. This value is decided
  // by the client and the library will provide it to all lifecycle callbacks.
  LifecycleId lifecycle_id = LifecycleId::NotSet();
};

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,
  // The client has performed an invalid operation.
  kUnsupportedOperation,
};

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";
    case ErrorKind::kUnsupportedOperation:
      return "UNSUPPORTED_OPERATION";
  }
}

enum class SendStatus {
  // The message was enqueued successfully. As sending the message is done
  // asynchronously, this is no guarantee that the message has been actually
  // sent.
  kSuccess,
  // The message was rejected as the payload was empty (which is not allowed in
  // SCTP).
  kErrorMessageEmpty,
  // The message was rejected as the payload was larger than what has been set
  // as `DcSctpOptions.max_message_size`.
  kErrorMessageTooLarge,
  // The message could not be enqueued as the socket is out of resources. This
  // mainly indicates that the send queue is full.
  kErrorResourceExhaustion,
  // The message could not be sent as the socket is shutting down.
  kErrorShuttingDown,
};

inline constexpr absl::string_view ToString(SendStatus error) {
  switch (error) {
    case SendStatus::kSuccess:
      return "SUCCESS";
    case SendStatus::kErrorMessageEmpty:
      return "ERROR_MESSAGE_EMPTY";
    case SendStatus::kErrorMessageTooLarge:
      return "ERROR_MESSAGE_TOO_LARGE";
    case SendStatus::kErrorResourceExhaustion:
      return "ERROR_RESOURCE_EXHAUSTION";
    case SendStatus::kErrorShuttingDown:
      return "ERROR_SHUTTING_DOWN";
  }
}

// Return value of ResetStreams.
enum class ResetStreamsStatus {
  // If the connection is not yet established, this will be returned.
  kNotConnected,
  // Indicates that ResetStreams operation has been successfully initiated.
  kPerformed,
  // Indicates that ResetStreams has failed as it's not supported by the peer.
  kNotSupported,
};

inline constexpr absl::string_view ToString(ResetStreamsStatus error) {
  switch (error) {
    case ResetStreamsStatus::kNotConnected:
      return "NOT_CONNECTED";
    case ResetStreamsStatus::kPerformed:
      return "PERFORMED";
    case ResetStreamsStatus::kNotSupported:
      return "NOT_SUPPORTED";
  }
}

// Return value of DcSctpSocketCallbacks::SendPacketWithStatus.
enum class SendPacketStatus {
  // Indicates that the packet was successfully sent. As sending is unreliable,
  // there are no guarantees that the packet was actually delivered.
  kSuccess,
  // The packet was not sent due to a temporary failure, such as the local send
  // buffer becoming exhausted. This return value indicates that the socket will
  // recover and sending that packet can be retried at a later time.
  kTemporaryFailure,
  // The packet was not sent due to other reasons.
  kError,
};

// Represent known SCTP implementations.
enum class SctpImplementation {
  // There is not enough information toto determine any SCTP implementation.
  kUnknown,
  // This implementation.
  kDcsctp,
  // https://github.com/sctplab/usrsctp.
  kUsrSctp,
  // Any other implementation.
  kOther,
};

inline constexpr absl::string_view ToString(SctpImplementation implementation) {
  switch (implementation) {
    case SctpImplementation::kUnknown:
      return "unknown";
    case SctpImplementation::kDcsctp:
      return "dcsctp";
    case SctpImplementation::kUsrSctp:
      return "usrsctp";
    case SctpImplementation::kOther:
      return "other";
  }
}

// Tracked metrics, which is the return value of GetMetrics. Optional members
// will be unset when they are not yet known.
struct Metrics {
  // Transmission stats and metrics.

  // Number of packets sent.
  size_t tx_packets_count = 0;

  // Number of messages requested to be sent.
  size_t tx_messages_count = 0;

  // Number of packets retransmitted. Since SCTP packets can contain both
  // retransmitted DATA chunks and DATA chunks that are transmitted for the
  // first time, this represents an upper bound as it's incremented every time a
  // packet contains a retransmitted DATA chunk.
  size_t rtx_packets_count = 0;

  // Total number of bytes retransmitted. This includes the payload and
  // DATA/I-DATA headers, but not SCTP packet headers.
  uint64_t rtx_bytes_count = 0;

  // The current congestion window (cwnd) in bytes, corresponding to spinfo_cwnd
  // defined in RFC6458.
  size_t cwnd_bytes = 0;

  // Smoothed round trip time, corresponding to spinfo_srtt defined in RFC6458.
  int srtt_ms = 0;

  // Number of data items in the retransmission queue that haven’t been
  // acked/nacked yet and are in-flight. Corresponding to sstat_unackdata
  // defined in RFC6458. This may be an approximation when there are messages in
  // the send queue that haven't been fragmented/packetized yet.
  size_t unack_data_count = 0;

  // Receive stats and metrics.

  // Number of packets received.
  size_t rx_packets_count = 0;

  // Number of messages received.
  size_t rx_messages_count = 0;

  // The peer’s last announced receiver window size, corresponding to
  // sstat_rwnd defined in RFC6458.
  uint32_t peer_rwnd_bytes = 0;

  // Returns the detected SCTP implementation of the peer. As this is not
  // explicitly signalled during the connection establishment, heuristics is
  // used to analyze e.g. the state cookie in the INIT-ACK chunk.
  SctpImplementation peer_implementation = SctpImplementation::kUnknown;

  // Indicates if RFC8260 User Message Interleaving has been negotiated by both
  // peers.
  bool uses_message_interleaving = false;

  // Indicates if draft-tuexen-tsvwg-sctp-zero-checksum-00 has been negotiated
  // by both peers.
  bool uses_zero_checksum = false;

  // The number of negotiated incoming and outgoing streams, which is configured
  // locally as `DcSctpOptions::announced_maximum_incoming_streams` and
  // `DcSctpOptions::announced_maximum_outgoing_streams`, and which will be
  // signaled by the peer during connection.
  uint16_t negotiated_maximum_incoming_streams = 0;
  uint16_t negotiated_maximum_outgoing_streams = 0;
};

// Callbacks that the DcSctpSocket will call 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.
  //
  // TODO(bugs.webrtc.org/12943): This method is deprecated, see
  // `SendPacketWithStatus`.
  //
  // Note that it's NOT ALLOWED to call into this library from within this
  // callback.
  virtual void SendPacket(rtc::ArrayView<const uint8_t> data) {}

  // 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 SendPacketStatus SendPacketWithStatus(
      rtc::ArrayView<const uint8_t> data) {
    SendPacket(data);
    return SendPacketStatus::kSuccess;
  }

  // Called when the library wants to create a Timeout. The callback must return
  // an object that implements that interface.
  //
  // Low precision tasks are scheduled more efficiently by using leeway to
  // reduce Idle Wake Ups and is the preferred precision whenever possible. High
  // precision timeouts do not have this leeway, but is still limited by OS
  // timer precision. At the time of writing, kLow's additional leeway may be up
  // to 17 ms, but please see webrtc::TaskQueueBase::DelayPrecision for
  // up-to-date information.
  //
  // Note that it's NOT ALLOWED to call into this library from within this
  // callback.
  virtual std::unique_ptr<Timeout> CreateTimeout(
      webrtc::TaskQueueBase::DelayPrecision precision) {
    // TODO(hbos): When dependencies have migrated to this new signature, make
    // this pure virtual and delete the other version.
    return CreateTimeout();
  }
  // TODO(hbos): When dependencies have migrated to the other signature, delete
  // this version.
  virtual std::unique_ptr<Timeout> CreateTimeout() {
    return CreateTimeout(webrtc::TaskQueueBase::DelayPrecision::kLow);
  }

  // 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 numbers used by the
  // library are not used for cryptographic purposes. There are no requirements
  // that the random number generator must be secure.
  //
  // 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).
  //
  // Note that it's NOT ALLOWED to call into this library from within this
  // callback.
  ABSL_DEPRECATED("Use OnTotalBufferedAmountLow instead")
  virtual void NotifyOutgoingMessageBufferEmpty() {}

  // 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;

  // Will be called when the amount of data buffered to be sent falls to or
  // below the threshold set when calling `SetBufferedAmountLowThreshold`.
  //
  // It is allowed to call into this library from within this callback.
  virtual void OnBufferedAmountLow(StreamID stream_id) {}

  // Will be called when the total amount of data buffered (in the entire send
  // buffer, for all streams) falls to or below the threshold specified in
  // `DcSctpOptions::total_buffered_amount_low_threshold`.
  virtual void OnTotalBufferedAmountLow() {}

  // == Lifecycle Events ==
  //
  // If a `lifecycle_id` is provided as `SendOptions`, lifecycle callbacks will
  // be triggered as the message is processed by the library.
  //
  // The possible transitions are shown in the graph below:
  //
  //        DcSctpSocket::Send  ────────────────────────┐
  //                │                                   │
  //                │                                   │
  //                v                                   v
  //    OnLifecycleMessageFullySent ───────> OnLifecycleMessageExpired
  //                │                                   │
  //                │                                   │
  //                v                                   v
  //    OnLifeCycleMessageDelivered ────────────> OnLifecycleEnd

  // OnLifecycleMessageFullySent will be called when a message has been fully
  // sent, meaning that the last fragment has been produced from the send queue
  // and sent on the network. Note that this will trigger at most once per
  // message even if the message was retransmitted due to packet loss.
  //
  // This is a lifecycle event.
  //
  // Note that it's NOT ALLOWED to call into this library from within this
  // callback.
  virtual void OnLifecycleMessageFullySent(LifecycleId lifecycle_id) {}

  // OnLifecycleMessageExpired will be called when a message has expired. If it
  // was expired with data remaining in the send queue that had not been sent
  // ever, `maybe_delivered` will be set to false. If `maybe_delivered` is true,
  // the message has at least once been sent and may have been correctly
  // received by the peer, but it has expired before the receiver managed to
  // acknowledge it. This means that if `maybe_delivered` is true, it's unknown
  // if the message was lost or was delivered, and if `maybe_delivered` is
  // false, it's guaranteed to not be delivered.
  //
  // It's guaranteed that `OnLifecycleMessageDelivered` is not called if this
  // callback has triggered.
  //
  // This is a lifecycle event.
  //
  // Note that it's NOT ALLOWED to call into this library from within this
  // callback.
  virtual void OnLifecycleMessageExpired(LifecycleId lifecycle_id,
                                         bool maybe_delivered) {}

  // OnLifecycleMessageDelivered will be called when a non-expired message has
  // been acknowledged by the peer as delivered.
  //
  // Note that this will trigger only when the peer moves its cumulative TSN ack
  // beyond this message, and will not fire for messages acked using
  // gap-ack-blocks as those are renegable. This means that this may fire a bit
  // later than the message was actually first "acked" by the peer, as -
  // according to the protocol - those acks may be unacked later by the client.
  //
  // It's guaranteed that `OnLifecycleMessageExpired` is not called if this
  // callback has triggered.
  //
  // This is a lifecycle event.
  //
  // Note that it's NOT ALLOWED to call into this library from within this
  // callback.
  virtual void OnLifecycleMessageDelivered(LifecycleId lifecycle_id) {}

  // OnLifecycleEnd will be called when a lifecycle event has reached its end.
  // It will be called when processing of a message is complete, no matter how
  // it completed. It will be called after all other lifecycle events, if any.
  //
  // Note that it's possible that this callback triggers without any other
  // lifecycle callbacks having been called before in case of errors, such as
  // attempting to send an empty message or failing to enqueue a message if the
  // send queue is full.
  //
  // NOTE: When the socket is deallocated, there will be no `OnLifecycleEnd`
  // callbacks sent for messages that were enqueued. But as long as the socket
  // is alive, `OnLifecycleEnd` callbacks are guaranteed to be sent as messages
  // are either expired or successfully acknowledged.
  //
  // This is a lifecycle event.
  //
  // Note that it's NOT ALLOWED to call into this library from within this
  // callback.
  virtual void OnLifecycleEnd(LifecycleId lifecycle_id) {}
};

// The DcSctpSocket implementation implements the following interface.
// This class is thread-compatible.
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;

  // Puts this socket to the state in which the original socket was when its
  // `DcSctpSocketHandoverState` was captured by `GetHandoverStateAndClose`.
  // `RestoreFromState` is allowed only on the closed socket.
  // `DcSctpSocketCallbacks::OnConnected` will be called if a connected socket
  // state is restored.
  // `DcSctpSocketCallbacks::OnError` will be called on error.
  virtual void RestoreFromState(const DcSctpSocketHandoverState& state) = 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;

  // The socket state.
  virtual SocketState state() const = 0;

  // The options it was created with.
  virtual const DcSctpOptions& options() const = 0;

  // Update the options max_message_size.
  virtual void SetMaxMessageSize(size_t max_message_size) = 0;

  // Sets the priority of an outgoing stream. The initial value, when not set,
  // is `DcSctpOptions::default_stream_priority`.
  virtual void SetStreamPriority(StreamID stream_id,
                                 StreamPriority priority) = 0;

  // Returns the currently set priority for an outgoing stream. The initial
  // value, when not set, is `DcSctpOptions::default_stream_priority`.
  virtual StreamPriority GetStreamPriority(StreamID stream_id) const = 0;

  // Sends the message `message` using the provided send options.
  // Sending a message is an asynchronous 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.
  virtual SendStatus Send(DcSctpMessage message,
                          const SendOptions& send_options) = 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 ResetStreamsStatus ResetStreams(
      rtc::ArrayView<const StreamID> outgoing_streams) = 0;

  // Returns the number of bytes of data currently queued to be sent on a given
  // stream.
  virtual size_t buffered_amount(StreamID stream_id) const = 0;

  // Returns the number of buffered outgoing bytes that is considered "low" for
  // a given stream. See `SetBufferedAmountLowThreshold`.
  virtual size_t buffered_amount_low_threshold(StreamID stream_id) const = 0;

  // Used to specify the number of bytes of buffered outgoing data that is
  // considered "low" for a given stream, which will trigger an
  // OnBufferedAmountLow event. The default value is zero (0).
  virtual void SetBufferedAmountLowThreshold(StreamID stream_id,
                                             size_t bytes) = 0;

  // Retrieves the latest metrics. If the socket is not fully connected,
  // `absl::nullopt` will be returned. Note that metrics are not guaranteed to
  // be carried over if this socket is handed over by calling
  // `GetHandoverStateAndClose`.
  virtual absl::optional<Metrics> GetMetrics() const = 0;

  // Returns empty bitmask if the socket is in the state in which a snapshot of
  // the state can be made by `GetHandoverStateAndClose()`. Return value is
  // invalidated by a call to any non-const method.
  virtual HandoverReadinessStatus GetHandoverReadiness() const = 0;

  // Collects a snapshot of the socket state that can be used to reconstruct
  // this socket in another process. On success this socket object is closed
  // synchronously and no callbacks will be made after the method has returned.
  // The method fails if the socket is not in a state ready for handover.
  // nullopt indicates the failure. `DcSctpSocketCallbacks::OnClosed` will be
  // called on success.
  virtual absl::optional<DcSctpSocketHandoverState>
  GetHandoverStateAndClose() = 0;

  // Returns the detected SCTP implementation of the peer. As this is not
  // explicitly signalled during the connection establishment, heuristics is
  // used to analyze e.g. the state cookie in the INIT-ACK chunk.
  //
  // If this method is called too early (before
  // `DcSctpSocketCallbacks::OnConnected` has triggered), this will likely
  // return `SctpImplementation::kUnknown`.
  ABSL_DEPRECATED("See Metrics::peer_implementation instead")
  virtual SctpImplementation peer_implementation() const {
    return SctpImplementation::kUnknown;
  }
};
}  // namespace dcsctp

#endif  // NET_DCSCTP_PUBLIC_DCSCTP_SOCKET_H_