mirror of
https://github.com/kunkundi/crossdesk.git
synced 2025-10-26 20:25:34 +08:00
229 lines
9.9 KiB
C
229 lines
9.9 KiB
C
/**
|
|
* Copyright (c) 2020 Paul-Louis Ageneau
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#ifndef JUICE_AGENT_H
|
|
#define JUICE_AGENT_H
|
|
|
|
#include "addr.h"
|
|
#include "conn.h"
|
|
#include "ice.h"
|
|
#include "juice.h"
|
|
#include "stun.h"
|
|
#include "thread.h"
|
|
#include "timestamp.h"
|
|
#include "turn.h"
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
|
|
// RFC 8445: Agents MUST NOT use an RTO value smaller than 500 ms.
|
|
#define MIN_STUN_RETRANSMISSION_TIMEOUT 500 // msecs
|
|
#define MAX_STUN_RETRANSMISSION_COUNT 5 // count (exponential backoff, will give ~30s)
|
|
// #define MAX_STUN_RETRANSMISSION_COUNT 2 // count (exponential backoff, will give ~30s)
|
|
|
|
// RFC 8445: ICE agents SHOULD use a default Ta value, 50 ms, but MAY use
|
|
// another value based on the characteristics of the associated data.
|
|
#define STUN_PACING_TIME 50 // msecs
|
|
|
|
// RFC 8445: Agents SHOULD use a Tr value of 15 seconds. Agents MAY use a bigger value but MUST NOT
|
|
// use a value smaller than 15 seconds.
|
|
#define STUN_KEEPALIVE_PERIOD 15000 // msecs
|
|
|
|
// Consent freshness
|
|
// RFC 7675: Consent expires after 30 seconds.
|
|
#define CONSENT_TIMEOUT 30000 // msecs
|
|
|
|
// RFC 7675: To prevent synchronization of consent checks, each interval MUST be randomized from
|
|
// between 0.8 and 1.2 times the basic period. Implementations SHOULD set a default interval of 5
|
|
// seconds, resulting in a period between checks of 4 to 6 seconds. Implementations MUST NOT set the
|
|
// period between checks to less than 4 seconds.
|
|
#define MIN_CONSENT_CHECK_PERIOD 4000 // msecs
|
|
#define MAX_CONSENT_CHECK_PERIOD 6000 // msecs
|
|
|
|
// TURN refresh period
|
|
#define TURN_LIFETIME 600000 // msecs, 10 min
|
|
#define TURN_REFRESH_PERIOD (TURN_LIFETIME - 60000) // msecs, lifetime - 1 min
|
|
|
|
// ICE trickling timeout
|
|
#define ICE_FAIL_TIMEOUT 30000 // msecs
|
|
|
|
// Max STUN and TURN server entries
|
|
#define MAX_SERVER_ENTRIES_COUNT 2 // max STUN server entries
|
|
#define MAX_RELAY_ENTRIES_COUNT 2 // max TURN server entries
|
|
|
|
// Max TURN redirections for ALTERNATE-SERVER mechanism
|
|
#define MAX_TURN_REDIRECTIONS 1
|
|
|
|
// Compute max candidates and entries count
|
|
#define MAX_STUN_SERVER_RECORDS_COUNT MAX_SERVER_ENTRIES_COUNT
|
|
#define MAX_HOST_CANDIDATES_COUNT ((ICE_MAX_CANDIDATES_COUNT - MAX_STUN_SERVER_RECORDS_COUNT) / 2)
|
|
#define MAX_PEER_REFLEXIVE_CANDIDATES_COUNT MAX_HOST_CANDIDATES_COUNT
|
|
#define MAX_CANDIDATE_PAIRS_COUNT (ICE_MAX_CANDIDATES_COUNT * (1 + MAX_RELAY_ENTRIES_COUNT))
|
|
#define MAX_STUN_ENTRIES_COUNT (MAX_CANDIDATE_PAIRS_COUNT + MAX_STUN_SERVER_RECORDS_COUNT)
|
|
|
|
#define AGENT_TURN_MAP_SIZE ICE_MAX_CANDIDATES_COUNT
|
|
|
|
typedef enum agent_mode {
|
|
AGENT_MODE_UNKNOWN,
|
|
AGENT_MODE_CONTROLLED,
|
|
AGENT_MODE_CONTROLLING
|
|
} agent_mode_t;
|
|
|
|
typedef enum agent_stun_entry_type {
|
|
AGENT_STUN_ENTRY_TYPE_EMPTY,
|
|
AGENT_STUN_ENTRY_TYPE_SERVER,
|
|
AGENT_STUN_ENTRY_TYPE_RELAY,
|
|
AGENT_STUN_ENTRY_TYPE_CHECK
|
|
} agent_stun_entry_type_t;
|
|
|
|
typedef enum agent_stun_entry_state {
|
|
AGENT_STUN_ENTRY_STATE_PENDING,
|
|
AGENT_STUN_ENTRY_STATE_CANCELLED,
|
|
AGENT_STUN_ENTRY_STATE_FAILED,
|
|
AGENT_STUN_ENTRY_STATE_SUCCEEDED,
|
|
AGENT_STUN_ENTRY_STATE_SUCCEEDED_KEEPALIVE,
|
|
AGENT_STUN_ENTRY_STATE_IDLE
|
|
} agent_stun_entry_state_t;
|
|
|
|
typedef struct agent_turn_state {
|
|
turn_map_t map;
|
|
stun_credentials_t credentials;
|
|
const char *password;
|
|
} agent_turn_state_t;
|
|
|
|
typedef struct agent_stun_entry {
|
|
agent_stun_entry_type_t type;
|
|
agent_stun_entry_state_t state;
|
|
agent_mode_t mode;
|
|
ice_candidate_pair_t *pair;
|
|
addr_record_t record;
|
|
addr_record_t relayed;
|
|
uint8_t transaction_id[STUN_TRANSACTION_ID_SIZE];
|
|
timestamp_t next_transmission;
|
|
timediff_t retransmission_timeout;
|
|
int retransmissions;
|
|
|
|
// TURN
|
|
agent_turn_state_t *turn;
|
|
unsigned int turn_redirections;
|
|
struct agent_stun_entry *relay_entry;
|
|
|
|
} agent_stun_entry_t;
|
|
|
|
struct juice_agent {
|
|
juice_config_t config;
|
|
juice_state_t state;
|
|
agent_mode_t mode;
|
|
|
|
ice_description_t local;
|
|
ice_description_t remote;
|
|
|
|
ice_candidate_pair_t candidate_pairs[MAX_CANDIDATE_PAIRS_COUNT];
|
|
ice_candidate_pair_t *ordered_pairs[MAX_CANDIDATE_PAIRS_COUNT];
|
|
ice_candidate_pair_t *selected_pair;
|
|
int candidate_pairs_count;
|
|
|
|
agent_stun_entry_t entries[MAX_STUN_ENTRIES_COUNT];
|
|
int entries_count;
|
|
atomic_ptr(agent_stun_entry_t) selected_entry;
|
|
|
|
uint64_t ice_tiebreaker;
|
|
timestamp_t fail_timestamp;
|
|
bool gathering_done;
|
|
|
|
int conn_index;
|
|
void *conn_impl;
|
|
|
|
thread_t resolver_thread;
|
|
bool resolver_thread_started;
|
|
};
|
|
|
|
juice_agent_t *agent_create(const juice_config_t *config);
|
|
void agent_destroy(juice_agent_t *agent);
|
|
|
|
int agent_gather_candidates(juice_agent_t *agent);
|
|
int agent_resolve_servers(juice_agent_t *agent);
|
|
int agent_get_local_description(juice_agent_t *agent, char *buffer, size_t size);
|
|
int agent_set_remote_description(juice_agent_t *agent, const char *sdp);
|
|
int agent_add_remote_candidate(juice_agent_t *agent, const char *sdp);
|
|
int agent_set_remote_gathering_done(juice_agent_t *agent);
|
|
int agent_send(juice_agent_t *agent, const char *data, size_t size, int ds);
|
|
int agent_direct_send(juice_agent_t *agent, const addr_record_t *dst, const char *data, size_t size,
|
|
int ds);
|
|
int agent_relay_send(juice_agent_t *agent, agent_stun_entry_t *entry, const addr_record_t *dst,
|
|
const char *data, size_t size, int ds);
|
|
int agent_channel_send(juice_agent_t *agent, agent_stun_entry_t *entry, const addr_record_t *dst,
|
|
const char *data, size_t size, int ds);
|
|
juice_state_t agent_get_state(juice_agent_t *agent);
|
|
int agent_get_selected_candidate_pair(juice_agent_t *agent, ice_candidate_t *local,
|
|
ice_candidate_t *remote);
|
|
|
|
int agent_conn_recv(juice_agent_t *agent, char *buf, size_t len, const addr_record_t *src);
|
|
int agent_conn_update(juice_agent_t *agent, timestamp_t *next_timestamp);
|
|
int agent_conn_fail(juice_agent_t *agent);
|
|
|
|
int agent_input(juice_agent_t *agent, char *buf, size_t len, const addr_record_t *src,
|
|
const addr_record_t *relayed); // relayed may be NULL
|
|
int agent_bookkeeping(juice_agent_t *agent, timestamp_t *next_timestamp);
|
|
void agent_change_state(juice_agent_t *agent, juice_state_t state);
|
|
int agent_verify_stun_binding(juice_agent_t *agent, void *buf, size_t size,
|
|
const stun_message_t *msg);
|
|
int agent_verify_credentials(juice_agent_t *agent, const agent_stun_entry_t *entry, void *buf,
|
|
size_t size, stun_message_t *msg);
|
|
int agent_dispatch_stun(juice_agent_t *agent, void *buf, size_t size, stun_message_t *msg,
|
|
const addr_record_t *src,
|
|
const addr_record_t *relayed); // relayed may be NULL
|
|
int agent_process_stun_binding(juice_agent_t *agent, const stun_message_t *msg,
|
|
agent_stun_entry_t *entry, const addr_record_t *src,
|
|
const addr_record_t *relayed); // relayed may be NULL
|
|
int agent_send_stun_binding(juice_agent_t *agent, agent_stun_entry_t *entry, stun_class_t msg_class,
|
|
unsigned int error_code, const uint8_t *transaction_id,
|
|
const addr_record_t *mapped);
|
|
int agent_process_turn_allocate(juice_agent_t *agent, const stun_message_t *msg,
|
|
agent_stun_entry_t *entry);
|
|
int agent_send_turn_allocate_request(juice_agent_t *agent, const agent_stun_entry_t *entry,
|
|
stun_method_t method);
|
|
int agent_process_turn_create_permission(juice_agent_t *agent, const stun_message_t *msg,
|
|
agent_stun_entry_t *entry);
|
|
int agent_send_turn_create_permission_request(juice_agent_t *agent, agent_stun_entry_t *entry,
|
|
const addr_record_t *record, int ds);
|
|
int agent_process_turn_channel_bind(juice_agent_t *agent, const stun_message_t *msg,
|
|
agent_stun_entry_t *entry);
|
|
int agent_send_turn_channel_bind_request(juice_agent_t *agent, agent_stun_entry_t *entry,
|
|
const addr_record_t *record, int ds,
|
|
uint16_t *out_channel); // out_channel may be NULL
|
|
int agent_process_turn_data(juice_agent_t *agent, const stun_message_t *msg,
|
|
agent_stun_entry_t *entry);
|
|
int agent_process_channel_data(juice_agent_t *agent, agent_stun_entry_t *entry, char *buf,
|
|
size_t len);
|
|
|
|
int agent_add_local_relayed_candidate(juice_agent_t *agent, const addr_record_t *record);
|
|
int agent_add_local_reflexive_candidate(juice_agent_t *agent, ice_candidate_type_t type,
|
|
const addr_record_t *record);
|
|
int agent_add_remote_reflexive_candidate(juice_agent_t *agent, ice_candidate_type_t type,
|
|
uint32_t priority, const addr_record_t *record);
|
|
int agent_add_candidate_pair(juice_agent_t *agent, ice_candidate_t *local,
|
|
ice_candidate_t *remote); // local may be NULL
|
|
int agent_add_candidate_pairs_for_remote(juice_agent_t *agent, ice_candidate_t *remote);
|
|
int agent_unfreeze_candidate_pair(juice_agent_t *agent, ice_candidate_pair_t *pair);
|
|
|
|
void agent_arm_keepalive(juice_agent_t *agent, agent_stun_entry_t *entry);
|
|
void agent_arm_transmission(juice_agent_t *agent, agent_stun_entry_t *entry, timediff_t delay);
|
|
void agent_update_gathering_done(juice_agent_t *agent);
|
|
void agent_update_candidate_pairs(juice_agent_t *agent);
|
|
void agent_update_ordered_pairs(juice_agent_t *agent);
|
|
|
|
agent_stun_entry_t *agent_find_entry_from_transaction_id(juice_agent_t *agent,
|
|
const uint8_t *transaction_id);
|
|
agent_stun_entry_t *
|
|
agent_find_entry_from_record(juice_agent_t *agent, const addr_record_t *record,
|
|
const addr_record_t *relayed); // relayed may be NULL
|
|
void agent_translate_host_candidate_entry(juice_agent_t *agent, agent_stun_entry_t *entry);
|
|
|
|
#endif
|