summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/p2p/base/stun_dictionary.h
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/p2p/base/stun_dictionary.h')
-rw-r--r--third_party/libwebrtc/p2p/base/stun_dictionary.h204
1 files changed, 204 insertions, 0 deletions
diff --git a/third_party/libwebrtc/p2p/base/stun_dictionary.h b/third_party/libwebrtc/p2p/base/stun_dictionary.h
new file mode 100644
index 0000000000..f93a1f151f
--- /dev/null
+++ b/third_party/libwebrtc/p2p/base/stun_dictionary.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2020 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 P2P_BASE_STUN_DICTIONARY_H_
+#define P2P_BASE_STUN_DICTIONARY_H_
+
+#include <deque>
+#include <map>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "api/rtc_error.h"
+#include "api/transport/stun.h"
+
+namespace cricket {
+
+// A StunDictionaryView is a dictionary of StunAttributes.
+// - the StunAttributes can be read using the |Get|-methods.
+// - the dictionary is updated by using the |ApplyDelta|-method.
+//
+// A StunDictionaryWriter is used to create |delta|s for the |ApplyDelta|-method
+// - It keeps track of which updates has been applied at StunDictionaryView.
+// - It optionally keeps a local StunDictionaryView contains modification made
+// `locally`
+//
+// A pair StunDictionaryView(A)/StunDictionaryWriter(B) are linked so that
+// modifications to B is transfered to A using the STUN_ATTR_GOOG_DELTA
+// (StunByteStringAttribute) and the modification is ack:ed using
+// STUN_ATTR_GOOG_DELTA_ACK (StunUInt64Attribute).
+//
+// Note:
+// 1) It is possible to update one StunDictionaryView from multiple writers,
+// but this only works of the different writers write disjoint keys (which
+// is not checked/enforced by these classes).
+// 2) The opposite, one writer updating multiple StunDictionaryView, is not
+// possible.
+class StunDictionaryView {
+ public:
+ // A reserved key used to transport the version number
+ static constexpr uint16_t kVersionKey = 0xFFFF;
+
+ // A magic number used when transporting deltas.
+ static constexpr uint16_t kDeltaMagic = 0x7788;
+
+ // The version number for the delta format.
+ static constexpr uint16_t kDeltaVersion = 0x1;
+
+ // Gets the desired attribute value, or NULL if no such attribute type exists.
+ // The pointer returned is guaranteed to be valid until ApplyDelta is called.
+ const StunAddressAttribute* GetAddress(int key) const;
+ const StunUInt32Attribute* GetUInt32(int key) const;
+ const StunUInt64Attribute* GetUInt64(int key) const;
+ const StunByteStringAttribute* GetByteString(int key) const;
+ const StunUInt16ListAttribute* GetUInt16List(int key) const;
+
+ bool empty() const { return attrs_.empty(); }
+ size_t size() const { return attrs_.size(); }
+ int bytes_stored() const { return bytes_stored_; }
+ void set_max_bytes_stored(int max_bytes_stored) {
+ max_bytes_stored_ = max_bytes_stored;
+ }
+
+ // Apply a delta and return
+ // a pair with
+ // - StunUInt64Attribute to ack the |delta|.
+ // - vector of keys that was modified.
+ webrtc::RTCErrorOr<
+ std::pair<std::unique_ptr<StunUInt64Attribute>, std::vector<uint16_t>>>
+ ApplyDelta(const StunByteStringAttribute& delta);
+
+ private:
+ friend class StunDictionaryWriter;
+
+ const StunAttribute* GetOrNull(
+ int key,
+ absl::optional<StunAttributeValueType> = absl::nullopt) const;
+ size_t GetLength(int key) const;
+ static webrtc::RTCErrorOr<
+ std::pair<uint64_t, std::deque<std::unique_ptr<StunAttribute>>>>
+ ParseDelta(const StunByteStringAttribute& delta);
+
+ std::map<uint16_t, std::unique_ptr<StunAttribute>> attrs_;
+ std::map<uint16_t, uint64_t> version_per_key_;
+
+ int max_bytes_stored_ = 16384;
+ int bytes_stored_ = 0;
+};
+
+class StunDictionaryWriter {
+ public:
+ StunDictionaryWriter() {
+ dictionary_ = std::make_unique<StunDictionaryView>();
+ }
+ explicit StunDictionaryWriter(
+ std::unique_ptr<StunDictionaryView> dictionary) {
+ dictionary_ = std::move(dictionary);
+ }
+
+ // A pending modification.
+ template <typename T>
+ class Modification {
+ public:
+ ~Modification() { commit(); }
+
+ T* operator->() { return attr_.get(); }
+
+ void abort() { attr_ = nullptr; }
+ void commit() {
+ if (attr_) {
+ writer_->Set(std::move(attr_));
+ }
+ }
+
+ private:
+ friend class StunDictionaryWriter;
+ Modification(StunDictionaryWriter* writer, std::unique_ptr<T> attr)
+ : writer_(writer), attr_(std::move(attr)) {}
+ StunDictionaryWriter* writer_;
+ std::unique_ptr<T> attr_;
+
+ Modification(const Modification<T>&) =
+ delete; // not copyable (but movable).
+ Modification& operator=(Modification<T>&) =
+ delete; // not copyable (but movable).
+ };
+
+ // Record a modification.
+ Modification<StunAddressAttribute> SetAddress(int key) {
+ return Modification<StunAddressAttribute>(
+ this, StunAttribute::CreateAddress(key));
+ }
+ Modification<StunUInt32Attribute> SetUInt32(int key) {
+ return Modification<StunUInt32Attribute>(this,
+ StunAttribute::CreateUInt32(key));
+ }
+ Modification<StunUInt64Attribute> SetUInt64(int key) {
+ return Modification<StunUInt64Attribute>(this,
+ StunAttribute::CreateUInt64(key));
+ }
+ Modification<StunByteStringAttribute> SetByteString(int key) {
+ return Modification<StunByteStringAttribute>(
+ this, StunAttribute::CreateByteString(key));
+ }
+ Modification<StunUInt16ListAttribute> SetUInt16List(int key) {
+ return Modification<StunUInt16ListAttribute>(
+ this, StunAttribute::CreateUInt16ListAttribute(key));
+ }
+
+ // Delete a key.
+ void Delete(int key);
+
+ // Check if a key has a pending change (i.e a change
+ // that has not been acked).
+ bool Pending(int key) const;
+
+ // Return number of of pending modifications.
+ int Pending() const;
+
+ // Create an StunByteStringAttribute containing the pending (e.g not ack:ed)
+ // modifications.
+ std::unique_ptr<StunByteStringAttribute> CreateDelta();
+
+ // Apply an delta ack.
+ void ApplyDeltaAck(const StunUInt64Attribute&);
+
+ // Return pointer to (optional) StunDictionaryView.
+ const StunDictionaryView* dictionary() { return dictionary_.get(); }
+ const StunDictionaryView* operator->() { return dictionary_.get(); }
+
+ // Disable writer,
+ // i.e CreateDelta always return null, and no modifications are made.
+ // This is called if remote peer does not support GOOG_DELTA.
+ void Disable();
+ bool disabled() const { return disabled_; }
+
+ private:
+ void Set(std::unique_ptr<StunAttribute> attr);
+
+ bool disabled_ = false;
+
+ // version of modification.
+ int64_t version_ = 1;
+
+ // (optional) StunDictionaryView.
+ std::unique_ptr<StunDictionaryView> dictionary_;
+
+ // sorted list of changes that has not been yet been ack:ed.
+ std::vector<std::pair<uint64_t, const StunAttribute*>> pending_;
+
+ // tombstones, i.e values that has been deleted but not yet acked.
+ std::map<uint16_t, std::unique_ptr<StunAttribute>> tombstones_;
+};
+
+} // namespace cricket
+
+#endif // P2P_BASE_STUN_DICTIONARY_H_