mirror of https://github.com/sipwise/rtpengine.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
246 lines
7.4 KiB
246 lines
7.4 KiB
#ifndef __ICE_H__
|
|
#define __ICE_H__
|
|
|
|
#include <arpa/inet.h>
|
|
#include <glib.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <stdbool.h>
|
|
|
|
#include "str.h"
|
|
#include "obj.h"
|
|
#include "helpers.h"
|
|
#include "media_socket.h"
|
|
#include "socket.h"
|
|
#include "timerthread.h"
|
|
#include "types.h"
|
|
|
|
#define MAX_COMPONENTS 2
|
|
#define TIMER_RUN_INTERVAL 20 /* ms */
|
|
#define STUN_RETRANSMIT_INTERVAL 100 /* ms, with exponential backoff */
|
|
#define STUN_MAX_RETRANSMITS 7
|
|
#define MAX_ICE_CANDIDATES 100
|
|
#define ICE_FOUNDATION_LENGTH 16
|
|
|
|
#define ICE_AGENT_COMPLETED 0x0002
|
|
#define ICE_AGENT_CONTROLLING 0x0004
|
|
#define ICE_AGENT_NOMINATING 0x0008
|
|
#define ICE_AGENT_USABLE 0x0010
|
|
#define ICE_AGENT_LITE_SELF 0x0020
|
|
|
|
#define ICE_PAIR_FROZEN 0x0001
|
|
#define ICE_PAIR_IN_PROGRESS 0x0002
|
|
#define ICE_PAIR_FAILED 0x0004
|
|
#define ICE_PAIR_SUCCEEDED 0x0008
|
|
#define ICE_PAIR_NOMINATED 0x0010
|
|
#define ICE_PAIR_LEARNED 0x0020
|
|
#define ICE_PAIR_VALID 0x0040
|
|
#define ICE_PAIR_TO_USE 0x0080
|
|
#define ICE_PAIR_TRIGGERED 0x0100
|
|
|
|
#define PAIR_ISSET(p, f) bf_isset(&(p)->pair_flags, ICE_PAIR_ ## f)
|
|
#define PAIR_SET(p, f) bf_set(&(p)->pair_flags, ICE_PAIR_ ## f)
|
|
#define PAIR_SET2(p, f, g) bf_set(&(p)->pair_flags, ICE_PAIR_ ## f | ICE_PAIR_ ## g)
|
|
#define PAIR_CLEAR(p, f) bf_clear(&(p)->pair_flags, ICE_PAIR_ ## f)
|
|
#define PAIR_CLEAR2(p, f, g) bf_clear(&(p)->pair_flags, ICE_PAIR_ ## f | ICE_PAIR_ ## g)
|
|
|
|
#define AGENT_ISSET(p, f) bf_isset(&(p)->agent_flags, ICE_AGENT_ ## f)
|
|
#define AGENT_ISSET2(p, f, g) bf_isset(&(p)->agent_flags, ICE_AGENT_ ## f | ICE_AGENT_ ## g)
|
|
#define AGENT_SET(p, f) bf_set(&(p)->agent_flags, ICE_AGENT_ ## f)
|
|
#define AGENT_SET2(p, f, g) bf_set(&(p)->agent_flags, ICE_AGENT_ ## f | ICE_AGENT_ ## g)
|
|
#define AGENT_CLEAR(p, f) bf_clear(&(p)->agent_flags, ICE_AGENT_ ## f)
|
|
#define AGENT_CLEAR3(p, f, g, h) \
|
|
bf_clear(&(p)->agent_flags, ICE_AGENT_ ## f | ICE_AGENT_ ## g | ICE_AGENT_ ## h)
|
|
|
|
struct logical_intf;
|
|
struct local_intf;
|
|
struct packet_stream;
|
|
struct call_media;
|
|
struct stream_params;
|
|
struct stun_attrs;
|
|
struct call_monologue;
|
|
|
|
enum ice_candidate_type {
|
|
ICT_UNKNOWN = 0,
|
|
ICT_HOST,
|
|
ICT_SRFLX,
|
|
ICT_PRFLX,
|
|
ICT_RELAY,
|
|
__ICT_LAST,
|
|
};
|
|
|
|
struct ice_candidate {
|
|
str foundation;
|
|
unsigned long component_id;
|
|
socktype_t *transport;
|
|
unsigned long priority;
|
|
endpoint_t endpoint;
|
|
enum ice_candidate_type type;
|
|
endpoint_t related;
|
|
str ufrag;
|
|
};
|
|
|
|
struct ice_candidate_pair {
|
|
struct ice_candidate *remote_candidate;
|
|
const struct local_intf *local_intf;
|
|
stream_fd *sfd;
|
|
atomic64 pair_flags;
|
|
uint32_t stun_transaction[3]; /* belongs to transaction_hash, thus agent->lock */
|
|
unsigned int retransmit_ms;
|
|
struct timeval retransmit;
|
|
unsigned int retransmits;
|
|
struct ice_agent *agent;
|
|
uint64_t pair_priority;
|
|
unsigned int was_controlling:1,
|
|
was_nominated:1;
|
|
};
|
|
|
|
TYPED_GHASHTABLE_PROTO(candidate_ht, struct ice_candidate, struct ice_candidate)
|
|
TYPED_GHASHTABLE_PROTO(candidate_pair_ht, struct ice_candidate_pair, struct ice_candidate_pair)
|
|
TYPED_GHASHTABLE_PROTO(foundation_ht, struct ice_candidate, struct ice_candidate)
|
|
TYPED_GHASHTABLE_PROTO(priority_ht, void, struct ice_candidate)
|
|
TYPED_GHASHTABLE_PROTO(transaction_ht, uint32_t, struct ice_candidate_pair)
|
|
|
|
/* these are protected by the call's master_lock */
|
|
struct ice_agent {
|
|
struct timerthread_obj tt_obj;
|
|
call_t *call; /* main reference */
|
|
struct call_media *media;
|
|
const struct logical_intf *logical_intf;
|
|
sockfamily_t *desired_family;
|
|
atomic64 last_activity;
|
|
|
|
mutex_t lock; /* for elements below. and call must be locked in R */
|
|
/* lock order: in_lock first, then agent->lock */
|
|
candidate_q remote_candidates;
|
|
candidate_pair_q candidate_pairs; /* for storage */
|
|
candidate_pair_q triggered;
|
|
candidate_ht candidate_hash;
|
|
priority_ht cand_prio_hash;
|
|
candidate_pair_ht pair_hash;
|
|
transaction_ht transaction_hash;
|
|
foundation_ht foundation_hash;
|
|
GTree *all_pairs;
|
|
candidate_pair_q all_pairs_list; /* sorted through gtree */
|
|
GTree *nominated_pairs; /* nominated by peer */
|
|
GTree *succeeded_pairs; /* checked by us */
|
|
GTree *valid_pairs; /* succeeded and nominated */
|
|
unsigned int active_components;
|
|
struct timeval start_nominating;
|
|
|
|
str ufrag[2]; /* 0 = remote, 1 = local */
|
|
str pwd[2]; /* ditto */
|
|
atomic64 agent_flags;
|
|
};
|
|
|
|
|
|
|
|
|
|
extern const unsigned int ice_type_preferences[];
|
|
extern const char * const ice_type_strings[];
|
|
|
|
|
|
|
|
|
|
void ice_init(void);
|
|
void ice_free(void);
|
|
|
|
enum ice_candidate_type ice_candidate_type(const str *s);
|
|
bool ice_has_related(enum ice_candidate_type);
|
|
void ice_foundation(str *);
|
|
bool ice_peer_address_known(struct ice_agent *, const endpoint_t *, struct packet_stream *,
|
|
const struct local_intf *ifa);
|
|
|
|
void ice_agent_init(struct ice_agent **agp, struct call_media *media);
|
|
void ice_update(struct ice_agent *, struct stream_params *, bool allow_restart);
|
|
void ice_shutdown(struct ice_agent **);
|
|
void ice_restart(struct ice_agent *);
|
|
|
|
void ice_candidates_free(candidate_q *);
|
|
void ice_remote_candidates(candidate_q *, struct ice_agent *);
|
|
|
|
void ice_thread_launch(void);
|
|
|
|
int ice_request(stream_fd *, const endpoint_t *, struct stun_attrs *);
|
|
int ice_response(stream_fd *, const endpoint_t *src,
|
|
struct stun_attrs *attrs, void *transaction);
|
|
|
|
void dequeue_sdp_fragments(struct call_monologue *);
|
|
bool trickle_ice_update(ng_buffer *ngbuf, call_t *call, sdp_ng_flags *flags,
|
|
sdp_streams_q *streams);
|
|
|
|
enum thread_looper_action ice_slow_timer(void);
|
|
|
|
#include "call.h"
|
|
|
|
|
|
/* returns 0 if ICE still has work to do, 1 otherwise */
|
|
INLINE bool ice_has_finished(struct call_media *media) {
|
|
if (!media)
|
|
return true;
|
|
if (!MEDIA_ISSET(media, ICE))
|
|
return true;
|
|
if (!media->ice_agent)
|
|
return true;
|
|
if (AGENT_ISSET(media->ice_agent, COMPLETED))
|
|
return true;
|
|
return false;
|
|
}
|
|
/* returns 1 if media has connectivity */
|
|
INLINE bool ice_is_usable(struct call_media *media) {
|
|
if (!media)
|
|
return true;
|
|
if (!MEDIA_ISSET(media, ICE))
|
|
return true;
|
|
if (!media->ice_agent)
|
|
return true;
|
|
if (AGENT_ISSET(media->ice_agent, USABLE))
|
|
return true;
|
|
return false;
|
|
}
|
|
INLINE bool ice_is_restart(struct ice_agent *ag, struct stream_params *sp) {
|
|
if (!ag || !sp)
|
|
return false;
|
|
struct call_media *media = ag->media;
|
|
if (ag->ufrag[0].s && sp->ice_ufrag.s && str_cmp_str(&ag->ufrag[0], &sp->ice_ufrag))
|
|
return true;
|
|
else if (ag->pwd[0].s && sp->ice_pwd.s && str_cmp_str(&ag->pwd[0], &sp->ice_pwd))
|
|
return true;
|
|
else if (ag->logical_intf != media->logical_intf)
|
|
return true;
|
|
return false;
|
|
|
|
}
|
|
INLINE unsigned int ice_type_preference(enum ice_candidate_type type) {
|
|
if (type >= __ICT_LAST)
|
|
return 0;
|
|
return ice_type_preferences[type];
|
|
}
|
|
/* local_pref starts with 0 */
|
|
INLINE uint32_t ice_priority_pref(unsigned int type_pref, unsigned int local_pref, unsigned int component) {
|
|
return type_pref << 24 | (65535 - local_pref) << 8 | (256 - component);
|
|
}
|
|
INLINE uint32_t ice_priority(enum ice_candidate_type type, unsigned int local_pref, unsigned int component) {
|
|
return ice_priority_pref(ice_type_preference(type), local_pref, component);
|
|
}
|
|
INLINE unsigned int ice_type_pref_from_prio(uint32_t prio) {
|
|
return (prio & 0xff000000) >> 24;
|
|
}
|
|
INLINE unsigned int ice_local_pref_from_prio(uint32_t prio) {
|
|
return 65535 - ((prio & 0xffff00) >> 8);
|
|
}
|
|
INLINE const char *ice_candidate_type_str(enum ice_candidate_type type) {
|
|
if (type >= __ICT_LAST)
|
|
return 0;
|
|
return ice_type_strings[type];
|
|
}
|
|
INLINE int ice_ufrag_cmp(struct ice_agent *ag, const str *s) {
|
|
if (!ag->ufrag[0].len) // fragment unknown
|
|
return 0;
|
|
return str_cmp_str0(&ag->ufrag[0], s);
|
|
}
|
|
|
|
|
|
|
|
#endif
|