| // Copyright 2022 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef IPCZ_SRC_IPCZ_ROUTE_EDGE_H_ |
| #define IPCZ_SRC_IPCZ_ROUTE_EDGE_H_ |
| |
| #include "ipcz/router_link.h" |
| #include "ipcz/sequence_number.h" |
| #include "ipcz/sublink_id.h" |
| #include "third_party/abseil-cpp/absl/base/macros.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "util/ref_counted.h" |
| |
| namespace ipcz { |
| |
| class NodeLink; |
| class Router; |
| class RouterLink; |
| |
| // A RouteEdge is responsible for message ingress and egress on one |
| // (inward-facing or outward-facing) side of a router. Every functioning router |
| // has one outward edge and (if proxying) one inward edge. |
| // |
| // Over the course of its lifetime a RouteEdge may utilize many different |
| // RouterLinks, but at any moment it has at most two: one "primary" link and one |
| // "decaying" link. |
| // |
| // The decaying link's usage is restricted to transmission and receipt of a |
| // limited range of parcels based on SequenceNumber, and once all expected |
| // parcels are sent and received, the link is dropped from the edge. |
| // |
| // When a RouteEdge has no decaying link, it may be able to transition its |
| // primary link to a decaying link, while adopting a new primary link to take |
| // its place. This process of incremental link replacement is the basis for ipcz |
| // route reduction. |
| // |
| // This object is not thread-safe. |
| class RouteEdge { |
| public: |
| RouteEdge(); |
| RouteEdge(const RouteEdge&) = delete; |
| RouteEdge& operator=(const RouteEdge&) = delete; |
| ~RouteEdge(); |
| |
| const Ref<RouterLink>& primary_link() const { return primary_link_; } |
| const Ref<RouterLink>& decaying_link() const { return decaying_link_; } |
| |
| // Indicates whether this edge is stable, meaning it has no decaying link and |
| // it is not set to decay the next primary link it adopts. |
| bool is_stable() const { return !decaying_link_ && !is_decay_deferred_; } |
| |
| // These accessors set the limits on the current (or deferred) decaying link. |
| // Once both of these values are set, the decaying link will be dropped from |
| // this edge as soon as the link transmits all messages up to (but not |
| // including) the SequenceNumber in `length_to_decaying_link_` AND the link |
| // receives all messages up to (but not including) the SequenceNumber in |
| // `length_from_decaying_link_`. |
| void set_length_to_decaying_link(SequenceNumber length) { |
| ABSL_ASSERT(!is_stable()); |
| ABSL_ASSERT(!length_to_decaying_link_); |
| length_to_decaying_link_ = length; |
| } |
| |
| void set_length_from_decaying_link(SequenceNumber length) { |
| ABSL_ASSERT(!is_stable()); |
| ABSL_ASSERT(!length_from_decaying_link_); |
| length_from_decaying_link_ = length; |
| } |
| |
| absl::optional<SequenceNumber> length_to_decaying_link() const { |
| return length_to_decaying_link_; |
| } |
| |
| absl::optional<SequenceNumber> length_from_decaying_link() const { |
| return length_from_decaying_link_; |
| } |
| |
| // Sets the primary link for this edge. Only valid to call if the edge does |
| // not currently have a primary link. |
| void SetPrimaryLink(Ref<RouterLink> link); |
| |
| // Releases this edge's primary link and returns a reference to it. |
| Ref<RouterLink> ReleasePrimaryLink(); |
| |
| // Releases this edge's decaying link and returns a reference to it. |
| Ref<RouterLink> ReleaseDecayingLink(); |
| |
| // Sets the current primary link to begin decay; or if there is no primary |
| // link yet, marks this edge for deferred decay. In the latter case, the next |
| // primary link adopted by this edge will immediately begin to decay. This may |
| // only be called while the edge has no decaying link. |
| bool BeginPrimaryLinkDecay(); |
| |
| // Indicates whether a parcel with the given SequenceNumber should be |
| // transmitted over this edge's decaying link. If not, the parcel should be |
| // transmitted over this edge's primary link. |
| bool ShouldTransmitOnDecayingLink(SequenceNumber sequence_number) const; |
| |
| // Attempts to drop this edge's decaying link, given that it has already |
| // transmitted a parcel sequence up to `length_sent` and received a parcel |
| // sequence up to `length_received`. Returns true if the decaying link was |
| // dropped, and false otherwise. |
| bool MaybeFinishDecay(SequenceNumber length_sent, |
| SequenceNumber length_received); |
| |
| private: |
| // The primary link over which this edge transmits and accepts parcels and |
| // other messages. If a decaying link is also present, then the decaying link |
| // is preferred for transmission of all parcels with a SequenceNumber up to |
| // (but not including) `length_to_decaying_link_`. If that value is not set, |
| // the decaying link is always preferred when set. |
| Ref<RouterLink> primary_link_; |
| |
| // If true, this edge was marked to decay its primary link before it actually |
| // acquired a primary link. In that case the next primary link adopted by |
| // this edge will be demoted immediately to a decaying link. |
| bool is_decay_deferred_ = false; |
| |
| // If non-null, this is a link which used to be the edge's primary link but |
| // which is being phased out. The decaying link may continue to receive |
| // parcels, but once `length_from_decaying_link_` is set, it will only expect |
| // to receive parcels with a SequenceNumber up to (but not including) that |
| // value. Similarly, the decaying link will be preferred for message |
| // transmission as long as `length_to_decaying_link_` remains unknown, but as |
| // soon as that value is set, only parcels with a SequenceNumber up to |
| // (but not including) that value will be transmitted over this link. Once |
| // both sequence lengths are known and surpassed, the edge will drop this |
| // link. |
| Ref<RouterLink> decaying_link_; |
| |
| // If present, the length of the parcel sequence after which this edge must |
| // stop using `decaying_link_` to transmit parcels. If this is 5, then the |
| // decaying link must be used to transmit any new parcels with a |
| // SequenceNumber in the range [0, 4] inclusive. Beyond that point the primary |
| // link must be used. |
| absl::optional<SequenceNumber> length_to_decaying_link_; |
| |
| // If present, the length of the parcel sequence after which this edge can |
| // stop expecting to receive parcels over `decaying_link_`. If this is 7, then |
| // the Router using this edge should still expect to receive parcels from the |
| // decaying link as long as it is missing any parcel in the range [0, 6] |
| // inclusive. Beyond that point parcels should only be expected from the |
| // primary link. |
| absl::optional<SequenceNumber> length_from_decaying_link_; |
| }; |
| |
| } // namespace ipcz |
| |
| #endif // IPCZ_SRC_IPCZ_ROUTE_EDGE_H_ |