8000 ICE pair and ICE checklists by poroh · Pull Request #4 · poroh/freewebrtc · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

ICE pair and ICE checklists #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ stack exist in this world but this implementation is different:
- If you want secure random for STUN transaction identifiers you can replace it
- etc.
- Code highly relies on strong typing
- Thorough unit testing (175 tests and counting)
- Thorough unit testing (177 tests and counting)
- No quirky practicies with raw pointers and type casts.
- Test coverage
- Address sanitizer
Expand Down
2 changes: 2 additions & 0 deletions src/ice/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#

add_subdirectory(candidate)
add_subdirectory(pair)
add_subdirectory(checklist)

set(SOURCES
)
Expand Down
9 changes: 9 additions & 0 deletions src/ice/candidate/ice_candidate_component_id.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,12 @@ inline unsigned ComponentId::value() const noexcept {
}

}

namespace std {
template<>
struct hash<freewebrtc::ice::candidate::ComponentId> {
size_t operator()(const freewebrtc::ice::candidate::ComponentId& id) const {
return hash<unsigned>()(id.value());
}
};
}
6 changes: 6 additions & 0 deletions src/ice/candidate/ice_candidate_priority.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class Priority {

bool operator==(const Priority&) const noexcept = default;

uint32_t value() const noexcept;

private:
explicit Priority(uint32_t);
uint32_t m_value;
Expand All @@ -39,4 +41,8 @@ inline Priority::Priority(uint32_t v)
: m_value(v)
{}

inline uint32_t Priority::value() const noexcept {
return m_value;
}

}
17 changes: 17 additions & 0 deletions src/ice/checklist/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#
# Copyright (c) 2023 Dmitry Poroh
# All rights reserved.
# Distributed under the terms of the MIT License. See the LICENSE file.
#

set(SOURCES
ice_checklist.cpp
)
file(GLOB HEADERS "*.hpp")

list(TRANSFORM SOURCES PREPEND ${CMAKE_CURRENT_SOURCE_DIR}/)

target_sources(freewebrtc PRIVATE ${SOURCES} ${HEADERS})

install(FILES ${HEADERS} DESTINATION include/freewebrtc/ice/checklist)

25 changes: 25 additions & 0 deletions src/ice/checklist/ice_checklist.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// Copyright (c) 2023 Dmitry Poroh
// All rights reserved.
// Distributed under the terms of the MIT License. See the LICENSE file.
//
// ICE checklist
//

#include <algorithm>

#include "ice/checklist/ice_checklist.hpp"

namespace freewebrtc::ice::checklist {

void Checklist::add_local(Candidate&& c) {
auto [it, _] = m_local.emplace(c.component, CandidateVec());
it->second.emplace_back(std::move(c));
}

void Checklist::add_remote(Candidate&& c) {
auto [it, _] = m_remote.emplace(c.component, CandidateVec());
it->second.emplace_back(std::move(c));
}

}
33 changes: 33 additions & 0 deletions src/ice/checklist/ice_checklist.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// Copyright (c) 2023 Dmitry Poroh
// All rights reserved.
// Distributed under the terms of the MIT License. See the LICENSE file.
//
// ICE checklist
//

#pragma once

#include "ice/pair/ice_pair.hpp"

#include <vector>

namespace freewebrtc::ice::checklist {

class Checklist {
public:
using Candidate = ice::candidate::Candidate;
void add_local(Candidate&&);
void add_remote(Candidate&&);

private:
using Pair = ice::pair::Pair;
using ComponentId = ice::candidate::ComponentId;
using CandidateVec = std::vector<ice::candidate::Candidate>;
using PairVec = std::vector<ice::pair::Pair>;
std::unordered_map<ComponentId, CandidateVec> m_local;
std::unordered_map<ComponentId, CandidateVec> m_remote;
std::unordered_map<ComponentId, PairVec> m_pairs;
};

}
19 changes: 19 additions & 0 deletions src/ice/pair/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#
# Copyright (c) 2023 Dmitry Poroh
# All rights reserved.
# Distributed under the terms of the MIT License. See the LICENSE file.
#

set(SOURCES
ice_pair.cpp
ice_pair_state.cpp
ice_pair_error.cpp
)
file(GLOB HEADERS "*.hpp")

list(TRANSFORM SOURCES PREPEND ${CMAKE_CURRENT_SOURCE_DIR}/)

target_sources(freewebrtc PRIVATE ${SOURCES} ${HEADERS})

install(FILES ${HEADERS} DESTINATION include/freewebrtc/ice/pair)

31 changes: 31 additions & 0 deletions src/ice/pair/ice_pair.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// Copyright (c) 2024 Dmitry Poroh
// All rights reserved.
// Distributed under the terms of the MIT License. See the LICENSE file.
//
// Interactive Connectivity Establishment (ICE)
// ICE Candidate Pair (RFC8445)
//

#include "ice/pair/ice_pair.hpp"

namespace freewebrtc::ice::pair {

// Let G be the priority for the candidate provided by the controlling agent.
// Let D be the priority for the candidate provided by the controlled agent.
Priority calc_priority(candidate::Priority g, candidate::Priority d) {
uint64_t G = g.value();
uint64_t D = d.value();
// pair priority = 2^32*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0)
return Priority{(G << 32) * std::min(G, D) + 2 * std::max(G, D) + (G > D ? 1 : 0)};
}

Priority Pair::controlling_agent() const noexcept {
return calc_priority(local.priority, remote.priority);
}

Priority Pair::controlled_agent() const noexcept {
return calc_priority(remote.priority, local.priority);
}

}
32 changes: 32 additions & 0 deletions src/ice/pair/ice_pair.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// Copyright (c) 2024 Dmitry Poroh
// All rights reserved.
// Distributed under the terms of the MIT License. See the LICENSE file.
//
// Interactive Connectivity Establishment (ICE)
// ICE Candidate Pair (RFC8445)
//

#pragma once

#include "ice/candidate/ice_candidate.hpp"
#include "ice/pair/ice_pair_state.hpp"
#include "util/util_tagged_type.hpp"

namespace freewebrtc::ice::pair {

struct PriorityTag{};
using Priority = util::TaggedType<uint64_t, PriorityTag>;

struct Pair {
candidate::Candidate local;
candidate::Candidate remote;
State state;

// Priority of the pair if this agengent is controlling agent.
Priority controlling_agent() const noexcept;
// Priority of the pair if this agengent is controlled agent.
Priority controlled_agent() const noexcept;
};

}
40 changes: 40 additions & 0 deletions src/ice/pair/ice_pair_error.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// Copyright (c) 2023 Dmitry Poroh
// All rights reserved.
// Distributed under the terms of the MIT License. See the LICENSE file.
//
// ICE candidate library error codes
//

#include "ice/pair/ice_pair_error.hpp"

namespace freewebrtc::ice::pair {

namespace {

class IceCandidateError : public std::error_category {
public:
const char *name() const noexcept override;
std::string message(int code) const override;
};

}

const std::error_category& ice_error_category() noexcept {
static const IceCandidateError cat;
return cat;
}

const char *IceCandidateError::name() const noexcept {
return "ice pair error";
}

std::string IceCandidateError::message(int code) const {
switch ((Error)code) {
case Error::ok: return "Success";
case Error::ice_pair_state_unexpected_event: return "Unexpected event for pair FSM";
}
return "Unknown ice pair error: " + std::to_string(code);
}

}
31 changes: 31 additions & 0 deletions src/ice/pair/ice_pair_error.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// Copyright (c) 2023 Dmitry Poroh
// All rights reserved.
// Distributed under the terms of the MIT License. See the LICENSE file.
//
// ICE library error codes
//

#pragma once

#include <system_error>

namespace freewebrtc::ice::pair {

enum class Error {
ok = 0,
ice_pair_state_unexpected_event,
};

std::error_code make_error_code(Error) noexcept;

const std::error_category& ice_error_category() noexcept;

//
// inline
//
inline std::error_code make_error_code(Error ec) noexcept {
return std::error_code((int)ec, ice_error_category());
}

}
110 changes: 110 additions & 0 deletions src/ice/pair/ice_pair_state.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//
// Copyright (c) 2024 Dmitry Poroh
// All rights reserved.
// Distributed under the terms of the MIT License. See the LICENSE file.
//
// Interactive Connectivity Establishment (ICE)
// ICE Candidate Pair State (RFC8445)
//

#include "ice/pair/ice_pair_state.hpp"
#include "ice/pair/ice_pair_error.hpp"

namespace freewebrtc::ice::pair {

Event::Event(Value v)
: m_value(v)
{}

Event Event::unfreeze() noexcept {
return Event{Value::unfreeze};
}

Event Event::perform() noexcept {
return Event{Value::perform};
}

Event Event::failure() noexcept {
return Event{Value::failure};
}

Event Event::success() noexcept {
return Event{Value::success};
}

std::string Event::to_string() const {
switch (m_value) {
case Value::unfreeze: return "unfreeze";
case Value::perform: return "perform";
case Value::failure: return "failure";
case Value::success: return "success";
}
return "unknown";
}

State::State(Value v)
: m_value(v)
{}

State State::waiting() noexcept {
return State(Value::waiting);
}

State State::in_progress() noexcept {
return State(Value::in_progress);
}

State State::succeeded() noexcept {
return State(Value::succeeded);
}

State State::failed() noexcept {
return State(Value::failed);
}

State State::frozen() noexcept {
return State(Value::frozen);
}


std::string State::to_string() const {
switch (m_value) {
case Value::frozen: return "Frozen";
case Value::waiting: return "Waiting";
case Value::in_progress: return "In-Progress";
case Value::succeeded: return "Succeeded";
case Value::failed: return "Failed";
}
return "unknown";
}

Result<State> State::transition(Event ev) const noexcept {
// RFC8445:
// 6.1.2.6. Computing Candidate Pair States
switch (m_value) {
case Value::frozen:
if (ev == Event::unfreeze()) {
return State(Value::waiting);
}
break;
case Value::waiting:
if (ev == Event::perform()) {
return State(Value::in_progress);
}
break;
case Value::in_progress:
if (ev == Event::success()) {
return State(Value::succeeded);
} else if (ev == Event::failure()) {
return State(Value::failed);
}
break;
case Value::succeeded:
case Value::failed:
break;
}
return Result<State>(make_error_code(Error::ice_pair_state_unexpected_event))
.add_context("state: " + to_string() + "; event: " + ev.to_string());
}

}
Loading
0