Skip to content
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

Relay to Aiortc #186

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
122 changes: 109 additions & 13 deletions src/agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@
#include "utils.h"

#define AGENT_POLL_TIMEOUT 1
#define AGENT_CONNCHECK_MAX 1000
#define AGENT_CONNCHECK_MAX 500
#define AGENT_CONNCHECK_PERIOD 100
#define AGENT_STUN_RECV_MAXTIMES 1000

void agent_clear_candidates(Agent* agent) {
agent->local_candidates_count = 0;
agent->remote_candidates_count = 0;
agent->candidate_pairs_num = 0;

agent->relay_channel_refresh_cnt = 0;
}

int agent_create(Agent* agent) {
Expand Down Expand Up @@ -61,9 +63,10 @@ static int agent_socket_recv(Agent* agent, Address* addr, uint8_t* buf, int len)
int maxfd = -1;
fd_set rfds;
struct timeval tv;
int addr_type[] = { AF_INET,
int addr_type[] = {
AF_INET,
#if CONFIG_IPV6
AF_INET6,
AF_INET6,
#endif
};

Expand Down Expand Up @@ -124,9 +127,10 @@ static int agent_create_host_addr(Agent* agent) {
int i, j;
const char* iface_prefx[] = {CONFIG_IFACE_PREFIX};
IceCandidate* ice_candidate;
int addr_type[] = { AF_INET,
int addr_type[] = {
AF_INET,
#if CONFIG_IPV6
AF_INET6,
AF_INET6,
#endif
};

Expand Down Expand Up @@ -228,9 +232,18 @@ static int agent_create_turn_addr(Agent* agent, Address* serv_addr, const char*
}

stun_parse_msg_buf(&recv_msg);

memcpy(&turn_addr, &recv_msg.relayed_addr, sizeof(Address));
IceCandidate* ice_candidate = agent->local_candidates + agent->local_candidates_count++;
ice_candidate_create(ice_candidate, agent->local_candidates_count, ICE_CANDIDATE_TYPE_RELAY, &turn_addr);

memcpy(&ice_candidate->raddr, &recv_msg.mapped_addr, sizeof(Address));
memcpy(&ice_candidate->serv_addr, serv_addr, sizeof(Address));
strcpy(ice_candidate->realm, recv_msg.realm);
strcpy(ice_candidate->nonce, recv_msg.nonce);

ice_candidate->username = username;
ice_candidate->credential = credential;
return ret;
}

Expand Down Expand Up @@ -299,10 +312,22 @@ void agent_get_local_description(Agent* agent, char* description, int length) {
}

int agent_send(Agent* agent, const uint8_t* buf, int len) {
if (agent->nominated_pair->local->type == ICE_CANDIDATE_TYPE_RELAY) {
char* channel_data_buf = malloc(len + 4);

*(uint16_t*)channel_data_buf = htons(agent->nominated_pair->channel_number);
*(uint16_t*)(channel_data_buf + 2) = htons(len);
memcpy(channel_data_buf + 4, buf, len);
int sent_size = agent_socket_send(agent, &agent->nominated_pair->local->serv_addr, (const uint8_t*)channel_data_buf, len + 4);
LOGD("Sent data to TURN server: %d", sent_size);
free(channel_data_buf);
return sent_size - 4;
}

return agent_socket_send(agent, &agent->nominated_pair->remote->addr, buf, len);
}

static void agent_create_binding_response(Agent* agent, StunMessage* msg, Address* addr) {
void agent_create_binding_response(Agent* agent, StunMessage* msg, Address* addr) {
int size = 0;
char username[584];
char mapped_address[32];
Expand All @@ -320,7 +345,7 @@ static void agent_create_binding_response(Agent* agent, StunMessage* msg, Addres
stun_msg_finish(msg, STUN_CREDENTIAL_SHORT_TERM, agent->local_upwd, strlen(agent->local_upwd));
}

static void agent_create_binding_request(Agent* agent, StunMessage* msg) {
void agent_create_binding_request(Agent* agent, StunMessage* msg) {
uint64_t tie_breaker = 0; // always be controlled
// send binding request
stun_msg_create(msg, STUN_CLASS_REQUEST | STUN_METHOD_BINDING);
Expand All @@ -338,6 +363,24 @@ static void agent_create_binding_request(Agent* agent, StunMessage* msg) {
stun_msg_finish(msg, STUN_CREDENTIAL_SHORT_TERM, agent->remote_upwd, strlen(agent->remote_upwd));
}

void agent_create_channel_bind_request(Agent* agent, StunMessage* msg, IceCandidatePair* pair) {
int size = 0;
char mapped_address[32];
uint8_t mask[16];
stun_msg_create(msg, STUN_CLASS_REQUEST | STUN_METHOD_CHANNEL_BIND);
char channel_number_buf[4];
memset(channel_number_buf, 0, sizeof(channel_number_buf));
*(uint16_t*)channel_number_buf = htons(pair->channel_number);
stun_msg_write_attr(msg, STUN_ATTR_TYPE_CHANNEL_NUMBER, 4, channel_number_buf);
*((uint32_t*)mask) = htonl(MAGIC_COOKIE);
size = stun_set_mapped_address(mapped_address, mask, &(pair->remote->addr));
stun_msg_write_attr(msg, STUN_ATTR_TYPE_XOR_PEER_ADDRESS, size, mapped_address);
stun_msg_write_attr(msg, STUN_ATTR_TYPE_USERNAME, strlen(pair->local->username), (char*)pair->local->username);
stun_msg_write_attr(msg, STUN_ATTR_TYPE_REALM, strlen(pair->local->realm), (char*)pair->local->realm);
stun_msg_write_attr(msg, STUN_ATTR_TYPE_NONCE, strlen(pair->local->nonce), (char*)pair->local->nonce);
stun_msg_finish(msg, STUN_CREDENTIAL_LONG_TERM, pair->local->credential, strlen(pair->local->credential));
}

void agent_process_stun_request(Agent* agent, StunMessage* stun_msg, Address* addr) {
StunMessage msg;
StunHeader* header;
Expand All @@ -347,7 +390,7 @@ void agent_process_stun_request(Agent* agent, StunMessage* stun_msg, Address* ad
header = (StunHeader*)stun_msg->buf;
memcpy(agent->transaction_id, header->transaction_id, sizeof(header->transaction_id));
agent_create_binding_response(agent, &msg, addr);
agent_socket_send(agent, addr, msg.buf, msg.size);
agent_send(agent, msg.buf, msg.size);
agent->binding_request_time = ports_get_epoch_time();
}
break;
Expand All @@ -364,6 +407,7 @@ void agent_process_stun_response(Agent* agent, StunMessage* stun_msg) {
}
break;
default:
LOGD("Unknown STUN method: %d", stun_msg->stunmethod);
break;
}
}
Expand All @@ -372,7 +416,20 @@ int agent_recv(Agent* agent, uint8_t* buf, int len) {
int ret = -1;
StunMessage stun_msg;
Address addr;
if ((ret = agent_socket_recv(agent, &addr, buf, len)) > 0 && stun_probe(buf, len) == 0) {

ret = agent_socket_recv(agent, &addr, buf, len);

if (agent->nominated_pair->local->type == ICE_CANDIDATE_TYPE_RELAY) {
if (ret > 0) {
if (*(uint16_t*)buf == htons(agent->nominated_pair->channel_number)) {
memcpy(buf, buf + 4, ret - 4);
ret -= 4;
}
} else
return 0;
}

if (ret > 0 && stun_probe(buf, len) == 0) {
memcpy(stun_msg.buf, buf, ret);
stun_msg.size = ret;
stun_parse_msg_buf(&stun_msg);
Expand All @@ -388,11 +445,38 @@ int agent_recv(Agent* agent, uint8_t* buf, int len) {
default:
break;
}
ret = 0;
return agent_recv(agent, buf, len);
}
return ret;
}

void agent_create_relay_channel(Agent* agent, IceCandidatePair* pair, int wait_response) {
char addr_string[ADDRSTRLEN];

addr_to_string(&pair->local->serv_addr, addr_string, sizeof(addr_string));
LOGD("create channel bind request relay server addr: %s, port: %d", addr_string, pair->local->serv_addr.port);
addr_to_string(&pair->local->addr, addr_string, sizeof(addr_string));
LOGD("to remote ip: %s, port: %d", addr_string, pair->remote->addr.port);

StunMessage msg;
memset(&msg, 0, sizeof(msg));
agent_create_channel_bind_request(agent, &msg, pair);

agent_socket_send(agent, &pair->local->serv_addr, msg.buf, msg.size);
if (wait_response) {
StunMessage recv_msg;
int ret = agent_socket_recv_attempts(agent, NULL, recv_msg.buf, sizeof(recv_msg.buf), AGENT_STUN_RECV_MAXTIMES);

if (ret > 0) {
stun_parse_msg_buf(&recv_msg);
}

if (ret <= 0 || recv_msg.stunclass != STUN_CLASS_RESPONSE) {
LOGW("Failed to receive TURN Channel Binding Response.");
}
}
}

void agent_set_remote_description(Agent* agent, char* description) {
/*
a=ice-ufrag:Iexb
Expand All @@ -402,7 +486,6 @@ void agent_set_remote_description(Agent* agent, char* description) {
int i, j;

LOGD("Set remote description:\n%s", description);

char* line_start = description;
char* line_end = NULL;

Expand Down Expand Up @@ -433,13 +516,19 @@ void agent_set_remote_description(Agent* agent, char* description) {
LOGD("remote upwd: %s", agent->remote_upwd);

// Please set gather candidates before set remote description

for (i = 0; i < agent->local_candidates_count; i++) {
for (j = 0; j < agent->remote_candidates_count; j++) {
if (agent->local_candidates[i].addr.family == agent->remote_candidates[j].addr.family) {
agent->candidate_pairs[agent->candidate_pairs_num].local = &agent->local_candidates[i];
agent->candidate_pairs[agent->candidate_pairs_num].remote = &agent->remote_candidates[j];
agent->candidate_pairs[agent->candidate_pairs_num].priority = agent->local_candidates[i].priority + agent->remote_candidates[j].priority;
agent->candidate_pairs[agent->candidate_pairs_num].state = ICE_CANDIDATE_STATE_FROZEN;

if (agent->local_candidates[i].type == ICE_CANDIDATE_TYPE_RELAY) {
agent->candidate_pairs[agent->candidate_pairs_num].channel_number = 0x4000 + j;
agent_create_relay_channel(agent, &agent->candidate_pairs[agent->candidate_pairs_num], 1);
}
agent->candidate_pairs_num++;
}
}
Expand All @@ -453,7 +542,7 @@ int agent_connectivity_check(Agent* agent) {
StunMessage msg;

if (agent->nominated_pair->state != ICE_CANDIDATE_STATE_INPROGRESS) {
LOGI("nominated pair is not in progress");
LOGI("nominated pair is not in progress %d", agent->nominated_pair->state);
return -1;
}

Expand All @@ -463,7 +552,7 @@ int agent_connectivity_check(Agent* agent) {
addr_to_string(&agent->nominated_pair->remote->addr, addr_string, sizeof(addr_string));
LOGD("send binding request to remote ip: %s, port: %d", addr_string, agent->nominated_pair->remote->addr.port);
agent_create_binding_request(agent, &msg);
agent_socket_send(agent, &agent->nominated_pair->remote->addr, msg.buf, msg.size);
agent_send(agent, msg.buf, msg.size);
}

agent_recv(agent, buf, sizeof(buf));
Expand Down Expand Up @@ -500,3 +589,10 @@ int agent_select_candidate_pair(Agent* agent) {
// all candidate pairs are failed
return -1;
}

void agent_refresh_relay_channel(Agent* agent) {
agent->relay_channel_refresh_cnt++;

if (agent->relay_channel_refresh_cnt % 300000 == 0) // ~5 minutes
agent_create_relay_channel(agent, agent->selected_pair, 0);
}
6 changes: 6 additions & 0 deletions src/agent.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ struct Agent {
int candidate_pairs_num;
int use_candidate;
uint32_t transaction_id[3];

uint32_t relay_channel_refresh_cnt;
};

void agent_gather_candidate(Agent* agent, const char* urls, const char* username, const char* credential);
Expand All @@ -82,6 +84,8 @@ int agent_recv(Agent* agent, uint8_t* buf, int len);

void agent_set_remote_description(Agent* agent, char* description);

void agent_create_permission(Agent* agent, const char* username, const char* credential);

int agent_select_candidate_pair(Agent* agent);

int agent_connectivity_check(Agent* agent);
Expand All @@ -92,4 +96,6 @@ int agent_create(Agent* agent);

void agent_destroy(Agent* agent);

void agent_refresh_relay_channel(Agent* agent);

#endif // AGENT_H_
2 changes: 1 addition & 1 deletion src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#define CONFIG_H_

// uncomment this if you want to handshake with a aiortc
// #define CONFIG_DTLS_USE_ECDSA 1
#define CONFIG_DTLS_USE_ECDSA 1

#define SCTP_MTU (1200)
#define CONFIG_MTU (1300)
Expand Down
28 changes: 19 additions & 9 deletions src/dtls_srtp.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,12 @@ void dtls_srtp_deinit(DtlsSrtp* dtls_srtp) {
srtp_dealloc(dtls_srtp->srtp_out);
}
}
static void set_policy_key(unsigned char* policy_key, uint8_t* key_material, int idx) {
int key_start = idx * SRTP_MASTER_KEY_LENGTH;
int salt_start = 2 * SRTP_MASTER_KEY_LENGTH + idx * SRTP_MASTER_SALT_LENGTH;
memcpy(policy_key, key_material + key_start, SRTP_MASTER_KEY_LENGTH);
memcpy(policy_key + SRTP_MASTER_KEY_LENGTH, key_material + salt_start, SRTP_MASTER_SALT_LENGTH);
}

static int dtls_srtp_key_derivation(DtlsSrtp* dtls_srtp, const unsigned char* master_secret, size_t secret_len, const unsigned char* randbytes, size_t randbytes_len, mbedtls_tls_prf_types tls_prf_type) {
int ret;
Expand Down Expand Up @@ -277,15 +283,18 @@ static int dtls_srtp_key_derivation(DtlsSrtp* dtls_srtp, const unsigned char* ma
srtp_crypto_policy_set_rtp_default(&dtls_srtp->remote_policy.rtp);
srtp_crypto_policy_set_rtcp_default(&dtls_srtp->remote_policy.rtcp);

memcpy(dtls_srtp->remote_policy_key, key_material, SRTP_MASTER_KEY_LENGTH);
memcpy(dtls_srtp->remote_policy_key + SRTP_MASTER_KEY_LENGTH, key_material + SRTP_MASTER_KEY_LENGTH + SRTP_MASTER_KEY_LENGTH, SRTP_MASTER_SALT_LENGTH);
if (dtls_srtp->role == DTLS_SRTP_ROLE_SERVER)
set_policy_key(dtls_srtp->remote_policy_key, key_material, 0);
else
set_policy_key(dtls_srtp->remote_policy_key, key_material, 1);

dtls_srtp->remote_policy.ssrc.type = ssrc_any_inbound;
dtls_srtp->remote_policy.key = dtls_srtp->remote_policy_key;
dtls_srtp->remote_policy.next = NULL;

if (srtp_create(&dtls_srtp->srtp_in, &dtls_srtp->remote_policy) != srtp_err_status_ok) {
LOGD("Error creating inbound SRTP session for component");
srtp_init();
srtp_err_status_t err = srtp_create(&dtls_srtp->srtp_in, &dtls_srtp->remote_policy);
if (err != srtp_err_status_ok) {
LOGI("Error creating inbound SRTP session for component %d", err);
return -1;
}

Expand All @@ -297,8 +306,10 @@ static int dtls_srtp_key_derivation(DtlsSrtp* dtls_srtp, const unsigned char* ma
srtp_crypto_policy_set_rtp_default(&dtls_srtp->local_policy.rtp);
srtp_crypto_policy_set_rtcp_default(&dtls_srtp->local_policy.rtcp);

memcpy(dtls_srtp->local_policy_key, key_material + SRTP_MASTER_KEY_LENGTH, SRTP_MASTER_KEY_LENGTH);
memcpy(dtls_srtp->local_policy_key + SRTP_MASTER_KEY_LENGTH, key_material + SRTP_MASTER_KEY_LENGTH + SRTP_MASTER_KEY_LENGTH + SRTP_MASTER_SALT_LENGTH, SRTP_MASTER_SALT_LENGTH);
if (dtls_srtp->role == DTLS_SRTP_ROLE_SERVER)
set_policy_key(dtls_srtp->local_policy_key, key_material, 1);
else
set_policy_key(dtls_srtp->local_policy_key, key_material, 0);

dtls_srtp->local_policy.ssrc.type = ssrc_any_outbound;
dtls_srtp->local_policy.key = dtls_srtp->local_policy_key;
Expand All @@ -309,7 +320,7 @@ static int dtls_srtp_key_derivation(DtlsSrtp* dtls_srtp, const unsigned char* ma
return -1;
}

LOGI("Created outbound SRTP session");
LOGI("Created outbound SRTP session");
dtls_srtp->state = DTLS_SRTP_STATE_CONNECTED;
return 0;
}
Expand All @@ -334,7 +345,6 @@ static void dtls_srtp_key_derivation_cb(void* context,
mbedtls_tls_prf_types tls_prf_type) {
#endif
DtlsSrtp* dtls_srtp = (DtlsSrtp*)context;

unsigned char master_secret[48];
unsigned char randbytes[64];

Expand Down
10 changes: 10 additions & 0 deletions src/ice.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ struct IceCandidate {
IceCandidateState state;
Address addr;
Address raddr;

Address serv_addr;

const char* username;
const char* credential;

char realm[64];
char nonce[64];
};

typedef struct IceCandidatePair IceCandidatePair;
Expand All @@ -50,6 +58,8 @@ struct IceCandidatePair {
IceCandidate* remote;
int conncheck;
uint64_t priority;

uint16_t channel_number;
};

void ice_candidate_create(IceCandidate* ice_candidate, int foundation, IceCandidateType type, Address* addr);
Expand Down
Loading
Loading